From 979ff809827ab25005364dad41d2fd043b8eaa4d Mon Sep 17 00:00:00 2001 From: frsyuki Date: Thu, 20 May 2010 03:49:26 +0900 Subject: java: redesign --- .../java/org/msgpack/BufferedUnpackerImpl.java | 384 ++++++++++++++++ .../main/java/org/msgpack/MessageConvertable.java | 23 + .../main/java/org/msgpack/MessageMergeable.java | 23 - .../java/org/msgpack/MessageTypeException.java | 4 +- .../main/java/org/msgpack/MessageUnpackable.java | 25 + java/src/main/java/org/msgpack/Packer.java | 2 +- .../main/java/org/msgpack/UnbufferedUnpacker.java | 82 ---- java/src/main/java/org/msgpack/UnpackCursor.java | 96 ++++ java/src/main/java/org/msgpack/UnpackIterator.java | 24 +- java/src/main/java/org/msgpack/UnpackResult.java | 42 ++ java/src/main/java/org/msgpack/Unpacker.java | 269 ++++++----- java/src/main/java/org/msgpack/UnpackerImpl.java | 504 +++++++++++++++++++++ .../main/java/org/msgpack/impl/UnpackerImpl.java | 500 -------------------- .../java/org/msgpack/TestDirectConversion.java | 154 +++++++ java/src/test/java/org/msgpack/TestPackUnpack.java | 2 +- 15 files changed, 1366 insertions(+), 768 deletions(-) create mode 100644 java/src/main/java/org/msgpack/BufferedUnpackerImpl.java create mode 100644 java/src/main/java/org/msgpack/MessageConvertable.java delete mode 100644 java/src/main/java/org/msgpack/MessageMergeable.java create mode 100644 java/src/main/java/org/msgpack/MessageUnpackable.java delete mode 100644 java/src/main/java/org/msgpack/UnbufferedUnpacker.java create mode 100644 java/src/main/java/org/msgpack/UnpackCursor.java create mode 100644 java/src/main/java/org/msgpack/UnpackResult.java create mode 100644 java/src/main/java/org/msgpack/UnpackerImpl.java delete mode 100644 java/src/main/java/org/msgpack/impl/UnpackerImpl.java create mode 100644 java/src/test/java/org/msgpack/TestDirectConversion.java (limited to 'java/src') 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/MessageConvertable.java b/java/src/main/java/org/msgpack/MessageConvertable.java new file mode 100644 index 0000000..da251dc --- /dev/null +++ b/java/src/main/java/org/msgpack/MessageConvertable.java @@ -0,0 +1,23 @@ +// +// 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 interface MessageConvertable { + public void messageConvert(Object obj) throws MessageTypeException; +} + diff --git a/java/src/main/java/org/msgpack/MessageMergeable.java b/java/src/main/java/org/msgpack/MessageMergeable.java deleted file mode 100644 index e5a5b45..0000000 --- a/java/src/main/java/org/msgpack/MessageMergeable.java +++ /dev/null @@ -1,23 +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; - -public interface MessageMergeable { - public void messageMerge(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 { +public class UnpackIterator extends UnpackResult implements Iterator { 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 { +public class Unpacker implements Iterable { + + // 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 { } 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 { 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 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 { } 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 { } 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/UnpackerImpl.java b/java/src/main/java/org/msgpack/UnpackerImpl.java new file mode 100644 index 0000000..ae01289 --- /dev/null +++ b/java/src/main/java/org/msgpack/UnpackerImpl.java @@ -0,0 +1,504 @@ +// +// 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.nio.ByteBuffer; +//import java.math.BigInteger; +import org.msgpack.*; +import org.msgpack.schema.GenericSchema; +import org.msgpack.schema.IMapSchema; +import org.msgpack.schema.IArraySchema; + +public class UnpackerImpl { + static final int CS_HEADER = 0x00; + static final int CS_FLOAT = 0x0a; + static final int CS_DOUBLE = 0x0b; + static final int CS_UINT_8 = 0x0c; + static final int CS_UINT_16 = 0x0d; + static final int CS_UINT_32 = 0x0e; + static final int CS_UINT_64 = 0x0f; + static final int CS_INT_8 = 0x10; + static final int CS_INT_16 = 0x11; + static final int CS_INT_32 = 0x12; + static final int CS_INT_64 = 0x13; + static final int CS_RAW_16 = 0x1a; + static final int CS_RAW_32 = 0x1b; + static final int CS_ARRAY_16 = 0x1c; + static final int CS_ARRAY_32 = 0x1d; + static final int CS_MAP_16 = 0x1e; + static final int CS_MAP_32 = 0x1f; + static final int ACS_RAW_VALUE = 0x20; + static final int CT_ARRAY_ITEM = 0x00; + static final int CT_MAP_KEY = 0x01; + static final int CT_MAP_VALUE = 0x02; + + static final int MAX_STACK_SIZE = 32; + + private int cs; + private int trail; + private int top; + private int[] stack_ct = new int[MAX_STACK_SIZE]; + private int[] stack_count = new int[MAX_STACK_SIZE]; + private Object[] stack_obj = new Object[MAX_STACK_SIZE]; + private Schema[] stack_schema = new Schema[MAX_STACK_SIZE]; + private int top_ct; + private int top_count; + private Object top_obj; + private Schema top_schema; + private ByteBuffer castBuffer = ByteBuffer.allocate(8); + private boolean finished = false; + private Object data = null; + + private static final Schema GENERIC_SCHEMA = new GenericSchema(); + private Schema rootSchema; + + public UnpackerImpl() + { + setSchema(GENERIC_SCHEMA); + } + + public void setSchema(Schema schema) + { + this.rootSchema = schema; + reset(); + } + + public final Object getData() + { + return data; + } + + public final boolean isFinished() + { + return finished; + } + + public final void resetState() { + cs = CS_HEADER; + top = -1; + top_ct = 0; + top_count = 0; + top_obj = null; + top_schema = rootSchema; + } + + public final void reset() + { + resetState(); + finished = false; + data = null; + } + + @SuppressWarnings("unchecked") + public final int execute(byte[] src, int off, int length) throws UnpackException + { + if(off >= length) { return off; } + + int limit = length; + int i = off; + int count; + + Object obj = null; + + _out: do { + _header_again: { + //System.out.println("while i:"+i+" limit:"+limit); + + int b = src[i]; + + _push: { + _fixed_trail_again: + if(cs == CS_HEADER) { + + if((b & 0x80) == 0) { // Positive Fixnum + //System.out.println("positive fixnum "+b); + obj = top_schema.createFromByte((byte)b); + break _push; + } + + if((b & 0xe0) == 0xe0) { // Negative Fixnum + //System.out.println("negative fixnum "+b); + obj = top_schema.createFromByte((byte)b); + break _push; + } + + if((b & 0xe0) == 0xa0) { // FixRaw + trail = b & 0x1f; + if(trail == 0) { + obj = top_schema.createFromRaw(new byte[0], 0, 0); + break _push; + } + cs = ACS_RAW_VALUE; + break _fixed_trail_again; + } + + if((b & 0xf0) == 0x90) { // FixArray + if(top >= MAX_STACK_SIZE) { + throw new UnpackException("parse error"); + } + if(!(top_schema instanceof IArraySchema)) { + throw new RuntimeException("type error"); + } + count = b & 0x0f; + //System.out.println("fixarray count:"+count); + obj = new Object[count]; + if(count == 0) { break _push; } // FIXME check IArraySchema + ++top; + stack_obj[top] = top_obj; + stack_ct[top] = top_ct; + stack_count[top] = top_count; + stack_schema[top] = top_schema; + top_obj = obj; + top_ct = CT_ARRAY_ITEM; + top_count = count; + top_schema = ((IArraySchema)top_schema).getElementSchema(0); + break _header_again; + } + + if((b & 0xf0) == 0x80) { // FixMap + if(top >= MAX_STACK_SIZE) { + throw new UnpackException("parse error"); + } + if(!(top_schema instanceof IMapSchema)) { + throw new RuntimeException("type error"); + } + count = b & 0x0f; + obj = new Object[count*2]; + if(count == 0) { break _push; } // FIXME check IMapSchema + //System.out.println("fixmap count:"+count); + ++top; + stack_obj[top] = top_obj; + stack_ct[top] = top_ct; + stack_count[top] = top_count; + stack_schema[top] = top_schema; + top_obj = obj; + top_ct = CT_MAP_KEY; + top_count = count; + top_schema = ((IMapSchema)top_schema).getKeySchema(); + break _header_again; + } + + switch(b & 0xff) { // FIXME + case 0xc0: // nil + obj = top_schema.createFromNil(); + break _push; + case 0xc2: // false + obj = top_schema.createFromBoolean(false); + break _push; + case 0xc3: // true + obj = top_schema.createFromBoolean(true); + break _push; + case 0xca: // float + case 0xcb: // double + case 0xcc: // unsigned int 8 + case 0xcd: // unsigned int 16 + case 0xce: // unsigned int 32 + case 0xcf: // unsigned int 64 + case 0xd0: // signed int 8 + case 0xd1: // signed int 16 + case 0xd2: // signed int 32 + case 0xd3: // signed int 64 + trail = 1 << (b & 0x03); + cs = b & 0x1f; + //System.out.println("a trail "+trail+" cs:"+cs); + break _fixed_trail_again; + case 0xda: // raw 16 + case 0xdb: // raw 32 + case 0xdc: // array 16 + case 0xdd: // array 32 + case 0xde: // map 16 + case 0xdf: // map 32 + trail = 2 << (b & 0x01); + cs = b & 0x1f; + //System.out.println("b trail "+trail+" cs:"+cs); + break _fixed_trail_again; + default: + //System.out.println("unknown b "+(b&0xff)); + throw new UnpackException("parse error"); + } + + } // _fixed_trail_again + + do { + _fixed_trail_again: { + + if(limit - i <= trail) { break _out; } + int n = i + 1; + i += trail; + + switch(cs) { + case CS_FLOAT: + castBuffer.rewind(); + castBuffer.put(src, n, 4); + obj = top_schema.createFromFloat( castBuffer.getFloat(0) ); + //System.out.println("float "+obj); + break _push; + case CS_DOUBLE: + castBuffer.rewind(); + castBuffer.put(src, n, 8); + obj = top_schema.createFromDouble( castBuffer.getDouble(0) ); + //System.out.println("double "+obj); + break _push; + case CS_UINT_8: + //System.out.println(n); + //System.out.println(src[n]); + //System.out.println(src[n+1]); + //System.out.println(src[n-1]); + obj = top_schema.createFromShort( (short)((src[n]) & 0xff) ); + //System.out.println("uint8 "+obj); + break _push; + case CS_UINT_16: + //System.out.println(src[n]); + //System.out.println(src[n+1]); + castBuffer.rewind(); + castBuffer.put(src, n, 2); + obj = top_schema.createFromInt( ((int)castBuffer.getShort(0)) & 0xffff ); + //System.out.println("uint 16 "+obj); + break _push; + case CS_UINT_32: + castBuffer.rewind(); + castBuffer.put(src, n, 4); + obj = top_schema.createFromLong( ((long)castBuffer.getInt(0)) & 0xffffffffL ); + //System.out.println("uint 32 "+obj); + break _push; + case CS_UINT_64: + castBuffer.rewind(); + castBuffer.put(src, n, 8); + { + long o = castBuffer.getLong(0); + if(o < 0) { + // FIXME + //obj = GenericBigInteger.valueOf(o & 0x7fffffffL).setBit(31); + throw new UnpackException("uint 64 bigger than 0x7fffffff is not supported"); + } else { + obj = top_schema.createFromLong( o ); + } + } + break _push; + case CS_INT_8: + obj = top_schema.createFromByte( src[n] ); + break _push; + case CS_INT_16: + castBuffer.rewind(); + castBuffer.put(src, n, 2); + obj = top_schema.createFromShort( castBuffer.getShort(0) ); + break _push; + case CS_INT_32: + castBuffer.rewind(); + castBuffer.put(src, n, 4); + obj = top_schema.createFromInt( castBuffer.getInt(0) ); + break _push; + case CS_INT_64: + castBuffer.rewind(); + castBuffer.put(src, n, 8); + obj = top_schema.createFromLong( castBuffer.getLong(0) ); + break _push; + case CS_RAW_16: + castBuffer.rewind(); + castBuffer.put(src, n, 2); + trail = ((int)castBuffer.getShort(0)) & 0xffff; + if(trail == 0) { + obj = top_schema.createFromRaw(new byte[0], 0, 0); + break _push; + } + cs = ACS_RAW_VALUE; + break _fixed_trail_again; + case CS_RAW_32: + castBuffer.rewind(); + castBuffer.put(src, n, 4); + // FIXME overflow check + trail = castBuffer.getInt(0) & 0x7fffffff; + if(trail == 0) { + obj = top_schema.createFromRaw(new byte[0], 0, 0); + break _push; + } + cs = ACS_RAW_VALUE; + case ACS_RAW_VALUE: + obj = top_schema.createFromRaw(src, n, trail); + break _push; + case CS_ARRAY_16: + if(top >= MAX_STACK_SIZE) { + throw new UnpackException("parse error"); + } + if(!(top_schema instanceof IArraySchema)) { + throw new RuntimeException("type error"); + } + castBuffer.rewind(); + castBuffer.put(src, n, 2); + count = ((int)castBuffer.getShort(0)) & 0xffff; + obj = new Object[count]; + if(count == 0) { break _push; } // FIXME check IArraySchema + ++top; + stack_obj[top] = top_obj; + stack_ct[top] = top_ct; + stack_count[top] = top_count; + stack_schema[top] = top_schema; + top_obj = obj; + top_ct = CT_ARRAY_ITEM; + top_count = count; + top_schema = ((IArraySchema)top_schema).getElementSchema(0); + break _header_again; + case CS_ARRAY_32: + if(top >= MAX_STACK_SIZE) { + throw new UnpackException("parse error"); + } + if(!(top_schema instanceof IArraySchema)) { + throw new RuntimeException("type error"); + } + castBuffer.rewind(); + castBuffer.put(src, n, 4); + // FIXME overflow check + count = castBuffer.getInt(0) & 0x7fffffff; + obj = new Object[count]; + if(count == 0) { break _push; } // FIXME check IArraySchema + ++top; + stack_obj[top] = top_obj; + stack_ct[top] = top_ct; + stack_count[top] = top_count; + stack_schema[top] = top_schema; + top_obj = obj; + top_ct = CT_ARRAY_ITEM; + top_count = count; + top_schema = ((IArraySchema)top_schema).getElementSchema(0); + break _header_again; + case CS_MAP_16: + if(top >= MAX_STACK_SIZE) { + throw new UnpackException("parse error"); + } + if(!(top_schema instanceof IMapSchema)) { + throw new RuntimeException("type error"); + } + castBuffer.rewind(); + castBuffer.put(src, n, 2); + count = ((int)castBuffer.getShort(0)) & 0xffff; + obj = new Object[count*2]; + if(count == 0) { break _push; } // FIXME check IMapSchema + //System.out.println("fixmap count:"+count); + ++top; + stack_obj[top] = top_obj; + stack_ct[top] = top_ct; + stack_count[top] = top_count; + stack_schema[top] = top_schema; + top_obj = obj; + top_ct = CT_MAP_KEY; + top_count = count; + top_schema = ((IMapSchema)top_schema).getKeySchema(); + break _header_again; + case CS_MAP_32: + if(top >= MAX_STACK_SIZE) { + throw new UnpackException("parse error"); + } + if(!(top_schema instanceof IMapSchema)) { + throw new RuntimeException("type error"); + } + castBuffer.rewind(); + castBuffer.put(src, n, 4); + // FIXME overflow check + count = castBuffer.getInt(0) & 0x7fffffff; + obj = new Object[count*2]; + if(count == 0) { break _push; } // FIXME check IMapSchema + //System.out.println("fixmap count:"+count); + ++top; + stack_obj[top] = top_obj; + stack_ct[top] = top_ct; + stack_count[top] = top_count; + stack_schema[top] = top_schema; + top_obj = obj; + top_ct = CT_MAP_KEY; + top_count = count; + top_schema = ((IMapSchema)top_schema).getKeySchema(); + break _header_again; + default: + throw new UnpackException("parse error"); + } + + } // _fixed_trail_again + } while(true); + } // _push + + do { + _push: { + //System.out.println("push top:"+top); + if(top == -1) { + ++i; + data = obj; + finished = true; + break _out; + } + + switch(top_ct) { + case CT_ARRAY_ITEM: { + //System.out.println("array item "+obj); + Object[] ar = (Object[])top_obj; + ar[ar.length - top_count] = obj; + if(--top_count == 0) { + top_obj = stack_obj[top]; + top_ct = stack_ct[top]; + top_count = stack_count[top]; + top_schema = stack_schema[top]; + obj = ((IArraySchema)top_schema).createFromArray(ar); + stack_obj[top] = null; + stack_schema[top] = null; + --top; + break _push; + } else { + top_schema = ((IArraySchema)stack_schema[top]).getElementSchema(ar.length - top_count); + } + break _header_again; + } + case CT_MAP_KEY: { + //System.out.println("map key:"+top+" "+obj); + Object[] mp = (Object[])top_obj; + mp[mp.length - top_count*2] = obj; + top_ct = CT_MAP_VALUE; + top_schema = ((IMapSchema)stack_schema[top]).getValueSchema(); + break _header_again; + } + case CT_MAP_VALUE: { + //System.out.println("map value:"+top+" "+obj); + Object[] mp = (Object[])top_obj; + mp[mp.length - top_count*2 + 1] = obj; + if(--top_count == 0) { + top_obj = stack_obj[top]; + top_ct = stack_ct[top]; + top_count = stack_count[top]; + top_schema = stack_schema[top]; + obj = ((IMapSchema)top_schema).createFromMap(mp); + stack_obj[top] = null; + stack_schema[top] = null; + --top; + break _push; + } + top_ct = CT_MAP_KEY; + break _header_again; + } + default: + throw new UnpackException("parse error"); + } + } // _push + } while(true); + + } // _header_again + cs = CS_HEADER; + ++i; + } while(i < limit); // _out + + return i; + } +} + diff --git a/java/src/main/java/org/msgpack/impl/UnpackerImpl.java b/java/src/main/java/org/msgpack/impl/UnpackerImpl.java deleted file mode 100644 index adc62b0..0000000 --- a/java/src/main/java/org/msgpack/impl/UnpackerImpl.java +++ /dev/null @@ -1,500 +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.impl; - -import java.nio.ByteBuffer; -//import java.math.BigInteger; -import org.msgpack.*; -import org.msgpack.schema.GenericSchema; -import org.msgpack.schema.IMapSchema; -import org.msgpack.schema.IArraySchema; - -public class UnpackerImpl { - static final int CS_HEADER = 0x00; - static final int CS_FLOAT = 0x0a; - static final int CS_DOUBLE = 0x0b; - static final int CS_UINT_8 = 0x0c; - static final int CS_UINT_16 = 0x0d; - static final int CS_UINT_32 = 0x0e; - static final int CS_UINT_64 = 0x0f; - static final int CS_INT_8 = 0x10; - static final int CS_INT_16 = 0x11; - static final int CS_INT_32 = 0x12; - static final int CS_INT_64 = 0x13; - static final int CS_RAW_16 = 0x1a; - static final int CS_RAW_32 = 0x1b; - static final int CS_ARRAY_16 = 0x1c; - static final int CS_ARRAY_32 = 0x1d; - static final int CS_MAP_16 = 0x1e; - static final int CS_MAP_32 = 0x1f; - static final int ACS_RAW_VALUE = 0x20; - static final int CT_ARRAY_ITEM = 0x00; - static final int CT_MAP_KEY = 0x01; - static final int CT_MAP_VALUE = 0x02; - - static final int MAX_STACK_SIZE = 16; - - private int cs; - private int trail; - private int top; - private int[] stack_ct = new int[MAX_STACK_SIZE]; - private int[] stack_count = new int[MAX_STACK_SIZE]; - private Object[] stack_obj = new Object[MAX_STACK_SIZE]; - private Schema[] stack_schema = new Schema[MAX_STACK_SIZE]; - private int top_ct; - private int top_count; - private Object top_obj; - private Schema top_schema; - private ByteBuffer castBuffer = ByteBuffer.allocate(8); - private boolean finished = false; - private Object data = null; - - private static final Schema GENERIC_SCHEMA = new GenericSchema(); - private Schema rootSchema; - - protected UnpackerImpl() - { - setSchema(GENERIC_SCHEMA); - } - - protected void setSchema(Schema schema) - { - this.rootSchema = schema; - reset(); - } - - protected Object getData() - { - return data; - } - - protected boolean isFinished() - { - return finished; - } - - protected void reset() - { - cs = CS_HEADER; - top = -1; - finished = false; - data = null; - top_ct = 0; - top_count = 0; - top_obj = null; - top_schema = rootSchema; - } - - @SuppressWarnings("unchecked") - protected int execute(byte[] src, int off, int length) throws UnpackException - { - if(off >= length) { return off; } - - int limit = length; - int i = off; - int count; - - Object obj = null; - - _out: do { - _header_again: { - //System.out.println("while i:"+i+" limit:"+limit); - - int b = src[i]; - - _push: { - _fixed_trail_again: - if(cs == CS_HEADER) { - - if((b & 0x80) == 0) { // Positive Fixnum - //System.out.println("positive fixnum "+b); - obj = top_schema.createFromByte((byte)b); - break _push; - } - - if((b & 0xe0) == 0xe0) { // Negative Fixnum - //System.out.println("negative fixnum "+b); - obj = top_schema.createFromByte((byte)b); - break _push; - } - - if((b & 0xe0) == 0xa0) { // FixRaw - trail = b & 0x1f; - if(trail == 0) { - obj = top_schema.createFromRaw(new byte[0], 0, 0); - break _push; - } - cs = ACS_RAW_VALUE; - break _fixed_trail_again; - } - - if((b & 0xf0) == 0x90) { // FixArray - if(top >= MAX_STACK_SIZE) { - throw new UnpackException("parse error"); - } - if(!(top_schema instanceof IArraySchema)) { - throw new RuntimeException("type error"); - } - count = b & 0x0f; - //System.out.println("fixarray count:"+count); - obj = new Object[count]; - if(count == 0) { break _push; } // FIXME check IArraySchema - ++top; - stack_obj[top] = top_obj; - stack_ct[top] = top_ct; - stack_count[top] = top_count; - stack_schema[top] = top_schema; - top_obj = obj; - top_ct = CT_ARRAY_ITEM; - top_count = count; - top_schema = ((IArraySchema)top_schema).getElementSchema(0); - break _header_again; - } - - if((b & 0xf0) == 0x80) { // FixMap - if(top >= MAX_STACK_SIZE) { - throw new UnpackException("parse error"); - } - if(!(top_schema instanceof IMapSchema)) { - throw new RuntimeException("type error"); - } - count = b & 0x0f; - obj = new Object[count*2]; - if(count == 0) { break _push; } // FIXME check IMapSchema - //System.out.println("fixmap count:"+count); - ++top; - stack_obj[top] = top_obj; - stack_ct[top] = top_ct; - stack_count[top] = top_count; - stack_schema[top] = top_schema; - top_obj = obj; - top_ct = CT_MAP_KEY; - top_count = count; - top_schema = ((IMapSchema)top_schema).getKeySchema(); - break _header_again; - } - - switch(b & 0xff) { // FIXME - case 0xc0: // nil - obj = top_schema.createFromNil(); - break _push; - case 0xc2: // false - obj = top_schema.createFromBoolean(false); - break _push; - case 0xc3: // true - obj = top_schema.createFromBoolean(true); - break _push; - case 0xca: // float - case 0xcb: // double - case 0xcc: // unsigned int 8 - case 0xcd: // unsigned int 16 - case 0xce: // unsigned int 32 - case 0xcf: // unsigned int 64 - case 0xd0: // signed int 8 - case 0xd1: // signed int 16 - case 0xd2: // signed int 32 - case 0xd3: // signed int 64 - trail = 1 << (b & 0x03); - cs = b & 0x1f; - //System.out.println("a trail "+trail+" cs:"+cs); - break _fixed_trail_again; - case 0xda: // raw 16 - case 0xdb: // raw 32 - case 0xdc: // array 16 - case 0xdd: // array 32 - case 0xde: // map 16 - case 0xdf: // map 32 - trail = 2 << (b & 0x01); - cs = b & 0x1f; - //System.out.println("b trail "+trail+" cs:"+cs); - break _fixed_trail_again; - default: - //System.out.println("unknown b "+(b&0xff)); - throw new UnpackException("parse error"); - } - - } // _fixed_trail_again - - do { - _fixed_trail_again: { - - if(limit - i <= trail) { break _out; } - int n = i + 1; - i += trail; - - switch(cs) { - case CS_FLOAT: - castBuffer.rewind(); - castBuffer.put(src, n, 4); - obj = top_schema.createFromFloat( castBuffer.getFloat(0) ); - //System.out.println("float "+obj); - break _push; - case CS_DOUBLE: - castBuffer.rewind(); - castBuffer.put(src, n, 8); - obj = top_schema.createFromDouble( castBuffer.getDouble(0) ); - //System.out.println("double "+obj); - break _push; - case CS_UINT_8: - //System.out.println(n); - //System.out.println(src[n]); - //System.out.println(src[n+1]); - //System.out.println(src[n-1]); - obj = top_schema.createFromShort( (short)((src[n]) & 0xff) ); - //System.out.println("uint8 "+obj); - break _push; - case CS_UINT_16: - //System.out.println(src[n]); - //System.out.println(src[n+1]); - castBuffer.rewind(); - castBuffer.put(src, n, 2); - obj = top_schema.createFromInt( ((int)castBuffer.getShort(0)) & 0xffff ); - //System.out.println("uint 16 "+obj); - break _push; - case CS_UINT_32: - castBuffer.rewind(); - castBuffer.put(src, n, 4); - obj = top_schema.createFromLong( ((long)castBuffer.getInt(0)) & 0xffffffffL ); - //System.out.println("uint 32 "+obj); - break _push; - case CS_UINT_64: - castBuffer.rewind(); - castBuffer.put(src, n, 8); - { - long o = castBuffer.getLong(0); - if(o < 0) { - // FIXME - //obj = GenericBigInteger.valueOf(o & 0x7fffffffL).setBit(31); - throw new UnpackException("uint 64 bigger than 0x7fffffff is not supported"); - } else { - obj = top_schema.createFromLong( o ); - } - } - break _push; - case CS_INT_8: - obj = top_schema.createFromByte( src[n] ); - break _push; - case CS_INT_16: - castBuffer.rewind(); - castBuffer.put(src, n, 2); - obj = top_schema.createFromShort( castBuffer.getShort(0) ); - break _push; - case CS_INT_32: - castBuffer.rewind(); - castBuffer.put(src, n, 4); - obj = top_schema.createFromInt( castBuffer.getInt(0) ); - break _push; - case CS_INT_64: - castBuffer.rewind(); - castBuffer.put(src, n, 8); - obj = top_schema.createFromLong( castBuffer.getLong(0) ); - break _push; - case CS_RAW_16: - castBuffer.rewind(); - castBuffer.put(src, n, 2); - trail = ((int)castBuffer.getShort(0)) & 0xffff; - if(trail == 0) { - obj = top_schema.createFromRaw(new byte[0], 0, 0); - break _push; - } - cs = ACS_RAW_VALUE; - break _fixed_trail_again; - case CS_RAW_32: - castBuffer.rewind(); - castBuffer.put(src, n, 4); - // FIXME overflow check - trail = castBuffer.getInt(0) & 0x7fffffff; - if(trail == 0) { - obj = top_schema.createFromRaw(new byte[0], 0, 0); - break _push; - } - cs = ACS_RAW_VALUE; - case ACS_RAW_VALUE: - obj = top_schema.createFromRaw(src, n, trail); - break _push; - case CS_ARRAY_16: - if(top >= MAX_STACK_SIZE) { - throw new UnpackException("parse error"); - } - if(!(top_schema instanceof IArraySchema)) { - throw new RuntimeException("type error"); - } - castBuffer.rewind(); - castBuffer.put(src, n, 2); - count = ((int)castBuffer.getShort(0)) & 0xffff; - obj = new Object[count]; - if(count == 0) { break _push; } // FIXME check IArraySchema - ++top; - stack_obj[top] = top_obj; - stack_ct[top] = top_ct; - stack_count[top] = top_count; - stack_schema[top] = top_schema; - top_obj = obj; - top_ct = CT_ARRAY_ITEM; - top_count = count; - top_schema = ((IArraySchema)top_schema).getElementSchema(0); - break _header_again; - case CS_ARRAY_32: - if(top >= MAX_STACK_SIZE) { - throw new UnpackException("parse error"); - } - if(!(top_schema instanceof IArraySchema)) { - throw new RuntimeException("type error"); - } - castBuffer.rewind(); - castBuffer.put(src, n, 4); - // FIXME overflow check - count = castBuffer.getInt(0) & 0x7fffffff; - obj = new Object[count]; - if(count == 0) { break _push; } // FIXME check IArraySchema - ++top; - stack_obj[top] = top_obj; - stack_ct[top] = top_ct; - stack_count[top] = top_count; - stack_schema[top] = top_schema; - top_obj = obj; - top_ct = CT_ARRAY_ITEM; - top_count = count; - top_schema = ((IArraySchema)top_schema).getElementSchema(0); - break _header_again; - case CS_MAP_16: - if(top >= MAX_STACK_SIZE) { - throw new UnpackException("parse error"); - } - if(!(top_schema instanceof IMapSchema)) { - throw new RuntimeException("type error"); - } - castBuffer.rewind(); - castBuffer.put(src, n, 2); - count = ((int)castBuffer.getShort(0)) & 0xffff; - obj = new Object[count*2]; - if(count == 0) { break _push; } // FIXME check IMapSchema - //System.out.println("fixmap count:"+count); - ++top; - stack_obj[top] = top_obj; - stack_ct[top] = top_ct; - stack_count[top] = top_count; - stack_schema[top] = top_schema; - top_obj = obj; - top_ct = CT_MAP_KEY; - top_count = count; - top_schema = ((IMapSchema)top_schema).getKeySchema(); - break _header_again; - case CS_MAP_32: - if(top >= MAX_STACK_SIZE) { - throw new UnpackException("parse error"); - } - if(!(top_schema instanceof IMapSchema)) { - throw new RuntimeException("type error"); - } - castBuffer.rewind(); - castBuffer.put(src, n, 4); - // FIXME overflow check - count = castBuffer.getInt(0) & 0x7fffffff; - obj = new Object[count*2]; - if(count == 0) { break _push; } // FIXME check IMapSchema - //System.out.println("fixmap count:"+count); - ++top; - stack_obj[top] = top_obj; - stack_ct[top] = top_ct; - stack_count[top] = top_count; - stack_schema[top] = top_schema; - top_obj = obj; - top_ct = CT_MAP_KEY; - top_count = count; - top_schema = ((IMapSchema)top_schema).getKeySchema(); - break _header_again; - default: - throw new UnpackException("parse error"); - } - - } // _fixed_trail_again - } while(true); - } // _push - - do { - _push: { - //System.out.println("push top:"+top); - if(top == -1) { - ++i; - data = obj; - finished = true; - break _out; - } - - switch(top_ct) { - case CT_ARRAY_ITEM: { - //System.out.println("array item "+obj); - Object[] ar = (Object[])top_obj; - ar[ar.length - top_count] = obj; - if(--top_count == 0) { - top_obj = stack_obj[top]; - top_ct = stack_ct[top]; - top_count = stack_count[top]; - top_schema = stack_schema[top]; - obj = ((IArraySchema)top_schema).createFromArray(ar); - stack_obj[top] = null; - stack_schema[top] = null; - --top; - break _push; - } else { - top_schema = ((IArraySchema)stack_schema[top]).getElementSchema(ar.length - top_count); - } - break _header_again; - } - case CT_MAP_KEY: { - //System.out.println("map key:"+top+" "+obj); - Object[] mp = (Object[])top_obj; - mp[mp.length - top_count*2] = obj; - top_ct = CT_MAP_VALUE; - top_schema = ((IMapSchema)stack_schema[top]).getValueSchema(); - break _header_again; - } - case CT_MAP_VALUE: { - //System.out.println("map value:"+top+" "+obj); - Object[] mp = (Object[])top_obj; - mp[mp.length - top_count*2 + 1] = obj; - if(--top_count == 0) { - top_obj = stack_obj[top]; - top_ct = stack_ct[top]; - top_count = stack_count[top]; - top_schema = stack_schema[top]; - obj = ((IMapSchema)top_schema).createFromMap(mp); - stack_obj[top] = null; - stack_schema[top] = null; - --top; - break _push; - } - top_ct = CT_MAP_KEY; - break _header_again; - } - default: - throw new UnpackException("parse error"); - } - } // _push - } while(true); - - } // _header_again - cs = CS_HEADER; - ++i; - } while(i < limit); // _out - - return i; - } -} - 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); } - } + } }; -- cgit v1.2.1