package org.simantics.db.common; import java.io.IOException; import java.io.UTFDataFormatException; import java.nio.charset.Charset; import java.util.Arrays; import org.simantics.databoard.Bindings; import org.simantics.databoard.Datatypes; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.binding.error.BindingConstructionException; import org.simantics.databoard.binding.impl.LongBindingDefault; import org.simantics.databoard.binding.impl.StringBindingDefault; import org.simantics.databoard.binding.mutable.Variant; import org.simantics.databoard.serialization.RuntimeSerializerConstructionException; import org.simantics.databoard.serialization.SerializationException; import org.simantics.databoard.serialization.Serializer; import org.simantics.databoard.serialization.impl.LongSerializer; import org.simantics.databoard.serialization.impl.ModifiedUTF8StringSerializer; import org.simantics.graph.representation.External; import org.simantics.graph.representation.Identity; import org.simantics.graph.representation.Internal; import org.simantics.graph.representation.Optional; import org.simantics.graph.representation.Root; import org.simantics.graph.representation.TransferableGraph1; import org.simantics.graph.representation.Value; public class WriteBindings { static class STRING_SERIALIZER extends ModifiedUTF8StringSerializer { public static final Charset UTF8 = Charset.forName("utf-8"); public static STRING_SERIALIZER INSTANCE = new STRING_SERIALIZER(); public STRING_SERIALIZER() { super(STRING_BINDING.INSTANCE); } static byte[] writeUTF(String str) throws IOException { int strlen = str.length(); int utflen = 0; int c/*, count = 0*/; /* use charAt instead of copying String to char array */ for (int i = 0; i < strlen; i++) { c = str.charAt(i); if ((c >= 0x0001) && (c <= 0x007F)) { utflen++; } else if (c > 0x07FF) { utflen += 3; } else { utflen += 2; } } if (utflen > 65535) throw new UTFDataFormatException( "encoded string too long: " + utflen + " bytes"); int byteIndex = 0; byte[] bytearr; if(utflen < 0x80) { bytearr = new byte[utflen+1]; bytearr[byteIndex++] = ((byte)utflen); } else { utflen -= 0x80; if(utflen < 0x4000) { bytearr = new byte[utflen+2]; bytearr[byteIndex++] = (byte)( ((utflen&0x3f) | 0x80) ); bytearr[byteIndex++] = (byte)( (utflen>>>6) ); } else { utflen -= 0x4000; if(utflen < 0x200000) { bytearr = new byte[utflen+3]; bytearr[byteIndex++] = (byte)( ((utflen&0x1f) | 0xc0) ); bytearr[byteIndex++] = (byte)( ((utflen>>>5)&0xff) ); bytearr[byteIndex++] = (byte)( ((utflen>>>13)&0xff) ); } else { utflen -= 0x200000; if(utflen < 0x10000000) { bytearr = new byte[utflen+4]; bytearr[byteIndex++] = (byte)( ((utflen&0x0f) | 0xe0) ); bytearr[byteIndex++] = (byte)( ((utflen>>>4)&0xff) ); bytearr[byteIndex++] = (byte)( ((utflen>>>12)&0xff) ); bytearr[byteIndex++] = (byte)( ((utflen>>>20)&0xff) ); } else { utflen -= 0x10000000; bytearr = new byte[utflen+5]; bytearr[byteIndex++] = (byte)( ((utflen&0x07) | 0xf0) ); bytearr[byteIndex++] = (byte)( ((utflen>>>3)&0xff) ); bytearr[byteIndex++] = (byte)( ((utflen>>>11)&0xff) ); bytearr[byteIndex++] = (byte)( ((utflen>>>19)&0xff) ); bytearr[byteIndex++] = (byte)( ((utflen>>>27)&0xff) ); } } } } int i=0; for (i=0; i= 0x0001) && (c <= 0x007F))) break; bytearr[byteIndex++] = (byte)(c); } for (;i < strlen; i++){ c = str.charAt(i); if ((c >= 0x0001) && (c <= 0x007F)) { bytearr[byteIndex++] = (byte)( c ); } else if (c > 0x07FF) { bytearr[byteIndex++] = (byte)(0xE0 | ((c >> 12) & 0x0F)); bytearr[byteIndex++] = (byte)(0x80 | ((c >> 6) & 0x3F)); bytearr[byteIndex++] = (byte)(0x80 | ((c >> 0) & 0x3F)); } else { bytearr[byteIndex++] = (byte)(0xC0 | ((c >> 6) & 0x1F)); bytearr[byteIndex++] = (byte)(0x80 | ((c >> 0) & 0x3F)); } } return bytearr; } @Override public byte[] serialize(Object obj) throws IOException { try { return writeUTF((String)obj); } catch (IOException e) { throw new SerializationException(); } } } static class BYTE_ARRAY_SERIALIZER extends LongSerializer { public static BYTE_ARRAY_SERIALIZER INSTANCE = new BYTE_ARRAY_SERIALIZER(); public BYTE_ARRAY_SERIALIZER() { super(BYTE_ARRAY_BINDING.INSTANCE); } @Override public byte[] serialize(Object obj) throws IOException { return (byte[])obj; } @Override public Object deserialize(byte[] data) throws IOException { return data; } } final static class LONG_ARRAY_SERIALIZER extends LongSerializer { public static LONG_ARRAY_SERIALIZER INSTANCE = new LONG_ARRAY_SERIALIZER(); public LONG_ARRAY_SERIALIZER() { super(LONG_ARRAY_BINDING.INSTANCE); } final private void loop(byte[] result, int index, long l) { result[index+7] = (byte)l;l >>>= 8; result[index+6] = (byte)l;l >>>= 8; result[index+5] = (byte)l;l >>>= 8; result[index+4] = (byte)l;l >>>= 8; result[index+3] = (byte)l;l >>>= 8; result[index+2] = (byte)l;l >>>= 8; result[index+1] = (byte)l;l >>>= 8; result[index] = (byte)l;l >>>= 8; // result[index+6] = (byte)(l & 0xFF); // l >>>= 8; // result[index+5] = (byte)(l & 0xFF); // l >>>= 8; // result[index+4] = (byte)(l & 0xFF); // l >>>= 8; // result[index+3] = (byte)(l & 0xFF); // l >>>= 8; // result[index+2] = (byte)(l & 0xFF); // l >>>= 8; // result[index+1] = (byte)(l & 0xFF); // l >>>= 8; // result[index] = (byte)(l & 0xFF); // l >>>= 8; } @Override public byte[] serialize(Object obj) throws IOException { long[] data = (long[])obj; byte[] result = new byte[4+8*data.length]; int len = data.length; result[3] = (byte)(len & 0xFF); len >>>= 8; result[2] = (byte)(len & 0xFF); len >>>= 8; result[1] = (byte)(len & 0xFF); len >>>= 8; result[0] = (byte)(len & 0xFF); int index = 4; for(int i=0;i>>= 8; // result[index+6] = (byte)(l & 0xFF); // l >>>= 8; // result[index+5] = (byte)(l & 0xFF); // l >>>= 8; // result[index+4] = (byte)(l & 0xFF); // l >>>= 8; // result[index+3] = (byte)(l & 0xFF); // l >>>= 8; // result[index+2] = (byte)(l & 0xFF); // l >>>= 8; // result[index+1] = (byte)(l & 0xFF); // l >>>= 8; // result[index] = (byte)(l & 0xFF); // l >>>= 8; index += 8; } return result; } } static class TRANSFERABLE_GRAPH_SERIALIZER extends LongSerializer { public static TRANSFERABLE_GRAPH_SERIALIZER INSTANCE = new TRANSFERABLE_GRAPH_SERIALIZER(); public TRANSFERABLE_GRAPH_SERIALIZER() { super(TRANSFERABLE_GRAPH_BINDING.INSTANCE); } static int writeUTF(String str, byte[] bytearr, int byteIndex) throws IOException { int strlen = str.length(); int utflen = 0; int c; int count = byteIndex; /* use charAt instead of copying String to char array */ for (int i = 0; i < strlen; i++) { c = str.charAt(i); if ((c >= 0x0001) && (c <= 0x007F)) { utflen++; } else if (c > 0x07FF) { utflen += 3; } else { utflen += 2; } } if (utflen > 65535) throw new UTFDataFormatException( "encoded string too long: " + utflen + " bytes"); // byte[] bytearr = new byte[utflen+2]; if(utflen < 0x80) { bytearr[count++] = ((byte)utflen); } else { utflen -= 0x80; if(utflen < 0x4000) { bytearr[count++] = (byte)( ((utflen&0x3f) | 0x80) ); bytearr[count++] = (byte)( (utflen>>>6) ); } else { utflen -= 0x4000; if(utflen < 0x200000) { bytearr[count++] = (byte)( ((utflen&0x1f) | 0xc0) ); bytearr[count++] = (byte)( ((utflen>>>5)&0xff) ); bytearr[count++] = (byte)( ((utflen>>>13)&0xff) ); } else { utflen -= 0x200000; if(utflen < 0x10000000) { bytearr[count++] = (byte)( ((utflen&0x0f) | 0xe0) ); bytearr[count++] = (byte)( ((utflen>>>4)&0xff) ); bytearr[count++] = (byte)( ((utflen>>>12)&0xff) ); bytearr[count++] = (byte)( ((utflen>>>20)&0xff) ); } else { utflen -= 0x10000000; bytearr[count++] = (byte)( ((utflen&0x07) | 0xf0) ); bytearr[count++] = (byte)( ((utflen>>>3)&0xff) ); bytearr[count++] = (byte)( ((utflen>>>11)&0xff) ); bytearr[count++] = (byte)( ((utflen>>>19)&0xff) ); bytearr[count++] = (byte)( ((utflen>>>27)&0xff) ); } } } } int i=0; for (i=0; i= 0x0001) && (c <= 0x007F))) break; bytearr[count++] = (byte) c; } for (;i < strlen; i++){ c = str.charAt(i); if ((c >= 0x0001) && (c <= 0x007F)) { bytearr[count++] = (byte) c; } else if (c > 0x07FF) { bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F)); bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F)); bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F)); } else { bytearr[count++] = (byte) (0xC0 | ((c >> 6) & 0x1F)); bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F)); } } return count - byteIndex; } @Override public byte[] serialize(Object obj) throws IOException { TransferableGraph1 tg = (TransferableGraph1)obj; return Bindings .getSerializerUnchecked(TransferableGraph1.class) .serialize(tg); /* // 16 = resourceCount + 3 arrays // long start = System.nanoTime(); int actualSize = 16 + 8*tg.values.length + 4*tg.statements.length + 5*tg.identities.length; for(Value v : tg.values) actualSize += v.value.length; for(Identity id : tg.identities) { if(id.definition instanceof Internal) actualSize += (4 + ((Internal)id.definition).name.length() + 5); else if(id.definition instanceof External) actualSize += (4 + ((External)id.definition).name.length() + 5); else if(id.definition instanceof Root) actualSize += (((Root)id.definition).name.length() + ((Root)id.definition).type.length() + 10); else if(id.definition instanceof Optional) actualSize += (4 + ((Optional)id.definition).name.length() + 5); } // long end = System.nanoTime() - start; // System.err.println("size took " + 1e-9*end); // long start2 = System.nanoTime(); byte[] bytes = new byte[actualSize]; int byteIndex = 0; int i = tg.resourceCount; bytes[byteIndex+3] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+2] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+1] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex] = (byte)(i & 0xFF);i >>>= 8; byteIndex+=4; i = tg.identities.length; bytes[byteIndex+3] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+2] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+1] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex] = (byte)(i & 0xFF);i >>>= 8; byteIndex+=4; for(Identity id : tg.identities) { i = id.resource; bytes[byteIndex+3] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+2] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+1] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex] = (byte)(i & 0xFF);i >>>= 8; byteIndex+=4; if(id.definition instanceof Internal) { Internal r = (Internal)id.definition; bytes[byteIndex++] = 3; i = r.parent; bytes[byteIndex+3] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+2] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+1] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex] = (byte)(i & 0xFF);i >>>= 8; byteIndex+=4; byteIndex += writeUTF(r.name, bytes, byteIndex); } else if(id.definition instanceof External) { External r = (External)id.definition; bytes[byteIndex++] = 1; i = r.parent; bytes[byteIndex+3] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+2] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+1] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex] = (byte)(i & 0xFF);i >>>= 8; byteIndex+=4; byteIndex += writeUTF(r.name, bytes, byteIndex); } else if(id.definition instanceof Root) { bytes[byteIndex++] = 0; Root r = (Root)id.definition; byteIndex += writeUTF(r.name, bytes, byteIndex); byteIndex += writeUTF(r.type, bytes, byteIndex); } else if(id.definition instanceof Optional) { Optional r = (Optional)id.definition; bytes[byteIndex++] = 2; i = r.parent; bytes[byteIndex+3] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+2] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+1] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex] = (byte)(i & 0xFF);i >>>= 8; byteIndex+=4; byteIndex += writeUTF(r.name, bytes, byteIndex); } } i = tg.statements.length; bytes[byteIndex+3] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+2] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+1] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex] = (byte)(i & 0xFF);i >>>= 8; byteIndex+=4; for(int s : tg.statements) { i = s; bytes[byteIndex+3] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+2] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+1] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex] = (byte)(i & 0xFF);i >>>= 8; byteIndex+=4; } i = tg.values.length; bytes[byteIndex+3] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+2] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+1] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex] = (byte)(i & 0xFF);i >>>= 8; byteIndex+=4; for(Value v : tg.values) { i = v.resource; bytes[byteIndex+3] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+2] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+1] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex] = (byte)(i & 0xFF);i >>>= 8; byteIndex+=4; i = v.value.length; bytes[byteIndex+3] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+2] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex+1] = (byte)(i & 0xFF);i >>>= 8; bytes[byteIndex] = (byte)(i & 0xFF);i >>>= 8; byteIndex+=4; System.arraycopy(v.value, 0, bytes, byteIndex, v.value.length); byteIndex += v.value.length; } // return bytes; // byte[] result = new byte[byteIndex]; // System.arraycopy(bytes, 0, result, 0, byteIndex); // // byte[] result = Arrays.copyOf(bytes, byteIndex); // long end2 = System.nanoTime() - start2; // System.err.println("size2 took " + 1e-9*end2); return bytes; // long[] data = (long[])obj; // byte[] result = new byte[4+8*data.length]; // // int len = data.length; // // result[3] = (byte)(len & 0xFF); // len >>>= 8; // result[2] = (byte)(len & 0xFF); // len >>>= 8; // result[1] = (byte)(len & 0xFF); // len >>>= 8; // result[0] = (byte)(len & 0xFF); // // int index = 4; // // for(int i=0;i>>= 8; // result[index+6] = (byte)(l & 0xFF); // l >>>= 8; // result[index+5] = (byte)(l & 0xFF); // l >>>= 8; // result[index+4] = (byte)(l & 0xFF); // l >>>= 8; // result[index+3] = (byte)(l & 0xFF); // l >>>= 8; // result[index+2] = (byte)(l & 0xFF); // l >>>= 8; // result[index+1] = (byte)(l & 0xFF); // l >>>= 8; // result[index] = (byte)(l & 0xFF); // l >>>= 8; // // index += 8; // // } // // return result; */ } final private String utf(byte[] bytes) { char[] chars = new char[bytes.length]; int index = 0; int length = bytes[index++]&0xff; if(length >= 0x80) { if(length >= 0xc0) { if(length >= 0xe0) { if(length >= 0xf0) { length &= 0x0f; length += ((bytes[index++]&0xff)<<3); length += ((bytes[index++]&0xff)<<11); length += ((bytes[index++]&0xff)<<19); length += 0x10204080; } else { length &= 0x1f; length += ((bytes[index++]&0xff)<<4); length += ((bytes[index++]&0xff)<<12); length += ((bytes[index++]&0xff)<<20); length += 0x204080; } } else { length &= 0x3f; length += ((bytes[index++]&0xff)<<5); length += ((bytes[index++]&0xff)<<13); length += 0x4080; } } else { length &= 0x7f; length += ((bytes[index++]&0xff)<<6); length += 0x80; } } int i = 0; int target = length+index; while(index < target) { int c = bytes[index++]&0xff; if(c <= 0x7F) { chars[i++] = (char)(c&0x7F); } else if (c > 0x07FF) { int c2 = bytes[index++]&0xff; int c3 = bytes[index++]&0xff; chars[i++] = (char)(((c&0xf)<<12) + ((c2&0x3f)<<6) + (c3&0x3f)); } else { int c2 = bytes[index++]&0xff; chars[i++] = (char)(((c&0x1f)<<6) + (c2&0x3f)); } } return new String(chars, 0, i); } @Override public Object deserialize(byte[] data) throws IOException { return utf(data); } } static class STRING_BINDING extends StringBindingDefault { public static STRING_BINDING INSTANCE = new STRING_BINDING(); public STRING_BINDING() { super(Datatypes.STRING); } @Override public Serializer serializer() throws RuntimeSerializerConstructionException { return STRING_SERIALIZER.INSTANCE; } @Override public boolean isInstance(Object obj) { return obj instanceof String; } } static class BYTE_ARRAY_BINDING extends LongBindingDefault { public static BYTE_ARRAY_BINDING INSTANCE = new BYTE_ARRAY_BINDING(); public BYTE_ARRAY_BINDING() { super(Datatypes.LONG); } @Override public Serializer serializer() throws RuntimeSerializerConstructionException { return BYTE_ARRAY_SERIALIZER.INSTANCE; } @Override public boolean isInstance(Object obj) { return obj instanceof byte[]; } } static class LONG_ARRAY_BINDING extends LongBindingDefault { public static LONG_ARRAY_BINDING INSTANCE = new LONG_ARRAY_BINDING(); public LONG_ARRAY_BINDING() { super(Datatypes.LONG); } @Override public Serializer serializer() throws RuntimeSerializerConstructionException { return LONG_ARRAY_SERIALIZER.INSTANCE; } } static class TRANSFERABLE_GRAPH_BINDING extends LongBindingDefault { public static TRANSFERABLE_GRAPH_BINDING INSTANCE = new TRANSFERABLE_GRAPH_BINDING(); public TRANSFERABLE_GRAPH_BINDING() { super(Datatypes.LONG); } @Override public Serializer serializer() throws RuntimeSerializerConstructionException { return TRANSFERABLE_GRAPH_SERIALIZER.INSTANCE; } } public static Binding STRING = STRING_BINDING.INSTANCE; public static Binding BYTE_ARRAY = BYTE_ARRAY_BINDING.INSTANCE; public static Binding LONG_ARRAY = LONG_ARRAY_BINDING.INSTANCE; public static Binding TRANSFERABLE_GRAPH = TRANSFERABLE_GRAPH_BINDING.INSTANCE; public static void main(String[] args) { TransferableGraph1 tg = new TransferableGraph1(123,new Identity[] { new Identity(11, new Root("foo", "bar1")), new Identity(12, new External(21, "bar2")), new Identity(13, new Internal(22, "bar3")), new Identity(14, new Optional(23, "bar4")) }, new int[] { 1, 2, 3 }, new Value[] { new Value(31, new Variant(Bindings.INTEGER, 123)) }); try { System.err.println(Arrays.toString(Bindings.getSerializerUnchecked(Bindings.getBinding(TransferableGraph1.class)).serialize(tg))); System.err.println(Arrays.toString(WriteBindings.TRANSFERABLE_GRAPH_SERIALIZER.INSTANCE.serialize(tg))); } catch (RuntimeSerializerConstructionException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (BindingConstructionException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }