/* ** XXX: The routines in this file that consume a string do not currently ** support having the string span buffers. In the future, as upb_sink and ** its buffering/sharing functionality evolve there should be an easy and ** idiomatic way of correctly handling this case. For now, we accept this ** limitation since we currently only parse descriptors from single strings. */ #include "upb/descriptor/reader.h" #include #include #include #include "upb/def.h" #include "upb/sink.h" #include "upb/descriptor/descriptor.upbdefs.h" /* Compares a NULL-terminated string with a non-NULL-terminated string. */ static bool upb_streq(const char *str, const char *buf, size_t n) { return strlen(str) == n && memcmp(str, buf, n) == 0; } /* We keep a stack of all the messages scopes we are currently in, as well as * the top-level file scope. This is necessary to correctly qualify the * definitions that are contained inside. "name" tracks the name of the * message or package (a bare name -- not qualified by any enclosing scopes). */ typedef struct { char *name; /* Index of the first def that is under this scope. For msgdefs, the * msgdef itself is at start-1. */ int start; uint32_t oneof_start; uint32_t oneof_index; } upb_descreader_frame; /* The maximum number of nested declarations that are allowed, ie. * message Foo { * message Bar { * message Baz { * } * } * } * * This is a resource limit that affects how big our runtime stack can grow. * TODO: make this a runtime-settable property of the Reader instance. */ #define UPB_MAX_MESSAGE_NESTING 64 struct upb_descreader { upb_sink sink; upb_inttable files; upb_strtable files_by_name; upb_filedef *file; /* The last file in files. */ upb_descreader_frame stack[UPB_MAX_MESSAGE_NESTING]; int stack_len; upb_inttable oneofs; uint32_t number; char *name; bool saw_number; bool saw_name; char *default_string; upb_fielddef *f; }; static char *upb_gstrndup(const char *buf, size_t n) { char *ret = upb_gmalloc(n + 1); if (!ret) return NULL; memcpy(ret, buf, n); ret[n] = '\0'; return ret; } /* Returns a newly allocated string that joins input strings together, for * example: * join("Foo.Bar", "Baz") -> "Foo.Bar.Baz" * join("", "Baz") -> "Baz" * Caller owns a ref on the returned string. */ static char *upb_join(const char *base, const char *name) { if (!base || strlen(base) == 0) { return upb_gstrdup(name); } else { char *ret = upb_gmalloc(strlen(base) + strlen(name) + 2); if (!ret) { return NULL; } ret[0] = '\0'; strcat(ret, base); strcat(ret, "."); strcat(ret, name); return ret; } } /* Qualify the defname for all defs starting with offset "start" with "str". */ static bool upb_descreader_qualify(upb_filedef *f, char *str, int32_t start) { size_t i; for (i = start; i < upb_filedef_defcount(f); i++) { upb_def *def = upb_filedef_mutabledef(f, i); char *name = upb_join(str, upb_def_fullname(def)); if (!name) { /* Need better logic here; at this point we've qualified some names but * not others. */ return false; } upb_def_setfullname(def, name, NULL); upb_gfree(name); } return true; } /* upb_descreader ************************************************************/ static upb_msgdef *upb_descreader_top(upb_descreader *r) { int index; UPB_ASSERT(r->stack_len > 1); index = r->stack[r->stack_len-1].start - 1; UPB_ASSERT(index >= 0); return upb_downcast_msgdef_mutable(upb_filedef_mutabledef(r->file, index)); } static upb_def *upb_descreader_last(upb_descreader *r) { return upb_filedef_mutabledef(r->file, upb_filedef_defcount(r->file) - 1); } /* Start/end handlers for FileDescriptorProto and DescriptorProto (the two * entities that have names and can contain sub-definitions. */ void upb_descreader_startcontainer(upb_descreader *r) { upb_descreader_frame *f = &r->stack[r->stack_len++]; f->start = upb_filedef_defcount(r->file); f->oneof_start = upb_inttable_count(&r->oneofs); f->oneof_index = 0; f->name = NULL; } bool upb_descreader_endcontainer(upb_descreader *r) { upb_descreader_frame *f = &r->stack[r->stack_len - 1]; while (upb_inttable_count(&r->oneofs) > f->oneof_start) { upb_oneofdef *o = upb_value_getptr(upb_inttable_pop(&r->oneofs)); bool ok = upb_msgdef_addoneof(upb_descreader_top(r), o, &r->oneofs, NULL); UPB_ASSERT(ok); } if (!upb_descreader_qualify(r->file, f->name, f->start)) { return false; } upb_gfree(f->name); f->name = NULL; r->stack_len--; return true; } void upb_descreader_setscopename(upb_descreader *r, char *str) { upb_descreader_frame *f = &r->stack[r->stack_len-1]; upb_gfree(f->name); f->name = str; } static upb_oneofdef *upb_descreader_getoneof(upb_descreader *r, uint32_t index) { bool found; upb_value val; upb_descreader_frame *f = &r->stack[r->stack_len-1]; /* DescriptorProto messages can be nested, so we will see the nested messages * between when we see the FieldDescriptorProto and the OneofDescriptorProto. * We need to preserve the oneofs in between these two things. */ index += f->oneof_start; while (upb_inttable_count(&r->oneofs) <= index) { upb_inttable_push(&r->oneofs, upb_value_ptr(upb_oneofdef_new(&r->oneofs))); } found = upb_inttable_lookup(&r->oneofs, index, &val); UPB_ASSERT(found); return upb_value_getptr(val); } /** Handlers for google.protobuf.FileDescriptorSet. ***************************/ static void *fileset_startfile(void *closure, const void *hd) { upb_descreader *r = closure; UPB_UNUSED(hd); r->file = upb_filedef_new(&r->files); upb_inttable_push(&r->files, upb_value_ptr(r->file)); return r; } /** Handlers for google.protobuf.FileDescriptorProto. *************************/ static bool file_start(void *closure, const void *hd) { upb_descreader *r = closure; UPB_UNUSED(hd); upb_descreader_startcontainer(r); return true; } static bool file_end(void *closure, const void *hd, upb_status *status) { upb_descreader *r = closure; UPB_UNUSED(hd); UPB_UNUSED(status); return upb_descreader_endcontainer(r); } static size_t file_onname(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; char *name; bool ok; UPB_UNUSED(hd); UPB_UNUSED(handle); name = upb_gstrndup(buf, n); upb_strtable_insert(&r->files_by_name, name, upb_value_ptr(r->file)); /* XXX: see comment at the top of the file. */ ok = upb_filedef_setname(r->file, name, NULL); upb_gfree(name); UPB_ASSERT(ok); return n; } static size_t file_onpackage(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; char *package; bool ok; UPB_UNUSED(hd); UPB_UNUSED(handle); package = upb_gstrndup(buf, n); /* XXX: see comment at the top of the file. */ upb_descreader_setscopename(r, package); ok = upb_filedef_setpackage(r->file, package, NULL); UPB_ASSERT(ok); return n; } static void *file_startphpnamespace(void *closure, const void *hd, size_t size_hint) { upb_descreader *r = closure; bool ok; UPB_UNUSED(hd); UPB_UNUSED(size_hint); ok = upb_filedef_setphpnamespace(r->file, "", NULL); UPB_ASSERT(ok); return closure; } static size_t file_onphpnamespace(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; char *php_namespace; bool ok; UPB_UNUSED(hd); UPB_UNUSED(handle); php_namespace = upb_gstrndup(buf, n); ok = upb_filedef_setphpnamespace(r->file, php_namespace, NULL); upb_gfree(php_namespace); UPB_ASSERT(ok); return n; } static size_t file_onphpprefix(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; char *prefix; bool ok; UPB_UNUSED(hd); UPB_UNUSED(handle); prefix = upb_gstrndup(buf, n); ok = upb_filedef_setphpprefix(r->file, prefix, NULL); upb_gfree(prefix); UPB_ASSERT(ok); return n; } static size_t file_onsyntax(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; bool ok; UPB_UNUSED(hd); UPB_UNUSED(handle); /* XXX: see comment at the top of the file. */ if (upb_streq("proto2", buf, n)) { ok = upb_filedef_setsyntax(r->file, UPB_SYNTAX_PROTO2, NULL); } else if (upb_streq("proto3", buf, n)) { ok = upb_filedef_setsyntax(r->file, UPB_SYNTAX_PROTO3, NULL); } else { ok = false; } UPB_ASSERT(ok); return n; } static void *file_startmsg(void *closure, const void *hd) { upb_descreader *r = closure; upb_msgdef *m = upb_msgdef_new(&m); bool ok = upb_filedef_addmsg(r->file, m, &m, NULL); UPB_UNUSED(hd); UPB_ASSERT(ok); return r; } static void *file_startenum(void *closure, const void *hd) { upb_descreader *r = closure; upb_enumdef *e = upb_enumdef_new(&e); bool ok = upb_filedef_addenum(r->file, e, &e, NULL); UPB_UNUSED(hd); UPB_ASSERT(ok); return r; } static void *file_startext(void *closure, const void *hd) { upb_descreader *r = closure; r->f = upb_fielddef_new(r); UPB_UNUSED(hd); return r; } static bool file_endext(void *closure, const void *hd) { /* The current symtab code can't handle extensions, so we just discard * them for now. */ upb_descreader *r = closure; upb_fielddef_unref(r->f, r); UPB_UNUSED(hd); r->f = NULL; return true; } static size_t file_ondep(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; upb_value val; if (upb_strtable_lookup2(&r->files_by_name, buf, n, &val)) { upb_filedef_adddep(r->file, upb_value_getptr(val)); } UPB_UNUSED(hd); UPB_UNUSED(handle); return n; } /** Handlers for google.protobuf.EnumValueDescriptorProto. *********************/ static bool enumval_startmsg(void *closure, const void *hd) { upb_descreader *r = closure; UPB_UNUSED(hd); r->saw_number = false; r->saw_name = false; return true; } static size_t enumval_onname(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; UPB_UNUSED(hd); UPB_UNUSED(handle); /* XXX: see comment at the top of the file. */ upb_gfree(r->name); r->name = upb_gstrndup(buf, n); r->saw_name = true; return n; } static bool enumval_onnumber(void *closure, const void *hd, int32_t val) { upb_descreader *r = closure; UPB_UNUSED(hd); r->number = val; r->saw_number = true; return true; } static bool enumval_endmsg(void *closure, const void *hd, upb_status *status) { upb_descreader *r = closure; upb_enumdef *e; UPB_UNUSED(hd); if(!r->saw_number || !r->saw_name) { upb_status_seterrmsg(status, "Enum value missing name or number."); return false; } e = upb_downcast_enumdef_mutable(upb_descreader_last(r)); upb_enumdef_addval(e, r->name, r->number, status); upb_gfree(r->name); r->name = NULL; return true; } /** Handlers for google.protobuf.EnumDescriptorProto. *************************/ static bool enum_endmsg(void *closure, const void *hd, upb_status *status) { upb_descreader *r = closure; upb_enumdef *e; UPB_UNUSED(hd); e = upb_downcast_enumdef_mutable(upb_descreader_last(r)); if (upb_def_fullname(upb_descreader_last(r)) == NULL) { upb_status_seterrmsg(status, "Enum had no name."); return false; } if (upb_enumdef_numvals(e) == 0) { upb_status_seterrmsg(status, "Enum had no values."); return false; } return true; } static size_t enum_onname(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; char *fullname = upb_gstrndup(buf, n); UPB_UNUSED(hd); UPB_UNUSED(handle); /* XXX: see comment at the top of the file. */ upb_def_setfullname(upb_descreader_last(r), fullname, NULL); upb_gfree(fullname); return n; } /** Handlers for google.protobuf.FieldDescriptorProto *************************/ static bool field_startmsg(void *closure, const void *hd) { upb_descreader *r = closure; UPB_UNUSED(hd); UPB_ASSERT(r->f); upb_gfree(r->default_string); r->default_string = NULL; /* fielddefs default to packed, but descriptors default to non-packed. */ upb_fielddef_setpacked(r->f, false); return true; } /* Converts the default value in string "str" into "d". Passes a ref on str. * Returns true on success. */ static bool parse_default(char *str, upb_fielddef *f) { bool success = true; char *end; switch (upb_fielddef_type(f)) { case UPB_TYPE_INT32: { long val = strtol(str, &end, 0); if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) success = false; else upb_fielddef_setdefaultint32(f, val); break; } case UPB_TYPE_INT64: { /* XXX: Need to write our own strtoll, since it's not available in c89. */ long long val = strtol(str, &end, 0); if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) success = false; else upb_fielddef_setdefaultint64(f, val); break; } case UPB_TYPE_UINT32: { unsigned long val = strtoul(str, &end, 0); if (val > UINT32_MAX || errno == ERANGE || *end) success = false; else upb_fielddef_setdefaultuint32(f, val); break; } case UPB_TYPE_UINT64: { /* XXX: Need to write our own strtoull, since it's not available in c89. */ unsigned long long val = strtoul(str, &end, 0); if (val > UINT64_MAX || errno == ERANGE || *end) success = false; else upb_fielddef_setdefaultuint64(f, val); break; } case UPB_TYPE_DOUBLE: { double val = strtod(str, &end); if (errno == ERANGE || *end) success = false; else upb_fielddef_setdefaultdouble(f, val); break; } case UPB_TYPE_FLOAT: { /* XXX: Need to write our own strtof, since it's not available in c89. */ float val = strtod(str, &end); if (errno == ERANGE || *end) success = false; else upb_fielddef_setdefaultfloat(f, val); break; } case UPB_TYPE_BOOL: { if (strcmp(str, "false") == 0) upb_fielddef_setdefaultbool(f, false); else if (strcmp(str, "true") == 0) upb_fielddef_setdefaultbool(f, true); else success = false; break; } default: abort(); } return success; } static bool field_endmsg(void *closure, const void *hd, upb_status *status) { upb_descreader *r = closure; upb_fielddef *f = r->f; UPB_UNUSED(hd); /* TODO: verify that all required fields were present. */ UPB_ASSERT(upb_fielddef_number(f) != 0); UPB_ASSERT(upb_fielddef_name(f) != NULL); UPB_ASSERT((upb_fielddef_subdefname(f) != NULL) == upb_fielddef_hassubdef(f)); if (r->default_string) { if (upb_fielddef_issubmsg(f)) { upb_status_seterrmsg(status, "Submessages cannot have defaults."); return false; } if (upb_fielddef_isstring(f) || upb_fielddef_type(f) == UPB_TYPE_ENUM) { upb_fielddef_setdefaultcstr(f, r->default_string, NULL); } else { if (r->default_string && !parse_default(r->default_string, f)) { /* We don't worry too much about giving a great error message since the * compiler should have ensured this was correct. */ upb_status_seterrmsg(status, "Error converting default value."); return false; } } } return true; } static bool field_onlazy(void *closure, const void *hd, bool val) { upb_descreader *r = closure; UPB_UNUSED(hd); upb_fielddef_setlazy(r->f, val); return true; } static bool field_onpacked(void *closure, const void *hd, bool val) { upb_descreader *r = closure; UPB_UNUSED(hd); upb_fielddef_setpacked(r->f, val); return true; } static bool field_ontype(void *closure, const void *hd, int32_t val) { upb_descreader *r = closure; UPB_UNUSED(hd); upb_fielddef_setdescriptortype(r->f, val); return true; } static bool field_onlabel(void *closure, const void *hd, int32_t val) { upb_descreader *r = closure; UPB_UNUSED(hd); upb_fielddef_setlabel(r->f, val); return true; } static bool field_onnumber(void *closure, const void *hd, int32_t val) { upb_descreader *r = closure; bool ok; UPB_UNUSED(hd); ok = upb_fielddef_setnumber(r->f, val, NULL); UPB_ASSERT(ok); return true; } static size_t field_onname(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; char *name = upb_gstrndup(buf, n); UPB_UNUSED(hd); UPB_UNUSED(handle); /* XXX: see comment at the top of the file. */ upb_fielddef_setname(r->f, name, NULL); upb_gfree(name); return n; } static size_t field_ontypename(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; char *name = upb_gstrndup(buf, n); UPB_UNUSED(hd); UPB_UNUSED(handle); /* XXX: see comment at the top of the file. */ upb_fielddef_setsubdefname(r->f, name, NULL); upb_gfree(name); return n; } static size_t field_onextendee(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; char *name = upb_gstrndup(buf, n); UPB_UNUSED(hd); UPB_UNUSED(handle); /* XXX: see comment at the top of the file. */ upb_fielddef_setcontainingtypename(r->f, name, NULL); upb_gfree(name); return n; } static size_t field_ondefaultval(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; UPB_UNUSED(hd); UPB_UNUSED(handle); /* Have to convert from string to the correct type, but we might not know the * type yet, so we save it as a string until the end of the field. * XXX: see comment at the top of the file. */ upb_gfree(r->default_string); r->default_string = upb_gstrndup(buf, n); return n; } static bool field_ononeofindex(void *closure, const void *hd, int32_t index) { upb_descreader *r = closure; upb_oneofdef *o = upb_descreader_getoneof(r, index); bool ok = upb_oneofdef_addfield(o, r->f, &r->f, NULL); UPB_UNUSED(hd); UPB_ASSERT(ok); return true; } /** Handlers for google.protobuf.OneofDescriptorProto. ************************/ static size_t oneof_name(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; upb_descreader_frame *f = &r->stack[r->stack_len-1]; upb_oneofdef *o = upb_descreader_getoneof(r, f->oneof_index++); char *name_null_terminated = upb_gstrndup(buf, n); bool ok = upb_oneofdef_setname(o, name_null_terminated, NULL); UPB_UNUSED(hd); UPB_UNUSED(handle); UPB_ASSERT(ok); free(name_null_terminated); return n; } /** Handlers for google.protobuf.DescriptorProto ******************************/ static bool msg_start(void *closure, const void *hd) { upb_descreader *r = closure; UPB_UNUSED(hd); upb_descreader_startcontainer(r); return true; } static bool msg_end(void *closure, const void *hd, upb_status *status) { upb_descreader *r = closure; upb_msgdef *m = upb_descreader_top(r); UPB_UNUSED(hd); if(!upb_def_fullname(upb_msgdef_upcast_mutable(m))) { upb_status_seterrmsg(status, "Encountered message with no name."); return false; } return upb_descreader_endcontainer(r); } static size_t msg_name(void *closure, const void *hd, const char *buf, size_t n, const upb_bufhandle *handle) { upb_descreader *r = closure; upb_msgdef *m = upb_descreader_top(r); /* XXX: see comment at the top of the file. */ char *name = upb_gstrndup(buf, n); UPB_UNUSED(hd); UPB_UNUSED(handle); upb_def_setfullname(upb_msgdef_upcast_mutable(m), name, NULL); upb_descreader_setscopename(r, name); /* Passes ownership of name. */ return n; } static void *msg_startmsg(void *closure, const void *hd) { upb_descreader *r = closure; upb_msgdef *m = upb_msgdef_new(&m); bool ok = upb_filedef_addmsg(r->file, m, &m, NULL); UPB_UNUSED(hd); UPB_ASSERT(ok); return r; } static void *msg_startext(void *closure, const void *hd) { upb_descreader *r = closure; r->f = upb_fielddef_new(r); UPB_UNUSED(hd); return r; } static bool msg_endext(void *closure, const void *hd) { /* The current symtab code can't handle extensions, so we just discard * them for now. */ upb_descreader *r = closure; upb_fielddef_unref(r->f, r); UPB_UNUSED(hd); r->f = NULL; return true; } static void *msg_startfield(void *closure, const void *hd) { upb_descreader *r = closure; r->f = upb_fielddef_new(&r->f); /* We can't add the new field to the message until its name/number are * filled in. */ UPB_UNUSED(hd); return r; } static bool msg_endfield(void *closure, const void *hd) { upb_descreader *r = closure; upb_msgdef *m = upb_descreader_top(r); bool ok; UPB_UNUSED(hd); /* Oneof fields are added to the msgdef through their oneof, so don't need to * be added here. */ if (upb_fielddef_containingoneof(r->f) == NULL) { ok = upb_msgdef_addfield(m, r->f, &r->f, NULL); UPB_ASSERT(ok); } r->f = NULL; return true; } static bool msg_onmapentry(void *closure, const void *hd, bool mapentry) { upb_descreader *r = closure; upb_msgdef *m = upb_descreader_top(r); UPB_UNUSED(hd); upb_msgdef_setmapentry(m, mapentry); r->f = NULL; return true; } /** Code to register handlers *************************************************/ #define F(msg, field) upbdefs_google_protobuf_ ## msg ## _f_ ## field(m) static void reghandlers(const void *closure, upb_handlers *h) { const upb_msgdef *m = upb_handlers_msgdef(h); UPB_UNUSED(closure); if (upbdefs_google_protobuf_FileDescriptorSet_is(m)) { upb_handlers_setstartsubmsg(h, F(FileDescriptorSet, file), &fileset_startfile, NULL); } else if (upbdefs_google_protobuf_DescriptorProto_is(m)) { upb_handlers_setstartmsg(h, &msg_start, NULL); upb_handlers_setendmsg(h, &msg_end, NULL); upb_handlers_setstring(h, F(DescriptorProto, name), &msg_name, NULL); upb_handlers_setstartsubmsg(h, F(DescriptorProto, extension), &msg_startext, NULL); upb_handlers_setendsubmsg(h, F(DescriptorProto, extension), &msg_endext, NULL); upb_handlers_setstartsubmsg(h, F(DescriptorProto, nested_type), &msg_startmsg, NULL); upb_handlers_setstartsubmsg(h, F(DescriptorProto, field), &msg_startfield, NULL); upb_handlers_setendsubmsg(h, F(DescriptorProto, field), &msg_endfield, NULL); upb_handlers_setstartsubmsg(h, F(DescriptorProto, enum_type), &file_startenum, NULL); } else if (upbdefs_google_protobuf_FileDescriptorProto_is(m)) { upb_handlers_setstartmsg(h, &file_start, NULL); upb_handlers_setendmsg(h, &file_end, NULL); upb_handlers_setstring(h, F(FileDescriptorProto, name), &file_onname, NULL); upb_handlers_setstring(h, F(FileDescriptorProto, package), &file_onpackage, NULL); upb_handlers_setstring(h, F(FileDescriptorProto, syntax), &file_onsyntax, NULL); upb_handlers_setstartsubmsg(h, F(FileDescriptorProto, message_type), &file_startmsg, NULL); upb_handlers_setstartsubmsg(h, F(FileDescriptorProto, enum_type), &file_startenum, NULL); upb_handlers_setstartsubmsg(h, F(FileDescriptorProto, extension), &file_startext, NULL); upb_handlers_setendsubmsg(h, F(FileDescriptorProto, extension), &file_endext, NULL); upb_handlers_setstring(h, F(FileDescriptorProto, dependency), &file_ondep, NULL); } else if (upbdefs_google_protobuf_EnumValueDescriptorProto_is(m)) { upb_handlers_setstartmsg(h, &enumval_startmsg, NULL); upb_handlers_setendmsg(h, &enumval_endmsg, NULL); upb_handlers_setstring(h, F(EnumValueDescriptorProto, name), &enumval_onname, NULL); upb_handlers_setint32(h, F(EnumValueDescriptorProto, number), &enumval_onnumber, NULL); } else if (upbdefs_google_protobuf_EnumDescriptorProto_is(m)) { upb_handlers_setendmsg(h, &enum_endmsg, NULL); upb_handlers_setstring(h, F(EnumDescriptorProto, name), &enum_onname, NULL); } else if (upbdefs_google_protobuf_FieldDescriptorProto_is(m)) { upb_handlers_setstartmsg(h, &field_startmsg, NULL); upb_handlers_setendmsg(h, &field_endmsg, NULL); upb_handlers_setint32(h, F(FieldDescriptorProto, type), &field_ontype, NULL); upb_handlers_setint32(h, F(FieldDescriptorProto, label), &field_onlabel, NULL); upb_handlers_setint32(h, F(FieldDescriptorProto, number), &field_onnumber, NULL); upb_handlers_setstring(h, F(FieldDescriptorProto, name), &field_onname, NULL); upb_handlers_setstring(h, F(FieldDescriptorProto, type_name), &field_ontypename, NULL); upb_handlers_setstring(h, F(FieldDescriptorProto, extendee), &field_onextendee, NULL); upb_handlers_setstring(h, F(FieldDescriptorProto, default_value), &field_ondefaultval, NULL); upb_handlers_setint32(h, F(FieldDescriptorProto, oneof_index), &field_ononeofindex, NULL); } else if (upbdefs_google_protobuf_OneofDescriptorProto_is(m)) { upb_handlers_setstring(h, F(OneofDescriptorProto, name), &oneof_name, NULL); } else if (upbdefs_google_protobuf_FieldOptions_is(m)) { upb_handlers_setbool(h, F(FieldOptions, lazy), &field_onlazy, NULL); upb_handlers_setbool(h, F(FieldOptions, packed), &field_onpacked, NULL); } else if (upbdefs_google_protobuf_MessageOptions_is(m)) { upb_handlers_setbool(h, F(MessageOptions, map_entry), &msg_onmapentry, NULL); } else if (upbdefs_google_protobuf_FileOptions_is(m)) { upb_handlers_setstring(h, F(FileOptions, php_class_prefix), &file_onphpprefix, NULL); upb_handlers_setstartstr(h, F(FileOptions, php_namespace), &file_startphpnamespace, NULL); upb_handlers_setstring(h, F(FileOptions, php_namespace), &file_onphpnamespace, NULL); } UPB_ASSERT(upb_ok(upb_handlers_status(h))); } #undef F void descreader_cleanup(void *_r) { upb_descreader *r = _r; size_t i; for (i = 0; i < upb_descreader_filecount(r); i++) { upb_filedef_unref(upb_descreader_file(r, i), &r->files); } upb_gfree(r->name); upb_inttable_uninit(&r->files); upb_strtable_uninit(&r->files_by_name); upb_inttable_uninit(&r->oneofs); upb_gfree(r->default_string); while (r->stack_len > 0) { upb_descreader_frame *f = &r->stack[--r->stack_len]; upb_gfree(f->name); } } /* Public API ****************************************************************/ upb_descreader *upb_descreader_create(upb_env *e, const upb_handlers *h) { upb_descreader *r = upb_env_malloc(e, sizeof(upb_descreader)); if (!r || !upb_env_addcleanup(e, descreader_cleanup, r)) { return NULL; } upb_inttable_init(&r->files, UPB_CTYPE_PTR); upb_strtable_init(&r->files_by_name, UPB_CTYPE_PTR); upb_inttable_init(&r->oneofs, UPB_CTYPE_PTR); upb_sink_reset(upb_descreader_input(r), h, r); r->stack_len = 0; r->name = NULL; r->default_string = NULL; return r; } size_t upb_descreader_filecount(const upb_descreader *r) { return upb_inttable_count(&r->files); } upb_filedef *upb_descreader_file(const upb_descreader *r, size_t i) { upb_value v; if (upb_inttable_lookup(&r->files, i, &v)) { return upb_value_getptr(v); } else { return NULL; } } upb_sink *upb_descreader_input(upb_descreader *r) { return &r->sink; } const upb_handlers *upb_descreader_newhandlers(const void *owner) { const upb_msgdef *m = upbdefs_google_protobuf_FileDescriptorSet_get(&m); const upb_handlers *h = upb_handlers_newfrozen(m, owner, reghandlers, NULL); upb_msgdef_unref(m, &m); return h; }