]> git.xonotic.org Git - xonotic/gmqcc.git/blobdiff - util.c
Merge pull request #141 from CurrentResident/big_endian_swap_fix
[xonotic/gmqcc.git] / util.c
diff --git a/util.c b/util.c
index 761d75316b10dd0a72d195e17f0f01f1bc71e0aa..030f54fa36e643ab091fbbeb98bb5db1e289df2b 100644 (file)
--- a/util.c
+++ b/util.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012, 2013
+ * Copyright (C) 2012, 2013, 2014
  *     Dale Weiler
  *     Wolfgang Bumiller
  *
@@ -22,6 +22,7 @@
  * SOFTWARE.
  */
 #define GMQCC_PLATFORM_HEADER
+#include <stdlib.h>
 #include "gmqcc.h"
 #include "platform.h"
 
@@ -110,42 +111,86 @@ void util_endianswap(void *_data, size_t length, unsigned int typesize) {
         switch (typesize) {
             case 1: return;
             case 2:
-                util_swap16((uint16_t*)_data, length>>1);
+                util_swap16((uint16_t*)_data, length);
                 return;
             case 4:
-                util_swap32((uint32_t*)_data, length>>2);
+                util_swap32((uint32_t*)_data, length);
                 return;
             case 8:
-                util_swap64((uint32_t*)_data, length>>3);
+                util_swap64((uint32_t*)_data, length<<1); /* swap64 operates on 32 bit words, thus scale to that length. */
                 return;
 
-            default: exit(EXIT_FAILURE); /* please blow the fuck up! */
+            default:
+                con_err ("util_endianswap: I don't know how to swap a %u byte structure!\n", typesize);
+                exit(EXIT_FAILURE); /* please blow the fuck up! */
         }
 #   endif
 #endif
 }
 
 /*
-* CRC algorithms vary in the width of the polynomial, the value of said polynomial,
-* the initial value used for the register, weather the bits of each byte are reflected
-* before being processed, weather the algorithm itself feeds input bytes through the
-* register or XORs them with a byte from one end and then straight into the table, as
-* well as (but not limited to the idea of reflected versions) where the final register
-* value becomes reversed, and finally weather the value itself is used to XOR the final
-* register value. AS such you can already imagine how painfully annoying CRCs are,
-* of course we stand to target Quake, which expects it's certain set of rules for proper
-* calculation of a CRC.
+* Based On:
+*   Slicing-by-8 algorithms by Michael E.
+*       Kounavis and Frank L. Berry from Intel Corp.
+*       http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
 *
-* In most traditional CRC algorithms on uses a reflected table driven method where a value
-* or register is reflected if it's bits are swapped around it's center. For example:
-* take the bits 0101 is the 4-bit reflection of 1010, and respectfully 0011 would be the
-* reflection of 1100. Quake however expects a NON-Reflected CRC on the output, but still
-* requires a final XOR on the values (0xFFFF and 0x0000) this is a standard CCITT CRC-16
-* which I respectfully as a programmer don't agree with.
+*   This code was made to be slightly less confusing with macros, which
+*   I suppose is somewhat ironic.
 *
-* So now you know what we target, and why we target it, despite how unsettling it may seem
-* but those are what Quake seems to request.
+*   The code had to be changed for non reflected on the output register
+*   since that's the method Quake uses.
+*
+*   The code also had to be changed for CRC16, which is slightly harder
+*   since the CRC32 method in the original Intel paper used a different
+*   bit order convention.
+*
+* Notes about the table:
+*   - It's exactly 4K in size
+*   - 64 elements fit in a cache line
+*   - can do 8 iterations unrolled 8 times for free
+*   - The first 256 elements of the table are standard CRC16 table
+*
+* Table can be generated with the following utility:
 */
