409 lines
12 KiB
C
409 lines
12 KiB
C
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@file fits_rw.c
|
|
@author N. Devillard
|
|
@date Mar 2000
|
|
@version $Revision: 1.21 $
|
|
@brief FITS header reading/writing.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
$Id: fits_rw.c,v 1.21 2005/05/18 14:38:01 yjung Exp $
|
|
$Author: yjung $
|
|
$Date: 2005/05/18 14:38:01 $
|
|
$Revision: 1.21 $
|
|
*/
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
Includes
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include "fits_rw.h"
|
|
#include "fits_h.h"
|
|
#include "fits_p.h"
|
|
#include "simple.h"
|
|
#include "xmemory.h"
|
|
#include "qerror.h"
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
Private to this module
|
|
-----------------------------------------------------------------------------*/
|
|
static int is_blank_line(char * s)
|
|
{
|
|
int i ;
|
|
|
|
for (i=0 ; i<(int)strlen(s) ; i++) {
|
|
if (s[i]!=' ') return 0 ;
|
|
}
|
|
return 1 ;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
Function codes
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Read a FITS header from a file to an internal structure.
|
|
@param filename Name of the file to be read
|
|
@return Pointer to newly allocated qfits_header or NULL in error case.
|
|
|
|
This function parses a FITS (main) header, and returns an allocated
|
|
qfits_header object. The qfits_header object contains a linked-list of
|
|
key "tuples". A key tuple contains:
|
|
|
|
- A keyword
|
|
- A value
|
|
- A comment
|
|
- An original FITS line (as read from the input file)
|
|
|
|
Direct access to the structure is not foreseen, use accessor
|
|
functions in fits_h.h
|
|
|
|
Value, comment, and original line might be NULL pointers.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
qfits_header * qfits_header_read(char * filename)
|
|
{
|
|
/* Forward job to readext */
|
|
return qfits_header_readext(filename, 0);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Read a FITS header from a 'hdr' file.
|
|
@param filename Name of the file to be read
|
|
@return Pointer to newly allocated qfits_header or NULL in error case
|
|
|
|
This function parses a 'hdr' file, and returns an allocated qfits_header
|
|
object. A hdr file is an ASCII format were the header is written with a
|
|
carriage return after each line. The command dfits typically displays
|
|
a hdr file.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
qfits_header * qfits_header_read_hdr(char * filename)
|
|
{
|
|
qfits_header * hdr ;
|
|
FILE * in ;
|
|
char line[81];
|
|
char * key,
|
|
* val,
|
|
* com ;
|
|
int i, j ;
|
|
|
|
/* Check input */
|
|
if (filename==NULL) return NULL ;
|
|
|
|
/* Initialise */
|
|
key = val = com = NULL ;
|
|
|
|
/* Open the file */
|
|
if ((in=fopen(filename, "r"))==NULL) {
|
|
qfits_error("cannot read [%s]", filename) ;
|
|
return NULL ;
|
|
}
|
|
|
|
/* Create the header */
|
|
hdr = qfits_header_new() ;
|
|
|
|
/* Go through the file */
|
|
while (fgets(line, 81, in)!=NULL) {
|
|
for (i=0 ; i<81 ; i++) {
|
|
if (line[i] == '\n') {
|
|
for (j=i ; j<81 ; j++) line[j] = ' ' ;
|
|
line[80] = (char)0 ;
|
|
break ;
|
|
}
|
|
}
|
|
if (!strcmp(line, "END")) {
|
|
line[3] = ' ';
|
|
line[4] = (char)0 ;
|
|
}
|
|
|
|
/* Rule out blank lines */
|
|
if (!is_blank_line(line)) {
|
|
|
|
/* Get key, value, comment for the current line */
|
|
key = qfits_getkey(line);
|
|
val = qfits_getvalue(line);
|
|
com = qfits_getcomment(line);
|
|
|
|
/* If key or value cannot be found, trigger an error */
|
|
if (key==NULL) {
|
|
qfits_header_destroy(hdr);
|
|
fclose(in) ;
|
|
return NULL ;
|
|
}
|
|
/* Append card to linked-list */
|
|
qfits_header_append(hdr, key, val, com, NULL);
|
|
}
|
|
}
|
|
fclose(in) ;
|
|
|
|
/* The last key should be 'END' */
|
|
if (strlen(key)!=3) {
|
|
qfits_header_destroy(hdr);
|
|
return NULL ;
|
|
}
|
|
if (key[0]!='E' || key[1]!='N' || key[2]!='D') {
|
|
qfits_header_destroy(hdr);
|
|
return NULL ;
|
|
}
|
|
|
|
return hdr ;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Read a FITS header from a 'hdr' string
|
|
@param hdr_str String containing the hdr file
|
|
@param nb_char Number of characters in the string
|
|
@return Pointer to newly allocated qfits_header or NULL in error case
|
|
|
|
This function parses a 'hdr' string, and returns an allocated qfits_header
|
|
object.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
qfits_header * qfits_header_read_hdr_string(
|
|
unsigned char * hdr_str,
|
|
int nb_char)
|
|
{
|
|
qfits_header * hdr ;
|
|
char line[81];
|
|
char * key,
|
|
* val,
|
|
* com ;
|
|
int ind ;
|
|
int i, j ;
|
|
|
|
/* Check input */
|
|
if (hdr_str==NULL) return NULL ;
|
|
|
|
/* Initialise */
|
|
key = val = com = NULL ;
|
|
|
|
/* Create the header */
|
|
hdr = qfits_header_new() ;
|
|
|
|
/* Go through the file */
|
|
ind = 0 ;
|
|
while (ind <= nb_char - 80) {
|
|
strncpy(line, (char*)hdr_str + ind, 80) ;
|
|
line[80] = (char)0 ;
|
|
for (i=0 ; i<81 ; i++) {
|
|
if (line[i] == '\n') {
|
|
for (j=i ; j<81 ; j++) line[j] = ' ' ;
|
|
line[80] = (char)0 ;
|
|
break ;
|
|
}
|
|
}
|
|
if (!strcmp(line, "END")) {
|
|
line[3] = ' ';
|
|
line[4] = (char)0 ;
|
|
}
|
|
|
|
/* Rule out blank lines */
|
|
if (!is_blank_line(line)) {
|
|
|
|
/* Get key, value, comment for the current line */
|
|
key = qfits_getkey(line);
|
|
val = qfits_getvalue(line);
|
|
com = qfits_getcomment(line);
|
|
|
|
/* If key or value cannot be found, trigger an error */
|
|
if (key==NULL) {
|
|
qfits_header_destroy(hdr);
|
|
return NULL ;
|
|
}
|
|
/* Append card to linked-list */
|
|
qfits_header_append(hdr, key, val, com, NULL);
|
|
}
|
|
ind += 80 ;
|
|
}
|
|
|
|
/* The last key should be 'END' */
|
|
if (strlen(key)!=3) {
|
|
qfits_header_destroy(hdr);
|
|
return NULL ;
|
|
}
|
|
if (key[0]!='E' || key[1]!='N' || key[2]!='D') {
|
|
qfits_header_destroy(hdr);
|
|
return NULL ;
|
|
}
|
|
|
|
return hdr ;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Read an extension header from a FITS file.
|
|
@param filename Name of the FITS file to read
|
|
@param xtnum Extension number to read, starting from 0.
|
|
@return Newly allocated qfits_header structure.
|
|
|
|
Strictly similar to qfits_header_read() but reads headers from
|
|
extensions instead. If the requested xtension is 0, this function
|
|
returns the main header.
|
|
|
|
Returns NULL in case of error.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
qfits_header * qfits_header_readext(char * filename, int xtnum)
|
|
{
|
|
qfits_header* hdr ;
|
|
int n_ext ;
|
|
char line[81];
|
|
char * where ;
|
|
char * start ;
|
|
char * key,
|
|
* val,
|
|
* com ;
|
|
int seg_start ;
|
|
int seg_size ;
|
|
size_t size ;
|
|
|
|
/* Check input */
|
|
if (filename==NULL || xtnum<0)
|
|
return NULL ;
|
|
|
|
/* Check that there are enough extensions */
|
|
if (xtnum>0) {
|
|
n_ext = qfits_query_n_ext(filename);
|
|
if (xtnum>n_ext) {
|
|
return NULL ;
|
|
}
|
|
}
|
|
|
|
/* Get offset to the extension header */
|
|
if (qfits_get_hdrinfo(filename, xtnum, &seg_start, &seg_size)!=0) {
|
|
return NULL ;
|
|
}
|
|
|
|
/* Memory-map the input file */
|
|
start = falloc(filename, seg_start, &size) ;
|
|
if (start==NULL) return NULL ;
|
|
|
|
hdr = qfits_header_new() ;
|
|
where = start ;
|
|
while (1) {
|
|
memcpy(line, where, 80);
|
|
line[80] = (char)0;
|
|
|
|
/* Rule out blank lines */
|
|
if (!is_blank_line(line)) {
|
|
|
|
/* Get key, value, comment for the current line */
|
|
key = qfits_getkey(line);
|
|
val = qfits_getvalue(line);
|
|
com = qfits_getcomment(line);
|
|
|
|
/* If key or value cannot be found, trigger an error */
|
|
if (key==NULL) {
|
|
qfits_header_destroy(hdr);
|
|
hdr = NULL ;
|
|
break ;
|
|
}
|
|
/* Append card to linked-list */
|
|
qfits_header_append(hdr, key, val, com, line);
|
|
/* Check for END keyword */
|
|
if (strlen(key)==3)
|
|
if (key[0]=='E' &&
|
|
key[1]=='N' &&
|
|
key[2]=='D')
|
|
break ;
|
|
}
|
|
where += 80 ;
|
|
/* If reaching the end of file, trigger an error */
|
|
if ((int)(where-start)>=(int)(seg_size+80)) {
|
|
qfits_header_destroy(hdr);
|
|
hdr = NULL ;
|
|
break ;
|
|
}
|
|
}
|
|
fdealloc(start, seg_start, size) ;
|
|
return hdr ;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Pad an existing file with zeros to a multiple of 2880.
|
|
@param filename Name of the file to pad.
|
|
@return void
|
|
|
|
This function simply pads an existing file on disk with enough zeros
|
|
for the file size to reach a multiple of 2880, as required by FITS.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
void qfits_zeropad(char * filename)
|
|
{
|
|
struct stat sta ;
|
|
int size ;
|
|
int remaining;
|
|
FILE * out ;
|
|
char * buf;
|
|
|
|
if (filename==NULL) return ;
|
|
|
|
/* Get file size in bytes */
|
|
if (stat(filename, &sta)!=0) {
|
|
return ;
|
|
}
|
|
size = (int)sta.st_size ;
|
|
/* Compute number of zeros to pad */
|
|
remaining = size % FITS_BLOCK_SIZE ;
|
|
if (remaining==0) return ;
|
|
remaining = FITS_BLOCK_SIZE - remaining ;
|
|
|
|
/* Open file, dump zeros, exit */
|
|
if ((out=fopen(filename, "a"))==NULL)
|
|
return ;
|
|
buf = calloc(remaining, sizeof(char));
|
|
fwrite(buf, 1, remaining, out);
|
|
fclose(out);
|
|
free(buf);
|
|
return ;
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
/**
|
|
@brief Identify if a file is a FITS file.
|
|
@param filename name of the file to check
|
|
@return int 0, 1, or -1
|
|
|
|
Returns 1 if the file name looks like a valid FITS file. Returns
|
|
0 else. If the file does not exist, returns -1.
|
|
*/
|
|
/*----------------------------------------------------------------------------*/
|
|
int is_fits_file(char *filename)
|
|
{
|
|
FILE * fp ;
|
|
char * magic ;
|
|
int isfits ;
|
|
|
|
if (filename==NULL) return -1 ;
|
|
if ((fp = fopen(filename, "r"))==NULL) {
|
|
qfits_error("cannot open file [%s]", filename) ;
|
|
return -1 ;
|
|
}
|
|
|
|
magic = calloc(FITS_MAGIC_SZ+1, sizeof(char)) ;
|
|
fread(magic, 1, FITS_MAGIC_SZ, fp) ;
|
|
fclose(fp) ;
|
|
magic[FITS_MAGIC_SZ] = (char)0 ;
|
|
if (strstr(magic, FITS_MAGIC)!=NULL)
|
|
isfits = 1 ;
|
|
else
|
|
isfits = 0 ;
|
|
free(magic) ;
|
|
return isfits ;
|
|
}
|
|
|
|
/* vim: set ts=4 et sw=4 tw=75 */
|