IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 5511 for trunk/psLib/src/fits


Ignore:
Timestamp:
Nov 14, 2005, 12:18:38 PM (20 years ago)
Author:
desonia
Message:

Overhauled the Fits functions to match latest SDRS.

Location:
trunk/psLib/src/fits
Files:
6 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/psLib/src/fits/Makefile.am

    r4981 r5511  
    33noinst_LTLIBRARIES = libpslibfits.la
    44
    5 libpslibfits_la_CPPFLAGS = $(SRCINC) $(CFITSIO_CFLAGS)
     5libpslibfits_la_CFLAGS = $(SRCINC) $(CFITSIO_CFLAGS) $(AM_CFLAGS)
    66libpslibfits_la_SOURCES = \
    7         psFits.c
     7        psFits.c \
     8        psFitsHeader.c \
     9        psFitsImage.c \
     10        psFitsTable.c
    811
    912EXTRA_DIST = fits.i
     
    1114pslibincludedir = $(includedir)
    1215pslibinclude_HEADERS = \
    13         psFits.h
     16        psFits.h \
     17        psFitsHeader.h \
     18        psFitsImage.h \
     19        psFitsTable.h
  • trunk/psLib/src/fits/fits.i

    r4540 r5511  
    11/* fits headers */
    22%include "psFits.h"
     3%include "psFitsHeader.h"
     4%include "psFitsImage.h"
     5%include "psFitsTable.h"
  • trunk/psLib/src/fits/psFits.c

    r5168 r5511  
    77 *  @author Robert DeSonia, MHPCC
    88 *
    9  *  @version $Revision: 1.50 $ $Name: not supported by cvs2svn $
    10  *  @date $Date: 2005-09-28 20:02:46 $
     9 *  @version $Revision: 1.51 $ $Name: not supported by cvs2svn $
     10 *  @date $Date: 2005-11-14 22:18:30 $
    1111 *
    1212 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
     
    2828#define MAX_STRING_LENGTH 256  // maximum length string for FITS routines
    2929
    30 // list of FITS header keys to ignore.
    31 static char* standardFitsKeys[] = {
    32                                       NULL
    33                                   };
    34 
    35 static psElemType convertFitsToPsType(int datatype)
    36 {
    37     switch (datatype) {
    38     case TBYTE:
    39         return PS_TYPE_U8;
    40     case TSBYTE:
    41         return PS_TYPE_S8;
    42     case TSHORT:
    43         return PS_TYPE_S16;
    44     case TUSHORT:
    45         return PS_TYPE_U16;
    46     case TLONG:
    47         if (sizeof(long) == 8) {
    48             return PS_TYPE_S64;
    49         }
    50         // no break
    51     case TINT:
    52         return PS_TYPE_S32;
    53     case TULONG:
    54         if (sizeof(unsigned long) == 8) {
    55             return PS_TYPE_U64;
    56         }
    57         // no break
    58     case TUINT:
    59         return PS_TYPE_U32;
    60     case TLONGLONG:
    61         return PS_TYPE_S64;
    62     case TFLOAT:
    63         return PS_TYPE_F32;
    64     case TDOUBLE:
    65         return PS_TYPE_F64;
    66     case TCOMPLEX:
    67         return PS_TYPE_C32;
    68     case TDBLCOMPLEX:
    69         return PS_TYPE_C64;
    70     case TLOGICAL:
    71         return PS_TYPE_BOOL;
    72     default:
    73         psError(PS_ERR_IO, true,
    74                 "Unknown FITS datatype, %d.",
    75                 datatype);
    76         return 0;
    77     }
    78 }
    79 
    80 static bool convertPsTypeToFits(int type, int* bitPix, double* bZero, int* dataType)
    81 {
    82 
    83     int bitpix;
    84     int datatype;
    85     double bzero = 0.0;
    86 
    87     switch (type) {
    88 
    89     case PS_TYPE_U8:
    90         bitpix = BYTE_IMG;
    91         datatype = TBYTE;
    92         break;
    93 
    94     case PS_TYPE_S8:
    95         bitpix = BYTE_IMG;
    96         bzero = INT8_MIN;
    97         datatype = TSBYTE;
    98         break;
    99 
    100     case PS_TYPE_U16:
    101         bitpix = SHORT_IMG;
    102         bzero = -1.0 * INT16_MIN;
    103         datatype = TUSHORT;
    104         break;
    105 
    106     case PS_TYPE_S16:
    107         bitpix = SHORT_IMG;
    108         datatype = TSHORT;
    109         break;
    110 
    111     case PS_TYPE_U32:
    112         bitpix = LONG_IMG;
    113         bzero = -1.0 * INT32_MIN;
    114         datatype = TUINT;
    115         break;
    116 
    117     case PS_TYPE_S32:
    118         bitpix = LONG_IMG;
    119         datatype = TINT;
    120         break;
    121 
    122     case PS_TYPE_F32:
    123         bitpix = FLOAT_IMG;
    124         datatype = TFLOAT;
    125         break;
    126 
    127     case PS_TYPE_F64:
    128         bitpix = DOUBLE_IMG;
    129         datatype = TDOUBLE;
    130         break;
    131 
    132     case PS_DATA_STRING:
    133         bitpix = BYTE_IMG;
    134         datatype = TSTRING;
    135         break;
    136 
    137     case PS_DATA_BOOL:
    138         bitpix = BYTE_IMG;
    139         datatype = TLOGICAL;
    140         break;
    141 
    142     default: {
    143             char* typeStr;
    144             PS_TYPE_NAME(typeStr,type);
    145             psError(PS_ERR_BAD_PARAMETER_TYPE, true,
    146                     PS_ERRORTEXT_psFits_TYPE_UNSUPPORTED,
    147                     typeStr);
    148             return false;
    149         }
    150     }
    151 
    152     // pass the requested parameters  (NULL parameters are not set, of course).
    153     if (bitPix != NULL) {
    154         *bitPix = bitpix;
    155     }
    156 
    157     if (dataType != NULL) {
    158         *dataType = datatype;
    159     }
    160 
    161     if (bZero != NULL) {
    162         *bZero = bzero;
    163     }
    164 
    165     return true;
    166 }
    167 
    168 static char getTForm(int type)
    169 {
    170     switch (type) {
    171     case PS_TYPE_U8:
    172     case PS_TYPE_S8:
    173         return 'B';
    174     case PS_TYPE_S16:
    175         return 'I';
    176     case PS_TYPE_S32:
    177         return 'J';
    178     case PS_TYPE_U64:
    179     case PS_TYPE_S64:
    180         return 'K';
    181     case PS_TYPE_U16:
    182         return 'U';
    183     case PS_TYPE_U32:
    184         return 'V';
    185     case PS_TYPE_F32:
    186         return 'E';
    187     case PS_TYPE_F64:
    188         return 'D';
    189     case PS_TYPE_C32:
    190         return 'C';
    191     case PS_TYPE_C64:
    192         return 'M';
    193     case PS_TYPE_BOOL:
    194         return 'L';
    195     case PS_DATA_STRING:
    196         return 'A';
    197     default:
    198         return '?';
    199     }
    200 }
    201 
    202 
    203 static bool getMetadataTForm(psMetadataItem* item, char** fitsType, int repeat)
    204 {
    205     if (item == NULL) {
    206         return false;
    207     }
    208 
    209     *fitsType = NULL;
    210     char tform = getTForm(item->type);
    211 
    212     switch (item->type) {
    213     case PS_TYPE_U8:
    214     case PS_TYPE_S8:
    215     case PS_TYPE_S16:
    216     case PS_TYPE_S32:
    217     case PS_TYPE_U64:
    218     case PS_TYPE_S64:
    219     case PS_TYPE_U16:
    220     case PS_TYPE_U32:
    221     case PS_TYPE_F32:
    222     case PS_TYPE_F64:
    223     case PS_TYPE_C32:
    224     case PS_TYPE_C64:
    225     case PS_TYPE_BOOL:
    226         psStringAppend(fitsType, "%d%c",repeat,tform);
    227         break;
    228 
    229     case PS_DATA_STRING:
    230         psStringAppend(fitsType,"%dA",
    231                        strlen(item->data.V)*repeat);
    232         break;
    233 
    234     case PS_DATA_VECTOR: {
    235             psVector* vec = item->data.V;
    236             tform = getTForm(vec->type.type);
    237             psStringAppend(fitsType,"%d%c",repeat*vec->n,tform);
    238         }
    239         break;
    240 
    241     default:
    242         return false;
    243     }
    244 
    245     return true;
    246 }
    247 
    24830static bool isHDUEmpty(const psFits* fits)
    24931{
     
    26446}
    26547
     48static bool fitsClose(psFits* fits)
     49{
     50    int status = 0;
     51
     52    if (fits != NULL) {
     53        if (fits_close_file(fits->fd, &status)) {
     54            char fitsErr[MAX_STRING_LENGTH];
     55            fits_get_errstatus(status, fitsErr);
     56            psError(PS_ERR_IO, true,
     57                    "Error while closing psFits object. CFITSIO error: %s",
     58                    fitsErr);
     59            return false;
     60        }
     61    }
     62
     63    return true;
     64}
     65
    26666static void fitsFree(psFits* fits)
    26767{
    268     int status = 0;
    269 
    270     if (fits != NULL) {
    271         (void)fits_close_file(fits->fd, &status);
    272         psFree(fits->filename);
    273     }
     68    (void)fitsClose(fits);
    27469}
    27570
    276 psFits* psFitsAlloc(const char* name)
    277 {
    278     int status = 0;
    279     fitsfile *fptr = NULL;      /* Pointer to the FITS file */
    280 
    281     if (name == NULL) {
    282         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    283                 PS_ERRORTEXT_psFits_FILENAME_NULL);
    284         return NULL;
    285     }
    286 
    287     /* Open/Create the FITS file */
    288     if (access(name, F_OK) == 0) {     // file exists
    289         (void)fits_open_file(&fptr, name, READWRITE, &status);
    290         if (fptr == NULL) { // if failed, try openning as just read-only
    291             status = 0;
    292             (void)fits_open_file(&fptr, name, READONLY, &status);
    293         }
    294         if (fptr == NULL || status != 0) {
    295             char fitsErr[MAX_STRING_LENGTH];
    296             fits_get_errstatus(status, fitsErr);
    297             psError(PS_ERR_BAD_PARAMETER_VALUE, true,
    298                     PS_ERRORTEXT_psFits_FILENAME_INVALID,
    299                     name, fitsErr);
    300             return NULL;
    301         }
    302     } else {  // file does not exist, so create.
    303         (void)fits_create_file(&fptr, name, &status);
    304         if (fptr == NULL || status != 0) {
    305             char fitsErr[MAX_STRING_LENGTH];
    306             fits_get_errstatus(status, fitsErr);
    307             psError(PS_ERR_IO, true,
    308                     PS_ERRORTEXT_psFits_FILENAME_CREATE_FAILED,
    309                     name, fitsErr);
    310             return NULL;
    311         }
    312     }
    313 
    314     psFits* fits = psAlloc(sizeof(psFits));
    315     fits->filename = psAlloc(strlen(name)+1);
    316     fits->fd = fptr;
    317     strcpy((char*)fits->filename,name);
    318     psMemSetDeallocator(fits,(psFreeFunc)fitsFree);
    319 
    320     return fits;
    321 }
    322 
    323 
    324 bool psMemCheckFits(psPtr ptr)
    325 {
    326     return ( psMemGetDeallocator(ptr) == (psFreeFunc)fitsFree );
    327 }
    328 
    329 
    330 bool psFitsMoveExtName(const psFits* fits,
    331                        const char* extname)
    332 {
    333     int status = 0;
    334 
    335     if (fits == NULL) {
    336         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    337                 PS_ERRORTEXT_psFits_NULL);
    338         return false;
    339     }
    340 
    341     if (extname == NULL) {
    342         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    343                 PS_ERRORTEXT_psFits_EXTNAME_NULL);
    344         return false;
    345     }
    346 
    347 
    348     if (fits_movnam_hdu(fits->fd, ANY_HDU, (char*)extname, 0, &status) != 0) {
    349         char fitsErr[MAX_STRING_LENGTH];
    350         fits_get_errstatus(status, fitsErr);
    351         psError(PS_ERR_LOCATION_INVALID, true,
    352                 PS_ERRORTEXT_psFits_EXTNAME_INVALID,
    353                 extname, fits->filename, fitsErr);
    354         return false;
    355     }
    356 
    357     return true;
    358 }
    359 
    360 bool psFitsMoveExtNum(const psFits* fits,
    361                       int extnum,
    362                       bool relative)
     71bool psFitsClose(psFits* fits)
    36372{
    36473    if (fits == NULL) {
     
    36877    }
    36978
     79    bool status = fitsClose(fits);
     80    psMemSetDeallocator(fits,NULL);
     81    psFree(fits);
     82
     83    return status;
     84}
     85
     86psFits* psFitsOpen(const char* name, const char* mode)
     87{
    37088    int status = 0;
    371     int hdutype = 0;
    372 
    373     if (relative) {
    374         fits_movrel_hdu(fits->fd, extnum, &hdutype, &status);
    375         if (status != 0) {
     89    fitsfile *fptr = NULL;      /* Pointer to the FITS file */
     90
     91    if (name == NULL) {
     92        psError(PS_ERR_BAD_PARAMETER_NULL, true,
     93                PS_ERRORTEXT_psFits_FILENAME_NULL);
     94        return NULL;
     95    }
     96
     97    /* check the mode to determine how to open/create file */
     98    int iomode;
     99    bool newFile;
     100    if (strcmp(mode,"r") == 0) {
     101        iomode = READONLY;
     102        newFile = false;
     103    } else if (strcmp(mode,"rw") == 0 || strcmp(mode,"r+") == 0) {
     104        iomode = READWRITE;
     105        newFile = false;
     106    } else if (strcmp(mode,"w") == 0 || strcmp(mode,"w+") == 0) {
     107        iomode = READWRITE;
     108        newFile = true;
     109    } else if (strcmp(mode,"a") == 0|| strcmp(mode,"a+") == 0) {
     110        iomode = READWRITE;
     111        newFile = (access(name, F_OK) != 0);
     112    } else {
     113        // mode is not valid
     114        psError(PS_ERR_BAD_PARAMETER_VALUE, true,
     115                "Specified mode, '%s', is invalid.  Supported modes are r, r+, rw, w, w+, a, or a+.",
     116                mode);
     117        return NULL;
     118    }
     119
     120    if (newFile) {
     121        /* Check if an existing file is in the way before creating file*/
     122        if (access(name, F_OK) == 0) {
     123            // file exists, delete old one first
     124            remove
     125                (name);
     126        }
     127
     128        #if ( CFITSIO_DISKFILE == 1 )
     129        (void)fits_create_diskfile(
     130            #else
     131            (void)fits_create_file(
     132                #endif
     133                &fptr,
     134                name,
     135                &status);
     136            if (fptr == NULL || status != 0) {
     137            char fitsErr[MAX_STRING_LENGTH]
     138                ;
     139                fits_get_errstatus(status, fitsErr);
     140                psError(PS_ERR_IO, true,
     141                        PS_ERRORTEXT_psFits_FILENAME_CREATE_FAILED,
     142                        name, fitsErr);
     143                return NULL;
     144            }
     145        } else {
     146            #if ( CFITSIO_DISKFILE == 1 )
     147            (void)fits_open_diskfile(
     148                #else
     149                (void)fits_open_file(
     150                    #endif
     151                    &fptr,
     152                    name,
     153                    iomode,
     154                    &status);
     155                if (fptr == NULL || status != 0) {
     156                char fitsErr[MAX_STRING_LENGTH]
     157                    ;
     158                    fits_get_errstatus(status, fitsErr);
     159                    psError(PS_ERR_BAD_PARAMETER_VALUE, true,
     160                            PS_ERRORTEXT_psFits_FILENAME_INVALID,
     161                            name, fitsErr);
     162                    return NULL;
     163                }
     164            }
     165
     166            psFits* fits = psAlloc(sizeof(psFits));
     167        fits->fd = fptr;
     168        psMemSetDeallocator(fits,(psFreeFunc)fitsFree);
     169
     170        return fits;
     171    }
     172
     173    bool psMemCheckFits(psPtr ptr)
     174    {
     175        return ( psMemGetDeallocator(ptr) == (psFreeFunc)fitsFree );
     176    }
     177
     178
     179    bool psFitsMoveExtName(const psFits* fits,
     180                           const char* extname)
     181    {
     182        int status = 0;
     183
     184        if (fits == NULL) {
     185            psError(PS_ERR_BAD_PARAMETER_NULL, true,
     186                    PS_ERRORTEXT_psFits_NULL);
     187            return false;
     188        }
     189
     190        if (extname == NULL) {
     191            psError(PS_ERR_BAD_PARAMETER_NULL, true,
     192                    PS_ERRORTEXT_psFits_EXTNAME_NULL);
     193            return false;
     194        }
     195
     196
     197        if (fits_movnam_hdu(fits->fd, ANY_HDU, (char*)extname, 0, &status) != 0) {
    376198            char fitsErr[MAX_STRING_LENGTH];
    377199            fits_get_errstatus(status, fitsErr);
    378200            psError(PS_ERR_LOCATION_INVALID, true,
    379                     PS_ERRORTEXT_psFits_EXTNUM_REL_MOVE_FAILED,
    380                     extnum, fits->filename, fitsErr);
    381             return false;
    382         }
    383     } else {
    384         fits_movabs_hdu(fits->fd, extnum+1, &hdutype, &status);
    385         if (status != 0) {
    386             char fitsErr[MAX_STRING_LENGTH];
    387             fits_get_errstatus(status, fitsErr);
    388             psError(PS_ERR_LOCATION_INVALID, true,
    389                     PS_ERRORTEXT_psFits_EXTNUM_ABS_MOVE_FAILED,
    390                     extnum, fits->filename, fitsErr);
    391             return false;
    392         }
    393     }
    394 
    395     return true;
    396 }
    397 
    398 int psFitsGetExtNum(const psFits* fits)
    399 {
    400     int hdunum;
    401 
    402     if (fits == NULL) {
    403         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    404                 PS_ERRORTEXT_psFits_NULL);
    405         return PS_FITS_TYPE_NONE;
    406     }
    407 
    408 
    409     return fits_get_hdu_num(fits->fd,&hdunum) - 1;
    410 }
    411 
    412 psString psFitsGetExtName(const psFits* fits)
    413 {
    414     if (fits == NULL) {
    415         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    416                 PS_ERRORTEXT_psFits_NULL);
    417         return NULL;
    418     }
    419 
    420     int status = 0;
    421     char name[MAX_STRING_LENGTH];
    422 
    423     if (fits_read_key_str(fits->fd, "EXTNAME", name, NULL, &status) != 0) {
    424         status = 0;
    425         if (fits_read_key_str(fits->fd, "HDUNAME", name, NULL, &status) != 0) {
    426             int num = psFitsGetExtNum(fits);
    427             snprintf(name, MAX_STRING_LENGTH, "EXT-%3d",num);
    428         }
    429     }
    430     return psStringCopy(name);
    431 }
    432 
    433 bool psFitsSetExtName(psFits* fits, const char* name)
    434 {
    435     if (fits == NULL) {
    436         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    437                 PS_ERRORTEXT_psFits_NULL);
    438         return false;
    439     }
    440 
    441     if (name == NULL) {
    442         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    443                 PS_ERRORTEXT_psFits_EXTNAME_NULL);
    444         return false;
    445     }
    446 
    447     int status = 0;
    448 
    449     if (fits_update_key_str(fits->fd, "EXTNAME", (char*)name, NULL, &status) != 0) {
    450         char fitsErr[MAX_STRING_LENGTH];
    451         (void)fits_get_errstatus(status, fitsErr);
    452         psError(PS_ERR_IO, true,
    453                 PS_ERRORTEXT_psFits_WRITE_FAILED,
    454                 fits->filename, fitsErr);
    455         return false;
    456     }
    457 
    458     return true;
    459 }
    460 
    461 int psFitsGetSize(const psFits* fits)
    462 {
    463     if (fits == NULL) {
    464         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    465                 PS_ERRORTEXT_psFits_NULL);
    466         return 0;
    467     }
    468 
    469     int num = 0;
    470     int status = 0;
    471 
    472     if (fits_get_num_hdus(fits->fd, &num, &status) != 0) {
    473         char fitsErr[MAX_STRING_LENGTH];
    474         fits_get_errstatus(status, fitsErr);
    475         psError(PS_ERR_LOCATION_INVALID, true,
    476                 PS_ERRORTEXT_psFits_GETNUMHDUS_FAILED,
    477                 fits->filename, fitsErr);
    478         return 0;
    479     }
    480 
    481     return num;
    482 }
    483 
    484 psFitsType psFitsGetExtType(const psFits* fits)
    485 {
    486     if (fits == NULL) {
    487         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    488                 PS_ERRORTEXT_psFits_NULL);
    489         return PS_FITS_TYPE_NONE;
    490     }
    491 
    492     int status = 0;
    493     int hdutype = PS_FITS_TYPE_NONE;
    494 
    495     if (fits_get_hdu_type(fits->fd, &hdutype, &status) != 0) {
    496         char fitsErr[MAX_STRING_LENGTH];
    497         fits_get_errstatus(status, fitsErr);
    498         psError(PS_ERR_LOCATION_INVALID, true,
    499                 PS_ERRORTEXT_psFits_GETHDUTYPE_FAILED,
    500                 fits->filename, fitsErr);
    501         return PS_FITS_TYPE_NONE;
    502     }
    503 
    504     if (hdutype == PS_FITS_TYPE_IMAGE &&
    505             psFitsGetExtNum(fits) > 0 &&
    506             isHDUEmpty(fits)) {
    507         return PS_FITS_TYPE_ANY;
    508     }
    509 
    510     return hdutype;
    511 }
    512 
    513 psMetadata* psFitsReadHeader(psMetadata* out,
    514                              const psFits* fits)
    515 {
    516     if (fits == NULL) {
    517         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    518                 PS_ERRORTEXT_psFits_NULL);
    519         return NULL;
    520     }
    521 
    522     if (out == NULL) {
    523         out = psMetadataAlloc();
    524         if (out == NULL) {
    525             psError(PS_ERR_UNKNOWN, false,
    526                     "Failed to allocate a new psMetadata container.");
     201                    PS_ERRORTEXT_psFits_EXTNAME_INVALID,
     202                    extname, fitsErr);
     203            return false;
     204        }
     205
     206        return true;
     207    }
     208
     209    bool psFitsMoveExtNum(const psFits* fits,
     210                          int extnum,
     211                          bool relative)
     212    {
     213        if (fits == NULL) {
     214            psError(PS_ERR_BAD_PARAMETER_NULL, true,
     215                    PS_ERRORTEXT_psFits_NULL);
     216            return false;
     217        }
     218
     219        int status = 0;
     220        int hdutype = 0;
     221
     222        if (relative) {
     223            fits_movrel_hdu(fits->fd, extnum, &hdutype, &status);
     224            if (status != 0) {
     225                char fitsErr[MAX_STRING_LENGTH];
     226                fits_get_errstatus(status, fitsErr);
     227                psError(PS_ERR_LOCATION_INVALID, true,
     228                        PS_ERRORTEXT_psFits_EXTNUM_REL_MOVE_FAILED,
     229                        extnum, fitsErr);
     230                return false;
     231            }
     232        } else {
     233            fits_movabs_hdu(fits->fd, extnum+1, &hdutype, &status);
     234            if (status != 0) {
     235                char fitsErr[MAX_STRING_LENGTH];
     236                fits_get_errstatus(status, fitsErr);
     237                psError(PS_ERR_LOCATION_INVALID, true,
     238                        PS_ERRORTEXT_psFits_EXTNUM_ABS_MOVE_FAILED,
     239                        extnum, fitsErr);
     240                return false;
     241            }
     242        }
     243
     244        return true;
     245    }
     246
     247    bool psFitsMoveLast(const psFits* fits)
     248    {
     249        if (fits == NULL) {
     250            psError(PS_ERR_BAD_PARAMETER_NULL, true,
     251                    PS_ERRORTEXT_psFits_NULL);
     252            return false;
     253        }
     254
     255        return psFitsMoveExtNum(fits,psFitsGetSize(fits),false);
     256    }
     257
     258    int psFitsGetExtNum(const psFits* fits)
     259    {
     260        int hdunum;
     261
     262        if (fits == NULL) {
     263            psError(PS_ERR_BAD_PARAMETER_NULL, true,
     264                    PS_ERRORTEXT_psFits_NULL);
     265            return PS_FITS_TYPE_NONE;
     266        }
     267
     268
     269        return fits_get_hdu_num(fits->fd,&hdunum) - 1;
     270    }
     271
     272    psString psFitsGetExtName(const psFits* fits)
     273    {
     274        if (fits == NULL) {
     275            psError(PS_ERR_BAD_PARAMETER_NULL, true,
     276                    PS_ERRORTEXT_psFits_NULL);
    527277            return NULL;
    528278        }
    529     }
    530 
    531     // Get number of key names
    532     int numKeys = 0;
    533     int keyNum = 0;
    534     int status = 0;
    535     fits_get_hdrpos(fits->fd, &numKeys, &keyNum, &status);
    536 
    537     // Get each key name. Keywords start at one.
    538     char keyType;
    539     char keyName[MAX_STRING_LENGTH];
    540     char keyValue[MAX_STRING_LENGTH];
    541     char keyComment[MAX_STRING_LENGTH];
    542     psBool tempBool;
    543     psBool success;
    544     psBool stdKey;
    545     for (int i = 1; i <= numKeys; i++) {
    546 
    547         fits_read_keyn(fits->fd, i, keyName, keyValue, keyComment, &status);
    548 
    549         stdKey = false;
    550 
    551         int stdKeyIdx = 0;
    552         while (standardFitsKeys[stdKeyIdx] != NULL && ! stdKey) {
    553             if (strcmp(keyName,standardFitsKeys[stdKeyIdx++]) == 0) {
    554                 stdKey = true;
    555             }
    556         }
    557 
    558         if (keyValue[0] != 0) { // blank values are not handled by fits_get_keytype
    559             fits_get_keytype(keyValue, &keyType, &status);
    560         } else {
    561             keyType = 'C';
    562         }
    563         if (status != 0) {
    564             break;
    565         }
    566 
    567         if (! stdKey) {
    568             switch (keyType) {
    569             case 'X': // bit
    570             case 'I': // short int.
    571             case 'J': // int.
    572             case 'B': // byte
    573                 success = psMetadataAdd(out,
    574                                         PS_LIST_TAIL,
    575                                         keyName,
    576                                         PS_DATA_S32 | PS_META_DUPLICATE_OK,
    577                                         keyComment,
    578                                         atoi(keyValue));
    579                 break;
    580             case 'U': // unsigned int. may not fit in a psS32
    581             case 'K': // long int. can't all fit in a psS32
    582             case 'F':
    583                 success = psMetadataAdd(out,
    584                                         PS_LIST_TAIL,
    585                                         keyName,
    586                                         PS_DATA_F64 | PS_META_DUPLICATE_OK,
    587                                         keyComment,
    588                                         atof(keyValue));
    589                 break;
    590             case 'C':
    591                 // remove the single-quotes at front/end
    592                 if (keyValue[0] == '\'' && keyValue[strlen(keyValue)-1] == '\'') {
    593                     keyValue[strlen(keyValue)-1] = '\0';
    594                     success = psMetadataAdd(out,
    595                                             PS_LIST_TAIL,
    596                                             keyName,
    597                                             PS_DATA_STRING | PS_META_DUPLICATE_OK,
    598                                             keyComment,
    599                                             keyValue+1);
    600                 } else {
    601                     success = psMetadataAdd(out,
    602                                             PS_LIST_TAIL,
    603                                             keyName,
    604                                             PS_DATA_STRING | PS_META_DUPLICATE_OK,
    605                                             keyComment,
    606                                             keyValue);
    607                 }
    608                 break;
    609             case 'L':
    610                 tempBool = (keyValue[0] == 'T') ? 1 : 0;
    611                 success = psMetadataAdd(out,
    612                                         PS_LIST_TAIL,
    613                                         keyName,
    614                                         PS_DATA_BOOL | PS_META_DUPLICATE_OK,
    615                                         keyComment,
    616                                         tempBool);
    617                 break;
    618             default:
    619                 psError(PS_ERR_IO, true,
    620                         PS_ERRORTEXT_psFits_METATYPE_INVALID,
    621                         keyType);
    622                 return out;
    623             }
    624 
    625             if (!success) {
    626                 psError(PS_ERR_UNKNOWN, false,
    627                         PS_ERRORTEXT_psFits_METADATA_ADD_FAILED,
    628                         keyName);
    629                 return out;
    630             }
    631         }
    632 
    633     }
    634 
    635     if ( status != 0) {
    636         char fitsErr[MAX_STRING_LENGTH];
    637         (void)fits_get_errstatus(status, fitsErr);
    638         psError(PS_ERR_IO, true,
    639                 PS_ERRORTEXT_psFits_METADATA_ADD_FAILED,
    640                 fitsErr);
    641         return false;
    642     }
    643 
    644     return out;
    645 }
    646 
    647 psMetadata* psFitsReadHeaderSet(psMetadata* out,
    648                                 const psFits* fits)
    649 {
    650     if (fits == NULL) {
    651         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    652                 PS_ERRORTEXT_psFits_NULL);
    653         psFree(out);
    654         return NULL;
    655     }
    656 
    657     if (out == NULL) {
    658         out = psMetadataAlloc();
    659         if (out == NULL) {
    660             psError(PS_ERR_UNKNOWN, false,
    661                     "Failed to allocate a new psMetadata container.");
    662             return NULL;
    663         }
    664     }
    665 
    666     int size = psFitsGetSize(fits);
    667 
    668     int origPosition = psFitsGetExtNum(fits);
    669 
    670     for (int lcv=0; lcv < size; lcv++) {
    671         psFitsMoveExtNum(fits, lcv, false);
    672 
    673         char* name = NULL;
    674         if (lcv == 0) {
    675             name = psStringCopy("PHU");
    676         } else {
    677             name = psFitsGetExtName(fits);
    678         }
    679 
    680         psMetadata* header = psFitsReadHeader(NULL, fits);
    681         if (name != NULL && header != NULL) {
    682             psMetadataAddMetadata(out, PS_LIST_HEAD, name, 0, "FITS Header",
    683                                   header);
    684         } else {
    685             psWarning("Failed to read HDU#%d header data.",
    686                       lcv);
    687         }
    688 
    689         psFree(name);
    690         psFree(header);
    691     }
    692 
    693     // reposition to the original position
    694     psFitsMoveExtNum(fits, origPosition, false);
    695 
    696     return out;
    697 }
    698 
    699 psImage* psFitsReadImage(psImage* output, // a psImage to recycle.
    700                          const psFits* fits,    // the psFits object
    701                          psRegion region, // the region in the FITS image to read
    702                          int z)           // the z-plane in the FITS image cube to read
    703 {
    704     psS32 status = 0;           /* CFITSIO file vars */
    705     psS32 nAxis = 0;
    706     psS32 anynull = 0;
    707     psS32 bitPix = 0;           /* Pixel type */
    708     long nAxes[3];
    709     long firstPixel[3];         /* lower-left corner of image subset */
    710     long lastPixel[3];          /* upper-right corner of image subset */
    711     long increment[3];          /* increment for image subset */
    712     char fitsErr[80] = "";      /* CFITSIO error message string */
    713     psS32 fitsDatatype = 0;
    714     psS32 datatype = 0;
    715 
    716     if (fits == NULL) {
    717         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    718                 PS_ERRORTEXT_psFits_NULL);
    719         psFree(output);
    720         return NULL;
    721     }
    722 
    723     // check to see if we even are positioned on an image HDU
    724     int hdutype;
    725     if ( fits_get_hdu_type(fits->fd,&hdutype, &status) != 0) {
    726         char fitsErr[MAX_STRING_LENGTH];
    727         (void)fits_get_errstatus(status, fitsErr);
    728         psError(PS_ERR_IO, true,
    729                 PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
    730                 fitsErr);
    731         return NULL;
    732     }
    733     if (hdutype != IMAGE_HDU) {
    734         psError(PS_ERR_IO, true,
    735                 PS_ERRORTEXT_psFits_NOT_IMAGE_TYPE);
    736         return NULL;
    737     }
    738 
    739     /* Get the data type 'bitPix' from the FITS image */
    740     if (fits_get_img_equivtype(fits->fd, &bitPix, &status) != 0) {
    741         fits_get_errstatus(status, fitsErr);
    742         psError(PS_ERR_IO, true,
    743                 PS_ERRORTEXT_psFits_DATATYPE_UNKNOWN,
    744                 fitsErr);
    745         psFree(output);
    746         return NULL;
    747     }
    748 
    749     /* Get the dimensions 'nAxis' from the FITS image */
    750     if (fits_get_img_dim(fits->fd, &nAxis, &status) != 0) {
    751         (void)fits_get_errstatus(status, fitsErr);
    752         psError(PS_ERR_IO, true,
    753                 PS_ERRORTEXT_psFits_IMAGE_DIM_UNKNOWN,
    754                 fitsErr);
    755         psFree(output);
    756         return NULL;
    757     }
    758 
    759     /* Validate the number of axis */
    760     if ((nAxis < 2) || (nAxis > 3)) {
    761         psError(PS_ERR_IO, true,
    762                 PS_ERRORTEXT_psFits_IMAGE_DIMENSION_UNSUPPORTED,
    763                 nAxis);
    764         psFree(output);
    765         return NULL;
    766     }
    767 
    768     /* Get the Image size from the FITS file */
    769     if (fits_get_img_size(fits->fd, nAxis, nAxes, &status) != 0) {
    770         (void)fits_get_errstatus(status, fitsErr);
    771         psError(PS_ERR_IO, true,
    772                 PS_ERRORTEXT_psFits_IMAGE_SIZE_UNKNOWN,
    773                 fitsErr);
    774         psFree(output);
    775         return NULL;
    776     }
    777 
    778     firstPixel[0] = region.x0 + 1;
    779     firstPixel[1] = region.y0 + 1;
    780     firstPixel[2] = z + 1;
    781 
    782     if (region.x1 > 0) {
    783         lastPixel[0] = region.x1;
    784     } else {
    785         lastPixel[0] = nAxes[0] + region.x1; // n.b., region.x1 < 0
    786     }
    787     if (region.y1 > 0) {
    788         lastPixel[1] = region.y1;
    789     } else {
    790         lastPixel[1] = nAxes[1] + region.y1; // n.b., region.y1 < 0
    791     }
    792     lastPixel[2] = z + 1;
    793 
    794     increment[0] = 1;
    795     increment[1] = 1;
    796     increment[2] = 1;
    797 
    798     switch (bitPix) {
    799     case BYTE_IMG:
    800         datatype = PS_TYPE_U8;
    801         fitsDatatype = TBYTE;
    802         break;
    803     case SBYTE_IMG:
    804         datatype = PS_TYPE_S8;
    805         fitsDatatype = TSBYTE;
    806         break;
    807     case USHORT_IMG:
    808         datatype = PS_TYPE_U16;
    809         fitsDatatype = TUSHORT;
    810         break;
    811     case SHORT_IMG:
    812         datatype = PS_TYPE_S16;
    813         fitsDatatype = TSHORT;
    814         break;
    815     case ULONG_IMG:
    816         datatype = PS_TYPE_U32;
    817         fitsDatatype = TUINT;
    818         break;
    819     case LONG_IMG:
    820         datatype = PS_TYPE_S32;
    821         fitsDatatype = TINT;
    822         break;
    823     case LONGLONG_IMG:
    824         datatype = PS_TYPE_S64;
    825         fitsDatatype = TLONGLONG;
    826         break;
    827     case FLOAT_IMG:
    828         datatype = PS_TYPE_F32;
    829         fitsDatatype = TFLOAT;
    830         break;
    831     case DOUBLE_IMG:
    832         datatype = PS_TYPE_F64;
    833         fitsDatatype = TDOUBLE;
    834         break;
    835     default:
    836         psError(PS_ERR_IO, true,
    837                 PS_ERRORTEXT_psFits_FITS_TYPE_UNSUPPORTED,
    838                 bitPix);
    839         psFree(output);
    840         return NULL;
    841     }
    842 
    843     output = psImageRecycle(output,
    844                             lastPixel[0]-firstPixel[0]+1,
    845                             lastPixel[1]-firstPixel[1]+1,
    846                             datatype);
    847 
    848     if (output == NULL) {
    849         psError(PS_ERR_UNKNOWN, false,
    850                 "Failed to allocate a properly sized image.");
    851         return false;
    852     }
    853 
    854     // n.b., this assumes contiguous image buffer
    855     if (fits_read_subset(fits->fd, fitsDatatype, firstPixel, lastPixel, increment,
    856                          NULL, output->data.V[0], &anynull, &status) != 0) {
    857         psFree(output);
    858         (void)fits_get_errstatus(status, fitsErr);
    859         psError(PS_ERR_IO, true,
    860                 PS_ERRORTEXT_psFits_READ_FAILED,
    861                 fitsErr);
    862         return NULL;
    863     }
    864 
    865     return output;
    866 
    867 }
    868 
    869 bool psFitsWriteImage(psFits* fits,
    870                       psMetadata* header,
    871                       const psImage* input,
    872                       int numZPlanes)
    873 {
    874 
    875     if (fits == NULL) {
    876         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    877                 PS_ERRORTEXT_psFits_NULL);
    878         return false;
    879     }
    880 
    881     if (input == NULL) {
    882         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    883                 PS_ERRORTEXT_psFits_IMAGE_NULL);
    884         return false;
    885     }
    886     int numCols = input->numCols;
    887     int numRows = input->numRows;
    888 
    889     int status = 0;
    890 
    891     // determine the FITS-equivalent parameters
    892     int bitPix;
    893     double bZero;
    894     int dataType;
    895     if (! convertPsTypeToFits(input->type.type, &bitPix, &bZero, &dataType) ) {
    896         return false;
    897     }
    898 
    899     int naxis = 3;
    900     long naxes[3];
    901 
    902     naxes[0] = numCols;
    903     naxes[1] = numRows;
    904     naxes[2] = numZPlanes;
    905 
    906     if (numZPlanes < 2) {
    907         naxis = 2;
    908     }
    909 
    910     fits_create_img(fits->fd, bitPix, naxis, naxes, &status);
    911 
    912     if (bZero != 0) {        // set the bscale/bzero
    913         fits_write_key_dbl(fits->fd, "BZERO", bZero, 12, "Pixel Value Offset", &status);
    914         fits_write_key_dbl(fits->fd, "BSCALE", 1.0, 12, "Pixel Value Scale", &status);
    915         fits_set_bscale(fits->fd, 1.0, bZero, &status);
    916     }
    917 
    918     // write the header, if any.
    919     if (header != NULL) {
    920         psFitsWriteHeader(header, (psPtr)fits);
    921     }
    922 
    923     if (input->parent == NULL) { // if no parent, assume that the image data is contiguous
    924         fits_write_img(fits->fd,
    925                        dataType,              // datatype
    926                        1,                     // writing to the first z-plane
    927                        numCols*numRows,       // number of elements to write, i.e., the whole image
    928                        input->data.V[0],      // the data
    929                        &status);
    930     } else { // image data may not be contiguous; write one row at a time
    931         int firstPixel = 1;
    932         for (int row = 0; row < numRows; row++) {
    933             fits_write_img(fits->fd,
    934                            dataType,          // datatype
    935                            firstPixel,
    936                            numCols,           // number of elements to write, i.e., one row's worth
    937                            input->data.V[row],// the raw row data
    938                            &status);
    939             firstPixel += numCols;  // move to next row
    940         }
    941     }
    942 
    943     if ( status != 0) {
    944         char fitsErr[MAX_STRING_LENGTH];
    945         (void)fits_get_errstatus(status, fitsErr);
    946         psError(PS_ERR_IO, true,
    947                 PS_ERRORTEXT_psFits_WRITE_FAILED,
    948                 fits->filename, fitsErr);
    949         return false;
    950     }
    951 
    952     return true;
    953 
    954 }
    955 
    956 bool psFitsUpdateImage(psFits* fits,
    957                        const psImage* input,
    958                        psRegion region,
    959                        int z)
    960 {
    961     int status = 0;
    962 
    963     if (fits == NULL) {
    964         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    965                 PS_ERRORTEXT_psFits_NULL);
    966         return false;
    967     }
    968 
    969     if (input == NULL) {
    970         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    971                 PS_ERRORTEXT_psFits_IMAGE_NULL);
    972         return false;
    973     }
    974 
    975     // check to see if we are positioned on an image HDU
    976     int hdutype;
    977     if ( fits_get_hdu_type(fits->fd,&hdutype, &status) != 0) {
    978         char fitsErr[MAX_STRING_LENGTH];
    979         (void)fits_get_errstatus(status, fitsErr);
    980         psError(PS_ERR_IO, true,
    981                 PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
    982                 fitsErr);
    983         return NULL;
    984     }
    985     if (hdutype != IMAGE_HDU) {
    986         psError(PS_ERR_IO, true,
    987                 PS_ERRORTEXT_psFits_NOT_IMAGE_TYPE);
    988         return NULL;
    989     }
    990 
    991     int numCols = input->numCols;
    992     int numRows = input->numRows;
    993 
    994     // determine the FITS-equivalent parameters
    995     int bitPix;
    996     double bZero;
    997     int dataType;
    998     if (! convertPsTypeToFits(input->type.type, &bitPix, &bZero, &dataType) ) {
    999         return false;
    1000     }
    1001 
    1002     //check to see if the HDU has the same datatype
    1003     int fileBitpix;
    1004     int naxis;
    1005     long nAxes[3];
    1006     nAxes[2] = 1;
    1007     fits_get_img_param(fits->fd, 3, &fileBitpix, &naxis, nAxes, &status);
    1008 
    1009     //check to see if the HDU has the same datatype
    1010     if (bitPix != fileBitpix) {
    1011         char* fitsTypeStr;
    1012         char* imageTypeStr;
    1013         PS_TYPE_NAME(fitsTypeStr,fileBitpix);
    1014         PS_TYPE_NAME(imageTypeStr,input->type.type);
    1015         psError(PS_ERR_IO, true,
    1016                 PS_ERRORTEXT_psFits_IMAGE_UPDATE_TYPE_MISMATCH,
    1017                 fitsTypeStr, imageTypeStr);
    1018         return false;
    1019     }
    1020 
    1021     //check if the HDU has the z-plane requested
    1022     if (z >= nAxes[2]) {
    1023         psError(PS_ERR_BAD_PARAMETER_SIZE, true,
    1024                 PS_ERRORTEXT_psFits_FITS_Z_SMALL,
    1025                 nAxes[2],z);
    1026         return false;
    1027     }
    1028 
    1029     // determine the region in the FITS file domain
    1030     long firstPixel[3];
    1031     long lastPixel[3];
    1032 
    1033     firstPixel[0] = region.x0 + 1;
    1034     firstPixel[1] = region.y0 + 1;
    1035     firstPixel[2] = z + 1;
    1036 
    1037     if (region.x1 > 0) {
    1038         lastPixel[0] = region.x1;
    1039     } else {
    1040         lastPixel[0] = nAxes[0] + region.x1; // n.b., region.x1 < 0
    1041     }
    1042     if (region.y1 > 0) {
    1043         lastPixel[1] = region.y1;
    1044     } else {
    1045         lastPixel[1] = nAxes[1] + region.y1; // n.b., region.y1 < 0
    1046     }
    1047     lastPixel[2] = z + 1;
    1048 
    1049     if (firstPixel[0] < 1 || firstPixel[0] > nAxes[0] ||
    1050             firstPixel[1] < 1 || firstPixel[1] > nAxes[1] ||
    1051             lastPixel[0] < 1 || lastPixel[0] > nAxes[0] ||
    1052             lastPixel[1] < 1 || lastPixel[1] > nAxes[1]) {
    1053         psError(PS_ERR_BAD_PARAMETER_VALUE, true,
    1054                 "Specified region [%d:%d,%d:%d], is not valid given the %dx%d FITS image.",
    1055                 region.y0,region.y1-1,region.x0,region.x1-1);
    1056         return false;
    1057 
    1058     }
    1059 
    1060     int dx = lastPixel[0] - firstPixel[0];
    1061     int dy = lastPixel[1] - firstPixel[1];
    1062     if (dx > numCols ||
    1063             dy > numRows) {
    1064         psError(PS_ERR_BAD_PARAMETER_VALUE, true,
    1065                 "The region [%d:%d,%d:%d], is not valid given the input %dx%d image.",
    1066                 firstPixel[1]-1,lastPixel[1]-1,
    1067                 firstPixel[0]-1,lastPixel[0]-1,
    1068                 numCols, numRows);
    1069         return false;
    1070     }
    1071 
    1072     psImage* subset;
    1073     if (dx != numCols || dy != numRows) {
    1074         // the input image needs to be subsetted
    1075         subset = psImageSubset((psImage*)input, psRegionSet(0,dx+1,0,dy+1));
    1076     } else {
    1077         subset = psMemIncrRefCounter((psImage*)input);
    1078     }
    1079 
    1080     fits_write_subset(fits->fd, dataType, firstPixel, lastPixel, subset->data.V[0], &status);
    1081 
    1082     if ( status != 0) {
    1083         char fitsErr[MAX_STRING_LENGTH];
    1084         (void)fits_get_errstatus(status, fitsErr);
    1085         psError(PS_ERR_IO, true,
    1086                 PS_ERRORTEXT_psFits_WRITE_FAILED,
    1087                 fits->filename, fitsErr);
    1088         return false;
    1089     }
    1090 
    1091     return true;
    1092 }
    1093 
    1094 bool psFitsWriteHeader(const psMetadata* output,
    1095                        psFits* fits)
    1096 {
    1097 
    1098     if (fits == NULL) {
    1099         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    1100                 PS_ERRORTEXT_psFits_NULL);
    1101         return false;
    1102     }
    1103 
    1104     if (output == NULL) {
    1105         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    1106                 PS_ERRORTEXT_psFits_METADATA_NULL);
    1107         return false;
    1108     }
    1109 
    1110     int status = 0;
    1111 
    1112     //transverse the metadata list and add each key.
    1113 
    1114     psListIterator* iter = psListIteratorAlloc(output->list,PS_LIST_HEAD,true);
    1115     psMetadataItem* item;
    1116     while ( (item=psListGetAndIncrement(iter)) != NULL ) {
    1117         switch (item->type) {
    1118         case PS_DATA_BOOL: {
    1119                 int value = item->data.B;
    1120                 fits_update_key(fits->fd,
    1121                                 TLOGICAL,
    1122                                 item->name,
    1123                                 &value,
    1124                                 item->comment,
    1125                                 &status);
    1126                 break;
    1127             }
    1128         case PS_DATA_S32:
    1129             fits_update_key(fits->fd,
    1130                             TINT,
    1131                             item->name,
    1132                             &item->data.S32,
    1133                             item->comment,
    1134                             &status);
    1135             break;
    1136         case PS_DATA_F32:
    1137             fits_update_key(fits->fd,
    1138                             TFLOAT,
    1139                             item->name,
    1140                             &item->data.F32,
    1141                             item->comment,
    1142                             &status);
    1143             break;
    1144         case PS_DATA_F64:
    1145             fits_update_key(fits->fd,
    1146                             TDOUBLE,
    1147                             item->name,
    1148                             &item->data.F64,
    1149                             item->comment,
    1150                             &status);
    1151             break;
    1152         case PS_DATA_STRING:
    1153             fits_update_key(fits->fd,
    1154                             TSTRING,
    1155                             item->name,
    1156                             item->data.V,
    1157                             item->comment,
    1158                             &status);
    1159             break;
    1160         default:  // all other META types are ignored
    1161             break;
    1162         }
    1163 
    1164         if ( status != 0) {
     279
     280        int status = 0;
     281        char name[MAX_STRING_LENGTH];
     282
     283        if (fits_read_key_str(fits->fd, "EXTNAME", name, NULL, &status) != 0) {
     284            status = 0;
     285            if (fits_read_key_str(fits->fd, "HDUNAME", name, NULL, &status) != 0) {
     286                int num = psFitsGetExtNum(fits);
     287                snprintf(name, MAX_STRING_LENGTH, "EXT-%3d",num);
     288            }
     289        }
     290        return psStringCopy(name);
     291    }
     292
     293    bool psFitsSetExtName(psFits* fits, const char* name)
     294    {
     295        if (fits == NULL) {
     296            psError(PS_ERR_BAD_PARAMETER_NULL, true,
     297                    PS_ERRORTEXT_psFits_NULL);
     298            return false;
     299        }
     300
     301        if (name == NULL) {
     302            psError(PS_ERR_BAD_PARAMETER_NULL, true,
     303                    PS_ERRORTEXT_psFits_EXTNAME_NULL);
     304            return false;
     305        }
     306
     307        int status = 0;
     308
     309        if (fits_update_key_str(fits->fd, "EXTNAME", (char*)name, NULL, &status) != 0) {
    1165310            char fitsErr[MAX_STRING_LENGTH];
    1166311            (void)fits_get_errstatus(status, fitsErr);
    1167312            psError(PS_ERR_IO, true,
    1168313                    PS_ERRORTEXT_psFits_WRITE_FAILED,
    1169                     fits->filename, fitsErr);
    1170             return false;
    1171         }
    1172     }
    1173 
    1174     return true;
    1175 }
    1176 
    1177 psMetadata* psFitsReadTableRow(const psFits* fits,
    1178                                int row)
    1179 {
    1180     long numRows;
    1181     int numCols;
    1182     int status = 0;
    1183 
    1184     if (fits == NULL) {
    1185         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    1186                 PS_ERRORTEXT_psFits_NULL);
    1187         return NULL;
    1188     }
    1189 
    1190     // check to see if we even are positioned on a table HDU
    1191     int hdutype;
    1192     fits_get_hdu_type(fits->fd,&hdutype, &status);
    1193     if ( status != 0) {
    1194         char fitsErr[MAX_STRING_LENGTH];
    1195         (void)fits_get_errstatus(status, fitsErr);
    1196         psError(PS_ERR_IO, true,
    1197                 PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
    1198                 fitsErr);
    1199         return NULL;
    1200     }
    1201     if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
    1202         psError(PS_ERR_IO, true,
    1203                 PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
    1204         return NULL;
    1205     }
    1206 
    1207     // get the size of the FITS table
    1208     fits_get_num_rows(fits->fd, &numRows, &status);
    1209     fits_get_num_cols(fits->fd, &numCols, &status);
    1210     if ( status != 0) {
    1211         char fitsErr[MAX_STRING_LENGTH];
    1212         (void)fits_get_errstatus(status, fitsErr);
    1213         psError(PS_ERR_IO, true,
    1214                 PS_ERRORTEXT_psFits_GET_TABLE_SIZE_FAILED,
    1215                 fitsErr);
    1216         return NULL;
    1217     }
    1218 
    1219     psTrace(".psFits.psFitsReadTableRow",5,"Table size is %ix%i\n",numCols, numRows);
    1220     // the row parameter in the proper range?
    1221     if (row < 0 || row >= numRows) {
    1222         psError(PS_ERR_BAD_PARAMETER_VALUE, true,
    1223                 PS_ERRORTEXT_psFits_ROW_INVALID,
    1224                 row,numRows);
    1225         return NULL;
    1226     }
    1227 
    1228     psMetadata* data = psMetadataAlloc();
    1229 
    1230     int typecode;
    1231     long repeat;
    1232     long width;
    1233     char name[60];
    1234     for (int col = 1; col <= numCols; col++) {
    1235         // get the column name
    1236         if (hdutype == BINARY_TBL) {
    1237             fits_get_bcolparms(fits->fd, col, name,
    1238                                NULL, NULL, NULL, NULL, NULL, NULL, NULL, &status);
    1239         } else {
    1240             fits_get_acolparms(fits->fd, col, name,
    1241                                NULL, NULL, NULL, NULL, NULL, NULL, NULL, &status);
    1242         }
    1243         // get the column type
    1244         fits_get_coltype(fits->fd, col, &typecode, &repeat, &width, &status);
    1245 
    1246         if (status == 0) {
    1247 
    1248             #define READ_TABLE_ROW_CASE(FITSTYPE, NATIVETYPE, TYPE) \
    1249         case FITSTYPE: { \
    1250                 if (repeat == 1) { \
    1251                     NATIVETYPE value; \
    1252                     int anynul = 0; \
    1253                     fits_read_col(fits->fd, FITSTYPE, col,row+1, \
    1254                                   1, 1, NULL, &value, &anynul, &status); \
    1255                     psTrace(".psFits.psFitsReadTableRow",5,"Column #%i, '%s', is type %i, repeat %i, Value = %g\n", \
    1256                             col, name, typecode, repeat, (double)value); \
    1257                     psMetadataAdd(data,PS_LIST_TAIL, name, \
    1258                                   PS_DATA_##TYPE, \
    1259                                   "", (ps##TYPE)value); \
    1260                 } else { \
    1261                     psVector* value = psVectorAlloc(repeat,PS_DATA_##TYPE); \
    1262                     int anynul = 0; \
    1263                     fits_read_col(fits->fd, FITSTYPE, col,row+1, \
    1264                                   1, repeat, NULL, value->data.U8, &anynul, &status); \
    1265                     psMetadataAdd(data,PS_LIST_TAIL, name, \
    1266                                   PS_DATA_VECTOR, \
    1267                                   "", value); \
    1268                     psFree(value); \
    1269                 } \
    1270                 break; \
    1271             }
    1272 
    1273             switch (typecode) {
    1274             case TBYTE:
    1275             case TSHORT:
    1276             case TLONGLONG:
    1277                 READ_TABLE_ROW_CASE(TLONG, long, S32)
    1278                 READ_TABLE_ROW_CASE(TFLOAT, float, F32)
    1279                 READ_TABLE_ROW_CASE(TDOUBLE, double, F64)
    1280                 READ_TABLE_ROW_CASE(TLOGICAL, bool, BOOL);
    1281             case TSTRING: {
    1282                     char* value = psAlloc(repeat+1);
    1283                     int anynul = 0;
    1284                     fits_read_col(fits->fd, TSTRING, col,row+1,
    1285                                   1, 1, NULL, &value, &anynul, &status);
    1286                     psTrace(".psFits.psFitsReadTableRow",5,"Column #%i, '%s', is type %i, repeat %i, value = %s\n",
    1287                             col, name, typecode, repeat, value);
    1288                     if (anynul == 0) {
    1289                         psMetadataAdd(data,PS_LIST_TAIL, name,
    1290                                       PS_DATA_STRING,
    1291                                       "", value);
    1292                     }
    1293                     psFree(value);
    1294                     break;
    1295                 }
    1296             default:
    1297                 psWarning("Data type (%d) not supportted for column %d",
    1298                           typecode, col);
    1299 
    1300                 psTrace("psFits.psFitsReadTableRow", 2,
    1301                         "Column %d or row %d was of a non primitive type, %d",
    1302                         col, row, typecode);
    1303             }
    1304         }
    1305 
    1306         if ( status != 0) {
    1307             char fitsErr[MAX_STRING_LENGTH];
    1308             (void)fits_get_errstatus(status, fitsErr);
    1309             psError(PS_ERR_IO, true,
    1310                     PS_ERRORTEXT_psFits_GET_TABLE_ELEMENT,
    1311                     col,row,fitsErr);
    1312             psFree(data);
    1313             return NULL;
    1314         }
    1315 
    1316     }
    1317 
    1318     return data;
    1319 }
    1320 
    1321 psArray* psFitsReadTableColumn(const psFits* fits,
    1322                                const char* colname)
    1323 {
    1324     int colnum = 0;
    1325     int status = 0;
    1326 
    1327     if (fits == NULL) {
    1328         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    1329                 PS_ERRORTEXT_psFits_NULL);
    1330         return NULL;
    1331     }
    1332 
    1333     // check to see if we even are positioned on a table HDU
    1334     int hdutype;
    1335     if ( fits_get_hdu_type(fits->fd,&hdutype, &status) != 0) {
    1336         char fitsErr[MAX_STRING_LENGTH];
    1337         (void)fits_get_errstatus(status, fitsErr);
    1338         psError(PS_ERR_IO, true,
    1339                 PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
    1340                 fitsErr);
    1341         return NULL;
    1342     }
    1343     if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
    1344         psError(PS_ERR_IO, true,
    1345                 PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
    1346         return NULL;
    1347     }
    1348 
    1349     // find the column by name
    1350     if ( fits_get_colnum(fits->fd, CASESEN, (char*)colname, &colnum, &status) != 0) {
    1351         char fitsErr[MAX_STRING_LENGTH];
    1352         (void)fits_get_errstatus(status, fitsErr);
    1353         psError(PS_ERR_IO, true,
    1354                 PS_ERRORTEXT_psFits_FIND_COLUMN,
    1355                 colname, fitsErr);
    1356         return NULL;
    1357     }
    1358 
    1359     // get the number of rows
    1360     long numRows = 0;
    1361     fits_get_num_rows(fits->fd, &numRows, &status);
    1362 
    1363     // get the column length.
    1364     int width;
    1365     if ( fits_get_col_display_width(fits->fd, colnum, &width, &status) != 0) {
    1366         char fitsErr[MAX_STRING_LENGTH];
    1367         (void)fits_get_errstatus(status, fitsErr);
    1368         psError(PS_ERR_IO, true,
    1369                 PS_ERRORTEXT_psFits_GET_COLTYPE,
    1370                 fitsErr);
    1371         return NULL;
    1372     }
    1373 
    1374     // allocate the buffers
    1375     psArray* result = psArrayAlloc(numRows);
    1376     for (int row = 0; row < numRows; row++) {
    1377         result->data[row] = psAlloc((width+1)*sizeof(char));
    1378     }
    1379     result->n = numRows;
    1380 
    1381     fits_read_col_str(fits->fd,
    1382                       colnum,
    1383                       1, // firstrow
    1384                       1, // firestelem
    1385                       numRows,
    1386                       "", // nulstr
    1387                       (char**)result->data,
    1388                       NULL,
    1389                       &status);
    1390 
    1391     if ( status != 0) {
    1392         char fitsErr[MAX_STRING_LENGTH];
    1393         (void)fits_get_errstatus(status, fitsErr);
    1394         psError(PS_ERR_IO, true,
    1395                 PS_ERRORTEXT_psFits_TABLE_READ_COL,
    1396                 fitsErr);
    1397         return NULL;
    1398     }
    1399 
    1400     return result;
    1401 }
    1402 
    1403 psVector* psFitsReadTableColumnNum(const psFits* fits,
    1404                                    const char* colname)
    1405 {
    1406     int status = 0;
    1407     int colnum = 0;
    1408 
    1409     if (fits == NULL) {
    1410         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    1411                 PS_ERRORTEXT_psFits_NULL);
    1412         return NULL;
    1413     }
    1414 
    1415     // check to see if we even are positioned on a table HDU
    1416     int hdutype;
    1417     if ( fits_get_hdu_type(fits->fd,&hdutype, &status) != 0) {
    1418         char fitsErr[MAX_STRING_LENGTH];
    1419         (void)fits_get_errstatus(status, fitsErr);
    1420         psError(PS_ERR_IO, true,
    1421                 PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
    1422                 fitsErr);
    1423         return NULL;
    1424     }
    1425     if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
    1426         psError(PS_ERR_IO, true,
    1427                 PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
    1428         return NULL;
    1429     }
    1430 
    1431     // find the column by name
    1432     if ( fits_get_colnum(fits->fd, CASESEN, (char*)colname, &colnum, &status) != 0) {
    1433         char fitsErr[MAX_STRING_LENGTH];
    1434         (void)fits_get_errstatus(status, fitsErr);
    1435         psError(PS_ERR_IO, true,
    1436                 PS_ERRORTEXT_psFits_FIND_COLUMN,
    1437                 colname, fitsErr);
    1438         return NULL;
    1439     }
    1440 
    1441     // get the number of rows
    1442     long numRows = 0;
    1443     fits_get_num_rows(fits->fd,
    1444                       &numRows,
    1445                       &status);
    1446 
    1447     // get the column datatype.
    1448     int typecode;
    1449     long repeat;
    1450     long width;
    1451     if ( fits_get_eqcoltype(fits->fd, colnum, &typecode, &repeat, &width, &status) != 0) {
    1452         char fitsErr[MAX_STRING_LENGTH];
    1453         (void)fits_get_errstatus(status, fitsErr);
    1454         psError(PS_ERR_IO, true,
    1455                 PS_ERRORTEXT_psFits_GET_COLTYPE,
    1456                 fitsErr);
    1457         return NULL;
    1458     }
    1459 
    1460     psVector* result = psVectorAlloc(numRows, convertFitsToPsType(typecode));
    1461 
    1462     fits_read_col(fits->fd,
    1463                   typecode,
    1464                   colnum,
    1465                   1 /* firstrow */,
    1466                   1 /* firstelem */,
    1467                   numRows,
    1468                   NULL,
    1469                   (psPtr)(result->data.U8),
    1470                   NULL,
    1471                   &status);
    1472 
    1473     if ( status != 0) {
    1474         char fitsErr[MAX_STRING_LENGTH];
    1475         (void)fits_get_errstatus(status, fitsErr);
    1476         psError(PS_ERR_IO, true,
    1477                 PS_ERRORTEXT_psFits_TABLE_READ_COL,
    1478                 fitsErr);
    1479         return NULL;
    1480     }
    1481 
    1482     return result;
    1483 }
    1484 
    1485 
    1486 psArray* psFitsReadTable(psFits* fits)
    1487 {
    1488     int status = 0;
    1489 
    1490     if (fits == NULL) {
    1491         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    1492                 PS_ERRORTEXT_psFits_NULL);
    1493         return NULL;
    1494     }
    1495 
    1496     // check to see if we even are positioned on a table HDU
    1497     int hdutype;
    1498     if ( fits_get_hdu_type(fits->fd,&hdutype, &status) != 0) {
    1499         char fitsErr[MAX_STRING_LENGTH];
    1500         (void)fits_get_errstatus(status, fitsErr);
    1501         psError(PS_ERR_IO, true,
    1502                 PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
    1503                 fitsErr);
    1504         return NULL;
    1505     }
    1506     if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
    1507         psError(PS_ERR_IO, true,
    1508                 PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
    1509         return NULL;
    1510     }
    1511 
    1512     // get the size of the FITS table
    1513     long numRows = 0;
    1514     fits_get_num_rows(fits->fd, &numRows, &status);
    1515     if ( status != 0) {
    1516         char fitsErr[MAX_STRING_LENGTH];
    1517         (void)fits_get_errstatus(status, fitsErr);
    1518         psError(PS_ERR_IO, true,
    1519                 PS_ERRORTEXT_psFits_GET_TABLE_SIZE_FAILED,
    1520                 fitsErr);
    1521         return NULL;
    1522     }
    1523 
    1524 
    1525     psArray* table = psArrayAlloc(numRows);
    1526 
    1527     for (int row = 0; row < numRows; row++) {
    1528         psTrace(".psFits.psFitsReadTable",5,"Reading row %i of %i\n",row, numRows);
    1529         table->data[row] = psFitsReadTableRow(fits,row);
    1530     }
    1531 
    1532     return table;
    1533 }
    1534 
    1535 bool psFitsWriteTable(psFits* fits,
    1536                       const psMetadata* header,
    1537                       const psArray* table)
    1538 {
    1539     int status = 0;
    1540 
    1541     if (fits == NULL) {
    1542         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    1543                 PS_ERRORTEXT_psFits_NULL);
    1544         return false;
    1545     }
    1546 
    1547     if (table == NULL) {
    1548         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    1549                 PS_ERRORTEXT_psFits_IMAGE_NULL);
    1550         return false;
    1551     }
    1552 
    1553     int rows = table->n;
    1554     if (rows < 1) {
    1555         // no table data, what can I do?
    1556         psError(PS_ERR_BAD_PARAMETER_SIZE, true,
    1557                 PS_ERRORTEXT_psFits_TABLE_EMPTY);
    1558         return false;
    1559     }
    1560 
    1561     // find all the columns needed
    1562     psArray* columns = psArrayAlloc(((psMetadata*)table->data[0])->list->n);
    1563     columns->n=0;
    1564 
    1565     // find the unique items in the array of metadata 'rows'
    1566     psMetadataItem* item;
    1567     for (int row=0; row < rows; row++) {
    1568         psMetadata* rowMeta = table->data[row];
    1569         if (rowMeta != NULL) {
    1570             psListIterator* iter = psListIteratorAlloc(rowMeta->list,
    1571                                    PS_LIST_HEAD,true);
    1572             while ( (item=psListGetAndIncrement(iter)) != NULL) {
    1573                 if (PS_DATA_IS_PRIMITIVE(item->type) ||
    1574                         item->type == PS_DATA_STRING ||
    1575                         item->type == PS_DATA_VECTOR) {
    1576                     bool found = false;
    1577                     psMetadataItem* fItem = NULL;
    1578                     int n;
    1579                     for (n=0; n < columns->n && ! found; n++) {
    1580                         fItem = (psMetadataItem*)(columns->data[n]);
    1581                         if (strcmp(item->name, fItem->name) == 0) {
    1582                             found = true;
    1583                             break;
    1584                         }
    1585                     }
    1586                     if (! found) {
    1587                         psArrayAdd(columns, columns->nalloc, item);
    1588                     } else if (item->type == PS_DATA_STRING &&
    1589                                strlen(fItem->data.V) < strlen(item->data.V)) {
    1590                         // got to keep the longest string value as to know what size to create the table column
    1591                         psMemDecrRefCounter(fItem);
    1592                         columns->data[n] = psMemIncrRefCounter(item);
    1593 
    1594                     } else if (item->type == PS_DATA_VECTOR &&
    1595                                ((psVector*)(fItem->data.V))->n < ((psVector*)(item->data.V))->n) {
    1596                         psMemDecrRefCounter(fItem);
    1597                         columns->data[n] = psMemIncrRefCounter(item);
    1598                     }
    1599                 } else {
    1600                     // unsupported type -- treating as an error
    1601                     psError(PS_ERR_BAD_PARAMETER_TYPE, true,
    1602                             "Unsupported data type (%d) for Metadata Item '%s' in row %d.",
    1603                             item->type, item->name, row);
    1604                     psFree(iter);
    1605                     psFree(columns);
    1606                     return false;
    1607                 }
    1608             }
    1609             psFree(iter);
    1610         }
    1611     }
    1612 
    1613     if (columns->n == 0) { // no table columns found
    1614         psError(PS_ERR_BAD_PARAMETER_SIZE, true,
    1615                 "Did not find any column data to write to a table.");
    1616         psFree(columns);
    1617         return false;
    1618     }
    1619 
    1620     //create list of column names and types.
    1621     psArray* columnNames = psArrayAlloc(columns->n);
    1622     psArray* columnTypes = psArrayAlloc(columns->n);
    1623     for (int n=0; n < columns->n; n++) {
    1624         columnNames->data[n] = psMemIncrRefCounter(((psMetadataItem*)columns->data[n])->name);
    1625         if ( ! getMetadataTForm((psMetadataItem*)columns->data[n],
    1626                                 (char**)&(columnTypes->data[n]),1) ) {
    1627             psError(PS_ERR_UNKNOWN, true,
    1628                     "Failed to determine the FITS data type of '%s' (type=%d).",
    1629                     columnNames->data[n],
    1630                     ((psMetadataItem*)columns->data[n])->type);
    1631             psFree(columns);
    1632             psFree(columnNames);
    1633             psFree(columnTypes);
    1634             return false;
    1635         }
    1636     }
    1637 
    1638     char* extname = NULL;
    1639     if (header != NULL) {
    1640         extname = psMetadataLookupPtr(NULL, header, "EXTNAME");
    1641         if ( extname == NULL) {
    1642             extname = psMetadataLookupPtr(NULL, header, "HDUNAME");
    1643         }
    1644     }
    1645 
    1646     fits_create_tbl(fits->fd,
    1647                     BINARY_TBL,
    1648                     table->n, // number of rows in table
    1649                     columns->n, // number of columns in table
    1650                     (char**)columnNames->data, // names of the columns
    1651                     (char**)columnTypes->data, // format of the columns
    1652                     NULL, // physical unit of columns
    1653                     extname, // extension name
    1654                     &status);
    1655 
    1656     psFree(columnNames);
    1657     psFree(columnTypes);
    1658 
    1659     // fill in the table elements with data
    1660     for (int n = 0; n < columns->n; n++) {
    1661         int row;
    1662         item = columns->data[n];
    1663         if (PS_DATA_IS_PRIMITIVE(item->type) ) {
    1664             psVector* col = psVectorAlloc(table->n, item->type);
    1665             int dataSize = PSELEMTYPE_SIZEOF(item->type);
    1666             int dataType;
    1667             convertPsTypeToFits(item->type, NULL,NULL,&dataType);
    1668             for (row = 0; row < table->n; row++) {
    1669                 psMetadataItem* dataItem = psMetadataLookup(
    1670                                                table->data[row],
    1671                                                item->name);
    1672                 memcpy(&col->data.U8[row*dataSize],&dataItem->data,dataSize);
    1673             }
    1674             fits_write_col(fits->fd,
    1675                            dataType,
    1676                            n+1, // column number
    1677                            1, // firstrow
    1678                            1, // firstelem
    1679                            table->n, // nelements
    1680                            col->data.U8,
    1681                            &status);
    1682             psFree(col);
    1683         } else if (item->type == PS_DATA_STRING) {
    1684             psArray* colArray = psArrayAlloc(table->n);
    1685             for (row = 0; row < table->n; row++) {
    1686                 colArray->data[row] = psMemIncrRefCounter(
    1687                                           psMetadataLookupStr(NULL,
    1688                                                               table->data[row],
    1689                                                               item->name));
    1690             }
    1691             fits_write_col_str(fits->fd,
    1692                                n+1,
    1693                                1,
    1694                                1,
    1695                                table->n,
    1696                                (char**)colArray->data,
    1697                                &status);
    1698             psFree(colArray);
    1699         } else if (item->type == PS_DATA_VECTOR) {
    1700             psVector* vec = (psVector*)(item->data.V);
    1701             psVector* col = psVectorAlloc(table->n*vec->n, vec->type.type);
    1702             int dataSize = PSELEMTYPE_SIZEOF(vec->type.type)*vec->n;
    1703             int dataType;
    1704             convertPsTypeToFits(vec->type.type, NULL,NULL,&dataType);
    1705             for (row = 0; row < table->n; row++) {
    1706                 psMetadataItem* dataItem = psMetadataLookup(
    1707                                                table->data[row],
    1708                                                item->name);
    1709                 memcpy(&col->data.U8[row*dataSize],
    1710                        ((psVector*)(dataItem->data.V))->data.U8,
    1711                        dataSize);
    1712             }
    1713             fits_write_col(fits->fd,
    1714                            dataType,
    1715                            n+1, // column number
    1716                            1, // firstrow
    1717                            1, // firstelem
    1718                            table->n*vec->n, // nelements
    1719                            col->data.U8,
    1720                            &status);
    1721             psFree(col);
    1722         }
    1723         if (status != 0) {
     314                    fitsErr);
     315            return false;
     316        }
     317
     318        return true;
     319    }
     320
     321    bool psFitsDeleteExtNum(psFits* fits,
     322                            int extnum,
     323                            bool relative)
     324    {
     325        if (fits == NULL) {
     326            psError(PS_ERR_BAD_PARAMETER_NULL, true,
     327                    PS_ERRORTEXT_psFits_NULL);
     328            return false;
     329        }
     330
     331        // move to the specified HDU
     332        if (! psFitsMoveExtNum(fits,extnum,relative) ) {
     333            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
     334                    "Failed to delete HDU #%d",
     335                    extnum);
     336            return false;
     337        }
     338
     339        int status = 0;
     340
     341        // OK, now let's delete the HDU
     342        if (fits_delete_hdu(fits->fd, NULL, &status) != 0) {
    1724343            char fitsErr[MAX_STRING_LENGTH];
    1725344            (void)fits_get_errstatus(status, fitsErr);
    1726345            psError(PS_ERR_IO, true,
    1727346                    PS_ERRORTEXT_psFits_WRITE_FAILED,
    1728                     fits->filename, fitsErr);
    1729             psFree(columns);
    1730             return false;
    1731         }
    1732 
    1733     }
    1734 
    1735     psFree(columns);
    1736 
    1737     return true;
    1738 }
    1739 
    1740 bool psFitsUpdateTable(psFits* fits,
    1741                        const psMetadata* data,
    1742                        int row)
    1743 {
    1744     int status = 0;
    1745 
    1746     if (fits == NULL) {
    1747         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    1748                 PS_ERRORTEXT_psFits_NULL);
    1749         return false;
    1750     }
    1751 
    1752     if (data == NULL) {
    1753         psError(PS_ERR_BAD_PARAMETER_NULL, true,
    1754                 PS_ERRORTEXT_psFits_IMAGE_NULL);
    1755         return false;
    1756     }
    1757 
    1758     // check to see if we even are positioned on a table HDU
    1759     int hdutype;
    1760     if ( fits_get_hdu_type(fits->fd,&hdutype, &status) != 0) {
    1761         char fitsErr[MAX_STRING_LENGTH];
    1762         (void)fits_get_errstatus(status, fitsErr);
    1763         psError(PS_ERR_IO, true,
    1764                 PS_ERRORTEXT_psFits_GET_HDU_TYPE_FAILED,
    1765                 fitsErr);
    1766         return false;
    1767     }
    1768     if (hdutype != ASCII_TBL && hdutype != BINARY_TBL) {
    1769         psError(PS_ERR_IO, true,
    1770                 PS_ERRORTEXT_psFits_NOT_TABLE_TYPE);
    1771         return false;
    1772     }
    1773 
    1774     psMetadataIterator* iter = psMetadataIteratorAlloc((psPtr)data,PS_LIST_HEAD,NULL);
    1775 
    1776     psMetadataItem* item;
    1777 
    1778     while ( (item=psMetadataGetAndIncrement(iter)) != NULL) {
    1779         if (PS_DATA_IS_PRIMITIVE(item->type) ||
    1780                 item->type == PS_DATA_BOOL ||
    1781                 item->type == PS_DATA_STRING) {
    1782             // operating on primitive data type or string, i.e., not a complex object
    1783             int colnum = 0;
    1784 
    1785             if ( fits_get_colnum(fits->fd, CASESEN, item->name, &colnum, &status) == 0) {
    1786                 // cooresponding column found in table
    1787                 int dataType;
    1788                 convertPsTypeToFits(item->type, NULL, NULL, &dataType);
    1789 
    1790                 if (fits_write_col(fits->fd, dataType, colnum, row+1, 1, 1, &item->data,&status) != 0) {
    1791                     char fitsErr[MAX_STRING_LENGTH];
    1792                     (void)fits_get_errstatus(status, fitsErr);
    1793                     psError(PS_ERR_IO, true,
    1794                             PS_ERRORTEXT_psFits_WRITE_FAILED,
    1795                             fits->filename, fitsErr);
    1796                     psFree(iter);
    1797                     return false;
    1798                 }
    1799             } else {
    1800                 // the column was not found.
    1801                 psWarning("No column with the name '%s' exists in the table.",
    1802                           item->name);
    1803             }
    1804         }
    1805     }
    1806 
    1807     psFree(iter);
    1808 
    1809     return true;
    1810 }
     347                    fitsErr);
     348            return false;
     349        }
     350
     351        return true;
     352    }
     353
     354    bool psFitsDeleteExtName(psFits* fits,
     355                             const char* extname)
     356    {
     357        if (fits == NULL) {
     358            psError(PS_ERR_BAD_PARAMETER_NULL, true,
     359                    PS_ERRORTEXT_psFits_NULL);
     360            return false;
     361        }
     362
     363        // move to the specified HDU
     364        if (! psFitsMoveExtName(fits,extname) ) {
     365            psError(PS_ERR_BAD_PARAMETER_VALUE, false,
     366                    "Failed to delete HDU with the name '%s'",
     367                    extname);
     368            return false;
     369        }
     370
     371
     372        int status = 0;
     373
     374        // OK, now let's delete the HDU
     375        if (fits_delete_hdu(fits->fd, NULL, &status) != 0) {
     376            char fitsErr[MAX_STRING_LENGTH];
     377            (void)fits_get_errstatus(status, fitsErr);
     378            psError(PS_ERR_IO, true,
     379                    PS_ERRORTEXT_psFits_WRITE_FAILED,
     380                    fitsErr);
     381            return false;
     382        }
     383
     384        return true;
     385    }
     386
     387    int psFitsGetSize(const psFits* fits)
     388    {
     389        if (fits == NULL) {
     390            psError(PS_ERR_BAD_PARAMETER_NULL, true,
     391                    PS_ERRORTEXT_psFits_NULL);
     392            return 0;
     393        }
     394
     395        int num = 0;
     396        int status = 0;
     397
     398        if (fits_get_num_hdus(fits->fd, &num, &status) != 0) {
     399            char fitsErr[MAX_STRING_LENGTH];
     400            fits_get_errstatus(status, fitsErr);
     401            psError(PS_ERR_LOCATION_INVALID, true,
     402                    PS_ERRORTEXT_psFits_GETNUMHDUS_FAILED,
     403                    fitsErr);
     404            return 0;
     405        }
     406
     407        return num;
     408    }
     409
     410    psFitsType psFitsGetExtType(const psFits* fits)
     411    {
     412        if (fits == NULL) {
     413            psError(PS_ERR_BAD_PARAMETER_NULL, true,
     414                    PS_ERRORTEXT_psFits_NULL);
     415            return PS_FITS_TYPE_NONE;
     416        }
     417
     418        int status = 0;
     419        int hdutype = PS_FITS_TYPE_NONE;
     420
     421        if (fits_get_hdu_type(fits->fd, &hdutype, &status) != 0) {
     422            char fitsErr[MAX_STRING_LENGTH];
     423            fits_get_errstatus(status, fitsErr);
     424            psError(PS_ERR_LOCATION_INVALID, true,
     425                    PS_ERRORTEXT_psFits_GETHDUTYPE_FAILED,
     426                    fitsErr);
     427            return PS_FITS_TYPE_NONE;
     428        }
     429
     430        if (hdutype == PS_FITS_TYPE_IMAGE &&
     431                psFitsGetExtNum(fits) > 0 &&
     432                isHDUEmpty(fits)) {
     433            return PS_FITS_TYPE_ANY;
     434        }
     435
     436        return hdutype;
     437    }
     438
     439    bool psFitsTruncate(psFits* fits)
     440    {
     441        if (fits == NULL) {
     442            psError(PS_ERR_BAD_PARAMETER_NULL, true,
     443                    PS_ERRORTEXT_psFits_NULL);
     444            return PS_FITS_TYPE_NONE;
     445        }
     446
     447        int newEnd = psFitsGetExtNum(fits);
     448
     449        psFitsMoveLast(fits);
     450        int end = psFitsGetExtNum(fits);
     451
     452        // delete HDUs from end to beginning position + 1;
     453        for (int lcv=end;lcv > newEnd; lcv--) {
     454            if (! psFitsDeleteExtNum(fits,lcv,false)) {
     455                // failed to delete an HDU!?
     456                psError(PS_ERR_UNKNOWN, false,
     457                        "Failed to truncate file.  HDU #%d out of %d could not be deleted.",
     458                        lcv,end);
     459                return false;
     460            }
     461        }
     462
     463        return true;
     464    }
  • trunk/psLib/src/fits/psFits.h

    r5057 r5511  
    77 *  @author Robert DeSonia, MHPCC
    88 *
    9  *  @version $Revision: 1.21 $ $Name: not supported by cvs2svn $
    10  *  @date $Date: 2005-09-15 21:22:21 $
     9 *  @version $Revision: 1.22 $ $Name: not supported by cvs2svn $
     10 *  @date $Date: 2005-11-14 22:18:30 $
    1111 *
    1212 *  Copyright 2004-2005 Maui High Performance Computing Center, University of Hawaii
     
    1616#define PS_FITS_H
    1717
    18 #include<fitsio.h>
     18#include <fitsio.h>
    1919
    2020#include "psType.h"
     
    4949{
    5050    fitsfile* fd;                      ///< the CFITSIO fits files handle.
    51     const char* filename;              ///< the filename of the fits file
    52     bool writable;                     ///< Is the file writable?
    5351}
    5452psFits;
     
    5957 *                     NULL if the open of the FITS file failed
    6058 */
    61 psFits* psFitsAlloc(
    62     const char* name                   ///< the FITS file name
     59psFits* psFitsOpen(
     60    const char* filename,              ///< the FITS file name
     61    const char* mode
     62    /**< File open mode. Could be one of the following:
     63     *       'r' (read only),
     64     *       'r+' (read & write),
     65     *       'rw' (same as 'r+'), or
     66     *       'w' (create new file for writing)
     67     */
     68);
     69
     70/** Closes a FITS file.
     71 *
     72 *  @return bool      TRUE if FITS file was successfully closed, otherwise FALSE
     73 */
     74bool psFitsClose(
     75    psFits* fits                       ///< psFits object to close
    6376);
    6477
    6578/** Checks the type of a particular pointer.
    6679 *
    67  *  Uses the appropriate deallocation function in psMemBlock to check the ptr datatype.
     80 *  Uses the appropriate deallocation function in psMemBlock to check the ptr
     81 *  datatype.
    6882 *
    69  *  @return bool:       True if the pointer matches a psFits structure, false otherwise.
     83 *  @return bool:       True if the pointer matches a psFits structure, false
     84 *                      otherwise.
    7085 */
    7186bool psMemCheckFits(
     
    7691/** Moves the FITS HDU to the specified extension name.
    7792 *
    78  *  @return psFitsType    The HDU type, or PS_FITS_TYPE_NONE if move failed.
     93 *  @return bool        TRUE if the extension name was found and move was
     94 *                      successful, otherwise FALSE
    7995 */
    8096bool psFitsMoveExtName(
     
    85101/** Moves the FITS HDU to the specified extension number
    86102 *
    87  *  @return psFitsType    The HDU type, or PS_FITS_TYPE_NONE if move failed.
     103 *  @return bool        TRUE if the extension number was found and move was
     104 *                      successful, otherwise FALSE
    88105 */
    89106bool psFitsMoveExtNum(
     
    91108    int extnum,                        ///< the extension number to move to (zero is primary HDU)
    92109    bool relative                      ///< if true, extnum is a relative number to the current position
     110);
     111
     112/** Moves the FITS HDU to the end of the file
     113 *
     114 *  @return bool        TRUE if the move was successful, otherwise FALSE
     115*/
     116bool psFitsMoveLast(
     117    const psFits* fits                 ///< the psFits object to move
    93118);
    94119
     
    129154);
    130155
     156/** Remove the an HDU as specified by number
     157 *
     158 *  @return bool        TRUE if the specified HDU was removed, otherwise FALSE
     159 */
     160bool psFitsDeleteExtNum(
     161    psFits* fits,                      ///< the psFits object
     162    int extnum,                        ///< the extension number to delete (zero is primary HDU)
     163    bool relative                      ///< if true, extnum is a relative number to the current position
     164);
     165
     166/** Remove the an HDU as specified by extension name
     167 *
     168 *  @return bool        TRUE if the specified HDU was removed, otherwise FALSE
     169 */
     170bool psFitsDeleteExtName(
     171    psFits* fits,                      ///< the psFits object
     172    const char* extname                ///< the extension name to delete
     173);
     174
    131175/** Get the extension type of the current HDU.
    132176 *
     
    138182);
    139183
    140 /** Reads the header of the current HDU.
     184/** Delete all extensions after the current position
    141185 *
    142  *  @return psMetadata*   the header data
     186 *  @return bool        TRUE if the operation was successful, otherwise FALSE
    143187 */
    144 psMetadata* psFitsReadHeader(
    145     psMetadata* out,
    146     ///< The psMetadata to add the header data.  If null, a new psMetadata is created.
    147 
    148     const psFits* fits                 ///< the psFits object
    149 );
    150 
    151 /** Reads the header of all HDUs.  The current HDU is not changed.
    152  *
    153  *  @return psMetadata*      the header data set as a number of metadata entries
    154  */
    155 psMetadata* psFitsReadHeaderSet(
    156     psMetadata* out,
    157     ///< The psMetadata to add the header data via psMetadata items.  If null, a
    158     ///< new psMetadata is created.  The keys of the psMetadata are the extension names
    159     ///< of the cooresponding HDUs.
    160 
    161     const psFits* fits                       ///< the psFits object
    162 );
    163 
    164 /** Writes the values of the metadata to the current HDU header.
    165  *
    166  *  @return bool        if TRUE, the write was successful, otherwise FALSE.
    167  */
    168 bool psFitsWriteHeader(
    169     const psMetadata* output,          ///< the psMetadata data in which to write
     188bool psFitsTruncate(
    170189    psFits* fits                       ///< the psFits object
    171 );
    172 
    173 /** Reads an image, given the desired region and z-plane.
    174  *
    175  *  @return psImage*     the read image or NULL if there was an error.
    176  */
    177 psImage* psFitsReadImage(
    178     psImage* out,                      ///< a psImage to recycle.
    179     const psFits* fits,                ///< the psFits object
    180     psRegion region,                   ///< the region in the FITS image to read
    181     int z                              ///< the z-plane in the FITS image cube to read
    182 );
    183 
    184 /** Writes an image, given the desired region and z-plane.
    185  *
    186  *  @return bool        TRUE is the write was successful, otherwise FALSE.
    187  */
    188 bool psFitsWriteImage(
    189     psFits* fits,                      ///< the psFits object
    190     psMetadata* header,                ///< header items for the new HDU.  Can be NULL.
    191     const psImage* input,              ///< the image to output
    192     int depth                          ///< the number of z-planes of the FITS image data cube
    193 );
    194 
    195 /** Updates the FITS file image, given the desired region and z-plane.
    196  *
    197  *  @return bool        TRUE is the write was successful, otherwise FALSE.
    198  */
    199 bool psFitsUpdateImage(
    200     psFits* fits,                      ///< the psFits object
    201     const psImage* input,              ///< the image to output
    202     psRegion region,                   ///< the region in the FITS image to write
    203     int z                              ///< the z-planes of the FITS image data cube to write
    204 );
    205 
    206 /** Reads a table row.  The current HDU type must be either
    207  *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
    208  *
    209  *  @return psMetadata*    The table row's data.  The keys are the column names.
    210  */
    211 psMetadata* psFitsReadTableRow(
    212     const psFits* fits,                ///< the psFits object
    213     int row                            ///< row number to read
    214 );
    215 
    216 /** Reads a table column.  The current HDU type must be either
    217  *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
    218  *
    219  *  @return psArray*    Array of data items for the specified column or NULL
    220  *                      if an error occurred.
    221  */
    222 psArray* psFitsReadTableColumn(
    223     const psFits* fits,                ///< the psFits object
    224     const char* colname                ///< the column name
    225 );
    226 
    227 /** Reads a table column of numbers.  The current HDU type must be either
    228  *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
    229  *
    230  *  @return psVector*    Vector of data for the specified column or NULL
    231  *                       if an error occurred.
    232  */
    233 psVector* psFitsReadTableColumnNum(
    234     const psFits* fits,                ///< the psFits object
    235     const char* colname                ///< the column name
    236 );
    237 
    238 
    239 /** Reads a whole FITS table.  The current HDU type must be either
    240  *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
    241  *
    242  *  @return psArray*     Array of psMetadata items, which contains the output
    243  *                       data items of each row.
    244  *
    245  *  @see psFitsReadTableRow
    246  */
    247 psArray* psFitsReadTable(
    248     psFits* fits                       ///< the psFits object
    249 );
    250 
    251 /** Writes a whole FITS table.  The current HDU type must be either
    252  *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
    253  *
    254  *  @return bool        TRUE if the write was successful, otherwise FALSE
    255  *
    256  *  @see psFitsReadTableRow
    257  */
    258 bool psFitsWriteTable(
    259     psFits* fits,                      ///< the psFits object
    260     const psMetadata* header,          ///< header items for the new HDU.  Can be NULL.
    261     const psArray* table
    262     ///< Array of psMetadata items, which contains the output data items of each row.
    263 );
    264 
    265 /** Updates a FITS table.  The current HDU type must be either
    266  *  PS_FITS_TYPE_BINARY_TABLE or PS_FITS_TYPE_ASCII_TABLE.
    267  *
    268  *  @return bool        TRUE if the write was successful, otherwise FALSE
    269  *
    270  *  @see psFitsWriteTable
    271  */
    272 bool psFitsUpdateTable(
    273     psFits* fits,                ///< the psFits object
    274     const psMetadata* data,
    275     ///< Array of psMetadata items, which contains the output data items of each row.
    276     int row                            ///< the row number to update.
    277190);
    278191
Note: See TracChangeset for help on using the changeset viewer.