blob: df6583228d7b23c1cbd5afbbb7cb05654a091c35 [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>ImageOutputStream</code> that writes its
38 * output directly to a <code>File</code> or
39 * <code>RandomAccessFile</code>.
40 *
41 */
42public class FileImageOutputStream extends ImageOutputStreamImpl {
43
44 private RandomAccessFile raf;
45
46 /** The referent to be registered with the Disposer. */
47 private final Object disposerReferent;
48
49 /** The DisposerRecord that closes the underlying RandomAccessFile. */
50 private final CloseableDisposerRecord disposerRecord;
51
52 /**
53 * Constructs a <code>FileImageOutputStream</code> that will write
54 * to a given <code>File</code>.
55 *
56 * @param f a <code>File</code> to write to.
57 *
58 * @exception IllegalArgumentException if <code>f</code> is
59 * <code>null</code>.
60 * @exception SecurityException if a security manager exists
61 * and does not allow write access to the file.
62 * @exception FileNotFoundException if <code>f</code> does not denote
63 * a regular file or it cannot be opened for reading and writing for any
64 * other reason.
65 * @exception IOException if an I/O error occurs.
66 */
67 public FileImageOutputStream(File f)
68 throws FileNotFoundException, IOException {
69 this(f == null ? null : new RandomAccessFile(f, "rw"));
70 }
71
72 /**
73 * Constructs a <code>FileImageOutputStream</code> that will write
74 * to a given <code>RandomAccessFile</code>.
75 *
76 * @param raf a <code>RandomAccessFile</code> to write to.
77 *
78 * @exception IllegalArgumentException if <code>raf</code> is
79 * <code>null</code>.
80 */
81 public FileImageOutputStream(RandomAccessFile raf) {
82 if (raf == null) {
83 throw new IllegalArgumentException("raf == null!");
84 }
85 this.raf = raf;
86
87 disposerRecord = new CloseableDisposerRecord(raf);
88 if (getClass() == FileImageOutputStream.class) {
89 disposerReferent = new Object();
90 Disposer.addRecord(disposerReferent, disposerRecord);
91 } else {
92 disposerReferent = new StreamFinalizer(this);
93 }
94 }
95
96 public int read() throws IOException {
97 checkClosed();
98 bitOffset = 0;
99 int val = raf.read();
100 if (val != -1) {
101 ++streamPos;
102 }
103 return val;
104 }
105
106 public int read(byte[] b, int off, int len) throws IOException {
107 checkClosed();
108 bitOffset = 0;
109 int nbytes = raf.read(b, off, len);
110 if (nbytes != -1) {
111 streamPos += nbytes;
112 }
113 return nbytes;
114 }
115
116 public void write(int b) throws IOException {
117 flushBits(); // this will call checkClosed() for us
118 raf.write(b);
119 ++streamPos;
120 }
121
122 public void write(byte[] b, int off, int len) throws IOException {
123 flushBits(); // this will call checkClosed() for us
124 raf.write(b, off, len);
125 streamPos += len;
126 }
127
128 public long length() {
129 try {
130 checkClosed();
131 return raf.length();
132 } catch (IOException e) {
133 return -1L;
134 }
135 }
136
137 /**
138 * Sets the current stream position and resets the bit offset to
139 * 0. It is legal to seeking past the end of the file; an
140 * <code>EOFException</code> will be thrown only if a read is
141 * performed. The file length will not be increased until a write
142 * is performed.
143 *
144 * @exception IndexOutOfBoundsException if <code>pos</code> is smaller
145 * than the flushed position.
146 * @exception IOException if any other I/O error occurs.
147 */
148 public void seek(long pos) throws IOException {
149 checkClosed();
150 if (pos < flushedPos) {
151 throw new IndexOutOfBoundsException("pos < flushedPos!");
152 }
153 bitOffset = 0;
154 raf.seek(pos);
155 streamPos = raf.getFilePointer();
156 }
157
158 public void close() throws IOException {
159 super.close();
160 disposerRecord.dispose(); // this closes the RandomAccessFile
161 raf = null;
162 }
163
164 /**
165 * {@inheritDoc}
166 */
167 protected void finalize() throws Throwable {
168 // Empty finalizer: for performance reasons we instead use the
169 // Disposer mechanism for ensuring that the underlying
170 // RandomAccessFile is closed prior to garbage collection
171 }
172}