001 /* @(#)FitsFile.java $Revision: 1.10 $ $Date: 2003/04/11 08:41:15 $
002 *
003 * Copyright (C) 2002 European Southern Observatory
004 * License: GNU General Public License version 2 or later
005 */
006 package org.eso.fits;
007
008 import java.lang.*;
009 import java.util.*;
010 import java.io.*;
011
012 /** FitsFile class represents a FITS file consisting of a set of
013 * Header/Data Units. The header information is stored in
014 * FitsHeader objects while data are not saved in objects but
015 * accessed through file. Thus, files may be corrupted if the
016 * disk file is modified independently by other modules.
017 *
018 * @version $Revision: 1.10 $ $Date: 2003/04/11 08:41:15 $
019 * @author P.Grosbol, DMD/ESO, <pgrosbol@eso.org> http://www.eso.org/~pgrosbol/fits_java/jfits.html
020 */
021 public class FitsFile {
022
023 private File file;
024 private RandomAccessFile raFile;
025 private Vector hdUnits;
026 private boolean changeHDU = false;
027
028 /** Default constructor for FitsFile class
029 */
030 public FitsFile() {
031 hdUnits = new Vector(1);
032 }
033
034 /** Constructor for FitsFile class given a FITS stream.
035 *
036 *
037 * @param file DataInput stream positioned at its start
038 * @exception FitsException */
039 public FitsFile(DataInput file) throws FitsException {
040 this();
041 scanFitsFile(file, false);
042 }
043
044 /** Constructor for FitsFile class given a FITS stream and a flag
045 * indicating if the data matrices should be stored internally.
046 * The store flag must be true to allow access to the data matrices
047 * where as header data will always be available.
048 *
049 * @param file DataInput stream positioned at its start
050 * @param sflag Flag indicating if data matrices should be
051 * stored internally in the class.
052 * @exception FitsException */
053 public FitsFile(DataInput file, boolean sflag) throws FitsException {
054 this();
055 scanFitsFile(file, sflag);
056 }
057
058 /** Constructor specifying a name of a disk file. Note: the file
059 * will be opened in read-only mode for security reasons. This
060 * means that the data matrix cannot be modified although headers
061 * can as they are stored in memory. If data should be modified,
062 * one must create a DataInput object for the file explicitly
063 * (with read/write permissions) and use the appropriate
064 * constructor.
065 *
066 * @param file name of disk file in FITS format
067 * @exception IOException,FitsException */
068 public FitsFile(File file) throws IOException, FitsException {
069 this();
070 this.raFile = new RandomAccessFile(file, "r");
071 this.file = file;
072 scanFitsFile(raFile, false);
073 }
074
075 /** Constructor from name of disk file. Note: the file will be
076 * opened in read-only mode for security reasons. This means
077 * that the data matrix cannot be modified although headers can
078 * as they are stored in memory. If data should be modified, one
079 * must create a DataInput object for the file explicitly (with
080 * read/write permissions) and use the appropriate constructor.
081 *
082 * @param filename name of disk file in FITS format
083 * @exception IOException,FitsException */
084 public FitsFile(String filename) throws IOException, FitsException {
085 this(new File(filename));
086 }
087
088 /** Private method which scans an input stream. It is used by the
089 * constructors.
090 * @param file DataInput file positioned at its start
091 * @param sflag Flag for internal storage of data matrices
092 * @exception FitsException */
093 private void scanFitsFile(DataInput file, boolean sflag)
094 throws FitsException {
095 FitsHDUnit hdu;
096 int no_hdu = 0;
097
098 try {
099 while (true) {
100 hdu = new FitsHDUnit(file, sflag);
101 hdUnits.setSize(no_hdu++);
102 hdUnits.addElement(hdu);
103 }
104 } catch (FitsException e) {
105 if (no_hdu<1) {
106 throw new FitsException("Not a FITS file (" + e + ")", FitsException.FILE);
107 }
108 }
109 hdUnits.trimToSize();
110 }
111
112 /** Finalize method which close disk file
113 *
114 * @exception IOException */
115 protected void finalize() throws IOException {
116 if (raFile != null) raFile.close();
117 file = null;
118 }
119
120 /** Static method to test if a disk file possibly is in FITS format.
121 * The test is trivial in the sense that the file may not be a correct
122 * FITS file even if 'true' is returned. On the other hand, it is
123 * certainly not a FITS file if 'false' is returned.
124 *
125 * @param file disk file */
126 public static boolean isFitsFile(File file) {
127 int nb = 0;
128 byte[] card = new byte[Fits.CARD];
129 try {
130 RandomAccessFile raf = new RandomAccessFile(file, "r");
131 nb = raf.read(card);
132 raf.close();
133 } catch (IOException e) {
134 return false;
135 }
136 if (nb<Fits.CARD) {
137 return false;
138 }
139 String str = new String(card);
140 return str.startsWith("SIMPLE = ");
141 }
142
143 /** Static method to test if a disk file possibly is in FITS format.
144 * The test is trivial in the sense that the file may not be a correct
145 * FITS file even if 'true' is returned. On the other hand, it is
146 * certainly not a FITS file if 'false' is returned.
147 *
148 * @param filename name of disk file */
149 public static boolean isFitsFile(String filename) {
150 return isFitsFile(new File(filename));
151 }
152
153 /** Add new HDUnit to FITS file.
154 *
155 * @param hdu FitsHDUnit to be added */
156 public void addHDUnit(FitsHDUnit hdu) {
157 hdUnits.addElement(hdu);
158 changeHDU = true;
159 }
160
161 /** Insert new HDUnit to FITS file at specified location.
162 *
163 * @param hdu FitsHDUnit to be inserted
164 * @param index location at which hte HDU should be inserted */
165 public void insertHDUnitAt(FitsHDUnit hdu, int index) {
166 hdUnits.insertElementAt(hdu, index);
167 changeHDU = true;
168 }
169
170 /** Remove HDUnit with given location from FITS file.
171 *
172 * @param index location of the HDU to be removed */
173 public void removeHDUnitAt(int index) {
174 hdUnits.removeElementAt(index);
175 changeHDU = true;
176 }
177
178 /** Get HDUnit in FitsFile by its position. If the position is
179 * less that 0, the first HDU is returned while the last is given
180 * for positions beyond the actual number.
181 *
182 * @param no number of HDUnit to retrieve (starting with 0) */
183 final public FitsHDUnit getHDUnit(int no){
184 int n = 0;
185
186 if (no<0) {
187 return (FitsHDUnit) hdUnits.firstElement();
188 } else if (no>=hdUnits.size()) {
189 return (FitsHDUnit) hdUnits.lastElement();
190 }
191
192 FitsHDUnit hdu;
193 Enumeration enumeration = hdUnits.elements();
194 while (enumeration.hasMoreElements()) {
195 hdu = (FitsHDUnit) enumeration.nextElement();
196 if (n==no) return hdu;
197 n++;
198 }
199 return (FitsHDUnit) hdUnits.lastElement();
200 }
201
202 /** Save changes made to a FITS file on disk. The FitsFile must have
203 * been creaded from a read/write RandomAccess disk file.
204 * Further, headers and data must fit into the original file.
205 * Not check is done to verify the correctness of the FITS headers.
206 *
207 * @exception IOException, FitsException */
208 public void saveFile() throws IOException,FitsException {
209 if (changeHDU) {
210 throw new FitsException("HD Units of file have been changes",
211 FitsException.FILE);
212 }
213 Enumeration enumeration = hdUnits.elements();
214 while (enumeration.hasMoreElements()) {
215 if (!((FitsHDUnit) enumeration.nextElement()).canSave()) {
216 throw new FitsException("No space in FITS header",
217 FitsException.NOHEADERSPACE);
218 }
219 }
220
221 RandomAccessFile raf = new RandomAccessFile(file, "rw");
222
223 enumeration = hdUnits.elements();
224 while (enumeration.hasMoreElements()) {
225 ((FitsHDUnit)enumeration.nextElement()).saveFile(raf);
226 }
227 raf.close();
228 }
229
230 /** Write FITS file to a DataOutput stream. Not check is done to verify
231 * the correctness of the FITS headers.
232 *
233 * @param file the data output to be written
234 * @exception IOException, FitsException */
235 public void writeFile(DataOutput file) throws IOException,FitsException {
236 Enumeration enumeration = hdUnits.elements();
237 while (enumeration.hasMoreElements()) {
238 ((FitsHDUnit)enumeration.nextElement()).writeFile(file);
239 }
240 }
241
242 /** Write FITS file on a new diskfile. Not check is done to verify
243 * the correctness of the FITS headers.
244 *
245 * @param file new file to be written
246 * @exception IOException, FitsException */
247 public void writeFile(File file) throws IOException,FitsException {
248 if (file == null) {
249 throw new FitsException("Cannot write to null-pointer file",
250 FitsException.FILE);
251 }
252 if (file.exists()) {
253 if (!file.isFile()) {
254 throw new FitsException("Cannot overwrite special file",
255 FitsException.FILE);
256 }
257 if ((this.file != null)
258 && this.file.getCanonicalPath().equals(
259 file.getCanonicalPath())) {
260 throw new FitsException("Cannot overwrite itself",
261 FitsException.FILE);
262 }
263 }
264 RandomAccessFile raf = new RandomAccessFile(file, "rw");
265 writeFile(raf);
266 raf.close();
267 }
268
269 /** Write FITS file on a new diskfile. Not check is done to verify
270 * the correctness of the FITS headers.
271 *
272 * @param filename name of new file to be written
273 * @exception IOException, FitsException */
274 public void writeFile(String filename) throws IOException,FitsException {
275 writeFile(new File(filename));
276 }
277
278 /** Remove all references to associated DataInput files. */
279 public void closeFile() {
280 Enumeration enumeration = hdUnits.elements();
281 while (enumeration.hasMoreElements()) {
282 ((FitsHDUnit)enumeration.nextElement()).closeFile();
283 }
284 if (raFile != null) {
285 try {
286 raFile.close();
287 } catch (IOException e) {
288 }
289 }
290 this.file = null;
291 }
292
293 /** Gets numnber of HDUnits in FITS file */
294 final public int getNoHDUnits(){
295 return hdUnits.size();
296 }
297
298 /** Gets Canonical path of FITS file */
299 public String getName(){
300 String name = "";
301 if (file != null) {
302 try {
303 name = file.getCanonicalPath();
304 } catch (IOException e) {
305 name = file.getAbsolutePath();
306 }
307 }
308 return name;
309 }
310
311 /** Gets file identifier for FITS file */
312 public File getFile(){
313 return file;
314 }
315 }
316
317
318
319