001 /*
002 * Copyright 2000-2006 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>ImageOutputStream</code> that writes its
039 * output directly to a <code>File</code> or
040 * <code>RandomAccessFile</code>.
041 *
042 * @version 0.5
043 */
044 public class FileImageOutputStream extends ImageOutputStreamImpl {
045
046 private RandomAccessFile raf;
047
048 /** The referent to be registered with the Disposer. */
049 private final Object disposerReferent;
050
051 /** The DisposerRecord that closes the underlying RandomAccessFile. */
052 private final CloseableDisposerRecord disposerRecord;
053
054 /**
055 * Constructs a <code>FileImageOutputStream</code> that will write
056 * to a given <code>File</code>.
057 *
058 * @param f a <code>File</code> to write to.
059 *
060 * @exception IllegalArgumentException if <code>f</code> is
061 * <code>null</code>.
062 * @exception SecurityException if a security manager exists
063 * and does not allow write access to the file.
064 * @exception FileNotFoundException if <code>f</code> does not denote
065 * a regular file or it cannot be opened for reading and writing for any
066 * other reason.
067 * @exception IOException if an I/O error occurs.
068 */
069 public FileImageOutputStream(File f) throws FileNotFoundException,
070 IOException {
071 this (f == null ? null : new RandomAccessFile(f, "rw"));
072 }
073
074 /**
075 * Constructs a <code>FileImageOutputStream</code> that will write
076 * to a given <code>RandomAccessFile</code>.
077 *
078 * @param raf a <code>RandomAccessFile</code> to write to.
079 *
080 * @exception IllegalArgumentException if <code>raf</code> is
081 * <code>null</code>.
082 */
083 public FileImageOutputStream(RandomAccessFile raf) {
084 if (raf == null) {
085 throw new IllegalArgumentException("raf == null!");
086 }
087 this .raf = raf;
088
089 disposerRecord = new CloseableDisposerRecord(raf);
090 if (getClass() == FileImageOutputStream.class) {
091 disposerReferent = new Object();
092 Disposer.addRecord(disposerReferent, disposerRecord);
093 } else {
094 disposerReferent = new StreamFinalizer(this );
095 }
096 }
097
098 public int read() throws IOException {
099 checkClosed();
100 bitOffset = 0;
101 int val = raf.read();
102 if (val != -1) {
103 ++streamPos;
104 }
105 return val;
106 }
107
108 public int read(byte[] b, int off, int len) throws IOException {
109 checkClosed();
110 bitOffset = 0;
111 int nbytes = raf.read(b, off, len);
112 if (nbytes != -1) {
113 streamPos += nbytes;
114 }
115 return nbytes;
116 }
117
118 public void write(int b) throws IOException {
119 flushBits(); // this will call checkClosed() for us
120 raf.write(b);
121 ++streamPos;
122 }
123
124 public void write(byte[] b, int off, int len) throws IOException {
125 flushBits(); // this will call checkClosed() for us
126 raf.write(b, off, len);
127 streamPos += len;
128 }
129
130 public long length() {
131 try {
132 checkClosed();
133 return raf.length();
134 } catch (IOException e) {
135 return -1L;
136 }
137 }
138
139 /**
140 * Sets the current stream position and resets the bit offset to
141 * 0. It is legal to seeking past the end of the file; an
142 * <code>EOFException</code> will be thrown only if a read is
143 * performed. The file length will not be increased until a write
144 * is performed.
145 *
146 * @exception IndexOutOfBoundsException if <code>pos</code> is smaller
147 * than the flushed position.
148 * @exception IOException if any other I/O error occurs.
149 */
150 public void seek(long pos) throws IOException {
151 checkClosed();
152 if (pos < flushedPos) {
153 throw new IndexOutOfBoundsException("pos < flushedPos!");
154 }
155 bitOffset = 0;
156 raf.seek(pos);
157 streamPos = raf.getFilePointer();
158 }
159
160 public void close() throws IOException {
161 super .close();
162 disposerRecord.dispose(); // this closes the RandomAccessFile
163 raf = null;
164 }
165
166 /**
167 * {@inheritDoc}
168 */
169 protected void finalize() throws Throwable {
170 // Empty finalizer: for performance reasons we instead use the
171 // Disposer mechanism for ensuring that the underlying
172 // RandomAccessFile is closed prior to garbage collection
173 }
174 }
|