summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua Haberman <joshua@reverberate.org>2009-02-25 22:11:53 -0800
committerJoshua Haberman <joshua@reverberate.org>2009-02-25 22:11:53 -0800
commite6b461c84af646e3cb93e1c9fc965f2da4b92f12 (patch)
tree9f09d5af45392355ddf281201ba72289d9781769
parent73978bfc74666fb13c6e65f8c9c4cec90de24236 (diff)
More tests and bugfixes -- parses its first proto!
-rw-r--r--pbstream.c30
-rw-r--r--pbstream.h8
-rw-r--r--tests.c37
3 files changed, 61 insertions, 14 deletions
diff --git a/pbstream.c b/pbstream.c
index c8711e7..82fc4d2 100644
--- a/pbstream.c
+++ b/pbstream.c
@@ -159,7 +159,9 @@ WVTOV_DELIMITED(MESSAGE);
static pbstream_status_t get_STRING(struct pbstream_parse_state *s, char *buf,
struct pbstream_value *d) {
uint32_t tmp;
- CHECK(get_v_uint32_t(&buf, &tmp));
+ char *b = buf;
+ CHECK(get_v_uint32_t(&b, &tmp));
+ s->offset += (b-buf); /* advance past length varint. */
wvtov_STRING(tmp, &d->v.delimited, s->offset);
s->offset = d->v.delimited.offset + d->v.delimited.len; /* skip string */
/* we leave UTF-8 validation to the client. */
@@ -169,7 +171,9 @@ static pbstream_status_t get_STRING(struct pbstream_parse_state *s, char *buf,
static pbstream_status_t get_BYTES(struct pbstream_parse_state *s, char *buf,
struct pbstream_value *d) {
uint32_t tmp;
- CHECK(get_v_uint32_t(&buf, &tmp));
+ char *b = buf;
+ CHECK(get_v_uint32_t(&b, &tmp));
+ s->offset += (b-buf); /* advance past length varint. */
wvtov_BYTES(tmp, &d->v.delimited, s->offset);
s->offset = d->v.delimited.offset + d->v.delimited.len; /* skip bytes */
return PBSTREAM_STATUS_OK;
@@ -179,9 +183,11 @@ static pbstream_status_t get_MESSAGE(struct pbstream_parse_state *s, char *buf,
struct pbstream_value *d) {
/* We're entering a sub-message. */
uint32_t tmp;
+ char *b = buf;
CHECK(get_v_uint32_t(&buf, &tmp));
+ s->offset += (b-buf); /* advance past length varint. */
wvtov_MESSAGE(tmp, &d->v.delimited, s->offset);
- s->offset = d->v.delimited.offset; /* skip past only the tag. */
+ /* Unlike STRING and BYTES, we *don't* advance past delimited here. */
if (unlikely(++s->top == s->limit)) {
/* Stack has grown beyond its limit, must reallocate. */
int cur_size = s->top - s->base;
@@ -254,7 +260,8 @@ static struct pbstream_field *find_field(struct pbstream_fieldset* fs,
pbstream_field_number_t num)
{
/* TODO: a hybrid array/hashtable structure. */
- if(num < fs->num_fields) return &fs->fields[num];
+ /* TODO: can zero be a tag number? */
+ if(num <= fs->num_fields) return &fs->fields[num-1];
else return NULL;
}
@@ -277,7 +284,7 @@ pbstream_status_t pbstream_parse_field(struct pbstream_parse_state *s,
struct pbstream_tag tag;
CHECK(parse_tag(&b, &tag));
- size_t val_offset = s->offset + (b-buf);
+ s->offset += (b-buf);
struct pbstream_field *fd = find_field(s->top->fieldset, tag.field_number);
pbstream_status_t unknown_value_status;
if(unlikely(!fd)) {
@@ -297,22 +304,25 @@ pbstream_status_t pbstream_parse_field(struct pbstream_parse_state *s,
unknown_value:
wv->type = tag.wire_type;
- CHECK(parse_unknown_value(&b, val_offset, wv));
+ CHECK(parse_unknown_value(&b, s->offset, wv));
s->offset += (b-buf);
return unknown_value_status;
}
void pbstream_init_parser(
struct pbstream_parse_state *state,
- struct pbstream_fieldset *toplevel_fieldset,
- void *user_data)
+ struct pbstream_fieldset *toplevel_fieldset)
{
state->offset = 0;
- state->user_data = user_data;
- /* Initial stack of <300b most protobufs are unlikely to nest >20 deep. */
+ /* Initial stack of <300b, most protobufs are unlikely to nest >20 deep. */
const int initial_stack = 20;
state->top = state->base = malloc(sizeof(*state->base) * initial_stack);
state->limit = state->base + initial_stack;
state->top->fieldset = toplevel_fieldset;
state->top->end_offset = SIZE_MAX;
}
+
+void pbstream_free_parser(struct pbstream_parse_state *state)
+{
+ free(state->base);
+}
diff --git a/pbstream.h b/pbstream.h
index 2713974..89e7329 100644
--- a/pbstream.h
+++ b/pbstream.h
@@ -9,7 +9,7 @@
/* A list of types as they can appear in a .proto file. */
typedef enum pbstream_type {
- PBSTREAM_TYPE_DOUBLE,
+ PBSTREAM_TYPE_DOUBLE = 0,
PBSTREAM_TYPE_FLOAT,
PBSTREAM_TYPE_INT32,
PBSTREAM_TYPE_INT64,
@@ -101,7 +101,6 @@ struct pbstream_parse_stack_frame {
/* The stream parser's state. */
struct pbstream_parse_state {
size_t offset;
- void *user_data;
struct pbstream_parse_stack_frame *base, *top, *limit;
};
@@ -110,8 +109,9 @@ struct pbstream_parse_state {
* unknown. */
void pbstream_init_parser(
struct pbstream_parse_state *state,
- struct pbstream_fieldset *toplevel_fieldset,
- void *user_data);
+ struct pbstream_fieldset *toplevel_fieldset);
+
+void pbstream_free_parser(struct pbstream_parse_state *state);
/* Status as returned by pbstream_parse(). Status codes <0 are fatal errors
* that cannot be recovered. Status codes >0 are unusual but nonfatal events,
diff --git a/tests.c b/tests.c
index 4277a19..ea87d79 100644
--- a/tests.c
+++ b/tests.c
@@ -42,9 +42,46 @@ void test_get_v_uint64_t()
assert(status == PBSTREAM_ERROR_UNTERMINATED_VARINT);
}
+void test_simple_proto()
+{
+ struct pbstream_fieldset *fieldset1 = malloc(sizeof(*fieldset1) +
+ 2*sizeof(struct pbstream_field));
+ fieldset1->num_fields = 2;
+ fieldset1->fields[0].field_number = 1;
+ fieldset1->fields[0].type = PBSTREAM_TYPE_INT32;
+ fieldset1->fields[1].field_number = 2;
+ fieldset1->fields[1].type = PBSTREAM_TYPE_STRING;
+
+ char message1[] = {0x08, 0x96, 0x01};
+ struct pbstream_parse_state s;
+ pbstream_init_parser(&s, fieldset1);
+ assert(s.offset == 0);
+ pbstream_field_number_t fieldnum;
+ struct pbstream_value val;
+ struct pbstream_wire_value wv;
+ assert(pbstream_parse_field(&s, message1, &fieldnum, &val, &wv) ==
+ PBSTREAM_STATUS_OK);
+ assert(val.field == &fieldset1->fields[0]);
+ assert(val.v.int32 == 150);
+ assert(s.offset == 3);
+ pbstream_free_parser(&s);
+
+ char message2[] = {0x12, 0x07, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67};
+ pbstream_init_parser(&s, fieldset1);
+ assert(pbstream_parse_field(&s, message2, &fieldnum, &val, &wv) ==
+ PBSTREAM_STATUS_OK);
+ assert(val.field == &fieldset1->fields[1]);
+ assert(val.v.delimited.offset == 2);
+ assert(val.v.delimited.len == 7);
+ assert(s.offset == 9);
+ pbstream_free_parser(&s);
+ free(fieldset1);
+}
+
int main()
{
test_get_v_uint64_t();
+ test_simple_proto();
printf("All tests passed.\n");
return 0;
}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback