442 lines
11 KiB
C
442 lines
11 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 */
|