- /*
- * @(#)MemoryCacheImageOutputStream.java 1.16 03/01/23
- *
- * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
-
- package javax.imageio.stream;
-
- import java.io.IOException;
- import java.io.OutputStream;
-
- /**
- * An implementation of <code>ImageOutputStream</code> that writes its
- * output to a regular <code>OutputStream</code>. A memory buffer is
- * used to cache at least the data between the discard position and
- * the current write position. The only constructor takes an
- * <code>OutputStream</code>, so this class may not be used for
- * read/modify/write operations. Reading can occur only on parts of
- * the stream that have already been written to the cache and not
- * yet flushed.
- *
- * @version 0.5
- */
- public class MemoryCacheImageOutputStream extends ImageOutputStreamImpl {
-
- private OutputStream stream;
-
- private MemoryCache cache = new MemoryCache();
-
- /**
- * Constructs a <code>MemoryCacheImageOutputStream</code> that will write
- * to a given <code>OutputStream</code>.
- *
- * @param stream an <code>OutputStream</code> to write to.
- *
- * @exception IllegalArgumentException if <code>stream</code> is
- * <code>null</code>.
- */
- public MemoryCacheImageOutputStream(OutputStream stream) {
- if (stream == null) {
- throw new IllegalArgumentException("stream == null!");
- }
- this.stream = stream;
- }
-
- public int read() throws IOException {
- checkClosed();
-
- bitOffset = 0;
-
- int val = cache.read(streamPos);
- if (val != -1) {
- ++streamPos;
- }
- return val;
- }
-
- public int read(byte[] b, int off, int len) throws IOException {
- checkClosed();
-
- // Fix 4467619: read([B,I,I) doesn't throw NPE as specified
- // Fix 4467608: read([B,I,I) works incorrectly if len<=0
- // Will throw NullPointerException if b == null
- // Will throw IIOBE if off, len are bad args
- if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {
- throw new IndexOutOfBoundsException
- ("off < 0 || len < 0 || off + len > b.length!");
- }
-
- bitOffset = 0;
-
- if (len == 0) {
- return 0;
- }
-
- // check if we're already at/past EOF i.e.
- // no more bytes left to read from cache
- long bytesLeftInCache = cache.getLength() - streamPos;
- if (bytesLeftInCache <= 0) {
- return -1; // EOF
- }
-
- // guaranteed by now that bytesLeftInCache > 0 && len > 0
- // and so the rest of the error checking is done by cache.read()
- // NOTE that alot of error checking is duplicated
- len = (int)Math.min(bytesLeftInCache, (long)len);
- cache.read(b, off, len, streamPos);
- streamPos += len;
- return len;
- }
-
- public void write(int b) throws IOException {
- checkClosed();
- flushBits();
- cache.write(b, streamPos);
- ++streamPos;
- }
-
- public void write(byte[] b, int off, int len) throws IOException {
- checkClosed();
- flushBits();
- cache.write(b, off, len, streamPos);
- streamPos += len;
- }
-
- public long length() {
- return cache.getLength();
- }
-
- /**
- * Returns <code>true</code> since this
- * <code>ImageOutputStream</code> caches data in order to allow
- * seeking backwards.
- *
- * @return <code>true</code>.
- *
- * @see #isCachedMemory
- * @see #isCachedFile
- */
- public boolean isCached() {
- return true;
- }
-
- /**
- * Returns <code>false</code> since this
- * <code>ImageOutputStream</code> does not maintain a file cache.
- *
- * @return <code>false</code>.
- *
- * @see #isCached
- * @see #isCachedMemory
- */
- public boolean isCachedFile() {
- return false;
- }
-
- /**
- * Returns <code>true</code> since this
- * <code>ImageOutputStream</code> maintains a main memory cache.
- *
- * @return <code>true</code>.
- *
- * @see #isCached
- * @see #isCachedFile
- */
- public boolean isCachedMemory() {
- return true;
- }
-
- /**
- * Closes this <code>MemoryCacheImageOutputStream</code>. All
- * pending data is flushed to the output, and the cache
- * is released. The destination <code>OutputStream</code>
- * is not closed.
- */
- public void close() throws IOException {
- long length = cache.getLength();
- seek(length);
- flushBefore(length);
- super.close();
- cache.reset();
- stream = null;
- }
-
- public void flushBefore(long pos) throws IOException {
- long oFlushedPos = flushedPos;
- super.flushBefore(pos);
-
- long flushBytes = flushedPos - oFlushedPos;
- cache.writeToStream(stream, oFlushedPos, flushBytes);
- cache.disposeBefore(flushedPos);
- stream.flush();
- }
- }