You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
5.2 KiB
203 lines
5.2 KiB
/*
|
|
* Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
|
|
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
package javax.imageio.stream;
|
|
|
|
import java.io.InputStream;
|
|
import java.io.IOException;
|
|
import com.sun.imageio.stream.StreamFinalizer;
|
|
import sun.java2d.Disposer;
|
|
import sun.java2d.DisposerRecord;
|
|
|
|
/**
|
|
* An implementation of <code>ImageInputStream</code> that gets its
|
|
* input from a regular <code>InputStream</code>. A memory buffer is
|
|
* used to cache at least the data between the discard position and
|
|
* the current read position.
|
|
*
|
|
* <p> In general, it is preferable to use a
|
|
* <code>FileCacheImageInputStream</code> when reading from a regular
|
|
* <code>InputStream</code>. This class is provided for cases where
|
|
* it is not possible to create a writable temporary file.
|
|
*
|
|
*/
|
|
public class MemoryCacheImageInputStream extends ImageInputStreamImpl {
|
|
|
|
private InputStream stream;
|
|
|
|
private MemoryCache cache = new MemoryCache();
|
|
|
|
/** The referent to be registered with the Disposer. */
|
|
private final Object disposerReferent;
|
|
|
|
/** The DisposerRecord that resets the underlying MemoryCache. */
|
|
private final DisposerRecord disposerRecord;
|
|
|
|
/**
|
|
* Constructs a <code>MemoryCacheImageInputStream</code> that will read
|
|
* from a given <code>InputStream</code>.
|
|
*
|
|
* @param stream an <code>InputStream</code> to read from.
|
|
*
|
|
* @exception IllegalArgumentException if <code>stream</code> is
|
|
* <code>null</code>.
|
|
*/
|
|
public MemoryCacheImageInputStream(InputStream stream) {
|
|
if (stream == null) {
|
|
throw new IllegalArgumentException("stream == null!");
|
|
}
|
|
this.stream = stream;
|
|
|
|
disposerRecord = new StreamDisposerRecord(cache);
|
|
if (getClass() == MemoryCacheImageInputStream.class) {
|
|
disposerReferent = new Object();
|
|
Disposer.addRecord(disposerReferent, disposerRecord);
|
|
} else {
|
|
disposerReferent = new StreamFinalizer(this);
|
|
}
|
|
}
|
|
|
|
public int read() throws IOException {
|
|
checkClosed();
|
|
bitOffset = 0;
|
|
long pos = cache.loadFromStream(stream, streamPos+1);
|
|
if (pos >= streamPos+1) {
|
|
return cache.read(streamPos++);
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
public int read(byte[] b, int off, int len) throws IOException {
|
|
checkClosed();
|
|
|
|
if (b == null) {
|
|
throw new NullPointerException("b == null!");
|
|
}
|
|
if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {
|
|
throw new IndexOutOfBoundsException
|
|
("off < 0 || len < 0 || off+len > b.length || off+len < 0!");
|
|
}
|
|
|
|
bitOffset = 0;
|
|
|
|
if (len == 0) {
|
|
return 0;
|
|
}
|
|
|
|
long pos = cache.loadFromStream(stream, streamPos+len);
|
|
|
|
len = (int)(pos - streamPos); // In case stream ended early
|
|
|
|
if (len > 0) {
|
|
cache.read(b, off, len, streamPos);
|
|
streamPos += len;
|
|
return len;
|
|
} else {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
public void flushBefore(long pos) throws IOException {
|
|
super.flushBefore(pos); // this will call checkClosed() for us
|
|
cache.disposeBefore(pos);
|
|
}
|
|
|
|
/**
|
|
* Returns <code>true</code> since this
|
|
* <code>ImageInputStream</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>ImageInputStream</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>ImageInputStream</code> maintains a main memory cache.
|
|
*
|
|
* @return <code>true</code>.
|
|
*
|
|
* @see #isCached
|
|
* @see #isCachedFile
|
|
*/
|
|
public boolean isCachedMemory() {
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Closes this <code>MemoryCacheImageInputStream</code>, freeing
|
|
* the cache. The source <code>InputStream</code> is not closed.
|
|
*/
|
|
public void close() throws IOException {
|
|
super.close();
|
|
disposerRecord.dispose(); // this resets the MemoryCache
|
|
stream = null;
|
|
cache = null;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
protected void finalize() throws Throwable {
|
|
// Empty finalizer: for performance reasons we instead use the
|
|
// Disposer mechanism for ensuring that the underlying
|
|
// MemoryCache is reset prior to garbage collection
|
|
}
|
|
|
|
private static class StreamDisposerRecord implements DisposerRecord {
|
|
private MemoryCache cache;
|
|
|
|
public StreamDisposerRecord(MemoryCache cache) {
|
|
this.cache = cache;
|
|
}
|
|
|
|
public synchronized void dispose() {
|
|
if (cache != null) {
|
|
cache.reset();
|
|
cache = null;
|
|
}
|
|
}
|
|
}
|
|
}
|