Added bitwriter framework
This commit is contained in:
parent
ec7e9f2016
commit
1b9314e73e
3 changed files with 123 additions and 1 deletions
|
|
@ -25,6 +25,7 @@ PARSERS := \
|
||||||
|
|
||||||
OUTPUTS := bitreader.o \
|
OUTPUTS := bitreader.o \
|
||||||
hammer.o \
|
hammer.o \
|
||||||
|
bitwriter.o \
|
||||||
libhammer.a \
|
libhammer.a \
|
||||||
pprint.o \
|
pprint.o \
|
||||||
allocator.o \
|
allocator.o \
|
||||||
|
|
@ -42,7 +43,7 @@ all: libhammer.a test_suite
|
||||||
test_suite: test_suite.o libhammer.a
|
test_suite: test_suite.o libhammer.a
|
||||||
$(call hush, "Linking $@") $(CC) -o $@ $^ $(LDFLAGS)
|
$(call hush, "Linking $@") $(CC) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
libhammer.a: bitreader.o hammer.o pprint.o allocator.o datastructures.o \
|
libhammer.a: bitreader.o hammer.o pprint.o allocator.o datastructures.o bitwriter.o \
|
||||||
$(PARSERS:%=parsers/%.o)
|
$(PARSERS:%=parsers/%.o)
|
||||||
|
|
||||||
bitreader.o: test_suite.h
|
bitreader.o: test_suite.h
|
||||||
|
|
|
||||||
93
src/bitwriter.c
Normal file
93
src/bitwriter.c
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "hammer.h"
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
// This file provides the logical inverse of bitreader.c
|
||||||
|
struct HBitWriter_ {
|
||||||
|
uint8_t* buf;
|
||||||
|
size_t index;
|
||||||
|
size_t capacity;
|
||||||
|
char bit_offset; // unlike in bit_reader, this is always the number
|
||||||
|
// of used bits in the current byte. i.e., 0 always
|
||||||
|
// means that 8 bits are available for use.
|
||||||
|
char flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
// h_bit_writer_
|
||||||
|
HBitWriter *h_bit_writer_new() {
|
||||||
|
HBitWriter *writer = g_new0(HBitWriter, 1);
|
||||||
|
writer->buf = g_malloc0(writer->capacity = 8);
|
||||||
|
|
||||||
|
writer->flags = BYTE_BIG_ENDIAN | BIT_BIG_ENDIAN;
|
||||||
|
|
||||||
|
return writer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure there are at least [nbits] bits available at the end of the
|
||||||
|
* buffer. If the buffer is expanded, the added bits should be zeroed.
|
||||||
|
*/
|
||||||
|
static void h_bit_writer_reserve(HBitWriter* w, size_t nbits) {
|
||||||
|
// As is, this may overshoot by a byte, e.g., nbits=9, bit_offset=1.
|
||||||
|
// This will assume that the last partial byte is full, and reserve
|
||||||
|
// 2 bytes at the end, whereas only one is necessary.
|
||||||
|
//
|
||||||
|
// That said, this guarantees the postcondition that w->buf[w->index]
|
||||||
|
// is valid.
|
||||||
|
|
||||||
|
// Round up to bytes
|
||||||
|
int nbytes = (nbits + 7) / 8 + ((w->bit_offset != 0) ? 1 : 0);
|
||||||
|
size_t old_capacity = w->capacity;
|
||||||
|
while (w->index + nbytes >= w->capacity) {
|
||||||
|
w->buf = g_realloc(w->buf, w->capacity *= 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (old_capacity != w->capacity)
|
||||||
|
memset(w->buf + old_capacity, 0, w->capacity - old_capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void h_bit_writer_put(HBitWriter* w, unsigned long long data, size_t nbits) {
|
||||||
|
assert(nbits > 0); // Less than or equal to zero makes complete nonsense
|
||||||
|
|
||||||
|
// expand size...
|
||||||
|
h_bit_writer_reserve(w, nbits);
|
||||||
|
|
||||||
|
while (nbits) {
|
||||||
|
size_t count = MIN((size_t)(8 - w->bit_offset), nbits);
|
||||||
|
|
||||||
|
// select the bits to be written from the source
|
||||||
|
uint16_t bits;
|
||||||
|
if (w->flags & BYTE_BIG_ENDIAN) {
|
||||||
|
// read from the top few bits; masking will be done later.
|
||||||
|
bits = data >> (nbits - count);
|
||||||
|
} else {
|
||||||
|
// just copy the bottom byte over.
|
||||||
|
bits = data & 0xff;
|
||||||
|
data >>= count; // remove the bits that have just been used.
|
||||||
|
}
|
||||||
|
// mask off the unnecessary bits.
|
||||||
|
bits &= (1 << count) - 1;
|
||||||
|
|
||||||
|
// Now, push those bits onto the current byte...
|
||||||
|
if (w->flags & BIT_BIG_ENDIAN)
|
||||||
|
w->buf[w->index] = (w->buf[w->index] << count) | bits;
|
||||||
|
else
|
||||||
|
w->buf[w->index] = (w->buf[w->index] | (bits << 8)) >> count;
|
||||||
|
|
||||||
|
// update index and bit_offset.
|
||||||
|
w->bit_offset += count;
|
||||||
|
if (w->bit_offset == 8) {
|
||||||
|
w->bit_offset = 0;
|
||||||
|
w->index++;
|
||||||
|
}
|
||||||
|
nbits -= count;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t *h_bit_writer_get_buffer(HBitWriter* w, size_t *len);
|
||||||
|
|
||||||
|
// TESTS BELOW HERE
|
||||||
28
src/hammer.h
28
src/hammer.h
|
|
@ -79,6 +79,12 @@ typedef struct HParseResult_ {
|
||||||
HArena * arena;
|
HArena * arena;
|
||||||
} HParseResult;
|
} HParseResult;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: document me.
|
||||||
|
* Relevant functions: h_bit_writer_new, h_bit_writer_put, h_bit_writer_get_buffer, h_bit_writer_free
|
||||||
|
*/
|
||||||
|
typedef struct HBitWriter_ HBitWriter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type of an action to apply to an AST, used in the action() parser.
|
* Type of an action to apply to an AST, used in the action() parser.
|
||||||
* It can be any (user-defined) function that takes a HParseResult*
|
* It can be any (user-defined) function that takes a HParseResult*
|
||||||
|
|
@ -449,4 +455,26 @@ char* h_write_result_unamb(const HParsedToken* tok);
|
||||||
*/
|
*/
|
||||||
void h_pprint(FILE* stream, const HParsedToken* tok, int indent, int delta);
|
void h_pprint(FILE* stream, const HParsedToken* tok, int indent, int delta);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Document me
|
||||||
|
*/
|
||||||
|
HBitWriter *h_bit_writer_new(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Document me
|
||||||
|
*/
|
||||||
|
void h_bit_writer_put(HBitWriter* w, unsigned long long data, size_t nbits);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Document me
|
||||||
|
* Must not free [w] until you're done with the result.
|
||||||
|
* [len] is in bytes.
|
||||||
|
*/
|
||||||
|
uint8_t *h_bit_writer_get_buffer(HBitWriter* w, size_t *len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Document me
|
||||||
|
*/
|
||||||
|
void h_bit_writer_free(HBitWriter* w);
|
||||||
|
|
||||||
#endif // #ifndef HAMMER_HAMMER__H
|
#endif // #ifndef HAMMER_HAMMER__H
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue