package org.simantics.graph.representation;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.util.ArrayList;
import java.util.List;
import org.simantics.databoard.Bindings;
import org.simantics.databoard.Datatypes;
import org.simantics.databoard.binding.error.RuntimeDatatypeConstructionException;
import org.simantics.databoard.binding.mutable.Variant;
import org.simantics.databoard.container.DataContainer;
import org.simantics.databoard.container.DataContainers;
import org.simantics.databoard.serialization.RuntimeSerializerConstructionException;
import org.simantics.databoard.serialization.Serializer;
import org.simantics.databoard.type.Datatype;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* It is recommended to use {@link #read(File)} and {@link #read(InputStream)}
* for reading to ensure proper resource handling.
*/
final public class TransferableGraphFileReader extends ByteFileReader {
private static final Logger LOGGER = LoggerFactory.getLogger(TransferableGraphFileReader.class);
InputStream in = new InputStream() {
@Override
public int read() throws IOException {
return getByte();
}
@Override
public int read(byte[] b) throws IOException {
// FIXME not correctly implemented
System.arraycopy(safeBytes(b.length), 0, b, 0, b.length);
return b.length;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
// FIXME not correctly implemented
System.arraycopy(safeBytes(len), 0, b, off, len);
return len;
}
};
private static boolean init = true;
final private static int SIZE = 1<<18;
final private static int HEADER = headerSize();
final private int header;
/**
* Reads a {@link DataContainer} containing a {@link TransferableGraph1}
* structure from the specified {@link File}.
*
* @param file the file to read from
* @return the TG contained by the file
* @throws IOException
*/
public static TransferableGraph1 read(File file) throws IOException {
try (TransferableGraphFileReader reader = new TransferableGraphFileReader(file)) {
return reader.readTG();
}
}
/**
* Reads a {@link DataContainer} containing a {@link TransferableGraph1}
* structure from the specified InputStream. Note that this implementation does
* not close the specified input
stream, it is expected to be
* closed by the caller.
*
* @param input the input stream to read from
* @return the TG contained by the stream
* @throws IOException
*/
public static TransferableGraph1 read(InputStream input) throws IOException {
try (TransferableGraphFileReader reader = new TransferableGraphFileReader(input)) {
return reader.readTG();
}
}
public TransferableGraphFileReader(File file) throws IOException {
super(file, SIZE);
if(init) {
init=false;
TransferableGraphFileReader r = new TransferableGraphFileReader(file, 0);
for(int i=0;i<40000;i++) r.readTG();
}
this.header = HEADER;
}
public TransferableGraphFileReader(InputStream stream) throws IOException {
super(null, new InputChannel(stream), SIZE);
if(init) {
init=false;
TransferableGraphFileReader r = new TransferableGraphFileReader(stream, 0);
for(int i=0;i<40000;i++) r.readTG();
}
this.header = 0;
}
public TransferableGraphFileReader(ReadableByteChannel channel) throws IOException {
super(null, channel, SIZE);
if(init) {
init=false;
TransferableGraphFileReader r = new TransferableGraphFileReader(channel, 0);
for(int i=0;i<40000;i++) r.readTG();
}
this.header = 0;
}
public TransferableGraphFileReader(ReadableByteChannel channel, int size) throws IOException {
super(null, channel, SIZE);
this.header = 0;
}
public TransferableGraphFileReader(InputStream stream, int size) throws IOException {
super(null, new InputChannel(stream), size);
this.header = 0;
}
public TransferableGraphFileReader(File file, int size) throws IOException {
super(file, size);
this.header = HEADER;
}
private static int headerSize() {
try {
return Bindings.getSerializerUnchecked(Datatype.class).serialize(Datatypes.getDatatypeUnchecked(TransferableGraph1.class)).length;
} catch (RuntimeSerializerConstructionException e) {
throw new Error("Failed to determine TransferableGraph1 header size. ", e);
} catch (RuntimeDatatypeConstructionException e) {
throw new Error("Failed to determine TransferableGraph1 header size. ", e);
} catch (IOException e) {
throw new Error("Failed to determine TransferableGraph1 header size. ", e);
}
}
public TransferableGraph1 readTG() throws IOException {
if(getSize() == 0) return null;
// long start = System.nanoTime();
final byte[] bytes = getBytes();
// byteIndex = header;
DataInputStream dis = new DataInputStream(in);
// Header
DataContainers.readHeader(dis);
// Content variant data type
Bindings.getSerializerUnchecked(Datatype.class).deserialize((DataInput)dis);
int resourceCount = safeInt();
List