/* @(#)FitsFile.java $Revision: 1.13 $ $Date: 2005/09/16 09:58:10 $
*
* Copyright (C) 2002 European Southern Observatory
* License: GNU General Public License version 2 or later
*/
package fr.unistra.pelican.util.jFits;
import java.util.*;
import java.io.*;
/** FitsFile class represents a FITS file consisting of a set of
* Header/Data Units. The header information is stored in
* FitsHeader objects while data are not saved in objects but
* accessed through file. Thus, files may be corrupted if the
* disk file is modified independently by other modules.
*
* @version $Revision: 1.13 $ $Date: 2005/09/16 09:58:10 $
* @author P.Grosbol, ESO, <pgrosbol@eso.org>
*/
public class FitsFile {
private File file;
private RandomAccessFile raFile;
private Vector hdUnits;
private boolean changeHDU = false;
/** Default constructor for FitsFile class
*/
public FitsFile() {
hdUnits = new Vector(1);
}
/** Constructor for FitsFile class given a FITS stream.
*
*
* @param file DataInput stream positioned at its start
* @exception FitsException */
public FitsFile(DataInput file) throws FitsException {
this();
scanFitsFile(file, false);
}
/** Constructor for FitsFile class given a FITS stream and a flag
* indicating if the data matrices should be stored internally.
* The store flag must be true to allow access to the data matrices
* whereas header data will always be available.
*
* @param file DataInput stream positioned at its start
* @param sflag Flag indicating if data matrices should be
* stored internally in the class.
* @exception FitsException */
public FitsFile(DataInput file, boolean sflag) throws FitsException {
this();
scanFitsFile(file, sflag);
}
/** Constructor specifying a name of a disk file. Note: the file
* will be opened in read-only mode for security reasons. This
* means that the data matrix cannot be modified although headers
* can as they are stored in memory. If data should be modified,
* one must create a DataInput object for the file explicitly
* (with read/write permissions) and use the appropriate
* constructor.
*
* @param file name of disk file in FITS format
* @exception IOException,FitsException */
public FitsFile(File file) throws IOException, FitsException {
this();
this.raFile = new RandomAccessFile(file, "r");
this.file = file;
scanFitsFile(raFile, false);
}
/** Constructor from name of disk file. Note: the file will be
* opened in read-only mode for security reasons. This means
* that the data matrix cannot be modified although headers can
* as they are stored in memory. If data should be modified, one
* must create a DataInput object for the file explicitly (with
* read/write permissions) and use the appropriate constructor.
*
* @param filename name of disk file in FITS format
* @exception IOException,FitsException */
public FitsFile(String filename) throws IOException, FitsException {
this(new File(filename));
}
/** Private method which scans an input stream. It is used by the
* constructors.
* @param file DataInput file positioned at its start
* @param sflag Flag for internal storage of data matrices
* @exception FitsException */
private void scanFitsFile(DataInput file, boolean sflag)
throws FitsException {
FitsHDUnit hdu;
int no_hdu = 0;
try {
while (true) {
hdu = new FitsHDUnit(file, sflag);
hdUnits.setSize(no_hdu++);
hdUnits.addElement(hdu);
}
} catch (FitsException e) {
//System.out.println("Fits read stop because " + e);
if (no_hdu<1) {
throw new FitsException("Not a FITS file (" +e +")", FitsException.FILE);
}
}
hdUnits.trimToSize();
}
/** Finalize method which close disk file
*
* @exception IOException */
protected void finalize() throws IOException {
if (raFile != null) raFile.close();
file = null;
}
/** Static method to test if a disk file possibly is in FITS format.
* The test is trivial in the sense that the file may not be a correct
* FITS file even if 'true' is returned. On the other hand, it is
* certainly not a FITS file if 'false' is returned.
*
* @param file disk file */
public static boolean isFitsFile(File file) {
int nb = 0;
byte[] card = new byte[Fits.CARD];
try {
RandomAccessFile raf = new RandomAccessFile(file, "r");
nb = raf.read(card);
raf.close();
} catch (IOException e) {
return false;
}
if (nb<Fits.CARD) {
return false;
}
String str = new String(card);
return str.startsWith("SIMPLE = ");
}
/** Static method to test if a disk file possibly is in FITS format.
* The test is trivial in the sense that the file may not be a correct
* FITS file even if 'true' is returned. On the other hand, it is
* certainly not a FITS file if 'false' is returned.
*
* @param filename name of disk file */
public static boolean isFitsFile(String filename) {
return isFitsFile(new File(filename));
}
/** Add new HDUnit to FITS file.
*
* @param hdu FitsHDUnit to be added */
public void addHDUnit(FitsHDUnit hdu) {
hdUnits.addElement(hdu);
changeHDU = true;
}
/** Insert new HDUnit to FITS file at specified location.
*
* @param hdu FitsHDUnit to be inserted
* @param index location at which hte HDU should be inserted */
public void insertHDUnitAt(FitsHDUnit hdu, int index) {
hdUnits.insertElementAt(hdu, index);
changeHDU = true;
}
/** Remove HDUnit with given location from FITS file.
*
* @param index location of the HDU to be removed */
public void removeHDUnitAt(int index) {
hdUnits.removeElementAt(index);
changeHDU = true;
}
/** Get HDUnit in FitsFile by its position. If the position is
* less that 0, the first HDU is returned while the kast is given
* for positions beyond the actual number.
*
* @param no number of HDUnit to retrieve (starting with 0) */
final public FitsHDUnit getHDUnit(int no){
int n = 0;
if (no<0) {
return (FitsHDUnit) hdUnits.firstElement();
} else if (no>=hdUnits.size()) {
return (FitsHDUnit) hdUnits.lastElement();
}
FitsHDUnit hdu;
Enumeration itr = hdUnits.elements();
while (itr.hasMoreElements()) {
hdu = (FitsHDUnit) itr.nextElement();
if (n==no) return hdu;
n++;
}
return (FitsHDUnit) hdUnits.lastElement();
}
/** Save changes made to a FITS file on disk. The FitsFile must have
* been created from a read/write RandomAccess disk file.
* Further, headers and data must fit into the original file.
* Not check is done to verify the correctness of the FITS headers.
*
* @exception IOException, FitsException */
public void saveFile() throws IOException,FitsException {
if (changeHDU) {
throw new FitsException("HD Units of file have been changes",
FitsException.FILE);
}
Enumeration itr = hdUnits.elements();
while (itr.hasMoreElements()) {
if (!((FitsHDUnit) itr.nextElement()).canSave()) {
throw new FitsException("No space in FITS header",
FitsException.NOHEADERSPACE);
}
}
RandomAccessFile raf = new RandomAccessFile(file, "rw");
itr = hdUnits.elements();
while (itr.hasMoreElements()) {
((FitsHDUnit)itr.nextElement()).saveFile(raf);
}
raf.close();
}
/** Write FITS file to a DataOutput stream. Not check is done to verify
* the correctness of the FITS headers.
*
* @param filename name of new file to be written
* @exception IOException, FitsException */
public void writeFile(DataOutput filename) throws IOException,FitsException {
Enumeration itr = hdUnits.elements();
while (itr.hasMoreElements()) {
((FitsHDUnit)itr.nextElement()).writeFile(filename);
}
}
/** Write FITS file on a new diskfile. Not check is done to verify
* the correctness of the FITS headers.
*
* @param file new file to be written
* @exception IOException, FitsException */
public void writeFile(File file) throws IOException,FitsException {
if (file == null) {
throw new FitsException("Cannot write to null-pointer file",
FitsException.FILE);
}
if (file.exists()) {
if (!file.isFile()) {
throw new FitsException("Cannot overwrite special file",
FitsException.FILE);
}
if ((this.file != null)
&& this.file.getCanonicalPath().equals(
file.getCanonicalPath())) {
throw new FitsException("Cannot overwrite itself",
FitsException.FILE);
}
}
RandomAccessFile raf = new RandomAccessFile(file, "rw");
writeFile(raf);
raf.close();
}
/** Write FITS file on a new diskfile. Not check is done to verify
* the correctness of the FITS headers.
*
* @param filename name of new file to be written
* @exception IOException, FitsException */
public void writeFile(String filename) throws IOException,FitsException {
writeFile(new File(filename));
}
/** Remove all references to associated DataInput files. */
public void closeFile() {
Enumeration itr = hdUnits.elements();
while (itr.hasMoreElements()) {
((FitsHDUnit)itr.nextElement()).closeFile();
}
if (raFile != null) {
try {
raFile.close();
} catch (IOException e) {
}
}
this.file = null;
}
/** Gets numnber of HDUnits in FITS file */
final public int getNoHDUnits(){
return hdUnits.size();
}
/** Gets Canonical path of FITS file */
public String getName(){
String name = "";
if (file != null) {
try {
name = file.getCanonicalPath();
} catch (IOException e) {
name = file.getAbsolutePath();
}
}
return name;
}
/** Gets file identifier for FITS file */
public File getFile(){
return file;
}
}