diff options
Diffstat (limited to 'src/upb_context.c')
-rw-r--r-- | src/upb_context.c | 350 |
1 files changed, 0 insertions, 350 deletions
diff --git a/src/upb_context.c b/src/upb_context.c deleted file mode 100644 index 469f879..0000000 --- a/src/upb_context.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. - */ - -#include <stdlib.h> -#include <string.h> -#include "descriptor.h" -#include "upb_context.h" -#include "upb_def.h" -#include "upb_mm.h" - -struct upb_symtab_entry { - struct upb_strtable_entry e; - struct upb_def *def; -}; - -/* Search for a character in a string, in reverse. */ -static int my_memrchr(char *data, char c, size_t len) -{ - int off = len-1; - while(off > 0 && data[off] != c) --off; - return off; -} - -void addfd(struct upb_strtable *addto, struct upb_strtable *existingdefs, - google_protobuf_FileDescriptorProto *fd, bool sort, - struct upb_status *status); - -struct upb_context *upb_context_new() -{ - struct upb_context *c = malloc(sizeof(*c)); - upb_atomic_refcount_init(&c->refcount, 1); - upb_rwlock_init(&c->lock); - upb_strtable_init(&c->symtab, 16, sizeof(struct upb_symtab_entry)); - upb_strtable_init(&c->psymtab, 16, sizeof(struct upb_symtab_entry)); - /* Add all the types in descriptor.proto so we can parse descriptors. */ - google_protobuf_FileDescriptorProto *fd = - upb_file_descriptor_set->file->elements[0]; /* We know there is only 1. */ - struct upb_status status = UPB_STATUS_INIT; - addfd(&c->psymtab, &c->symtab, fd, false, &status); - if(!upb_ok(&status)) { - fprintf(stderr, "Failed to initialize upb: %s.\n", status.msg); - assert(false); - return NULL; /* Indicates that upb is buggy or corrupt. */ - } - struct upb_string name = UPB_STRLIT("google.protobuf.FileDescriptorSet"); - struct upb_symtab_entry *e = upb_strtable_lookup(&c->psymtab, &name); - assert(e); - c->fds_msgdef = upb_downcast_msgdef(e->def); - return c; -} - -static void free_symtab(struct upb_strtable *t) -{ - struct upb_symtab_entry *e = upb_strtable_begin(t); - for(; e; e = upb_strtable_next(t, &e->e)) { - upb_def_unref(e->def); - upb_string_unref(e->e.key); - } - upb_strtable_free(t); -} - -static void free_context(struct upb_context *c) -{ - free_symtab(&c->symtab); - free_symtab(&c->psymtab); -} - -void upb_context_unref(struct upb_context *c) -{ - if(upb_atomic_unref(&c->refcount)) { - upb_rwlock_wrlock(&c->lock); - free_context(c); - upb_rwlock_unlock(&c->lock); - upb_rwlock_destroy(&c->lock); - free(c); - } -} - -struct upb_def **upb_context_getandref_defs(struct upb_context *c, int *count) -{ - upb_rwlock_wrlock(&c->lock); - *count = upb_strtable_count(&c->symtab); - struct upb_def **defs = malloc(sizeof(*defs) * (*count)); - struct upb_symtab_entry *e = upb_strtable_begin(&c->symtab); - int i = 0; - for(; e; e = upb_strtable_next(&c->symtab, &e->e), i++) { - assert(e->def); - defs[i] = e->def; - upb_def_ref(defs[i]); - } - assert(*count == i); - upb_rwlock_unlock(&c->lock); - return defs; -} - -struct upb_def *upb_context_lookup(struct upb_context *c, - struct upb_string *sym) -{ - upb_rwlock_rdlock(&c->lock); - struct upb_symtab_entry *e = upb_strtable_lookup(&c->symtab, sym); - upb_rwlock_unlock(&c->lock); - return e ? e->def : NULL; -} - -/* Given a symbol and the base symbol inside which it is defined, find the - * symbol's definition in t. */ -static struct upb_symtab_entry *resolve(struct upb_strtable *t, - struct upb_string *base, - struct upb_string *symbol) -{ - if(base->byte_len + symbol->byte_len + 1 >= UPB_SYMBOL_MAXLEN || - symbol->byte_len == 0) return NULL; - - if(symbol->ptr[0] == UPB_SYMBOL_SEPARATOR) { - /* Symbols starting with '.' are absolute, so we do a single lookup. */ - struct upb_string sym_str = {.ptr = symbol->ptr+1, - .byte_len = symbol->byte_len-1}; - return upb_strtable_lookup(t, &sym_str); - } else { - /* Remove components from base until we find an entry or run out. */ - char sym[UPB_SYMBOL_MAXLEN+1]; - struct upb_string sym_str = {.ptr = sym}; - int baselen = base->byte_len; - while(1) { - /* sym_str = base[0...base_len] + UPB_SYMBOL_SEPARATOR + symbol */ - memcpy(sym, base->ptr, baselen); - sym[baselen] = UPB_SYMBOL_SEPARATOR; - memcpy(sym + baselen + 1, symbol->ptr, symbol->byte_len); - sym_str.byte_len = baselen + symbol->byte_len + 1; - - struct upb_symtab_entry *e = upb_strtable_lookup(t, &sym_str); - if (e) return e; - else if(baselen == 0) return NULL; /* No more scopes to try. */ - - baselen = my_memrchr(base->ptr, UPB_SYMBOL_SEPARATOR, baselen); - } - } -} - -/* Tries to resolve a symbol in two different tables. */ -struct upb_def *resolve2(struct upb_strtable *t1, struct upb_strtable *t2, - struct upb_string *base, struct upb_string *sym, - enum upb_def_type expected_type) { - struct upb_symtab_entry *e = resolve(t1, base, sym); - if(e == NULL) e = resolve(t2, base, sym); - if(e && e->def->type == expected_type) return e->def; - return NULL; -} - - -struct upb_def *upb_context_resolve(struct upb_context *c, - struct upb_string *base, - struct upb_string *symbol) { - upb_rwlock_rdlock(&c->lock); - struct upb_symtab_entry *e = resolve(&c->symtab, base, symbol); - upb_rwlock_unlock(&c->lock); - return e ? e->def : NULL; -} - -/* Joins strings together, for example: - * join("Foo.Bar", "Baz") -> "Foo.Bar.Baz" - * join("", "Baz") -> "Baz" - * Caller owns the returned string and must free it. */ -static struct upb_string *join(struct upb_string *base, struct upb_string *name) { - size_t len = base->byte_len + name->byte_len; - if(base->byte_len > 0) len++; /* For the separator. */ - struct upb_string *joined = upb_string_new(); - upb_string_resize(joined, len); - if(base->byte_len > 0) { - /* nested_base = base + '.' + d->name */ - memcpy(joined->ptr, base->ptr, base->byte_len); - joined->ptr[base->byte_len] = UPB_SYMBOL_SEPARATOR; - memcpy(&joined->ptr[base->byte_len+1], name->ptr, name->byte_len); - } else { - memcpy(joined->ptr, name->ptr, name->byte_len); - } - return joined; -} - -static void insert_enum(struct upb_strtable *t, - google_protobuf_EnumDescriptorProto *ed, - struct upb_string *base, - struct upb_status *status) -{ - if(!ed->set_flags.has.name) { - upb_seterr(status, UPB_STATUS_ERROR, - "enum in context '" UPB_STRFMT "' does not have a name", - UPB_STRARG(base)); - return; - } - - struct upb_string *fqname = join(base, ed->name); - if(upb_strtable_lookup(t, fqname)) { - upb_seterr(status, UPB_STATUS_ERROR, - "attempted to redefine symbol '" UPB_STRFMT "'", - UPB_STRARG(fqname)); - upb_string_unref(fqname); - return; - } - - struct upb_symtab_entry e; - e.e.key = fqname; // Donating our ref to the table. - e.def = (struct upb_def*)upb_enumdef_new(ed, fqname); - upb_strtable_insert(t, &e.e); -} - -static void insert_message(struct upb_strtable *t, - google_protobuf_DescriptorProto *d, - struct upb_string *base, bool sort, - struct upb_status *status) -{ - if(!d->set_flags.has.name) { - upb_seterr(status, UPB_STATUS_ERROR, - "message in context '" UPB_STRFMT "' does not have a name", - UPB_STRARG(base)); - return; - } - - /* We own this and must free it on destruct. */ - struct upb_string *fqname = join(base, d->name); - - if(upb_strtable_lookup(t, fqname)) { - upb_seterr(status, UPB_STATUS_ERROR, - "attempted to redefine symbol '" UPB_STRFMT "'", - UPB_STRARG(fqname)); - upb_string_unref(fqname); - return; - } - - struct upb_symtab_entry e; - e.e.key = fqname; // Donating our ref to the table. - struct upb_fielddef *fielddefs = malloc(sizeof(*fielddefs) * d->field->len); - for (unsigned int i = 0; i < d->field->len; i++) { - google_protobuf_FieldDescriptorProto *fd = d->field->elements[i]; - upb_fielddef_init(&fielddefs[i], fd); - } - if(sort) upb_fielddef_sort(fielddefs, d->field->len); - e.def = (struct upb_def*)upb_msgdef_new(fielddefs, d->field->len, fqname); - upb_strtable_insert(t, &e.e); - - /* Add nested messages and enums. */ - if(d->set_flags.has.nested_type) - for(unsigned int i = 0; i < d->nested_type->len; i++) - insert_message(t, d->nested_type->elements[i], fqname, sort, status); - - if(d->set_flags.has.enum_type) - for(unsigned int i = 0; i < d->enum_type->len; i++) - insert_enum(t, d->enum_type->elements[i], fqname, status); -} - -void addfd(struct upb_strtable *addto, struct upb_strtable *existingdefs, - google_protobuf_FileDescriptorProto *fd, bool sort, - struct upb_status *status) -{ - struct upb_string pkg = {.byte_len=0}; - if(fd->set_flags.has.package) pkg = *fd->package; - - if(fd->set_flags.has.message_type) - for(unsigned int i = 0; i < fd->message_type->len; i++) - insert_message(addto, fd->message_type->elements[i], &pkg, sort, status); - - if(fd->set_flags.has.enum_type) - for(unsigned int i = 0; i < fd->enum_type->len; i++) - insert_enum(addto, fd->enum_type->elements[i], &pkg, status); - - if(!upb_ok(status)) return; - - /* TODO: handle extensions and services. */ - - /* Attempt to resolve all references. */ - struct upb_symtab_entry *e; - for(e = upb_strtable_begin(addto); e; e = upb_strtable_next(addto, &e->e)) { - if(upb_strtable_lookup(existingdefs, e->e.key)) { - upb_seterr(status, UPB_STATUS_ERROR, - "attempted to redefine symbol '" UPB_STRFMT "'", - UPB_STRARG(e->e.key)); - return; - } - if(e->def->type == UPB_DEF_MESSAGE) { - struct upb_msgdef *m = upb_downcast_msgdef(e->def); - for(unsigned int i = 0; i < m->num_fields; i++) { - struct upb_fielddef *f = &m->fields[i]; - if(!upb_issubmsg(f) && f->type != UPB_TYPENUM(ENUM)) { - // No resolving necessary. - continue; - } - struct upb_def *def; - struct upb_string *name = upb_downcast_unresolveddef(f->def)->name; - if(upb_issubmsg(f)) - def = resolve2(existingdefs, addto, e->e.key, name, UPB_DEF_MESSAGE); - else if(f->type == UPB_TYPENUM(ENUM)) - def = resolve2(existingdefs, addto, e->e.key, name, UPB_DEF_ENUM); - if(!def) { - upb_seterr(status, UPB_STATUS_ERROR, - "could not resolve symbol '" UPB_STRFMT "'" - " in context '" UPB_STRFMT "'", - UPB_STRARG(name), UPB_STRARG(e->e.key)); - return; - } - upb_msgdef_resolve(m, f, def); - } - } - } -} - -void upb_context_addfds(struct upb_context *c, - google_protobuf_FileDescriptorSet *fds, - struct upb_status *status) -{ - if(fds->set_flags.has.file) { - /* Insert new symbols into a temporary table until we have verified that - * the descriptor is valid. */ - struct upb_strtable tmp; - upb_strtable_init(&tmp, 0, sizeof(struct upb_symtab_entry)); - upb_rwlock_rdlock(&c->lock); - for(uint32_t i = 0; i < fds->file->len; i++) { - addfd(&tmp, &c->symtab, fds->file->elements[i], true, status); - if(!upb_ok(status)) { - free_symtab(&tmp); - upb_rwlock_unlock(&c->lock); - return; - } - } - upb_rwlock_unlock(&c->lock); - - /* Everything was successfully added, copy from the tmp symtable. */ - struct upb_symtab_entry *e; - { - upb_rwlock_wrlock(&c->lock); - for(e = upb_strtable_begin(&tmp); e; e = upb_strtable_next(&tmp, &e->e)) - upb_strtable_insert(&c->symtab, &e->e); - upb_rwlock_unlock(&c->lock); - } - upb_strtable_free(&tmp); - } - return; -} - -void upb_context_parsefds(struct upb_context *c, struct upb_string *fds_str, - struct upb_status *status) -{ - struct upb_msg *fds = upb_msg_new(c->fds_msgdef); - upb_msg_parsestr(fds, fds_str->ptr, fds_str->byte_len, status); - if(!upb_ok(status)) return; - upb_context_addfds(c, (google_protobuf_FileDescriptorSet*)fds, status); - return; -} |