Implemented roboust compile-time endianess check.
authorDale Weiler <killfieldengine@gmail.com>
Thu, 20 Dec 2012 23:07:06 +0000 (23:07 +0000)
committerDale Weiler <killfieldengine@gmail.com>
Thu, 20 Dec 2012 23:07:06 +0000 (23:07 +0000)
gmqcc.h
util.c

diff --git a/gmqcc.h b/gmqcc.h
index 1adcd5268ae868cf7181a211d1583de10daeeb6a..65a1fad5084c7f31954939fc14a1ad4737192112 100644 (file)
--- a/gmqcc.h
+++ b/gmqcc.h
 #   include <stdint.h>
 #endif
 
+/*
+ * Very roboust way at determining endianess at compile time: this handles
+ * almost every possible situation.  Otherwise a runtime check has to be
+ * performed.
+ */
+#define GMQCC_BYTE_ORDER_LITTLE 1234
+#define GMQCC_BYTE_ORDER_BIG    4321
+
+#if defined (__GNUC__) || defined (__GNU_LIBRARY__)
+#   if defined (__FreeBSD__) || defined (__OpenBSD__)
+#       include <sys/endian.h>
+#   elif defined (BSD) && (BSD >= 199103) || defined (__DJGPP__) || defined (__CYGWIN32__)
+#       include <machine/endiane.h>
+#   elif defined (__APPLE__)
+#       if defined (__BIG_ENDIAN__) && !defined(BIG_ENDIAN)
+#           define BIG_ENDIAN
+#       elif defined (__LITTLE_ENDIAN__) && !defined (LITTLE_ENDIAN)
+#           define LITTLE_ENDIAN
+#       endif
+#   elif !defined (__MINGW32__)
+#       include <endian.h>
+#       if !defined (__BEOS__)
+#           include <byteswap.h>
+#       endif
+#   endif
+#endif
+#if !defined(PLATFORM_BYTE_ORDER)
+#   if defined (LITTLE_ENDIAN) || defined (BIG_ENDIAN)
+#       if defined (LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
+#       elif !defined (LITTLE_ENDIAN) && defined (BIG_ENDIAN)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
+#       elif defined (BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
+#       elif defined (BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
+#       endif
+#   elif defined (_LITTLE_ENDIAN) || defined (_BIG_ENDIAN)
+#       if defined (_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
+#       elif !defined (_LITTLE_ENDIAN) && defined (_BIG_ENDIAN)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
+#       elif defined (_BYTE_ORDER) && (_BYTE_ORDER == _LITTLE_ENDIAN)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
+#       elif defined (_BYTE_ORDER) && (_BYTE_ORDER == _BIG_ENDIAN)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
+#       endif
+#   elif defined (__LITTLE_ENDIAN__) || defined (__BIG_ENDIAN__)
+#       if defined (__LITTLE_ENDIAN__) && !defined (__BIG_ENDIAN__)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
+#       elif !defined (__LITTLE_ENDIAN__) && defined (__BIG_ENDIAN__)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
+#       elif defined (__BYTE_ORDER__) && (__BYTE_ORDER__ == __LITTLE_ENDIAN__)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
+#       elif defined (__BYTE_ORDER__) && (__BYTE_ORDER__ == __BIG_ENDIAN__)
+#           define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
+#       endif
+#   endif
+#endif
+#if !defined (PLATFORM_BYTE_ORDER)
+#   if   defined (__aplha__) || defined (__aplha)    || defined (i386)       || \
+         defined (__i386__)  || defined (_M_I86)     || defined (_M_IX86)    || \
+         defined (__OS2__)   || defined (sun386)     || defined (__TURBOC__) || \
+         defined (vax)       || defined (vms)        || defined (VMS)        || \
+         defined (__VMS)     || defined (__x86_64__) || defined (_M_IA64)    || \
+         defined (_M_X64)    || defined (__i386)     || defined (__x86_64)
+#       define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_LITTLE
+#   elif defined (AMIGA)     || defined (applec)     || defined (__AS400__)  || \
+         defined (_CRAY)     || defined (__hppa)     || defined (__hp9000)   || \
+         defined (ibm370)    || defined (mc68000)    || defined (m68k)       || \
+         defined (__MRC__)   || defined (__MVS__)    || defined (__MWERKS__) || \
+         defined (sparc)     || defined (__sparc)    || defined (SYMANTEC_C) || \
+         defined (__TANDEM)  || defined (THINK_C)    || defined (__VMCMS__)  || \
+         defined (__PPC__)   || defined (__PPC)      || defined (PPC)
+#       define PLATFORM_BYTE_ORDER GMQCC_BYTE_ORDER_BIG
+#   else
+#       define PLATFORM_BYTE_ORDER -1
+#   endif
+#endif
+
+
+
 /*===================================================================*/
 /*=========================== util.c ================================*/
 /*===================================================================*/
diff --git a/util.c b/util.c
index 03cf40efda956590f2c8c97a0c545b3e6e4e1c1f..d277ae45b8df865eaa3e9182d9ade2abbef168ac 100644 (file)
--- a/util.c
+++ b/util.c
@@ -283,61 +283,76 @@ void util_endianswap(void *m, int s, int l) {
 }
 #endif
 
-static void util_swap16(uint16_t *d, size_t l) {
-    while (l--) {
-        d[l] = (d[l] << 8) | (d[l] >> 8);
+/*
+ * only required if big endian .. otherwise no need to swap
+ * data.
+ */   
+#if PLATFORM_BYTE_ORDER == GMQCC_BYTE_ORDER_BIG
+    static void util_swap16(uint16_t *d, size_t l) {
+        while (l--) {
+            d[l] = (d[l] << 8) | (d[l] >> 8);
+        }
     }
-}
 
-static void util_swap32(uint32_t *d, size_t l) {
-    while (l--) {
-        uint32_t v;
-        v = ((d[l] << 8) & 0xFF00FF00) | ((d[l] >> 8) & 0x00FF00FF);
-        d[l] = (v << 16) | (v >> 16);
+    static void util_swap32(uint32_t *d, size_t l) {
+        while (l--) {
+            uint32_t v;
+            v = ((d[l] << 8) & 0xFF00FF00) | ((d[l] >> 8) & 0x00FF00FF);
+            d[l] = (v << 16) | (v >> 16);
+        }
     }
-}
 
-/* Some strange system doesn't like constants that big, AND doesn't recognize an ULL suffix
- * so let's go the safe way
- */
-static void util_swap64(uint32_t *d, size_t l) {
-    /*
-    while (l--) {
-        uint64_t v;
-        v = ((d[l] << 8) & 0xFF00FF00FF00FF00) | ((d[l] >> 8) & 0x00FF00FF00FF00FF);
-        v = ((v << 16) & 0xFFFF0000FFFF0000) | ((v >> 16) & 0x0000FFFF0000FFFF);
-        d[l] = (v << 32) | (v >> 32);
-    }
-    */
-    size_t i;
-    for (i = 0; i < l; i += 2) {
-        uint32_t v1 = d[i];
-        d[i] = d[i+1];
-        d[i+1] = v1;
-        util_swap32(d+i, 2);
+    /* Some strange system doesn't like constants that big, AND doesn't recognize an ULL suffix
+     * so let's go the safe way
+     */
+    static void util_swap64(uint32_t *d, size_t l) {
+        /*
+        while (l--) {
+            uint64_t v;
+            v = ((d[l] << 8) & 0xFF00FF00FF00FF00) | ((d[l] >> 8) & 0x00FF00FF00FF00FF);
+            v = ((v << 16) & 0xFFFF0000FFFF0000) | ((v >> 16) & 0x0000FFFF0000FFFF);
+            d[l] = (v << 32) | (v >> 32);
+        }
+        */
+        size_t i;
+        for (i = 0; i < l; i += 2) {
+            uint32_t v1 = d[i];
+            d[i] = d[i+1];
+            d[i+1] = v1;
+            util_swap32(d+i, 2);
+        }
     }
-}
+#endif
 
 void util_endianswap(void *_data, size_t length, unsigned int typesize) {
-    /* I'm guessing there's no GOOD way to do this at compile time:
-     * FIXME:
-     */
+#   if PLATFORM_BYTE_ORDER == -1 /* runtime check */
     if (*((char*)&typesize))
         return;
-    if (typesize == 1)
-        return;
-    if (typesize == 2) {
-        util_swap16((uint16_t*)_data, length>>1);
-        return;
-    }
-    if (typesize == 4) {
-        util_swap32((uint32_t*)_data, length>>2);
-        return;
-    }
-    if (typesize == 4) {
-        util_swap64((uint32_t*)_data, length>>3);
+#else
+    /* prevent unused warnings */
+    (void) _data;
+    (void) length;
+    (void) typesize;
+
+#   if PLATFORM_BYTE_ORDER == GMQCC_BYTE_ORDER_LITTLE
         return;
-    }
+#   else
+        switch (typesize) {
+            case 1: return;
+            case 2:
+                util_swap16((uint16_t*)_data, length>>1);
+                return;
+            case 4:
+                util_swap32((uint32_t*)_data, length>>2);
+                return;
+            case 8:
+                util_swap64((uint32_t*)_data, length>>3);
+                return;
+
+            default: abort(); /* please blow the fuck up! */
+        }
+#   endif
+#endif
 }
 
 /*