feat(jdk8): move files to new folder to avoid resources compiled.
This commit is contained in:
294
jdkSrc/jdk8/javax/imageio/stream/FileCacheImageInputStream.java
Normal file
294
jdkSrc/jdk8/javax/imageio/stream/FileCacheImageInputStream.java
Normal file
@@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.imageio.stream;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.file.Files;
|
||||
import com.sun.imageio.stream.StreamCloser;
|
||||
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 file is used to
|
||||
* cache previously read data.
|
||||
*
|
||||
*/
|
||||
public class FileCacheImageInputStream extends ImageInputStreamImpl {
|
||||
|
||||
private InputStream stream;
|
||||
|
||||
private File cacheFile;
|
||||
|
||||
private RandomAccessFile cache;
|
||||
|
||||
private static final int BUFFER_LENGTH = 1024;
|
||||
|
||||
private byte[] buf = new byte[BUFFER_LENGTH];
|
||||
|
||||
private long length = 0L;
|
||||
|
||||
private boolean foundEOF = false;
|
||||
|
||||
/** The referent to be registered with the Disposer. */
|
||||
private final Object disposerReferent;
|
||||
|
||||
/** The DisposerRecord that closes the underlying cache. */
|
||||
private final DisposerRecord disposerRecord;
|
||||
|
||||
/** The CloseAction that closes the stream in
|
||||
* the StreamCloser's shutdown hook */
|
||||
private final StreamCloser.CloseAction closeAction;
|
||||
|
||||
/**
|
||||
* Constructs a <code>FileCacheImageInputStream</code> that will read
|
||||
* from a given <code>InputStream</code>.
|
||||
*
|
||||
* <p> A temporary file is used as a cache. If
|
||||
* <code>cacheDir</code>is non-<code>null</code> and is a
|
||||
* directory, the file will be created there. If it is
|
||||
* <code>null</code>, the system-dependent default temporary-file
|
||||
* directory will be used (see the documentation for
|
||||
* <code>File.createTempFile</code> for details).
|
||||
*
|
||||
* @param stream an <code>InputStream</code> to read from.
|
||||
* @param cacheDir a <code>File</code> indicating where the
|
||||
* cache file should be created, or <code>null</code> to use the
|
||||
* system directory.
|
||||
*
|
||||
* @exception IllegalArgumentException if <code>stream</code> is
|
||||
* <code>null</code>.
|
||||
* @exception IllegalArgumentException if <code>cacheDir</code> is
|
||||
* non-<code>null</code> but is not a directory.
|
||||
* @exception IOException if a cache file cannot be created.
|
||||
*/
|
||||
public FileCacheImageInputStream(InputStream stream, File cacheDir)
|
||||
throws IOException {
|
||||
if (stream == null) {
|
||||
throw new IllegalArgumentException("stream == null!");
|
||||
}
|
||||
if ((cacheDir != null) && !(cacheDir.isDirectory())) {
|
||||
throw new IllegalArgumentException("Not a directory!");
|
||||
}
|
||||
this.stream = stream;
|
||||
if (cacheDir == null)
|
||||
this.cacheFile = Files.createTempFile("imageio", ".tmp").toFile();
|
||||
else
|
||||
this.cacheFile = Files.createTempFile(cacheDir.toPath(), "imageio", ".tmp")
|
||||
.toFile();
|
||||
this.cache = new RandomAccessFile(cacheFile, "rw");
|
||||
|
||||
this.closeAction = StreamCloser.createCloseAction(this);
|
||||
StreamCloser.addToQueue(closeAction);
|
||||
|
||||
disposerRecord = new StreamDisposerRecord(cacheFile, cache);
|
||||
if (getClass() == FileCacheImageInputStream.class) {
|
||||
disposerReferent = new Object();
|
||||
Disposer.addRecord(disposerReferent, disposerRecord);
|
||||
} else {
|
||||
disposerReferent = new StreamFinalizer(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that at least <code>pos</code> bytes are cached,
|
||||
* or the end of the source is reached. The return value
|
||||
* is equal to the smaller of <code>pos</code> and the
|
||||
* length of the source file.
|
||||
*/
|
||||
private long readUntil(long pos) throws IOException {
|
||||
// We've already got enough data cached
|
||||
if (pos < length) {
|
||||
return pos;
|
||||
}
|
||||
// pos >= length but length isn't getting any bigger, so return it
|
||||
if (foundEOF) {
|
||||
return length;
|
||||
}
|
||||
|
||||
long len = pos - length;
|
||||
cache.seek(length);
|
||||
while (len > 0) {
|
||||
// Copy a buffer's worth of data from the source to the cache
|
||||
// BUFFER_LENGTH will always fit into an int so this is safe
|
||||
int nbytes =
|
||||
stream.read(buf, 0, (int)Math.min(len, (long)BUFFER_LENGTH));
|
||||
if (nbytes == -1) {
|
||||
foundEOF = true;
|
||||
return length;
|
||||
}
|
||||
|
||||
cache.write(buf, 0, nbytes);
|
||||
len -= nbytes;
|
||||
length += nbytes;
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
checkClosed();
|
||||
bitOffset = 0;
|
||||
long next = streamPos + 1;
|
||||
long pos = readUntil(next);
|
||||
if (pos >= next) {
|
||||
cache.seek(streamPos++);
|
||||
return cache.read();
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
checkClosed();
|
||||
|
||||
if (b == null) {
|
||||
throw new NullPointerException("b == null!");
|
||||
}
|
||||
// Fix 4430357 - if off + len < 0, overflow occurred
|
||||
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 = readUntil(streamPos + len);
|
||||
|
||||
// len will always fit into an int so this is safe
|
||||
len = (int)Math.min((long)len, pos - streamPos);
|
||||
if (len > 0) {
|
||||
cache.seek(streamPos);
|
||||
cache.readFully(b, off, len);
|
||||
streamPos += len;
|
||||
return len;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>true</code> since this
|
||||
* <code>ImageInputStream</code> maintains a file cache.
|
||||
*
|
||||
* @return <code>true</code>.
|
||||
*
|
||||
* @see #isCached
|
||||
* @see #isCachedMemory
|
||||
*/
|
||||
public boolean isCachedFile() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>false</code> since this
|
||||
* <code>ImageInputStream</code> does not maintain a main memory
|
||||
* cache.
|
||||
*
|
||||
* @return <code>false</code>.
|
||||
*
|
||||
* @see #isCached
|
||||
* @see #isCachedFile
|
||||
*/
|
||||
public boolean isCachedMemory() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this <code>FileCacheImageInputStream</code>, closing
|
||||
* and removing the cache file. The source <code>InputStream</code>
|
||||
* is not closed.
|
||||
*
|
||||
* @exception IOException if an error occurs.
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
disposerRecord.dispose(); // this will close/delete the cache file
|
||||
stream = null;
|
||||
cache = null;
|
||||
cacheFile = null;
|
||||
StreamCloser.removeFromQueue(closeAction);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected void finalize() throws Throwable {
|
||||
// Empty finalizer: for performance reasons we instead use the
|
||||
// Disposer mechanism for ensuring that the underlying
|
||||
// RandomAccessFile is closed/deleted prior to garbage collection
|
||||
}
|
||||
|
||||
private static class StreamDisposerRecord implements DisposerRecord {
|
||||
private File cacheFile;
|
||||
private RandomAccessFile cache;
|
||||
|
||||
public StreamDisposerRecord(File cacheFile, RandomAccessFile cache) {
|
||||
this.cacheFile = cacheFile;
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
public synchronized void dispose() {
|
||||
if (cache != null) {
|
||||
try {
|
||||
cache.close();
|
||||
} catch (IOException e) {
|
||||
} finally {
|
||||
cache = null;
|
||||
}
|
||||
}
|
||||
if (cacheFile != null) {
|
||||
cacheFile.delete();
|
||||
cacheFile = null;
|
||||
}
|
||||
// Note: Explicit removal of the stream from the StreamCloser
|
||||
// queue is not mandatory in this case, as it will be removed
|
||||
// automatically by GC shortly after this method is called.
|
||||
}
|
||||
}
|
||||
}
|
||||
261
jdkSrc/jdk8/javax/imageio/stream/FileCacheImageOutputStream.java
Normal file
261
jdkSrc/jdk8/javax/imageio/stream/FileCacheImageOutputStream.java
Normal file
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.imageio.stream;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.file.Files;
|
||||
import com.sun.imageio.stream.StreamCloser;
|
||||
|
||||
/**
|
||||
* An implementation of <code>ImageOutputStream</code> that writes its
|
||||
* output to a regular <code>OutputStream</code>. A file is used to
|
||||
* cache data until it is flushed to the output stream.
|
||||
*
|
||||
*/
|
||||
public class FileCacheImageOutputStream extends ImageOutputStreamImpl {
|
||||
|
||||
private OutputStream stream;
|
||||
|
||||
private File cacheFile;
|
||||
|
||||
private RandomAccessFile cache;
|
||||
|
||||
// Pos after last (rightmost) byte written
|
||||
private long maxStreamPos = 0L;
|
||||
|
||||
/** The CloseAction that closes the stream in
|
||||
* the StreamCloser's shutdown hook */
|
||||
private final StreamCloser.CloseAction closeAction;
|
||||
|
||||
/**
|
||||
* Constructs a <code>FileCacheImageOutputStream</code> that will write
|
||||
* to a given <code>outputStream</code>.
|
||||
*
|
||||
* <p> A temporary file is used as a cache. If
|
||||
* <code>cacheDir</code>is non-<code>null</code> and is a
|
||||
* directory, the file will be created there. If it is
|
||||
* <code>null</code>, the system-dependent default temporary-file
|
||||
* directory will be used (see the documentation for
|
||||
* <code>File.createTempFile</code> for details).
|
||||
*
|
||||
* @param stream an <code>OutputStream</code> to write to.
|
||||
* @param cacheDir a <code>File</code> indicating where the
|
||||
* cache file should be created, or <code>null</code> to use the
|
||||
* system directory.
|
||||
*
|
||||
* @exception IllegalArgumentException if <code>stream</code>
|
||||
* is <code>null</code>.
|
||||
* @exception IllegalArgumentException if <code>cacheDir</code> is
|
||||
* non-<code>null</code> but is not a directory.
|
||||
* @exception IOException if a cache file cannot be created.
|
||||
*/
|
||||
public FileCacheImageOutputStream(OutputStream stream, File cacheDir)
|
||||
throws IOException {
|
||||
if (stream == null) {
|
||||
throw new IllegalArgumentException("stream == null!");
|
||||
}
|
||||
if ((cacheDir != null) && !(cacheDir.isDirectory())) {
|
||||
throw new IllegalArgumentException("Not a directory!");
|
||||
}
|
||||
this.stream = stream;
|
||||
if (cacheDir == null)
|
||||
this.cacheFile = Files.createTempFile("imageio", ".tmp").toFile();
|
||||
else
|
||||
this.cacheFile = Files.createTempFile(cacheDir.toPath(), "imageio", ".tmp")
|
||||
.toFile();
|
||||
this.cache = new RandomAccessFile(cacheFile, "rw");
|
||||
|
||||
this.closeAction = StreamCloser.createCloseAction(this);
|
||||
StreamCloser.addToQueue(closeAction);
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
checkClosed();
|
||||
bitOffset = 0;
|
||||
int val = cache.read();
|
||||
if (val != -1) {
|
||||
++streamPos;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int nbytes = cache.read(b, off, len);
|
||||
if (nbytes != -1) {
|
||||
streamPos += nbytes;
|
||||
}
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
flushBits(); // this will call checkClosed() for us
|
||||
cache.write(b);
|
||||
++streamPos;
|
||||
maxStreamPos = Math.max(maxStreamPos, streamPos);
|
||||
}
|
||||
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
flushBits(); // this will call checkClosed() for us
|
||||
cache.write(b, off, len);
|
||||
streamPos += len;
|
||||
maxStreamPos = Math.max(maxStreamPos, streamPos);
|
||||
}
|
||||
|
||||
public long length() {
|
||||
try {
|
||||
checkClosed();
|
||||
return cache.length();
|
||||
} catch (IOException e) {
|
||||
return -1L;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current stream position and resets the bit offset to
|
||||
* 0. It is legal to seek past the end of the file; an
|
||||
* <code>EOFException</code> will be thrown only if a read is
|
||||
* performed. The file length will not be increased until a write
|
||||
* is performed.
|
||||
*
|
||||
* @exception IndexOutOfBoundsException if <code>pos</code> is smaller
|
||||
* than the flushed position.
|
||||
* @exception IOException if any other I/O error occurs.
|
||||
*/
|
||||
public void seek(long pos) throws IOException {
|
||||
checkClosed();
|
||||
|
||||
if (pos < flushedPos) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
cache.seek(pos);
|
||||
this.streamPos = cache.getFilePointer();
|
||||
maxStreamPos = Math.max(maxStreamPos, streamPos);
|
||||
this.bitOffset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>true</code> since this
|
||||
* <code>ImageOutputStream</code> maintains a file cache.
|
||||
*
|
||||
* @return <code>true</code>.
|
||||
*
|
||||
* @see #isCached
|
||||
* @see #isCachedMemory
|
||||
*/
|
||||
public boolean isCachedFile() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>false</code> since this
|
||||
* <code>ImageOutputStream</code> does not maintain a main memory
|
||||
* cache.
|
||||
*
|
||||
* @return <code>false</code>.
|
||||
*
|
||||
* @see #isCached
|
||||
* @see #isCachedFile
|
||||
*/
|
||||
public boolean isCachedMemory() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes this <code>FileCacheImageOutputStream</code>. All
|
||||
* pending data is flushed to the output, and the cache file
|
||||
* is closed and removed. The destination <code>OutputStream</code>
|
||||
* is not closed.
|
||||
*
|
||||
* @exception IOException if an error occurs.
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
maxStreamPos = cache.length();
|
||||
|
||||
seek(maxStreamPos);
|
||||
flushBefore(maxStreamPos);
|
||||
super.close();
|
||||
cache.close();
|
||||
cache = null;
|
||||
cacheFile.delete();
|
||||
cacheFile = null;
|
||||
stream.flush();
|
||||
stream = null;
|
||||
StreamCloser.removeFromQueue(closeAction);
|
||||
}
|
||||
|
||||
public void flushBefore(long pos) throws IOException {
|
||||
long oFlushedPos = flushedPos;
|
||||
super.flushBefore(pos); // this will call checkClosed() for us
|
||||
|
||||
long flushBytes = flushedPos - oFlushedPos;
|
||||
if (flushBytes > 0) {
|
||||
int bufLen = 512;
|
||||
byte[] buf = new byte[bufLen];
|
||||
cache.seek(oFlushedPos);
|
||||
while (flushBytes > 0) {
|
||||
int len = (int)Math.min(flushBytes, bufLen);
|
||||
cache.readFully(buf, 0, len);
|
||||
stream.write(buf, 0, len);
|
||||
flushBytes -= len;
|
||||
}
|
||||
stream.flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
164
jdkSrc/jdk8/javax/imageio/stream/FileImageInputStream.java
Normal file
164
jdkSrc/jdk8/javax/imageio/stream/FileImageInputStream.java
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.imageio.stream;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import com.sun.imageio.stream.CloseableDisposerRecord;
|
||||
import com.sun.imageio.stream.StreamFinalizer;
|
||||
import sun.java2d.Disposer;
|
||||
|
||||
/**
|
||||
* An implementation of <code>ImageInputStream</code> that gets its
|
||||
* input from a <code>File</code> or <code>RandomAccessFile</code>.
|
||||
* The file contents are assumed to be stable during the lifetime of
|
||||
* the object.
|
||||
*
|
||||
*/
|
||||
public class FileImageInputStream extends ImageInputStreamImpl {
|
||||
|
||||
private RandomAccessFile raf;
|
||||
|
||||
/** The referent to be registered with the Disposer. */
|
||||
private final Object disposerReferent;
|
||||
|
||||
/** The DisposerRecord that closes the underlying RandomAccessFile. */
|
||||
private final CloseableDisposerRecord disposerRecord;
|
||||
|
||||
/**
|
||||
* Constructs a <code>FileImageInputStream</code> that will read
|
||||
* from a given <code>File</code>.
|
||||
*
|
||||
* <p> The file contents must not change between the time this
|
||||
* object is constructed and the time of the last call to a read
|
||||
* method.
|
||||
*
|
||||
* @param f a <code>File</code> to read from.
|
||||
*
|
||||
* @exception IllegalArgumentException if <code>f</code> is
|
||||
* <code>null</code>.
|
||||
* @exception SecurityException if a security manager exists
|
||||
* and does not allow read access to the file.
|
||||
* @exception FileNotFoundException if <code>f</code> is a
|
||||
* directory or cannot be opened for reading for any other reason.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
public FileImageInputStream(File f)
|
||||
throws FileNotFoundException, IOException {
|
||||
this(f == null ? null : new RandomAccessFile(f, "r"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>FileImageInputStream</code> that will read
|
||||
* from a given <code>RandomAccessFile</code>.
|
||||
*
|
||||
* <p> The file contents must not change between the time this
|
||||
* object is constructed and the time of the last call to a read
|
||||
* method.
|
||||
*
|
||||
* @param raf a <code>RandomAccessFile</code> to read from.
|
||||
*
|
||||
* @exception IllegalArgumentException if <code>raf</code> is
|
||||
* <code>null</code>.
|
||||
*/
|
||||
public FileImageInputStream(RandomAccessFile raf) {
|
||||
if (raf == null) {
|
||||
throw new IllegalArgumentException("raf == null!");
|
||||
}
|
||||
this.raf = raf;
|
||||
|
||||
disposerRecord = new CloseableDisposerRecord(raf);
|
||||
if (getClass() == FileImageInputStream.class) {
|
||||
disposerReferent = new Object();
|
||||
Disposer.addRecord(disposerReferent, disposerRecord);
|
||||
} else {
|
||||
disposerReferent = new StreamFinalizer(this);
|
||||
}
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
checkClosed();
|
||||
bitOffset = 0;
|
||||
int val = raf.read();
|
||||
if (val != -1) {
|
||||
++streamPos;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
checkClosed();
|
||||
bitOffset = 0;
|
||||
int nbytes = raf.read(b, off, len);
|
||||
if (nbytes != -1) {
|
||||
streamPos += nbytes;
|
||||
}
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the underlying file, or <code>-1</code>
|
||||
* if it is unknown.
|
||||
*
|
||||
* @return the file length as a <code>long</code>, or
|
||||
* <code>-1</code>.
|
||||
*/
|
||||
public long length() {
|
||||
try {
|
||||
checkClosed();
|
||||
return raf.length();
|
||||
} catch (IOException e) {
|
||||
return -1L;
|
||||
}
|
||||
}
|
||||
|
||||
public void seek(long pos) throws IOException {
|
||||
checkClosed();
|
||||
if (pos < flushedPos) {
|
||||
throw new IndexOutOfBoundsException("pos < flushedPos!");
|
||||
}
|
||||
bitOffset = 0;
|
||||
raf.seek(pos);
|
||||
streamPos = raf.getFilePointer();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
disposerRecord.dispose(); // this closes the RandomAccessFile
|
||||
raf = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected void finalize() throws Throwable {
|
||||
// Empty finalizer: for performance reasons we instead use the
|
||||
// Disposer mechanism for ensuring that the underlying
|
||||
// RandomAccessFile is closed prior to garbage collection
|
||||
}
|
||||
}
|
||||
172
jdkSrc/jdk8/javax/imageio/stream/FileImageOutputStream.java
Normal file
172
jdkSrc/jdk8/javax/imageio/stream/FileImageOutputStream.java
Normal file
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.imageio.stream;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import com.sun.imageio.stream.CloseableDisposerRecord;
|
||||
import com.sun.imageio.stream.StreamFinalizer;
|
||||
import sun.java2d.Disposer;
|
||||
|
||||
/**
|
||||
* An implementation of <code>ImageOutputStream</code> that writes its
|
||||
* output directly to a <code>File</code> or
|
||||
* <code>RandomAccessFile</code>.
|
||||
*
|
||||
*/
|
||||
public class FileImageOutputStream extends ImageOutputStreamImpl {
|
||||
|
||||
private RandomAccessFile raf;
|
||||
|
||||
/** The referent to be registered with the Disposer. */
|
||||
private final Object disposerReferent;
|
||||
|
||||
/** The DisposerRecord that closes the underlying RandomAccessFile. */
|
||||
private final CloseableDisposerRecord disposerRecord;
|
||||
|
||||
/**
|
||||
* Constructs a <code>FileImageOutputStream</code> that will write
|
||||
* to a given <code>File</code>.
|
||||
*
|
||||
* @param f a <code>File</code> to write to.
|
||||
*
|
||||
* @exception IllegalArgumentException if <code>f</code> is
|
||||
* <code>null</code>.
|
||||
* @exception SecurityException if a security manager exists
|
||||
* and does not allow write access to the file.
|
||||
* @exception FileNotFoundException if <code>f</code> does not denote
|
||||
* a regular file or it cannot be opened for reading and writing for any
|
||||
* other reason.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
public FileImageOutputStream(File f)
|
||||
throws FileNotFoundException, IOException {
|
||||
this(f == null ? null : new RandomAccessFile(f, "rw"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a <code>FileImageOutputStream</code> that will write
|
||||
* to a given <code>RandomAccessFile</code>.
|
||||
*
|
||||
* @param raf a <code>RandomAccessFile</code> to write to.
|
||||
*
|
||||
* @exception IllegalArgumentException if <code>raf</code> is
|
||||
* <code>null</code>.
|
||||
*/
|
||||
public FileImageOutputStream(RandomAccessFile raf) {
|
||||
if (raf == null) {
|
||||
throw new IllegalArgumentException("raf == null!");
|
||||
}
|
||||
this.raf = raf;
|
||||
|
||||
disposerRecord = new CloseableDisposerRecord(raf);
|
||||
if (getClass() == FileImageOutputStream.class) {
|
||||
disposerReferent = new Object();
|
||||
Disposer.addRecord(disposerReferent, disposerRecord);
|
||||
} else {
|
||||
disposerReferent = new StreamFinalizer(this);
|
||||
}
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
checkClosed();
|
||||
bitOffset = 0;
|
||||
int val = raf.read();
|
||||
if (val != -1) {
|
||||
++streamPos;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
checkClosed();
|
||||
bitOffset = 0;
|
||||
int nbytes = raf.read(b, off, len);
|
||||
if (nbytes != -1) {
|
||||
streamPos += nbytes;
|
||||
}
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
flushBits(); // this will call checkClosed() for us
|
||||
raf.write(b);
|
||||
++streamPos;
|
||||
}
|
||||
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
flushBits(); // this will call checkClosed() for us
|
||||
raf.write(b, off, len);
|
||||
streamPos += len;
|
||||
}
|
||||
|
||||
public long length() {
|
||||
try {
|
||||
checkClosed();
|
||||
return raf.length();
|
||||
} catch (IOException e) {
|
||||
return -1L;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current stream position and resets the bit offset to
|
||||
* 0. It is legal to seeking past the end of the file; an
|
||||
* <code>EOFException</code> will be thrown only if a read is
|
||||
* performed. The file length will not be increased until a write
|
||||
* is performed.
|
||||
*
|
||||
* @exception IndexOutOfBoundsException if <code>pos</code> is smaller
|
||||
* than the flushed position.
|
||||
* @exception IOException if any other I/O error occurs.
|
||||
*/
|
||||
public void seek(long pos) throws IOException {
|
||||
checkClosed();
|
||||
if (pos < flushedPos) {
|
||||
throw new IndexOutOfBoundsException("pos < flushedPos!");
|
||||
}
|
||||
bitOffset = 0;
|
||||
raf.seek(pos);
|
||||
streamPos = raf.getFilePointer();
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
super.close();
|
||||
disposerRecord.dispose(); // this closes the RandomAccessFile
|
||||
raf = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
protected void finalize() throws Throwable {
|
||||
// Empty finalizer: for performance reasons we instead use the
|
||||
// Disposer mechanism for ensuring that the underlying
|
||||
// RandomAccessFile is closed prior to garbage collection
|
||||
}
|
||||
}
|
||||
143
jdkSrc/jdk8/javax/imageio/stream/IIOByteBuffer.java
Normal file
143
jdkSrc/jdk8/javax/imageio/stream/IIOByteBuffer.java
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.imageio.stream;
|
||||
|
||||
/**
|
||||
* A class representing a mutable reference to an array of bytes and
|
||||
* an offset and length within that array. <code>IIOByteBuffer</code>
|
||||
* is used by <code>ImageInputStream</code> to supply a sequence of bytes
|
||||
* to the caller, possibly with fewer copies than using the conventional
|
||||
* <code>read</code> methods that take a user-supplied byte array.
|
||||
*
|
||||
* <p> The byte array referenced by an <code>IIOByteBuffer</code> will
|
||||
* generally be part of an internal data structure belonging to an
|
||||
* <code>ImageReader</code> implementation; its contents should be
|
||||
* considered read-only and must not be modified.
|
||||
*
|
||||
*/
|
||||
public class IIOByteBuffer {
|
||||
|
||||
private byte[] data;
|
||||
|
||||
private int offset;
|
||||
|
||||
private int length;
|
||||
|
||||
/**
|
||||
* Constructs an <code>IIOByteBuffer</code> that references a
|
||||
* given byte array, offset, and length.
|
||||
*
|
||||
* @param data a byte array.
|
||||
* @param offset an int offset within the array.
|
||||
* @param length an int specifying the length of the data of
|
||||
* interest within byte array, in bytes.
|
||||
*/
|
||||
public IIOByteBuffer(byte[] data, int offset, int length) {
|
||||
this.data = data;
|
||||
this.offset = offset;
|
||||
this.length = length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the byte array. The returned value should
|
||||
* be treated as read-only, and only the portion specified by the
|
||||
* values of <code>getOffset</code> and <code>getLength</code> should
|
||||
* be used.
|
||||
*
|
||||
* @return a byte array reference.
|
||||
*
|
||||
* @see #getOffset
|
||||
* @see #getLength
|
||||
* @see #setData
|
||||
*/
|
||||
public byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the array reference that will be returned by subsequent calls
|
||||
* to the <code>getData</code> method.
|
||||
*
|
||||
* @param data a byte array reference containing the new data value.
|
||||
*
|
||||
* @see #getData
|
||||
*/
|
||||
public void setData(byte[] data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offset within the byte array returned by
|
||||
* <code>getData</code> at which the data of interest start.
|
||||
*
|
||||
* @return an int offset.
|
||||
*
|
||||
* @see #getData
|
||||
* @see #getLength
|
||||
* @see #setOffset
|
||||
*/
|
||||
public int getOffset() {
|
||||
return offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the value that will be returned by subsequent calls
|
||||
* to the <code>getOffset</code> method.
|
||||
*
|
||||
* @param offset an int containing the new offset value.
|
||||
*
|
||||
* @see #getOffset
|
||||
*/
|
||||
public void setOffset(int offset) {
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the data of interest within the byte
|
||||
* array returned by <code>getData</code>.
|
||||
*
|
||||
* @return an int length.
|
||||
*
|
||||
* @see #getData
|
||||
* @see #getOffset
|
||||
* @see #setLength
|
||||
*/
|
||||
public int getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the value that will be returned by subsequent calls
|
||||
* to the <code>getLength</code> method.
|
||||
*
|
||||
* @param length an int containing the new length value.
|
||||
*
|
||||
* @see #getLength
|
||||
*/
|
||||
public void setLength(int length) {
|
||||
this.length = length;
|
||||
}
|
||||
}
|
||||
1000
jdkSrc/jdk8/javax/imageio/stream/ImageInputStream.java
Normal file
1000
jdkSrc/jdk8/javax/imageio/stream/ImageInputStream.java
Normal file
File diff suppressed because it is too large
Load Diff
880
jdkSrc/jdk8/javax/imageio/stream/ImageInputStreamImpl.java
Normal file
880
jdkSrc/jdk8/javax/imageio/stream/ImageInputStreamImpl.java
Normal file
@@ -0,0 +1,880 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.imageio.stream;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteOrder;
|
||||
import java.util.Stack;
|
||||
import javax.imageio.IIOException;
|
||||
|
||||
/**
|
||||
* An abstract class implementing the <code>ImageInputStream</code> interface.
|
||||
* This class is designed to reduce the number of methods that must
|
||||
* be implemented by subclasses.
|
||||
*
|
||||
* <p> In particular, this class handles most or all of the details of
|
||||
* byte order interpretation, buffering, mark/reset, discarding,
|
||||
* closing, and disposing.
|
||||
*/
|
||||
public abstract class ImageInputStreamImpl implements ImageInputStream {
|
||||
|
||||
private Stack markByteStack = new Stack();
|
||||
|
||||
private Stack markBitStack = new Stack();
|
||||
|
||||
private boolean isClosed = false;
|
||||
|
||||
// Length of the buffer used for readFully(type[], int, int)
|
||||
private static final int BYTE_BUF_LENGTH = 8192;
|
||||
|
||||
/**
|
||||
* Byte buffer used for readFully(type[], int, int). Note that this
|
||||
* array is also used for bulk reads in readShort(), readInt(), etc, so
|
||||
* it should be large enough to hold a primitive value (i.e. >= 8 bytes).
|
||||
* Also note that this array is package protected, so that it can be
|
||||
* used by ImageOutputStreamImpl in a similar manner.
|
||||
*/
|
||||
byte[] byteBuf = new byte[BYTE_BUF_LENGTH];
|
||||
|
||||
/**
|
||||
* The byte order of the stream as an instance of the enumeration
|
||||
* class <code>java.nio.ByteOrder</code>, where
|
||||
* <code>ByteOrder.BIG_ENDIAN</code> indicates network byte order
|
||||
* and <code>ByteOrder.LITTLE_ENDIAN</code> indicates the reverse
|
||||
* order. By default, the value is
|
||||
* <code>ByteOrder.BIG_ENDIAN</code>.
|
||||
*/
|
||||
protected ByteOrder byteOrder = ByteOrder.BIG_ENDIAN;
|
||||
|
||||
/**
|
||||
* The current read position within the stream. Subclasses are
|
||||
* responsible for keeping this value current from any method they
|
||||
* override that alters the read position.
|
||||
*/
|
||||
protected long streamPos;
|
||||
|
||||
/**
|
||||
* The current bit offset within the stream. Subclasses are
|
||||
* responsible for keeping this value current from any method they
|
||||
* override that alters the bit offset.
|
||||
*/
|
||||
protected int bitOffset;
|
||||
|
||||
/**
|
||||
* The position prior to which data may be discarded. Seeking
|
||||
* to a smaller position is not allowed. <code>flushedPos</code>
|
||||
* will always be {@literal >= 0}.
|
||||
*/
|
||||
protected long flushedPos = 0;
|
||||
|
||||
/**
|
||||
* Constructs an <code>ImageInputStreamImpl</code>.
|
||||
*/
|
||||
public ImageInputStreamImpl() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws an <code>IOException</code> if the stream has been closed.
|
||||
* Subclasses may call this method from any of their methods that
|
||||
* require the stream not to be closed.
|
||||
*
|
||||
* @exception IOException if the stream is closed.
|
||||
*/
|
||||
protected final void checkClosed() throws IOException {
|
||||
if (isClosed) {
|
||||
throw new IOException("closed");
|
||||
}
|
||||
}
|
||||
|
||||
public void setByteOrder(ByteOrder byteOrder) {
|
||||
this.byteOrder = byteOrder;
|
||||
}
|
||||
|
||||
public ByteOrder getByteOrder() {
|
||||
return byteOrder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a single byte from the stream and returns it as an
|
||||
* <code>int</code> between 0 and 255. If EOF is reached,
|
||||
* <code>-1</code> is returned.
|
||||
*
|
||||
* <p> Subclasses must provide an implementation for this method.
|
||||
* The subclass implementation should update the stream position
|
||||
* before exiting.
|
||||
*
|
||||
* <p> The bit offset within the stream must be reset to zero before
|
||||
* the read occurs.
|
||||
*
|
||||
* @return the value of the next byte in the stream, or <code>-1</code>
|
||||
* if EOF is reached.
|
||||
*
|
||||
* @exception IOException if the stream has been closed.
|
||||
*/
|
||||
public abstract int read() throws IOException;
|
||||
|
||||
/**
|
||||
* A convenience method that calls <code>read(b, 0, b.length)</code>.
|
||||
*
|
||||
* <p> The bit offset within the stream is reset to zero before
|
||||
* the read occurs.
|
||||
*
|
||||
* @return the number of bytes actually read, or <code>-1</code>
|
||||
* to indicate EOF.
|
||||
*
|
||||
* @exception NullPointerException if <code>b</code> is
|
||||
* <code>null</code>.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
public int read(byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads up to <code>len</code> bytes from the stream, and stores
|
||||
* them into <code>b</code> starting at index <code>off</code>.
|
||||
* If no bytes can be read because the end of the stream has been
|
||||
* reached, <code>-1</code> is returned.
|
||||
*
|
||||
* <p> The bit offset within the stream must be reset to zero before
|
||||
* the read occurs.
|
||||
*
|
||||
* <p> Subclasses must provide an implementation for this method.
|
||||
* The subclass implementation should update the stream position
|
||||
* before exiting.
|
||||
*
|
||||
* @param b an array of bytes to be written to.
|
||||
* @param off the starting position within <code>b</code> to write to.
|
||||
* @param len the maximum number of bytes to read.
|
||||
*
|
||||
* @return the number of bytes actually read, or <code>-1</code>
|
||||
* to indicate EOF.
|
||||
*
|
||||
* @exception IndexOutOfBoundsException if <code>off</code> is
|
||||
* negative, <code>len</code> is negative, or <code>off +
|
||||
* len</code> is greater than <code>b.length</code>.
|
||||
* @exception NullPointerException if <code>b</code> is
|
||||
* <code>null</code>.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
public abstract int read(byte[] b, int off, int len) throws IOException;
|
||||
|
||||
public void readBytes(IIOByteBuffer buf, int len) throws IOException {
|
||||
if (len < 0) {
|
||||
throw new IndexOutOfBoundsException("len < 0!");
|
||||
}
|
||||
if (buf == null) {
|
||||
throw new NullPointerException("buf == null!");
|
||||
}
|
||||
|
||||
byte[] data = new byte[len];
|
||||
len = read(data, 0, len);
|
||||
|
||||
buf.setData(data);
|
||||
buf.setOffset(0);
|
||||
buf.setLength(len);
|
||||
}
|
||||
|
||||
public boolean readBoolean() throws IOException {
|
||||
int ch = this.read();
|
||||
if (ch < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
return (ch != 0);
|
||||
}
|
||||
|
||||
public byte readByte() throws IOException {
|
||||
int ch = this.read();
|
||||
if (ch < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
return (byte)ch;
|
||||
}
|
||||
|
||||
public int readUnsignedByte() throws IOException {
|
||||
int ch = this.read();
|
||||
if (ch < 0) {
|
||||
throw new EOFException();
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
public short readShort() throws IOException {
|
||||
if (read(byteBuf, 0, 2) != 2) {
|
||||
throw new EOFException();
|
||||
}
|
||||
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
return (short)
|
||||
(((byteBuf[0] & 0xff) << 8) | ((byteBuf[1] & 0xff) << 0));
|
||||
} else {
|
||||
return (short)
|
||||
(((byteBuf[1] & 0xff) << 8) | ((byteBuf[0] & 0xff) << 0));
|
||||
}
|
||||
}
|
||||
|
||||
public int readUnsignedShort() throws IOException {
|
||||
return ((int)readShort()) & 0xffff;
|
||||
}
|
||||
|
||||
public char readChar() throws IOException {
|
||||
return (char)readShort();
|
||||
}
|
||||
|
||||
public int readInt() throws IOException {
|
||||
if (read(byteBuf, 0, 4) != 4) {
|
||||
throw new EOFException();
|
||||
}
|
||||
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
return
|
||||
(((byteBuf[0] & 0xff) << 24) | ((byteBuf[1] & 0xff) << 16) |
|
||||
((byteBuf[2] & 0xff) << 8) | ((byteBuf[3] & 0xff) << 0));
|
||||
} else {
|
||||
return
|
||||
(((byteBuf[3] & 0xff) << 24) | ((byteBuf[2] & 0xff) << 16) |
|
||||
((byteBuf[1] & 0xff) << 8) | ((byteBuf[0] & 0xff) << 0));
|
||||
}
|
||||
}
|
||||
|
||||
public long readUnsignedInt() throws IOException {
|
||||
return ((long)readInt()) & 0xffffffffL;
|
||||
}
|
||||
|
||||
public long readLong() throws IOException {
|
||||
// REMIND: Once 6277756 is fixed, we should do a bulk read of all 8
|
||||
// bytes here as we do in readShort() and readInt() for even better
|
||||
// performance (see 6347575 for details).
|
||||
int i1 = readInt();
|
||||
int i2 = readInt();
|
||||
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
return ((long)i1 << 32) + (i2 & 0xFFFFFFFFL);
|
||||
} else {
|
||||
return ((long)i2 << 32) + (i1 & 0xFFFFFFFFL);
|
||||
}
|
||||
}
|
||||
|
||||
public float readFloat() throws IOException {
|
||||
return Float.intBitsToFloat(readInt());
|
||||
}
|
||||
|
||||
public double readDouble() throws IOException {
|
||||
return Double.longBitsToDouble(readLong());
|
||||
}
|
||||
|
||||
public String readLine() throws IOException {
|
||||
StringBuffer input = new StringBuffer();
|
||||
int c = -1;
|
||||
boolean eol = false;
|
||||
|
||||
while (!eol) {
|
||||
switch (c = read()) {
|
||||
case -1:
|
||||
case '\n':
|
||||
eol = true;
|
||||
break;
|
||||
case '\r':
|
||||
eol = true;
|
||||
long cur = getStreamPosition();
|
||||
if ((read()) != '\n') {
|
||||
seek(cur);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
input.append((char)c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((c == -1) && (input.length() == 0)) {
|
||||
return null;
|
||||
}
|
||||
return input.toString();
|
||||
}
|
||||
|
||||
public String readUTF() throws IOException {
|
||||
this.bitOffset = 0;
|
||||
|
||||
// Fix 4494369: method ImageInputStreamImpl.readUTF()
|
||||
// does not work as specified (it should always assume
|
||||
// network byte order).
|
||||
ByteOrder oldByteOrder = getByteOrder();
|
||||
setByteOrder(ByteOrder.BIG_ENDIAN);
|
||||
|
||||
String ret;
|
||||
try {
|
||||
ret = DataInputStream.readUTF(this);
|
||||
} catch (IOException e) {
|
||||
// Restore the old byte order even if an exception occurs
|
||||
setByteOrder(oldByteOrder);
|
||||
throw e;
|
||||
}
|
||||
|
||||
setByteOrder(oldByteOrder);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void readFully(byte[] b, int off, int len) throws IOException {
|
||||
// Fix 4430357 - if off + len < 0, overflow occurred
|
||||
if (off < 0 || len < 0 || off + len > b.length || off + len < 0) {
|
||||
throw new IndexOutOfBoundsException
|
||||
("off < 0 || len < 0 || off + len > b.length!");
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
int nbytes = read(b, off, len);
|
||||
if (nbytes == -1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
off += nbytes;
|
||||
len -= nbytes;
|
||||
}
|
||||
}
|
||||
|
||||
public void readFully(byte[] b) throws IOException {
|
||||
readFully(b, 0, b.length);
|
||||
}
|
||||
|
||||
public void readFully(short[] s, int off, int len) throws IOException {
|
||||
// Fix 4430357 - if off + len < 0, overflow occurred
|
||||
if (off < 0 || len < 0 || off + len > s.length || off + len < 0) {
|
||||
throw new IndexOutOfBoundsException
|
||||
("off < 0 || len < 0 || off + len > s.length!");
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
int nelts = Math.min(len, byteBuf.length/2);
|
||||
readFully(byteBuf, 0, nelts*2);
|
||||
toShorts(byteBuf, s, off, nelts);
|
||||
off += nelts;
|
||||
len -= nelts;
|
||||
}
|
||||
}
|
||||
|
||||
public void readFully(char[] c, int off, int len) throws IOException {
|
||||
// Fix 4430357 - if off + len < 0, overflow occurred
|
||||
if (off < 0 || len < 0 || off + len > c.length || off + len < 0) {
|
||||
throw new IndexOutOfBoundsException
|
||||
("off < 0 || len < 0 || off + len > c.length!");
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
int nelts = Math.min(len, byteBuf.length/2);
|
||||
readFully(byteBuf, 0, nelts*2);
|
||||
toChars(byteBuf, c, off, nelts);
|
||||
off += nelts;
|
||||
len -= nelts;
|
||||
}
|
||||
}
|
||||
|
||||
public void readFully(int[] i, int off, int len) throws IOException {
|
||||
// Fix 4430357 - if off + len < 0, overflow occurred
|
||||
if (off < 0 || len < 0 || off + len > i.length || off + len < 0) {
|
||||
throw new IndexOutOfBoundsException
|
||||
("off < 0 || len < 0 || off + len > i.length!");
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
int nelts = Math.min(len, byteBuf.length/4);
|
||||
readFully(byteBuf, 0, nelts*4);
|
||||
toInts(byteBuf, i, off, nelts);
|
||||
off += nelts;
|
||||
len -= nelts;
|
||||
}
|
||||
}
|
||||
|
||||
public void readFully(long[] l, int off, int len) throws IOException {
|
||||
// Fix 4430357 - if off + len < 0, overflow occurred
|
||||
if (off < 0 || len < 0 || off + len > l.length || off + len < 0) {
|
||||
throw new IndexOutOfBoundsException
|
||||
("off < 0 || len < 0 || off + len > l.length!");
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
int nelts = Math.min(len, byteBuf.length/8);
|
||||
readFully(byteBuf, 0, nelts*8);
|
||||
toLongs(byteBuf, l, off, nelts);
|
||||
off += nelts;
|
||||
len -= nelts;
|
||||
}
|
||||
}
|
||||
|
||||
public void readFully(float[] f, int off, int len) throws IOException {
|
||||
// Fix 4430357 - if off + len < 0, overflow occurred
|
||||
if (off < 0 || len < 0 || off + len > f.length || off + len < 0) {
|
||||
throw new IndexOutOfBoundsException
|
||||
("off < 0 || len < 0 || off + len > f.length!");
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
int nelts = Math.min(len, byteBuf.length/4);
|
||||
readFully(byteBuf, 0, nelts*4);
|
||||
toFloats(byteBuf, f, off, nelts);
|
||||
off += nelts;
|
||||
len -= nelts;
|
||||
}
|
||||
}
|
||||
|
||||
public void readFully(double[] d, int off, int len) throws IOException {
|
||||
// Fix 4430357 - if off + len < 0, overflow occurred
|
||||
if (off < 0 || len < 0 || off + len > d.length || off + len < 0) {
|
||||
throw new IndexOutOfBoundsException
|
||||
("off < 0 || len < 0 || off + len > d.length!");
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
int nelts = Math.min(len, byteBuf.length/8);
|
||||
readFully(byteBuf, 0, nelts*8);
|
||||
toDoubles(byteBuf, d, off, nelts);
|
||||
off += nelts;
|
||||
len -= nelts;
|
||||
}
|
||||
}
|
||||
|
||||
private void toShorts(byte[] b, short[] s, int off, int len) {
|
||||
int boff = 0;
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
for (int j = 0; j < len; j++) {
|
||||
int b0 = b[boff];
|
||||
int b1 = b[boff + 1] & 0xff;
|
||||
s[off + j] = (short)((b0 << 8) | b1);
|
||||
boff += 2;
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < len; j++) {
|
||||
int b0 = b[boff + 1];
|
||||
int b1 = b[boff] & 0xff;
|
||||
s[off + j] = (short)((b0 << 8) | b1);
|
||||
boff += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void toChars(byte[] b, char[] c, int off, int len) {
|
||||
int boff = 0;
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
for (int j = 0; j < len; j++) {
|
||||
int b0 = b[boff];
|
||||
int b1 = b[boff + 1] & 0xff;
|
||||
c[off + j] = (char)((b0 << 8) | b1);
|
||||
boff += 2;
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < len; j++) {
|
||||
int b0 = b[boff + 1];
|
||||
int b1 = b[boff] & 0xff;
|
||||
c[off + j] = (char)((b0 << 8) | b1);
|
||||
boff += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void toInts(byte[] b, int[] i, int off, int len) {
|
||||
int boff = 0;
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
for (int j = 0; j < len; j++) {
|
||||
int b0 = b[boff];
|
||||
int b1 = b[boff + 1] & 0xff;
|
||||
int b2 = b[boff + 2] & 0xff;
|
||||
int b3 = b[boff + 3] & 0xff;
|
||||
i[off + j] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
|
||||
boff += 4;
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < len; j++) {
|
||||
int b0 = b[boff + 3];
|
||||
int b1 = b[boff + 2] & 0xff;
|
||||
int b2 = b[boff + 1] & 0xff;
|
||||
int b3 = b[boff] & 0xff;
|
||||
i[off + j] = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
|
||||
boff += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void toLongs(byte[] b, long[] l, int off, int len) {
|
||||
int boff = 0;
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
for (int j = 0; j < len; j++) {
|
||||
int b0 = b[boff];
|
||||
int b1 = b[boff + 1] & 0xff;
|
||||
int b2 = b[boff + 2] & 0xff;
|
||||
int b3 = b[boff + 3] & 0xff;
|
||||
int b4 = b[boff + 4];
|
||||
int b5 = b[boff + 5] & 0xff;
|
||||
int b6 = b[boff + 6] & 0xff;
|
||||
int b7 = b[boff + 7] & 0xff;
|
||||
|
||||
int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
|
||||
int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
|
||||
|
||||
l[off + j] = ((long)i0 << 32) | (i1 & 0xffffffffL);
|
||||
boff += 8;
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < len; j++) {
|
||||
int b0 = b[boff + 7];
|
||||
int b1 = b[boff + 6] & 0xff;
|
||||
int b2 = b[boff + 5] & 0xff;
|
||||
int b3 = b[boff + 4] & 0xff;
|
||||
int b4 = b[boff + 3];
|
||||
int b5 = b[boff + 2] & 0xff;
|
||||
int b6 = b[boff + 1] & 0xff;
|
||||
int b7 = b[boff] & 0xff;
|
||||
|
||||
int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
|
||||
int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
|
||||
|
||||
l[off + j] = ((long)i0 << 32) | (i1 & 0xffffffffL);
|
||||
boff += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void toFloats(byte[] b, float[] f, int off, int len) {
|
||||
int boff = 0;
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
for (int j = 0; j < len; j++) {
|
||||
int b0 = b[boff];
|
||||
int b1 = b[boff + 1] & 0xff;
|
||||
int b2 = b[boff + 2] & 0xff;
|
||||
int b3 = b[boff + 3] & 0xff;
|
||||
int i = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
|
||||
f[off + j] = Float.intBitsToFloat(i);
|
||||
boff += 4;
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < len; j++) {
|
||||
int b0 = b[boff + 3];
|
||||
int b1 = b[boff + 2] & 0xff;
|
||||
int b2 = b[boff + 1] & 0xff;
|
||||
int b3 = b[boff + 0] & 0xff;
|
||||
int i = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
|
||||
f[off + j] = Float.intBitsToFloat(i);
|
||||
boff += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void toDoubles(byte[] b, double[] d, int off, int len) {
|
||||
int boff = 0;
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
for (int j = 0; j < len; j++) {
|
||||
int b0 = b[boff];
|
||||
int b1 = b[boff + 1] & 0xff;
|
||||
int b2 = b[boff + 2] & 0xff;
|
||||
int b3 = b[boff + 3] & 0xff;
|
||||
int b4 = b[boff + 4];
|
||||
int b5 = b[boff + 5] & 0xff;
|
||||
int b6 = b[boff + 6] & 0xff;
|
||||
int b7 = b[boff + 7] & 0xff;
|
||||
|
||||
int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
|
||||
int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
|
||||
long l = ((long)i0 << 32) | (i1 & 0xffffffffL);
|
||||
|
||||
d[off + j] = Double.longBitsToDouble(l);
|
||||
boff += 8;
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < len; j++) {
|
||||
int b0 = b[boff + 7];
|
||||
int b1 = b[boff + 6] & 0xff;
|
||||
int b2 = b[boff + 5] & 0xff;
|
||||
int b3 = b[boff + 4] & 0xff;
|
||||
int b4 = b[boff + 3];
|
||||
int b5 = b[boff + 2] & 0xff;
|
||||
int b6 = b[boff + 1] & 0xff;
|
||||
int b7 = b[boff] & 0xff;
|
||||
|
||||
int i0 = (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
|
||||
int i1 = (b4 << 24) | (b5 << 16) | (b6 << 8) | b7;
|
||||
long l = ((long)i0 << 32) | (i1 & 0xffffffffL);
|
||||
|
||||
d[off + j] = Double.longBitsToDouble(l);
|
||||
boff += 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public long getStreamPosition() throws IOException {
|
||||
checkClosed();
|
||||
return streamPos;
|
||||
}
|
||||
|
||||
public int getBitOffset() throws IOException {
|
||||
checkClosed();
|
||||
return bitOffset;
|
||||
}
|
||||
|
||||
public void setBitOffset(int bitOffset) throws IOException {
|
||||
checkClosed();
|
||||
if (bitOffset < 0 || bitOffset > 7) {
|
||||
throw new IllegalArgumentException("bitOffset must be betwwen 0 and 7!");
|
||||
}
|
||||
this.bitOffset = bitOffset;
|
||||
}
|
||||
|
||||
public int readBit() throws IOException {
|
||||
checkClosed();
|
||||
|
||||
// Compute final bit offset before we call read() and seek()
|
||||
int newBitOffset = (this.bitOffset + 1) & 0x7;
|
||||
|
||||
int val = read();
|
||||
if (val == -1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
|
||||
if (newBitOffset != 0) {
|
||||
// Move byte position back if in the middle of a byte
|
||||
seek(getStreamPosition() - 1);
|
||||
// Shift the bit to be read to the rightmost position
|
||||
val >>= 8 - newBitOffset;
|
||||
}
|
||||
this.bitOffset = newBitOffset;
|
||||
|
||||
return val & 0x1;
|
||||
}
|
||||
|
||||
public long readBits(int numBits) throws IOException {
|
||||
checkClosed();
|
||||
|
||||
if (numBits < 0 || numBits > 64) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
if (numBits == 0) {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
// Have to read additional bits on the left equal to the bit offset
|
||||
int bitsToRead = numBits + bitOffset;
|
||||
|
||||
// Compute final bit offset before we call read() and seek()
|
||||
int newBitOffset = (this.bitOffset + numBits) & 0x7;
|
||||
|
||||
// Read a byte at a time, accumulate
|
||||
long accum = 0L;
|
||||
while (bitsToRead > 0) {
|
||||
int val = read();
|
||||
if (val == -1) {
|
||||
throw new EOFException();
|
||||
}
|
||||
|
||||
accum <<= 8;
|
||||
accum |= val;
|
||||
bitsToRead -= 8;
|
||||
}
|
||||
|
||||
// Move byte position back if in the middle of a byte
|
||||
if (newBitOffset != 0) {
|
||||
seek(getStreamPosition() - 1);
|
||||
}
|
||||
this.bitOffset = newBitOffset;
|
||||
|
||||
// Shift away unwanted bits on the right.
|
||||
accum >>>= (-bitsToRead); // Negative of bitsToRead == extra bits read
|
||||
|
||||
// Mask out unwanted bits on the left
|
||||
accum &= (-1L >>> (64 - numBits));
|
||||
|
||||
return accum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>-1L</code> to indicate that the stream has unknown
|
||||
* length. Subclasses must override this method to provide actual
|
||||
* length information.
|
||||
*
|
||||
* @return -1L to indicate unknown length.
|
||||
*/
|
||||
public long length() {
|
||||
return -1L;
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances the current stream position by calling
|
||||
* <code>seek(getStreamPosition() + n)</code>.
|
||||
*
|
||||
* <p> The bit offset is reset to zero.
|
||||
*
|
||||
* @param n the number of bytes to seek forward.
|
||||
*
|
||||
* @return an <code>int</code> representing the number of bytes
|
||||
* skipped.
|
||||
*
|
||||
* @exception IOException if <code>getStreamPosition</code>
|
||||
* throws an <code>IOException</code> when computing either
|
||||
* the starting or ending position.
|
||||
*/
|
||||
public int skipBytes(int n) throws IOException {
|
||||
long pos = getStreamPosition();
|
||||
seek(pos + n);
|
||||
return (int)(getStreamPosition() - pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Advances the current stream position by calling
|
||||
* <code>seek(getStreamPosition() + n)</code>.
|
||||
*
|
||||
* <p> The bit offset is reset to zero.
|
||||
*
|
||||
* @param n the number of bytes to seek forward.
|
||||
*
|
||||
* @return a <code>long</code> representing the number of bytes
|
||||
* skipped.
|
||||
*
|
||||
* @exception IOException if <code>getStreamPosition</code>
|
||||
* throws an <code>IOException</code> when computing either
|
||||
* the starting or ending position.
|
||||
*/
|
||||
public long skipBytes(long n) throws IOException {
|
||||
long pos = getStreamPosition();
|
||||
seek(pos + n);
|
||||
return getStreamPosition() - pos;
|
||||
}
|
||||
|
||||
public void seek(long pos) throws IOException {
|
||||
checkClosed();
|
||||
|
||||
// This test also covers pos < 0
|
||||
if (pos < flushedPos) {
|
||||
throw new IndexOutOfBoundsException("pos < flushedPos!");
|
||||
}
|
||||
|
||||
this.streamPos = pos;
|
||||
this.bitOffset = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes the current stream position onto a stack of marked
|
||||
* positions.
|
||||
*/
|
||||
public void mark() {
|
||||
try {
|
||||
markByteStack.push(Long.valueOf(getStreamPosition()));
|
||||
markBitStack.push(Integer.valueOf(getBitOffset()));
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the current stream byte and bit positions from the stack
|
||||
* of marked positions.
|
||||
*
|
||||
* <p> An <code>IOException</code> will be thrown if the previous
|
||||
* marked position lies in the discarded portion of the stream.
|
||||
*
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
public void reset() throws IOException {
|
||||
if (markByteStack.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
long pos = ((Long)markByteStack.pop()).longValue();
|
||||
if (pos < flushedPos) {
|
||||
throw new IIOException
|
||||
("Previous marked position has been discarded!");
|
||||
}
|
||||
seek(pos);
|
||||
|
||||
int offset = ((Integer)markBitStack.pop()).intValue();
|
||||
setBitOffset(offset);
|
||||
}
|
||||
|
||||
public void flushBefore(long pos) throws IOException {
|
||||
checkClosed();
|
||||
if (pos < flushedPos) {
|
||||
throw new IndexOutOfBoundsException("pos < flushedPos!");
|
||||
}
|
||||
if (pos > getStreamPosition()) {
|
||||
throw new IndexOutOfBoundsException("pos > getStreamPosition()!");
|
||||
}
|
||||
// Invariant: flushedPos >= 0
|
||||
flushedPos = pos;
|
||||
}
|
||||
|
||||
public void flush() throws IOException {
|
||||
flushBefore(getStreamPosition());
|
||||
}
|
||||
|
||||
public long getFlushedPosition() {
|
||||
return flushedPos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation returns false. Subclasses should
|
||||
* override this if they cache data.
|
||||
*/
|
||||
public boolean isCached() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation returns false. Subclasses should
|
||||
* override this if they cache data in main memory.
|
||||
*/
|
||||
public boolean isCachedMemory() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation returns false. Subclasses should
|
||||
* override this if they cache data in a temporary file.
|
||||
*/
|
||||
public boolean isCachedFile() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void close() throws IOException {
|
||||
checkClosed();
|
||||
|
||||
isClosed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalizes this object prior to garbage collection. The
|
||||
* <code>close</code> method is called to close any open input
|
||||
* source. This method should not be called from application
|
||||
* code.
|
||||
*
|
||||
* @exception Throwable if an error occurs during superclass
|
||||
* finalization.
|
||||
*/
|
||||
protected void finalize() throws Throwable {
|
||||
if (!isClosed) {
|
||||
try {
|
||||
close();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
662
jdkSrc/jdk8/javax/imageio/stream/ImageOutputStream.java
Normal file
662
jdkSrc/jdk8/javax/imageio/stream/ImageOutputStream.java
Normal file
@@ -0,0 +1,662 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.imageio.stream;
|
||||
|
||||
import java.io.DataOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* A seekable output stream interface for use by
|
||||
* <code>ImageWriter</code>s. Various output destinations, such as
|
||||
* <code>OutputStream</code>s and <code>File</code>s, as well as
|
||||
* future fast I/O destinations may be "wrapped" by a suitable
|
||||
* implementation of this interface for use by the Image I/O API.
|
||||
*
|
||||
* <p> Unlike a standard <code>OutputStream</code>, ImageOutputStream
|
||||
* extends its counterpart, <code>ImageInputStream</code>. Thus it is
|
||||
* possible to read from the stream as it is being written. The same
|
||||
* seek and flush positions apply to both reading and writing, although
|
||||
* the semantics for dealing with a non-zero bit offset before a byte-aligned
|
||||
* write are necessarily different from the semantics for dealing with
|
||||
* a non-zero bit offset before a byte-aligned read. When reading bytes,
|
||||
* any bit offset is set to 0 before the read; when writing bytes, a
|
||||
* non-zero bit offset causes the remaining bits in the byte to be written
|
||||
* as 0s. The byte-aligned write then starts at the next byte position.
|
||||
*
|
||||
* @see ImageInputStream
|
||||
*
|
||||
*/
|
||||
public interface ImageOutputStream extends ImageInputStream, DataOutput {
|
||||
|
||||
/**
|
||||
* Writes a single byte to the stream at the current position.
|
||||
* The 24 high-order bits of <code>b</code> are ignored.
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write. Implementers can use the
|
||||
* {@link ImageOutputStreamImpl#flushBits flushBits}
|
||||
* method of {@link ImageOutputStreamImpl ImageOutputStreamImpl}
|
||||
* to guarantee this.
|
||||
*
|
||||
* @param b an <code>int</code> whose lower 8 bits are to be
|
||||
* written.
|
||||
*
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void write(int b) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a sequence of bytes to the stream at the current
|
||||
* position. If <code>b.length</code> is 0, nothing is written.
|
||||
* The byte <code>b[0]</code> is written first, then the byte
|
||||
* <code>b[1]</code>, and so on.
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write.
|
||||
*
|
||||
* @param b an array of <code>byte</code>s to be written.
|
||||
*
|
||||
* @exception NullPointerException if <code>b</code> is
|
||||
* <code>null</code>.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void write(byte b[]) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a sequence of bytes to the stream at the current
|
||||
* position. If <code>len</code> is 0, nothing is written.
|
||||
* The byte <code>b[off]</code> is written first, then the byte
|
||||
* <code>b[off + 1]</code>, and so on.
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write. Implementers can use the
|
||||
* {@link ImageOutputStreamImpl#flushBits flushBits}
|
||||
* method of {@link ImageOutputStreamImpl ImageOutputStreamImpl}
|
||||
* to guarantee this.
|
||||
*
|
||||
* @param b an array of <code>byte</code>s to be written.
|
||||
* @param off the start offset in the data.
|
||||
* @param len the number of <code>byte</code>s to write.
|
||||
*
|
||||
* @exception IndexOutOfBoundsException if <code>off</code> is
|
||||
* negative, <code>len</code> is negative, or <code>off +
|
||||
* len</code> is greater than <code>b.length</code>.
|
||||
* @exception NullPointerException if <code>b</code> is
|
||||
* <code>null</code>.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void write(byte b[], int off, int len) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a <code>boolean</code> value to the stream. If
|
||||
* <code>v</code> is true, the value <code>(byte)1</code> is
|
||||
* written; if <code>v</code> is false, the value
|
||||
* <code>(byte)0</code> is written.
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write.
|
||||
*
|
||||
* @param v the <code>boolean</code> to be written.
|
||||
*
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void writeBoolean(boolean v) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes the 8 low-order bits of <code>v</code> to the
|
||||
* stream. The 24 high-order bits of <code>v</code> are ignored.
|
||||
* (This means that <code>writeByte</code> does exactly the same
|
||||
* thing as <code>write</code> for an integer argument.)
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write.
|
||||
*
|
||||
* @param v an <code>int</code> containing the byte value to be
|
||||
* written.
|
||||
*
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void writeByte(int v) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes the 16 low-order bits of <code>v</code> to the
|
||||
* stream. The 16 high-order bits of <code>v</code> are ignored.
|
||||
* If the stream uses network byte order, the bytes written, in
|
||||
* order, will be:
|
||||
*
|
||||
* <pre>
|
||||
* (byte)((v >> 8) & 0xff)
|
||||
* (byte)(v & 0xff)
|
||||
* </pre>
|
||||
*
|
||||
* Otherwise, the bytes written will be:
|
||||
*
|
||||
* <pre>
|
||||
* (byte)(v & 0xff)
|
||||
* (byte)((v >> 8) & 0xff)
|
||||
* </pre>
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write.
|
||||
*
|
||||
* @param v an <code>int</code> containing the short value to be
|
||||
* written.
|
||||
*
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void writeShort(int v) throws IOException;
|
||||
|
||||
/**
|
||||
* This method is a synonym for {@link #writeShort writeShort}.
|
||||
*
|
||||
* @param v an <code>int</code> containing the char (unsigned
|
||||
* short) value to be written.
|
||||
*
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*
|
||||
* @see #writeShort(int)
|
||||
*/
|
||||
void writeChar(int v) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes the 32 bits of <code>v</code> to the stream. If the
|
||||
* stream uses network byte order, the bytes written, in order,
|
||||
* will be:
|
||||
*
|
||||
* <pre>
|
||||
* (byte)((v >> 24) & 0xff)
|
||||
* (byte)((v >> 16) & 0xff)
|
||||
* (byte)((v >> 8) & 0xff)
|
||||
* (byte)(v & 0xff)
|
||||
* </pre>
|
||||
*
|
||||
* Otheriwse, the bytes written will be:
|
||||
*
|
||||
* <pre>
|
||||
* (byte)(v & 0xff)
|
||||
* (byte)((v >> 8) & 0xff)
|
||||
* (byte)((v >> 16) & 0xff)
|
||||
* (byte)((v >> 24) & 0xff)
|
||||
* </pre>
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write.
|
||||
*
|
||||
* @param v an <code>int</code> containing the value to be
|
||||
* written.
|
||||
*
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void writeInt(int v) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes the 64 bits of <code>v</code> to the stream. If the
|
||||
* stream uses network byte order, the bytes written, in order,
|
||||
* will be:
|
||||
*
|
||||
* <pre>
|
||||
* (byte)((v >> 56) & 0xff)
|
||||
* (byte)((v >> 48) & 0xff)
|
||||
* (byte)((v >> 40) & 0xff)
|
||||
* (byte)((v >> 32) & 0xff)
|
||||
* (byte)((v >> 24) & 0xff)
|
||||
* (byte)((v >> 16) & 0xff)
|
||||
* (byte)((v >> 8) & 0xff)
|
||||
* (byte)(v & 0xff)
|
||||
* </pre>
|
||||
*
|
||||
* Otherwise, the bytes written will be:
|
||||
*
|
||||
* <pre>
|
||||
* (byte)(v & 0xff)
|
||||
* (byte)((v >> 8) & 0xff)
|
||||
* (byte)((v >> 16) & 0xff)
|
||||
* (byte)((v >> 24) & 0xff)
|
||||
* (byte)((v >> 32) & 0xff)
|
||||
* (byte)((v >> 40) & 0xff)
|
||||
* (byte)((v >> 48) & 0xff)
|
||||
* (byte)((v >> 56) & 0xff)
|
||||
* </pre>
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write.
|
||||
*
|
||||
* @param v a <code>long</code> containing the value to be
|
||||
* written.
|
||||
*
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void writeLong(long v) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a <code>float</code> value, which is comprised of four
|
||||
* bytes, to the output stream. It does this as if it first
|
||||
* converts this <code>float</code> value to an <code>int</code>
|
||||
* in exactly the manner of the <code>Float.floatToIntBits</code>
|
||||
* method and then writes the int value in exactly the manner of
|
||||
* the <code>writeInt</code> method.
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write.
|
||||
*
|
||||
* @param v a <code>float</code> containing the value to be
|
||||
* written.
|
||||
*
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void writeFloat(float v) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a <code>double</code> value, which is comprised of four
|
||||
* bytes, to the output stream. It does this as if it first
|
||||
* converts this <code>double</code> value to an <code>long</code>
|
||||
* in exactly the manner of the
|
||||
* <code>Double.doubleToLongBits</code> method and then writes the
|
||||
* long value in exactly the manner of the <code>writeLong</code>
|
||||
* method.
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write.
|
||||
*
|
||||
* @param v a <code>double</code> containing the value to be
|
||||
* written.
|
||||
*
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void writeDouble(double v) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a string to the output stream. For every character in
|
||||
* the string <code>s</code>, taken in order, one byte is written
|
||||
* to the output stream. If <code>s</code> is <code>null</code>, a
|
||||
* <code>NullPointerException</code> is thrown.
|
||||
*
|
||||
* <p> If <code>s.length</code> is zero, then no bytes are
|
||||
* written. Otherwise, the character <code>s[0]</code> is written
|
||||
* first, then <code>s[1]</code>, and so on; the last character
|
||||
* written is <code>s[s.length-1]</code>. For each character, one
|
||||
* byte is written, the low-order byte, in exactly the manner of
|
||||
* the <code>writeByte</code> method. The high-order eight bits of
|
||||
* each character in the string are ignored.
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write.
|
||||
*
|
||||
* @param s a <code>String</code> containing the value to be
|
||||
* written.
|
||||
*
|
||||
* @exception NullPointerException if <code>s</code> is
|
||||
* <code>null</code>.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void writeBytes(String s) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a string to the output stream. For every character in
|
||||
* the string <code>s</code>, taken in order, two bytes are
|
||||
* written to the output stream, ordered according to the current
|
||||
* byte order setting. If network byte order is being used, the
|
||||
* high-order byte is written first; the order is reversed
|
||||
* otherwise. If <code>s</code> is <code>null</code>, a
|
||||
* <code>NullPointerException</code> is thrown.
|
||||
*
|
||||
* <p> If <code>s.length</code> is zero, then no bytes are
|
||||
* written. Otherwise, the character <code>s[0]</code> is written
|
||||
* first, then <code>s[1]</code>, and so on; the last character
|
||||
* written is <code>s[s.length-1]</code>.
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write.
|
||||
*
|
||||
* @param s a <code>String</code> containing the value to be
|
||||
* written.
|
||||
*
|
||||
* @exception NullPointerException if <code>s</code> is
|
||||
* <code>null</code>.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void writeChars(String s) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes two bytes of length information to the output stream in
|
||||
* network byte order, followed by the
|
||||
* <a href="../../../java/io/DataInput.html#modified-utf-8">modified
|
||||
* UTF-8</a>
|
||||
* representation of every character in the string <code>s</code>.
|
||||
* If <code>s</code> is <code>null</code>, a
|
||||
* <code>NullPointerException</code> is thrown. Each character in
|
||||
* the string <code>s</code> is converted to a group of one, two,
|
||||
* or three bytes, depending on the value of the character.
|
||||
*
|
||||
* <p> If a character <code>c</code> is in the range
|
||||
* <code>\u0001</code> through <code>\u007f</code>, it is
|
||||
* represented by one byte:
|
||||
*
|
||||
* <p><pre>
|
||||
* (byte)c
|
||||
* </pre>
|
||||
*
|
||||
* <p> If a character <code>c</code> is <code>\u0000</code> or
|
||||
* is in the range <code>\u0080</code> through
|
||||
* <code>\u07ff</code>, then it is represented by two bytes,
|
||||
* to be written in the order shown:
|
||||
*
|
||||
* <p> <pre><code>
|
||||
* (byte)(0xc0 | (0x1f & (c >> 6)))
|
||||
* (byte)(0x80 | (0x3f & c))
|
||||
* </code></pre>
|
||||
*
|
||||
* <p> If a character <code>c</code> is in the range
|
||||
* <code>\u0800</code> through <code>uffff</code>, then it is
|
||||
* represented by three bytes, to be written in the order shown:
|
||||
*
|
||||
* <p> <pre><code>
|
||||
* (byte)(0xe0 | (0x0f & (c >> 12)))
|
||||
* (byte)(0x80 | (0x3f & (c >> 6)))
|
||||
* (byte)(0x80 | (0x3f & c))
|
||||
* </code></pre>
|
||||
*
|
||||
* <p> First, the total number of bytes needed to represent all
|
||||
* the characters of <code>s</code> is calculated. If this number
|
||||
* is larger than <code>65535</code>, then a
|
||||
* <code>UTFDataFormatException</code> is thrown. Otherwise, this
|
||||
* length is written to the output stream in exactly the manner of
|
||||
* the <code>writeShort</code> method; after this, the one-, two-,
|
||||
* or three-byte representation of each character in the string
|
||||
* <code>s</code> is written.
|
||||
*
|
||||
* <p> The current byte order setting is ignored.
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write.
|
||||
*
|
||||
* <p><strong>Note:</strong> This method should not be used in
|
||||
* the implementation of image formats that use standard UTF-8,
|
||||
* because the modified UTF-8 used here is incompatible with
|
||||
* standard UTF-8.
|
||||
*
|
||||
* @param s a <code>String</code> containing the value to be
|
||||
* written.
|
||||
*
|
||||
* @exception NullPointerException if <code>s</code> is
|
||||
* <code>null</code>.
|
||||
* @exception java.io.UTFDataFormatException if the modified UTF-8
|
||||
* representation of <code>s</code> requires more than 65536 bytes.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void writeUTF(String s) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a sequence of shorts to the stream at the current
|
||||
* position. If <code>len</code> is 0, nothing is written.
|
||||
* The short <code>s[off]</code> is written first, then the short
|
||||
* <code>s[off + 1]</code>, and so on. The byte order of the
|
||||
* stream is used to determine the order in which the individual
|
||||
* bytes are written.
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write.
|
||||
*
|
||||
* @param s an array of <code>short</code>s to be written.
|
||||
* @param off the start offset in the data.
|
||||
* @param len the number of <code>short</code>s to write.
|
||||
*
|
||||
* @exception IndexOutOfBoundsException if <code>off</code> is
|
||||
* negative, <code>len</code> is negative, or <code>off +
|
||||
* len</code> is greater than <code>s.length</code>.
|
||||
* @exception NullPointerException if <code>s</code> is
|
||||
* <code>null</code>.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void writeShorts(short[] s, int off, int len) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a sequence of chars to the stream at the current
|
||||
* position. If <code>len</code> is 0, nothing is written.
|
||||
* The char <code>c[off]</code> is written first, then the char
|
||||
* <code>c[off + 1]</code>, and so on. The byte order of the
|
||||
* stream is used to determine the order in which the individual
|
||||
* bytes are written.
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write.
|
||||
*
|
||||
* @param c an array of <code>char</code>s to be written.
|
||||
* @param off the start offset in the data.
|
||||
* @param len the number of <code>char</code>s to write.
|
||||
*
|
||||
* @exception IndexOutOfBoundsException if <code>off</code> is
|
||||
* negative, <code>len</code> is negative, or <code>off +
|
||||
* len</code> is greater than <code>c.length</code>.
|
||||
* @exception NullPointerException if <code>c</code> is
|
||||
* <code>null</code>.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void writeChars(char[] c, int off, int len) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a sequence of ints to the stream at the current
|
||||
* position. If <code>len</code> is 0, nothing is written.
|
||||
* The int <code>i[off]</code> is written first, then the int
|
||||
* <code>i[off + 1]</code>, and so on. The byte order of the
|
||||
* stream is used to determine the order in which the individual
|
||||
* bytes are written.
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write.
|
||||
*
|
||||
* @param i an array of <code>int</code>s to be written.
|
||||
* @param off the start offset in the data.
|
||||
* @param len the number of <code>int</code>s to write.
|
||||
*
|
||||
* @exception IndexOutOfBoundsException if <code>off</code> is
|
||||
* negative, <code>len</code> is negative, or <code>off +
|
||||
* len</code> is greater than <code>i.length</code>.
|
||||
* @exception NullPointerException if <code>i</code> is
|
||||
* <code>null</code>.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void writeInts(int[] i, int off, int len) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a sequence of longs to the stream at the current
|
||||
* position. If <code>len</code> is 0, nothing is written.
|
||||
* The long <code>l[off]</code> is written first, then the long
|
||||
* <code>l[off + 1]</code>, and so on. The byte order of the
|
||||
* stream is used to determine the order in which the individual
|
||||
* bytes are written.
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write.
|
||||
*
|
||||
* @param l an array of <code>long</code>s to be written.
|
||||
* @param off the start offset in the data.
|
||||
* @param len the number of <code>long</code>s to write.
|
||||
*
|
||||
* @exception IndexOutOfBoundsException if <code>off</code> is
|
||||
* negative, <code>len</code> is negative, or <code>off +
|
||||
* len</code> is greater than <code>l.length</code>.
|
||||
* @exception NullPointerException if <code>l</code> is
|
||||
* <code>null</code>.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void writeLongs(long[] l, int off, int len) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a sequence of floats to the stream at the current
|
||||
* position. If <code>len</code> is 0, nothing is written.
|
||||
* The float <code>f[off]</code> is written first, then the float
|
||||
* <code>f[off + 1]</code>, and so on. The byte order of the
|
||||
* stream is used to determine the order in which the individual
|
||||
* bytes are written.
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write.
|
||||
*
|
||||
* @param f an array of <code>float</code>s to be written.
|
||||
* @param off the start offset in the data.
|
||||
* @param len the number of <code>float</code>s to write.
|
||||
*
|
||||
* @exception IndexOutOfBoundsException if <code>off</code> is
|
||||
* negative, <code>len</code> is negative, or <code>off +
|
||||
* len</code> is greater than <code>f.length</code>.
|
||||
* @exception NullPointerException if <code>f</code> is
|
||||
* <code>null</code>.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void writeFloats(float[] f, int off, int len) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a sequence of doubles to the stream at the current
|
||||
* position. If <code>len</code> is 0, nothing is written.
|
||||
* The double <code>d[off]</code> is written first, then the double
|
||||
* <code>d[off + 1]</code>, and so on. The byte order of the
|
||||
* stream is used to determine the order in which the individual
|
||||
* bytes are written.
|
||||
*
|
||||
* <p> If the bit offset within the stream is non-zero, the
|
||||
* remainder of the current byte is padded with 0s
|
||||
* and written out first. The bit offset will be 0 after the
|
||||
* write.
|
||||
*
|
||||
* @param d an array of <code>doubles</code>s to be written.
|
||||
* @param off the start offset in the data.
|
||||
* @param len the number of <code>double</code>s to write.
|
||||
*
|
||||
* @exception IndexOutOfBoundsException if <code>off</code> is
|
||||
* negative, <code>len</code> is negative, or <code>off +
|
||||
* len</code> is greater than <code>d.length</code>.
|
||||
* @exception NullPointerException if <code>d</code> is
|
||||
* <code>null</code>.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void writeDoubles(double[] d, int off, int len) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a single bit, given by the least significant bit of the
|
||||
* argument, to the stream at the current bit offset within the
|
||||
* current byte position. The upper 31 bits of the argument are
|
||||
* ignored. The given bit replaces the previous bit at that
|
||||
* position. The bit offset is advanced by one and reduced modulo
|
||||
* 8.
|
||||
*
|
||||
* <p> If any bits of a particular byte have never been set
|
||||
* at the time the byte is flushed to the destination, those
|
||||
* bits will be set to 0 automatically.
|
||||
*
|
||||
* @param bit an <code>int</code> whose least significant bit
|
||||
* is to be written to the stream.
|
||||
*
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void writeBit(int bit) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes a sequence of bits, given by the <code>numBits</code>
|
||||
* least significant bits of the <code>bits</code> argument in
|
||||
* left-to-right order, to the stream at the current bit offset
|
||||
* within the current byte position. The upper <code>64 -
|
||||
* numBits</code> bits of the argument are ignored. The bit
|
||||
* offset is advanced by <code>numBits</code> and reduced modulo
|
||||
* 8. Note that a bit offset of 0 always indicates the
|
||||
* most-significant bit of the byte, and bytes of bits are written
|
||||
* out in sequence as they are encountered. Thus bit writes are
|
||||
* always effectively in network byte order. The actual stream
|
||||
* byte order setting is ignored.
|
||||
*
|
||||
* <p> Bit data may be accumulated in memory indefinitely, until
|
||||
* <code>flushBefore</code> is called. At that time, all bit data
|
||||
* prior to the flushed position will be written.
|
||||
*
|
||||
* <p> If any bits of a particular byte have never been set
|
||||
* at the time the byte is flushed to the destination, those
|
||||
* bits will be set to 0 automatically.
|
||||
*
|
||||
* @param bits a <code>long</code> containing the bits to be
|
||||
* written, starting with the bit in position <code>numBits -
|
||||
* 1</code> down to the least significant bit.
|
||||
*
|
||||
* @param numBits an <code>int</code> between 0 and 64, inclusive.
|
||||
*
|
||||
* @exception IllegalArgumentException if <code>numBits</code> is
|
||||
* not between 0 and 64, inclusive.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void writeBits(long bits, int numBits) throws IOException;
|
||||
|
||||
/**
|
||||
* Flushes all data prior to the given position to the underlying
|
||||
* destination, such as an <code>OutputStream</code> or
|
||||
* <code>File</code>. Attempting to seek to the flushed portion
|
||||
* of the stream will result in an
|
||||
* <code>IndexOutOfBoundsException</code>.
|
||||
*
|
||||
* @param pos a <code>long</code> containing the length of the
|
||||
* stream prefix that may be flushed to the destination.
|
||||
*
|
||||
* @exception IndexOutOfBoundsException if <code>pos</code> lies
|
||||
* in the flushed portion of the stream or past the current stream
|
||||
* position.
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
void flushBefore(long pos) throws IOException;
|
||||
}
|
||||
510
jdkSrc/jdk8/javax/imageio/stream/ImageOutputStreamImpl.java
Normal file
510
jdkSrc/jdk8/javax/imageio/stream/ImageOutputStreamImpl.java
Normal file
@@ -0,0 +1,510 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.imageio.stream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UTFDataFormatException;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
/**
|
||||
* An abstract class implementing the <code>ImageOutputStream</code> interface.
|
||||
* This class is designed to reduce the number of methods that must
|
||||
* be implemented by subclasses.
|
||||
*
|
||||
*/
|
||||
public abstract class ImageOutputStreamImpl
|
||||
extends ImageInputStreamImpl
|
||||
implements ImageOutputStream {
|
||||
|
||||
/**
|
||||
* Constructs an <code>ImageOutputStreamImpl</code>.
|
||||
*/
|
||||
public ImageOutputStreamImpl() {
|
||||
}
|
||||
|
||||
public abstract void write(int b) throws IOException;
|
||||
|
||||
public void write(byte b[]) throws IOException {
|
||||
write(b, 0, b.length);
|
||||
}
|
||||
|
||||
public abstract void write(byte b[], int off, int len) throws IOException;
|
||||
|
||||
public void writeBoolean(boolean v) throws IOException {
|
||||
write(v ? 1 : 0);
|
||||
}
|
||||
|
||||
public void writeByte(int v) throws IOException {
|
||||
write(v);
|
||||
}
|
||||
|
||||
public void writeShort(int v) throws IOException {
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
byteBuf[0] = (byte)(v >>> 8);
|
||||
byteBuf[1] = (byte)(v >>> 0);
|
||||
} else {
|
||||
byteBuf[0] = (byte)(v >>> 0);
|
||||
byteBuf[1] = (byte)(v >>> 8);
|
||||
}
|
||||
write(byteBuf, 0, 2);
|
||||
}
|
||||
|
||||
public void writeChar(int v) throws IOException {
|
||||
writeShort(v);
|
||||
}
|
||||
|
||||
public void writeInt(int v) throws IOException {
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
byteBuf[0] = (byte)(v >>> 24);
|
||||
byteBuf[1] = (byte)(v >>> 16);
|
||||
byteBuf[2] = (byte)(v >>> 8);
|
||||
byteBuf[3] = (byte)(v >>> 0);
|
||||
} else {
|
||||
byteBuf[0] = (byte)(v >>> 0);
|
||||
byteBuf[1] = (byte)(v >>> 8);
|
||||
byteBuf[2] = (byte)(v >>> 16);
|
||||
byteBuf[3] = (byte)(v >>> 24);
|
||||
}
|
||||
write(byteBuf, 0, 4);
|
||||
}
|
||||
|
||||
public void writeLong(long v) throws IOException {
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
byteBuf[0] = (byte)(v >>> 56);
|
||||
byteBuf[1] = (byte)(v >>> 48);
|
||||
byteBuf[2] = (byte)(v >>> 40);
|
||||
byteBuf[3] = (byte)(v >>> 32);
|
||||
byteBuf[4] = (byte)(v >>> 24);
|
||||
byteBuf[5] = (byte)(v >>> 16);
|
||||
byteBuf[6] = (byte)(v >>> 8);
|
||||
byteBuf[7] = (byte)(v >>> 0);
|
||||
} else {
|
||||
byteBuf[0] = (byte)(v >>> 0);
|
||||
byteBuf[1] = (byte)(v >>> 8);
|
||||
byteBuf[2] = (byte)(v >>> 16);
|
||||
byteBuf[3] = (byte)(v >>> 24);
|
||||
byteBuf[4] = (byte)(v >>> 32);
|
||||
byteBuf[5] = (byte)(v >>> 40);
|
||||
byteBuf[6] = (byte)(v >>> 48);
|
||||
byteBuf[7] = (byte)(v >>> 56);
|
||||
}
|
||||
// REMIND: Once 6277756 is fixed, we should do a bulk write of all 8
|
||||
// bytes here as we do in writeShort() and writeInt() for even better
|
||||
// performance. For now, two bulk writes of 4 bytes each is still
|
||||
// faster than 8 individual write() calls (see 6347575 for details).
|
||||
write(byteBuf, 0, 4);
|
||||
write(byteBuf, 4, 4);
|
||||
}
|
||||
|
||||
public void writeFloat(float v) throws IOException {
|
||||
writeInt(Float.floatToIntBits(v));
|
||||
}
|
||||
|
||||
public void writeDouble(double v) throws IOException {
|
||||
writeLong(Double.doubleToLongBits(v));
|
||||
}
|
||||
|
||||
public void writeBytes(String s) throws IOException {
|
||||
int len = s.length();
|
||||
for (int i = 0 ; i < len ; i++) {
|
||||
write((byte)s.charAt(i));
|
||||
}
|
||||
}
|
||||
|
||||
public void writeChars(String s) throws IOException {
|
||||
int len = s.length();
|
||||
|
||||
byte[] b = new byte[len*2];
|
||||
int boff = 0;
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
for (int i = 0; i < len ; i++) {
|
||||
int v = s.charAt(i);
|
||||
b[boff++] = (byte)(v >>> 8);
|
||||
b[boff++] = (byte)(v >>> 0);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < len ; i++) {
|
||||
int v = s.charAt(i);
|
||||
b[boff++] = (byte)(v >>> 0);
|
||||
b[boff++] = (byte)(v >>> 8);
|
||||
}
|
||||
}
|
||||
|
||||
write(b, 0, len*2);
|
||||
}
|
||||
|
||||
public void writeUTF(String s) throws IOException {
|
||||
int strlen = s.length();
|
||||
int utflen = 0;
|
||||
char[] charr = new char[strlen];
|
||||
int c, boff = 0;
|
||||
|
||||
s.getChars(0, strlen, charr, 0);
|
||||
|
||||
for (int i = 0; i < strlen; i++) {
|
||||
c = charr[i];
|
||||
if ((c >= 0x0001) && (c <= 0x007F)) {
|
||||
utflen++;
|
||||
} else if (c > 0x07FF) {
|
||||
utflen += 3;
|
||||
} else {
|
||||
utflen += 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (utflen > 65535) {
|
||||
throw new UTFDataFormatException("utflen > 65536!");
|
||||
}
|
||||
|
||||
byte[] b = new byte[utflen+2];
|
||||
b[boff++] = (byte) ((utflen >>> 8) & 0xFF);
|
||||
b[boff++] = (byte) ((utflen >>> 0) & 0xFF);
|
||||
for (int i = 0; i < strlen; i++) {
|
||||
c = charr[i];
|
||||
if ((c >= 0x0001) && (c <= 0x007F)) {
|
||||
b[boff++] = (byte) c;
|
||||
} else if (c > 0x07FF) {
|
||||
b[boff++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
|
||||
b[boff++] = (byte) (0x80 | ((c >> 6) & 0x3F));
|
||||
b[boff++] = (byte) (0x80 | ((c >> 0) & 0x3F));
|
||||
} else {
|
||||
b[boff++] = (byte) (0xC0 | ((c >> 6) & 0x1F));
|
||||
b[boff++] = (byte) (0x80 | ((c >> 0) & 0x3F));
|
||||
}
|
||||
}
|
||||
write(b, 0, utflen + 2);
|
||||
}
|
||||
|
||||
public void writeShorts(short[] s, int off, int len) throws IOException {
|
||||
// Fix 4430357 - if off + len < 0, overflow occurred
|
||||
if (off < 0 || len < 0 || off + len > s.length || off + len < 0) {
|
||||
throw new IndexOutOfBoundsException
|
||||
("off < 0 || len < 0 || off + len > s.length!");
|
||||
}
|
||||
|
||||
byte[] b = new byte[len*2];
|
||||
int boff = 0;
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
short v = s[off + i];
|
||||
b[boff++] = (byte)(v >>> 8);
|
||||
b[boff++] = (byte)(v >>> 0);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < len; i++) {
|
||||
short v = s[off + i];
|
||||
b[boff++] = (byte)(v >>> 0);
|
||||
b[boff++] = (byte)(v >>> 8);
|
||||
}
|
||||
}
|
||||
|
||||
write(b, 0, len*2);
|
||||
}
|
||||
|
||||
public void writeChars(char[] c, int off, int len) throws IOException {
|
||||
// Fix 4430357 - if off + len < 0, overflow occurred
|
||||
if (off < 0 || len < 0 || off + len > c.length || off + len < 0) {
|
||||
throw new IndexOutOfBoundsException
|
||||
("off < 0 || len < 0 || off + len > c.length!");
|
||||
}
|
||||
|
||||
byte[] b = new byte[len*2];
|
||||
int boff = 0;
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
char v = c[off + i];
|
||||
b[boff++] = (byte)(v >>> 8);
|
||||
b[boff++] = (byte)(v >>> 0);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < len; i++) {
|
||||
char v = c[off + i];
|
||||
b[boff++] = (byte)(v >>> 0);
|
||||
b[boff++] = (byte)(v >>> 8);
|
||||
}
|
||||
}
|
||||
|
||||
write(b, 0, len*2);
|
||||
}
|
||||
|
||||
public void writeInts(int[] i, int off, int len) throws IOException {
|
||||
// Fix 4430357 - if off + len < 0, overflow occurred
|
||||
if (off < 0 || len < 0 || off + len > i.length || off + len < 0) {
|
||||
throw new IndexOutOfBoundsException
|
||||
("off < 0 || len < 0 || off + len > i.length!");
|
||||
}
|
||||
|
||||
byte[] b = new byte[len*4];
|
||||
int boff = 0;
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
for (int j = 0; j < len; j++) {
|
||||
int v = i[off + j];
|
||||
b[boff++] = (byte)(v >>> 24);
|
||||
b[boff++] = (byte)(v >>> 16);
|
||||
b[boff++] = (byte)(v >>> 8);
|
||||
b[boff++] = (byte)(v >>> 0);
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < len; j++) {
|
||||
int v = i[off + j];
|
||||
b[boff++] = (byte)(v >>> 0);
|
||||
b[boff++] = (byte)(v >>> 8);
|
||||
b[boff++] = (byte)(v >>> 16);
|
||||
b[boff++] = (byte)(v >>> 24);
|
||||
}
|
||||
}
|
||||
|
||||
write(b, 0, len*4);
|
||||
}
|
||||
|
||||
public void writeLongs(long[] l, int off, int len) throws IOException {
|
||||
// Fix 4430357 - if off + len < 0, overflow occurred
|
||||
if (off < 0 || len < 0 || off + len > l.length || off + len < 0) {
|
||||
throw new IndexOutOfBoundsException
|
||||
("off < 0 || len < 0 || off + len > l.length!");
|
||||
}
|
||||
|
||||
byte[] b = new byte[len*8];
|
||||
int boff = 0;
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
long v = l[off + i];
|
||||
b[boff++] = (byte)(v >>> 56);
|
||||
b[boff++] = (byte)(v >>> 48);
|
||||
b[boff++] = (byte)(v >>> 40);
|
||||
b[boff++] = (byte)(v >>> 32);
|
||||
b[boff++] = (byte)(v >>> 24);
|
||||
b[boff++] = (byte)(v >>> 16);
|
||||
b[boff++] = (byte)(v >>> 8);
|
||||
b[boff++] = (byte)(v >>> 0);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < len; i++) {
|
||||
long v = l[off + i];
|
||||
b[boff++] = (byte)(v >>> 0);
|
||||
b[boff++] = (byte)(v >>> 8);
|
||||
b[boff++] = (byte)(v >>> 16);
|
||||
b[boff++] = (byte)(v >>> 24);
|
||||
b[boff++] = (byte)(v >>> 32);
|
||||
b[boff++] = (byte)(v >>> 40);
|
||||
b[boff++] = (byte)(v >>> 48);
|
||||
b[boff++] = (byte)(v >>> 56);
|
||||
}
|
||||
}
|
||||
|
||||
write(b, 0, len*8);
|
||||
}
|
||||
|
||||
public void writeFloats(float[] f, int off, int len) throws IOException {
|
||||
// Fix 4430357 - if off + len < 0, overflow occurred
|
||||
if (off < 0 || len < 0 || off + len > f.length || off + len < 0) {
|
||||
throw new IndexOutOfBoundsException
|
||||
("off < 0 || len < 0 || off + len > f.length!");
|
||||
}
|
||||
|
||||
byte[] b = new byte[len*4];
|
||||
int boff = 0;
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
int v = Float.floatToIntBits(f[off + i]);
|
||||
b[boff++] = (byte)(v >>> 24);
|
||||
b[boff++] = (byte)(v >>> 16);
|
||||
b[boff++] = (byte)(v >>> 8);
|
||||
b[boff++] = (byte)(v >>> 0);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < len; i++) {
|
||||
int v = Float.floatToIntBits(f[off + i]);
|
||||
b[boff++] = (byte)(v >>> 0);
|
||||
b[boff++] = (byte)(v >>> 8);
|
||||
b[boff++] = (byte)(v >>> 16);
|
||||
b[boff++] = (byte)(v >>> 24);
|
||||
}
|
||||
}
|
||||
|
||||
write(b, 0, len*4);
|
||||
}
|
||||
|
||||
public void writeDoubles(double[] d, int off, int len) throws IOException {
|
||||
// Fix 4430357 - if off + len < 0, overflow occurred
|
||||
if (off < 0 || len < 0 || off + len > d.length || off + len < 0) {
|
||||
throw new IndexOutOfBoundsException
|
||||
("off < 0 || len < 0 || off + len > d.length!");
|
||||
}
|
||||
|
||||
byte[] b = new byte[len*8];
|
||||
int boff = 0;
|
||||
if (byteOrder == ByteOrder.BIG_ENDIAN) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
long v = Double.doubleToLongBits(d[off + i]);
|
||||
b[boff++] = (byte)(v >>> 56);
|
||||
b[boff++] = (byte)(v >>> 48);
|
||||
b[boff++] = (byte)(v >>> 40);
|
||||
b[boff++] = (byte)(v >>> 32);
|
||||
b[boff++] = (byte)(v >>> 24);
|
||||
b[boff++] = (byte)(v >>> 16);
|
||||
b[boff++] = (byte)(v >>> 8);
|
||||
b[boff++] = (byte)(v >>> 0);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < len; i++) {
|
||||
long v = Double.doubleToLongBits(d[off + i]);
|
||||
b[boff++] = (byte)(v >>> 0);
|
||||
b[boff++] = (byte)(v >>> 8);
|
||||
b[boff++] = (byte)(v >>> 16);
|
||||
b[boff++] = (byte)(v >>> 24);
|
||||
b[boff++] = (byte)(v >>> 32);
|
||||
b[boff++] = (byte)(v >>> 40);
|
||||
b[boff++] = (byte)(v >>> 48);
|
||||
b[boff++] = (byte)(v >>> 56);
|
||||
}
|
||||
}
|
||||
|
||||
write(b, 0, len*8);
|
||||
}
|
||||
|
||||
public void writeBit(int bit) throws IOException {
|
||||
writeBits((1L & bit), 1);
|
||||
}
|
||||
|
||||
public void writeBits(long bits, int numBits) throws IOException {
|
||||
checkClosed();
|
||||
|
||||
if (numBits < 0 || numBits > 64) {
|
||||
throw new IllegalArgumentException("Bad value for numBits!");
|
||||
}
|
||||
if (numBits == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prologue: deal with pre-existing bits
|
||||
|
||||
// Bug 4499158, 4507868 - if we're at the beginning of the stream
|
||||
// and the bit offset is 0, there can't be any pre-existing bits
|
||||
if ((getStreamPosition() > 0) || (bitOffset > 0)) {
|
||||
int offset = bitOffset; // read() will reset bitOffset
|
||||
int partialByte = read();
|
||||
if (partialByte != -1) {
|
||||
seek(getStreamPosition() - 1);
|
||||
} else {
|
||||
partialByte = 0;
|
||||
}
|
||||
|
||||
if (numBits + offset < 8) {
|
||||
// Notch out the partial byte and drop in the new bits
|
||||
int shift = 8 - (offset+numBits);
|
||||
int mask = -1 >>> (32 - numBits);
|
||||
partialByte &= ~(mask << shift); // Clear out old bits
|
||||
partialByte |= ((bits & mask) << shift); // Or in new ones
|
||||
write(partialByte);
|
||||
seek(getStreamPosition() - 1);
|
||||
bitOffset = offset + numBits;
|
||||
numBits = 0; // Signal that we are done
|
||||
} else {
|
||||
// Fill out the partial byte and reduce numBits
|
||||
int num = 8 - offset;
|
||||
int mask = -1 >>> (32 - num);
|
||||
partialByte &= ~mask; // Clear out bits
|
||||
partialByte |= ((bits >> (numBits - num)) & mask);
|
||||
// Note that bitOffset is already 0, so there is no risk
|
||||
// of this advancing to the next byte
|
||||
write(partialByte);
|
||||
numBits -= num;
|
||||
}
|
||||
}
|
||||
|
||||
// Now write any whole bytes
|
||||
if (numBits > 7) {
|
||||
int extra = numBits % 8;
|
||||
for (int numBytes = numBits / 8; numBytes > 0; numBytes--) {
|
||||
int shift = (numBytes-1)*8+extra;
|
||||
int value = (int) ((shift == 0)
|
||||
? bits & 0xFF
|
||||
: (bits>>shift) & 0xFF);
|
||||
write(value);
|
||||
}
|
||||
numBits = extra;
|
||||
}
|
||||
|
||||
// Epilogue: write out remaining partial byte, if any
|
||||
// Note that we may be at EOF, in which case we pad with 0,
|
||||
// or not, in which case we must preserve the existing bits
|
||||
if (numBits != 0) {
|
||||
// If we are not at the end of the file, read the current byte
|
||||
// If we are at the end of the file, initialize our byte to 0.
|
||||
int partialByte = 0;
|
||||
partialByte = read();
|
||||
if (partialByte != -1) {
|
||||
seek(getStreamPosition() - 1);
|
||||
}
|
||||
// Fix 4494976: writeBit(int) does not pad the remainder
|
||||
// of the current byte with 0s
|
||||
else { // EOF
|
||||
partialByte = 0;
|
||||
}
|
||||
|
||||
int shift = 8 - numBits;
|
||||
int mask = -1 >>> (32 - numBits);
|
||||
partialByte &= ~(mask << shift);
|
||||
partialByte |= (bits & mask) << shift;
|
||||
// bitOffset is always already 0 when we get here.
|
||||
write(partialByte);
|
||||
seek(getStreamPosition() - 1);
|
||||
bitOffset = numBits;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the bit offset is non-zero, forces the remaining bits
|
||||
* in the current byte to 0 and advances the stream position
|
||||
* by one. This method should be called by subclasses at the
|
||||
* beginning of the <code>write(int)</code> and
|
||||
* <code>write(byte[], int, int)</code> methods.
|
||||
*
|
||||
* @exception IOException if an I/O error occurs.
|
||||
*/
|
||||
protected final void flushBits() throws IOException {
|
||||
checkClosed();
|
||||
if (bitOffset != 0) {
|
||||
int offset = bitOffset;
|
||||
int partialByte = read(); // Sets bitOffset to 0
|
||||
if (partialByte < 0) {
|
||||
// Fix 4465683: When bitOffset is set
|
||||
// to something non-zero beyond EOF,
|
||||
// we should set that whole byte to
|
||||
// zero and write it to stream.
|
||||
partialByte = 0;
|
||||
bitOffset = 0;
|
||||
}
|
||||
else {
|
||||
seek(getStreamPosition() - 1);
|
||||
partialByte &= -1 << (8 - offset);
|
||||
}
|
||||
write(partialByte);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
364
jdkSrc/jdk8/javax/imageio/stream/MemoryCache.java
Normal file
364
jdkSrc/jdk8/javax/imageio/stream/MemoryCache.java
Normal file
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package javax.imageio.stream;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Package-visible class consolidating common code for
|
||||
* <code>MemoryCacheImageInputStream</code> and
|
||||
* <code>MemoryCacheImageOutputStream</code>.
|
||||
* This class keeps an <code>ArrayList</code> of 8K blocks,
|
||||
* loaded sequentially. Blocks may only be disposed of
|
||||
* from the index 0 forward. As blocks are freed, the
|
||||
* corresponding entries in the array list are set to
|
||||
* <code>null</code>, but no compacting is performed.
|
||||
* This allows the index for each block to never change,
|
||||
* and the length of the cache is always the same as the
|
||||
* total amount of data ever cached. Cached data is
|
||||
* therefore always contiguous from the point of last
|
||||
* disposal to the current length.
|
||||
*
|
||||
* <p> The total number of blocks resident in the cache must not
|
||||
* exceed <code>Integer.MAX_VALUE</code>. In practice, the limit of
|
||||
* available memory will be exceeded long before this becomes an
|
||||
* issue, since a full cache would contain 8192*2^31 = 16 terabytes of
|
||||
* data.
|
||||
*
|
||||
* A <code>MemoryCache</code> may be reused after a call
|
||||
* to <code>reset()</code>.
|
||||
*/
|
||||
class MemoryCache {
|
||||
|
||||
private static final int BUFFER_LENGTH = 8192;
|
||||
|
||||
private ArrayList cache = new ArrayList();
|
||||
|
||||
private long cacheStart = 0L;
|
||||
|
||||
/**
|
||||
* The largest position ever written to the cache.
|
||||
*/
|
||||
private long length = 0L;
|
||||
|
||||
private byte[] getCacheBlock(long blockNum) throws IOException {
|
||||
long blockOffset = blockNum - cacheStart;
|
||||
if (blockOffset > Integer.MAX_VALUE) {
|
||||
// This can only happen when the cache hits 16 terabytes of
|
||||
// contiguous data...
|
||||
throw new IOException("Cache addressing limit exceeded!");
|
||||
}
|
||||
return (byte[])cache.get((int)blockOffset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that at least <code>pos</code> bytes are cached,
|
||||
* or the end of the source is reached. The return value
|
||||
* is equal to the smaller of <code>pos</code> and the
|
||||
* length of the source.
|
||||
*/
|
||||
public long loadFromStream(InputStream stream, long pos)
|
||||
throws IOException {
|
||||
// We've already got enough data cached
|
||||
if (pos < length) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
int offset = (int)(length % BUFFER_LENGTH);
|
||||
byte [] buf = null;
|
||||
|
||||
long len = pos - length;
|
||||
if (offset != 0) {
|
||||
buf = getCacheBlock(length/BUFFER_LENGTH);
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
if (buf == null) {
|
||||
try {
|
||||
buf = new byte[BUFFER_LENGTH];
|
||||
} catch (OutOfMemoryError e) {
|
||||
throw new IOException("No memory left for cache!");
|
||||
}
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
int left = BUFFER_LENGTH - offset;
|
||||
int nbytes = (int)Math.min(len, (long)left);
|
||||
nbytes = stream.read(buf, offset, nbytes);
|
||||
if (nbytes == -1) {
|
||||
return length; // EOF
|
||||
}
|
||||
|
||||
if (offset == 0) {
|
||||
cache.add(buf);
|
||||
}
|
||||
|
||||
len -= nbytes;
|
||||
length += nbytes;
|
||||
offset += nbytes;
|
||||
|
||||
if (offset >= BUFFER_LENGTH) {
|
||||
// we've filled the current buffer, so a new one will be
|
||||
// allocated next time around (and offset will be reset to 0)
|
||||
buf = null;
|
||||
}
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes out a portion of the cache to an <code>OutputStream</code>.
|
||||
* This method preserves no state about the output stream, and does
|
||||
* not dispose of any blocks containing bytes written. To dispose
|
||||
* blocks, use {@link #disposeBefore <code>disposeBefore()</code>}.
|
||||
*
|
||||
* @exception IndexOutOfBoundsException if any portion of
|
||||
* the requested data is not in the cache (including if <code>pos</code>
|
||||
* is in a block already disposed), or if either <code>pos</code> or
|
||||
* <code>len</code> is < 0.
|
||||
*/
|
||||
public void writeToStream(OutputStream stream, long pos, long len)
|
||||
throws IOException {
|
||||
if (pos + len > length) {
|
||||
throw new IndexOutOfBoundsException("Argument out of cache");
|
||||
}
|
||||
if ((pos < 0) || (len < 0)) {
|
||||
throw new IndexOutOfBoundsException("Negative pos or len");
|
||||
}
|
||||
if (len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
long bufIndex = pos/BUFFER_LENGTH;
|
||||
if (bufIndex < cacheStart) {
|
||||
throw new IndexOutOfBoundsException("pos already disposed");
|
||||
}
|
||||
int offset = (int)(pos % BUFFER_LENGTH);
|
||||
|
||||
byte[] buf = getCacheBlock(bufIndex++);
|
||||
while (len > 0) {
|
||||
if (buf == null) {
|
||||
buf = getCacheBlock(bufIndex++);
|
||||
offset = 0;
|
||||
}
|
||||
int nbytes = (int)Math.min(len, (long)(BUFFER_LENGTH - offset));
|
||||
stream.write(buf, offset, nbytes);
|
||||
buf = null;
|
||||
len -= nbytes;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that there is space to write a byte at the given position.
|
||||
*/
|
||||
private void pad(long pos) throws IOException {
|
||||
long currIndex = cacheStart + cache.size() - 1;
|
||||
long lastIndex = pos/BUFFER_LENGTH;
|
||||
long numNewBuffers = lastIndex - currIndex;
|
||||
for (long i = 0; i < numNewBuffers; i++) {
|
||||
try {
|
||||
cache.add(new byte[BUFFER_LENGTH]);
|
||||
} catch (OutOfMemoryError e) {
|
||||
throw new IOException("No memory left for cache!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites and/or appends the cache from a byte array.
|
||||
* The length of the cache will be extended as needed to hold
|
||||
* the incoming data.
|
||||
*
|
||||
* @param b an array of bytes containing data to be written.
|
||||
* @param off the starting offset withing the data array.
|
||||
* @param len the number of bytes to be written.
|
||||
* @param pos the cache position at which to begin writing.
|
||||
*
|
||||
* @exception NullPointerException if <code>b</code> is <code>null</code>.
|
||||
* @exception IndexOutOfBoundsException if <code>off</code>,
|
||||
* <code>len</code>, or <code>pos</code> are negative,
|
||||
* or if <code>off+len > b.length</code>.
|
||||
*/
|
||||
public void write(byte[] b, int off, int len, long pos)
|
||||
throws IOException {
|
||||
if (b == null) {
|
||||
throw new NullPointerException("b == null!");
|
||||
}
|
||||
// Fix 4430357 - if off + len < 0, overflow occurred
|
||||
if ((off < 0) || (len < 0) || (pos < 0) ||
|
||||
(off + len > b.length) || (off + len < 0)) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
// Ensure there is space for the incoming data
|
||||
long lastPos = pos + len - 1;
|
||||
if (lastPos >= length) {
|
||||
pad(lastPos);
|
||||
length = lastPos + 1;
|
||||
}
|
||||
|
||||
// Copy the data into the cache, block by block
|
||||
int offset = (int)(pos % BUFFER_LENGTH);
|
||||
while (len > 0) {
|
||||
byte[] buf = getCacheBlock(pos/BUFFER_LENGTH);
|
||||
int nbytes = Math.min(len, BUFFER_LENGTH - offset);
|
||||
System.arraycopy(b, off, buf, offset, nbytes);
|
||||
|
||||
pos += nbytes;
|
||||
off += nbytes;
|
||||
len -= nbytes;
|
||||
offset = 0; // Always after the first time
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrites or appends a single byte to the cache.
|
||||
* The length of the cache will be extended as needed to hold
|
||||
* the incoming data.
|
||||
*
|
||||
* @param b an <code>int</code> whose 8 least significant bits
|
||||
* will be written.
|
||||
* @param pos the cache position at which to begin writing.
|
||||
*
|
||||
* @exception IndexOutOfBoundsException if <code>pos</code> is negative.
|
||||
*/
|
||||
public void write(int b, long pos) throws IOException {
|
||||
if (pos < 0) {
|
||||
throw new ArrayIndexOutOfBoundsException("pos < 0");
|
||||
}
|
||||
|
||||
// Ensure there is space for the incoming data
|
||||
if (pos >= length) {
|
||||
pad(pos);
|
||||
length = pos + 1;
|
||||
}
|
||||
|
||||
// Insert the data.
|
||||
byte[] buf = getCacheBlock(pos/BUFFER_LENGTH);
|
||||
int offset = (int)(pos % BUFFER_LENGTH);
|
||||
buf[offset] = (byte)b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the total length of data that has been cached,
|
||||
* regardless of whether any early blocks have been disposed.
|
||||
* This value will only ever increase.
|
||||
*/
|
||||
public long getLength() {
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the single byte at the given position, as an
|
||||
* <code>int</code>. Returns -1 if this position has
|
||||
* not been cached or has been disposed.
|
||||
*/
|
||||
public int read(long pos) throws IOException {
|
||||
if (pos >= length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
byte[] buf = getCacheBlock(pos/BUFFER_LENGTH);
|
||||
if (buf == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return buf[(int)(pos % BUFFER_LENGTH)] & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy <code>len</code> bytes from the cache, starting
|
||||
* at cache position <code>pos</code>, into the array
|
||||
* <code>b</code> at offset <code>off</code>.
|
||||
*
|
||||
* @exception NullPointerException if b is <code>null</code>
|
||||
* @exception IndexOutOfBoundsException if <code>off</code>,
|
||||
* <code>len</code> or <code>pos</code> are negative or if
|
||||
* <code>off + len > b.length</code> or if any portion of the
|
||||
* requested data is not in the cache (including if
|
||||
* <code>pos</code> is in a block that has already been disposed).
|
||||
*/
|
||||
public void read(byte[] b, int off, int len, long pos)
|
||||
throws IOException {
|
||||
if (b == null) {
|
||||
throw new NullPointerException("b == null!");
|
||||
}
|
||||
// Fix 4430357 - if off + len < 0, overflow occurred
|
||||
if ((off < 0) || (len < 0) || (pos < 0) ||
|
||||
(off + len > b.length) || (off + len < 0)) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
if (pos + len > length) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
long index = pos/BUFFER_LENGTH;
|
||||
int offset = (int)pos % BUFFER_LENGTH;
|
||||
while (len > 0) {
|
||||
int nbytes = Math.min(len, BUFFER_LENGTH - offset);
|
||||
byte[] buf = getCacheBlock(index++);
|
||||
System.arraycopy(buf, offset, b, off, nbytes);
|
||||
|
||||
len -= nbytes;
|
||||
off += nbytes;
|
||||
offset = 0; // Always after the first time
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the blocks up to the position <code>pos</code>.
|
||||
* The byte at <code>pos</code> remains available.
|
||||
*
|
||||
* @exception IndexOutOfBoundsException if <code>pos</code>
|
||||
* is in a block that has already been disposed.
|
||||
*/
|
||||
public void disposeBefore(long pos) {
|
||||
long index = pos/BUFFER_LENGTH;
|
||||
if (index < cacheStart) {
|
||||
throw new IndexOutOfBoundsException("pos already disposed");
|
||||
}
|
||||
long numBlocks = Math.min(index - cacheStart, cache.size());
|
||||
for (long i = 0; i < numBlocks; i++) {
|
||||
cache.remove(0);
|
||||
}
|
||||
this.cacheStart = index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase the entire cache contents and reset the length to 0.
|
||||
* The cache object may subsequently be reused as though it had just
|
||||
* been allocated.
|
||||
*/
|
||||
public void reset() {
|
||||
cache.clear();
|
||||
cacheStart = 0;
|
||||
length = 0L;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
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.
|
||||
*
|
||||
*/
|
||||
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();
|
||||
|
||||
if (b == null) {
|
||||
throw new NullPointerException("b == null!");
|
||||
}
|
||||
// Fix 4467608: read([B,I,I) works incorrectly if len<=0
|
||||
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;
|
||||
}
|
||||
|
||||
// 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 {
|
||||
flushBits(); // this will call checkClosed() for us
|
||||
cache.write(b, streamPos);
|
||||
++streamPos;
|
||||
}
|
||||
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
flushBits(); // this will call checkClosed() for us
|
||||
cache.write(b, off, len, streamPos);
|
||||
streamPos += len;
|
||||
}
|
||||
|
||||
public long length() {
|
||||
try {
|
||||
checkClosed();
|
||||
return cache.getLength();
|
||||
} catch (IOException e) {
|
||||
return -1L;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
||||
cache = null;
|
||||
stream = null;
|
||||
}
|
||||
|
||||
public void flushBefore(long pos) throws IOException {
|
||||
long oFlushedPos = flushedPos;
|
||||
super.flushBefore(pos); // this will call checkClosed() for us
|
||||
|
||||
long flushBytes = flushedPos - oFlushedPos;
|
||||
cache.writeToStream(stream, oFlushedPos, flushBytes);
|
||||
cache.disposeBefore(flushedPos);
|
||||
stream.flush();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user