rlm@10: /*
rlm@10: * @(#)SeekableByteArrayOutputStream.java 1.0 2010-12-27
rlm@10: *
rlm@68: * Copyright (c) 2010 Werner Randelshofer, Immensee, Switzerland.
rlm@10: * All rights reserved.
rlm@10: *
rlm@10: * You may not use, copy or modify this file, except in compliance with the
rlm@10: * license agreement you entered into with Werner Randelshofer.
rlm@10: * For details see accompanying license terms.
rlm@10: */
rlm@10:
rlm@10: package ca.randelshofer;
rlm@10:
rlm@10: import java.io.ByteArrayOutputStream;
rlm@10: import java.io.IOException;
rlm@10: import java.io.OutputStream;
rlm@10: import java.util.Arrays;
rlm@10: import static java.lang.Math.*;
rlm@10: /**
rlm@10: * {@code SeekableByteArrayOutputStream}.
rlm@10: *
rlm@10: * @author Werner Randelshofer
rlm@10: * @version 1.0 2010-12-27 Created.
rlm@10: */
rlm@10: public class SeekableByteArrayOutputStream extends ByteArrayOutputStream {
rlm@10:
rlm@10: /**
rlm@10: * The current stream position.
rlm@10: */
rlm@10: private int pos;
rlm@10:
rlm@10: /**
rlm@10: * Creates a new byte array output stream. The buffer capacity is
rlm@10: * initially 32 bytes, though its size increases if necessary.
rlm@10: */
rlm@10: public SeekableByteArrayOutputStream() {
rlm@10: this(32);
rlm@10: }
rlm@10:
rlm@10: /**
rlm@10: * Creates a new byte array output stream, with a buffer capacity of
rlm@10: * the specified size, in bytes.
rlm@10: *
rlm@10: * @param size the initial size.
rlm@10: * @exception IllegalArgumentException if size is negative.
rlm@10: */
rlm@10: public SeekableByteArrayOutputStream(int size) {
rlm@10: if (size < 0) {
rlm@10: throw new IllegalArgumentException("Negative initial size: "
rlm@10: + size);
rlm@10: }
rlm@10: buf = new byte[size];
rlm@10: }
rlm@10:
rlm@10: /**
rlm@10: * Writes the specified byte to this byte array output stream.
rlm@10: *
rlm@10: * @param b the byte to be written.
rlm@10: */
rlm@10: @Override
rlm@10: public synchronized void write(int b) {
rlm@10: int newcount = max(pos + 1, count);
rlm@10: if (newcount > buf.length) {
rlm@10: buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
rlm@10: }
rlm@10: buf[pos++] = (byte)b;
rlm@10: count = newcount;
rlm@10: }
rlm@10:
rlm@10: /**
rlm@10: * Writes len
bytes from the specified byte array
rlm@10: * starting at offset off
to this byte array output stream.
rlm@10: *
rlm@10: * @param b the data.
rlm@10: * @param off the start offset in the data.
rlm@10: * @param len the number of bytes to write.
rlm@10: */
rlm@10: @Override
rlm@10: public synchronized void write(byte b[], int off, int len) {
rlm@10: if ((off < 0) || (off > b.length) || (len < 0) ||
rlm@10: ((off + len) > b.length) || ((off + len) < 0)) {
rlm@10: throw new IndexOutOfBoundsException();
rlm@10: } else if (len == 0) {
rlm@10: return;
rlm@10: }
rlm@10: int newcount = max(pos+len,count);
rlm@10: if (newcount > buf.length) {
rlm@10: buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
rlm@10: }
rlm@10: System.arraycopy(b, off, buf, pos, len);
rlm@10: pos+=len;
rlm@10: count = newcount;
rlm@10: }
rlm@10:
rlm@10: /**
rlm@10: * Resets the count
field of this byte array output
rlm@10: * stream to zero, so that all currently accumulated output in the
rlm@10: * output stream is discarded. The output stream can be used again,
rlm@10: * reusing the already allocated buffer space.
rlm@10: *
rlm@10: * @see java.io.ByteArrayInputStream#count
rlm@10: */
rlm@10: @Override
rlm@10: public synchronized void reset() {
rlm@10: count = 0;
rlm@10: pos=0;
rlm@10: }
rlm@10:
rlm@10: /**
rlm@10: * Sets the current stream position to the desired location. The
rlm@10: * next read will occur at this location. The bit offset is set
rlm@10: * to 0.
rlm@10: *
rlm@10: *
An IndexOutOfBoundsException
will be thrown if
rlm@10: * pos
is smaller than the flushed position (as
rlm@10: * returned by getflushedPosition
).
rlm@10: *
rlm@10: *
It is legal to seek past the end of the file; an
rlm@10: * EOFException
will be thrown only if a read is
rlm@10: * performed.
rlm@10: *
rlm@10: * @param pos a long
containing the desired file
rlm@10: * pointer position.
rlm@10: *
rlm@10: * @exception IndexOutOfBoundsException if pos
is smaller
rlm@10: * than the flushed position.
rlm@10: * @exception IOException if any other I/O error occurs.
rlm@10: */
rlm@10: public void seek(long pos) throws IOException {
rlm@10: this.pos = (int)pos;
rlm@10: }
rlm@10:
rlm@10: /**
rlm@10: * Returns the current byte position of the stream. The next write
rlm@10: * will take place starting at this offset.
rlm@10: *
rlm@10: * @return a long containing the position of the stream.
rlm@10: *
rlm@10: * @exception IOException if an I/O error occurs.
rlm@10: */
rlm@10: public long getStreamPosition() throws IOException {
rlm@10: return pos;
rlm@10: }
rlm@10:
rlm@10: /** Writes the contents of the byte array into the specified output
rlm@10: * stream.
rlm@10: * @param out
rlm@10: */
rlm@10: public void toOutputStream(OutputStream out) throws IOException {
rlm@10: out.write(buf, 0, count);
rlm@10: }
rlm@10:
rlm@10: }