/***************************************************************************
* GFitsHDU.cpp - FITS HDU handling class *
* ----------------------------------------------------------------------- *
* copyright (C) 2008-2014 by Juergen Knoedlseder *
* ----------------------------------------------------------------------- *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see . *
* *
***************************************************************************/
/**
* @file GFitsHDU.cpp
* @brief GFitsHDU class implementation.
* @author Juergen Knoedlseder
*/
/* __ Includes ___________________________________________________________ */
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include "GException.hpp"
#include "GTools.hpp"
#include "GFitsCfitsio.hpp"
#include "GFits.hpp"
#include "GFitsHDU.hpp"
#include "GFitsHeaderCard.hpp"
#include "GTools.hpp"
/* __ Method name definitions ____________________________________________ */
#define G_OPEN "GFitsHDU::open(int)"
#define G_SAVE "GFitsHDU::save()"
#define G_HEADER "GFitsHDU::header()"
#define G_DATA "GFitsHDU::data()"
#define G_COLUMN "GFitsHDU::column(std::string&)"
#define G_CONNECT "GFitsHDU::connect(void*)"
#define G_MOVE_TO_HDU "GFitsHDU::move_to_hdu()"
#define G_GET_HDU_TYPE "GFitsHDU::get_hdu_type()"
#define G_NEW_IMAGE "GFitsHDU::new_image()"
/* __ Definitions ________________________________________________________ */
#define DEBUG 0
/* __ Macros _____________________________________________________________ */
/* __ Coding definitions _________________________________________________ */
/* __ Debug definitions __________________________________________________ */
/*==========================================================================
= =
= Constructors/destructors =
= =
==========================================================================*/
/***********************************************************************//**
* @brief Void constructor
***************************************************************************/
GFitsHDU::GFitsHDU(void)
{
// Initialise class members for clean destruction
init_members();
// Return
return;
}
/***********************************************************************//**
* @brief Copy constructor
*
* @param[in] hdu HDU from which the instance should be constructed.
***************************************************************************/
GFitsHDU::GFitsHDU(const GFitsHDU& hdu)
{
// Initialise class members for clean destruction
init_members();
// Copy members
copy_members(hdu);
// Return
return;
}
/***********************************************************************//**
* @brief Destructor
***************************************************************************/
GFitsHDU::~GFitsHDU(void)
{
// Free members
free_members();
// Return
return;
}
/*==========================================================================
= =
= Operators =
= =
==========================================================================*/
/***********************************************************************//**
* @brief Assignment operator
*
* @param[in] hdu HDU which should be assigned.
***************************************************************************/
GFitsHDU& GFitsHDU::operator= (const GFitsHDU& hdu)
{
// Execute only if object is not identical
if (this != &hdu) {
// Free members
free_members();
// Initialise private members for clean destruction
init_members();
// Copy members
copy_members(hdu);
} // endif: object was not identical
// Return this object
return *this;
}
/*==========================================================================
= =
= Public methods =
= =
==========================================================================*/
/***********************************************************************//**
* @brief Set HDU extension name (EXTNAME keyword)
*
* @param[in] extname Name of HDU.
*
* This method sets the extension name of the HDU. The extension name will
* be saved in the 'EXTNAME' header keyword. The header attached to the
* HDU will be automatically updated by this method.
***************************************************************************/
void GFitsHDU::extname(const std::string& extname)
{
// Set extension name
m_name = extname;
// If no header exists then create one now
//if (m_header == NULL) m_header = new GFitsHeader();
// Update header
m_header.append(GFitsHeaderCard("EXTNAME", extname,
"name of this extension"));
// Return
return;
}
/*==========================================================================
= =
= Protected methods =
= =
==========================================================================*/
/***********************************************************************//**
* @brief Connect HDU to FITS file
*
* @param[in] vptr FITS file pointer.
*
* Connects the HDU to the file specified by the FITS file pointer. Sets
* also the HDU number (or extension number, starting from 0). This method
* does nothing if the file pointer in not valid.
***************************************************************************/
void GFitsHDU::connect(void* vptr)
{
// Continue only if file pointer is valid
if (vptr != NULL) {
// Connect HDU by copying the file pointer
FPTR_COPY(m_fitsfile, vptr);
// Extract HDU number from file pointer
m_hdunum = FPTR(m_fitsfile)->HDUposition;
// Connect data
data_connect(vptr);
} // endif: file pointer was valid
// Return
return;
}
/***********************************************************************//**
* @brief Move FITS file pointer to HDU
*
* @exception GException::fits_file_not_open
* No FITS file has been opened.
*
* Moves to FITS file pointer to the actual HDU. This operation should
* preceed any FITS file manipulation.
***************************************************************************/
void GFitsHDU::move_to_hdu(void)
{
// Throw an exception if FITS file is not open
if (FPTR(m_fitsfile)->Fptr == NULL) {
throw GException::fits_file_not_open(G_MOVE_TO_HDU,
"Open file before moving file pointer to HDU.");
}
// Move to HDU
gammalib::fits_move_to_hdu(G_MOVE_TO_HDU, m_fitsfile, m_hdunum+1);
// Return
return;
}
/***********************************************************************//**
* @brief Get HDU type from FITS file
*
* @exception GException::fits_file_not_open
* No FITS file has been opened.
* @exception GException::fits_hdu_not_found
* Requested HDU not found.
***************************************************************************/
GFitsHDU::HDUType GFitsHDU::get_hdu_type(void) const
{
// Initialise HDU type
int type = 0;
// Throw an exception if FITS file is not open
if (FPTR(m_fitsfile)->Fptr == NULL) {
throw GException::fits_file_not_open(G_GET_HDU_TYPE,
"Open file before requesting HDU type.");
}
// Get HDU type
int status = 0;
status = __ffghdt(FPTR(m_fitsfile), &type, &status);
if (status != 0) {
throw GException::fits_error(G_GET_HDU_TYPE, status);
}
// Return HDU type
return (HDUType)type;
}
/***********************************************************************//**
* @brief Open HDU
*
* @param[in] vptr FITS file pointer.
* @param[in] hdunum Number of HDU (starting from 0).
*
* @exception GException::fits_file_not_open
* FITS file pointer does not point to an open FITS file
* @exception GException::fits_error
* Unable to open FITS HDU.
*
* Opens an (existing) HDU in the FITS file. This method does NOT create any
* HDU if it does not exist. Opening consists of fetching all header cards
* (by opening an associated GFitsHeader instance) and of opening the data
* area (which can be of type Image or Table)
***************************************************************************/
void GFitsHDU::open(void* vptr, int hdunum)
{
// Verify that FITS file pointer is valid
if (vptr == NULL) {
throw GException::fits_file_not_open(G_OPEN,
"FITS file pointer does not point to an open FITS file.");
}
// Move to HDU
gammalib::fits_move_to_hdu(G_OPEN, vptr, hdunum+1);
// Save the FITS file pointer and the HDU number
FPTR_COPY(m_fitsfile, vptr);
m_hdunum = hdunum;
// Load HDU header
m_header.load(FPTR(m_fitsfile));
// Open HDU data area
data_open(FPTR(m_fitsfile));
// Get HDU name from header. If no name was found and this is the primary
// HDU then set the name to "Primary", otherwise to "NoName".
if (m_header.contains("EXTNAME")) {
m_name = gammalib::strip_whitespace(m_header.string("EXTNAME"));
}
else {
m_name.clear();
}
if (m_name.length() == 0) {
if (hdunum == 0) {
m_name = "Primary";
}
else {
m_name = "NoName";
}
}
// Return
return;
}
/***********************************************************************//**
* @brief Saves HDU
*
* Save the HDU to the FITS file. In case that the HDU does not exist in the
* file it will be created (by the save_data() method). In the special case
* that no first HDU exists, an empty primary image is created.
*
* @todo Put the m_header.save(FPTR(m_fitsfile)) call in the data_save()
* methods
***************************************************************************/
void GFitsHDU::save(void)
{
// Debug header
#if DEBUG
std::cout << "GFitsHDU::save() -->" << std::endl;
#endif
// Save data. This method allows saving past the file and will
// physically append a new HDU to a FITS file. It has to be called
// before the saving of the header cards, since header card
// saving requires the HDU to exist in the FITS file.
data_save();
// Save header cards (assumes implicitely that the HDU exists in
// FITS file)
m_header.save(FPTR(m_fitsfile));
// Debug trailer
#if DEBUG
std::cout << "<-- GFitsHDU::save" << std::endl;
#endif
// Return
return;
}
/***********************************************************************//**
* @brief Print basic HDU information
*
* @param[in] chatter Chattiness (defaults to NORMAL).
* @return String containing basic HDU information.
***************************************************************************/
std::string GFitsHDU::print_hdu(const GChatter& chatter) const
{
// Initialise result string
std::string result;
// Continue only if chatter is not silent
if (chatter != SILENT) {
// Append HDU information
result.append(gammalib::parformat("HDU number"));
result.append(gammalib::str(m_hdunum)+"\n");
result.append(gammalib::parformat("HDU name")+m_name);
} // endif: chatter was not silent
// Return result
return result;
}
/***********************************************************************//**
* @brief Return typecode as string
*
* @param[in] type Type code.
***************************************************************************/
std::string GFitsHDU::typecode(int type) const
{
// Allocate string
std::string result;
// Set typecode
switch (type) {
case __TBIT:
result = "bit";
break;
case __TBYTE:
result = "unsigned byte";
break;
case __TSBYTE:
result = "signed byte";
break;
case __TLOGICAL:
result = "boolean";
break;
case __TSTRING:
result = "string";
break;
case __TUSHORT:
result = "unsigned short integer";
break;
case __TSHORT:
result = "short integer";
break;
case __TULONG:
result = "unsigned long integer";
break;
case __TLONG:
result = "long integer";
break;
case __TFLOAT:
result = "single precision floating point";
break;
case __TLONGLONG:
result = "long long integer";
break;
case __TDOUBLE:
result = "double precision floating point";
break;
default:
result = "unsupported format";
break;
}
// Return result
return result;
}
/*==========================================================================
= =
= Private methods =
= =
==========================================================================*/
/***********************************************************************//**
* @brief Initialise class members
*
* Sets all class members to well defined values.
***************************************************************************/
void GFitsHDU::init_members(void)
{
// Allocate FITS file pointer. As the pointer is of type void the C-style
// memory allocation function malloc is used as this function does not
// deal with types but always returns a void pointer
m_fitsfile = malloc(sizeof(__fitsfile));
// Initialise FITS file pointer
FPTR(m_fitsfile)->HDUposition = 0;
FPTR(m_fitsfile)->Fptr = NULL;
// Initialise members
m_hdunum = 0;
m_name.clear();
// Return
return;
}
/***********************************************************************//**
* @brief Copy class members
*
* @param[in] hdu HDU to be copied.
*
* Assumes that all memory has been freed correctly before calling.
***************************************************************************/
void GFitsHDU::copy_members(const GFitsHDU& hdu)
{
// Copy members
FPTR_COPY(m_fitsfile, hdu.m_fitsfile);
m_hdunum = hdu.m_hdunum;
m_name = hdu.m_name;
m_header = hdu.m_header;
// Return
return;
}
/***********************************************************************//**
* @brief Delete class members
***************************************************************************/
void GFitsHDU::free_members(void)
{
// Free memory. Note that the malloc function was used for allocation,
// hence the free function needs to be called for freeing.
if (m_fitsfile != NULL) free(m_fitsfile);
// Signal free pointers
m_fitsfile = NULL;
// Return
return;
}