package org.openlca.cloud.api.data; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.util.zip.GZIPInputStream; import org.openlca.cloud.model.data.Dataset; import org.openlca.util.BinUtils; import com.google.gson.Gson; public class ModelStreamReader implements Closeable { private final Gson gson = new Gson(); private final InputStream stream; private final int total; private int read; public ModelStreamReader(InputStream stream) throws IOException { this.stream = stream; this.total = readNextInt(); } public String readNextPartAsString() throws IOException { return new String(readNextPart(), ModelStream.CHARSET); } public boolean hasMore() { return read < total; } public int getTotal() { return total; } public Dataset readNextPartAsDataset() throws IOException { byte[] dataset = readNextPart(); read++; dataset = BinUtils.gunzip(dataset); String json = new String(dataset, ModelStream.CHARSET); return gson.fromJson(json, Dataset.class); } public boolean readNextPartToStream(OutputStream out) throws IOException { int length = readNextInt(); return readBytes(length, out, true); } public byte[] readNextPart() throws IOException { int length = readNextInt(); if (length == 0) return new byte[0]; return readBytes(length); } public int readNextInt() throws IOException { byte[] bytes = readBytes(4); return ByteBuffer.wrap(bytes).getInt(); } private byte[] readBytes(int length) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); readBytes(length, out, false); return out.toByteArray(); } private boolean readBytes(int length, OutputStream out, boolean decrypt) throws IOException { if (length == 0) return false; InputStream in = new FixedLengthInputStream(length); if (decrypt) { in = new GZIPInputStream(in); } byte[] buffer = new byte[1024]; int count = -1; while ((count = in.read(buffer)) >= 0) { out.write(buffer, 0, count); } in.close(); return true; } @Override public void close() throws IOException { stream.close(); } private class FixedLengthInputStream extends InputStream { private final int length; private int totalRead = 0; private FixedLengthInputStream(int length) { this.length = length; } @Override public int read() throws IOException { if (totalRead == length) return -1; totalRead++; return stream.read(); } } }