1 /* 2 * Copyright (c) 2000, 2017, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.imageio.stream; 27 28 import java.io.File; 29 import java.io.FileNotFoundException; 30 import java.io.IOException; 31 import java.io.RandomAccessFile; 32 import com.sun.imageio.stream.CloseableDisposerRecord; 33 import com.sun.imageio.stream.StreamFinalizer; 34 import sun.java2d.Disposer; 35 36 /** 37 * An implementation of {@code ImageOutputStream} that writes its 38 * output directly to a {@code File} or 39 * {@code RandomAccessFile}. 40 * 41 */ 42 public 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} that will write 54 * to a given {@code File}. 55 * 56 * @param f a {@code File} to write to. 57 * 58 * @exception IllegalArgumentException if {@code f} is 59 * {@code null}. 60 * @exception SecurityException if a security manager exists 61 * and does not allow write access to the file. 62 * @exception FileNotFoundException if {@code f} 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} that will write 74 * to a given {@code RandomAccessFile}. 75 * 76 * @param raf a {@code RandomAccessFile} to write to. 77 * 78 * @exception IllegalArgumentException if {@code raf} is 79 * {@code null}. 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} 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} 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 * @deprecated Finalization has been deprecated for removal. See 168 * {@link java.lang.Object#finalize} for background information and details 169 * about migration options. 170 */ 171 @Deprecated(since="9", forRemoval=true) 172 @SuppressWarnings("removal") 173 protected void finalize() throws Throwable { 174 // Empty finalizer: for performance reasons we instead use the 175 // Disposer mechanism for ensuring that the underlying 176 // RandomAccessFile is closed prior to garbage collection 177 } 178 }