+#if 0
+#include <stdio.h>
+#include <stdint.h>
+int main(void) {
+    for (unsigned i = 0; i < 0x100; ++i) {
+        uint16_t x = i << 8;
+        for (int j = 0; j < 8; ++j)
+            x = (x << 1) ^ ((x & 0x8000) ? 0x1021 : 0);
+        tab[0][i] = x;
+    }
+    for (unsigned i = 0; i < 0x100; ++i) {
+        uint16_t c = tab[0][i];
+        for (unsigned j = 1; j < 8; ++j) {
+            c = tab[0][c >> 8] ^ (c << 8);
+            tab[j][i] = c;
+        }
+    }
+    printf("static const uint16_t util_crc16_table[8][256] = {");
+    for (int i = 0; i < 8; ++i) {
+        printf("{\n");
+        for (int j = 0; j < 0x100; ++j) {
+            printf((j & 7) ? " " : "    ");
+            printf((j != 0x100-1) ? "0x%04X," : "0x%04X", tab[i][j]);
+            if ((j & 7) == 7)
+                printf("\n");
+        }
+        printf((i != 7) ? "}," : "}");
+    }
+    printf("};\n");
+    return 0;
+}
+#endif
+/*
+ * Non-Reflective version is present as well as a reference.
+ *
+ * TODO:
+ *  combine the crc16 into u32s and mask off low high for byte order
+ *  to make the arrays smaller.
+ */
 
 static const uint16_t util_crc16_table[8][256] = {{
     0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
@@ -414,11 +459,11 @@ static const uint16_t util_crc16_table[8][256] = {{
 }};
 
 /* Non - Reflected */
-uint16_t util_crc16(uint16_t current, const char *k, size_t len) {
+uint16_t util_crc16(uint16_t current, const char *GMQCC_RESTRICT k, size_t len) {
     register uint16_t h = current;
 
     /* don't load twice */
-    uint8_t *GMQCC_RESTRICT data = (uint8_t *GMQCC_RESTRICT)k;
+    const uint8_t *GMQCC_RESTRICT data = (const uint8_t *GMQCC_RESTRICT)k;
     size_t n;
 
     /* deal with the first bytes as bytes until we reach an 8 byte boundary */
@@ -440,8 +485,12 @@ uint16_t util_crc16(uint16_t current, const char *k, size_t len) {
             SELECT_DATA(1) ^
             SELECT_DATA(0);
         data += 8;
+        len  -= 8;
     }
 
+    #undef SELECT_BULK
+    #undef SELECT_DATA
+
     /* deal with the rest with the byte method */
     for (n = len & 7; n; --n)
         h = (uint16_t)(h << 8) ^ (*util_crc16_table)[(h >> 8) ^ *data++];
@@ -449,45 +498,11 @@ uint16_t util_crc16(uint16_t current, const char *k, size_t len) {
     return h;
 }
 
-#if 0
-/* for reference: table generated with this: */
-/* compile with cc -std=c99 */
-int main(void) {
-    for (unsigned i = 0; i < 0x100; ++i) {
-        uint16_t x = i << 8;
-        for (int j = 0; j < 8; ++j)
-            x = (x << 1) ^ ((x & 0x8000) ? 0x1021 : 0);
-        tab[0][i] = x;
-    }
-    for (unsigned i = 0; i < 0x100; ++i) {
-        uint16_t c = tab[0][i];
-        for (unsigned j = 1; j < 8; ++j) {
-            c = tab[0][c >> 8] ^ (c << 8);
-            tab[j][i] = c;
-        }
-    }
-
-    printf("static const uint16_t util_crc16_table[8][256] = {");
-    for (int i = 0; i < 8; ++i) {
-        printf("{\n");
-        for (int j = 0; j < 0x100; ++j) {
-            printf((j & 7) ? " " : "    ");
-            printf((j != 0x100-1) ? "0x%04X," : "0x%04X", tab[i][j]);
-            if ((j & 7) == 7)
-                printf("\n");
-        }
-        printf((i != 7) ? "}," : "}");
-    }
-    printf("};\n");
-    return 0;
-}
-#endif
-
 /*
  * modifier is the match to make and the transposition from it, while add is the upper-value that determines the
  * transposition from uppercase to lower case.
  */
-static GMQCC_INLINE size_t util_strtransform(const char *in, char *out, size_t outsz, const char *mod, int add) {
+static size_t util_strtransform(const char *in, char *out, size_t outsz, const char *mod, int add) {
     size_t sz = 1;
     for (; *in && sz < outsz; ++in, ++out, ++sz) {
         *out = (*in == mod[0])