about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--common.mk2
-rw-r--r--converter/other/fitstopnm.c207
-rw-r--r--lib/util/floatcode.h185
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