001    /* @(#)FitsHDUnit.java     $Revision: 1.7 $    $Date: 2002/02/28 09:20:28 $
002     *
003     * Copyright (C) 202 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    /** FitsHDUnit class represents a FITS header plus a FITS data unit
013     *
014     *  @version $Revision: 1.7 $ $Date: 2002/02/28 09:20:28 $
015     *  @author  P.Grosbol, DMD/ESO, <pgrosbol@eso.org>
016     */
017    public class FitsHDUnit {
018    
019        private FitsHeader header;
020        private FitsData data;
021        // changeHeader flag set by FitsMatrix, FitsTable or FitsRGroup constructors to indicate more headers after data
022        private boolean changeHeader = false;  
023        private long headerOffset = 0;
024        private RandomAccessFile headerFile = null;
025    
026        /** Constructor for FitsHDUnit class given a FITS stream and a internal
027         *  storage flag.
028         *
029         *  @param file    DataInput file positioned at the start of the
030         *                 header/data unit
031         *  @param sflag   Flag for storing data matrix internally
032         *  @exception FitsException */
033        public FitsHDUnit(DataInput file, boolean sflag) throws FitsException {
034            if (file instanceof RandomAccessFile) {
035                headerFile = (RandomAccessFile) file;
036                try {
037                    headerOffset = headerFile.getFilePointer();
038                } catch (IOException e) {
039                    throw new FitsException("Cannot read header offset",FitsException.FILE);
040                }
041            }
042    
043            header = new FitsHeader(file);
044            int type = header.getType();
045            switch (type) {
046            case Fits.IMAGE:
047                data = new FitsMatrix(header, file, sflag);
048                break;
049            case Fits.BTABLE:
050            case Fits.ATABLE:
051                data = new FitsTable(header, file, sflag);
052                break;
053            case Fits.RGROUP:
054                data = new FitsRGroup(header, file, sflag);
055                break;
056            }
057            changeHeader = false;
058        }
059    
060        /** Constructor from individual header and data objects.
061         *
062         *  @param header new FitsHeader object to used
063         *  @param data   new FitsData object associated to header
064         *  @exception FitsException  */
065        public FitsHDUnit(FitsHeader header, FitsData data) throws FitsException {
066            this.header = header;
067            this.data = data;
068            changeHeader = true;
069        }
070    
071        /**  Get the type of Header/Data unit as indicated by its header. */
072        public int getType(){
073            return header.getType();
074        }
075    
076        /** Check if HD unit can be save to FITS file in place that is
077         *  a FITS file exists and has space enough.
078         */
079        public boolean canSave() {
080            if (changeHeader || (headerFile==null)) {
081                return false;
082            }
083    
084            int nfill = header.getHeaderSpace() - header.getNoKeywords() - 1;
085            if (nfill<0) {
086                return false;
087            }
088            return true;
089        }
090    
091        /** Save changes of a HD unit to FITS file.  The HDunit must have
092         *  been created from a read/write RandomAccess disk file.
093         *  There are no check for the consistence of Header and Data.
094         *
095         *  @exception IOException, FitsException */
096        protected void saveFile(RandomAccessFile file)
097            throws IOException, FitsException {
098            if (changeHeader) {
099                throw new FitsException("HD unit modified", FitsException.FILE);
100            }
101            if (headerFile == null) {
102                throw new FitsException("No header file", FitsException.FILE);
103            }
104    
105            int nfill = header.getHeaderSpace() - header.getNoKeywords() - 1;
106    
107            if (nfill<0) {
108                throw new FitsException("No space in FITS header",FitsException.NOHEADERSPACE);
109            }
110    
111            file.seek(headerOffset);
112            file.write((header.toString()).getBytes());  // Write the header
113            while (0<nfill--) file.write(Fits.BLANK_CARD.getBytes());
114            file.write(Fits.END_CARD.getBytes());
115        }
116    
117        /** Write FITS header/Data unit to a DataOutput stream.
118         *
119         *  @param  file  DataOutput object to which to write
120         *  @exception IOException, FitsException */
121        public void writeFile(DataOutput file) throws IOException, FitsException {
122            int nokw = header.getNoKeywords();
123            if (nokw<2) {
124                throw new FitsException("Bad FITS header",FitsException.HEADER);
125            }
126    
127            file.write((header.toString()).getBytes());  // Write the header
128    
129            // Add BLANK-cards and the final END-card to fill the FITS record
130    
131            int nfill = Fits.NOCARDS*(nokw/Fits.NOCARDS + 1) - nokw - 1;
132            while (0<nfill--) file.write(Fits.BLANK_CARD.getBytes());
133            file.write(Fits.END_CARD.getBytes());
134    
135            data.writeFile(file);
136        }
137    
138        /** Remove all references to the DataInput file from data unit  */
139        public void closeFile() {
140            headerFile = null;
141            data.closeFile();
142        }
143      
144        /**  Return the FitsData object in the Header/Data unit */
145        public FitsData getData(){
146            return data;
147        }
148    
149        /**  Return the header object in the Header/Data unit */
150        public FitsHeader getHeader(){
151            return header;
152        }
153    }