aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/bytorder.h52
-rw-r--r--src/crunch.c45
2 files changed, 95 insertions, 2 deletions
diff --git a/src/bytorder.h b/src/bytorder.h
new file mode 100644
index 0000000..cb8231e
--- /dev/null
+++ b/src/bytorder.h
@@ -0,0 +1,52 @@
+#if defined(ALF_LSB_FIRST) && defined(ALF_MSB_FIRST)
+# error Cannot define both ALF_LSB_FIRST and ALF_MSB_FIRST
+#endif
+
+#if defined(ALF_LSB_FIRST) || defined(ALF_MSB_FIRST)
+# define ALF_ENDIAN_OK
+#endif
+
+/* try to get the byte order on this platform.
+ if we succeed, either ALF_LSB_FIRST or ALF_MSB_FIRST will
+ defined, and so will ALF_ENDIAN_OK. */
+
+#ifndef ALF_ENDIAN_OK
+# if defined(__BYTE_ORDER__)
+# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+# define ALF_LSB_FIRST
+# define ALF_ENDIAN_OK
+# else
+# if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+# define ALF_MSB_FIRST
+# define ALF_ENDIAN_OK
+# endif
+# endif
+# endif
+#endif
+
+#ifndef ALF_ENDIAN_OK
+# if defined(__LITTLE_ENDIAN__)
+# define ALF_LSB_FIRST
+# define ALF_ENDIAN_OK
+# else
+# if defined(__BIG_ENDIAN__)
+# define ALF_MSB_FIRST
+# define ALF_ENDIAN_OK
+# endif
+# endif
+#endif
+
+#ifdef ALF_ENDIAN_OK
+# ifdef ALF_LSB_FIRST
+# define HIBYTE 2
+# define MIDBYTE 1
+# define LOBYTE 0
+# else
+# define HIBYTE 1
+# define MIDBYTE 2
+# define LOBYTE 3
+# endif
+#else
+# warning Cannot determine endianness, falling back to safe but slow append_bit().
+# warning Recompile with -DALF_LSB_FIRST or -DALF_MSB_FIRST.
+#endif
diff --git a/src/crunch.c b/src/crunch.c
index cb1ce5f..82cc095 100644
--- a/src/crunch.c
+++ b/src/crunch.c
@@ -9,6 +9,7 @@
#include "u816.h"
#include "crunch.h"
#include "self.h"
+#include "bytorder.h"
#define INITIAL_BITS 9
#define MAX_BITS 12
@@ -122,14 +123,52 @@ void init_table(void) {
curr_token = INIT_TOKEN;
}
-void inc_output_len(void) {
- if(++output_len == MAX_INPUT_SIZE) {
+void check_output_len(void) {
+ if(output_len >= MAX_INPUT_SIZE) {
fprintf(stderr, "%s: fatal: compressed file would be >16MB.\n", self);
exit(1);
}
+}
+
+void inc_output_len(void) {
+ output_len++;
+ check_output_len();
output_buf[output_len] = 0;
}
+#ifdef ALF_ENDIAN_OK
+
+/* This is 20% faster, but it requires knowing the endianness of
+ the platform at compile time. See bytorder.h for gory details. */
+union { unsigned int ui; u8 bytes[4]; } ui2bytes;
+
+void store_token(int tok) {
+ if(opt_verbose > 1) {
+ printf("<%d >%d:%d #%d", in_pos, output_len, out_bitpos, tok);
+ if(tok == TOK_RESET)
+ fputs(" RESET", stdout);
+ else if(tok == TOK_END)
+ fputs(" END", stdout);
+ else if(tok < 256)
+ printf(" %s", fmt_chr(tok));
+ putchar('\n');
+ }
+
+ tok <<= (MAX_BITS - token_bits);
+ ui2bytes.ui = tok << (12 - out_bitpos);
+ output_buf[output_len] |= ui2bytes.bytes[HIBYTE];
+ output_buf[output_len + 1] = ui2bytes.bytes[MIDBYTE];
+ output_buf[output_len + 2] = ui2bytes.bytes[LOBYTE];
+ out_bitpos += token_bits;
+ output_len += out_bitpos / 8;
+ out_bitpos %= 8;
+
+ check_output_len();
+}
+
+#else
+
+/* Slower but portable. */
void append_bit(int bit) {
output_buf[output_len] |= (bit << (7 - out_bitpos));
out_bitpos++;
@@ -157,6 +196,7 @@ void store_token(int tok) {
append_bit(tok & mask ? 1 : 0);
}
}
+#endif
short match_token(void) {
short t, nt;
@@ -211,6 +251,7 @@ void crunch(void) {
init_table();
out_bitpos = 0;
in_pos = 0;
+ output_buf[output_len] = 0; /* just in case */
/* 0-byte input files don't get a TOK_RESET */
if(!input_len) {