summaryrefslogtreecommitdiff
path: root/src/upb_decoder.c
diff options
context:
space:
mode:
authorJoshua Haberman <joshua@reverberate.org>2010-06-03 12:07:07 -0700
committerJoshua Haberman <joshua@reverberate.org>2010-06-03 12:07:07 -0700
commita484ea0275f4d451d881b4edb1e1e4ae93be42a7 (patch)
tree76f152fc5091fb3fa012633f416828e33279ca9f /src/upb_decoder.c
parent0034e6fdb82b7e0623983f44ba4fc1c98393d032 (diff)
WIP: intrusive changes to upb_decoder.
Diffstat (limited to 'src/upb_decoder.c')
-rw-r--r--src/upb_decoder.c171
1 files changed, 80 insertions, 91 deletions
diff --git a/src/upb_decoder.c b/src/upb_decoder.c
index 32b8f16..5cb25a1 100644
--- a/src/upb_decoder.c
+++ b/src/upb_decoder.c
@@ -221,23 +221,6 @@ const uint8_t *upb_get_v_uint64_t_full(const uint8_t *buf, const uint8_t *end,
return buf;
}
-const uint8_t *upb_decode_wire_value(uint8_t *buf, uint8_t *end,
- upb_wire_type_t wt, upb_wire_value *wv,
- upb_status *status)
-{
- switch(wt) {
- case UPB_WIRE_TYPE_VARINT:
- return upb_get_v_uint64_t(buf, end, &wv->varint, status);
- case UPB_WIRE_TYPE_64BIT:
- return upb_get_f_uint64_t(buf, end, &wv->_64bit, status);
- case UPB_WIRE_TYPE_32BIT:
- return upb_get_f_uint32_t(buf, end, &wv->_32bit, status);
- default:
- status->code = UPB_STATUS_ERROR; // Doesn't handle delimited, groups.
- return end;
- }
-}
-
// Advances buf past the current wire value (of type wt), saving the result in
// outbuf.
static const uint8_t *skip_wire_value(const uint8_t *buf, const uint8_t *end,
@@ -293,7 +276,7 @@ static const uint8_t *upb_decode_value(const uint8_t *buf, const uint8_t *end,
typedef struct {
upb_msgdef *msgdef;
upb_fielddef *field;
- size_t end_offset; // For groups, 0.
+ int32_t end_offset; // For groups, 0.
} upb_decoder_frame;
struct upb_decoder {
@@ -304,7 +287,15 @@ struct upb_decoder {
// State pertaining to a particular decode (resettable).
// Stack entries store the offset where the submsg ends (for groups, 0).
upb_decoder_frame stack[UPB_MAX_NESTING], *top, *limit;
- size_t completed_offset;
+
+ // The current buffer.
+ upb_string *buf;
+
+ // The overall stream offset of the beginning of this buffer.
+ uint32_t stream_offset;
+
+ // The current offset in this buffer.
+ uint32_t buffer_offset;
};
upb_decoder *upb_decoder_new(upb_msgdef *msgdef)
@@ -331,16 +322,6 @@ void upb_decoder_reset(upb_decoder *d, upb_sink *sink)
d->top->end_offset = 0;
}
-// Parses a tag, places the result in *tag.
-upb_key upb_decoder_src_getkey(upb_decoder *d)
-{
- upb_key key;
- upb_fill_buffer(d);
- d->
- const uint8_t *ret = upb_get_v_uint32_t(buf, end, &tag_int, status);
- return ret;
-}
-
static const void *get_msgend(upb_decoder *d, const uint8_t *start)
@@ -395,9 +376,78 @@ static const void *pop(upb_decoder *d, const uint8_t *start, upb_status *status)
return get_msgend(d, start);
}
+// Parses a tag, places the result in *tag.
+upb_fielddef *upb_decoder_src_getdef(upb_decoder *d)
+{
+ uint32_t key;
+ upb_fill_buffer(d);
+ d->buf = upb_get_v_uint32_t(d->buf, d->end, &key, &d->status);
+ if (!upb_ok(status)) return NULL;
+ if(upb_wiretype_from_key(key) == UPB_WIRE_TYPE_END_GROUP) {
+ if(!isgroup(d->submsg_end)) {
+ upb_seterr(d->status, UPB_STATUS_ERROR, "End group seen but current "
+ "message is not a group, byte offset: %zd",
+ d->completed_offset + (completed - start));
+ return NULL;
+ }
+ submsg_end = pop(d, start, status);
+ msgdef = d->top->msgdef;
+ completed = buf;
+ return NULL;
+ }
+ // Look up field by tag number.
+ return upb_msg_itof(d->top->msgdef, upb_fieldnum_from_key(key));
+}
-size_t upb_decoder_decode(upb_decoder *d, upb_strptr str, upb_status *status)
+bool upb_decoder_src_getval(upb_src *src, upb_valueptr val)
{
+ if(upb_wiretype_from_key(d->key) == UPB_WIRE_TYPE_DELIMITED) {
+ int32_t delim_len;
+ d->buf = upb_get_INT32(d->buf, d->end, &delim_len, &d->status);
+ CHECK_STATUS(); // Checking decode_tag() and upb_get_INT32().
+ int32_t needed =
+ const uint8_t *delim_end = buf + delim_len;
+ if(f->type == UPB_TYPE(MESSAGE)) {
+ submsg_end = push(d, start, delim_end - start, f, status);
+ msgdef = d->top->msgdef;
+ } else {
+ if(f && upb_isstringtype(f->type)) {
+ int32_t str_start = buf - start;
+ uint32_t len = str_start + delim_len;
+ sink_status = upb_sink_onstr(d->sink, f, str, str_start, len, status);
+ } // else { TODO: packed arrays }
+ // If field was not found, it is skipped silently.
+ buf = delim_end; // Could be >end.
+ }
+ } else {
+ if(!upb_check_type(tag.wire_type, f->type)) {
+ buf = skip_wire_value(buf, end, tag.wire_type, status);
+ } else if (f->type == UPB_TYPE(GROUP)) {
+ submsg_end = push(d, start, 0, f, status);
+ msgdef = d->top->msgdef;
+ } else {
+ upb_value val;
+ buf = upb_decode_value(buf, end, f->type, upb_value_addrof(&val),
+ status);
+ CHECK_STATUS(); // Checking upb_decode_value().
+ sink_status = upb_sink_onvalue(d->sink, f, val, status);
+ }
+ }
+ CHECK_STATUS();
+
+ while(buf >= submsg_end) {
+ if(buf > submsg_end) {
+ upb_seterr(status, UPB_STATUS_ERROR, "Expected submsg end offset "
+ "did not lie on a tag/value boundary.");
+ goto err;
+ }
+ submsg_end = pop(d, start, status);
+ msgdef = d->top->msgdef;
+ }
+ // while(buf < d->packed_end) { TODO: packed arrays }
+ completed = buf;
+}
+
// buf is our current offset, moves from start to end.
const uint8_t *buf = (uint8_t*)upb_string_getrobuf(str);
const uint8_t *const start = buf; // ptr equivalent of d->completed_offset
@@ -421,68 +471,7 @@ size_t upb_decoder_decode(upb_decoder *d, upb_strptr str, upb_status *status)
// Parse/handle tag.
upb_tag tag;
buf = decode_tag(buf, end, &tag, status);
- if(tag.wire_type == UPB_WIRE_TYPE_END_GROUP) {
- CHECK_STATUS();
- if(!isgroup(submsg_end)) {
- upb_seterr(status, UPB_STATUS_ERROR, "End group seen but current "
- "message is not a group, byte offset: %zd",
- d->completed_offset + (completed - start));
- goto err;
- }
- submsg_end = pop(d, start, status);
- msgdef = d->top->msgdef;
- completed = buf;
- continue;
- }
-
- // Look up field by tag number.
- upb_fielddef *f = upb_msg_itof(msgdef, tag.field_number);
-
// Parse/handle field.
- if(tag.wire_type == UPB_WIRE_TYPE_DELIMITED) {
- int32_t delim_len;
- buf = upb_get_INT32(buf, end, &delim_len, status);
- CHECK_STATUS(); // Checking decode_tag() and upb_get_INT32().
- const uint8_t *delim_end = buf + delim_len;
- if(f && f->type == UPB_TYPE(MESSAGE)) {
- submsg_end = push(d, start, delim_end - start, f, status);
- msgdef = d->top->msgdef;
- } else {
- if(f && upb_isstringtype(f->type)) {
- int32_t str_start = buf - start;
- uint32_t len = str_start + delim_len;
- sink_status = upb_sink_onstr(d->sink, f, str, str_start, len, status);
- } // else { TODO: packed arrays }
- // If field was not found, it is skipped silently.
- buf = delim_end; // Could be >end.
- }
- } else {
- if(!f || !upb_check_type(tag.wire_type, f->type)) {
- buf = skip_wire_value(buf, end, tag.wire_type, status);
- } else if (f->type == UPB_TYPE(GROUP)) {
- submsg_end = push(d, start, 0, f, status);
- msgdef = d->top->msgdef;
- } else {
- upb_value val;
- buf = upb_decode_value(buf, end, f->type, upb_value_addrof(&val),
- status);
- CHECK_STATUS(); // Checking upb_decode_value().
- sink_status = upb_sink_onvalue(d->sink, f, val, status);
- }
- }
- CHECK_STATUS();
-
- while(buf >= submsg_end) {
- if(buf > submsg_end) {
- upb_seterr(status, UPB_STATUS_ERROR, "Expected submsg end offset "
- "did not lie on a tag/value boundary.");
- goto err;
- }
- submsg_end = pop(d, start, status);
- msgdef = d->top->msgdef;
- }
- // while(buf < d->packed_end) { TODO: packed arrays }
- completed = buf;
}
size_t read;
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback