/* @(#)FitsHeader.java $Revision: 1.12 $ $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.*; /** FITS Header class which is an ordered set of FitsKeywords. * * @version $Revision: 1.12 $ $Date: 2005/09/16 09:58:10 $ * @author P.Grosbol, ESO, <pgrosbol@eso.org> */ public class FitsHeader { private Vector keywords = null; private Hashtable kwHash; private Hashtable commentHash; private int headerSpace = 0; /** Default constructor for empty FitsHeader class */ public FitsHeader() { keywords = new Vector(Fits.NOCARDS, Fits.NOCARDS); kwHash = new Hashtable(); commentHash = new Hashtable(); } /** Constructor for FitsHeader class given a DataInput file * positioned at the FITS header. * * @param file RandomAccess file positioned at the start of a * FITS header * @exception FitsException */ public FitsHeader(DataInput file) throws FitsException { byte record[] = new byte[Fits.RECORD]; byte line[] = new byte[Fits.CARD]; FitsKeyword kw; try { // check if FITS format file.readFully(record, 0, Fits.RECORD); kw = new FitsKeyword(record); if (!kw.getName().equals("SIMPLE") && !kw.getName().equals("XTENSION")) { throw new FitsException("Not Standard records", FitsException.HEADER); } } catch (IOException e) { throw new FitsException("No more data", FitsException.HEADER); } catch (FitsException e) { throw new FitsException("", FitsException.HEADER); } int no_kw = 1; keywords = new Vector(Fits.NOCARDS, Fits.NOCARDS); no_kw = 0; try { int n = 0; while (true) { for (int k=0; k<Fits.CARD; k++) { line[k] = record[n++]; } kw = new FitsKeyword(line); keywords.setSize(no_kw++); keywords.addElement(kw); if (Fits.RECORD <= n) { file.readFully(record, 0, Fits.RECORD); n = 0; } } } catch (IOException e) { throw new FitsException("Cannot read header", FitsException.HEADER); } catch (FitsException e) { if (e.getType() != FitsException.ENDCARD) { throw new FitsException("Bad FITS keyword:"+e, FitsException.HEADER); } } int idx = keywords.size() - 1; // remove trailing empty keywords while (((FitsKeyword)keywords.elementAt(idx)).isEmpty()) { keywords.removeElementAt(idx--); } keywords.trimToSize(); headerSpace = (1+no_kw/Fits.NOCARDS)*Fits.NOCARDS; kwHash = new Hashtable(keywords.size()); commentHash = new Hashtable(); Enumeration list = keywords.elements(); while (list.hasMoreElements()) { kw = (FitsKeyword) list.nextElement(); hashKeyword(kw); } } /** Append FITS keyword to the end of the header. * * @param kw FitsKeyword to be appended */ public void addKeyword(FitsKeyword kw){ if (kw == null) return; keywords.addElement(kw); hashKeyword(kw); } /** Insert FITS keyword at a given position in the header. * * @param kw FitsKeyword to be appended * @param index place where the keyword should be inserted */ public void insertKeywordAt(FitsKeyword kw, int index){ if (kw == null) { return; } keywords.insertElementAt(kw, index); hashKeyword(kw); } /** Remove FITS keyword at a given position in the header. * * @param index location of keyword which should be removed */ public void removeKeywordAt(int index) { FitsKeyword kw = (FitsKeyword) keywords.elementAt(index); if (kw==null) { return; } kwHash.remove(kw.getName()); keywords.removeElementAt(index); } /** Add keyword to internal hash tables. * * @param kw FitsKeyword to be hashed */ private void hashKeyword(FitsKeyword kw){ if (kw == null) { return; } if (kw.getType() == FitsKeyword.COMMENT) { Vector vec = (Vector) commentHash.get(kw.getName()); if (vec == null) { vec = new Vector(); commentHash.put(kw.getName(), vec); } vec.addElement(kw); } else { kwHash.put(kw.getName(), kw); } } /** Return the type of the FITS header e.g. Fits.IMAGE or Fits.BTABLE. */ final public int getType(){ if (keywords.size()<3) { return Fits.FALSE; } int type = Fits.FALSE; FitsKeyword kw = (FitsKeyword) keywords.elementAt(0); if (kw.getName().equals("SIMPLE") && kw.getBool()) { kw = (FitsKeyword) kwHash.get("NAXIS1"); if ((kw != null) && (kw.getInt() == 0)) { kw = (FitsKeyword) kwHash.get("GROUPS"); type = (((kw != null) && kw.getBool())) ? Fits.RGROUP : Fits.IMAGE; } else { type = Fits.IMAGE; } } else if (kw.getName().equals("XTENSION")) { if (kw.getString().startsWith("IMAGE")) { type = Fits.IMAGE; } else if (kw.getString().startsWith("BINTABLE")) { type = Fits.BTABLE; } else if (kw.getString().startsWith("TABLE")) { type = Fits.ATABLE; } else { type = Fits.UNKNOWN; } } return type; } /** Compute size of FITS data matrix in bytes */ final public long getDataSize(){ if (kwHash == null) { return 0; } int type = getType(); FitsKeyword kw; kw = (FitsKeyword) kwHash.get("NAXIS"); // get no. of axes long naxis = kw.getInt(); if (naxis < 1) { return 0; } kw = (FitsKeyword) kwHash.get("BITPIX"); // get no. of bytes per value long n_byte = Math.abs(kw.getInt())/8; long d_size = 1; for (int n=1; n<=naxis; n++) { if (type==Fits.RGROUP && n==1) continue; kw = (FitsKeyword) kwHash.get("NAXIS" + n); d_size *= kw.getInt(); } kw = (FitsKeyword) kwHash.get("PCOUNT"); // add parameter block size if (kw != null) { d_size += kw.getInt(); } kw = (FitsKeyword) kwHash.get("GCOUNT"); // multiple with group count if (kw != null) { d_size *= kw.getInt(); } d_size *= n_byte; return d_size; } /** Get name of FITS HUunit as given by the EXTNAME keyword. If * this keyword is not present in the header, 'NONE' is returned. */ final public String getName(){ FitsKeyword kw = (FitsKeyword) kwHash.get("EXTNAME"); if ((kw == null) || (kw.getType() != FitsKeyword.STRING)) { return "NONE"; } return kw.getString(); } /** Get version of FITS HUunit as given by the EXTVER keyword. If * this keyword is not present in the header 1 is returned. */ final public int getVersion(){ FitsKeyword kw = (FitsKeyword) kwHash.get("EXTVER"); if ((kw == null) || (kw.getType() != FitsKeyword.INTEGER)) { return 1; } return (int) kw.getInt(); } /** Obtain the total number of keywords in the header. */ final public int getNoKeywords(){ return keywords.size(); } /** Return a keyword giving its relative position. If the position * is not in the valid range a NULL is returned. * * @param no position of keyword in header (starting with 0) */ final public FitsKeyword getKeyword(int no){ if ((no < 0) || (keywords.size() <= no)) { return (FitsKeyword) null; } return (FitsKeyword) keywords.elementAt(no); } /** Return a keyword giving its name. If there a multiple keywords, * the last is returned. In cases where multiple keywords makes * sense (e.g. comments), the first of this set is given. If none * is found, a NULL is returned. * * @param name string with name of keyword */ final public FitsKeyword getKeyword(String name){ FitsKeyword kw = (FitsKeyword) kwHash.get(name); if (kw == null) { Vector vec = (Vector) commentHash.get(name); if (vec != null) { kw = (FitsKeyword) vec.firstElement(); } } return kw; } /** Return an array of keywords giving a name. If none * is found, a NULL is returned. * * @param name string with name of keyword */ final public FitsKeyword[] getKeywords(String name){ FitsKeyword kw = (FitsKeyword) kwHash.get(name); if (kw == null) { Vector vec = (Vector) commentHash.get(name); if (vec == null) { return null; } FitsKeyword setKw[] = new FitsKeyword[vec.size()]; for (int n=0; n<vec.size(); n++) { setKw[n] = (FitsKeyword) vec.elementAt(n); } return setKw; } FitsKeyword setKw[] = new FitsKeyword[1]; setKw[0] = kw; return setKw; } /** Obtain an Enumeration object for the keywords in the header. */ final public Enumeration getKeywords(){ return keywords.elements(); } /** Generate a string with the FITS header. The header string will * include the END-card and NOT be space filled with empty cards to * a full FITS 2880 char record. */ public String toString(){ int size = keywords.size(); StringBuffer hd = new StringBuffer(Fits.CARD*size); Enumeration itr = keywords.elements(); while (itr.hasMoreElements()) { FitsKeyword kw = (FitsKeyword) itr.nextElement(); hd.append(kw.toString()); } return hd.toString(); } /** Get space in FITS header read from file in terms of number of * keyword cards to can contain. */ public int getHeaderSpace(){ return headerSpace; } /** Sets the first keyword in the header to XTENSION with the * type indicated. Nothing will be done if a non-standard * extension is specified. * * @param type Type of FITS extension */ public void setExtension(int type) { FitsKeyword kw; switch (type) { case Fits.IMAGE : kw = new FitsKeyword("XTENSION", "IMAGE", "Image extension"); break; case Fits.BTABLE : kw = new FitsKeyword("XTENSION", "BINTABLE", "Binary table extension"); break; case Fits.ATABLE : kw = new FitsKeyword("XTENSION", "TABLE", "ASCII table extension"); break; default: return; } removeKeywordAt(0); insertKeywordAt(kw, 0); } }