diff --git a/src/upb_decoder.c b/src/upb_decoder.c index 7db8243905..f028297f3d 100644 --- a/src/upb_decoder.c +++ b/src/upb_decoder.c @@ -197,9 +197,8 @@ static upb_flow_t upb_push(upb_decoder *d, upb_fielddef *f, UPB_GROUP_END_OFFSET : d->buf_stream_offset + (d->ptr - upb_string_getrobuf(d->buf)) + upb_value_getint32(submsg_len); - upb_msgdef *md = upb_downcast_msgdef(f->def); - d->top->msgdef = md; - d->msgdef = md; + d->top->f = f; + d->msgdef = upb_downcast_msgdef(f->def); upb_dstate_setmsgend(d); upb_flow_t ret = upb_dispatch_startsubmsg(&d->dispatcher, f); if (ret == UPB_SKIPSUBMSG) { @@ -217,9 +216,9 @@ static upb_flow_t upb_push(upb_decoder *d, upb_fielddef *f, static upb_flow_t upb_pop(upb_decoder *d) { --d->top; + d->msgdef = upb_downcast_msgdef(d->top->f->def); upb_dstate_setmsgend(d); - d->msgdef = d->top->msgdef; - return upb_dispatch_endsubmsg(&d->dispatcher); + return upb_dispatch_endsubmsg(&d->dispatcher, d->top->f); } void upb_decoder_run(upb_src *src, upb_status *status) { @@ -228,7 +227,7 @@ void upb_decoder_run(upb_src *src, upb_status *status) { d->ptr = NULL; d->end = NULL; // Force a buffer pull. d->submsg_end = (void*)0x1; // But don't let end-of-message get triggered. - d->msgdef = d->top->msgdef; + d->msgdef = upb_downcast_msgdef(d->top->f->def); // TODO: handle UPB_SKIPSUBMSG #define CHECK_FLOW(expr) if ((expr) == UPB_BREAK) { /*assert(!upb_ok(status));*/ goto callback_err; } @@ -373,9 +372,6 @@ void upb_decoder_sethandlers(upb_src *src, upb_handlers *handlers) { upb_dispatcher_reset(&d->dispatcher, handlers, true); d->top = d->stack; d->buf_stream_offset = 0; - // The top-level message is not delimited (we can keep receiving data for it - // indefinitely), so we treat it like a group. - d->top->end_offset = 0; } void upb_decoder_init(upb_decoder *d, upb_msgdef *msgdef) { @@ -385,7 +381,9 @@ void upb_decoder_init(upb_decoder *d, upb_msgdef *msgdef) { }; upb_src_init(&d->src, &vtbl); upb_dispatcher_init(&d->dispatcher); - d->stack[0].msgdef = msgdef; + d->f.def = UPB_UPCAST(msgdef); + d->stack[0].f = &d->f; + // Never want to end top-level message, so treat it like a group. d->stack[0].end_offset = UPB_GROUP_END_OFFSET; d->limit = &d->stack[UPB_MAX_NESTING]; d->buf = NULL; diff --git a/src/upb_decoder.h b/src/upb_decoder.h index 6a9f7cca01..98b1b94435 100644 --- a/src/upb_decoder.h +++ b/src/upb_decoder.h @@ -30,7 +30,7 @@ extern "C" { // The decoder keeps a stack with one entry per level of recursion. // upb_decoder_frame is one frame of that stack. typedef struct { - upb_msgdef *msgdef; + upb_fielddef *f; size_t end_offset; // For groups, 0. } upb_decoder_frame; @@ -69,6 +69,8 @@ struct _upb_decoder { // Where we will store any errors that occur. upb_status *status; + // A fake fielddef for storing the msgdef for the top-level message. + upb_fielddef f; upb_decoder_frame stack[UPB_MAX_NESTING]; }; diff --git a/src/upb_def.c b/src/upb_def.c index b12ed14678..3b2144367d 100644 --- a/src/upb_def.c +++ b/src/upb_def.c @@ -1471,7 +1471,7 @@ static void upb_baredecoder_run(upb_src *src, upb_status *status) { } // Detect end-of-submessage. while(d->offset >= *top) { - CHECK(upb_dispatch_endsubmsg(&d->dispatcher)); + CHECK(upb_dispatch_endsubmsg(&d->dispatcher, &f)); d->offset = *(top--); } } diff --git a/src/upb_msg.c b/src/upb_msg.c index 951b5e00ac..89913dd58e 100644 --- a/src/upb_msg.c +++ b/src/upb_msg.c @@ -270,7 +270,8 @@ static upb_flow_t upb_msgpopulator_startsubmsg(void *_p, upb_fielddef *f, return UPB_CONTINUE; } -static upb_flow_t upb_msgpopulator_endsubmsg(void *_p) { +static upb_flow_t upb_msgpopulator_endsubmsg(void *_p, upb_fielddef *f) { + (void)f; upb_msgpopulator *p = _p; --p->top; return UPB_CONTINUE; diff --git a/src/upb_stream.h b/src/upb_stream.h index 229cf86cd2..34e27101c4 100644 --- a/src/upb_stream.h +++ b/src/upb_stream.h @@ -98,7 +98,8 @@ typedef upb_flow_t (*upb_value_handler_t)(void *closure, typedef upb_flow_t (*upb_startsubmsg_handler_t)(void *closure, struct _upb_fielddef *f, upb_handlers *delegate_to); -typedef upb_flow_t (*upb_endsubmsg_handler_t)(void *closure); +typedef upb_flow_t (*upb_endsubmsg_handler_t)(void *closure, + struct _upb_fielddef *f); typedef upb_flow_t (*upb_unknownval_handler_t)(void *closure, upb_field_number_t fieldnum, upb_value val); @@ -126,7 +127,7 @@ typedef upb_flow_t (*upb_unknownval_handler_t)(void *closure, // return UPB_CONTINUE; // } // -// static upb_flow_t endsubmsg(void *closure) { +// static upb_flow_t endsubmsg(void *closure, upb_fielddef *f) { // // Called when a submessage ends. // return UPB_CONTINUE; // } @@ -207,7 +208,8 @@ INLINE upb_flow_t upb_dispatch_startmsg(upb_dispatcher *d); INLINE upb_flow_t upb_dispatch_endmsg(upb_dispatcher *d); INLINE upb_flow_t upb_dispatch_startsubmsg(upb_dispatcher *d, struct _upb_fielddef *f); -INLINE upb_flow_t upb_dispatch_endsubmsg(upb_dispatcher *d); +INLINE upb_flow_t upb_dispatch_endsubmsg(upb_dispatcher *d, + struct _upb_fielddef *f); INLINE upb_flow_t upb_dispatch_value(upb_dispatcher *d, struct _upb_fielddef *f, upb_value val); INLINE upb_flow_t upb_dispatch_unknownval(upb_dispatcher *d, diff --git a/src/upb_stream_vtbl.h b/src/upb_stream_vtbl.h index 10ee9172e2..e9a4043ca8 100644 --- a/src/upb_stream_vtbl.h +++ b/src/upb_stream_vtbl.h @@ -186,6 +186,12 @@ INLINE upb_flow_t upb_startsubmsg_nop(void *closure, struct _upb_fielddef *f, return UPB_CONTINUE; } +INLINE upb_flow_t upb_endsubmsg_nop(void *closure, struct _upb_fielddef *f) { + (void)closure; + (void)f; + return UPB_CONTINUE; +} + INLINE upb_flow_t upb_unknownval_nop(void *closure, upb_field_number_t fieldnum, upb_value val) { (void)closure; @@ -199,7 +205,7 @@ INLINE void upb_register_handlerset(upb_handlers *h, upb_handlerset *set) { if (!set->endmsg) set->endmsg = &upb_nop; if (!set->value) set->value = &upb_value_nop; if (!set->startsubmsg) set->startsubmsg = &upb_startsubmsg_nop; - if (!set->endsubmsg) set->endsubmsg = &upb_nop; + if (!set->endsubmsg) set->endsubmsg = &upb_endsubmsg_nop; if (!set->unknownval) set->unknownval = &upb_unknownval_nop; h->set = set; } @@ -264,7 +270,8 @@ INLINE upb_flow_t upb_dispatch_startsubmsg(upb_dispatcher *d, return ret; } -INLINE upb_flow_t upb_dispatch_endsubmsg(upb_dispatcher *d) { +INLINE upb_flow_t upb_dispatch_endsubmsg(upb_dispatcher *d, + struct _upb_fielddef *f) { upb_flow_t ret; if (--d->top->depth == 0) { ret = d->top->handlers.set->endmsg(d->top->handlers.closure); @@ -273,7 +280,7 @@ INLINE upb_flow_t upb_dispatch_endsubmsg(upb_dispatcher *d) { --d->top; assert(d->top >= d->stack); } - return d->top->handlers.set->endsubmsg(d->top->handlers.closure); + return d->top->handlers.set->endsubmsg(d->top->handlers.closure, f); } INLINE upb_flow_t upb_dispatch_value(upb_dispatcher *d, diff --git a/src/upb_textprinter.c b/src/upb_textprinter.c index 894a1eaee6..c0fb944169 100644 --- a/src/upb_textprinter.c +++ b/src/upb_textprinter.c @@ -107,8 +107,9 @@ err: return UPB_BREAK; } -static upb_flow_t upb_textprinter_endsubmsg(void *_p) +static upb_flow_t upb_textprinter_endsubmsg(void *_p, upb_fielddef *f) { + (void)f; upb_textprinter *p = _p; p->indent_depth--; upb_textprinter_indent(p); diff --git a/tests/test_stream.c b/tests/test_stream.c index 468d40cd8e..8a136fd157 100644 --- a/tests/test_stream.c +++ b/tests/test_stream.c @@ -53,7 +53,8 @@ static upb_flow_t startsubmsg(void *closure, struct _upb_fielddef *f, } } -static upb_flow_t endsubmsg(void *closure) { +static upb_flow_t endsubmsg(void *closure, struct _upb_fielddef *f) { + (void)f; test_data *d = closure; strappendf(d->str, "endsubmsg\n"); return UPB_CONTINUE; @@ -99,9 +100,9 @@ static void test_dispatcher() { data.should_delegate = false; upb_dispatch_startsubmsg(&d, NULL); upb_dispatch_value(&d, NULL, val); - upb_dispatch_endsubmsg(&d); - upb_dispatch_endsubmsg(&d); - upb_dispatch_endsubmsg(&d); + upb_dispatch_endsubmsg(&d, NULL); + upb_dispatch_endsubmsg(&d, NULL); + upb_dispatch_endsubmsg(&d, NULL); upb_dispatch_endmsg(&d); upb_string expected = UPB_STACK_STRING(