1
0
Fork 0
sattools/qfits/src/fits_rw.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 */