diff --git a/java-plan1/MessagePack.java b/java-plan1/MessagePack.java new file mode 100644 index 00000000..143f6b51 --- /dev/null +++ b/java-plan1/MessagePack.java @@ -0,0 +1,31 @@ +import java.nio.ByteBuffer; +import java.io.InputStream; +import java.io.IOException; + +public class MessagePack { + + static public Object unpack(InputStream source) + { + // FIXME not implemented yet + return null; + } + + static public Object unpack(byte[] source, int len) throws IOException + { + // FIXME not implemented yet + return null; + } + + static public Object unpack(ByteBuffer source) throws IOException + { + // FIXME not implemented yet + return null; + } + + static public Object unpack(ByteBuffer[] source) throws IOException + { + // FIXME not implemented yet + return null; + } +} + diff --git a/java-plan1/Packer.java b/java-plan1/Packer.java new file mode 100644 index 00000000..ea6b2d4d --- /dev/null +++ b/java-plan1/Packer.java @@ -0,0 +1,266 @@ +import java.io.*; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.math.BigInteger; + +public class Packer { + protected byte[] castBytes = new byte[9]; + protected ByteBuffer castBuffer = ByteBuffer.wrap(castBytes); + protected OutputStream out; + + public Packer(OutputStream out) + { + this.out = out; + } + + public Packer packByte(byte d) throws IOException + { + if(d < -(1<<5)) { + castBytes[0] = (byte)0xd1; + castBytes[1] = d; + out.write(castBytes, 0, 2); + } else { + out.write(d); + } + return this; + } + + public Packer packShort(short d) throws IOException + { + if(d < -(1<<5)) { + if(d < -(1<<7)) { + // signed 16 + castBytes[0] = (byte)0xd1; + castBuffer.putShort(1, d); + out.write(castBytes, 0, 3); + } else { + // signed 8 + castBytes[0] = (byte)0xd0; + castBytes[1] = (byte)d; + out.write(castBytes, 0, 2); + } + } else if(d < (1<<7)) { + // fixnum + out.write((byte)d); + } else { + if(d < (1<<8)) { + // unsigned 8 + castBytes[0] = (byte)0xcc; + castBytes[1] = (byte)d; + out.write(castBytes, 0, 2); + } else { + // unsigned 16 + castBytes[0] = (byte)0xcd; + castBuffer.putShort(1, d); + out.write(castBytes, 0, 3); + } + } + return this; + } + + public Packer packInt(int d) throws IOException + { + if(d < -(1<<5)) { + if(d < -(1<<15)) { + // signed 32 + castBytes[0] = (byte)0xd2; + castBuffer.putInt(1, d); + out.write(castBytes, 0, 5); + } else if(d < -(1<<7)) { + // signed 16 + castBytes[0] = (byte)0xd1; + castBuffer.putShort(1, (short)d); + out.write(castBytes, 0, 3); + } else { + // signed 8 + castBytes[0] = (byte)0xd0; + castBytes[1] = (byte)d; + out.write(castBytes, 0, 2); + } + } else if(d < (1<<7)) { + // fixnum + out.write((byte)d); + } else { + if(d < (1<<8)) { + // unsigned 8 + castBytes[0] = (byte)0xcc; + castBytes[1] = (byte)d; + out.write(castBytes, 0, 2); + } else if(d < (1<<16)) { + // unsigned 16 + castBytes[0] = (byte)0xcd; + castBuffer.putShort(1, (short)d); + out.write(castBytes, 0, 3); + } else { + // unsigned 32 + castBytes[0] = (byte)0xce; + castBuffer.putInt(1, d); + out.write(castBytes, 0, 5); + } + } + return this; + } + + public Packer packLong(long d) throws IOException + { + if(d < -(1L<<5)) { + if(d < -(1L<<15)) { + if(d < -(1L<<31)) { + // signed 64 + castBytes[0] = (byte)0xd3; + castBuffer.putLong(1, d); + out.write(castBytes, 0, 9); + } else { + // signed 32 + castBytes[0] = (byte)0xd2; + castBuffer.putInt(1, (int)d); + out.write(castBytes, 0, 5); + } + } else { + if(d < -(1<<7)) { + // signed 16 + castBytes[0] = (byte)0xd1; + castBuffer.putShort(1, (short)d); + out.write(castBytes, 0, 3); + } else { + // signed 8 + castBytes[0] = (byte)0xd0; + castBytes[1] = (byte)d; + out.write(castBytes, 0, 2); + } + } + } else if(d < (1<<7)) { + // fixnum + out.write((byte)d); + } else { + if(d < (1L<<16)) { + if(d < (1<<8)) { + // unsigned 8 + castBytes[0] = (byte)0xcc; + castBytes[1] = (byte)d; + out.write(castBytes, 0, 2); + } else { + // unsigned 16 + castBytes[0] = (byte)0xcd; + castBuffer.putShort(1, (short)d); + out.write(castBytes, 0, 3); + //System.out.println("pack uint 16 "+(short)d); + } + } else { + if(d < (1L<<32)) { + // unsigned 32 + castBytes[0] = (byte)0xce; + castBuffer.putInt(1, (int)d); + out.write(castBytes, 0, 5); + } else { + // unsigned 64 + castBytes[0] = (byte)0xcf; + castBuffer.putLong(1, d); + out.write(castBytes, 0, 9); + } + } + } + return this; + } + + public Packer packFloat(float d) throws IOException + { + castBytes[0] = (byte)0xca; + castBuffer.putFloat(1, d); + out.write(castBytes, 0, 5); + return this; + } + + public Packer packDouble(double d) throws IOException + { + castBytes[0] = (byte)0xcb; + castBuffer.putDouble(1, d); + out.write(castBytes, 0, 9); + return this; + } + + public Packer packNil() throws IOException + { + out.write((byte)0xc0); + return this; + } + + public Packer packTrue() throws IOException + { + out.write((byte)0xc3); + return this; + } + + public Packer packFalse() throws IOException + { + out.write((byte)0xc2); + return this; + } + + public Packer packArray(int n) throws IOException + { + if(n < 16) { + final int d = 0x90 | n; + out.write((byte)d); + } else if(n < 65536) { + castBytes[0] = (byte)0xdc; + castBuffer.putShort(1, (short)n); + out.write(castBytes, 0, 3); + } else { + castBytes[0] = (byte)0xdd; + castBuffer.putInt(1, n); + out.write(castBytes, 0, 5); + } + return this; + } + + public Packer packMap(int n) throws IOException + { + if(n < 16) { + final int d = 0x80 | n; + out.write((byte)d); + } else if(n < 65536) { + castBytes[0] = (byte)0xde; + castBuffer.putShort(1, (short)n); + out.write(castBytes, 0, 3); + } else { + castBytes[0] = (byte)0xdf; + castBuffer.putInt(1, n); + out.write(castBytes, 0, 5); + } + return this; + } + + public Packer packRaw(int n) throws IOException + { + if(n < 32) { + final int d = 0xa0 | n; + out.write((byte)d); + } else if(n < 65536) { + castBytes[0] = (byte)0xda; + castBuffer.putShort(1, (short)n); + out.write(castBytes, 0, 3); + } else { + castBytes[0] = (byte)0xdb; + castBuffer.putInt(1, n); + out.write(castBytes, 0, 5); + } + return this; + } + + public Packer packRawBody(byte[] b) throws IOException + { + out.write(b); + return this; + } + + public Packer packRawBody(byte[] b, int off, int length) throws IOException + { + out.write(b, off, length); + return this; + } + + //public Packer pack(Object o) throws IOException +} + diff --git a/java-plan1/Unpacker.java b/java-plan1/Unpacker.java new file mode 100644 index 00000000..be86344e --- /dev/null +++ b/java-plan1/Unpacker.java @@ -0,0 +1,385 @@ +import java.io.*; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashMap; +import java.math.BigInteger; + +public class Unpacker { + protected static final int CS_HEADER = 0x00; + protected static final int CS_FLOAT = 0x0a; + protected static final int CS_DOUBLE = 0x0b; + protected static final int CS_UINT_8 = 0x0c; + protected static final int CS_UINT_16 = 0x0d; + protected static final int CS_UINT_32 = 0x0e; + protected static final int CS_UINT_64 = 0x0f; + protected static final int CS_INT_8 = 0x10; + protected static final int CS_INT_16 = 0x11; + protected static final int CS_INT_32 = 0x12; + protected static final int CS_INT_64 = 0x13; + protected static final int CS_RAW_16 = 0x1a; + protected static final int CS_RAW_32 = 0x1b; + protected static final int CS_ARRAY_16 = 0x1c; + protected static final int CS_ARRAY_32 = 0x1d; + protected static final int CS_MAP_16 = 0x1e; + protected static final int CS_MAP_32 = 0x1f; + protected static final int ACS_RAW_VALUE = 0x20; + protected static final int CT_ARRAY_ITEM = 0x00; + protected static final int CT_MAP_KEY = 0x01; + protected static final int CT_MAP_VALUE = 0x02; + + protected static final int MAX_STACK_SIZE = 16; + + protected int cs = CS_HEADER; + protected int trail = 0; + protected int top = -1; + protected boolean finished = false; + protected int[] stack_ct = new int[MAX_STACK_SIZE]; + protected int[] stack_count = new int[MAX_STACK_SIZE]; + protected Object[] stack_obj = new Object[MAX_STACK_SIZE]; + protected Object[] stack_map_key = new Object[MAX_STACK_SIZE]; + //protected Object user; + protected ByteBuffer castBuffer = ByteBuffer.allocate(8); + + public Object getData() + { + return stack_obj[0]; + } + + public boolean isFinished() + { + return finished; + } + + + @SuppressWarnings("unchecked") + public int execute(byte[] src, int off, int length) throws IOException + { + if(off >= length) { return off; } + + int limit = off + length; + int i = off; + int count; + + Object obj = null; + + _out: do { + _header_again: { + //System.out.println("while i:"+i); + + 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 = b; + break _push; + } + + if((b & 0xe0) == 0xe0) { // Negative Fixnum + //System.out.println("negative fixnum "+b); + obj = b; + break _push; + } + + if((b & 0xe0) == 0xa0) { // FixRaw + trail = b & 0x1f; + if(trail == 0) { + obj = new byte[0]; + break _push; + } + cs = ACS_RAW_VALUE; + break _fixed_trail_again; + } + + if((b & 0xf0) == 0x90) { // FixArray + if(top >= MAX_STACK_SIZE) { + throw new IOException("parse error"); + } + count = b & 0x0f; + ++top; + stack_obj[top] = new ArrayList(count); + stack_ct[top] = CT_ARRAY_ITEM; + stack_count[top] = count; + //System.out.println("fixarray count:"+count); + break _header_again; + } + + if((b & 0xf0) == 0x80) { // FixMap + if(top >= MAX_STACK_SIZE) { + throw new IOException("parse error"); + } + count = b & 0x0f; + ++top; + stack_obj[top] = new HashMap(count); + stack_ct[top] = CT_MAP_KEY; + stack_count[top] = count; + //System.out.println("fixmap count:"+count); + break _header_again; + } + + switch(b & 0xff) { // FIXME + case 0xc0: // nil + obj = null; + break _push; + case 0xc2: // false + obj = false; + break _push; + case 0xc3: // true + obj = 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 IOException("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 = castBuffer.getFloat(0); + //System.out.println("float "+obj); + break _push; + case CS_DOUBLE: + castBuffer.rewind(); + castBuffer.put(src, n, 8); + obj = 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 = ((int)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 = ((int)castBuffer.getShort(0)) & 0xffff; + //System.out.println("uint 16 "+obj); + break _push; + case CS_UINT_32: + castBuffer.rewind(); + castBuffer.put(src, n, 4); + { + // FIXME always long? + int o = castBuffer.getInt(0); + if(o < 0) { + obj = ((long)o) & 0xffffffffL; + } else { + obj = o; + } + } + //System.out.println("uint 32 "+obj); + break _push; + case CS_UINT_64: + castBuffer.rewind(); + castBuffer.put(src, n, 8); + { + // FIXME always BigInteger? + long o = castBuffer.getLong(0); + if(o < 0) { + obj = BigInteger.valueOf(o & 0x7fffffffL).setBit(31); + } else { + obj = o; + } + } + throw new IOException("uint 64 is not supported"); + case CS_INT_8: + obj = (int)src[n]; + break _push; + case CS_INT_16: + castBuffer.rewind(); + castBuffer.put(src, n, 2); + obj = (int)castBuffer.getShort(0); + break _push; + case CS_INT_32: + castBuffer.rewind(); + castBuffer.put(src, n, 4); + obj = (int)castBuffer.getInt(0); + break _push; + case CS_INT_64: + castBuffer.rewind(); + castBuffer.put(src, n, 8); + { + // FIXME always long? + long o = castBuffer.getLong(0); + if(o <= 0x7fffffffL && o > -0x80000000L) { + obj = (int)o; + } else { + obj = o; + } + } + //System.out.println("long "+obj); + break _push; + case CS_RAW_16: + castBuffer.rewind(); + castBuffer.put(src, n, 2); + trail = ((int)castBuffer.getShort(0)) & 0xffff; + if(trail == 0) { + obj = new byte[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 = new byte[0]; + break _push; + } + cs = ACS_RAW_VALUE; + case ACS_RAW_VALUE: + obj = ByteBuffer.wrap(src, n, trail); // FIXME プール? コピー + break _push; + case CS_ARRAY_16: + if(top >= MAX_STACK_SIZE) { + throw new IOException("parse error"); + } + castBuffer.rewind(); + castBuffer.put(src, n, 2); + count = ((int)castBuffer.getShort(0)) & 0xffff; + ++top; + stack_obj[top] = new ArrayList(count); + stack_ct[top] = CT_ARRAY_ITEM; + stack_count[top] = count; + break _header_again; + case CS_ARRAY_32: + if(top >= MAX_STACK_SIZE) { + throw new IOException("parse error"); + } + castBuffer.rewind(); + castBuffer.put(src, n, 4); + // FIXME overflow check + count = castBuffer.getInt(0) & 0x7fffffff; + ++top; + stack_obj[top] = new ArrayList(count); + stack_ct[top] = CT_ARRAY_ITEM; + stack_count[top] = count; + break _header_again; + case CS_MAP_16: + if(top >= MAX_STACK_SIZE) { + throw new IOException("parse error"); + } + castBuffer.rewind(); + castBuffer.put(src, n, 2); + count = ((int)castBuffer.getShort(0)) & 0xffff; + ++top; + stack_obj[top] = new HashMap(count); + stack_ct[top] = CT_MAP_KEY; + stack_count[top] = count; + //System.out.println("fixmap count:"+count); + break _header_again; + case CS_MAP_32: + if(top >= MAX_STACK_SIZE) { + throw new IOException("parse error"); + } + castBuffer.rewind(); + castBuffer.put(src, n, 4); + // FIXME overflow check + count = castBuffer.getInt(0) & 0x7fffffff; + ++top; + stack_obj[top] = new HashMap(count); + stack_ct[top] = CT_MAP_KEY; + stack_count[top] = count; + //System.out.println("fixmap count:"+count); + break _header_again; + default: + throw new IOException("parse error"); + } + + } // _fixed_trail_again + } while(true); + } // _push + + do { + _push: { + //System.out.println("push top:"+top); + if(top == -1) { + stack_obj[0] = obj; + finished = true; + break _out; + } + + switch(stack_ct[top]) { + case CT_ARRAY_ITEM: + //System.out.println("array item "+obj); + ((ArrayList)(stack_obj[top])).add(obj); + if(--stack_count[top] == 0) { + obj = stack_obj[top]; + --top; + break _push; + } + break _header_again; + case CT_MAP_KEY: + //System.out.println("map key:"+top+" "+obj); + stack_map_key[top] = obj; + stack_ct[top] = CT_MAP_VALUE; + break _header_again; + case CT_MAP_VALUE: + //System.out.println("map value:"+top+" "+obj); + ((HashMap)(stack_obj[top])).put(stack_map_key[top], obj); + if(--stack_count[top] == 0) { + obj = stack_obj[top]; + --top; + break _push; + } + stack_ct[top] = CT_MAP_KEY; + break _header_again; + default: + throw new IOException("parse error"); + } + } // _push + } while(true); + + } // _header_again + cs = CS_HEADER; + ++i; + } while(i < limit); // _out + + return i - off; + } +} + diff --git a/java-plan1/run.sh b/java-plan1/run.sh new file mode 100755 index 00000000..1539a37b --- /dev/null +++ b/java-plan1/run.sh @@ -0,0 +1,3 @@ +#!/bin/sh +javac MessagePack.java Packer.java Unpacker.java test.java +java test diff --git a/java-plan1/test.java b/java-plan1/test.java new file mode 100644 index 00000000..938a6871 --- /dev/null +++ b/java-plan1/test.java @@ -0,0 +1,27 @@ +import java.util.*; +import java.io.*; + +class OpenByteArrayOutputStream extends ByteArrayOutputStream { + int getCount() { return count; } + byte[] getBuffer() { return buf; } +} + +public class test { + public static void main(String[] args) throws IOException + { + OpenByteArrayOutputStream out = new OpenByteArrayOutputStream(); + + Packer pk = new Packer(out); + pk.packArray(3) + .packInt(0) + .packByte((byte)1) + .packDouble(0.1); + + Unpacker pac = new Unpacker(); + int nlen = pac.execute(out.getBuffer(), 0, out.getCount()); + if(pac.isFinished()) { + System.out.println(pac.getData()); + } + } +} +