/******************************************************************************* * 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= 0) { buffer.needs(constantSize); unsafeSerialize(buffer, obj); } else { Object[] subobjects = (Object[])obj; // FIXME Catch cast exception // FIXME Check length for(int i=0;i= 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= 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 bytes.length) { // FIXME bytes = Arrays.copyOf(bytes, newSize); byte[] newBytes = new byte[offset*2 + size]; for(int i=0;i>> 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>> 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= 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); } } }