diff --git a/lib/allocator.h b/lib/allocator.h
index 3cea5906f1df279f0cfa6592515ac5d4c6d300f3..130804ad589d36f0f864713b8f9802f0f3eeaf16 100644
--- a/lib/allocator.h
+++ b/lib/allocator.h
@@ -1,5 +1,5 @@
-#ifndef LIB_ALLOCATOR__H__
-#define LIB_ALLOCATOR__H__
+#ifndef HAMMER_ALLOCATOR__H__
+#define HAMMER_ALLOCATOR__H__
 #include <sys/types.h>
 
 typedef struct arena* arena_t; // hidden implementation
diff --git a/src/bitreader.c b/src/bitreader.c
new file mode 100644
index 0000000000000000000000000000000000000000..431c351c7b1a7e97c224436367d150bb130e6c0d
--- /dev/null
+++ b/src/bitreader.c
@@ -0,0 +1,49 @@
+#include <stdint.h>
+#include "internal.h"
+#include "hammer.h"
+
+#define LSB(range) (0:range)
+#define MSB(range) (1:range)
+#define LDB(range,i) (((i)>>LSB(range))&((1<<(MSB(range)-LSB(range)+1))-1))
+
+long long read_bits(parse_state_t* state, int count) {
+  long long out = 0;
+  int offset = 0;
+  while (count) {
+    int segment, segment_len;
+    // Read a segment...
+    if (state->endianness & BIT_BIG_ENDIAN) {
+      if (count >= state->bit_offset) {
+	segment_len = state->bit_offset;
+	state->bit_offset = 8;
+	segment = state->input[state->index] & ((1 << segment_len) - 1);
+	state->index++;
+      } else {
+	segment_len = count;
+	state->bit_offset -= count;
+	segment = (state->input[state->index] >> state->bit_offset) & ((1 << segment_len) - 1);
+      }
+    } else { // BIT_LITTLE_ENDIAN
+      if (count + state->bit_offset >= 8) {
+	segment_len = 8 - state->bit_offset;
+	segment = (state->input[state->index] >> state->bit_offset);
+	state->index++;
+	state->bit_offset = 0;
+      } else {
+	segment_len = count;
+	segment = (state->input[state->index] >> state->bit_offset) & ((1 << segment_len) - 1);
+	state->bit_offset += segment_len;
+      }
+    }
+
+    // have a valid segment; time to assemble the byte
+    if (state->endianness & BYTE_BIG_ENDIAN) {
+      out = out << segment_len | segment;
+    } else { // BYTE_LITTLE_ENDIAN
+      out |= segment << offset;
+      offset += segment_len;
+    }
+    count -= segment_len;
+  }
+  return out;
+}
diff --git a/src/hammer.h b/src/hammer.h
index bbacb13d416b7b3ed85d09ffec5a6a05f1967833..d6c73eeba73a435ce5439e5c0596809da8be6204 100644
--- a/src/hammer.h
+++ b/src/hammer.h
@@ -15,6 +15,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
+#ifndef HAMMER_HAMMER__H
+#define HAMMER_HAMMER__H
 #include <glib.h>
 #include <stdint.h>
 
@@ -33,11 +35,16 @@
  *           at which it's been applied are memoized.
  *
  */
+#define BYTE_BIG_ENDIAN 0x1
+#define BIT_BIG_ENDIAN 0x2
+
 typedef struct parse_state {
   const uint8_t *input;
+  GHashTable *cache; 
   size_t index;
   size_t length;
-  GHashTable *cache; 
+  char bit_offset;
+  char endianness;
 } parse_state_t;
 
 typedef struct parse_result {
@@ -81,5 +88,4 @@ parser_t* epsilon_p();
 parser_t* and(parser_t* p);
 parser_t* not(parser_t* p);
 
-
-
+#endif // #ifndef HAMMER_HAMMER__H
diff --git a/src/internal.h b/src/internal.h
new file mode 100644
index 0000000000000000000000000000000000000000..0657de0a08f269db8f856122f1153604e3dca92b
--- /dev/null
+++ b/src/internal.h
@@ -0,0 +1,7 @@
+#ifndef HAMMER_INTERNAL__H
+#define HAMMER_INTERNAL__H
+#include "hammer.h"
+
+long long read_bits(parse_state_t* state, int count);
+
+#endif // #ifndef HAMMER_INTERNAL__H