/*----------------------------------------------------------------------------*/ /** @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 #include #include #include #include #include #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 */