More work on upb_src.

pull/13171/head
Joshua Haberman 14 years ago
parent db512df98e
commit 4559918090
  1. 4
      Makefile
  2. 43
      core/upb.h
  3. 443
      core/upb_def.c
  4. 6
      core/upb_stream.h

@ -28,7 +28,7 @@ CC=gcc
CXX=g++ CXX=g++
CFLAGS=-std=c99 CFLAGS=-std=c99
INCLUDE=-Idescriptor -Icore -Itests -Istream -I. INCLUDE=-Idescriptor -Icore -Itests -Istream -I.
CPPFLAGS=-Wall -Wextra -g $(INCLUDE) $(strip $(shell test -f perf-cppflags && cat perf-cppflags)) CPPFLAGS=-Wall -Wextra -Wno-missing-field-initializers -g $(INCLUDE) $(strip $(shell test -f perf-cppflags && cat perf-cppflags))
LDLIBS=-lpthread core/libupb.a LDLIBS=-lpthread core/libupb.a
ifeq ($(shell uname), Darwin) ifeq ($(shell uname), Darwin)
CPPFLAGS += -I/usr/include/lua5.1 CPPFLAGS += -I/usr/include/lua5.1
@ -61,7 +61,7 @@ SRC=core/upb.c \
core/upb_table.c \ core/upb_table.c \
core/upb_string.c \ core/upb_string.c \
descriptor/descriptor.c \ descriptor/descriptor.c \
# core/upb_def.c \ core/upb_def.c \
# core/upb_msg.c \ # core/upb_msg.c \
# stream/upb_decoder.c \ # stream/upb_decoder.c \
# stream/upb_stdio.c \ # stream/upb_stdio.c \

