summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pbstream.c84
-rw-r--r--pbstream.h3
-rw-r--r--tests.c12
3 files changed, 65 insertions, 34 deletions
diff --git a/pbstream.c b/pbstream.c
index dd91bb8..10f149c 100644
--- a/pbstream.c
+++ b/pbstream.c
@@ -91,6 +91,9 @@ static pbstream_status_t get_f_uint64_t(char **buf, char *end, uint64_t *val)
static int32_t zz_decode_32(uint32_t n) { return (n >> 1) ^ -(int32_t)(n & 1); }
static int64_t zz_decode_64(uint64_t n) { return (n >> 1) ^ -(int64_t)(n & 1); }
+/* Functions for reading wire values and converting them to values. These
+ * are generated with macros because they follow a higly consistent pattern. */
+
#define CHECK(func) do { \
pbstream_wire_type_t status = func; \
if(status != PBSTREAM_STATUS_OK) return status; \
@@ -106,11 +109,14 @@ static int64_t zz_decode_64(uint64_t n) { return (n >> 1) ^ -(int64_t)(n & 1); }
* pbstream_status_t get_TYPE(char **buf, char *end, size_t offset,
* pbstream_value *dst) */
#define GET(type, v_or_f, wire_t, val_t, member_name) \
- static pbstream_status_t get_ ## type(char **buf, char *end, size_t offset, \
+ static pbstream_status_t get_ ## type(struct pbstream_parse_state *s, \
+ char *buf, char *end, \
struct pbstream_value *d) { \
wire_t tmp; \
- CHECK(get_ ## v_or_f ## _ ## wire_t(buf, end, &tmp)); \
- wvtov_ ## type(tmp, &d->v.member_name, offset); \
+ char *b = buf; \
+ CHECK(get_ ## v_or_f ## _ ## wire_t(&b, end, &tmp)); \
+ wvtov_ ## type(tmp, &d->v.member_name, s->offset); \
+ s->offset += (b-buf); \
return PBSTREAM_STATUS_OK; \
}
@@ -134,22 +140,61 @@ T(SFIXED64, f, uint64_t, int64_t, int64) { *d = (int64_t)s; }
T(BOOL, v, uint32_t, bool, _bool) { *d = (bool)s; }
T(ENUM, v, uint32_t, int32_t, _enum) { *d = (int32_t)s; }
-#define T_DELIMITED(type) \
- T(type, v, uint32_t, struct pbstream_delimited, delimited) { \
+#define WVTOV_DELIMITED(type) \
+ WVTOV(type, uint32_t, struct pbstream_delimited) { \
d->offset = offset; \
d->len = s; \
}
-T_DELIMITED(STRING); /* We leave UTF-8 validation to the client. */
-T_DELIMITED(BYTES);
-T_DELIMITED(MESSAGE);
+WVTOV_DELIMITED(STRING);
+WVTOV_DELIMITED(BYTES);
+WVTOV_DELIMITED(MESSAGE);
#undef WVTOV
#undef GET
#undef T
#undef T_DELIMITED
+static pbstream_status_t get_STRING(struct pbstream_parse_state *s,
+ char *buf, char *end,
+ struct pbstream_value *d) {
+ uint32_t tmp;
+ CHECK(get_v_uint32_t(&buf, end, &tmp));
+ 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. */
+ return PBSTREAM_STATUS_OK;
+}
+
+static pbstream_status_t get_BYTES(struct pbstream_parse_state *s,
+ char *buf, char *end,
+ struct pbstream_value *d) {
+ uint32_t tmp;
+ CHECK(get_v_uint32_t(&buf, end, &tmp));
+ wvtov_BYTES(tmp, &d->v.delimited, s->offset);
+ s->offset = d->v.delimited.offset + d->v.delimited.len; /* skip bytes */
+ return PBSTREAM_STATUS_OK;
+}
+
+static pbstream_status_t get_MESSAGE(struct pbstream_parse_state *s,
+ char *buf, char *end,
+ struct pbstream_value *d) {
+ /* We're entering a sub-message. */
+ uint32_t tmp;
+ CHECK(get_v_uint32_t(&buf, end, &tmp));
+ wvtov_MESSAGE(tmp, &d->v.delimited, s->offset);
+ s->offset = d->v.delimited.offset; /* skip past only the tag. */
+ RESIZE_DYNARRAY(s->stack, s->stack_len+1);
+ struct pbstream_parse_stack_frame *frame = DYNARRAY_GET_TOP(s->stack);
+ frame->message_descriptor = d->field_descriptor->d.message;
+ frame->end_offset = d->v.delimited.offset + d->v.delimited.len;
+ int num_seen_fields = frame->message_descriptor->num_seen_fields;
+ INIT_DYNARRAY(frame->seen_fields, num_seen_fields, num_seen_fields);
+ return PBSTREAM_STATUS_OK;
+}
+
struct pbstream_type_info {
pbstream_wire_type_t expected_wire_type;
- pbstream_status_t (*get)(char **buf, char *end, size_t offset,
+ pbstream_status_t (*get)(struct pbstream_parse_state *s,
+ char *buf, char *end,
struct pbstream_value *d);
};
static struct pbstream_type_info type_info[] = {
@@ -228,7 +273,6 @@ static struct pbstream_field_descriptor *find_field_descriptor(
return NULL;
}
-/* Process actions associated with the end of a [sub-]message. */
pbstream_status_t process_message_end(struct pbstream_parse_state *s)
{
struct pbstream_parse_stack_frame *frame = DYNARRAY_GET_TOP(s->stack);
@@ -283,23 +327,9 @@ pbstream_status_t parse_field(struct pbstream_parse_state *s,
frame->seen_fields[fd->seen_field_num] = true;
}
- if(unlikely(fd->type == PBSTREAM_TYPE_MESSAGE)) {
- /* We're entering a sub-message. */
- CHECK(info->get(&b, end, val_offset, val));
- RESIZE_DYNARRAY(s->stack, s->stack_len+1);
- struct pbstream_parse_stack_frame *frame = DYNARRAY_GET_TOP(s->stack);
- frame->message_descriptor = fd->d.message;
- frame->end_offset = val->v.delimited.offset + val->v.delimited.len;
- s->offset = wv->v.delimited.offset; /* skip past only the tag. */
- int num_seen_fields = frame->message_descriptor->num_seen_fields;
- INIT_DYNARRAY(frame->seen_fields, num_seen_fields, num_seen_fields);
- } else {
- /* This is a scalar value. */
- *fieldnum = tag.field_number;
- val->type = fd->type;
- CHECK(info->get(&b, end, val_offset, val));
- s->offset += (b-buf);
- }
+ *fieldnum = tag.field_number;
+ val->field_descriptor = fd;
+ CHECK(info->get(s, b, end, val));
return PBSTREAM_STATUS_OK;
unknown_value:
diff --git a/pbstream.h b/pbstream.h
index 686692e..3c551d2 100644
--- a/pbstream.h
+++ b/pbstream.h
@@ -50,8 +50,9 @@ typedef enum pbstream_cardinality {
typedef int32_t pbstream_field_number_t;
/* A deserialized value as described in a .proto file. */
+struct pbstream_field_descriptor;
struct pbstream_value {
- pbstream_type_t type;
+ struct pbstream_field_descriptor *field_descriptor;
union {
double _double;
float _float;
diff --git a/tests.c b/tests.c
index 079f325..e429188 100644
--- a/tests.c
+++ b/tests.c
@@ -8,7 +8,7 @@ void test_get_v_uint64_t()
char zero[] = {0x00};
char *zero_buf = zero;
- uint64_t zero_val;
+ uint64_t zero_val = 0;
status = get_v_uint64_t(&zero_buf, zero_buf+sizeof(zero), &zero_val);
assert(status == PBSTREAM_STATUS_OK);
assert(zero_val == 0);
@@ -16,34 +16,34 @@ void test_get_v_uint64_t()
char one[] = {0x01};
char *one_buf = one;
- uint64_t one_val;
+ uint64_t one_val = 0;
status = get_v_uint64_t(&one_buf, one_buf+sizeof(one), &one_val);
assert(status == PBSTREAM_STATUS_OK);
assert(one_val == 1);
char twobyte[] = {0xAC, 0x02};
char *twobyte_buf = twobyte;
- uint64_t twobyte_val;
+ uint64_t twobyte_val = 0;
status = get_v_uint64_t(&twobyte_buf, twobyte_buf+sizeof(twobyte), &twobyte_val);
assert(status == PBSTREAM_STATUS_OK);
assert(twobyte_val == 300);
char ninebyte[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7F};
char *ninebyte_buf = ninebyte;
- uint64_t ninebyte_val;
+ uint64_t ninebyte_val = 0;
status = get_v_uint64_t(&ninebyte_buf, ninebyte_buf+sizeof(ninebyte), &ninebyte_val);
assert(status == PBSTREAM_STATUS_OK);
assert(ninebyte_val == (1LL<<63));
char overrun[] = {0x80, 0x01};
char *overrun_buf = overrun;
- uint64_t overrun_val;
+ uint64_t overrun_val = 0;
status = get_v_uint64_t(&overrun_buf, overrun_buf+sizeof(overrun)-1, &overrun_val);
assert(status == PBSTREAM_STATUS_INCOMPLETE);
char tenbyte[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x01};
char *tenbyte_buf = tenbyte;
- uint64_t tenbyte_val;
+ uint64_t tenbyte_val = 0;
status = get_v_uint64_t(&tenbyte_buf, tenbyte_buf+sizeof(tenbyte), &tenbyte_val);
assert(status == PBSTREAM_ERROR_UNTERMINATED_VARINT);
}
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback