Merge pull request #2 from thequux/master

New binary parsing code is in!
This commit is contained in:
Meredith L. Patterson 2012-04-28 18:09:19 -07:00
commit 4032db51f1
11 changed files with 199 additions and 11 deletions

2
.gitignore vendored
View file

@ -1,2 +1,4 @@
*.o
*~
*.a
src/test_suite

14
common.mk Normal file
View file

@ -0,0 +1,14 @@
CFLAGS := $(shell pkg-config --cflags glib-2.0)
LDFLAGS := $(shell pkg-config --libs glib-2.0)
CC := gcc
CFLAGS += -DINCLUDE_TESTS
.SUFFIX:
%.a:
-rm -f $@
ar crv $@ $^
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<

View file

@ -1,2 +0,0 @@
CFLAGS := $(shell pkg-config --cflags glib-2.0)
LDFLAGS := $(shell pkg-config --libs glib-2.0)

View file

@ -1,6 +1,4 @@
include ../config.mk
include ../common.mk
all: allocator.o
%.o: %.c
gcc $(CFLAGS) -c -o $@ $^

View file

@ -1,11 +1,11 @@
#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
arena_t new_arena(size_t block_size); // pass 0 for default...
void* arena_malloc(arena_t arena, size_t count); // TODO: needs the malloc attribute
void* arena_malloc(arena_t arena, size_t count) __attribute__(( malloc, alloc_size(2) ));
void delete_arena(arena_t arena);

10
src/Makefile Normal file
View file

@ -0,0 +1,10 @@
-include ../common.mk
all: libhammer.a test_suite
test_suite: test_suite.o libhammer.a
$(CC) $(LDFLAGS) -o $@ $^
libhammer.a: bitreader.o
bitreader.o: test_suite.h

112
src/bitreader.c Normal file
View file

@ -0,0 +1,112 @@
#include <stdint.h>
#include <stdio.h>
#include "internal.h"
#include "hammer.h"
#include "test_suite.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(input_stream_t* state, int count, char signed_p) {
long long out = 0;
int offset = 0;
long long msb = (!!signed_p) << (count - 1); // 0 if unsigned, else 1 << (nbits - 1)
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 ^ msb) - msb; // perform sign extension
}
#ifdef INCLUDE_TESTS
#define MK_INPUT_STREAM(buf,len,endianness_) \
{ \
.input = buf, \
.length = len, \
.index = 0, \
.bit_offset = (((endianness_) & BIT_BIG_ENDIAN) ? 8 : 0), \
.endianness = endianness_ \
}
static void test_bitreader_be(void) {
input_stream_t is = MK_INPUT_STREAM("\x6A\x5A", 2, BIT_BIG_ENDIAN | BYTE_BIG_ENDIAN);
g_check_cmpint(read_bits(&is, 3, false), ==, 0x03);
g_check_cmpint(read_bits(&is, 8, false), ==, 0x52);
g_check_cmpint(read_bits(&is, 5, false), ==, 0x1A);
}
static void test_bitreader_le(void) {
input_stream_t is = MK_INPUT_STREAM("\x6A\x5A", 2, BIT_LITTLE_ENDIAN | BYTE_LITTLE_ENDIAN);
g_check_cmpint(read_bits(&is, 3, false), ==, 0x02);
g_check_cmpint(read_bits(&is, 8, false), ==, 0x4D);
g_check_cmpint(read_bits(&is, 5, false), ==, 0x0B);
}
static void test_largebits_be(void) {
input_stream_t is = MK_INPUT_STREAM("\x6A\x5A", 2, BIT_BIG_ENDIAN | BYTE_BIG_ENDIAN);
g_check_cmpint(read_bits(&is, 11, false), ==, 0x352);
g_check_cmpint(read_bits(&is, 5, false), ==, 0x1A);
}
static void test_largebits_le(void) {
input_stream_t is = MK_INPUT_STREAM("\x6A\x5A", 2, BIT_LITTLE_ENDIAN | BYTE_LITTLE_ENDIAN);
g_check_cmpint(read_bits(&is, 11, false), ==, 0x26A);
g_check_cmpint(read_bits(&is, 5, false), ==, 0x0B);
}
static void test_offset_largebits_be(void) {
input_stream_t is = MK_INPUT_STREAM("\x6A\x5A", 2, BIT_BIG_ENDIAN | BYTE_BIG_ENDIAN);
g_check_cmpint(read_bits(&is, 5, false), ==, 0xD);
g_check_cmpint(read_bits(&is, 11, false), ==, 0x25A);
}
static void test_offset_largebits_le(void) {
input_stream_t is = MK_INPUT_STREAM("\x6A\x5A", 2, BIT_LITTLE_ENDIAN | BYTE_LITTLE_ENDIAN);
g_check_cmpint(read_bits(&is, 5, false), ==, 0xA);
g_check_cmpint(read_bits(&is, 11, false), ==, 0x2D3);
}
void register_bitreader_tests(void) {
g_test_add_func("/core/bitreader/be", test_bitreader_be);
g_test_add_func("/core/bitreader/le", test_bitreader_le);
g_test_add_func("/core/bitreader/largebits-be", test_largebits_be);
g_test_add_func("/core/bitreader/largebits-le", test_largebits_le);
g_test_add_func("/core/bitreader/offset-largebits-be", test_offset_largebits_be);
g_test_add_func("/core/bitreader/offset-largebits-le", test_offset_largebits_le);
}
#endif // #ifdef INCLUDE_TESTS

View file

@ -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,23 @@
* at which it's been applied are memoized.
*
*/
typedef struct parse_state {
#define BYTE_BIG_ENDIAN 0x1
#define BIT_BIG_ENDIAN 0x2
#define BIT_LITTLE_ENDIAN 0x0
#define BYTE_LITTLE_ENDIAN 0x0
typedef struct input_stream {
// This should be considered to be a really big value type.
const uint8_t *input;
size_t index;
size_t length;
char bit_offset;
char endianness;
} input_stream_t;
typedef struct parse_state {
GHashTable *cache;
input_stream_t input_stream;
} parse_state_t;
typedef struct parse_result {
@ -81,5 +95,4 @@ parser_t* epsilon_p();
parser_t* and(parser_t* p);
parser_t* not(parser_t* p);
#endif // #ifndef HAMMER_HAMMER__H

10
src/internal.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef HAMMER_INTERNAL__H
#define HAMMER_INTERNAL__H
#include "hammer.h"
#define false 0
#define true 1
long long read_bits(input_stream_t* state, int count, char signed_p);
#endif // #ifndef HAMMER_INTERNAL__H

14
src/test_suite.c Normal file
View file

@ -0,0 +1,14 @@
#include "hammer.h"
#include "test_suite.h"
extern void register_bitreader_tests();
int main(int argc, char** argv) {
g_test_init(&argc, &argv, NULL);
// register various test suites...
register_bitreader_tests();
g_test_run();
}

17
src/test_suite.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef HAMMER_TEST_SUITE__H
#define HAMMER_TEST_SUITE__H
// Equivalent to g_assert_*, but not using g_assert...
#define g_check_cmpint(n1, op, n2) { \
typeof (n1) _n1 = (n1); \
typeof (n2) _n2 = (n2); \
if (!(_n1 op _n2)) { \
g_test_message("Check failed: (%s): (%d %s %d)", \
#n1 " " #op " " #n2, \
_n1, #op, _n2); \
g_test_fail(); \
} \
}
#endif // #ifndef HAMMER_TEST_SUITE__H