summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfrsyuki <frsyuki@users.sourceforge.jp>2010-05-20 03:49:26 +0900
committerfrsyuki <frsyuki@users.sourceforge.jp>2010-05-20 03:49:26 +0900
commit979ff809827ab25005364dad41d2fd043b8eaa4d (patch)
tree7ff28f97752207791c44268a081e968bcb9a4488
parent6cde9f3a9d3ce03db1f67ea8169b8c7c10be2532 (diff)
downloadmsgpack-python-979ff809827ab25005364dad41d2fd043b8eaa4d.tar.gz
java: redesign
-rw-r--r--cpp/msgpack/type/nil.hpp8
-rw-r--r--java/src/main/java/org/msgpack/BufferedUnpackerImpl.java384
-rw-r--r--java/src/main/java/org/msgpack/MessageConvertable.java (renamed from java/src/main/java/org/msgpack/MessageMergeable.java)4
-rw-r--r--java/src/main/java/org/msgpack/MessageTypeException.java4
-rw-r--r--java/src/main/java/org/msgpack/MessageUnpackable.java25
-rw-r--r--java/src/main/java/org/msgpack/Packer.java2
-rw-r--r--java/src/main/java/org/msgpack/UnbufferedUnpacker.java82
-rw-r--r--java/src/main/java/org/msgpack/UnpackCursor.java96
-rw-r--r--java/src/main/java/org/msgpack/UnpackIterator.java24
-rw-r--r--java/src/main/java/org/msgpack/UnpackResult.java42
-rw-r--r--java/src/main/java/org/msgpack/Unpacker.java269
-rw-r--r--java/src/main/java/org/msgpack/UnpackerImpl.java (renamed from java/src/main/java/org/msgpack/impl/UnpackerImpl.java)26
-rw-r--r--java/src/test/java/org/msgpack/TestDirectConversion.java154
-rw-r--r--java/src/test/java/org/msgpack/TestPackUnpack.java2
14 files changed, 864 insertions, 258 deletions
diff --git a/cpp/msgpack/type/nil.hpp b/cpp/msgpack/type/nil.hpp
index e58bc9d..f44e45e 100644
--- a/cpp/msgpack/type/nil.hpp
+++ b/cpp/msgpack/type/nil.hpp
@@ -51,6 +51,14 @@ inline void operator<< (object::with_zone& o, type::nil v)
{ static_cast<object&>(o) << v; }
+template <>
+inline void object::as<void>() const
+{
+ msgpack::type::nil v;
+ convert(&v);
+}
+
+
} // namespace msgpack
#endif /* msgpack/type/nil.hpp */
diff --git a/java/src/main/java/org/msgpack/BufferedUnpackerImpl.java b/java/src/main/java/org/msgpack/BufferedUnpackerImpl.java
new file mode 100644
index 0000000..0ef9c12
--- /dev/null
+++ b/java/src/main/java/org/msgpack/BufferedUnpackerImpl.java
@@ -0,0 +1,384 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2010 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 org.msgpack;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+//import java.math.BigInteger;
+
+abstract class BufferedUnpackerImpl extends UnpackerImpl {
+ int filled = 0;
+ byte[] buffer = null;
+ private ByteBuffer castBuffer = ByteBuffer.allocate(8);
+
+ abstract boolean fill() throws IOException;
+
+ final int next(int offset, UnpackResult result) throws IOException, UnpackException {
+ if(filled == 0) {
+ if(!fill()) {
+ return offset;
+ }
+ }
+
+ do {
+ int noffset = super.execute(buffer, offset, filled);
+ if(noffset <= offset) {
+ if(!fill()) {
+ return offset;
+ }
+ }
+ offset = noffset;
+ } while(!super.isFinished());
+
+ Object obj = super.getData();
+ super.reset();
+ result.done(obj);
+
+ return offset;
+ }
+
+ private final void more(int offset, int require) throws IOException, UnpackException {
+ while(filled - offset < require) {
+ if(!fill()) {
+ // FIXME
+ throw new UnpackException("insufficient buffer");
+ }
+ }
+ }
+
+ final byte unpackByte(UnpackCursor c, int offset) throws IOException, MessageTypeException {
+ int o = unpackInt(c, offset);
+ if(0x7f < o || o < -0x80) {
+ throw new MessageTypeException();
+ }
+ return (byte)o;
+ }
+
+ final short unpackShort(UnpackCursor c, int offset) throws IOException, MessageTypeException {
+ int o = unpackInt(c, offset);
+ if(0x7fff < o || o < -0x8000) {
+ throw new MessageTypeException();
+ }
+ return (short)o;
+ }
+
+ final int unpackInt(UnpackCursor c, int offset) throws IOException, MessageTypeException {
+ more(offset, 1);
+ int b = buffer[offset];
+ if((b & 0x80) == 0 || (b & 0xe0) == 0xe0) { // Fixnum
+ return (int)b;
+ }
+ switch(b & 0xff) {
+ case 0xcc: // unsigned int 8
+ more(offset, 2);
+ c.advance(2);
+ return (int)((short)buffer[offset+1] & 0xff);
+ case 0xcd: // unsigned int 16
+ more(offset, 3);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 2);
+ c.advance(3);
+ return (int)((int)castBuffer.getShort(0) & 0xffff);
+ case 0xce: // unsigned int 32
+ more(offset, 5);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 4);
+ {
+ int o = castBuffer.getInt(0);
+ if(o < 0) {
+ throw new MessageTypeException();
+ }
+ c.advance(5);
+ return o;
+ }
+ case 0xcf: // unsigned int 64
+ more(offset, 9);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 8);
+ {
+ long o = castBuffer.getLong(0);
+ if(o < 0 || o > 0x7fffffffL) {
+ throw new MessageTypeException();
+ }
+ c.advance(9);
+ return (int)o;
+ }
+ case 0xd0: // signed int 8
+ more(offset, 2);
+ c.advance(2);
+ return (int)buffer[offset+1];
+ case 0xd1: // signed int 16
+ more(offset, 3);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 2);
+ c.advance(3);
+ return (int)castBuffer.getShort(0);
+ case 0xd2: // signed int 32
+ more(offset, 4);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 4);
+ c.advance(4);
+ return (int)castBuffer.getInt(0);
+ case 0xd3: // signed int 64
+ more(offset, 9);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 8);
+ {
+ long o = castBuffer.getLong(0);
+ if(0x7fffffffL < o || o < -0x80000000L) {
+ throw new MessageTypeException();
+ }
+ c.advance(9);
+ return (int)o;
+ }
+ default:
+ throw new MessageTypeException();
+ }
+ }
+
+ final long unpackLong(UnpackCursor c, int offset) throws IOException, MessageTypeException {
+ more(offset, 1);
+ int b = buffer[offset];
+ if((b & 0x80) == 0 || (b & 0xe0) == 0xe0) { // Fixnum
+ return (long)b;
+ }
+ switch(b & 0xff) {
+ case 0xcc: // unsigned int 8
+ more(offset, 2);
+ c.advance(2);
+ return (long)((short)buffer[offset+1] & 0xff);
+ case 0xcd: // unsigned int 16
+ more(offset, 3);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 2);
+ c.advance(3);
+ return (long)((int)castBuffer.getShort(0) & 0xffff);
+ case 0xce: // unsigned int 32
+ more(offset, 5);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 4);
+ c.advance(5);
+ return ((long)castBuffer.getInt(0) & 0xffffffffL);
+ case 0xcf: // unsigned int 64
+ more(offset, 9);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 8);
+ {
+ long o = castBuffer.getLong(0);
+ if(o < 0) {
+ // FIXME
+ throw new MessageTypeException("uint 64 bigger than 0x7fffffff is not supported");
+ }
+ c.advance(9);
+ return o;
+ }
+ case 0xd0: // signed int 8
+ more(offset, 2);
+ c.advance(2);
+ return (long)buffer[offset+1];
+ case 0xd1: // signed int 16
+ more(offset, 3);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 2);
+ c.advance(3);
+ return (long)castBuffer.getShort(0);
+ case 0xd2: // signed int 32
+ more(offset, 4);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 4);
+ c.advance(4);
+ return (long)castBuffer.getInt(0);
+ case 0xd3: // signed int 64
+ more(offset, 9);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 8);
+ c.advance(9);
+ return (long)castBuffer.getLong(0);
+ default:
+ throw new MessageTypeException();
+ }
+ }
+
+ final float unpackFloat(UnpackCursor c, int offset) throws IOException, MessageTypeException {
+ more(offset, 1);
+ int b = buffer[offset];
+ switch(b & 0xff) {
+ case 0xca: // float
+ more(offset, 5);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 4);
+ c.advance(5);
+ return castBuffer.getFloat(0);
+ case 0xcb: // double
+ more(offset, 9);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 8);
+ c.advance(9);
+ // FIXME overflow check
+ return (float)castBuffer.getDouble(0);
+ default:
+ throw new MessageTypeException();
+ }
+ }
+
+ final double unpackDouble(UnpackCursor c, int offset) throws IOException, MessageTypeException {
+ more(offset, 1);
+ int b = buffer[offset];
+ switch(b & 0xff) {
+ case 0xca: // float
+ more(offset, 5);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 4);
+ c.advance(5);
+ return (double)castBuffer.getFloat(0);
+ case 0xcb: // double
+ more(offset, 9);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 8);
+ c.advance(9);
+ return castBuffer.getDouble(0);
+ default:
+ throw new MessageTypeException();
+ }
+ }
+
+ final Object unpackNull(UnpackCursor c, int offset) throws IOException, MessageTypeException {
+ more(offset, 1);
+ int b = buffer[offset] & 0xff;
+ if(b != 0xc0) { // nil
+ throw new MessageTypeException();
+ }
+ c.advance(1);
+ return null;
+ }
+
+ final boolean unpackBoolean(UnpackCursor c, int offset) throws IOException, MessageTypeException {
+ more(offset, 1);
+ int b = buffer[offset] & 0xff;
+ if(b == 0xc2) { // false
+ c.advance(1);
+ return false;
+ } else if(b == 0xc3) { // true
+ c.advance(1);
+ return true;
+ } else {
+ throw new MessageTypeException();
+ }
+ }
+
+ final int unpackArray(UnpackCursor c, int offset) throws IOException, MessageTypeException {
+ more(offset, 1);
+ int b = buffer[offset];
+ if((b & 0xf0) == 0x90) { // FixArray
+ c.advance(1);
+ return (int)(b & 0x0f);
+ }
+ switch(b & 0xff) {
+ case 0xdc: // array 16
+ more(offset, 3);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 2);
+ c.advance(3);
+ return (int)castBuffer.getShort(0) & 0xffff;
+ case 0xdd: // array 32
+ more(offset, 5);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 4);
+ c.advance(5);
+ // FIXME overflow check
+ return castBuffer.getInt(0) & 0x7fffffff;
+ default:
+ throw new MessageTypeException();
+ }
+ }
+
+ final int unpackMap(UnpackCursor c, int offset) throws IOException, MessageTypeException {
+ more(offset, 1);
+ int b = buffer[offset];
+ if((b & 0xf0) == 0x80) { // FixMap
+ c.advance(1);
+ return (int)(b & 0x0f);
+ }
+ switch(b & 0xff) {
+ case 0xde: // map 16
+ more(offset, 3);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 2);
+ c.advance(3);
+ return (int)castBuffer.getShort(0) & 0xffff;
+ case 0xdf: // map 32
+ more(offset, 5);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 4);
+ c.advance(5);
+ // FIXME overflow check
+ return castBuffer.getInt(0) & 0x7fffffff;
+ default:
+ throw new MessageTypeException();
+ }
+ }
+
+ final int unpackRaw(UnpackCursor c, int offset) throws IOException, MessageTypeException {
+ more(offset, 1);
+ int b = buffer[offset];
+ if((b & 0xe0) == 0xa0) { // FixRaw
+ c.advance(1);
+ return (int)(b & 0x0f);
+ }
+ switch(b & 0xff) {
+ case 0xda: // raw 16
+ more(offset, 3);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 2);
+ c.advance(3);
+ return (int)castBuffer.getShort(0) & 0xffff;
+ case 0xdb: // raw 32
+ more(offset, 5);
+ castBuffer.rewind();
+ castBuffer.put(buffer, offset+1, 4);
+ c.advance(5);
+ // FIXME overflow check
+ return castBuffer.getInt(0) & 0x7fffffff;
+ default:
+ throw new MessageTypeException();
+ }
+ }
+
+ final byte[] unpackRawBody(UnpackCursor c, int offset, int length) throws IOException, MessageTypeException {
+ more(offset, length);
+ byte[] bytes = new byte[length];
+ System.arraycopy(buffer, offset, bytes, 0, length);
+ c.advance(length);
+ return bytes;
+ }
+
+ final String unpackString(UnpackCursor c, int offset) throws IOException, MessageTypeException {
+ int length = unpackRaw(c, offset);
+ offset = c.getOffset();
+ more(offset, length);
+ String s;
+ try {
+ s = new String(buffer, offset, length, "UTF-8");
+ } catch (Exception e) {
+ throw new MessageTypeException();
+ }
+ c.advance(length);
+ return s;
+ }
+}
+
diff --git a/java/src/main/java/org/msgpack/MessageMergeable.java b/java/src/main/java/org/msgpack/MessageConvertable.java
index e5a5b45..da251dc 100644
--- a/java/src/main/java/org/msgpack/MessageMergeable.java
+++ b/java/src/main/java/org/msgpack/MessageConvertable.java
@@ -17,7 +17,7 @@
//
package org.msgpack;
-public interface MessageMergeable {
- public void messageMerge(Object obj) throws MessageTypeException;
+public interface MessageConvertable {
+ public void messageConvert(Object obj) throws MessageTypeException;
}
diff --git a/java/src/main/java/org/msgpack/MessageTypeException.java b/java/src/main/java/org/msgpack/MessageTypeException.java
index feb6c08..0fa37b7 100644
--- a/java/src/main/java/org/msgpack/MessageTypeException.java
+++ b/java/src/main/java/org/msgpack/MessageTypeException.java
@@ -17,9 +17,7 @@
//
package org.msgpack;
-import java.io.IOException;
-
-public class MessageTypeException extends IOException {
+public class MessageTypeException extends RuntimeException {
public MessageTypeException() { }
public MessageTypeException(String s) {
diff --git a/java/src/main/java/org/msgpack/MessageUnpackable.java b/java/src/main/java/org/msgpack/MessageUnpackable.java
new file mode 100644
index 0000000..20e4d56
--- /dev/null
+++ b/java/src/main/java/org/msgpack/MessageUnpackable.java
@@ -0,0 +1,25 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2010 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 org.msgpack;
+
+import java.io.IOException;
+
+public interface MessageUnpackable {
+ public void messageUnpack(Unpacker pk) throws IOException, MessageTypeException;
+}
+
diff --git a/java/src/main/java/org/msgpack/Packer.java b/java/src/main/java/org/msgpack/Packer.java
index 935728d..6d79414 100644
--- a/java/src/main/java/org/msgpack/Packer.java
+++ b/java/src/main/java/org/msgpack/Packer.java
@@ -401,7 +401,7 @@ public class Packer {
} else if(o instanceof Double) {
return packDouble((Double)o);
} else {
- throw new IOException("unknown object "+o+" ("+o.getClass()+")");
+ throw new MessageTypeException("unknown object "+o+" ("+o.getClass()+")");
}
}
}
diff --git a/java/src/main/java/org/msgpack/UnbufferedUnpacker.java b/java/src/main/java/org/msgpack/UnbufferedUnpacker.java
deleted file mode 100644
index b427973..0000000
--- a/java/src/main/java/org/msgpack/UnbufferedUnpacker.java
+++ /dev/null
@@ -1,82 +0,0 @@
-//
-// MessagePack for Java
-//
-// Copyright (C) 2009-2010 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 org.msgpack;
-
-import java.lang.Iterable;
-import java.io.InputStream;
-import java.io.IOException;
-import java.util.Iterator;
-import org.msgpack.impl.UnpackerImpl;
-
-public class UnbufferedUnpacker extends UnpackerImpl {
- private int offset;
- private boolean finished;
- private Object data;
-
- public UnbufferedUnpacker() {
- super();
- this.offset = 0;
- this.finished = false;
- }
-
- public UnbufferedUnpacker useSchema(Schema s) {
- super.setSchema(s);
- return this;
- }
-
- public Object getData() {
- return data;
- }
-
- public boolean isFinished() {
- return finished;
- }
-
- public void reset() {
- super.reset();
- this.offset = 0;
- }
-
- int getOffset() {
- return offset;
- }
-
- void setOffset(int offset) {
- this.offset = offset;
- }
-
- public int execute(byte[] buffer) throws UnpackException {
- return execute(buffer, 0, buffer.length);
- }
-
- // FIXME
- public int execute(byte[] buffer, int offset, int length) throws UnpackException
- {
- int noffset = super.execute(buffer, offset + this.offset, length);
- this.offset = noffset - offset;
- if(super.isFinished()) {
- this.data = super.getData();
- this.finished = true;
- super.reset();
- } else {
- this.finished = false;
- }
- return noffset;
- }
-}
-
diff --git a/java/src/main/java/org/msgpack/UnpackCursor.java b/java/src/main/java/org/msgpack/UnpackCursor.java
new file mode 100644
index 0000000..33f4258
--- /dev/null
+++ b/java/src/main/java/org/msgpack/UnpackCursor.java
@@ -0,0 +1,96 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2010 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 org.msgpack;
+
+import java.io.IOException;
+
+public class UnpackCursor {
+ private Unpacker pac;
+ private int offset;
+
+ UnpackCursor(Unpacker pac, int offset)
+ {
+ this.pac = pac;
+ this.offset = offset;
+ }
+
+ final void advance(int length) {
+ offset += length;
+ }
+
+ final int getOffset() {
+ return offset;
+ }
+
+ public byte unpackByte() throws IOException, MessageTypeException {
+ return pac.impl.unpackByte(this, offset);
+ }
+
+ public short unpackShort() throws IOException, MessageTypeException {
+ return pac.impl.unpackShort(this, offset);
+ }
+
+ public int unpackInt() throws IOException, MessageTypeException {
+ return pac.impl.unpackInt(this, offset);
+ }
+
+ public long unpackLong() throws IOException, MessageTypeException {
+ return pac.impl.unpackLong(this, offset);
+ }
+
+ public float unpackFloat() throws IOException, MessageTypeException {
+ return pac.impl.unpackFloat(this, offset);
+ }
+
+ public double unpackDouble() throws IOException, MessageTypeException {
+ return pac.impl.unpackDouble(this, offset);
+ }
+
+ public Object unpackNull() throws IOException, MessageTypeException {
+ return pac.impl.unpackNull(this, offset);
+ }
+
+ public boolean unpackBoolean() throws IOException, MessageTypeException {
+ return pac.impl.unpackBoolean(this, offset);
+ }
+
+ public int unpackArray() throws IOException, MessageTypeException {
+ return pac.impl.unpackArray(this, offset);
+ }
+
+ public int unpackMap() throws IOException, MessageTypeException {
+ return pac.impl.unpackMap(this, offset);
+ }
+
+ public int unpackRaw() throws IOException, MessageTypeException {
+ return pac.impl.unpackRaw(this, offset);
+ }
+
+ public byte[] unpackRawBody(int length) throws IOException, MessageTypeException {
+ return pac.impl.unpackRawBody(this, offset, length);
+ }
+
+ public String unpackString() throws IOException, MessageTypeException {
+ return pac.impl.unpackString(this, offset);
+ }
+
+ public void commit() {
+ pac.setOffset(offset);
+ }
+}
+
diff --git a/java/src/main/java/org/msgpack/UnpackIterator.java b/java/src/main/java/org/msgpack/UnpackIterator.java
index 0a78e83..5cc994d 100644
--- a/java/src/main/java/org/msgpack/UnpackIterator.java
+++ b/java/src/main/java/org/msgpack/UnpackIterator.java
@@ -21,41 +21,27 @@ import java.io.IOException;
import java.util.Iterator;
import java.util.NoSuchElementException;
-public class UnpackIterator implements Iterator<Object> {
+public class UnpackIterator extends UnpackResult implements Iterator<Object> {
private Unpacker pac;
- private boolean have;
- private Object data;
UnpackIterator(Unpacker pac) {
+ super();
this.pac = pac;
- this.have = false;
}
public boolean hasNext() {
- if(have) { return true; }
try {
- while(true) {
- if(pac.execute()) {
- data = pac.getData();
- pac.reset();
- have = true;
- return true;
- }
-
- if(!pac.fill()) {
- return false;
- }
- }
+ return pac.next(this);
} catch (IOException e) {
return false;
}
}
public Object next() {
- if(!have && !hasNext()) {
+ if(!finished && !hasNext()) {
throw new NoSuchElementException();
}
- have = false;
+ finished = false;
return data;
}
diff --git a/java/src/main/java/org/msgpack/UnpackResult.java b/java/src/main/java/org/msgpack/UnpackResult.java
new file mode 100644
index 0000000..cec18a1
--- /dev/null
+++ b/java/src/main/java/org/msgpack/UnpackResult.java
@@ -0,0 +1,42 @@
+//
+// MessagePack for Java
+//
+// Copyright (C) 2009-2010 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 org.msgpack;
+
+public class UnpackResult {
+ protected boolean finished = false;
+ protected Object data = null;
+
+ public boolean isFinished() {
+ return finished;
+ }
+
+ public Object getData() {
+ return data;
+ }
+
+ public void reset() {
+ finished = false;
+ data = null;
+ }
+
+ void done(Object obj) {
+ finished = true;
+ data = obj;
+ }
+}
+
diff --git a/java/src/main/java/org/msgpack/Unpacker.java b/java/src/main/java/org/msgpack/Unpacker.java
index c8a8823..20a8c4a 100644
--- a/java/src/main/java/org/msgpack/Unpacker.java
+++ b/java/src/main/java/org/msgpack/Unpacker.java
@@ -22,18 +22,43 @@ import java.io.InputStream;
import java.io.IOException;
import java.util.Iterator;
import java.nio.ByteBuffer;
-import org.msgpack.impl.UnpackerImpl;
-public class Unpacker extends UnpackerImpl implements Iterable<Object> {
+public class Unpacker implements Iterable<Object> {
+
+ // buffer:
+ // +---------------------------------------------+
+ // | [object] | [obje| unparsed ... | unused ...|
+ // +---------------------------------------------+
+ // ^ parsed
+ // ^ offset
+ // ^ filled
+ // ^ buffer.length
+
+ private static final int DEFAULT_BUFFER_SIZE = 32*1024;
+
+ protected int offset;
+ protected int parsed;
+ protected int bufferReserveSize;
+ protected InputStream stream;
+
+ class BufferedUnpackerMixin extends BufferedUnpackerImpl {
+ boolean fill() throws IOException {
+ if(stream == null) {
+ return false;
+ }
+ reserveBuffer(bufferReserveSize);
+ int rl = stream.read(buffer, filled, buffer.length - filled);
+ // equals: stream.read(getBuffer(), getBufferOffset(), getBufferCapacity());
+ if(rl <= 0) {
+ return false;
+ }
+ bufferConsumed(rl);
+ return true;
+ }
+ };
- public static final int DEFAULT_BUFFER_SIZE = 32*1024;
+ final BufferedUnpackerMixin impl = new BufferedUnpackerMixin();
- private int used;
- private int offset;
- private int parsed;
- private byte[] buffer;
- private int bufferReserveSize;
- private InputStream stream;
public Unpacker() {
this(DEFAULT_BUFFER_SIZE);
@@ -48,67 +73,31 @@ public class Unpacker extends UnpackerImpl implements Iterable<Object> {
}
public Unpacker(InputStream stream, int bufferReserveSize) {
- super();
- this.used = 0;
this.offset = 0;
this.parsed = 0;
- this.buffer = new byte[bufferReserveSize];
this.bufferReserveSize = bufferReserveSize/2;
this.stream = stream;
}
public Unpacker useSchema(Schema s) {
- super.setSchema(s);
+ impl.setSchema(s);
return this;
}
- public void reserveBuffer(int size) {
- if(buffer.length - used >= size) {
- return;
- }
- /*
- if(used == parsed && buffer.length >= size) {
- // rewind buffer
- used = 0;
- offset = 0;
- return;
- }
- */
-
- int nextSize = buffer.length * 2;
- while(nextSize < size + used) {
- nextSize *= 2;
- }
-
- byte[] tmp = new byte[nextSize];
- System.arraycopy(buffer, offset, tmp, 0, used - offset);
-
- buffer = tmp;
- used -= offset;
- offset = 0;
- }
-
- public byte[] getBuffer() {
- return buffer;
- }
-
- public int getBufferOffset() {
- return used;
- }
- public int getBufferCapacity() {
- return buffer.length - used;
+ public InputStream getStream() {
+ return this.stream;
}
- public void bufferConsumed(int size) {
- used += size;
+ public void setStream(InputStream stream) {
+ this.stream = stream;
}
public void feed(ByteBuffer buffer) {
int length = buffer.remaining();
if (length == 0) return;
reserveBuffer(length);
- buffer.get(this.buffer, this.offset, length);
+ buffer.get(impl.buffer, this.offset, length);
bufferConsumed(length);
}
@@ -118,48 +107,116 @@ public class Unpacker extends UnpackerImpl implements Iterable<Object> {
public void feed(byte[] buffer, int offset, int length) {
reserveBuffer(length);
- System.arraycopy(buffer, offset, this.buffer, this.offset, length);
+ System.arraycopy(buffer, offset, impl.buffer, this.offset, length);
bufferConsumed(length);
}
public boolean fill() throws IOException {
- if(stream == null) {
- return false;
- }
- reserveBuffer(bufferReserveSize);
- int rl = stream.read(getBuffer(), getBufferOffset(), getBufferCapacity());
- if(rl <= 0) {
- return false;
- }
- bufferConsumed(rl);
- return true;
+ return impl.fill();
}
public Iterator<Object> iterator() {
return new UnpackIterator(this);
}
+ public UnpackResult next() throws IOException, UnpackException {
+ UnpackResult result = new UnpackResult();
+ this.offset = impl.next(this.offset, result);
+ return result;
+ }
+
+ public boolean next(UnpackResult result) throws IOException, UnpackException {
+ this.offset = impl.next(this.offset, result);
+ return result.isFinished();
+ }
+
+
+ public void reserveBuffer(int require) {
+ if(impl.buffer == null) {
+ int nextSize = (bufferReserveSize < require) ? require : bufferReserveSize;
+ impl.buffer = new byte[nextSize];
+ return;
+ }
+
+ if(impl.buffer.length - impl.filled >= require) {
+ return;
+ }
+
+ int nextSize = impl.buffer.length * 2;
+ int notParsed = impl.filled - this.offset;
+ while(nextSize < require + notParsed) {
+ nextSize *= 2;
+ }
+
+ byte[] tmp = new byte[nextSize];
+ System.arraycopy(impl.buffer, this.offset, tmp, 0, impl.filled - this.offset);
+
+ impl.buffer = tmp;
+ impl.filled = notParsed;
+ this.offset = 0;
+ }
+
+ public byte[] getBuffer() {
+ return impl.buffer;
+ }
+
+ public int getBufferOffset() {
+ return impl.filled;
+ }
+
+ public int getBufferCapacity() {
+ return impl.buffer.length - impl.filled;
+ }
+
+ public void bufferConsumed(int size) {
+ impl.filled += size;
+ }
+
public boolean execute() throws UnpackException {
- int noffset = super.execute(buffer, offset, used);
+ int noffset = impl.execute(impl.buffer, offset, impl.filled);
if(noffset <= offset) {
return false;
}
parsed += noffset - offset;
offset = noffset;
- return super.isFinished();
+ return impl.isFinished();
+ }
+
+
+ public int execute(byte[] buffer) throws UnpackException {
+ return execute(buffer, 0, buffer.length);
+ }
+
+ public int execute(byte[] buffer, int offset, int length) throws UnpackException {
+ int noffset = impl.execute(buffer, offset + this.offset, length);
+ this.offset = noffset - offset;
+ if(impl.isFinished()) {
+ impl.resetState();
+ }
+ return noffset;
+ }
+
+ public boolean isFinished() {
+ return impl.isFinished();
}
public Object getData() {
- return super.getData();
+ return impl.getData();
}
public void reset() {
- super.reset();
- parsed = 0;
+ impl.reset();
+ }
+
+
+ public UnpackCursor begin()
+ {
+ return new UnpackCursor(this, offset);
}
+
public int getMessageSize() {
- return parsed - offset + used;
+ return parsed - offset + impl.filled;
}
public int getParsedSize() {
@@ -167,7 +224,7 @@ public class Unpacker extends UnpackerImpl implements Iterable<Object> {
}
public int getNonParsedSize() {
- return used - offset;
+ return impl.filled - offset;
}
public void skipNonparsedBuffer(int size) {
@@ -175,80 +232,14 @@ public class Unpacker extends UnpackerImpl implements Iterable<Object> {
}
public void removeNonparsedBuffer() {
- used = offset;
+ impl.filled = offset;
}
- /*
- public static class Context {
- private boolean finished;
- private Object data;
- private int offset;
- private UnpackerImpl impl;
- public Context()
- {
- this.finished = false;
- this.impl = new UnpackerImpl();
- }
-
- public boolean isFinished()
- {
- return finished;
- }
-
- public Object getData()
- {
- return data;
- }
-
- int getOffset()
- {
- return offset;
- }
-
- void setFinished(boolean finished)
- {
- this.finished = finished;
- }
-
- void setData(Object data)
- {
- this.data = data;
- }
-
- void setOffset(int offset)
- {
- this.offset = offset;
- }
-
- UnpackerImpl getImpl()
- {
- return impl;
- }
- }
-
- public static int unpack(Context ctx, byte[] buffer) throws UnpackException
+ void setOffset(int offset)
{
- return unpack(ctx, buffer, 0, buffer.length);
- }
-
- public static int unpack(Context ctx, byte[] buffer, int offset, int length) throws UnpackException
- {
- UnpackerImpl impl = ctx.getImpl();
- int noffset = impl.execute(buffer, offset + ctx.getOffset(), length);
- ctx.setOffset(noffset - offset);
- if(impl.isFinished()) {
- ctx.setData(impl.getData());
- ctx.setFinished(false);
- impl.reset();
- } else {
- ctx.setData(null);
- ctx.setFinished(true);
- }
- int parsed = noffset - offset;
- ctx.setOffset(parsed);
- return noffset;
+ parsed += offset - this.offset;
+ this.offset = offset;
}
- */
}
diff --git a/java/src/main/java/org/msgpack/impl/UnpackerImpl.java b/java/src/main/java/org/msgpack/UnpackerImpl.java
index adc62b0..ae01289 100644
--- a/java/src/main/java/org/msgpack/impl/UnpackerImpl.java
+++ b/java/src/main/java/org/msgpack/UnpackerImpl.java
@@ -15,7 +15,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
//
-package org.msgpack.impl;
+package org.msgpack;
import java.nio.ByteBuffer;
//import java.math.BigInteger;
@@ -47,7 +47,7 @@ public class UnpackerImpl {
static final int CT_MAP_KEY = 0x01;
static final int CT_MAP_VALUE = 0x02;
- static final int MAX_STACK_SIZE = 16;
+ static final int MAX_STACK_SIZE = 32;
private int cs;
private int trail;
@@ -67,41 +67,45 @@ public class UnpackerImpl {
private static final Schema GENERIC_SCHEMA = new GenericSchema();
private Schema rootSchema;
- protected UnpackerImpl()
+ public UnpackerImpl()
{
setSchema(GENERIC_SCHEMA);
}
- protected void setSchema(Schema schema)
+ public void setSchema(Schema schema)
{
this.rootSchema = schema;
reset();
}
- protected Object getData()
+ public final Object getData()
{
return data;
}
- protected boolean isFinished()
+ public final boolean isFinished()
{
return finished;
}
- protected void reset()
- {
+ public final void resetState() {
cs = CS_HEADER;
top = -1;
- finished = false;
- data = null;
top_ct = 0;
top_count = 0;
top_obj = null;
top_schema = rootSchema;
}
+ public final void reset()
+ {
+ resetState();
+ finished = false;
+ data = null;
+ }
+
@SuppressWarnings("unchecked")
- protected int execute(byte[] src, int off, int length) throws UnpackException
+ public final int execute(byte[] src, int off, int length) throws UnpackException
{
if(off >= length) { return off; }
diff --git a/java/src/test/java/org/msgpack/TestDirectConversion.java b/java/src/test/java/org/msgpack/TestDirectConversion.java
new file mode 100644
index 0000000..d77fe13
--- /dev/null
+++ b/java/src/test/java/org/msgpack/TestDirectConversion.java
@@ -0,0 +1,154 @@
+package org.msgpack;
+
+import org.msgpack.*;
+import java.io.*;
+import java.util.*;
+
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+public class TestDirectConversion {
+ private UnpackCursor prepareCursor(ByteArrayOutputStream out) {
+ ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+ Unpacker upk = new Unpacker(in);
+ return upk.begin();
+ }
+
+ @Test
+ public void testInt() throws Exception {
+ testInt(0);
+ testInt(-1);
+ testInt(1);
+ testInt(Integer.MIN_VALUE);
+ testInt(Integer.MAX_VALUE);
+ Random rand = new Random();
+ for (int i = 0; i < 1000; i++)
+ testInt(rand.nextInt());
+ }
+ public void testInt(int val) throws Exception {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ new Packer(out).pack(val);
+ UnpackCursor c = prepareCursor(out);
+ assertEquals(val, c.unpackInt());
+ c.commit();
+ }
+
+ @Test
+ public void testFloat() throws Exception {
+ testFloat((float)0.0);
+ testFloat((float)-0.0);
+ testFloat((float)1.0);
+ testFloat((float)-1.0);
+ testFloat((float)Float.MAX_VALUE);
+ testFloat((float)Float.MIN_VALUE);
+ testFloat((float)Float.NaN);
+ testFloat((float)Float.NEGATIVE_INFINITY);
+ testFloat((float)Float.POSITIVE_INFINITY);
+ Random rand = new Random();
+ for (int i = 0; i < 1000; i++)
+ testFloat(rand.nextFloat());
+ }
+ public void testFloat(float val) throws Exception {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ new Packer(out).pack(val);
+ UnpackCursor c = prepareCursor(out);
+ float f = c.unpackFloat();
+ if(Float.isNaN(val)) {
+ assertTrue(Float.isNaN(f));
+ } else {
+ assertEquals(val, f, 10e-10);
+ }
+ c.commit();
+ }
+
+ @Test
+ public void testDouble() throws Exception {
+ testDouble((double)0.0);
+ testDouble((double)-0.0);
+ testDouble((double)1.0);
+ testDouble((double)-1.0);
+ testDouble((double)Double.MAX_VALUE);
+ testDouble((double)Double.MIN_VALUE);
+ testDouble((double)Double.NaN);
+ testDouble((double)Double.NEGATIVE_INFINITY);
+ testDouble((double)Double.POSITIVE_INFINITY);
+ Random rand = new Random();
+ for (int i = 0; i < 1000; i++)
+ testDouble(rand.nextDouble());
+ }
+ public void testDouble(double val) throws Exception {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ new Packer(out).pack(val);
+ UnpackCursor c = prepareCursor(out);
+ double f = c.unpackDouble();
+ if(Double.isNaN(val)) {
+ assertTrue(Double.isNaN(f));
+ } else {
+ assertEquals(val, f, 10e-10);
+ }
+ c.commit();
+ }
+
+ @Test
+ public void testNil() throws Exception {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ new Packer(out).packNil();
+ UnpackCursor c = prepareCursor(out);
+ assertEquals(null, c.unpackNull());
+ c.commit();
+ }
+
+ @Test
+ public void testBoolean() throws Exception {
+ testBoolean(false);
+ testBoolean(true);
+ }
+ public void testBoolean(boolean val) throws Exception {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ new Packer(out).pack(val);
+ UnpackCursor c = prepareCursor(out);
+ assertEquals(val, c.unpackBoolean());
+ c.commit();
+ }
+
+ @Test
+ public void testString() throws Exception {
+ testString("");
+ testString("a");
+ testString("ab");
+ testString("abc");
+ // small size string
+ for (int i = 0; i < 100; i++) {
+ StringBuilder sb = new StringBuilder();
+ int len = (int)Math.random() % 31 + 1;
+ for (int j = 0; j < len; j++)
+ sb.append('a' + ((int)Math.random()) & 26);
+ testString(sb.toString());
+ }
+ // medium size string
+ for (int i = 0; i < 100; i++) {
+ StringBuilder sb = new StringBuilder();
+ int len = (int)Math.random() % 100 + (1 << 15);
+ for (int j = 0; j < len; j++)
+ sb.append('a' + ((int)Math.random()) & 26);
+ testString(sb.toString());
+ }
+ // large size string
+ for (int i = 0; i < 10; i++) {
+ StringBuilder sb = new StringBuilder();
+ int len = (int)Math.random() % 100 + (1 << 31);
+ for (int j = 0; j < len; j++)
+ sb.append('a' + ((int)Math.random()) & 26);
+ testString(sb.toString());
+ }
+ }
+ public void testString(String val) throws Exception {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ new Packer(out).pack(val);
+ UnpackCursor c = prepareCursor(out);
+ assertEquals(val, c.unpackString());
+ c.commit();
+ }
+
+ // FIXME container types
+};
diff --git a/java/src/test/java/org/msgpack/TestPackUnpack.java b/java/src/test/java/org/msgpack/TestPackUnpack.java
index 6877853..a16b5b1 100644
--- a/java/src/test/java/org/msgpack/TestPackUnpack.java
+++ b/java/src/test/java/org/msgpack/TestPackUnpack.java
@@ -237,5 +237,5 @@ public class TestPackUnpack {
System.out.println("Got unexpected class: " + obj.getClass());
assertTrue(false);
}
- }
+ }
};