001 /*
002 * Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package javax.imageio.stream;
027
028 import java.io.DataInput;
029 import java.io.File;
030 import java.io.FileNotFoundException;
031 import java.io.IOException;
032 import java.io.RandomAccessFile;
033 import com.sun.imageio.stream.CloseableDisposerRecord;
034 import com.sun.imageio.stream.StreamFinalizer;
035 import sun.java2d.Disposer;
036
037 /**
038 * An implementation of <code>ImageInputStream</code> that gets its
039 * input from a <code>File</code> or <code>RandomAccessFile</code>.
040 * The file contents are assumed to be stable during the lifetime of
041 * the object.
042 *
043 * @version 0.5
044 */
045 public class FileImageInputStream extends ImageInputStreamImpl {
046
047 private RandomAccessFile raf;
048
049 /** The referent to be registered with the Disposer. */
050 private final Object disposerReferent;
051
052 /** The DisposerRecord that closes the underlying RandomAccessFile. */
053 private final CloseableDisposerRecord disposerRecord;
054
055 /**
056 * Constructs a <code>FileImageInputStream</code> that will read
057 * from a given <code>File</code>.
058 *
059 * <p> The file contents must not change between the time this
060 * object is constructed and the time of the last call to a read
061 * method.
062 *
063 * @param f a <code>File</code> to read from.
064 *
065 * @exception IllegalArgumentException if <code>f</code> is
066 * <code>null</code>.
067 * @exception SecurityException if a security manager exists
068 * and does not allow read access to the file.
069 * @exception FileNotFoundException if <code>f</code> is a
070 * directory or cannot be opened for reading for any other reason.
071 * @exception IOException if an I/O error occurs.
072 */
073 public FileImageInputStream(File f) throws FileNotFoundException,
074 IOException {
075 this (f == null ? null : new RandomAccessFile(f, "r"));
076 }
077
078 /**
079 * Constructs a <code>FileImageInputStream</code> that will read
080 * from a given <code>RandomAccessFile</code>.
081 *
082 * <p> The file contents must not change between the time this
083 * object is constructed and the time of the last call to a read
084 * method.
085 *
086 * @param raf a <code>RandomAccessFile</code> to read from.
087 *
088 * @exception IllegalArgumentException if <code>raf</code> is
089 * <code>null</code>.
090 */
091 public FileImageInputStream(RandomAccessFile raf) {
092 if (raf == null) {
093 throw new IllegalArgumentException("raf == null!");
094 }
095 this .raf = raf;
096
097 disposerRecord = new CloseableDisposerRecord(raf);
098 if (getClass() == FileImageInputStream.class) {
099 disposerReferent = new Object();
100 Disposer.addRecord(disposerReferent, disposerRecord);
101 } else {
102 disposerReferent = new StreamFinalizer(this );
103 }
104 }
105
106 public int read() throws IOException {
107 checkClosed();
108 bitOffset = 0;
109 int val = raf.read();
110 if (val != -1) {
111 ++streamPos;
112 }
113 return val;
114 }
115
116 public int read(byte[] b, int off, int len) throws IOException {
117 checkClosed();
118 bitOffset = 0;
119 int nbytes = raf.read(b, off, len);
120 if (nbytes != -1) {
121 streamPos += nbytes;
122 }
123 return nbytes;
124 }
125
126 /**
127 * Returns the length of the underlying file, or <code>-1</code>
128 * if it is unknown.
129 *
130 * @return the file length as a <code>long</code>, or
131 * <code>-1</code>.
132 */
133 public long length() {
134 try {
135 checkClosed();
136 return raf.length();
137 } catch (IOException e) {
138 return -1L;
139 }
140 }
141
142 public void seek(long pos) throws IOException {
143 checkClosed();
144 if (pos < flushedPos) {
145 throw new IndexOutOfBoundsException("pos < flushedPos!");
146 }
147 bitOffset = 0;
148 raf.seek(pos);
149 streamPos = raf.getFilePointer();
150 }
151
152 public void close() throws IOException {
153 super .close();
154 disposerRecord.dispose(); // this closes the RandomAccessFile
155 raf = null;
156 }
157
158 /**
159 * {@inheritDoc}
160 */
161 protected void finalize() throws Throwable {
162 // Empty finalizer: for performance reasons we instead use the
163 // Disposer mechanism for ensuring that the underlying
164 // RandomAccessFile is closed prior to garbage collection
165 }
166 }
|