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 ImageInputStream} that gets its 38 * input from a {@code File} or {@code RandomAccessFile}. 39 * The file contents are assumed to be stable during the lifetime of 40 * the object. 41 * 42 */ 43 public 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} that will read 55 * from a given {@code File}. 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} to read from. 62 * 63 * @exception IllegalArgumentException if {@code f} is 64 * {@code null}. 65 * @exception SecurityException if a security manager exists 66 * and does not allow read access to the file. 67 * @exception FileNotFoundException if {@code f} 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} that will read 78 * from a given {@code RandomAccessFile}. 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} to read from. 85 * 86 * @exception IllegalArgumentException if {@code raf} is 87 * {@code null}. 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} 126 * if it is unknown. 127 * 128 * @return the file length as a {@code long}, or 129 * {@code -1}. 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 * @deprecated The {@code finalize} method has been deprecated. 160 * Subclasses that override {@code finalize} in order to perform cleanup 161 * should be modified to use alternative cleanup mechanisms and 162 * to remove the overriding {@code finalize} method. 163 * When overriding the {@code finalize} method, its implementation must explicitly 164 * ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}. 165 * See the specification for {@link Object#finalize()} for further 166 * information about migration options. 167 */ 168 @Deprecated(since="9") 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 }