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; } public void reset() { for(int i=0; i <= top; ++top) { stack_ct[top] = 0; stack_count[top] = 0; stack_obj[top] = null; stack_map_key[top] = null; } cs = CS_HEADER; trail = 0; top = -1; finished = false; } @SuppressWarnings("unchecked") public int execute(byte[] src, int off, int length) throws IOException { 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 = 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]; stack_obj[top] = null; --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]; stack_map_key[top] = null; stack_obj[top] = null; --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; } }