@ -12,6 +12,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> // only for size_t. #include <stdio.h> // only for size_t.
#include <assert.h>
#include "descriptor_const.h" #include "descriptor_const.h"
#include "upb_atomic.h" #include "upb_atomic.h"
@ -128,6 +129,11 @@ typedef struct _upb_msg upb_msg;
typedef uint32_t upb_strlen_t; typedef uint32_t upb_strlen_t;
// The type of a upb_value. This is like a upb_fieldtype_t, but adds the
// constant UPB_VALUETYPE_ARRAY to represent an array.
typedef uint8_t upb_valuetype_t;
#define UPB_VALUETYPE_ARRAY 32
// A single .proto value. The owner must have an out-of-band way of knowing // A single .proto value. The owner must have an out-of-band way of knowing
// the type, so that it knows which union member to use. // the type, so that it knows which union member to use.
typedef struct { typedef struct {
@ -153,14 +159,20 @@ typedef struct {
#endif #endif
} upb_value; } upb_value;
#ifdef NDEBUG
#define SET_TYPE(dest, val)
#else
#define SET_TYPE(dest, val) dest = val
#endif
#define UPB_VALUE_ACCESSORS(name, membername, ctype, proto_type) \ #define UPB_VALUE_ACCESSORS(name, membername, ctype, proto_type) \
ctype upb_value_get ## name(upb_value val) { \ ctype upb_value_get ## name(upb_value val) { \
assert(val.type == UPB_TYPE(proto_type)); \ assert(val.type == UPB_TYPE(proto_type)); \
return val.membername; \ return val.val.membername; \
} \ } \
void upb_value_ ## name(upb_value *val, ctype cval) { \ void upb_value_ ## name(upb_value *val, ctype cval) { \
val.type = UPB_TYPE(proto_type); \ SET_TYPE(val->type, UPB_TYPE(proto_type)); \
val.membername = cval; \ val->val.membername = cval; \
} }
UPB_VALUE_ACCESSORS(double, _double, double, DOUBLE); UPB_VALUE_ACCESSORS(double, _double, double, DOUBLE);
UPB_VALUE_ACCESSORS(float, _float, float, FLOAT); UPB_VALUE_ACCESSORS(float, _float, float, FLOAT);
@ -169,6 +181,7 @@ UPB_VALUE_ACCESSORS(int64, int64, int64_t, INT64);
UPB_VALUE_ACCESSORS(uint32, uint32, uint32_t, UINT32); UPB_VALUE_ACCESSORS(uint32, uint32, uint32_t, UINT32);
UPB_VALUE_ACCESSORS(uint64, uint64, uint64_t, UINT64); UPB_VALUE_ACCESSORS(uint64, uint64, uint64_t, UINT64);
UPB_VALUE_ACCESSORS(bool, _bool, bool, BOOL); UPB_VALUE_ACCESSORS(bool, _bool, bool, BOOL);
UPB_VALUE_ACCESSORS(str, str, upb_string*, STRING);
// A pointer to a .proto value. The owner must have an out-of-band way of // A pointer to a .proto value. The owner must have an out-of-band way of
// knowing the type, so it knows which union member to use. // knowing the type, so it knows which union member to use.
@ -187,24 +200,23 @@ typedef union {
void *_void; void *_void;
} upb_valueptr; } upb_valueptr;
// The type of a upb_value. This is like a upb_fieldtype_t, but adds the
// constant UPB_VALUETYPE_ARRAY to represent an array.
typedef uint8_t upb_valuetype_t;
#define UPB_VALUETYPE_ARRAY 32
INLINE upb_valueptr upb_value_addrof(upb_value *val) { INLINE upb_valueptr upb_value_addrof(upb_value *val) {
upb_valueptr ptr = {&val->_double}; upb_valueptr ptr = {&val->val._double};
return ptr; return ptr;
} }
// Converts upb_value_ptr -> upb_value by reading from the pointer. We need to // Reads or writes a upb_value from an address represented by a upb_value_ptr.
// know the value type to perform this operation, because we need to know how // We need to know the value type to perform this operation, because we need to
// much memory to copy. // know how much memory to copy (and for big-endian machines, we need to know
// where in the upb_value the data goes).
//
// For little endian-machines where we didn't mind overreading, we could make
// upb_value_read simply use memcpy().
INLINE upb_value upb_value_read(upb_valueptr ptr, upb_fieldtype_t ft) { INLINE upb_value upb_value_read(upb_valueptr ptr, upb_fieldtype_t ft) {
upb_value val; upb_value val;
#define CASE(t, member_name) \ #define CASE(t, member_name) \
case UPB_TYPE(t): val.member_name = *ptr.member_name; break; case UPB_TYPE(t): val.val.member_name = *ptr.member_name; break;
switch(ft) { switch(ft) {
CASE(DOUBLE, _double) CASE(DOUBLE, _double)
@ -232,13 +244,10 @@ INLINE upb_value upb_value_read(upb_valueptr ptr, upb_fieldtype_t ft) {
#undef CASE #undef CASE
} }
// Writes a upb_value to a upb_value_ptr location. We need to know the value
// type to perform this operation, because we need to know how much memory to
// copy.
INLINE void upb_value_write(upb_valueptr ptr, upb_value val, INLINE void upb_value_write(upb_valueptr ptr, upb_value val,
upb_fieldtype_t ft) { upb_fieldtype_t ft) {
#define CASE(t, member_name) \ #define CASE(t, member_name) \
case UPB_TYPE(t): *ptr.member_name = val.member_name; break; case UPB_TYPE(t): *ptr.member_name = val.val.member_name; break;
switch(ft) { switch(ft) {
CASE(DOUBLE, _double) CASE(DOUBLE, _double)

@ -9,9 +9,6 @@
#include "descriptor.h" #include "descriptor.h"
#include "upb_def.h" #include "upb_def.h"
#define CHECKSRC(x) if(!(x)) goto src_err
#define CHECK(x) if(!(x)) goto err
/* Rounds p up to the next multiple of t. */ /* Rounds p up to the next multiple of t. */
static size_t upb_align_up(size_t val, size_t align) { static size_t upb_align_up(size_t val, size_t align) {
return val % align == 0 ? val : val + align - (val % align); return val % align == 0 ? val : val + align - (val % align);
@ -184,6 +181,188 @@ static void upb_def_uninit(upb_def *def) {
} }
/* upb_defbuilder ************************************************************/
// A upb_defbuilder builds a list of defs by handling a parse of a protobuf in
// the format defined in descriptor.proto. The output of a upb_defbuilder is
// a list of upb_def* that possibly contain unresolved references.
//
// We use a separate object (upb_defbuilder) instead of having the defs handle
// the parse themselves because we need to store state that is only necessary
// during the building process itself.
// When we are bootstrapping descriptor.proto, we must help the bare decoder out
// by telling it when to descend into a submessage, because with the wire format
// alone we cannot tell the difference between a submessage and a string.
//
// TODO: In the long-term, we should bootstrap from a serialization format that
// contains this information, so we can remove this special-case code. This
// would involve defining a serialization format very similar to the existing
// protobuf format, but that contains more information about the wire type.
#define BEGIN_SUBMSG 100
// upb_deflist: A little dynamic array for storing a growing list of upb_defs.
typedef struct {
upb_def **defs;
uint32_t len;
uint32_t size;
} upb_deflist;
static void upb_deflist_init(upb_deflist *l) {
l->size = 8;
l->defs = malloc(l->size * sizeof(void*));
l->len = 0;
}
static void upb_deflist_uninit(upb_deflist *l) {
for(uint32_t i = 0; i < l->len; i++)
if(l->defs[i]) upb_def_unref(l->defs[i]);
free(l->defs);
}
static void upb_deflist_push(upb_deflist *l, upb_def *d) {
if(l->len == l->size) {
l->size *= 2;
l->defs = realloc(l->defs, l->size * sizeof(void*));
}
l->defs[l->len++] = d;
}
// Qualify the defname for all defs starting with offset "start" with "str".
static void upb_deflist_qualify(upb_deflist *l, upb_string *str, int32_t start) {
for(uint32_t i = start; i < l->len; i++) {
upb_def *def = l->defs[i];
upb_string *name = def->fqname;
def->fqname = upb_join(str, name);
upb_string_unref(name);
}
}
typedef struct {
upb_string *name;
int start;
} upb_defbuilder_frame;
struct _upb_defbuilder {
upb_deflist defs;
upb_defbuilder_frame stack[UPB_MAX_TYPE_DEPTH];
int stack_len;
uint32_t number;
upb_string *name;
};
typedef struct _upb_defbuilder upb_defbuilder;
// Forward declares for top-level file descriptors.
static void upb_msgdef_register_DescriptorProto(upb_defbuilder *b, upb_handlers *h);
static void upb_enumdef_register_EnumDescriptorProto(upb_defbuilder *b,
upb_handlers *h);
// Start/end handlers for FileDescriptorProto and DescriptorProto (the two
// entities that have names and can contain sub-definitions.
void upb_defbuilder_startcontainer(upb_defbuilder *b) {
upb_defbuilder_frame *f = &b->stack[b->stack_len++];
f->start = b->defs.len;
f->name = NULL;
}
void upb_defbuilder_endcontainer(upb_defbuilder *b) {
upb_defbuilder_frame *f = &b->stack[--b->stack_len];
upb_deflist_qualify(&b->defs, f->name, f->start);
upb_string_unref(f->name);
}
void upb_defbuilder_setscopename(upb_defbuilder *b, upb_string *str) {
upb_defbuilder_frame *f = &b->stack[b->stack_len-1];
upb_string_unref(f->name);
f->name = upb_string_getref(str);
}
// Handlers for google.protobuf.FileDescriptorProto.
static upb_flow_t upb_defbuilder_FileDescriptorProto_value(void *_b,
upb_fielddef *f,
upb_value val) {
upb_defbuilder *b = _b;
switch(f->number) {
case GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_FIELDNUM:
upb_defbuilder_setscopename(b, upb_value_getstr(val));
break;
case GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_FIELDNUM:
case GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_FIELDNUM:
return BEGIN_SUBMSG;
default:
return UPB_SKIP;
}
}
static upb_flow_t upb_defbuilder_FileDescriptorProto_startsubmsg(
void *_b, upb_fielddef *f, upb_handlers *h) {
upb_defbuilder *b = _b;
switch(f->number) {
case GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_FIELDNUM:
upb_msgdef_register_DescriptorProto(b, h);
return UPB_DELEGATE;
case GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_FIELDNUM:
upb_enumdef_register_EnumDescriptorProto(b, h);
return UPB_DELEGATE;
default:
// TODO: services and extensions.
return UPB_SKIP;
}
}
static void upb_defbuilder_register_FileDescriptorProto(upb_defbuilder *b,
upb_handlers *h) {
static upb_handlerset upb_defbuilder_FileDescriptorProto_handlers = {
NULL, // startmsg
NULL, // endmsg
&upb_defbuilder_FileDescriptorProto_value,
&upb_defbuilder_FileDescriptorProto_startsubmsg,
};
upb_register_handlerset(h, &upb_defbuilder_FileDescriptorProto_handlers);
upb_set_handler_closure(h, b);
}
// Handlers for google.protobuf.FileDescriptorSet.
static upb_flow_t upb_defbuilder_FileDescriptorSet_value(void *b,
upb_fielddef *f,
upb_value val) {
(void)b;
(void)val;
switch(f->number) {
case GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_FIELDNUM:
return BEGIN_SUBMSG;
default:
return UPB_SKIP;
}
}
static upb_flow_t upb_defbuilder_FileDescriptorSet_startsubmsg(
void *_b, upb_fielddef *f, upb_handlers *h) {
upb_defbuilder *b = _b;
switch(f->number) {
case GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_FIELDNUM:
upb_defbuilder_register_FileDescriptorProto(b, h);
return UPB_DELEGATE;
default:
return UPB_SKIP;
}
}
static void upb_defbuilder_register_FileDescriptorSet(
upb_defbuilder *b, upb_handlers *h) {
static upb_handlerset upb_defbuilder_FileDescriptorSet_handlers = {
NULL, // startmsg
NULL, // endmsg
&upb_defbuilder_FileDescriptorSet_value,
&upb_defbuilder_FileDescriptorSet_startsubmsg,
};
upb_register_handlerset(h, &upb_defbuilder_FileDescriptorSet_handlers);
upb_set_handler_closure(h, b);
}
/* upb_unresolveddef **********************************************************/ /* upb_unresolveddef **********************************************************/
// Unresolved defs are used as temporary placeholders for a def whose name has // Unresolved defs are used as temporary placeholders for a def whose name has
@ -227,28 +406,30 @@ static void upb_enumdef_free(upb_enumdef *e) {
} }
// google.protobuf.EnumValueDescriptorProto. // google.protobuf.EnumValueDescriptorProto.
static void upb_enumdef_startmsg(upb_defbuilder *b) { static void upb_enumdef_EnumValueDescriptorProto_startmsg(upb_defbuilder *b) {
b->number = -1; b->number = -1;
name = NULL; b->name = NULL;
} }
static upb_flow_t upb_enumdef_value(upb_defbuilder *b, upb_fielddef *f, upb_value val) { static upb_flow_t upb_enumdef_EnumValueDescriptorProto_value(upb_defbuilder *b,
upb_fielddef *f,
upb_value val) {
switch(f->number) { switch(f->number) {
case GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_FIELDNUM: case GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_FIELDNUM:
name = upb_string_tryrecycle(name); b->name = upb_string_tryrecycle(name);
CHECKSRC(upb_src_getstr(src, name)); CHECKSRC(upb_src_getstr(src, name));
break; break;
case GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NUMBER_FIELDNUM: case GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NUMBER_FIELDNUM:
CHECKSRC(upb_src_getint32(src, &number)); b->number = upb_value_getint32(val);
break; break;
default: default:
CHECKSRC(upb_src_skipval(src));
break; break;
} }
return UPB_CONTINUE;
} }
static void upb_enumdef_endmsg(upb_defbuilder *b) { static void upb_enumdef_EnumValueDescriptorProto_endmsg(upb_defbuilder *b) {
if(name == NULL || number == -1) { if(b->name == NULL || b->number == -1) {
upb_seterr(status, UPB_STATUS_ERROR, "Enum value missing name or number."); upb_seterr(status, UPB_STATUS_ERROR, "Enum value missing name or number.");
goto err; goto err;
} }
@ -262,6 +443,65 @@ static void upb_enumdef_endmsg(upb_defbuilder *b) {
return UPB_CONTINUE; return UPB_CONTINUE;
} }
static void upb_enumdef_register_EnumValueDescriptorProto(upb_defbuilder *b,
upb_handlers *h) {
static upb_handlerset upb_enumdef_EnumValueDescriptorProto_handlers = {
&upb_enumdef_EnumValueDescriptorProto_startmsg,
&upb_enumdef_EnumValueDescriptorProto_endmsg,
&upb_enumdef_EnumValueDescriptorProto_value,
}
upb_register_handlerset(h, &upb_enumdef_EnumValueDescriptorProto_handlers);
upb_set_handler_closure(h, b);
}
// google.protobuf.EnumDescriptorProto.
void upb_enumdef_EnumDescriptorProto_startmsg(upb_defbuilder *b) {
upb_enumdef *e = malloc(sizeof(*e));
upb_def_init(&e->base, UPB_DEF_ENUM);
upb_strtable_init(&e->ntoi, 0, sizeof(upb_ntoi_ent));
upb_inttable_init(&e->iton, 0, sizeof(upb_iton_ent));
upb_deflist_push(&b->defs, UPB_UPCAST(e));
}
void upb_enumdef_EnumDescriptorProto_endmsg(upb_defbuilder *b) {
assert(e->base.fqname);
}
static upb_flow_t upb_enumdef_EnumDescriptorProto_value(upb_defbuilder *b,
upb_fielddef *f,
upb_value val) {
switch(f->number) {
case GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_FIELDNUM:
upb_string_unref(e->base.fqname);
e->base.fqname = upb_value_getstr(val);
case GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_FIELDNUM:
return BEGIN_SUBMSG;
}
return UPB_CONTINUE;
}
static upb_flow_t upb_enumdef_EnumDescriptorProto_startsubmsg(upb_defbuilder *b,
upb_fielddef *f,
upb_handlers *h) {
switch(f->number) {
case GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_FIELDNUM:
upb_enumdef_register_EnumValueDescriptorProto(b, h);
return UPB_DELEGATE;
}
return UPB_SKIP;
}
static void upb_enumdef_register_EnumDescriptorProto(upb_defbuilder *b,
upb_handlers *h) {
static upb_handlerset upb_enumdef_EnumDescriptorProto_handlers = {
&upb_enumdef_EnumDescriptorProto_startmsg,
&upb_enumdef_EnumDescriptorProto_endmsg,
&upb_enumdef_EnumDescriptorProto_value,
}
upb_register_handlerset(h, &upb_enumdef_EnumDescriptorProto_handlers);
upb_set_handler_closure(h, b);
}
upb_enum_iter upb_enum_begin(upb_enumdef *e) { upb_enum_iter upb_enum_begin(upb_enumdef *e) {
// We could iterate over either table here; the choice is arbitrary. // We could iterate over either table here; the choice is arbitrary.
return upb_inttable_begin(&e->iton); return upb_inttable_begin(&e->iton);
@ -355,7 +595,7 @@ static int upb_compare_fields(const void *f1, const void *f2) {
return upb_compare_typed_fields(*(void**)f1, *(void**)f2); return upb_compare_typed_fields(*(void**)f1, *(void**)f2);
} }
// Processes a google.protobuf.DescriptorProto, adding defs to "defs." // google.protobuf.DescriptorProto.
static void upb_msgdef_startmsg(upb_defbuilder *b) { static void upb_msgdef_startmsg(upb_defbuilder *b) {
upb_msgdef *m = malloc(sizeof(*m)); upb_msgdef *m = malloc(sizeof(*m));
upb_def_init(&m->base, UPB_DEF_MSG); upb_def_init(&m->base, UPB_DEF_MSG);
@ -417,9 +657,6 @@ static void upb_msgdef_endmsg(upb_defbuilder *b) {
static bool upb_msgdef_value(upb_defbuilder *b, upb_fielddef *f, upb_value val) { static bool upb_msgdef_value(upb_defbuilder *b, upb_fielddef *f, upb_value val) {
switch(f->number) { switch(f->number) {
case GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_FIELDNUM: case GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_FIELDNUM:
// XXX
m->base.fqname = upb_string_tryrecycle(m->base.fqname);
m->base.fqname = upb_value_getstr(val);
upb_defbuilder_setscopename(upb_value_getstr(val)); upb_defbuilder_setscopename(upb_value_getstr(val));
break; break;
case GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_FIELDNUM: case GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_FIELDNUM:
@ -432,13 +669,14 @@ static bool upb_msgdef_value(upb_defbuilder *b, upb_fielddef *f, upb_value val)
} }
} }
static upb_flow_t upb_msgdef_startsubmsg(upb_defbuilder *b, upb_fielddef *f, upb_handlers *h) { static upb_flow_t upb_msgdef_startsubmsg(upb_defbuilder *b, upb_fielddef *f,
upb_handlers *h) {
switch(f->number) { switch(f->number) {
case GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_FIELDNUM: case GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_FIELDNUM:
upb_register_FieldDescriptorProto(b, h); upb_register_FieldDescriptorProto(b, h);
return UPB_DELEGATE; return UPB_DELEGATE;
case GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_FIELDNUM: case GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_FIELDNUM:
upb_register_DescriptorProto(b, h); upb_msgdef_register_DescriptorProto(b, h);
return UPB_DELEGATE; return UPB_DELEGATE;
case GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_FIELDNUM: case GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_FIELDNUM:
upb_register_EnumDescriptorProto(b, h); upb_register_EnumDescriptorProto(b, h);
@ -449,6 +687,18 @@ static upb_flow_t upb_msgdef_startsubmsg(upb_defbuilder *b, upb_fielddef *f, upb
} }
} }
static void upb_msgdef_register_DescriptorProto(upb_defbuilder *b,
upb_handlers *h) {
static upb_handlerset upb_msgdef_DescriptorProto_handlers = {
&upb_msgdef_startmsg,
&upb_msgdef_endmsg,
&upb_msgdef_value,
&upb_msgdef_startsubmsg,
}
upb_register_handlerset(h, &upb_msgdef_DescriptorProto_handlers);
upb_set_handler_closure(h, b);
}
static void upb_msgdef_free(upb_msgdef *m) static void upb_msgdef_free(upb_msgdef *m)
{ {
upb_msg_iter i; upb_msg_iter i;
@ -477,165 +727,6 @@ upb_msg_iter upb_msg_next(upb_msgdef *m, upb_msg_iter iter) {
return upb_inttable_next(&m->itof, &iter->e); return upb_inttable_next(&m->itof, &iter->e);
} }
/* upb_defbuilder ************************************************************/
// A upb_defbuilder builds a list of defs by handling a parse of a protobuf in
// the format defined in descriptor.proto. The output of a upb_defbuilder is
// a list of upb_def* that possibly contain unresolved references.
//
// We use a separate object (upb_defbuilder) instead of having the defs handle
// the parse themselves because we need to store state that is only necessary
// during the building process itself.
// When we are bootstrapping descriptor.proto, we must help the bare decoder out
// by telling it when to descend into a submessage, because with the wire format
// alone we cannot tell the difference between a submessage and a string.
#define BEGIN_SUBMSG 100
// upb_deflist: A little dynamic array for storing a growing list of upb_defs.
typedef struct {
upb_def **defs;
uint32_t len;
uint32_t size;
} upb_deflist;
static void upb_deflist_init(upb_deflist *l) {
l->size = 8;
l->defs = malloc(l->size * sizeof(void*));
l->len = 0;
}
static void upb_deflist_uninit(upb_deflist *l) {
for(uint32_t i = 0; i < l->len; i++)
if(l->defs[i]) upb_def_unref(l->defs[i]);
free(l->defs);
}
static void upb_deflist_push(upb_deflist *l, upb_def *d) {
if(l->len == l->size) {
l->size *= 2;
l->defs = realloc(l->defs, l->size * sizeof(void*));
}
l->defs[l->len++] = d;
}
// Qualify the defname for all defs starting with offset "start" with "str".
static void upb_deflist_qualify(upb_deflist *l, upb_string *str, int32_t start) {
for(uint32_t i = start; i < l->len; i++) {
upb_def *def = l->defs[i];
upb_string *name = def->fqname;
def->fqname = upb_join(str, name);
upb_string_unref(name);
}
}
typedef struct {
upb_deflist defs;
struct {
upb_string *name;
int start;
} upb_defbuilder_frame;
upb_defbuilder_frame stack[UPB_MAX_TYPE_DEPTH];
int stack_len;
} upb_defbuilder;
// Start/end handlers for FileDescriptorProto and DescriptorProto (the two
// entities that have names and can contain sub-definitions.
upb_defbuilder_startcontainer(upb_defbuilder *b) {
upb_defbuilder_frame *f = b->stack[b->stack_len++];
f->start = b->defs.len;
f->name = NULL;
}
upb_defbuilder_endcontainer(upb_defbuilder *b) {
upb_defbuilder_frame *f = b->stack[--b->stack_len];
upb_deflist_qualify(&b->defs, f->name, f->start);
upb_string_unref(f->name);
}
upb_defbuilder_setscopename(upb_defbuilder *b, upb_string *str) {
}
// Handlers for google.protobuf.FileDescriptorProto.
static bool upb_defbuilder_FileDescriptorProto_value(upb_defbuilder *b,
upb_fielddef *f,
upb_value val) {
switch(f->number) {
case GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_PACKAGE_FIELDNUM:
upb_defbuilder_setscopename(b, val.str);
break;
case GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_FIELDNUM:
case GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_FIELDNUM:
return BEGIN_SUBMSG;
default:
return UPB_SKIP;
}
}
static bool upb_defbuilder_FileDescriptorProto_startsubmsg(upb_defbuilder *b,
upb_fielddef *f,
upb_handlers *h) {
switch(f->number) {
case GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_MESSAGE_TYPE_FIELDNUM:
upb_defbuilder_register_DescriptorProto(b, h);
return UPB_DELEGATE;
case GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO_ENUM_TYPE_FIELDNUM:
upb_defbuilder_register_EnumDescriptorProto(b, h);
return UPB_DELEGATE;
default:
// TODO: services and extensions.
return UPB_SKIP;
}
}
static upb_handlers upb_defbuilder_FileDescriptorProto_handlers = {
NULL, // startmsg
NULL, // endmsg
&upb_defbuilder_FileDescriptorProto_value,
&upb_defbuilder_FileDescriptorProto_startsubmsg,
}
upb_defbuilder_register_FileDescriptorProto(upb_defbuilder *b, upb_handlers *h) {
upb_register_handlerset(h, &upb_defbuilder_FileDescriptorProto_handlers);
upb_set_handler_closure(h, b);
}
// Handlers for google.protobuf.FileDescriptorSet.
upb_defbuilder_FileDescriptorSet_value(upb_defbuilder *b, upb_fielddef *f,
upb_value val) {
switch(f->number) {
case GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_FIELDNUM:
return BEGIN_SUBMSG;
default:
return UPB_SKIP;
}
}
upb_defbuilder_FileDescriptorSet_startsubmsg(upb_defbuilder *b,
upb_fielddef *f, upb_handlers *h) {
switch(f->number) {
case GOOGLE_PROTOBUF_FILEDESCRIPTORSET_FILE_FIELDNUM:
upb_defbuilder_register_FileDescriptorProto(b, h);
return UPB_DELEGATE;
default:
return UPB_SKIP;
}
}
static upb_handlers upb_defbuilder_FileDescriptorSet_handlers = {
NULL, // startmsg
NULL, // endmsg
&upb_defbuilder_FileDescriptorSet_value,
&upb_defbuilder_FileDescriptorSet_startsubmsg,
}
upb_defbuilder_register_FileDescriptorSet(upb_defbuilder *b, upb_handlers *h) {
upb_register_handlerset(h, &upb_defbuilder_FileDescriptorSet_handlers);
upb_set_handler_closure(h, b);
}
/* upb_symtab adding defs *****************************************************/ /* upb_symtab adding defs *****************************************************/
// This is a self-contained group of functions that, given a list of upb_defs // This is a self-contained group of functions that, given a list of upb_defs

@ -135,6 +135,12 @@ INLINE upb_flow_t upb_dispatch_unknownval(upb_dispatcher *d,
upb_field_number_t fieldnum, upb_value val); upb_field_number_t fieldnum, upb_value val);
/* upb_src ********************************************************************/
struct _upb_src;
typedef struct _upb_src upb_src;
/* upb_bytesrc ****************************************************************/ /* upb_bytesrc ****************************************************************/
struct _upb_bytesrc; struct _upb_bytesrc;

Loading…
Cancel
Save