-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.db.common.utils;\r
-\r
-public abstract class ValueType {\r
-\r
- private ValueType() {\r
- } \r
-\r
- public abstract int getConstantSize(); // returns -1 if not constant size\r
- public abstract void serialize(ByteBuffer buffer, Object obj);\r
- public abstract void unsafeSerialize(ByteBuffer buffer, Object obj);\r
- public abstract Object deserialize(ByteBuffer buffer);\r
-\r
- public boolean supportsNativeArray() {\r
- return false;\r
- }\r
- public void serializeNativeArray(ByteBuffer buffer, Object obj, int length) {\r
- // TODO Throw exception\r
- }\r
-\r
- public Object deserializeNativeArray(ByteBuffer buffer, int length) {\r
- // TODO Throw exception\r
- return null;\r
- }\r
-\r
- public byte[] serialize(Object obj) {\r
- int constantSize = getConstantSize();\r
- ByteBuffer buffer = new ByteBuffer(constantSize >= 0 ? constantSize : 0);\r
- serialize(buffer, obj);\r
- return buffer.content();\r
- }\r
-\r
- public Object deserialize(byte[] bytes) {\r
- return deserialize(new ByteBuffer(bytes));\r
- } \r
-\r
- public static class BooleanType extends ValueType {\r
- public BooleanType() {} \r
-\r
- @Override\r
- public int getConstantSize() {\r
- return 1;\r
- } \r
- @Override\r
- public void serialize(ByteBuffer buffer, Object obj) {\r
- buffer.needs(1);\r
- buffer.putByte( (Boolean)obj == true ? (byte)1 : (byte)0 );\r
-\r
- }\r
- @Override\r
- public void unsafeSerialize(ByteBuffer buffer, Object obj) {\r
- buffer.putByte( (Boolean)obj == true ? (byte)1 : (byte)0 ); \r
- }\r
- @Override\r
- public Object deserialize(ByteBuffer buffer) {\r
- return buffer.getByte() != 0;\r
- }\r
- }\r
-\r
- public static class ByteType extends ValueType {\r
- public ByteType() {} \r
-\r
- @Override\r
- public int getConstantSize() {\r
- return 1;\r
- } \r
- @Override\r
- public void serialize(ByteBuffer buffer, Object obj) {\r
- buffer.needs(1);\r
- buffer.putByte((Byte)obj);\r
-\r
- }\r
- @Override\r
- public void unsafeSerialize(ByteBuffer buffer, Object obj) {\r
- buffer.putByte((Byte)obj); \r
- }\r
- @Override\r
- public Object deserialize(ByteBuffer buffer) {\r
- return buffer.getByte();\r
- }\r
- }\r
-\r
- public static class IntegerType extends ValueType {\r
- public IntegerType() {} \r
-\r
- @Override\r
- public int getConstantSize() {\r
- return 4;\r
- } \r
- @Override\r
- public void serialize(ByteBuffer buffer, Object obj) {\r
- buffer.needs(4);\r
- buffer.putInt((Integer)obj);\r
-\r
- }\r
- @Override\r
- public void unsafeSerialize(ByteBuffer buffer, Object obj) {\r
- buffer.putInt((Integer)obj); \r
- }\r
- @Override\r
- public Object deserialize(ByteBuffer buffer) {\r
- return buffer.getInt();\r
- }\r
- }\r
-\r
- public static class LongType extends ValueType {\r
- public LongType() {} \r
-\r
- @Override\r
- public int getConstantSize() {\r
- return 8;\r
- } \r
- @Override\r
- public void serialize(ByteBuffer buffer, Object obj) {\r
- buffer.needs(8);\r
- buffer.putLong((Long)obj);\r
-\r
- }\r
- @Override\r
- public void unsafeSerialize(ByteBuffer buffer, Object obj) {\r
- buffer.putLong((Long)obj); \r
- }\r
- @Override\r
- public Object deserialize(ByteBuffer buffer) {\r
- return buffer.getLong();\r
- }\r
- }\r
- \r
- public static class FloatType extends ValueType {\r
- public FloatType() {} \r
-\r
- @Override\r
- public int getConstantSize() {\r
- return 4;\r
- } \r
- @Override\r
- public void serialize(ByteBuffer buffer, Object obj) {\r
- buffer.needs(4);\r
- buffer.putFloat((Float)obj);\r
-\r
- }\r
- @Override\r
- public void unsafeSerialize(ByteBuffer buffer, Object obj) {\r
- buffer.putFloat((Float)obj); \r
- }\r
- @Override\r
- public Object deserialize(ByteBuffer buffer) {\r
- return buffer.getFloat();\r
- }\r
- }\r
-\r
- public static class DoubleType extends ValueType {\r
- public DoubleType() {} \r
-\r
- @Override\r
- public int getConstantSize() {\r
- return 8;\r
- } \r
- @Override\r
- public void serialize(ByteBuffer buffer, Object obj) {\r
- buffer.needs(8);\r
- buffer.putDouble((Double)obj);\r
-\r
- }\r
- @Override\r
- public void unsafeSerialize(ByteBuffer buffer, Object obj) {\r
- buffer.putDouble((Double)obj); \r
- }\r
- @Override\r
- public Object deserialize(ByteBuffer buffer) {\r
- return buffer.getDouble();\r
- }\r
- public boolean supportsNativeArray() {\r
- return true;\r
- }\r
- public void serializeNativeArray(ByteBuffer buffer, Object obj, int length) {\r
- double[] array = (double[])obj;\r
- if(length < 0)\r
- buffer.putInt(array.length);\r
- else\r
- ; // TODO check\r
- for(double d : array)\r
- buffer.putDouble(d);\r
- }\r
-\r
- public Object deserializeNativeArray(ByteBuffer buffer, int length) {\r
- double[] ret = new double[length];\r
- for(int i=0;i<length;++i)\r
- ret[i] = buffer.getDouble();\r
- return ret;\r
- }\r
- }\r
-\r
- public static class StringType extends ValueType {\r
- public StringType() {} \r
-\r
- @Override\r
- public int getConstantSize() {\r
- return -1;\r
- } \r
- @Override\r
- public void serialize(ByteBuffer buffer, Object obj) {\r
- buffer.putString((String)obj);\r
-\r
- }\r
- @Override\r
- public void unsafeSerialize(ByteBuffer buffer, Object obj) {\r
- // TODO Throw exception\r
- }\r
- @Override\r
- public Object deserialize(ByteBuffer buffer) {\r
- return buffer.getString();\r
- }\r
- }\r
-\r
- public static class ProductType extends ValueType {\r
- public final ValueType[] baseTypes;\r
- private int constantSize;\r
-\r
- public ProductType(ValueType[] baseTypes) {\r
- this.baseTypes = baseTypes;\r
- constantSize = 0;\r
- for(ValueType b : baseTypes) {\r
- int temp = b.getConstantSize();\r
- if(temp==-1) {\r
- constantSize = -1;\r
- break;\r
- }\r
- constantSize += temp;\r
- }\r
- }\r
-\r
- @Override\r
- public int getConstantSize() {\r
- return constantSize;\r
- } \r
- @Override\r
- public void serialize(ByteBuffer buffer, Object obj) {\r
- if(constantSize >= 0) {\r
- buffer.needs(constantSize);\r
- unsafeSerialize(buffer, obj);\r
- }\r
- else {\r
- Object[] subobjects = (Object[])obj;\r
- // FIXME Catch cast exception\r
- // FIXME Check length\r
- for(int i=0;i<baseTypes.length;++i)\r
- baseTypes[i].serialize(buffer, subobjects[i]);\r
- }\r
- }\r
- @Override\r
- public void unsafeSerialize(ByteBuffer buffer, Object obj) {\r
- Object[] subobjects = (Object[])obj;\r
- // FIXME Catch cast exception\r
- // FIXME Check length\r
- for(int i=0;i<baseTypes.length;++i)\r
- baseTypes[i].unsafeSerialize(buffer, subobjects[i]);\r
- }\r
- @Override\r
- public Object deserialize(ByteBuffer buffer) {\r
- Object[] ret = new Object[baseTypes.length];\r
- for(int i=0;i<baseTypes.length;++i)\r
- ret[i] = baseTypes[i].deserialize(buffer);\r
- return ret;\r
- }\r
- }\r
-\r
- public static class Construction {\r
- int constructor;\r
- Object value;\r
- }\r
-\r
- public static class SumType extends ValueType {\r
- public final ValueType[] baseTypes;\r
- private int constantSize;\r
-\r
- public SumType(ValueType[] baseTypes) {\r
- this.baseTypes = baseTypes;\r
- constantSize = -2;\r
- for(ValueType b : baseTypes) {\r
- int temp = b.getConstantSize();\r
- if(temp != constantSize) {\r
- if(constantSize==-2 && temp >= 0)\r
- constantSize = temp; \r
- else {\r
- constantSize = -1;\r
- break;\r
- }\r
- }\r
- }\r
- if(constantSize >= 0)\r
- constantSize += 4;\r
- }\r
-\r
- @Override\r
- public int getConstantSize() {\r
- return constantSize;\r
- } \r
- @Override\r
- public void serialize(ByteBuffer buffer, Object obj) {\r
- if(constantSize >= 0) {\r
- buffer.needs(constantSize);\r
- unsafeSerialize(buffer, obj);\r
- }\r
- else {\r
- Construction construction = (Construction)obj;\r
- // FIXME validate construction.constructor\r
- buffer.needs(4);\r
- buffer.putInt(construction.constructor);\r
- baseTypes[construction.constructor].serialize(buffer, construction.value);\r
- }\r
- }\r
- @Override\r
- public void unsafeSerialize(ByteBuffer buffer, Object obj) {\r
- Construction construction = (Construction)obj;\r
- // FIXME validate construction.constructor\r
- buffer.putInt(construction.constructor);\r
- baseTypes[construction.constructor].unsafeSerialize(buffer, construction.value);\r
- }\r
- @Override\r
- public Object deserialize(ByteBuffer buffer) {\r
- Construction ret = new Construction();\r
- ret.constructor = buffer.getInt();\r
- // FIXME validate construction.constructor\r
- ret.value = baseTypes[ret.constructor].deserialize(buffer);\r
- return ret;\r
- }\r
- }\r
-\r
- public static class VariableLengthArrayType extends ValueType {\r
- public final ValueType baseType;\r
- private int baseTypeConstantSize;\r
- private boolean supportsNativeArray;\r
-\r
- public VariableLengthArrayType(ValueType baseType) {\r
- this.baseType = baseType;\r
- baseTypeConstantSize = baseType.getConstantSize();\r
- supportsNativeArray = baseType.supportsNativeArray();\r
- }\r
-\r
- @Override\r
- public int getConstantSize() {\r
- return -1;\r
- } \r
-\r
- @Override\r
- public void serialize(ByteBuffer buffer, Object obj) {\r
- if(baseTypeConstantSize >= 0) {\r
- if(obj instanceof Object[]) {\r
- Object[] subobjects = (Object[])obj; \r
- buffer.needs(4 + subobjects.length * baseTypeConstantSize);\r
- buffer.putInt(subobjects.length);\r
- for(Object subobj : subobjects)\r
- baseType.unsafeSerialize(buffer, subobj);\r
- }\r
- else if(supportsNativeArray) \r
- baseType.serializeNativeArray(buffer, obj, -1);\r
- else\r
- ; // TODO exc\r
-\r
- }\r
- else {\r
- Object[] subobjects = (Object[])obj; \r
- buffer.needs(4);\r
- buffer.putInt(subobjects.length);\r
- for(Object subobj : subobjects)\r
- baseType.serialize(buffer, subobj);\r
- }\r
- }\r
- @Override\r
- public void unsafeSerialize(ByteBuffer buffer, Object obj) {\r
- // TODO Throw exception\r
- }\r
- @Override\r
- public Object deserialize(ByteBuffer buffer) {\r
- int length = buffer.getInt();\r
- if(supportsNativeArray) \r
- return baseType.deserializeNativeArray(buffer, length);\r
- else {\r
- Object[] ret = new Object[length];\r
- for(int i=0;i<length;++i)\r
- ret[i] = baseType.deserialize(buffer);\r
- return ret;\r
- }\r
- }\r
- }\r
-\r
- public static class FixedLengthArrayType extends ValueType {\r
- public final ValueType baseType;\r
- public final int dimension;\r
- private int constantSize;\r
- private boolean supportsNativeArray;\r
-\r
- public FixedLengthArrayType(ValueType baseType, int dimension) {\r
- this.baseType = baseType;\r
- this.dimension = dimension;\r
- constantSize = baseType.getConstantSize();\r
- if(constantSize >= 0) {\r
- constantSize *= dimension;\r
- supportsNativeArray = baseType.supportsNativeArray();\r
- }\r
- }\r
-\r
- @Override\r
- public int getConstantSize() {\r
- return constantSize;\r
- } \r
-\r
- @Override\r
- public void serialize(ByteBuffer buffer, Object obj) {\r
- if(constantSize >= 0) {\r
- buffer.needs(constantSize);\r
- unsafeSerialize(buffer, obj);\r
- }\r
- else {\r
- Object[] subobjects = (Object[])obj; \r
- // FIXME checks\r
- for(Object subobj : subobjects)\r
- baseType.serialize(buffer, subobj);\r
- }\r
- }\r
- @Override\r
- public void unsafeSerialize(ByteBuffer buffer, Object obj) {\r
- if(supportsNativeArray)\r
- baseType.serializeNativeArray(buffer, obj, dimension);\r
- else {\r
- Object[] subobjects = (Object[])obj; \r
- // FIXME checks\r
- for(Object subobj : subobjects)\r
- baseType.unsafeSerialize(buffer, subobj);\r
- }\r
- }\r
- @Override\r
- public Object deserialize(ByteBuffer buffer) {\r
- if(supportsNativeArray) \r
- return baseType.deserializeNativeArray(buffer, dimension);\r
- else {\r
- Object[] ret = new Object[dimension];\r
- for(int i=0;i<dimension;++i)\r
- ret[i] = baseType.deserialize(buffer);\r
- return ret;\r
- }\r
- }\r
- } \r
-\r
- static final private class ByteBuffer {\r
- public byte[] bytes;\r
- public int offset;\r
-\r
- public ByteBuffer(int capacity) {\r
- this.bytes = new byte[capacity];\r
- this.offset = 0;\r
- }\r
-\r
- public ByteBuffer(byte[] bytes) {\r
- this.bytes = bytes;\r
- this.offset = 0;\r
- }\r
-\r
- public void needs(int size) {\r
- if(offset + size > bytes.length) {\r
- // FIXME bytes = Arrays.copyOf(bytes, newSize);\r
- byte[] newBytes = new byte[offset*2 + size];\r
- for(int i=0;i<bytes.length;++i)\r
- newBytes[i] = bytes[i];\r
- bytes = newBytes;\r
- }\r
- }\r
-\r
- public byte[] content() {\r
- if(offset == bytes.length)\r
- return bytes;\r
- // FIXME bytes = Arrays.copyOf(bytes, offset);\r
- byte[] newBytes = new byte[offset];\r
- for(int i=0;i<offset;++i)\r
- newBytes[i] = bytes[i];\r
- return newBytes;\r
- }\r
-\r
- public void putByte(byte v) {\r
- bytes[offset] = v;\r
- offset += 1;\r
- }\r
- public void putShort(short v) {\r
- bytes[offset] = (byte) v;\r
- bytes[offset+1] = (byte) (v >>> 8);\r
- offset += 2;\r
- }\r
- public void putInt(int v) {\r
- bytes[offset] = (byte) v;\r
- bytes[offset+1] = (byte) (v >>> 8);\r
- bytes[offset+2] = (byte) (v >>> 16);\r
- bytes[offset+3] = (byte) (v >>> 24);\r
- offset += 4;\r
- }\r
- public void putLong(long v) {\r
- bytes[offset] = (byte) v;\r
- bytes[offset+1] = (byte) (v >>> 8);\r
- bytes[offset+2] = (byte) (v >>> 16);\r
- bytes[offset+3] = (byte) (v >>> 24);\r
- bytes[offset+4] = (byte) (v >>> 32);\r
- bytes[offset+5] = (byte) (v >>> 40);\r
- bytes[offset+6] = (byte) (v >>> 48);\r
- bytes[offset+7] = (byte) (v >>> 56);\r
- offset += 8;\r
- }\r
- public void putFloat(float _v) {\r
- int v = Float.floatToIntBits(_v);\r
- bytes[offset] = (byte) v;\r
- bytes[offset+1] = (byte) (v >>> 8);\r
- bytes[offset+2] = (byte) (v >>> 16);\r
- bytes[offset+3] = (byte) (v >>> 24);\r
- offset += 4;\r
- }\r
- public void putDouble(double _v) {\r
- long v = Double.doubleToLongBits(_v);\r
- bytes[offset] = (byte) v;\r
- bytes[offset+1] = (byte) (v >>> 8);\r
- bytes[offset+2] = (byte) (v >>> 16);\r
- bytes[offset+3] = (byte) (v >>> 24);\r
- bytes[offset+4] = (byte) (v >>> 32);\r
- bytes[offset+5] = (byte) (v >>> 40);\r
- bytes[offset+6] = (byte) (v >>> 48);\r
- bytes[offset+7] = (byte) (v >>> 56);\r
- offset += 8;\r
- }\r
- public void putString(String str) {\r
-\r
- // UTF-16 -> modified UTF-8\r
-\r
- int length = 4;\r
- for(int i=0;i<str.length();++i) {\r
- char c = str.charAt(i);\r
- if(c < 0x80)\r
- length += 1;\r
- else if(c < 0x800)\r
- length += 2;\r
- else \r
- length += 3;\r
- }\r
- needs(length);\r
- putInt(str.length());\r
- for(int i=0;i<str.length();++i) {\r
- char c = str.charAt(i);\r
- if(c < 0x80) {\r
- bytes[offset] = (byte)c;\r
- offset += 1;\r
- }\r
- else if(c < 0x800) {\r
- bytes[offset] = (byte)(0xc0 + (c >>> 6));\r
- bytes[offset+1] = (byte)(0x80 + (c & 0x3f));\r
- offset += 2;\r
- }\r
- else {\r
- // FIXME handle range D800 - DFFF\r
- bytes[offset] = (byte)(0xe0 + (c >>> 12));\r
- bytes[offset+1] = (byte)(0x80 + ((c >>> 6) & 0x3f));\r
- bytes[offset+2] = (byte)(0x80 + (c & 0x3f));\r
- offset += 3;\r
- }\r
- }\r
- }\r
- public byte getByte() {\r
- ++offset;\r
- return bytes[offset-1];\r
- }\r
- public short getShort() {\r
- int v = bytes[offset] & 0xFF;\r
- v += (bytes[offset+1] & 0xFF) << 8;\r
- offset += 2;\r
- return (short)v;\r
- }\r
- public int getInt() {\r
- int v = bytes[offset] & 0xFF;\r
- v += (bytes[offset+1] & 0xFF) << 8;\r
- v += (bytes[offset+2] & 0xFF) << 16;\r
- v += (bytes[offset+3] & 0xFF) << 24;\r
- offset += 4;\r
- return v;\r
- }\r
- public long getLong() {\r
- long v = bytes[offset] & 0xFFL;\r
- v += (bytes[offset+1] & 0xFFL) << 8;\r
- v += (bytes[offset+2] & 0xFFL) << 16;\r
- v += (bytes[offset+3] & 0xFFL) << 24;\r
- v += (bytes[offset+4] & 0xFFL) << 32;\r
- v += (bytes[offset+5] & 0xFFL) << 40;\r
- v += (bytes[offset+6] & 0xFFL) << 48;\r
- v += (bytes[offset+7] & 0xFFL) << 56;\r
- offset += 8;\r
- return v;\r
- }\r
- public float getFloat() {\r
- int v = bytes[offset] & 0xFF;\r
- v += (bytes[offset+1] & 0xFF) << 8;\r
- v += (bytes[offset+2] & 0xFF) << 16;\r
- v += (bytes[offset+3] & 0xFF) << 24;\r
- offset += 4;\r
- return Float.intBitsToFloat(v);\r
- }\r
- public double getDouble() {\r
- long v = bytes[offset] & 0xFFL;\r
- v += (bytes[offset+1] & 0xFFL) << 8;\r
- v += (bytes[offset+2] & 0xFFL) << 16;\r
- v += (bytes[offset+3] & 0xFFL) << 24;\r
- v += (bytes[offset+4] & 0xFFL) << 32;\r
- v += (bytes[offset+5] & 0xFFL) << 40;\r
- v += (bytes[offset+6] & 0xFFL) << 48;\r
- v += (bytes[offset+7] & 0xFFL) << 56;\r
- offset += 8;\r
- return Double.longBitsToDouble(v);\r
- }\r
- public String getString() {\r
- int length = getInt();\r
- char[] chars = new char[length];\r
- for(int i=0;i<length;++i) {\r
- int b0 = (int)bytes[offset];\r
- int c;\r
- if(b0 >= 0) {\r
- c = b0;\r
- offset += 1;\r
- }\r
- else if(b0 < 0xe0-256) {\r
- c = ((b0 & 0x1f) << 6) +\r
- (bytes[offset+1] & 0x3f);\r
- offset += 2;\r
- }\r
- else if(b0 < 0xf0-256) {\r
- c = ((b0 & 0x0f) << 12) +\r
- ((bytes[offset+1] & 0x3f) << 6) +\r
- (bytes[offset+2] & 0x3f);\r
- offset += 3;\r
- }\r
- else\r
- c = 0; // FIXME\r
- chars[i] = (char)c;\r
- }\r
- return new String(chars);\r
- }\r
- \r
- }\r
- \r
-}\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.db.common.utils;
+
+public abstract class ValueType {
+
+ private ValueType() {
+ }
+
+ public abstract int getConstantSize(); // returns -1 if not constant size
+ public abstract void serialize(ByteBuffer buffer, Object obj);
+ public abstract void unsafeSerialize(ByteBuffer buffer, Object obj);
+ public abstract Object deserialize(ByteBuffer buffer);
+
+ public boolean supportsNativeArray() {
+ return false;
+ }
+ public void serializeNativeArray(ByteBuffer buffer, Object obj, int length) {
+ // TODO Throw exception
+ }
+
+ public Object deserializeNativeArray(ByteBuffer buffer, int length) {
+ // TODO Throw exception
+ return null;
+ }
+
+ public byte[] serialize(Object obj) {
+ int constantSize = getConstantSize();
+ ByteBuffer buffer = new ByteBuffer(constantSize >= 0 ? constantSize : 0);
+ serialize(buffer, obj);
+ return buffer.content();
+ }
+
+ public Object deserialize(byte[] bytes) {
+ return deserialize(new ByteBuffer(bytes));
+ }
+
+ public static class BooleanType extends ValueType {
+ public BooleanType() {}
+
+ @Override
+ public int getConstantSize() {
+ return 1;
+ }
+ @Override
+ public void serialize(ByteBuffer buffer, Object obj) {
+ buffer.needs(1);
+ buffer.putByte( (Boolean)obj == true ? (byte)1 : (byte)0 );
+
+ }
+ @Override
+ public void unsafeSerialize(ByteBuffer buffer, Object obj) {
+ buffer.putByte( (Boolean)obj == true ? (byte)1 : (byte)0 );
+ }
+ @Override
+ public Object deserialize(ByteBuffer buffer) {
+ return buffer.getByte() != 0;
+ }
+ }
+
+ public static class ByteType extends ValueType {
+ public ByteType() {}
+
+ @Override
+ public int getConstantSize() {
+ return 1;
+ }
+ @Override
+ public void serialize(ByteBuffer buffer, Object obj) {
+ buffer.needs(1);
+ buffer.putByte((Byte)obj);
+
+ }
+ @Override
+ public void unsafeSerialize(ByteBuffer buffer, Object obj) {
+ buffer.putByte((Byte)obj);
+ }
+ @Override
+ public Object deserialize(ByteBuffer buffer) {
+ return buffer.getByte();
+ }
+ }
+
+ public static class IntegerType extends ValueType {
+ public IntegerType() {}
+
+ @Override
+ public int getConstantSize() {
+ return 4;
+ }
+ @Override
+ public void serialize(ByteBuffer buffer, Object obj) {
+ buffer.needs(4);
+ buffer.putInt((Integer)obj);
+
+ }
+ @Override
+ public void unsafeSerialize(ByteBuffer buffer, Object obj) {
+ buffer.putInt((Integer)obj);
+ }
+ @Override
+ public Object deserialize(ByteBuffer buffer) {
+ return buffer.getInt();
+ }
+ }
+
+ public static class LongType extends ValueType {
+ public LongType() {}
+
+ @Override
+ public int getConstantSize() {
+ return 8;
+ }
+ @Override
+ public void serialize(ByteBuffer buffer, Object obj) {
+ buffer.needs(8);
+ buffer.putLong((Long)obj);
+
+ }
+ @Override
+ public void unsafeSerialize(ByteBuffer buffer, Object obj) {
+ buffer.putLong((Long)obj);
+ }
+ @Override
+ public Object deserialize(ByteBuffer buffer) {
+ return buffer.getLong();
+ }
+ }
+
+ public static class FloatType extends ValueType {
+ public FloatType() {}
+
+ @Override
+ public int getConstantSize() {
+ return 4;
+ }
+ @Override
+ public void serialize(ByteBuffer buffer, Object obj) {
+ buffer.needs(4);
+ buffer.putFloat((Float)obj);
+
+ }
+ @Override
+ public void unsafeSerialize(ByteBuffer buffer, Object obj) {
+ buffer.putFloat((Float)obj);
+ }
+ @Override
+ public Object deserialize(ByteBuffer buffer) {
+ return buffer.getFloat();
+ }
+ }
+
+ public static class DoubleType extends ValueType {
+ public DoubleType() {}
+
+ @Override
+ public int getConstantSize() {
+ return 8;
+ }
+ @Override
+ public void serialize(ByteBuffer buffer, Object obj) {
+ buffer.needs(8);
+ buffer.putDouble((Double)obj);
+
+ }
+ @Override
+ public void unsafeSerialize(ByteBuffer buffer, Object obj) {
+ buffer.putDouble((Double)obj);
+ }
+ @Override
+ public Object deserialize(ByteBuffer buffer) {
+ return buffer.getDouble();
+ }
+ public boolean supportsNativeArray() {
+ return true;
+ }
+ public void serializeNativeArray(ByteBuffer buffer, Object obj, int length) {
+ double[] array = (double[])obj;
+ if(length < 0)
+ buffer.putInt(array.length);
+ else
+ ; // TODO check
+ for(double d : array)
+ buffer.putDouble(d);
+ }
+
+ public Object deserializeNativeArray(ByteBuffer buffer, int length) {
+ double[] ret = new double[length];
+ for(int i=0;i<length;++i)
+ ret[i] = buffer.getDouble();
+ return ret;
+ }
+ }
+
+ public static class StringType extends ValueType {
+ public StringType() {}
+
+ @Override
+ public int getConstantSize() {
+ return -1;
+ }
+ @Override
+ public void serialize(ByteBuffer buffer, Object obj) {
+ buffer.putString((String)obj);
+
+ }
+ @Override
+ public void unsafeSerialize(ByteBuffer buffer, Object obj) {
+ // TODO Throw exception
+ }
+ @Override
+ public Object deserialize(ByteBuffer buffer) {
+ return buffer.getString();
+ }
+ }
+
+ public static class ProductType extends ValueType {
+ public final ValueType[] baseTypes;
+ private int constantSize;
+
+ public ProductType(ValueType[] baseTypes) {
+ this.baseTypes = baseTypes;
+ constantSize = 0;
+ for(ValueType b : baseTypes) {
+ int temp = b.getConstantSize();
+ if(temp==-1) {
+ constantSize = -1;
+ break;
+ }
+ constantSize += temp;
+ }
+ }
+
+ @Override
+ public int getConstantSize() {
+ return constantSize;
+ }
+ @Override
+ public void serialize(ByteBuffer buffer, Object obj) {
+ if(constantSize >= 0) {
+ buffer.needs(constantSize);
+ unsafeSerialize(buffer, obj);
+ }
+ else {
+ Object[] subobjects = (Object[])obj;
+ // FIXME Catch cast exception
+ // FIXME Check length
+ for(int i=0;i<baseTypes.length;++i)
+ baseTypes[i].serialize(buffer, subobjects[i]);
+ }
+ }
+ @Override
+ public void unsafeSerialize(ByteBuffer buffer, Object obj) {
+ Object[] subobjects = (Object[])obj;
+ // FIXME Catch cast exception
+ // FIXME Check length
+ for(int i=0;i<baseTypes.length;++i)
+ baseTypes[i].unsafeSerialize(buffer, subobjects[i]);
+ }
+ @Override
+ public Object deserialize(ByteBuffer buffer) {
+ Object[] ret = new Object[baseTypes.length];
+ for(int i=0;i<baseTypes.length;++i)
+ ret[i] = baseTypes[i].deserialize(buffer);
+ return ret;
+ }
+ }
+
+ public static class Construction {
+ int constructor;
+ Object value;
+ }
+
+ public static class SumType extends ValueType {
+ public final ValueType[] baseTypes;
+ private int constantSize;
+
+ public SumType(ValueType[] baseTypes) {
+ this.baseTypes = baseTypes;
+ constantSize = -2;
+ for(ValueType b : baseTypes) {
+ int temp = b.getConstantSize();
+ if(temp != constantSize) {
+ if(constantSize==-2 && temp >= 0)
+ constantSize = temp;
+ else {
+ constantSize = -1;
+ break;
+ }
+ }
+ }
+ if(constantSize >= 0)
+ constantSize += 4;
+ }
+
+ @Override
+ public int getConstantSize() {
+ return constantSize;
+ }
+ @Override
+ public void serialize(ByteBuffer buffer, Object obj) {
+ if(constantSize >= 0) {
+ buffer.needs(constantSize);
+ unsafeSerialize(buffer, obj);
+ }
+ else {
+ Construction construction = (Construction)obj;
+ // FIXME validate construction.constructor
+ buffer.needs(4);
+ buffer.putInt(construction.constructor);
+ baseTypes[construction.constructor].serialize(buffer, construction.value);
+ }
+ }
+ @Override
+ public void unsafeSerialize(ByteBuffer buffer, Object obj) {
+ Construction construction = (Construction)obj;
+ // FIXME validate construction.constructor
+ buffer.putInt(construction.constructor);
+ baseTypes[construction.constructor].unsafeSerialize(buffer, construction.value);
+ }
+ @Override
+ public Object deserialize(ByteBuffer buffer) {
+ Construction ret = new Construction();
+ ret.constructor = buffer.getInt();
+ // FIXME validate construction.constructor
+ ret.value = baseTypes[ret.constructor].deserialize(buffer);
+ return ret;
+ }
+ }
+
+ public static class VariableLengthArrayType extends ValueType {
+ public final ValueType baseType;
+ private int baseTypeConstantSize;
+ private boolean supportsNativeArray;
+
+ public VariableLengthArrayType(ValueType baseType) {
+ this.baseType = baseType;
+ baseTypeConstantSize = baseType.getConstantSize();
+ supportsNativeArray = baseType.supportsNativeArray();
+ }
+
+ @Override
+ public int getConstantSize() {
+ return -1;
+ }
+
+ @Override
+ public void serialize(ByteBuffer buffer, Object obj) {
+ if(baseTypeConstantSize >= 0) {
+ if(obj instanceof Object[]) {
+ Object[] subobjects = (Object[])obj;
+ buffer.needs(4 + subobjects.length * baseTypeConstantSize);
+ buffer.putInt(subobjects.length);
+ for(Object subobj : subobjects)
+ baseType.unsafeSerialize(buffer, subobj);
+ }
+ else if(supportsNativeArray)
+ baseType.serializeNativeArray(buffer, obj, -1);
+ else
+ ; // TODO exc
+
+ }
+ else {
+ Object[] subobjects = (Object[])obj;
+ buffer.needs(4);
+ buffer.putInt(subobjects.length);
+ for(Object subobj : subobjects)
+ baseType.serialize(buffer, subobj);
+ }
+ }
+ @Override
+ public void unsafeSerialize(ByteBuffer buffer, Object obj) {
+ // TODO Throw exception
+ }
+ @Override
+ public Object deserialize(ByteBuffer buffer) {
+ int length = buffer.getInt();
+ if(supportsNativeArray)
+ return baseType.deserializeNativeArray(buffer, length);
+ else {
+ Object[] ret = new Object[length];
+ for(int i=0;i<length;++i)
+ ret[i] = baseType.deserialize(buffer);
+ return ret;
+ }
+ }
+ }
+
+ public static class FixedLengthArrayType extends ValueType {
+ public final ValueType baseType;
+ public final int dimension;
+ private int constantSize;
+ private boolean supportsNativeArray;
+
+ public FixedLengthArrayType(ValueType baseType, int dimension) {
+ this.baseType = baseType;
+ this.dimension = dimension;
+ constantSize = baseType.getConstantSize();
+ if(constantSize >= 0) {
+ constantSize *= dimension;
+ supportsNativeArray = baseType.supportsNativeArray();
+ }
+ }
+
+ @Override
+ public int getConstantSize() {
+ return constantSize;
+ }
+
+ @Override
+ public void serialize(ByteBuffer buffer, Object obj) {
+ if(constantSize >= 0) {
+ buffer.needs(constantSize);
+ unsafeSerialize(buffer, obj);
+ }
+ else {
+ Object[] subobjects = (Object[])obj;
+ // FIXME checks
+ for(Object subobj : subobjects)
+ baseType.serialize(buffer, subobj);
+ }
+ }
+ @Override
+ public void unsafeSerialize(ByteBuffer buffer, Object obj) {
+ if(supportsNativeArray)
+ baseType.serializeNativeArray(buffer, obj, dimension);
+ else {
+ Object[] subobjects = (Object[])obj;
+ // FIXME checks
+ for(Object subobj : subobjects)
+ baseType.unsafeSerialize(buffer, subobj);
+ }
+ }
+ @Override
+ public Object deserialize(ByteBuffer buffer) {
+ if(supportsNativeArray)
+ return baseType.deserializeNativeArray(buffer, dimension);
+ else {
+ Object[] ret = new Object[dimension];
+ for(int i=0;i<dimension;++i)
+ ret[i] = baseType.deserialize(buffer);
+ return ret;
+ }
+ }
+ }
+
+ static final private class ByteBuffer {
+ public byte[] bytes;
+ public int offset;
+
+ public ByteBuffer(int capacity) {
+ this.bytes = new byte[capacity];
+ this.offset = 0;
+ }
+
+ public ByteBuffer(byte[] bytes) {
+ this.bytes = bytes;
+ this.offset = 0;
+ }
+
+ public void needs(int size) {
+ if(offset + size > bytes.length) {
+ // FIXME bytes = Arrays.copyOf(bytes, newSize);
+ byte[] newBytes = new byte[offset*2 + size];
+ for(int i=0;i<bytes.length;++i)
+ newBytes[i] = bytes[i];
+ bytes = newBytes;
+ }
+ }
+
+ public byte[] content() {
+ if(offset == bytes.length)
+ return bytes;
+ // FIXME bytes = Arrays.copyOf(bytes, offset);
+ byte[] newBytes = new byte[offset];
+ for(int i=0;i<offset;++i)
+ newBytes[i] = bytes[i];
+ return newBytes;
+ }
+
+ public void putByte(byte v) {
+ bytes[offset] = v;
+ offset += 1;
+ }
+ public void putShort(short v) {
+ bytes[offset] = (byte) v;
+ bytes[offset+1] = (byte) (v >>> 8);
+ offset += 2;
+ }
+ public void putInt(int v) {
+ bytes[offset] = (byte) v;
+ bytes[offset+1] = (byte) (v >>> 8);
+ bytes[offset+2] = (byte) (v >>> 16);
+ bytes[offset+3] = (byte) (v >>> 24);
+ offset += 4;
+ }
+ public void putLong(long v) {
+ bytes[offset] = (byte) v;
+ bytes[offset+1] = (byte) (v >>> 8);
+ bytes[offset+2] = (byte) (v >>> 16);
+ bytes[offset+3] = (byte) (v >>> 24);
+ bytes[offset+4] = (byte) (v >>> 32);
+ bytes[offset+5] = (byte) (v >>> 40);
+ bytes[offset+6] = (byte) (v >>> 48);
+ bytes[offset+7] = (byte) (v >>> 56);
+ offset += 8;
+ }
+ public void putFloat(float _v) {
+ int v = Float.floatToIntBits(_v);
+ bytes[offset] = (byte) v;
+ bytes[offset+1] = (byte) (v >>> 8);
+ bytes[offset+2] = (byte) (v >>> 16);
+ bytes[offset+3] = (byte) (v >>> 24);
+ offset += 4;
+ }
+ public void putDouble(double _v) {
+ long v = Double.doubleToLongBits(_v);
+ bytes[offset] = (byte) v;
+ bytes[offset+1] = (byte) (v >>> 8);
+ bytes[offset+2] = (byte) (v >>> 16);
+ bytes[offset+3] = (byte) (v >>> 24);
+ bytes[offset+4] = (byte) (v >>> 32);
+ bytes[offset+5] = (byte) (v >>> 40);
+ bytes[offset+6] = (byte) (v >>> 48);
+ bytes[offset+7] = (byte) (v >>> 56);
+ offset += 8;
+ }
+ public void putString(String str) {
+
+ // UTF-16 -> modified UTF-8
+
+ int length = 4;
+ for(int i=0;i<str.length();++i) {
+ char c = str.charAt(i);
+ if(c < 0x80)
+ length += 1;
+ else if(c < 0x800)
+ length += 2;
+ else
+ length += 3;
+ }
+ needs(length);
+ putInt(str.length());
+ for(int i=0;i<str.length();++i) {
+ char c = str.charAt(i);
+ if(c < 0x80) {
+ bytes[offset] = (byte)c;
+ offset += 1;
+ }
+ else if(c < 0x800) {
+ bytes[offset] = (byte)(0xc0 + (c >>> 6));
+ bytes[offset+1] = (byte)(0x80 + (c & 0x3f));
+ offset += 2;
+ }
+ else {
+ // FIXME handle range D800 - DFFF
+ bytes[offset] = (byte)(0xe0 + (c >>> 12));
+ bytes[offset+1] = (byte)(0x80 + ((c >>> 6) & 0x3f));
+ bytes[offset+2] = (byte)(0x80 + (c & 0x3f));
+ offset += 3;
+ }
+ }
+ }
+ public byte getByte() {
+ ++offset;
+ return bytes[offset-1];
+ }
+ public short getShort() {
+ int v = bytes[offset] & 0xFF;
+ v += (bytes[offset+1] & 0xFF) << 8;
+ offset += 2;
+ return (short)v;
+ }
+ public int getInt() {
+ int v = bytes[offset] & 0xFF;
+ v += (bytes[offset+1] & 0xFF) << 8;
+ v += (bytes[offset+2] & 0xFF) << 16;
+ v += (bytes[offset+3] & 0xFF) << 24;
+ offset += 4;
+ return v;
+ }
+ public long getLong() {
+ long v = bytes[offset] & 0xFFL;
+ v += (bytes[offset+1] & 0xFFL) << 8;
+ v += (bytes[offset+2] & 0xFFL) << 16;
+ v += (bytes[offset+3] & 0xFFL) << 24;
+ v += (bytes[offset+4] & 0xFFL) << 32;
+ v += (bytes[offset+5] & 0xFFL) << 40;
+ v += (bytes[offset+6] & 0xFFL) << 48;
+ v += (bytes[offset+7] & 0xFFL) << 56;
+ offset += 8;
+ return v;
+ }
+ public float getFloat() {
+ int v = bytes[offset] & 0xFF;
+ v += (bytes[offset+1] & 0xFF) << 8;
+ v += (bytes[offset+2] & 0xFF) << 16;
+ v += (bytes[offset+3] & 0xFF) << 24;
+ offset += 4;
+ return Float.intBitsToFloat(v);
+ }
+ public double getDouble() {
+ long v = bytes[offset] & 0xFFL;
+ v += (bytes[offset+1] & 0xFFL) << 8;
+ v += (bytes[offset+2] & 0xFFL) << 16;
+ v += (bytes[offset+3] & 0xFFL) << 24;
+ v += (bytes[offset+4] & 0xFFL) << 32;
+ v += (bytes[offset+5] & 0xFFL) << 40;
+ v += (bytes[offset+6] & 0xFFL) << 48;
+ v += (bytes[offset+7] & 0xFFL) << 56;
+ offset += 8;
+ return Double.longBitsToDouble(v);
+ }
+ public String getString() {
+ int length = getInt();
+ char[] chars = new char[length];
+ for(int i=0;i<length;++i) {
+ int b0 = (int)bytes[offset];
+ int c;
+ if(b0 >= 0) {
+ c = b0;
+ offset += 1;
+ }
+ else if(b0 < 0xe0-256) {
+ c = ((b0 & 0x1f) << 6) +
+ (bytes[offset+1] & 0x3f);
+ offset += 2;
+ }
+ else if(b0 < 0xf0-256) {
+ c = ((b0 & 0x0f) << 12) +
+ ((bytes[offset+1] & 0x3f) << 6) +
+ (bytes[offset+2] & 0x3f);
+ offset += 3;
+ }
+ else
+ c = 0; // FIXME
+ chars[i] = (char)c;
+ }
+ return new String(chars);
+ }
+
+ }
+
+}