    001/*****************************************************************************
    002 * Copyright by The HDF Group.                                               *
    003 * Copyright by the Board of Trustees of the University of Illinois.         *
    004 * All rights reserved.                                                      *
    005 *                                                                           *
    006 * This file is part of the HDF Java Products distribution.                  *
    007 * The full copyright notice, including terms governing use, modification,   *
    008 * and redistribution, is contained in the files COPYING and Copyright.html. *
    009 * COPYING can be found at the root of the source code distribution tree.    *
    010 * Or, see https://support.hdfgroup.org/products/licenses.html               *
    011 * If you do not have access to either file, you may request a copy from     *
    012 * help@hdfgroup.org.                                                        *
    013 ****************************************************************************/
    014
    015package hdf.object.fits;
    016
    017import java.io.DataInput;
    018import java.io.IOException;
    019import java.io.InputStream;
    020import java.io.RandomAccessFile;
    021
    022import hdf.object.Dataset;
    023import hdf.object.Datatype;
    024import hdf.object.FileFormat;
    025import hdf.object.Group;
    026import hdf.object.HObject;
    027import nom.tam.fits.AsciiTableHDU;
    028import nom.tam.fits.BasicHDU;
    029import nom.tam.fits.BinaryTableHDU;
    030import nom.tam.fits.Fits;
    031import nom.tam.fits.ImageHDU;
    032import nom.tam.fits.RandomGroupsHDU;
    033import nom.tam.fits.TableHDU;
    034
    035/**
    036 * This class provides file level APIs. File access APIs include retrieving the
    037 * file hierarchy, opening and closing file, and writing file content to disk.
    038 * <p>
    039 * @version 2.4 9/4/2007
    040 * @author Peter X. Cao
    041 */
    042public class FitsFile extends FileFormat
    043{
    044    private static final long serialVersionUID = -1965689032980605791L;
    045
    046    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(FitsFile.class);
    047
    048    /**
    049     * The root object of the file hierarchy.
    050     */
    051    private HObject rootObject;
    052
    053    /** the fits file */
    054    private Fits fitsFile;
    055
    056    private static boolean isFileOpen;
    057
    058    /**
    059     * Constructs an empty FitsFile with read-only access.
    060     */
    061    public FitsFile() {
    062        this("");
    063    }
    064
    065    /**
    066     * Constructs an FitsFile object of given file name with read-only access.
    067     * @param pathname the file name.
    068     */
    069    public FitsFile(String pathname) {
    070        super(pathname);
    071
    072        isReadOnly = true;
    073        isFileOpen = false;
    074        this.fid = -1;
    075        try {
    076            fitsFile = new Fits(fullFileName);
    077        }
    078        catch (Exception ex) {
    079            if(!pathname.isEmpty())
    080                log.debug("Fits({}):", fullFileName, ex);
    081        }
    082    }
    083
    084
    085    /**
    086     * Checks if the given file format is a Fits file.
    087     * <p>
    088     * @param fileformat the fileformat to be checked.
    089     * @return true if the given file is an Fits file; otherwise returns false.
    090     */
    091    @Override
    092    public boolean isThisType(FileFormat fileformat) {
    093        return (fileformat instanceof FitsFile);
    094    }
    095
    096    /**
    097     * Checks if a given file is a Fits file.
    098     * <p>
    099     * @param filename the file to be checked.
    100     * @return true if the given file is an Fits file; otherwise returns false.
    101     */
    102    @Override
    103    public boolean isThisType(String filename)
    104    {
    105        boolean is_fits = false;
    106        RandomAccessFile raf = null;
    107        try {
    108            raf = new RandomAccessFile(filename, "r");
    109        }
    110        catch (Exception ex) {
    111            raf = null;
    112        }
    113
    114        if (raf == null) {
    115            return false;
    116        }
    117
    118        byte[] header = new byte[80];
    119        try {
    120            raf.read(header);
    121        }
    122        catch (Exception ex) {
    123            header = null;
    124        }
    125
    126        if (header != null) {
    127            String front = new String(header, 0, 9);
    128            if (!front.startsWith("SIMPLE  =")) {
    129                try {
    130                    raf.close();
    131                }
    132                catch (Exception ex) {
    133                    log.debug("closing RandomAccessFile({}):", filename, ex);
    134                }
    135                return false;
    136            }
    137
    138            String back = new String(header, 9, 70);
    139            back = back.trim();
    140            if ((back.length() < 1) || (back.charAt(0) != 'T')) {
    141                try {
    142                    raf.close();
    143                }
    144                catch (Exception ex) {
    145                    log.debug("closing RandomAccessFile({}):", filename, ex);
    146                }
    147                return false;
    148            }
    149
    150            is_fits = true;;
    151        }
    152
    153        try {
    154            raf.close();
    155        }
    156        catch (Exception ex) {
    157            log.debug("closing RandomAccessFile({}):", filename, ex);
    158        }
    159
    160        return is_fits;
    161    }
    162
    163
    164    /**
    165     * Creates a FitsFile instance with specified file name and READ access.
    166     * <p>
    167     * @param filename the full path name of the file.
    168     * @param access the access properties of the file.
    169     * Regardless of specified access, the FitsFile implementation uses* READ.
    170     */
    171    @Override
    172    public FileFormat createInstance(String filename, int access)
    173                              throws Exception {
    174        return new FitsFile(filename);
    175    }
    176
    177
    178    // Implementing FileFormat
    179    @Override
    180    public long open() throws Exception {
    181        if (!isFileOpen) {
    182            isFileOpen = true;
    183            rootObject = loadTree();
    184        }
    185
    186        return 0;
    187    }
    188
    189    private HObject loadTree() {
    190
    191        long[] oid = {0};
    192        // root object does not have a parent path or a parent node
    193        FitsGroup rootGroup = new FitsGroup(this, "/", null, null, oid);
    194
    195        if (fitsFile == null) {
    196            return rootGroup;
    197        }
    198
    199        BasicHDU[] hdus = null;
    200
    201        try {
    202            hdus = fitsFile.read();
    203        }
    204        catch (Exception ex) {
    205            log.debug("fitsFile.read():", ex);
    206        }
    207
    208        if (hdus == null) {
    209            return rootGroup;
    210        }
    211
    212        int n = hdus.length;
    213        int nImageHDU = 0;
    214        int nTableHDU =  0;
    215        String hduName = null;
    216        BasicHDU hdu = null;
    217        for (int i=0; i<n; i++) {
    218            hdu = hdus[i];
    219            hduName = null;
    220            // only deal with ImageHDU and TableHDU
    221            if (hdu instanceof ImageHDU) {
    222                hduName = "ImageHDU #"+nImageHDU++;
    223            }
    224            else if (hdu instanceof RandomGroupsHDU) {
    225                hduName = "RandomGroupsHDU #"+nImageHDU++;
    226            }
    227            else if (hdu instanceof TableHDU) {
    228                if (hdu instanceof AsciiTableHDU) {
    229                    hduName = "AsciiTableHDU #"+nTableHDU++;
    230                }
    231                else if (hdu instanceof BinaryTableHDU) {
    232                    hduName = "BinaryTableHDU #"+nTableHDU++;
    233                }
    234                else {
    235                    hduName = "TableHDU #"+nTableHDU++;
    236                }
    237            }
    238
    239            if (hduName != null) {
    240                oid[0] = hdu.hashCode();
    241                FitsDataset d =  new FitsDataset(this, hdu, hduName, oid);
    242                rootGroup.addToMemberList(d);
    243            }
    244        }
    245
    246        return rootGroup;
    247    }
    248
    249    // Implementing FileFormat
    250    @Override
    251    public void close() throws IOException {
    252        if (fitsFile == null) {
    253            return;
    254        }
    255
    256        DataInput di = fitsFile.getStream();
    257        if (di instanceof InputStream) {
    258            ((InputStream)di).close();
    259        }
    260    }
    261
    262    // Implementing FileFormat
    263    @Override
    264    public HObject getRootObject() {
    265        return rootObject;
    266    }
    267
    268    public Fits getFitsFile() {
    269        return fitsFile;
    270    }
    271
    272    // implementign FileFormat
    273    @Override
    274    public Group createGroup(String name, Group pgroup) throws Exception {
    275        throw new UnsupportedOperationException("Unsupported createGroup operation for Fits.");
    276    }
    277
    278    // implementign FileFormat
    279    @Override
    280    public Datatype createDatatype(int tclass, int tsize, int torder, int tsign) throws Exception {
    281        throw new UnsupportedOperationException("Unsupported createDatatype operation for Fits.");
    282    }
    283
    284    // implementign FileFormat
    285    @Override
    286    public Datatype createNamedDatatype(Datatype tnative, String name) throws Exception {
    287        throw new UnsupportedOperationException("Fits does not support named datatype.");
    288    }
    289
    290    // implementign FileFormat
    291    @Override
    292    public Dataset createScalarDS(String name, Group pgroup, Datatype type,
    293            long[] dims, long[] maxdims, long[] chunks,
    294            int gzip, Object fillValue, Object data) throws Exception {
    295        throw new UnsupportedOperationException("Unsupported createScalarDS operation.");
    296    }
    297
    298    // implementign FileFormat
    299    @Override
    300    public Dataset createImage(String name, Group pgroup, Datatype type,
    301            long[] dims, long[] maxdims, long[] chunks,
    302            int gzip, int ncomp, int intelace, Object data) throws Exception {
    303        throw new UnsupportedOperationException("Unsupported createImage operation.");
    304    }
    305
    306    // implementing FileFormat
    307    @Override
    308    public void delete(HObject obj) throws Exception {
    309        throw new UnsupportedOperationException("Unsupported delete operation.");
    310    }
    311
    312    // implementing FileFormat
    313    @Override
    314    public HObject copy(HObject srcObj, Group dstGroup, String dstName) throws Exception {
    315        throw new UnsupportedOperationException("Unsupported copy operation.");
    316    }
    317
    318    /** copy a dataset into another group.
    319     * @param srcDataset the dataset to be copied.
    320     * @param pgroup the group where the dataset is copied to.
    321     * @return the treeNode containing the new copy of the dataset.
    322     */
    323    private void copyDataset(Dataset srcDataset, FitsGroup pgroup) throws Exception {
    324        throw new UnsupportedOperationException("Unsupported copyDataset operation.");
    325    }
    326
    327    private void copyGroup(FitsGroup srcGroup, FitsGroup pgroup) throws Exception {
    328        throw new UnsupportedOperationException("Unsupported copyGroup operation.");
    329    }
    330
    331    /*
    332     * Copy attributes of the source object to the destination object.
    333     */
    334    public void copyAttributes(HObject src, HObject dst) {
    335        throw new UnsupportedOperationException("Unsupported copyAttributes operation.");
    336    }
    337
    338    /*
    339     * Copy attributes of the source object to the destination object.
    340     */
    341    public void copyAttributes(long srcID, long dstID) {
    342        throw new UnsupportedOperationException("Unsupported copyAttributes with id operation.");
    343    }
    344
    345    /**
    346     * Creates a new attribute and attached to the object if attribute does
    347     * not exist. Otherwise, just update the value of the attribute.
    348     *
    349     * <p>
    350     * @param obj the object which the attribute is to be attached to.
    351     * @param attr the atribute to attach.
    352     * @param attrExisted The indicator if the given attribute exists.
    353     */
    354    @Override
    355    public void writeAttribute(HObject obj, hdf.object.Attribute attr, boolean attrExisted) throws Exception {
    356        throw new UnsupportedOperationException("Unsupported operation.");
    357    }
    358
    359    /**
    360     *  Returns the version of the library.
    361     */
    362    @Override
    363    public String getLibversion()
    364    {
    365        String ver = "Fits Java (version 2.4)";
    366
    367        return ver;
    368    }
    369
    370    // implementing FileFormat
    371    @Override
    372    public HObject get(String path) throws Exception
    373    {
    374        throw new UnsupportedOperationException("get() is not supported");
    375    }
    376}
    377