add a few helpers for parsing binary data
parent
48f36eb580
commit
32cafc2b80
@ -0,0 +1,12 @@
|
||||
#include "parse.h"
|
||||
|
||||
// This function is supposed to tell the caller if there is more data to
|
||||
// read. However, we have several limits we could run into. We have our
|
||||
// own limit, which we check first, but then, if the bytestream is bound
|
||||
// to an I/O stream we should also try to find out if the I/O stream has
|
||||
// hit EOF.
|
||||
int bs_capacitycheck(struct bytestream* bs,size_t capacity) {
|
||||
if (bs->cur>=bs->max) return 0; // if EOF or error, return 0
|
||||
if (bs->max - bs->cur < capacity) return 0; // not EOF but less than that many bytes left
|
||||
return 1;
|
||||
}
|
@ -0,0 +1,112 @@
|
||||
#include "parse.h"
|
||||
|
||||
unsigned char bs_get(struct bytestream* bs) {
|
||||
unsigned char r;
|
||||
char c;
|
||||
if (bs->cur>=bs->max) { // EOF or already error state?
|
||||
bs->max=0; // signal error
|
||||
bs->cur=1;
|
||||
return 0; // return 0
|
||||
}
|
||||
switch (bs->type) {
|
||||
|
||||
case MEMBUF:
|
||||
r=bs->u.base[bs->cur];
|
||||
break;
|
||||
|
||||
case IOBUF:
|
||||
{
|
||||
int ret=buffer_getc(bs->u.b, &c);
|
||||
if (ret==1) {
|
||||
r=c;
|
||||
} else {
|
||||
bs->max=0;
|
||||
bs->cur=1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case BSTREAM:
|
||||
r=bs_get(bs->u.bs);
|
||||
break;
|
||||
|
||||
default:
|
||||
r=0; // cannot happen
|
||||
}
|
||||
++bs->cur;
|
||||
return r;
|
||||
}
|
||||
|
||||
int bs_err(struct bytestream* bs) {
|
||||
return (bs->cur > bs->max);
|
||||
}
|
||||
|
||||
#ifdef UNITTEST
|
||||
#include <assert.h>
|
||||
|
||||
int main() {
|
||||
struct bytestream bs = BS_FROM_MEMBUF("fnord\nx", 6);
|
||||
int i;
|
||||
char buf[7];
|
||||
|
||||
/* first test: membuf.
|
||||
* See if we get all the bytes we put in and then error is signaled */
|
||||
for (i=0; i<6; ++i) {
|
||||
buf[i] = bs_get(&bs);
|
||||
assert(buf[i] == "fnord\n"[i]);
|
||||
assert(!bs_err(&bs));
|
||||
}
|
||||
buf[6] = bs_get(&bs);
|
||||
/* We put an x there in memory.
|
||||
* If the bytestream range check failed, we'll get 'x', otherwise 0. */
|
||||
assert(buf[6] == 0);
|
||||
assert(bs_err(&bs));
|
||||
|
||||
/* second test: iobuf with no limit. Otherwise the same. */
|
||||
|
||||
struct buffer b;
|
||||
buffer_init_staticcontents(&b, "fnord\nx", 6); // this will let us read 6 bytes
|
||||
bs_init_iobuf(&bs, &b);
|
||||
for (i=0; i<6; ++i) {
|
||||
buf[i] = bs_get(&bs);
|
||||
assert(buf[i] == "fnord\n"[i]);
|
||||
assert(!bs_err(&bs));
|
||||
}
|
||||
buf[6] = bs_get(&bs);
|
||||
/* We put an x there in memory.
|
||||
* If the bytestream range check failed, we'll get 'x', otherwise 0. */
|
||||
assert(buf[6] == 0);
|
||||
assert(bs_err(&bs));
|
||||
|
||||
/* third test: iobuf with limit. Otherwise the same. */
|
||||
buffer_init_staticcontents(&b, "fnord\nx", 7); // this will let us read 7 bytes
|
||||
|
||||
bs_init_iobuf_size(&bs, &b, 6); // but we tell bytestream the limit is 6
|
||||
for (i=0; i<6; ++i) {
|
||||
buf[i] = bs_get(&bs);
|
||||
assert(buf[i] == "fnord\n"[i]);
|
||||
assert(!bs_err(&bs));
|
||||
}
|
||||
buf[6] = bs_get(&bs);
|
||||
/* We put an x there in the backing buffer.
|
||||
* If the bytestream range check failed, we'll get 'x', otherwise 0. */
|
||||
assert(buf[6] == 0);
|
||||
assert(bs_err(&bs));
|
||||
|
||||
/* fourth test: iobuf with EOF */
|
||||
buffer_init_staticcontents(&b, "fnord\nx", 6);
|
||||
bs_init_iobuf(&bs, &b); // bytestream has no limit but will hit EOF in backing buffer
|
||||
for (i=0; i<6; ++i) {
|
||||
buf[i] = bs_get(&bs);
|
||||
assert(buf[i] == "fnord\n"[i]);
|
||||
assert(!bs_err(&bs));
|
||||
}
|
||||
buf[6] = bs_get(&bs);
|
||||
/* We did not give the bytestream a limit, but the buffer should
|
||||
* refuse to return more. */
|
||||
assert(buf[6] == 0);
|
||||
assert(bs_err(&bs));
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,15 @@
|
||||
#include "parse.h"
|
||||
|
||||
void bs_init_bstream_size(struct bytestream* bs,struct bytestream* other,size_t maxlen) {
|
||||
bs->type = BSTREAM;
|
||||
// check if we have enough capacity in the parent bytestream
|
||||
if (bs_capacitycheck(other, maxlen)) {
|
||||
bs->cur = 0;
|
||||
bs->max = maxlen;
|
||||
} else {
|
||||
// nope, so set the new stream to error state right out of the box
|
||||
bs->cur = 1;
|
||||
bs->max = 0;
|
||||
}
|
||||
bs->u.bs=other;
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
#include "parse.h"
|
||||
|
||||
void bs_init_iobuf(struct bytestream* bs,struct buffer* b) {
|
||||
bs->type = IOBUF;
|
||||
bs->cur = 0;
|
||||
bs->max = (size_t)-1;
|
||||
bs->u.b=b;
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
#include "parse.h"
|
||||
|
||||
void bs_init_iobuf_size(struct bytestream* bs,struct buffer* b,size_t maxlen) {
|
||||
bs->type = IOBUF;
|
||||
bs->cur = 0;
|
||||
bs->max = maxlen;
|
||||
bs->u.b=b;
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
#include "parse.h"
|
||||
|
||||
void bs_init_membuf(struct bytestream* bs,const unsigned char* membuf,size_t len) {
|
||||
bs->type = MEMBUF;
|
||||
bs->cur = 0;
|
||||
bs->max = len;
|
||||
bs->u.base=membuf;
|
||||
}
|
||||
|
||||
#ifdef UNITTEST
|
||||
#include <assert.h>
|
||||
int main() {
|
||||
static struct bytestream bs;
|
||||
bs_init_membuf(&bs, "fnord\n", 6);
|
||||
char buf[7];
|
||||
int i;
|
||||
for (i=0; i<7; ++i) buf[i]=bs_get(&bs);
|
||||
assert(!memcmp(buf,"fnord\n",7)); // we should have gotten everything and then a 0 byte
|
||||
assert(bs_err(&bs)); // that should have set the error flag
|
||||
}
|
||||
#endif
|
@ -0,0 +1,29 @@
|
||||
#include "buffer.h"
|
||||
#include <mmap.h>
|
||||
|
||||
static ssize_t op() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void buffer_init_staticcontents(buffer* b, char* y, size_t len) {
|
||||
b->x=y;
|
||||
b->p=0; b->a=b->n=len;
|
||||
b->fd=-1;
|
||||
b->op=op;
|
||||
b->deinit=0;
|
||||
}
|
||||
|
||||
#ifdef UNITTEST
|
||||
#include <assert.h>
|
||||
|
||||
int main() {
|
||||
buffer b;
|
||||
buffer_init_staticcontents(&b, "fnord", 5);
|
||||
char tmp[6];
|
||||
assert(buffer_get(&b, tmp, 6) == 5);
|
||||
assert(!memcmp(tmp,"fnord",5));
|
||||
buffer_init_staticcontents(&b, tmp, sizeof tmp);
|
||||
buffer_puts(&b, "foo\n");
|
||||
assert(!memcmp(tmp, "foo\n", 4));
|
||||
}
|
||||
#endif
|
@ -0,0 +1,7 @@
|
||||
#include "buffer.h"
|
||||
#include <mmap.h>
|
||||
|
||||
void buffer_init_staticcontents_free(buffer* b, char* y, size_t len) {
|
||||
buffer_init_staticcontents(b, y, len);
|
||||
b->deinit=buffer_free;
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
#include "parse.h"
|
||||
|
||||
uint16_t prs_u16(struct bytestream* bs) {
|
||||
return bs_get(bs) | (bs_get(bs) << 8);
|
||||
}
|
||||
|
||||
#ifdef UNITTEST
|
||||
#include <assert.h>
|
||||
|
||||
int main() {
|
||||
struct bytestream bs = BS_FROM_MEMBUF("\x34\x12",2);
|
||||
assert(prs_u16(&bs) == 0x1234);
|
||||
assert(bs_err(&bs) == 0);
|
||||
assert(prs_u16(&bs) == 0);
|
||||
assert(bs_err(&bs));
|
||||
}
|
||||
#endif
|
@ -0,0 +1,17 @@
|
||||
#include "parse.h"
|
||||
|
||||
uint16_t prs_u16_big(struct bytestream* bs) {
|
||||
return (bs_get(bs) << 8) | bs_get(bs);
|
||||
}
|
||||
|
||||
#ifdef UNITTEST
|
||||
#include <assert.h>
|
||||
|
||||
int main() {
|
||||
struct bytestream bs = BS_FROM_MEMBUF("\x12\x34",2);
|
||||
assert(prs_u16_big(&bs) == 0x1234);
|
||||
assert(bs_err(&bs) == 0);
|
||||
assert(prs_u16_big(&bs) == 0);
|
||||
assert(bs_err(&bs));
|
||||
}
|
||||
#endif
|
@ -0,0 +1,17 @@
|
||||
#include "parse.h"
|
||||
|
||||
uint32_t prs_u32(struct bytestream* bs) {
|
||||
return bs_get(bs) | (bs_get(bs) << 8) | (bs_get(bs) << 16) | (bs_get(bs) << 24);
|
||||
}
|
||||
|
||||
#ifdef UNITTEST
|
||||
#include <assert.h>
|
||||
|
||||
int main() {
|
||||
struct bytestream bs = BS_FROM_MEMBUF("\x78\x56\x34\x12",4);
|
||||
assert(prs_u32(&bs) == 0x12345678);
|
||||
assert(bs_err(&bs) == 0);
|
||||
assert(prs_u32(&bs) == 0);
|
||||
assert(bs_err(&bs));
|
||||
}
|
||||
#endif
|
@ -0,0 +1,17 @@
|
||||
#include "parse.h"
|
||||
|
||||
uint32_t prs_u32_big(struct bytestream* bs) {
|
||||
return (bs_get(bs) << 24) | (bs_get(bs) << 16) | (bs_get(bs) << 8) | bs_get(bs);
|
||||
}
|
||||
|
||||
#ifdef UNITTEST
|
||||
#include <assert.h>
|
||||
|
||||
int main() {
|
||||
struct bytestream bs = BS_FROM_MEMBUF("\x12\x34\x56\x78",4);
|
||||
assert(prs_u32_big(&bs) == 0x12345678);
|
||||
assert(bs_err(&bs) == 0);
|
||||
assert(prs_u32_big(&bs) == 0);
|
||||
assert(bs_err(&bs));
|
||||
}
|
||||
#endif
|
@ -0,0 +1,21 @@
|
||||
#include "parse.h"
|
||||
|
||||
uint64_t prs_u64(struct bytestream* bs) {
|
||||
unsigned int i;
|
||||
uint64_t x = bs_get(bs);
|
||||
for (i=1; i<8; ++i)
|
||||
x |= ((uint64_t)bs_get(bs) << (i*8));
|
||||
return x;
|
||||
}
|
||||
|
||||
#ifdef UNITTEST
|
||||
#include <assert.h>
|
||||
|
||||
int main() {
|
||||
struct bytestream bs = BS_FROM_MEMBUF("\x78\x56\x34\x12\xef\xbe\xad\xde",8);
|
||||
assert(prs_u64(&bs) == 0xdeadbeef12345678);
|
||||
assert(bs_err(&bs) == 0);
|
||||
assert(prs_u64(&bs) == 0);
|
||||
assert(bs_err(&bs));
|
||||
}
|
||||
#endif
|
@ -0,0 +1,21 @@
|
||||
#include "parse.h"
|
||||
|
||||
uint64_t prs_u64_big(struct bytestream* bs) {
|
||||
unsigned int i;
|
||||
uint64_t x = bs_get(bs);
|
||||
for (i=1; i<8; ++i)
|
||||
x = (x << 8) | bs_get(bs);
|
||||
return x;
|
||||
}
|
||||
|
||||
#ifdef UNITTEST
|
||||
#include <assert.h>
|
||||
|
||||
int main() {
|
||||
struct bytestream bs = BS_FROM_MEMBUF("\xde\xad\xbe\xef\x12\x34\x56\x78",8);
|
||||
assert(prs_u64_big(&bs) == 0xdeadbeef12345678);
|
||||
assert(bs_err(&bs) == 0);
|
||||
assert(prs_u64_big(&bs) == 0);
|
||||
assert(bs_err(&bs));
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue