package freenet.support.io;
import java.io.DataOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import freenet.support.api.Bucket;
import freenet.support.api.BucketFactory;
/** Write to a temporary Bucket. On close, if not abort()'ed, write length and then copy the
* data. Does not close the underlying Bucket. */
public class PrependLengthOutputStream extends FilterOutputStream {
private final Bucket temp;
private final OutputStream origOS;
private final int offset;
private final boolean closeUnderlying;
private boolean aborted;
private boolean closed;
/** Create a stream which writes to temporary space and then on a non-aborted close() will
* write the length (minus the offset) followed by the data. */
public static PrependLengthOutputStream create(OutputStream out, BucketFactory bf, int offset, boolean closeUnderlying) throws IOException {
Bucket temp = bf.makeBucket(-1);
OutputStream os = temp.getOutputStream();
return new PrependLengthOutputStream(os, temp, out, offset, closeUnderlying);
}
private PrependLengthOutputStream(OutputStream os, Bucket temp, OutputStream origOS, int offset, boolean closeUnderlying) {
super(os);
this.temp = temp;
this.origOS = origOS;
this.offset = offset;
this.closeUnderlying = closeUnderlying;
}
@Override
public void write(byte[] buf, int offset, int length) throws IOException {
// Unfortunately this is necessary because FilterOutputStream passes everything through write(int).
out.write(buf, offset, length);
}
@Override
public void write(byte[] buf) throws IOException {
write(buf, 0, buf.length);
}
/** Abort the stream. Will write a length of 0 when close()'ed.
* @return False if the stream has already been closed. */
public boolean abort() throws IOException {
if(closed) return false;
aborted = true;
return true;
}
@Override
public void close() throws IOException {
if(closed) return;
out.close();
DataOutputStream dos = new DataOutputStream(origOS);
if(aborted) {
dos.writeLong(0);
} else {
dos.writeLong(temp.size() - offset);
BucketTools.copyTo(temp, dos, Long.MAX_VALUE);
}
temp.free();
closed = true;
if(closeUnderlying)
dos.close();
}
}