package org.simantics.db.common.utils; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.Arrays; import org.simantics.databoard.Bindings; import org.simantics.databoard.Files; import org.simantics.databoard.binding.Binding; import org.simantics.databoard.serialization.Serializer; import org.simantics.databoard.type.Datatype; import org.simantics.databoard.util.binary.RandomAccessBinary; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.WriteGraph; import org.simantics.db.exception.DatabaseException; import org.simantics.layer0.Layer0; /** * Converts byte[] literals to files and back. These utilities are not usable * for literals of any other type than byte[]. */ public class LiteralFileUtil { public static void copyByteArrayToFile(ReadGraph g, Resource source, File target) throws DatabaseException, IOException { byte[] data = g.getValue(source, Bindings.BYTE_ARRAY); OutputStream stream = new FileOutputStream(target); try { // TODO: For some peculiar reason a direct stream.write(data) OOMs with approx. 70MB array for(int pos = 0;pos < data.length;) { int len = Math.min(65536, data.length-pos); stream.write(data,pos,len); pos += len; } } finally { stream.close(); } } public static void copyByteArrayToFile(ReadGraph g, Resource subject, Resource predicate, File target) throws DatabaseException, IOException { Resource source = g.getSingleObject(subject, predicate); copyByteArrayToFile(g, source, target); } public static void copyRandomAccessBinaryToFile(ReadGraph g, Resource source, File target) throws DatabaseException, IOException { OutputStream stream = new FileOutputStream(target); try { RandomAccessBinary rab = g.getRandomAccessBinary(source); // Skip byte array length data according to databoard byte[] serialization rules. rab.position(4); ByteBuffer bb = ByteBuffer.wrap(new byte[65536]); byte[] bbArray = bb.array(); while (rab.position() < rab.length()) { rab.readFully(bb, (int) Math.min(bbArray.length, rab.length() - rab.position())); stream.write(bbArray, 0, bb.position()); bb.position(0); } } finally { stream.close(); } } public static void copyRandomAccessBinaryFromFile(File source, RandomAccessBinary rab) throws IOException { ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[65536]); FileInputStream stream = new FileInputStream(source); FileChannel channel = stream.getChannel(); try { rab.position(0); rab.writeInt((int)source.length()); while(channel.read(byteBuffer) != -1) { byteBuffer.limit(byteBuffer.position()); byteBuffer.position(0); rab.writeFully(byteBuffer); byteBuffer.position(0); } } finally { stream.close(); } // Make sure the RAB file will not be longer than the // source file due to possible previously existing data. rab.setLength(rab.position()); rab.flush(); } public static void copyRandomAccessBinaryToFile(ReadGraph g, Resource subject, Resource predicate, File target) throws DatabaseException, IOException { Resource source = g.getSingleObject(subject, predicate); copyRandomAccessBinaryToFile(g, source, target); } public static void copyToFileWithBinding(ReadGraph g, Resource source, File target, Binding binding) throws DatabaseException, IOException { // Datatyyppi tieto on jo resurssissa, eik�? // Sidonnan saisi Bindings.getBinding( type ) Object value = g.getValue(source, binding); Serializer s = Bindings.getSerializerUnchecked(binding); s.serialize(value, target); } public static void copyToFileWithBinding(ReadGraph g, Resource subject, Resource predicate, File target, Binding binding) throws DatabaseException, IOException { Resource source = g.getSingleObject(subject, predicate); copyToFileWithBinding(g, source, target, binding); } public static void copyToFileAsVariant(ReadGraph g, Resource source, File target, Binding binding) throws DatabaseException, IOException { Object value = g.getValue(source, binding); Files.createFile(target, binding, value); } public static void copyToFileAsVariant(ReadGraph g, Resource source, File target) throws DatabaseException, IOException { Datatype type = g.getDataType(source); Binding binding = Bindings.getBinding(type); copyToFileAsVariant(g, source, target, binding); } public static void copyToFileAsVariant(ReadGraph g, Resource subject, Resource predicate, File target) throws DatabaseException, IOException { Resource source = g.getSingleObject(subject, predicate); copyToFileAsVariant(g, source, target); } public static void copyByteArrayFromFile(WriteGraph g, File source, Resource target) throws DatabaseException, IOException { InputStream stream = new FileInputStream(source); byte[] data = new byte[(int)source.length()]; stream.read(data); stream.close(); g.claimValue(target, data, Bindings.BYTE_ARRAY); } public static void copyByteArrayFromFile(WriteGraph g, File source, Resource subject, Resource predicate) throws DatabaseException, IOException { InputStream stream = new FileInputStream(source); byte[] data = new byte[(int)source.length()]; stream.read(data); stream.close(); g.claimLiteral(subject, predicate, data, Bindings.BYTE_ARRAY); } /** * @param g * @param source * @param subject * @param predicate * @throws DatabaseException * @throws IOException */ public static void streamingCopyByteArrayFromFile(WriteGraph g, File source, Resource subject, Resource predicate) throws DatabaseException, IOException { Resource target = g.getPossibleObject(subject, predicate); if (target == null) { Layer0 L0 = Layer0.getInstance(g); target = g.newResource(); g.claim(target, L0.InstanceOf, null, L0.ByteArray); g.claim(subject, predicate, target); } InputStream stream = new FileInputStream(source); try { copyStreamToRandomAccessBinary(g, stream, target); } finally { stream.close(); } } public static void copyByteArrayFromStream(WriteGraph g, InputStream source, Resource target) throws IOException, DatabaseException { byte[] buffer = new byte[0x10000]; int pos = 0; while(true) { int count = source.read(buffer, pos, buffer.length - pos); if(count <= 0) break; pos += count; if(pos == buffer.length) buffer = Arrays.copyOf(buffer, (pos * 3) / 2); } buffer = Arrays.copyOf(buffer, pos); g.claimValue(target, buffer, Bindings.BYTE_ARRAY); } public static void copyStreamToRandomAccessBinary(WriteGraph g, InputStream source, Resource target) throws IOException, DatabaseException { RandomAccessBinary rab = g.getRandomAccessBinary(target); byte[] buffer = new byte[0x10000]; if (rab.length() < 4) rab.setLength(4); rab.position(4); int length = 0; while (true) { int count = source.read(buffer, 0, buffer.length); if (count <= 0) break; rab.write(buffer, 0, count); length += count; } rab.position(0); rab.writeInt(length); rab.flush(); } }