blob: 55b3d3fcbe03dfc023fbfcc0ad35755abc249f2d [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2007 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package javax.imageio.stream;
27
28import java.io.File;
29import java.io.FileNotFoundException;
30import java.io.IOException;
31import java.io.RandomAccessFile;
32import com.sun.imageio.stream.CloseableDisposerRecord;
33import com.sun.imageio.stream.StreamFinalizer;
34import sun.java2d.Disposer;
35
36/**
37 * An implementation of <code>ImageInputStream</code> that gets its
38 * input from a <code>File</code> or <code>RandomAccessFile</code>.
39 * The file contents are assumed to be stable during the lifetime of
40 * the object.
41 *
42 */
43public class FileImageInputStream extends ImageInputStreamImpl {
44
45 private RandomAccessFile raf;
46
47 /** The referent to be registered with the Disposer. */
48 private final Object disposerReferent;
49
50 /** The DisposerRecord that closes the underlying RandomAccessFile. */
51 private final CloseableDisposerRecord disposerRecord;
52
53 /**
54 * Constructs a <code>FileImageInputStream</code> that will read
55 * from a given <code>File</code>.
56 *
57 * <p> The file contents must not change between the time this
58 * object is constructed and the time of the last call to a read
59 * method.
60 *
61 * @param f a <code>File</code> to read from.
62 *
63 * @exception IllegalArgumentException if <code>f</code> is
64 * <code>null</code>.
65 * @exception SecurityException if a security manager exists
66 * and does not allow read access to the file.
67 * @exception FileNotFoundException if <code>f</code> is a
68 * directory or cannot be opened for reading for any other reason.
69 * @exception IOException if an I/O error occurs.
70 */
71 public FileImageInputStream(File f)
72 throws FileNotFoundException, IOException {
73 this(f == null ? null : new RandomAccessFile(f, "r"));
74 }
75
76 /**
77 * Constructs a <code>FileImageInputStream</code> that will read
78 * from a given <code>RandomAccessFile</code>.
79 *
80 * <p> The file contents must not change between the time this
81 * object is constructed and the time of the last call to a read
82 * method.
83 *
84 * @param raf a <code>RandomAccessFile</code> to read from.
85 *
86 * @exception IllegalArgumentException if <code>raf</code> is
87 * <code>null</code>.
88 */
89 public FileImageInputStream(RandomAccessFile raf) {
90 if (raf == null) {
91 throw new IllegalArgumentException("raf == null!");
92 }
93 this.raf = raf;
94
95 disposerRecord = new CloseableDisposerRecord(raf);
96 if (getClass() == FileImageInputStream.class) {
97 disposerReferent = new Object();
98 Disposer.addRecord(disposerReferent, disposerRecord);
99 } else {
100 disposerReferent = new StreamFinalizer(this);
101 }
102 }
103
104 public int read() throws IOException {
105 checkClosed();
106 bitOffset = 0;
107 int val = raf.read();
108 if (val != -1) {
109 ++streamPos;
110 }
111 return val;
112 }
113
114 public int read(byte[] b, int off, int len) throws IOException {
115 checkClosed();
116 bitOffset = 0;
117 int nbytes = raf.read(b, off, len);
118 if (nbytes != -1) {
119 streamPos += nbytes;
120 }
121 return nbytes;
122 }
123
124 /**
125 * Returns the length of the underlying file, or <code>-1</code>
126 * if it is unknown.
127 *
128 * @return the file length as a <code>long</code>, or
129 * <code>-1</code>.
130 */
131 public long length() {
132 try {
133 checkClosed();
134 return raf.length();
135 } catch (IOException e) {
136 return -1L;
137 }
138 }
139
140 public void seek(long pos) throws IOException {
141 checkClosed();
142 if (pos < flushedPos) {
143 throw new IndexOutOfBoundsException("pos < flushedPos!");
144 }
145 bitOffset = 0;
146 raf.seek(pos);
147 streamPos = raf.getFilePointer();
148 }
149
150 public void close() throws IOException {
151 super.close();
152 disposerRecord.dispose(); // this closes the RandomAccessFile
153 raf = null;
154 }
155
156 /**
157 * {@inheritDoc}
158 */
159 protected void finalize() throws Throwable {
160 // Empty finalizer: for performance reasons we instead use the
161 // Disposer mechanism for ensuring that the underlying
162 // RandomAccessFile is closed prior to garbage collection
163 }
164}