package com.esotericsoftware.kryo.io;
import java.io.IOException;
import java.io.InputStream;
import com.esotericsoftware.kryo.KryoException;
import static com.esotericsoftware.minlog.Log.*;
/** An InputStream that reads lengths and chunks of data from another OutputStream, allowing chunks to be skipped.
* @author Nathan Sweet <misc@n4te.com> */
public class InputChunked extends Input {
private int chunkSize = -1;
/** Creates an uninitialized InputChunked with a buffer size of 2048. The InputStream must be set before it can be used. */
public InputChunked () {
super(2048);
}
/** Creates an uninitialized InputChunked. The InputStream must be set before it can be used. */
public InputChunked (int bufferSize) {
super(bufferSize);
}
/** Creates an InputChunked with a buffer size of 2048. */
public InputChunked (InputStream inputStream) {
super(inputStream, 2048);
}
public InputChunked (InputStream inputStream, int bufferSize) {
super(inputStream, bufferSize);
}
public void setInputStream (InputStream inputStream) {
super.setInputStream(inputStream);
chunkSize = -1;
}
public void setBuffer (byte[] bytes, int offset, int count) {
super.setBuffer(bytes, offset, count);
chunkSize = -1;
}
public void rewind () {
super.rewind();
chunkSize = -1;
}
protected int fill (byte[] buffer, int offset, int count) throws KryoException {
if (chunkSize == -1) // No current chunk, expect a new chunk.
readChunkSize();
else if (chunkSize == 0) // End of chunks.
return -1;
int actual = super.fill(buffer, offset, Math.min(chunkSize, count));
chunkSize -= actual;
if (chunkSize == 0) readChunkSize(); // Read next chunk size.
return actual;
}
private void readChunkSize () {
try {
InputStream inputStream = getInputStream();
for (int offset = 0, result = 0; offset < 32; offset += 7) {
int b = inputStream.read();
if (b == -1) throw new KryoException("Buffer underflow.");
result |= (b & 0x7F) << offset;
if ((b & 0x80) == 0) {
chunkSize = result;
if (TRACE) trace("kryo", "Read chunk: " + chunkSize);
return;
}
}
} catch (IOException ex) {
throw new KryoException(ex);
}
throw new KryoException("Malformed integer.");
}
/** Advances the stream to the next set of chunks. InputChunked will appear to hit the end of the data until this method is
* called. */
public void nextChunks () {
if (chunkSize == -1) readChunkSize(); // No current chunk, expect a new chunk.
while (chunkSize > 0)
skip(chunkSize);
chunkSize = -1;
if (TRACE) trace("kryo", "Next chunks.");
}
}