/* File iraf2fits.c
* July 20, 2000
* By Doug Mink
*/
/* Module: iraf2fits.c (Translate IRAF header to FITS header)
* Purpose: Translate IRAF header to FITS header
* Copyright: 1998 Smithsonian Astrophysical Observatory
* You may do anything you like with this file except remove
* this copyright. The Smithsonian Astrophysical Observatory
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*/
#include <stdio.h> /* define stderr, FD, and NULL */
#include <unistd.h> /* define lseek arguments */
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "fitshead.h"
#ifndef VMS
#ifdef SYSV
#include <string.h> /* strlen, strcat, strcpy, strrchr */
#else
#include <strings.h> /* strlen, strcat, strcpy, rindex */
#define strchr index
#define strrchr rindex
#endif
#else
#include <string.h> /* strlen, strcat, strcpy, strrchr */
#endif
/* Parameters from iraf/lib/imhdr.h for IRAF version 1 images */
#define SZ_IMPIXFILE 79 /* name of pixel storage file */
#define SZ_IMHDRFILE 79 /* length of header storage file */
#define SZ_IMTITLE 79 /* image title string */
#define LEN_IMHDR 2052 /* length of std header */
/* Parameters from iraf/lib/imhdr.h for IRAF version 2 images */
#define SZ_IM2PIXFILE 255 /* name of pixel storage file */
#define SZ_IM2HDRFILE 255 /* name of header storage file */
#define SZ_IM2TITLE 383 /* image title string */
#define LEN_IM2HDR 2046 /* length of std header */
/* Offsets into header in bytes for parameters in IRAF version 1 images */
#define IM_PIXTYPE 16 /* datatype of the pixels */
#define IM_NDIM 20 /* number of dimensions */
#define IM_LEN 24 /* length (as stored) */
#define IM_PHYSLEN 52 /* physical length (as stored) */
#define IM_PIXOFF 88 /* offset of the pixels */
#define IM_PIXFILE 412 /* name of pixel storage file */
#define IM_HDRFILE 572 /* name of header storage file */
#define IM_TITLE 732 /* image name string */
/* Offsets into header in bytes for parameters in IRAF version 2 images */
#define IM2_PIXTYPE 10 /* datatype of the pixels */
#define IM2_NDIM 18 /* number of dimensions */
#define IM2_LEN 22 /* length (as stored) */
#define IM2_PHYSLEN 50 /* physical length (as stored) */
#define IM2_PIXOFF 86 /* offset of the pixels */
#define IM2_PIXFILE 126 /* name of pixel storage file */
#define IM2_HDRFILE 382 /* name of header storage file */
#define IM2_TITLE 638 /* image name string */
/* Codes from iraf/unix/hlib/iraf.h */
#define TY_CHAR 2
#define TY_SHORT 3
#define TY_INT 4
#define TY_LONG 5
#define TY_REAL 6
#define TY_DOUBLE 7
#define TY_COMPLEX 8
#define TY_POINTER 9
#define TY_STRUCT 10
#define TY_USHORT 11
#define TY_UBYTE 12
/* Local subroutines used to decode the IRAF header */
int irafgeti4();
char *irafgetc2();
char *irafgetc();
char *iraf2str();
static void same_path();
static int swapiraf=0; /* =1 if IRAF file has DEC/PC byte order */
static void irafswap();
static void irafswap2();
static void irafswap4();
static void irafswap8();
static int machswap();
/* Convert IRAF image header to FITS image header, returning FITS header */
char *
iraf2fits (hdrname, irafheader, imhver, nbiraf, nbfits)
char *hdrname; /* IRAF header file name (may be path) */
char *irafheader; /* IRAF image header */
int imhver; /* IRAF .imh format version number */
int nbiraf; /* Number of bytes in IRAF header */
int *nbfits; /* Number of bytes in FITS header (returned) */
{
int lfhead; /* Actual length of FITS header (returned) */
char *objname; /* object name from FITS file */
int i, j, k, nax, nbits;
char *pixname, *bang, *chead;
char *fitsheader;
int nblock, nlines;
char *fhead, *fhead1, *fp, endline[81];
char fitsline[81];
int pixtype;
char irafchar;
int n, ib, imu, pixoff, impixoff;
int imndim, imphyslen, impixtype;
char *calloc_errchk();
/* Set up last line of FITS header */
(void)strncpy (endline,"END", 3);
for (i = 3; i < 80; i++)
endline[i] = ' ';
endline[80] = 0;
if (imhver == 2) {
nlines = 7 + ((nbiraf - LEN_IM2HDR) / 81);
imndim = IM2_NDIM;
imphyslen = IM2_PHYSLEN;
impixtype = IM2_PIXTYPE;
impixoff = IM2_PIXOFF;
}
else {
nlines = 7 + (nbiraf - (4 * LEN_IMHDR) / 162);
imndim = IM_NDIM;
imphyslen = IM_PHYSLEN;
impixtype = IM_PIXTYPE;
impixoff = IM_PIXOFF;
}
/* Initialize FITS header */
nblock = (nlines * 80) / 2880;
*nbfits = (nblock + 3) * 2880;
fitsheader = calloc_errchk(*nbfits, 1, "FITS header");
fhead = fitsheader;
lfhead = 0;
(void)strncpy (fitsheader, endline, 80);
hputl (fitsheader, "SIMPLE", 1);
fhead = fhead + 80;
/* Set pixel size in FITS header */
pixtype = irafgeti4 (irafheader, impixtype);
switch (pixtype) {
case TY_UBYTE:
nbits = 8;
break;
case TY_CHAR:
nbits = 8;
break;
case TY_USHORT:
nbits = -16;
break;
case TY_SHORT:
nbits = 16;
break;
case TY_INT:
case TY_LONG:
nbits = 32;
break;
case TY_REAL:
nbits = -32;
break;
case TY_DOUBLE:
nbits = -64;
break;
default:
(void)fprintf(stderr,"Unsupported data type: %d\n", pixtype);
return (NULL);
}
hputi4 (fitsheader,"BITPIX",nbits);
fhead = fhead + 80;
/* Set image dimensions in FITS header */
nax = irafgeti4 (irafheader, imndim);
hputi4 (fitsheader,"NAXIS",nax);
fhead = fhead + 80;
n = irafgeti4 (irafheader, imphyslen);
hputi4 (fitsheader, "NAXIS1", n);
fhead = fhead + 80;
if (nax > 1) {
n = irafgeti4 (irafheader, imphyslen+4);
hputi4 (fitsheader, "NAXIS2", n);
}
else
hputi4 (fitsheader, "NAXIS2", 1);
fhead = fhead + 80;
if (nax > 2) {
n = irafgeti4 (irafheader, imphyslen+8);
hputi4 (fitsheader, "NAXIS3", n);
fhead = fhead + 80;
}
if (nax > 3) {
n = irafgeti4 (irafheader, imphyslen+12);
hputi4 (fitsheader, "NAXIS4", n);
fhead = fhead + 80;
}
/* Set object name in FITS header */
if (imhver == 2)
objname = irafgetc (irafheader, IM2_TITLE, SZ_IM2TITLE);
else
objname = irafgetc2 (irafheader, IM_TITLE, SZ_IMTITLE);
hputs (fitsheader,"OBJECT",objname);
free (objname);
fhead = fhead + 80;
/* Save image header filename in header */
hputs (fitsheader,"IMHFILE",hdrname);
fhead = fhead + 80;
/* Save image pixel file pathname in header */
if (imhver == 2)
pixname = irafgetc (irafheader, IM2_PIXFILE, SZ_IM2PIXFILE);
else {
pixname = irafgetc2 (irafheader, IM_PIXFILE, SZ_IMPIXFILE);
}
if (strncmp(pixname, "HDR", 3) == 0 )
same_path (pixname, hdrname);
if ((bang = strchr (pixname, '!')) != NULL )
hputs (fitsheader,"PIXFILE",bang+1);
else
hputs (fitsheader,"PIXFILE",pixname);
free (pixname);
fhead = fhead + 80;
/* Save image offset from star of pixel file */
pixoff = irafgeti4 (irafheader, impixoff);
pixoff = (pixoff - 1) * 2;
hputi4 (fitsheader, "PIXOFF", pixoff);
fhead = fhead + 80;
/* Save IRAF file format version in header */
hputi4 (fitsheader,"IMHVER",imhver);
fhead = fhead + 80;
/* Save flag as to whether to swap IRAF data for this file and machine */
if (machswap() != swapiraf)
hputl (fitsheader, "SWAPIRAF", 1);
else
hputl (fitsheader, "SWAPIRAF", 0);
fhead = fhead + 80;
/* Add user portion of IRAF header to FITS header */
fitsline[80] = 0;
if (imhver == 2) {
imu = LEN_IM2HDR;
chead = (char *)irafheader;
j = 0;
for (k = 0; k < 80; k++)
fitsline[k] = ' ';
for (i = imu; i < nbiraf; i++) {
irafchar = chead[i];
if (irafchar == 0)
break;
else if (irafchar == 10) {
(void)strncpy (fhead, fitsline, 80);
/* printf ("%80s\n",fitsline); */
j = 0;
fhead = fhead + 80;
for (k = 0; k < 80; k++)
fitsline[k] = ' ';
}
else {
if (j > 80) {
(void)strncpy (fhead, fitsline, 80);
/* printf ("%80s\n",fitsline); */
j = 9;
fhead = fhead + 80;
for (k = 0; k < 80; k++)
fitsline[k] = ' ';
}
if (irafchar > 32)
fitsline[j] = irafchar;
j++;
}
}
}
else {
imu = LEN_IMHDR;
chead = (char *) irafheader;
if (swapiraf == 1)
ib = 0;
else
ib = 1;
for (k = 0; k < 80; k++)
fitsline[k] = ' ';
j = 0;
for (i = imu; i < nbiraf; i=i+2) {
irafchar = chead[i+ib];
if (irafchar == 0)
break;
else if (irafchar == 10) {
(void)strncpy (fhead, fitsline, 80);
/* printf ("%80s\n",fitsline); */
j = 0;
fhead = fhead + 80;
for (k = 0; k < 80; k++)
fitsline[k] = ' ';
}
else {
if (j > 80) {
(void)strncpy (fhead, fitsline, 80);
/* printf ("%80s\n",fitsline); */
j = 9;
fhead = fhead + 80;
for (k = 0; k < 80; k++)
fitsline[k] = ' ';
}
if (irafchar > 32)
fitsline[j] = irafchar;
j++;
}
}
}
/* Add END to last line */
(void)strncpy (fhead, endline, 80);
lfhead = fhead - fitsheader + 80;
/* Find end of last 2880-byte block of header */
nblock = lfhead / 2880;
if (nblock*2880 < lfhead)
nblock = nblock + 1;
*nbfits = (nblock + 3) * 2880;
fhead = ksearch (fitsheader, "END") + 80;
fhead1 = fitsheader + *nbfits;
/* Pad rest of header with spaces */
strncpy (endline," ",3);
for (fp = fhead1; fp < fhead; fp = fp + 80) {
(void)strncpy (fp, endline,80);
}
return (fitsheader);
}
/* Put filename and header path together */
static void
same_path (pixname, hdrname)
char *pixname; /* IRAF pixel file pathname */
char *hdrname; /* IRAF image header file pathname */
{
int len;
char temp[SZ_IMPIXFILE];
/* Pixel file is in same directory as header */
if (strncmp(pixname, "HDR$", 4) == 0 ) {
(void)strncpy (temp, &pixname[4], SZ_IMPIXFILE);
(void)strncpy (pixname, hdrname, SZ_IMPIXFILE);
/* find the end of the pathname */
len = strlen(pixname);
#ifndef VMS
while( (len > 0) && (pixname[len-1] != '/') )
#else
while( (len > 0) && (pixname[len-1] != ']') && (pixname[len-1] != ':') )
#endif
len--;
/* add name */
pixname[len] = '\0';
(void)strncat(pixname, temp, SZ_IMPIXFILE);
}
/* Pixel file has same name as header file, but with .pix extension */
else if (strncmp (pixname, "HDR", 3) == 0 ) {
/* load entire header name string into name buffer */
(void)strncpy (pixname, hdrname, SZ_IMPIXFILE);
len = strlen (pixname);
pixname[len-3] = 'p';
pixname[len-2] = 'i';
pixname[len-1] = 'x';
}
return;
}
int
irafgeti4 (irafheader, offset)
char *irafheader; /* IRAF image header */
int offset; /* Number of bytes to skip before number */
{
char *ctemp;
int temp;
ctemp = (char *) &temp;
if ((int)irafheader[offset] > 0)
swapiraf = 1;
else
swapiraf = 0;
if (machswap() != swapiraf) {
ctemp[3] = irafheader[offset];
ctemp[2] = irafheader[offset+1];
ctemp[1] = irafheader[offset+2];
ctemp[0] = irafheader[offset+3];
}
else {
ctemp[0] = irafheader[offset];
ctemp[1] = irafheader[offset+1];
ctemp[2] = irafheader[offset+2];
ctemp[3] = irafheader[offset+3];
}
return (temp);
}
/* IRAFGETC2 -- Get character string from arbitrary part of v.1 IRAF header */
char *
irafgetc2 (irafheader, offset, nc)
char *irafheader; /* IRAF image header */
int offset; /* Number of bytes to skip before string */
int nc; /* Maximum number of characters in string */
{
char *irafstring, *string;
irafstring = irafgetc (irafheader, offset, 2*nc);
string = iraf2str (irafstring, nc);
return (string);
}
/* IRAFGETC -- Get character string from arbitrary part of IRAF header */
char *
irafgetc (irafheader, offset, nc)
char *irafheader; /* IRAF image header */
int offset; /* Number of bytes to skip before string */
int nc; /* Maximum number of characters in string */
{
char *ctemp;
int i;
ctemp = (char *) malloc (nc+1);
for (i = 0; i < nc; i++) {
ctemp[i] = irafheader[offset+i];
if (ctemp[i] > 0 && ctemp[i] < 32)
ctemp[i] = ' ';
}
return (ctemp);
}
/* Convert IRAF 2-byte/char string to 1-byte/char string */
char *
iraf2str (irafstring, nchar)
char *irafstring; /* IRAF 2-byte/character string */
int nchar; /* Number of characters in string */
{
char *string;
int i, j;
/* Set swap flag according to position of nulls in 2-byte characters */
if ((int)irafstring[0] != 0 && (int)irafstring[1] == 0)
swapiraf = 1;
else if ((int)irafstring[0] == 0 && (int)irafstring[1] != 0)
swapiraf = 0;
string = (char *) malloc (nchar+1);
/* Swap bytes, if requested */
if (swapiraf)
j = 0;
else
j = 1;
/* Convert appropriate byte of input to output character */
for (i = 0; i < nchar; i++) {
string[i] = irafstring[j];
j = j + 2;
}
return (string);
}
/* IRAFSWAP -- Reverse bytes of any type of vector in place */
static void
irafswap (bitpix, string, nbytes)
int bitpix; /* Number of bits per pixel */
/* 16 = short, -16 = unsigned short, 32 = int */
/* -32 = float, -64 = double */
char *string; /* Address of starting point of bytes to swap */
int nbytes; /* Number of bytes to swap */
{
switch (bitpix) {
case 16:
if (nbytes < 2) return;
irafswap2 (string,nbytes);
break;
case 32:
if (nbytes < 4) return;
irafswap4 (string,nbytes);
break;
case -16:
if (nbytes < 2) return;
irafswap2 (string,nbytes);
break;
case -32:
if (nbytes < 4) return;
irafswap4 (string,nbytes);
break;
case -64:
if (nbytes < 8) return;
irafswap8 (string,nbytes);
break;
}
return;
}
/* IRAFSWAP2 -- Swap bytes in string in place */
static void
irafswap2 (string,nbytes)
char *string; /* Address of starting point of bytes to swap */
int nbytes; /* Number of bytes to swap */
{
char *sbyte, temp, *slast;
slast = string + nbytes;
sbyte = string;
while (sbyte < slast) {
temp = sbyte[0];
sbyte[0] = sbyte[1];
sbyte[1] = temp;
sbyte= sbyte + 2;
}
return;
}
/* IRAFSWAP4 -- Reverse bytes of Integer*4 or Real*4 vector in place */
static void
irafswap4 (string,nbytes)
char *string; /* Address of Integer*4 or Real*4 vector */
int nbytes; /* Number of bytes to reverse */
{
char *sbyte, *slast;
char temp0, temp1, temp2, temp3;
slast = string + nbytes;
sbyte = string;
while (sbyte < slast) {
temp3 = sbyte[0];
temp2 = sbyte[1];
temp1 = sbyte[2];
temp0 = sbyte[3];
sbyte[0] = temp0;
sbyte[1] = temp1;
sbyte[2] = temp2;
sbyte[3] = temp3;
sbyte = sbyte + 4;
}
return;
}
/* IRAFSWAP8 -- Reverse bytes of Real*8 vector in place */
static void
irafswap8 (string,nbytes)
char *string; /* Address of Real*8 vector */
int nbytes; /* Number of bytes to reverse */
{
char *sbyte, *slast;
char temp[8];
slast = string + nbytes;
sbyte = string;
while (sbyte < slast) {
temp[7] = sbyte[0];
temp[6] = sbyte[1];
temp[5] = sbyte[2];
temp[4] = sbyte[3];
temp[3] = sbyte[4];
temp[2] = sbyte[5];
temp[1] = sbyte[6];
temp[0] = sbyte[7];
sbyte[0] = temp[0];
sbyte[1] = temp[1];
sbyte[2] = temp[2];
sbyte[3] = temp[3];
sbyte[4] = temp[4];
sbyte[5] = temp[5];
sbyte[6] = temp[6];
sbyte[7] = temp[7];
sbyte = sbyte + 8;
}
return;
}
static int
machswap ()
{
char *ctest;
int itest;
itest = 1;
ctest = (char *)&itest;
if (*ctest)
return (1);
else
return (0);
}
/*
* Feb 15 1996 New file
* Apr 10 1996 Add more documentation
* Apr 17 1996 Print error message on open failure
* Jun 5 1996 Add byte swapping (reversal); use streams
* Jun 10 1996 Make fixes after running lint
* Jun 12 1996 Use IMSWAP subroutines instead of local ones
* Jul 3 1996 Go back to using local IRAFSWAP subroutines
* Jul 3 1996 Write to pixel file from FITS header
* Jul 10 1996 Allocate all headers
* Aug 13 1996 Add unistd.h to include list
* Aug 26 1996 Allow 1-d images; fix comments; fix arguments after lint
* Aug 26 1996 Add IRAF header lingth argument to IRAFWIMAGE and IRAFWHEAD
* Aug 28 1996 Clean up code in IRAF2FITS
* Aug 30 1996 Use write instead of fwrite
* Sep 4 1996 Fix write mode bug
* Oct 15 1996 Drop unused variables
* Oct 17 1996 Minor fix after lint; cast arguments to STR2IRAF
*
* May 15 1997 Fix returned header length in IRAF2FITS
* Dec 15 1997 Add IRAF version 2 .imh files
*
* Jan 2 1998 Allow uneven length of user parameter lines in IRAF 2.11 headers
* Jan 13 1998 Allow uneven length of user parameter lines in IRAF 2.10 headers
* Jan 14 1998 Fix byte swapping so files can be read on any machine
* Apr 15 1998 Declare irafswap subroutines static
* Apr 17 1998 Add data type values for unsigned byte and unsigned short
* Jul 20 2000 Drop unused variables
*/
syntax highlighted by Code2HTML, v. 0.9.1