diff options
-rw-r--r-- | common.mk | 2 | ||||
-rw-r--r-- | converter/other/fitstopnm.c | 207 | ||||
-rw-r--r-- | lib/util/floatcode.h | 185 |
3 files changed, 311 insertions, 83 deletions
diff --git a/common.mk b/common.mk index c69d3d6b..277c71a9 100644 --- a/common.mk +++ b/common.mk @@ -123,7 +123,7 @@ IMPORTINC_LIB_HEADERS := \ pm_gamma.h lum.h dithers.h IMPORTINC_LIB_UTIL_HEADERS := \ - bitarith.h bitreverse.h filename.h intcode.h mallocvar.h\ + bitarith.h bitreverse.h filename.h intcode.h floatcode.h mallocvar.h\ nsleep.h nstring.h pm_c_util.h shhopt.h \ wordaccess.h wordaccess_64_le.h wordaccess_gcc3_be.h wordaccess_gcc3_le.h \ wordaccess_generic.h \ diff --git a/converter/other/fitstopnm.c b/converter/other/fitstopnm.c index 4a6b7115..0d8753e5 100644 --- a/converter/other/fitstopnm.c +++ b/converter/other/fitstopnm.c @@ -39,11 +39,12 @@ #include <string.h> #include <float.h> +#include "pm_config.h" #include "pm_c_util.h" #include "mallocvar.h" +#include "floatcode.h" #include "shhopt.h" #include "pnm.h" -#include "pm_config.h" @@ -156,22 +157,7 @@ struct FITS_Header { }; -static void -swapbytes(void * const p, - unsigned int const nbytes) { -#if BYTE_ORDER == LITTLE_ENDIAN - unsigned char * const c = p; - unsigned int i; - for (i = 0; i < nbytes/2; ++i) { - unsigned char const orig = c[i]; - c[i] = c[nbytes-(i+1)]; - c[nbytes-(i+1)] = orig; - } -#endif -} - - -/* This code will deal properly with integers, no matter what the byte order +/* This code deals properly with integers, no matter what the byte order or integer size of the host machine. We handle sign extension manually to prevent problems with signed/unsigned characters. We read floating point values properly only when the host architecture conforms to IEEE-754. If @@ -180,84 +166,141 @@ swapbytes(void * const p, */ static void -readVal(FILE * const ifP, - int const bitpix, - double * const vP) { +readFitsChar(FILE * const ifP, + double * const vP) { - switch (bitpix) { - /* 8 bit FITS integers are unsigned */ - case 8: { + /* 8 bit FITS integers are unsigned */ + + int const ich = getc(ifP); + + if (ich == EOF) + pm_error("EOF / read error"); + else + *vP = ich; +} + + + +static void +readFitsShort(FILE * const ifP, + double * const vP) { + + int ich; + int ival; + unsigned char c[8]; + + ich = getc(ifP); + + if (ich == EOF) + pm_error("EOF / read error"); + + c[0] = ich; + + ich = getc(ifP); + + if (ich == EOF) + pm_error("EOF / read error"); + + c[1] = ich; + + if (c[0] & 0x80) + ival = ~0xFFFF | c[0] << 8 | c[1]; + else + ival = c[0] << 8 | c[1]; + + *vP = ival; +} + + + +static void +readFitsLong(FILE * const ifP, + double * const vP) { + + unsigned int i; + long int lval; + unsigned char c[4]; + + for (i = 0; i < 4; ++i) { int const ich = getc(ifP); if (ich == EOF) pm_error("EOF / read error"); - *vP = ich; - } break; + c[i] = ich; + } - case 16: { - int ich; - int ival; - unsigned char c[8]; + if (c[0] & 0x80) + lval = ~0xFFFFFFFF | c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3]; + else + lval = c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3] << 0; - ich = getc(ifP); + *vP = lval; +} + + + +static void +readFitsFloat(FILE * const ifP, + double * const vP) { + + unsigned int i; + pm_bigendFloat bigend; + + for (i = 0; i < 4; ++i) { + int const ich = getc(ifP); if (ich == EOF) pm_error("EOF / read error"); - c[0] = ich; - ich = getc(ifP); + bigend.bytes[i] = ich; + } + + *vP = pm_floatFromBigendFloat(bigend); +} + + + +static void +readFitsDouble(FILE * const ifP, + double * const vP) { + + unsigned int i; + pm_bigendDouble bigend; + + for (i = 0; i < 8; ++i) { + int const ich = getc(ifP); if (ich == EOF) pm_error("EOF / read error"); - c[1] = ich; - if (c[0] & 0x80) - ival = ~0xFFFF | c[0] << 8 | c[1]; - else - ival = c[0] << 8 | c[1]; - *vP = ival; - } break; + bigend.bytes[i] = ich; + } + + *vP = pm_doubleFromBigendDouble(bigend); +} + + + +static void +readVal(FILE * const ifP, + int const bitpix, + double * const vP) { + + switch (bitpix) { + case 8: + readFitsChar(ifP, vP); + break; + + case 16: + readFitsShort(ifP, vP); + break; - case 32: { - unsigned int i; - long int lval; - unsigned char c[4]; - - for (i = 0; i < 4; ++i) { - int const ich = getc(ifP); - if (ich == EOF) - pm_error("EOF / read error"); - c[i] = ich; - } - if (c[0] & 0x80) - lval = ~0xFFFFFFFF | c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3]; - else - lval = c[0] << 24 | c[1] << 16 | c[2] << 8 | c[3] << 0; - *vP = lval; - } break; + case 32: + readFitsLong(ifP, vP); + break; - case -32: { - unsigned int i; - unsigned char c[4]; - - for (i = 0; i < 4; ++i) { - int const ich = getc(ifP); - if (ich == EOF) - pm_error("EOF / read error"); - c[i] = ich; - } - swapbytes(c, 4); - *vP = *((float *)c); - } break; + case -32: + readFitsFloat(ifP, vP); + break; - case -64: { - unsigned int i; - unsigned char c[8]; - - for (i = 0; i < 8; ++i) { - int const ich = getc(ifP); - if (ich == EOF) - pm_error("EOF / read error"); - c[i] = ich; - } - swapbytes(c, 8); - *vP = *((double *)c); - } break; + case -64: + readFitsDouble(ifP, vP); + break; default: pm_error("Strange bitpix value %d in readVal()", bitpix); diff --git a/lib/util/floatcode.h b/lib/util/floatcode.h new file mode 100644 index 00000000..99aec256 --- /dev/null +++ b/lib/util/floatcode.h @@ -0,0 +1,185 @@ +#ifndef FLOATCODE_H_INCLUDED +#define FLOATCODE_H_INCLUDED + +#include "pm_config.h" /* BYTE_ORDER */ + +unsigned int const pm_byteOrder = BYTE_ORDER; + + +typedef struct { +/*---------------------------------------------------------------------------- + This is a big-endian representation of a 32 bit floating point number. + I.e. bytes[0] contains the sign bit, etc. + + On a big-endian machines, this is bit for bit identical to 'float'. + On a little-endian machine, it isn't. + + This is an important data type because decent file formats use + big-endian -- they don't care if some CPU happens to use some other + code for its own work. +-----------------------------------------------------------------------------*/ + unsigned char bytes[4]; +} pm_bigendFloat; + + +static __inline__ float +pm_floatFromBigendFloat(pm_bigendFloat const arg) { + + uint32_t retval; + + switch (pm_byteOrder) { + case BIG_ENDIAN: { + union { + pm_bigendFloat bigend; + float native; + } converter; + + converter.bigend = arg; + + retval = converter.native; + }; break; + case LITTLE_ENDIAN: { + union { + unsigned char bytes[4]; + float native; + } converter; + + converter.bytes[0] = arg.bytes[3]; + converter.bytes[1] = arg.bytes[2]; + converter.bytes[2] = arg.bytes[1]; + converter.bytes[3] = arg.bytes[0]; + + retval = converter.native; + } break; + } + return retval; +} + + + +static __inline__ pm_bigendFloat +pm_bigendFloatFromFloat(float const arg) { + + pm_bigendFloat retval; + + switch (pm_byteOrder) { + case BIG_ENDIAN: { + union { + pm_bigendFloat bigend; + float native; + } converter; + + converter.native = arg; + + retval = converter.bigend; + } break; + case LITTLE_ENDIAN: { + union { + unsigned char bytes[4]; + float native; + } converter; + + converter.native = arg; + + retval.bytes[0] = converter.bytes[3]; + retval.bytes[1] = converter.bytes[2]; + retval.bytes[2] = converter.bytes[1]; + retval.bytes[3] = converter.bytes[0]; + } break; + } + return retval; +} + +typedef struct { +/*---------------------------------------------------------------------------- + This is a big-endian representation of a 64 bit floating point number. + I.e. bytes[0] contains the sign bit, etc. + + On a big-endian machines, this is bit for bit identical to 'float'. + On a little-endian machine, it isn't. + + This is an important data type because decent file formats use + big-endian -- they don't care if some CPU happens to use some other + code for its own work. +-----------------------------------------------------------------------------*/ + unsigned char bytes[8]; +} pm_bigendDouble; + + +static __inline__ double +pm_doubleFromBigendDouble(pm_bigendDouble const arg) { + + uint32_t retval; + + switch (pm_byteOrder) { + case BIG_ENDIAN: { + union { + pm_bigendDouble bigend; + double native; + } converter; + + converter.bigend = arg; + + retval = converter.native; + }; break; + case LITTLE_ENDIAN: { + union { + unsigned char bytes[4]; + double native; + } converter; + + converter.bytes[0] = arg.bytes[7]; + converter.bytes[1] = arg.bytes[6]; + converter.bytes[2] = arg.bytes[5]; + converter.bytes[3] = arg.bytes[4]; + converter.bytes[4] = arg.bytes[3]; + converter.bytes[5] = arg.bytes[2]; + converter.bytes[6] = arg.bytes[1]; + converter.bytes[7] = arg.bytes[0]; + + retval = converter.native; + } break; + } + return retval; +} + + + +static __inline__ pm_bigendDouble +pm_bigendDoubleFromDouble(double const arg) { + + pm_bigendDouble retval; + + switch (pm_byteOrder) { + case BIG_ENDIAN: { + union { + pm_bigendDouble bigend; + double native; + } converter; + + converter.native = arg; + + retval = converter.bigend; + } break; + case LITTLE_ENDIAN: { + union { + unsigned char bytes[4]; + double native; + } converter; + + converter.native = arg; + + retval.bytes[0] = converter.bytes[7]; + retval.bytes[1] = converter.bytes[6]; + retval.bytes[2] = converter.bytes[5]; + retval.bytes[3] = converter.bytes[4]; + retval.bytes[4] = converter.bytes[3]; + retval.bytes[5] = converter.bytes[2]; + retval.bytes[6] = converter.bytes[1]; + retval.bytes[7] = converter.bytes[0]; + } break; + } + return retval; +} + +#endif |