diff options
50 files changed, 5669 insertions, 6041 deletions
@@ -1,6 +1,6 @@ -Copyright (c) 2009, Joshua Haberman -Copyright (c) 2009, Google Inc. +Copyright (c) 2009-2010, Joshua Haberman +Copyright (c) 2009-2010, Google Inc. All rights reserved. Redistribution and use in source and binary forms, with or without @@ -27,34 +27,68 @@ rwildcard=$(strip $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2)$(filter $ CC=gcc CXX=g++ CFLAGS=-std=c99 -INCLUDE=-Idescriptor -Isrc -Itests -I. -CPPFLAGS=-Wall -Wextra -g $(INCLUDE) $(strip $(shell test -f perf-cppflags && cat perf-cppflags)) -LDLIBS=-lpthread - -LIBUPB=src/libupb.a -LIBUPB_PIC=src/libupb_pic.a -LIBUPB_SHARED=src/libupb.so -ALL=deps $(OBJ) $(LIBUPB) $(LIBUPB_PIC) tools/upbc +INCLUDE=-Idescriptor -Icore -Itests -Istream -I. +CPPFLAGS=-Wall -Wextra -Wno-missing-field-initializers -g $(INCLUDE) $(strip $(shell test -f perf-cppflags && cat perf-cppflags)) +LDLIBS=-lpthread core/libupb.a +ifeq ($(shell uname), Darwin) + CPPFLAGS += -I/usr/include/lua5.1 + LDFLAGS += -L/usr/local/lib -llua +else + CFLAGS += $(strip $(shell pkg-config --silence-errors --cflags lua || pkg-config --cflags lua5.1)) + LDFLAGS += $(strip $(shell pkg-config --silence-errors --libs lua || pkg-config --libs lua5.1)) +endif + +LIBUPB=core/libupb.a +LIBUPB_PIC=core/libupb_pic.a +LIBUPB_SHARED=core/libupb.so +ALL=deps $(OBJ) $(LIBUPB) $(LIBUPB_PIC) all: $(ALL) clean: rm -rf $(LIBUPB) $(LIBUPB_PIC) - rm -rf $(call rwildcard,,*.o) $(call rwildcard,,*.lo) + rm -rf $(call rwildcard,,*.o) $(call rwildcard,,*.lo) $(call rwildcard,,*.gc*) rm -rf benchmark/google_messages.proto.pb benchmark/google_messages.pb.* benchmarks/b.* benchmarks/*.pb* - rm -rf tests/tests tests/t.* tests/test_table - rm -rf descriptor/descriptor.proto.pb + rm -rf $(TESTS) tests/t.* + rm -rf descriptor/descriptor.pb rm -rf tools/upbc deps cd lang_ext/python && python setup.py clean --all -# The core library (src/libupb.a) -SRC=src/upb.c src/upb_decoder.c src/upb_table.c src/upb_def.c src/upb_data.c \ - src/upb_encoder.c descriptor/descriptor.c src/upb_text.c +-include deps +deps: gen-deps.sh Makefile $(call rwildcard,,*.c) $(call rwildcard,,*.h) + @./gen-deps.sh $(SRC) + +# The core library -- the absolute minimum you must compile in to successfully +# bootstrap. +CORE= \ + core/upb.c \ + core/upb_table.c \ + core/upb_string.c \ + core/upb_def.c \ + descriptor/descriptor.c + +# Common encoders/decoders and upb_msg -- you're almost certain to want these. +STREAM= \ + stream/upb_decoder.c \ + stream/upb_stdio.c \ + stream/upb_textprinter.c \ + stream/upb_strstream.c \ + core/upb_msg.c \ + +SRC=$(CORE) $(STREAM) + +$(SRC): perf-cppflags +# Parts of core that are yet to be converted. +OTHERSRC=src/upb_encoder.c src/upb_text.c # Override the optimization level for upb_def.o, because it is not in the # critical path but gets very large when -O3 is used. -src/upb_def.o: src/upb_def.c +core/upb_def.o: core/upb_def.c $(CC) $(CFLAGS) $(CPPFLAGS) -Os -c -o $@ $< -src/upb_def.lo: src/upb_def.c +core/upb_def.lo: core/upb_def.c $(CC) $(CFLAGS) $(CPPFLAGS) -Os -c -o $@ $< -fPIC +lang_ext/lua/upb.so: lang_ext/lua/upb.lo + $(CC) $(CFLAGS) $(CPPFLAGS) -shared -o $@ $< core/libupb_pic.a + + STATICOBJ=$(patsubst %.c,%.o,$(SRC)) SHAREDOBJ=$(patsubst %.c,%.lo,$(SRC)) # building shared objects is like building static ones, except -fPIC is added. @@ -67,12 +101,12 @@ $(LIBUPB_SHARED): $(SHAREDOBJ) $(CC) -shared -o $(LIBUPB_SHARED) $(SHAREDOBJ) # Regenerating the auto-generated files in descriptor/. -descriptor/descriptor.proto.pb: descriptor/descriptor.proto +descriptor/descriptor.pb: descriptor/descriptor.proto # TODO: replace with upbc - protoc descriptor/descriptor.proto -odescriptor/descriptor.proto.pb + protoc descriptor/descriptor.proto -odescriptor/descriptor.pb -descriptorgen: descriptor/descriptor.proto.pb tools/upbc - ./tools/upbc -i upb_file_descriptor_set -o descriptor/descriptor descriptor/descriptor.proto.pb +descriptorgen: descriptor/descriptor.pb + cd descriptor && xxd -i descriptor.pb > descriptor.c # Language extensions. python: $(LIBUPB_PIC) @@ -83,25 +117,33 @@ tests/test.proto.pb: tests/test.proto # TODO: replace with upbc protoc tests/test.proto -otests/test.proto.pb -tests: tests/tests \ +TESTS=tests/test_string \ tests/test_table \ - tests/t.test_vs_proto2.googlemessage1 \ - tests/t.test_vs_proto2.googlemessage2 \ - tests/test.proto.pb + tests/test_def \ + tests/test_stream \ + tests/test_decoder \ +# tests/t.test_vs_proto2.googlemessage1 \ +# tests/t.test_vs_proto2.googlemessage2 \ +# tests/test.proto.pb +tests: $(LIBUPB) $(TESTS) + +OTHER_TESTS=tests/tests \ +$(TESTS): $(LIBUPB) -#VALGRIND=valgrind --leak-check=full --error-exitcode=1 -VALGRIND= +VALGRIND=valgrind --leak-check=full --error-exitcode=1 +#VALGRIND= test: tests @echo Running all tests under valgrind. - $(VALGRIND) ./tests/tests + @set -e # Abort on error. # Needs to be rewritten to separate the benchmark. # valgrind --error-exitcode=1 ./tests/test_table - @for test in tests/t.* ; do \ - if [ -f ./$$test ] ; then \ - echo $(VALGRIND) ./$$test: \\c; \ - $(VALGRIND) ./$$test; \ + @for test in $(TESTS); do \ + if [ -x ./$$test ] ; then \ + echo !!! $(VALGRIND) ./$$test; \ + $(VALGRIND) ./$$test || exit 1; \ fi \ - done; + done; \ + echo "All tests passed!" tests/t.test_vs_proto2.googlemessage1 \ tests/t.test_vs_proto2.googlemessage2: \ @@ -125,16 +167,16 @@ tests/test_table: tests/test_table.cc # Includes <hash_set> which is a deprecated header. $(CXX) $(CXXFLAGS) $(CPPFLAGS) -Wno-deprecated -o $@ $< $(LIBUPB) -tests/tests: src/libupb.a +tests/tests: core/libupb.a # Tools -tools/upbc: src/libupb.a +tools/upbc: core/libupb.a # Benchmarks -UPB_BENCHMARKS=benchmarks/b.parsetostruct_googlemessage1.upb_table_byval \ - benchmarks/b.parsetostruct_googlemessage1.upb_table_byref \ - benchmarks/b.parsetostruct_googlemessage2.upb_table_byval \ - benchmarks/b.parsetostruct_googlemessage2.upb_table_byref +#UPB_BENCHMARKS=benchmarks/b.parsetostruct_googlemessage1.upb_table \ +# benchmarks/b.parsetostruct_googlemessage2.upb_table +UPB_BENCHMARKS=benchmarks/b.parsestream_googlemessage1.upb_table \ + benchmarks/b.parsestream_googlemessage2.upb_table BENCHMARKS=$(UPB_BENCHMARKS) \ benchmarks/b.parsetostruct_googlemessage1.proto2_table \ @@ -181,6 +223,20 @@ benchmarks/b.parsetostruct_googlemessage2.upb_table_byref: \ -DMESSAGE_FILE=\"google_message2.dat\" \ -DBYREF=true $(LIBUPB) +benchmarks/b.parsestream_googlemessage1.upb_table \ +benchmarks/b.parsestream_googlemessage2.upb_table: \ + benchmarks/parsestream.upb_table.c $(LIBUPB) benchmarks/google_messages.proto.pb + $(CC) $(CFLAGS) $(CPPFLAGS) -o benchmarks/b.parsestream_googlemessage1.upb_table $< \ + -DMESSAGE_NAME=\"benchmarks.SpeedMessage1\" \ + -DMESSAGE_DESCRIPTOR_FILE=\"google_messages.proto.pb\" \ + -DMESSAGE_FILE=\"google_message1.dat\" \ + $(LIBUPB) + $(CC) $(CFLAGS) $(CPPFLAGS) -o benchmarks/b.parsestream_googlemessage2.upb_table $< \ + -DMESSAGE_NAME=\"benchmarks.SpeedMessage2\" \ + -DMESSAGE_DESCRIPTOR_FILE=\"google_messages.proto.pb\" \ + -DMESSAGE_FILE=\"google_message2.dat\" \ + $(LIBUPB) + benchmarks/b.parsetostruct_googlemessage1.proto2_table \ benchmarks/b.parsetostruct_googlemessage2.proto2_table: \ benchmarks/parsetostruct.proto2_table.cc benchmarks/google_messages.pb.cc @@ -210,6 +266,3 @@ benchmarks/b.parsetostruct_googlemessage2.proto2_compiled: \ -DMESSAGE_HFILE=\"google_messages.pb.h\" \ benchmarks/google_messages.pb.cc -lprotobuf -lpthread --include deps -deps: gen-deps.sh Makefile $(call rwildcard,,*.c) $(call rwildcard,,*.h) - @./gen-deps.sh $(SRC) @@ -10,6 +10,11 @@ ROADMAP OF THE SOURCE benchmark/ Benchmarks of upb and other protocol buffer implementations. +core/ + The core source directory. builds into core/libupb.a. Contains only the + very core library, which is capable of loading descriptors given the + appropriate decoder. Does not even contain decoders for the standard + formats like the protobuf text and binary formats. descriptor/ Files that describe the format of Protocol Buffer "descriptors", which are protocol buffers that describe the format of other protocol buffers. These @@ -19,8 +24,8 @@ labs/ about alternate ways of implementing things. When possible, these are benchmarked by the tests in benchmark/. We also test these with the tests in tests/, to ensure that the alternate implementations are actually correct. -src/ - The core source directory. builds into src/libupb.a. +stream/ + Implementations of streaming protobuf encoders and decoders. tests/ Unit tests. tools/ diff --git a/benchmarks/parsestream.upb_table.c b/benchmarks/parsestream.upb_table.c new file mode 100644 index 0000000..16979b0 --- /dev/null +++ b/benchmarks/parsestream.upb_table.c @@ -0,0 +1,116 @@ + +#include "main.c" + +#include "upb_def.h" +#include "upb_decoder.h" +#include "upb_strstream.h" + +static upb_stringsrc *stringsrc; +static upb_string *input_str; +static upb_string *tmp_str; +static upb_msgdef *def; +static upb_decoder *decoder; + +static bool initialize() +{ + // Initialize upb state, decode descriptor. + upb_status status = UPB_STATUS_INIT; + upb_symtab *s = upb_symtab_new(); + upb_symtab_add_descriptorproto(s); + upb_def *fds_def = upb_symtab_lookup( + s, UPB_STRLIT("google.protobuf.FileDescriptorSet")); + if (!fds_def) { + fprintf(stderr, "Couldn't load FileDescriptorSet def"); + } + + upb_string *fds_str = upb_strreadfile(MESSAGE_DESCRIPTOR_FILE); + if(fds_str == NULL) { + fprintf(stderr, "Couldn't read " MESSAGE_DESCRIPTOR_FILE ":"), + upb_printerr(&status); + return false; + } + + upb_stringsrc *ssrc = upb_stringsrc_new(); + upb_stringsrc_reset(ssrc, fds_str); + upb_decoder *d = upb_decoder_new(upb_downcast_msgdef(fds_def)); + upb_decoder_reset(d, upb_stringsrc_bytesrc(ssrc)); + + upb_symtab_addfds(s, upb_decoder_src(d), &status); + + if(!upb_ok(&status)) { + fprintf(stderr, "Error importing " MESSAGE_DESCRIPTOR_FILE ":"); + upb_printerr(&status); + return false; + } + + upb_string_unref(fds_str); + upb_decoder_free(d); + upb_stringsrc_free(ssrc); + upb_def_unref(fds_def); + + def = upb_downcast_msgdef(upb_symtab_lookup(s, UPB_STRLIT(MESSAGE_NAME))); + if(!def) { + fprintf(stderr, "Error finding symbol '" UPB_STRFMT "'.\n", + UPB_STRARG(UPB_STRLIT(MESSAGE_NAME))); + return false; + } + upb_symtab_unref(s); + + // Read the message data itself. + input_str = upb_strreadfile(MESSAGE_FILE); + if(input_str == NULL) { + fprintf(stderr, "Error reading " MESSAGE_FILE "\n"); + return false; + } + tmp_str = NULL; + decoder = upb_decoder_new(def); + stringsrc = upb_stringsrc_new(); + return true; +} + +static void cleanup() +{ + upb_string_unref(input_str); + upb_string_unref(tmp_str); + upb_def_unref(UPB_UPCAST(def)); + upb_decoder_free(decoder); + upb_stringsrc_free(stringsrc); +} + +static size_t run(int i) +{ + (void)i; + upb_status status = UPB_STATUS_INIT; + upb_stringsrc_reset(stringsrc, input_str); + upb_decoder_reset(decoder, upb_stringsrc_bytesrc(stringsrc)); + upb_src *src = upb_decoder_src(decoder); + upb_fielddef *f; + int depth = 0; + while(1) { + while(!upb_src_eof(src) && (f = upb_src_getdef(src)) != NULL) { + if(upb_issubmsg(f)) { + upb_src_startmsg(src); + ++depth; + } else if(upb_isstring(f)) { + tmp_str = upb_string_tryrecycle(tmp_str); + upb_src_getstr(src, tmp_str); + } else { + // Primitive type. + upb_value val; + upb_src_getval(src, upb_value_addrof(&val)); + } + } + // If we're not EOF now, the loop terminated due to an error. + if (!upb_src_eof(src)) goto err; + if (depth == 0) break; + --depth; + upb_src_endmsg(src); + } + if(!upb_ok(&status)) goto err; + return upb_string_len(input_str); + +err: + fprintf(stderr, "Decode error"); + upb_printerr(&status); + return 0; +} diff --git a/core/upb.c b/core/upb.c new file mode 100644 index 0000000..525c8a8 --- /dev/null +++ b/core/upb.c @@ -0,0 +1,75 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. + * + */ + +#include <stdarg.h> +#include <stddef.h> +#include <string.h> + +#include "upb.h" +#include "upb_string.h" + +#define alignof(t) offsetof(struct { char c; t x; }, x) +#define TYPE_INFO(wire_type, ctype, allows_delimited) \ + {alignof(ctype), sizeof(ctype), wire_type, \ + (1 << wire_type) | (allows_delimited << UPB_WIRE_TYPE_DELIMITED), \ + #ctype}, + +const upb_type_info upb_types[] = { + {0, 0, 0, 0, ""}, // There is no type 0. + TYPE_INFO(UPB_WIRE_TYPE_64BIT, double, 1) // DOUBLE + TYPE_INFO(UPB_WIRE_TYPE_32BIT, float, 1) // FLOAT + TYPE_INFO(UPB_WIRE_TYPE_VARINT, int64_t, 1) // INT64 + TYPE_INFO(UPB_WIRE_TYPE_VARINT, uint64_t, 1) // UINT64 + TYPE_INFO(UPB_WIRE_TYPE_VARINT, int32_t, 1) // INT32 + TYPE_INFO(UPB_WIRE_TYPE_64BIT, uint64_t, 1) // FIXED64 + TYPE_INFO(UPB_WIRE_TYPE_32BIT, uint32_t, 1) // FIXED32 + TYPE_INFO(UPB_WIRE_TYPE_VARINT, bool, 1) // BOOL + TYPE_INFO(UPB_WIRE_TYPE_DELIMITED, void*, 1) // STRING + TYPE_INFO(UPB_WIRE_TYPE_START_GROUP, void*, 0) // GROUP + TYPE_INFO(UPB_WIRE_TYPE_DELIMITED, void*, 1) // MESSAGE + TYPE_INFO(UPB_WIRE_TYPE_DELIMITED, void*, 1) // BYTES + TYPE_INFO(UPB_WIRE_TYPE_VARINT, uint32_t, 1) // UINT32 + TYPE_INFO(UPB_WIRE_TYPE_VARINT, uint32_t, 1) // ENUM + TYPE_INFO(UPB_WIRE_TYPE_32BIT, int32_t, 1) // SFIXED32 + TYPE_INFO(UPB_WIRE_TYPE_64BIT, int64_t, 1) // SFIXED64 + TYPE_INFO(UPB_WIRE_TYPE_VARINT, int32_t, 1) // SINT32 + TYPE_INFO(UPB_WIRE_TYPE_VARINT, int64_t, 1) // SINT64 +}; + +void upb_seterr(upb_status *status, enum upb_status_code code, + const char *msg, ...) { + status->code = code; + upb_string_recycle(&status->str); + va_list args; + va_start(args, msg); + upb_string_vprintf(status->str, msg, args); + va_end(args); +} + +void upb_copyerr(upb_status *to, upb_status *from) +{ + to->code = from->code; + if(from->str) to->str = upb_string_getref(from->str); +} + +void upb_clearerr(upb_status *status) { + status->code = UPB_OK; + upb_string_recycle(&status->str); +} + +void upb_printerr(upb_status *status) { + if(status->str) { + fprintf(stderr, "code: %d, msg: " UPB_STRFMT "\n", + status->code, UPB_STRARG(status->str)); + } else { + fprintf(stderr, "code: %d, no msg\n", status->code); + } +} + +void upb_status_uninit(upb_status *status) { + upb_string_unref(status->str); +} @@ -12,6 +12,7 @@ #include <stdbool.h> #include <stdint.h> #include <stdio.h> // only for size_t. +#include <assert.h> #include "descriptor_const.h" #include "upb_atomic.h" @@ -58,6 +59,10 @@ typedef int16_t upb_field_count_t; // unlimited nesting if we do not limit it. #define UPB_MAX_TYPE_DEPTH 64 +// The biggest possible single value is a 10-byte varint. +#define UPB_MAX_ENCODED_SIZE 10 + + /* Fundamental types and type constants. **************************************/ // A list of types as they are encoded on-the-wire. @@ -67,39 +72,36 @@ enum upb_wire_type { UPB_WIRE_TYPE_DELIMITED = 2, UPB_WIRE_TYPE_START_GROUP = 3, UPB_WIRE_TYPE_END_GROUP = 4, - UPB_WIRE_TYPE_32BIT = 5 + UPB_WIRE_TYPE_32BIT = 5, + + // This isn't a real wire type, but we use this constant to describe varints + // that are expected to be a maximum of 32 bits. + UPB_WIRE_TYPE_32BIT_VARINT = 8 }; typedef uint8_t upb_wire_type_t; -// Value type as defined in a .proto file. eg. string, int32, etc. The +// Type of a field as defined in a .proto file. eg. string, int32, etc. The // integers that represent this are defined by descriptor.proto. Note that // descriptor.proto reserves "0" for errors, and we use it to represent // exceptional circumstances. -typedef uint8_t upb_field_type_t; +typedef uint8_t upb_fieldtype_t; // For referencing the type constants tersely. #define UPB_TYPE(type) GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_ ## type #define UPB_LABEL(type) GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_ ## type -INLINE bool upb_issubmsgtype(upb_field_type_t type) { - return type == UPB_TYPE(GROUP) || type == UPB_TYPE(MESSAGE); -} - -INLINE bool upb_isstringtype(upb_field_type_t type) { - return type == UPB_TYPE(STRING) || type == UPB_TYPE(BYTES); -} - // Info for a given field type. typedef struct { uint8_t align; uint8_t size; - upb_wire_type_t expected_wire_type; + upb_wire_type_t native_wire_type; + uint8_t allowed_wire_types; // For packable fields, also allows delimited. char *ctype; } upb_type_info; // A static array of info about all of the field types, indexed by type number. -extern upb_type_info upb_types[]; +extern const upb_type_info upb_types[]; // The number of a field, eg. "optional string foo = 3". typedef int32_t upb_field_number_t; @@ -116,59 +118,92 @@ typedef union { uint32_t _32bit; } upb_wire_value; -// A tag occurs before each value on-the-wire. -typedef struct { - upb_field_number_t field_number; - upb_wire_type_t wire_type; -} upb_tag; - - /* Polymorphic values of .proto types *****************************************/ -// INTERNAL-ONLY: never refer to these types with a tag ("union", "struct"). -// Always use the typedefs. +struct _upb_string; +typedef struct _upb_string upb_string; +struct _upb_array; +typedef struct _upb_array upb_array; struct _upb_msg; - typedef struct _upb_msg upb_msg; +struct _upb_bytesrc; +typedef struct _upb_bytesrc upb_bytesrc; -typedef upb_atomic_refcount_t upb_data; - -typedef uint32_t upb_strlen_t; - -struct upb_norefcount_string; -struct upb_refcounted_string; -typedef union { - // Must be first, for the UPB_STATIC_STRING_PTR_INIT() macro. - struct upb_norefcount_string *norefcount; - struct upb_refcounted_string *refcounted; - upb_data *base; -} upb_strptr; - -typedef uint32_t upb_arraylen_t; +typedef int32_t upb_strlen_t; +#define UPB_STRLEN_MAX INT32_MAX -typedef union { - // Must be first, for the UPB_STATIC_ARRAY_PTR_INIT() macro. - struct upb_norefcount_array *norefcount; - struct upb_refcounted_array *refcounted; - upb_data *base; -} upb_arrayptr; +// 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 +#define UPB_VALUETYPE_BYTESRC 32 +#define UPB_VALUETYPE_RAW 33 // 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. -typedef union { - double _double; - float _float; - int32_t int32; - int64_t int64; - uint32_t uint32; - uint64_t uint64; - bool _bool; - upb_strptr str; - upb_arrayptr arr; - upb_msg *msg; - upb_data *data; +typedef struct { + union { + double _double; + float _float; + int32_t int32; + int64_t int64; + uint32_t uint32; + uint64_t uint64; + bool _bool; + upb_string *str; + upb_bytesrc *bytesrc; + upb_msg *msg; + upb_array *arr; + upb_atomic_refcount_t *refcount; + void *_void; + } val; + + // In debug mode we carry the value type around also so we can check accesses + // to be sure the right member is being read. +#ifndef NDEBUG + upb_valuetype_t type; +#endif } 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) \ + INLINE ctype upb_value_get ## name(upb_value val) { \ + assert(val.type == proto_type || val.type == UPB_VALUETYPE_RAW); \ + return val.val.membername; \ + } \ + INLINE void upb_value_set ## name(upb_value *val, ctype cval) { \ + SET_TYPE(val->type, proto_type); \ + val->val.membername = cval; \ + } +UPB_VALUE_ACCESSORS(double, _double, double, UPB_TYPE(DOUBLE)); +UPB_VALUE_ACCESSORS(float, _float, float, UPB_TYPE(FLOAT)); +UPB_VALUE_ACCESSORS(int32, int32, int32_t, UPB_TYPE(INT32)); +UPB_VALUE_ACCESSORS(int64, int64, int64_t, UPB_TYPE(INT64)); +UPB_VALUE_ACCESSORS(uint32, uint32, uint32_t, UPB_TYPE(UINT32)); +UPB_VALUE_ACCESSORS(uint64, uint64, uint64_t, UPB_TYPE(UINT64)); +UPB_VALUE_ACCESSORS(bool, _bool, bool, UPB_TYPE(BOOL)); +UPB_VALUE_ACCESSORS(str, str, upb_string*, UPB_TYPE(STRING)); +UPB_VALUE_ACCESSORS(msg, msg, upb_msg*, UPB_TYPE(MESSAGE)); +UPB_VALUE_ACCESSORS(arr, arr, upb_array*, UPB_VALUETYPE_ARRAY); +UPB_VALUE_ACCESSORS(bytesrc, bytesrc, upb_bytesrc*, UPB_VALUETYPE_BYTESRC); + +INLINE void upb_value_setraw(upb_value *val, uint64_t cval) { + SET_TYPE(val->type, UPB_VALUETYPE_RAW); + val->val.uint64 = cval; +} + +INLINE upb_atomic_refcount_t *upb_value_getrefcount(upb_value val) { + assert(val.type == UPB_TYPE(MESSAGE) || + val.type == UPB_TYPE(STRING) || + val.type == UPB_VALUETYPE_ARRAY); + return val.val.refcount; +} + // 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. typedef union { @@ -180,28 +215,29 @@ typedef union { uint32_t *uint32; uint64_t *uint64; bool *_bool; - upb_strptr *str; - upb_arrayptr *arr; + upb_string **str; upb_msg **msg; - upb_data **data; + upb_array **arr; void *_void; } upb_valueptr; INLINE upb_valueptr upb_value_addrof(upb_value *val) { - upb_valueptr ptr = {&val->_double}; + upb_valueptr ptr = {&val->val._double}; return ptr; } -/** - * Converts upb_value_ptr -> upb_value by reading from the pointer. We need to - * know the field type to perform this operation, because we need to know how - * much memory to copy. - */ -INLINE upb_value upb_value_read(upb_valueptr ptr, upb_field_type_t ft) { +// Reads or writes a upb_value from an address represented by a upb_value_ptr. +// We need to know the value type to perform this operation, because we need to +// 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) { upb_value val; #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) { CASE(DOUBLE, _double) @@ -229,15 +265,10 @@ INLINE upb_value upb_value_read(upb_valueptr ptr, upb_field_type_t ft) { #undef CASE } -/** - * Writes a upb_value to a upb_value_ptr location. We need to know the field - * 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, - upb_field_type_t ft) { + upb_fieldtype_t ft) { #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) { CASE(DOUBLE, _double) @@ -267,40 +298,49 @@ INLINE void upb_value_write(upb_valueptr ptr, upb_value val, // Status codes used as a return value. Codes >0 are not fatal and can be // resumed. enum upb_status_code { - UPB_STATUS_OK = 0, + // The operation completed successfully. + UPB_OK = 0, - // The input byte stream ended in the middle of a record. - UPB_STATUS_NEED_MORE_DATA = 1, + // The bytesrc is at EOF and all data was read successfully. + UPB_EOF = 1, - // An unrecoverable error occurred. - UPB_STATUS_ERROR = -1, + // A read or write from a streaming src/sink could not be completed right now. + UPB_TRYAGAIN = 2, - // A varint went for 10 bytes without terminating. - UPB_ERROR_UNTERMINATED_VARINT = -2, + // An unrecoverable error occurred. + UPB_ERROR = -1, - // The max nesting level (UPB_MAX_NESTING) was exceeded. - UPB_ERROR_MAX_NESTING_EXCEEDED = -3 + // A recoverable error occurred (for example, data of the wrong type was + // encountered which we can skip over). + // UPB_STATUS_RECOVERABLE_ERROR = -2 }; -#define UPB_ERRORMSG_MAXLEN 256 +// TODO: consider adding error space and code, to let ie. errno be stored +// as a proper code, or application-specific error codes. typedef struct { - enum upb_status_code code; - char msg[UPB_ERRORMSG_MAXLEN]; + char code; + upb_string *str; } upb_status; -#define UPB_STATUS_INIT {UPB_STATUS_OK, ""} +#define UPB_STATUS_INIT {UPB_OK, NULL} +#define UPB_ERRORMSG_MAXLEN 256 INLINE bool upb_ok(upb_status *status) { - return status->code == UPB_STATUS_OK; + return status->code == UPB_OK; } -INLINE void upb_reset(upb_status *status) { - status->code = UPB_STATUS_OK; - status->msg[0] = '\0'; +INLINE void upb_status_init(upb_status *status) { + status->code = UPB_OK; + status->str = NULL; } +void upb_status_uninit(upb_status *status); + +void upb_printerr(upb_status *status); +void upb_clearerr(upb_status *status); void upb_seterr(upb_status *status, enum upb_status_code code, const char *msg, ...); +void upb_copyerr(upb_status *to, upb_status *from); #ifdef __cplusplus } /* extern "C" */ diff --git a/src/upb_atomic.h b/core/upb_atomic.h index c2cb8ba..1cd848b 100644 --- a/src/upb_atomic.h +++ b/core/upb_atomic.h @@ -29,7 +29,6 @@ extern "C" { #define INLINE static inline #endif -#define UPB_THREAD_UNSAFE #ifdef UPB_THREAD_UNSAFE /* Non-thread-safe implementations. ******************************************/ @@ -65,15 +64,6 @@ INLINE int upb_atomic_fetch_and_add(upb_atomic_refcount_t *a, int val) { return ret; } -typedef struct { -} upb_rwlock_t; - -INLINE void upb_rwlock_init(upb_rwlock_t *l) { (void)l; } -INLINE void upb_rwlock_destroy(upb_rwlock_t *l) { (void)l; } -INLINE void upb_rwlock_rdlock(upb_rwlock_t *l) { (void)l; } -INLINE void upb_rwlock_wrlock(upb_rwlock_t *l) { (void)l; } -INLINE void upb_rwlock_unlock(upb_rwlock_t *l) { (void)l; } - #endif /* Atomic refcount ************************************************************/ @@ -111,10 +101,6 @@ INLINE bool upb_atomic_read(upb_atomic_refcount_t *a) { return __sync_fetch_and_add(&a->v, 0); } -INLINE bool upb_atomic_write(upb_atomic_refcount_t *a, int val) { - a->v = val; -} - #elif defined(WIN32) /* Windows defines atomic increment/decrement. */ @@ -141,11 +127,22 @@ INLINE bool upb_atomic_unref(upb_atomic_refcount_t *a) { Implement them or compile with UPB_THREAD_UNSAFE. #endif +INLINE bool upb_atomic_only(upb_atomic_refcount_t *a) { + return upb_atomic_read(a) == 1; +} + /* Reader/Writer lock. ********************************************************/ #ifdef UPB_THREAD_UNSAFE -/* Already defined. */ +typedef struct { +} upb_rwlock_t; + +INLINE void upb_rwlock_init(upb_rwlock_t *l) { (void)l; } +INLINE void upb_rwlock_destroy(upb_rwlock_t *l) { (void)l; } +INLINE void upb_rwlock_rdlock(upb_rwlock_t *l) { (void)l; } +INLINE void upb_rwlock_wrlock(upb_rwlock_t *l) { (void)l; } +INLINE void upb_rwlock_unlock(upb_rwlock_t *l) { (void)l; } #elif defined(UPB_USE_PTHREADS) diff --git a/core/upb_def.c b/core/upb_def.c new file mode 100644 index 0000000..2eda89f --- /dev/null +++ b/core/upb_def.c @@ -0,0 +1,1326 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2008-2009 Joshua Haberman. See LICENSE for details. + */ + +#include <stdlib.h> +#include "descriptor_const.h" +#include "descriptor.h" +#include "upb_def.h" + +/* Rounds p up to the next multiple of t. */ +static size_t upb_align_up(size_t val, size_t align) { + return val % align == 0 ? val : val + align - (val % align); +} + +static int upb_div_round_up(int numerator, int denominator) { + /* cf. http://stackoverflow.com/questions/17944/how-to-round-up-the-result-of-integer-division */ + return numerator > 0 ? (numerator - 1) / denominator + 1 : 0; +} + +/* Joins strings together, for example: + * join("Foo.Bar", "Baz") -> "Foo.Bar.Baz" + * join("", "Baz") -> "Baz" + * Caller owns a ref on the returned string. */ +static upb_string *upb_join(upb_string *base, upb_string *name) { + if (upb_string_len(base) == 0) { + return upb_string_getref(name); + } else { + return upb_string_asprintf(UPB_STRFMT "." UPB_STRFMT, + UPB_STRARG(base), UPB_STRARG(name)); + } +} + +/* 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; +} + +/* upb_def ********************************************************************/ + +// Defs are reference counted, but can have cycles when types are +// self-recursive or mutually recursive, so we need to be capable of collecting +// the cycles. In our situation defs are immutable (so cycles cannot be +// created or destroyed post-initialization). We need to be thread-safe but +// want to avoid locks if at all possible and rely only on atomic operations. +// +// Our scheme is as follows. First we give each def a flag indicating whether +// it is part of a cycle or not. Because defs are immutable, this flag will +// never change. For acyclic defs, we can use a naive algorithm and avoid the +// overhead of dealing with cycles. Most defs will be acyclic, and most cycles +// will be very short. +// +// For defs that participate in cycles we keep two reference counts. One +// tracks references that come from outside the cycle (we call these external +// references), and is incremented and decremented like a regular refcount. +// The other is a cycle refcount, and works as follows. Every cycle is +// considered distinct, even if two cycles share members. For example, this +// graph has two distinct cycles: +// +// A-->B-->C +// ^ | | +// +---+---+ +// +// The cycles in this graph are AB and ABC. When A's external refcount +// transitions from 0->1, we say that A takes "cycle references" on both +// cycles. Taking a cycle reference means incrementing the cycle refcount of +// all defs in the cycle. Since A and B are common to both cycles, A and B's +// cycle refcounts will be incremented by two, and C's will be incremented by +// one. Likewise, when A's external refcount transitions from 1->0, we +// decrement A and B's cycle refcounts by two and C's by one. We collect a +// cyclic type when its cycle refcount drops to zero. A precondition for this +// is that the external refcount has dropped to zero also. +// +// This algorithm is relatively cheap, since it only requires extra work when +// the external refcount on a cyclic type transitions from 0->1 or 1->0. + +static void upb_msgdef_free(upb_msgdef *m); +static void upb_enumdef_free(upb_enumdef *e); +static void upb_unresolveddef_free(struct _upb_unresolveddef *u); + +static void upb_def_free(upb_def *def) +{ + switch(def->type) { + case UPB_DEF_MSG: + upb_msgdef_free(upb_downcast_msgdef(def)); + break; + case UPB_DEF_ENUM: + upb_enumdef_free(upb_downcast_enumdef(def)); + break; + case UPB_DEF_SVC: + assert(false); /* Unimplemented. */ + break; + case UPB_DEF_UNRESOLVED: + upb_unresolveddef_free(upb_downcast_unresolveddef(def)); + break; + default: + assert(false); + } +} + +// Depth-first search for all cycles that include cycle_base. Returns the +// number of paths from def that lead to cycle_base, which is equivalent to the +// number of cycles def is in that include cycle_base. +// +// open_defs tracks the set of nodes that are currently being visited in the +// search so we can stop the search if we detect a cycles that do not involve +// cycle_base. We can't color the nodes as we go by writing to a member of the +// def, because another thread could be performing the search concurrently. +static int upb_cycle_ref_or_unref(upb_msgdef *m, upb_msgdef *cycle_base, + upb_msgdef **open_defs, int num_open_defs, + bool ref) { + bool found = false; + for(int i = 0; i < num_open_defs; i++) { + if(open_defs[i] == m) { + // We encountered a cycle that did not involve cycle_base. + found = true; + break; + } + } + + if(found || num_open_defs == UPB_MAX_TYPE_CYCLE_LEN) { + return 0; + } else if(m == cycle_base) { + return 1; + } else { + int path_count = 0; + if(cycle_base == NULL) { + cycle_base = m; + } else { + open_defs[num_open_defs++] = m; + } + upb_msg_iter iter = upb_msg_begin(m); + for(; !upb_msg_done(iter); iter = upb_msg_next(m, iter)) { + upb_fielddef *f = upb_msg_iter_field(iter); + upb_def *def = f->def; + if(upb_issubmsg(f) && def->is_cyclic) { + upb_msgdef *sub_m = upb_downcast_msgdef(def); + path_count += upb_cycle_ref_or_unref(sub_m, cycle_base, open_defs, + num_open_defs, ref); + } + } + if(ref) { + upb_atomic_add(&m->cycle_refcount, path_count); + } else { + if(upb_atomic_add(&m->cycle_refcount, -path_count)) + upb_def_free(UPB_UPCAST(m)); + } + return path_count; + } +} + +void _upb_def_reftozero(upb_def *def) { + if(def->is_cyclic) { + upb_msgdef *m = upb_downcast_msgdef(def); + upb_msgdef *open_defs[UPB_MAX_TYPE_CYCLE_LEN]; + upb_cycle_ref_or_unref(m, NULL, open_defs, 0, false); + } else { + upb_def_free(def); + } +} + +void _upb_def_cyclic_ref(upb_def *def) { + upb_msgdef *open_defs[UPB_MAX_TYPE_CYCLE_LEN]; + upb_cycle_ref_or_unref(upb_downcast_msgdef(def), NULL, open_defs, 0, true); +} + +static void upb_def_init(upb_def *def, upb_deftype type) { + def->type = type; + def->is_cyclic = 0; // We detect this later, after resolving refs. + def->search_depth = 0; + def->fqname = NULL; + upb_atomic_refcount_init(&def->refcount, 1); +} + +static void upb_def_uninit(upb_def *def) { + upb_string_unref(def->fqname); +} + + +/* 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; +} + +static upb_def *upb_deflist_last(upb_deflist *l) { + return l->defs[l->len-1]; +} + +// 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); + } +} + +// 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 { + upb_string *name; + // Index of the first def that is under this scope. For msgdefs, the + // msgdef itself is at start-1. + int start; +} upb_defbuilder_frame; + +struct _upb_defbuilder { + upb_deflist defs; + upb_defbuilder_frame stack[UPB_MAX_TYPE_DEPTH]; + int stack_len; + upb_status status; + + uint32_t number; + upb_string *name; + bool saw_number; + bool saw_name; + + upb_fielddef *f; +}; +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); + + +static void upb_defbuilder_init(upb_defbuilder *b) { + upb_deflist_init(&b->defs); + upb_status_init(&b->status); + b->stack_len = 0; + b->name = NULL; +} + +static void upb_defbuilder_uninit(upb_defbuilder *b) { + upb_string_unref(b->name); + upb_status_uninit(&b->status); + upb_deflist_uninit(&b->defs); +} + +static upb_msgdef *upb_defbuilder_top(upb_defbuilder *b) { + if (b->stack_len <= 1) return NULL; + int index = b->stack[b->stack_len-1].start - 1; + assert(index >= 0); + return upb_downcast_msgdef(b->defs.defs[index]); +} + +static upb_def *upb_defbuilder_last(upb_defbuilder *b) { + return upb_deflist_last(&b->defs); +} + +// 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_startmsg(void *_b) { + upb_defbuilder *b = _b; + upb_defbuilder_startcontainer(b); + return UPB_CONTINUE; +} + +static upb_flow_t upb_defbuilder_FileDescriptorProto_endmsg(void *_b) { + upb_defbuilder *b = _b; + upb_defbuilder_endcontainer(b); + return UPB_CONTINUE; +} + +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; + } + return UPB_CONTINUE; +} + +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_SKIPSUBMSG; + } +} + +static void upb_defbuilder_register_FileDescriptorProto(upb_defbuilder *b, + upb_handlers *h) { + static upb_handlerset handlers = { + &upb_defbuilder_FileDescriptorProto_startmsg, + &upb_defbuilder_FileDescriptorProto_endmsg, + &upb_defbuilder_FileDescriptorProto_value, + &upb_defbuilder_FileDescriptorProto_startsubmsg, + }; + upb_register_handlerset(h, &handlers); + upb_set_handler_closure(h, b, &b->status); +} + +// 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; + } + return UPB_CONTINUE; +} + +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; + } + return UPB_SKIPSUBMSG; +} + +static void upb_defbuilder_register_FileDescriptorSet( + upb_defbuilder *b, upb_handlers *h) { + static upb_handlerset handlers = { + NULL, // startmsg + NULL, // endmsg + &upb_defbuilder_FileDescriptorSet_value, + &upb_defbuilder_FileDescriptorSet_startsubmsg, + }; + upb_register_handlerset(h, &handlers); + upb_set_handler_closure(h, b, &b->status); +} + + +/* upb_unresolveddef **********************************************************/ + +// Unresolved defs are used as temporary placeholders for a def whose name has +// not been resolved yet. During the name resolution step, all unresolved defs +// are replaced with pointers to the actual def being referenced. +typedef struct _upb_unresolveddef { + upb_def base; + + // The target type name. This may or may not be fully qualified. It is + // tempting to want to use base.fqname for this, but that will be qualified + // which is inappropriate for a name we still have to resolve. + upb_string *name; +} upb_unresolveddef; + +// Is passed a ref on the string. +static upb_unresolveddef *upb_unresolveddef_new(upb_string *str) { + upb_unresolveddef *def = malloc(sizeof(*def)); + upb_def_init(&def->base, UPB_DEF_UNRESOLVED); + def->name = upb_string_getref(str); + return def; +} + +static void upb_unresolveddef_free(struct _upb_unresolveddef *def) { + upb_string_unref(def->name); + upb_def_uninit(&def->base); + free(def); +} + + +/* upb_enumdef ****************************************************************/ + +static void upb_enumdef_free(upb_enumdef *e) { + upb_enum_iter i; + for(i = upb_enum_begin(e); !upb_enum_done(i); i = upb_enum_next(e, i)) { + // Frees the ref taken when the string was parsed. + upb_string_unref(upb_enum_iter_name(i)); + } + upb_strtable_free(&e->ntoi); + upb_inttable_free(&e->iton); + upb_def_uninit(&e->base); + free(e); +} + +// google.protobuf.EnumValueDescriptorProto. +static upb_flow_t upb_enumdef_EnumValueDescriptorProto_startmsg(void *_b) { + upb_defbuilder *b = _b; + b->saw_number = false; + b->saw_name = false; + return UPB_CONTINUE; +} + +static upb_flow_t upb_enumdef_EnumValueDescriptorProto_value(void *_b, + upb_fielddef *f, + upb_value val) { + upb_defbuilder *b = _b; + switch(f->number) { + case GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NAME_FIELDNUM: + upb_string_unref(b->name); + b->name = upb_string_getref(upb_value_getstr(val)); + b->saw_name = true; + break; + case GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO_NUMBER_FIELDNUM: + b->number = upb_value_getint32(val); + b->saw_number = true; + break; + default: + break; + } + return UPB_CONTINUE; +} + +static upb_flow_t upb_enumdef_EnumValueDescriptorProto_endmsg(void *_b) { + upb_defbuilder *b = _b; + if(!b->saw_number || !b->saw_name) { + upb_seterr(&b->status, UPB_ERROR, "Enum value missing name or number."); + return UPB_BREAK; + } + upb_ntoi_ent ntoi_ent = {{b->name, 0}, b->number}; + upb_iton_ent iton_ent = {{b->number, 0}, b->name}; + upb_enumdef *e = upb_downcast_enumdef(upb_defbuilder_last(b)); + upb_strtable_insert(&e->ntoi, &ntoi_ent.e); + upb_inttable_insert(&e->iton, &iton_ent.e); + // We don't unref "name" because we pass our ref to the iton entry of the + // table. strtables can ref their keys, but the inttable doesn't know that + // the value is a string. + b->name = NULL; + return UPB_CONTINUE; +} + +static void upb_enumdef_register_EnumValueDescriptorProto(upb_defbuilder *b, + upb_handlers *h) { + static upb_handlerset handlers = { + &upb_enumdef_EnumValueDescriptorProto_startmsg, + &upb_enumdef_EnumValueDescriptorProto_endmsg, + &upb_enumdef_EnumValueDescriptorProto_value, + }; + upb_register_handlerset(h, &handlers); + upb_set_handler_closure(h, b, &b->status); +} + +// google.protobuf.EnumDescriptorProto. +static upb_flow_t upb_enumdef_EnumDescriptorProto_startmsg(void *_b) { + upb_defbuilder *b = _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)); + return UPB_CONTINUE; +} + +static upb_flow_t upb_enumdef_EnumDescriptorProto_endmsg(void *_b) { + (void)_b; + assert(upb_defbuilder_last((upb_defbuilder*)_b)->fqname != NULL); + return UPB_CONTINUE; +} + +static upb_flow_t upb_enumdef_EnumDescriptorProto_value(void *_b, + upb_fielddef *f, + upb_value val) { + upb_defbuilder *b = _b; + switch(f->number) { + case GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_NAME_FIELDNUM: { + upb_enumdef *e = upb_downcast_enumdef(upb_defbuilder_last(b)); + upb_string_unref(e->base.fqname); + e->base.fqname = upb_string_getref(upb_value_getstr(val)); + return UPB_CONTINUE; + } + case GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_FIELDNUM: + return BEGIN_SUBMSG; + default: + return UPB_CONTINUE; + } +} + +static upb_flow_t upb_enumdef_EnumDescriptorProto_startsubmsg(void *_b, + upb_fielddef *f, + upb_handlers *h) { + upb_defbuilder *b = _b; + switch(f->number) { + case GOOGLE_PROTOBUF_ENUMDESCRIPTORPROTO_VALUE_FIELDNUM: + upb_enumdef_register_EnumValueDescriptorProto(b, h); + return UPB_DELEGATE; + default: + return UPB_SKIPSUBMSG; + } +} + +static void upb_enumdef_register_EnumDescriptorProto(upb_defbuilder *b, + upb_handlers *h) { + static upb_handlerset handlers = { + &upb_enumdef_EnumDescriptorProto_startmsg, + &upb_enumdef_EnumDescriptorProto_endmsg, + &upb_enumdef_EnumDescriptorProto_value, + &upb_enumdef_EnumDescriptorProto_startsubmsg, + }; + upb_register_handlerset(h, &handlers); + upb_set_handler_closure(h, b, &b->status); +} + +upb_enum_iter upb_enum_begin(upb_enumdef *e) { + // We could iterate over either table here; the choice is arbitrary. + return upb_inttable_begin(&e->iton); +} + +upb_enum_iter upb_enum_next(upb_enumdef *e, upb_enum_iter iter) { + assert(iter); + return upb_inttable_next(&e->iton, &iter->e); +} + +upb_string *upb_enumdef_iton(upb_enumdef *def, upb_enumval_t num) { + upb_iton_ent *e = + (upb_iton_ent*)upb_inttable_fastlookup(&def->iton, num, sizeof(*e)); + return e ? e->string : NULL; +} + + +/* upb_fielddef ***************************************************************/ + +static void upb_fielddef_free(upb_fielddef *f) { + upb_string_unref(f->name); + if(f->owned) { + upb_def_unref(f->def); + } + free(f); +} + +static upb_flow_t upb_fielddef_startmsg(void *_b) { + upb_defbuilder *b = _b; + upb_fielddef *f = malloc(sizeof(*f)); + f->number = -1; + f->name = NULL; + f->def = NULL; + f->owned = false; + f->msgdef = upb_defbuilder_top(b); + b->f = f; + return UPB_CONTINUE; +} + +static upb_flow_t upb_fielddef_endmsg(void *_b) { + upb_defbuilder *b = _b; + upb_fielddef *f = b->f; + // TODO: verify that all required fields were present. + assert(f->number != -1 && f->name != NULL); + assert((f->def != NULL) == upb_hasdef(f)); + + // Field was successfully read, add it as a field of the msgdef. + upb_msgdef *m = upb_defbuilder_top(b); + upb_itof_ent itof_ent = {{f->number, 0}, f}; + upb_ntof_ent ntof_ent = {{f->name, 0}, f}; + upb_inttable_insert(&m->itof, &itof_ent.e); + upb_strtable_insert(&m->ntof, &ntof_ent.e); + return UPB_CONTINUE; +} + +static upb_flow_t upb_fielddef_value(void *_b, upb_fielddef *f, upb_value val) { + upb_defbuilder *b = _b; + switch(f->number) { + case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_FIELDNUM: + b->f->type = upb_value_getint32(val); + break; + case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_FIELDNUM: + b->f->label = upb_value_getint32(val); + break; + case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NUMBER_FIELDNUM: + b->f->number = upb_value_getint32(val); + break; + case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_NAME_FIELDNUM: + upb_string_unref(b->f->name); + b->f->name = upb_string_getref(upb_value_getstr(val)); + break; + case GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_NAME_FIELDNUM: { + upb_def_unref(b->f->def); + b->f->def = UPB_UPCAST(upb_unresolveddef_new(upb_value_getstr(val))); + b->f->owned = true; + break; + } + } + return UPB_CONTINUE; +} + +static void upb_fielddef_register_FieldDescriptorProto(upb_defbuilder *b, + upb_handlers *h) { + static upb_handlerset handlers = { + &upb_fielddef_startmsg, + &upb_fielddef_endmsg, + &upb_fielddef_value, + }; + upb_register_handlerset(h, &handlers); + upb_set_handler_closure(h, b, &b->status); +} + + +/* upb_msgdef *****************************************************************/ + +static int upb_compare_typed_fields(upb_fielddef *f1, upb_fielddef *f2) { + // Sort by data size (ascending) to reduce padding. + size_t size1 = upb_types[f1->type].size; + size_t size2 = upb_types[f2->type].size; + if (size1 != size2) return size1 - size2; + // Otherwise return in number order (just so we get a reproduceable order. + return f1->number - f2->number; +} + +static int upb_compare_fields(const void *f1, const void *f2) { + return upb_compare_typed_fields(*(void**)f1, *(void**)f2); +} + +// google.protobuf.DescriptorProto. +static upb_flow_t upb_msgdef_startmsg(void *_b) { + upb_defbuilder *b = _b; + upb_msgdef *m = malloc(sizeof(*m)); + upb_def_init(&m->base, UPB_DEF_MSG); + upb_atomic_refcount_init(&m->cycle_refcount, 0); + upb_inttable_init(&m->itof, 4, sizeof(upb_itof_ent)); + upb_strtable_init(&m->ntof, 4, sizeof(upb_ntof_ent)); + upb_deflist_push(&b->defs, UPB_UPCAST(m)); + upb_defbuilder_startcontainer(b); + return UPB_CONTINUE; +} + +static upb_flow_t upb_msgdef_endmsg(void *_b) { + upb_defbuilder *b = _b; + upb_msgdef *m = upb_defbuilder_top(b); + if(!m->base.fqname) { + upb_seterr(&b->status, UPB_ERROR, "Encountered message with no name."); + return UPB_BREAK; + } + + // Create an ordering over the fields. + upb_field_count_t n = upb_msgdef_numfields(m); + upb_fielddef **sorted_fields = malloc(sizeof(upb_fielddef*) * n); + upb_field_count_t field = 0; + upb_msg_iter i; + for (i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) { + sorted_fields[field++]= upb_msg_iter_field(i); + } + qsort(sorted_fields, n, sizeof(*sorted_fields), upb_compare_fields); + + // Assign offsets in the msg. + m->set_flags_bytes = upb_div_round_up(n, 8); + m->size = sizeof(upb_atomic_refcount_t) + m->set_flags_bytes; + + size_t max_align = 0; + for (int i = 0; i < n; i++) { + upb_fielddef *f = sorted_fields[i]; + const upb_type_info *type_info = &upb_types[f->type]; + + // This identifies the set bit. When we implement is_initialized (a + // general check about whether all required bits are set) we will probably + // want to use a different ordering that puts all the required bits + // together. + f->field_index = i; + + // General alignment rules are: each member must be at an address that is a + // multiple of that type's alignment. Also, the size of the structure as a + // whole must be a multiple of the greatest alignment of any member. + size_t offset = upb_align_up(m->size, type_info->align); + // Offsets are relative to the end of the refcount. + f->byte_offset = offset - sizeof(upb_atomic_refcount_t); + m->size = offset + type_info->size; + max_align = UPB_MAX(max_align, type_info->align); + } + free(sorted_fields); + + if (max_align > 0) m->size = upb_align_up(m->size, max_align); + + upb_defbuilder_endcontainer(b); + return UPB_CONTINUE; +} + +static upb_flow_t upb_msgdef_value(void *_b, upb_fielddef *f, upb_value val) { + upb_defbuilder *b = _b; + switch(f->number) { + case GOOGLE_PROTOBUF_DESCRIPTORPROTO_NAME_FIELDNUM: { + upb_msgdef *m = upb_defbuilder_top(b); + upb_string_unref(m->base.fqname); + m->base.fqname = upb_string_getref(upb_value_getstr(val)); + upb_defbuilder_setscopename(b, upb_value_getstr(val)); + return UPB_CONTINUE; + } + case GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_FIELDNUM: + case GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_FIELDNUM: + case GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_FIELDNUM: + return BEGIN_SUBMSG; + default: + // TODO: extensions. + return UPB_CONTINUE; + } +} + +static upb_flow_t upb_msgdef_startsubmsg(void *_b, upb_fielddef *f, + upb_handlers *h) { + upb_defbuilder *b = _b; + switch(f->number) { + case GOOGLE_PROTOBUF_DESCRIPTORPROTO_FIELD_FIELDNUM: + upb_fielddef_register_FieldDescriptorProto(b, h); + return UPB_DELEGATE; + case GOOGLE_PROTOBUF_DESCRIPTORPROTO_NESTED_TYPE_FIELDNUM: + upb_msgdef_register_DescriptorProto(b, h); + return UPB_DELEGATE; + case GOOGLE_PROTOBUF_DESCRIPTORPROTO_ENUM_TYPE_FIELDNUM: + upb_enumdef_register_EnumDescriptorProto(b, h); + return UPB_DELEGATE; + break; + default: + return UPB_SKIPSUBMSG; + } +} + +static void upb_msgdef_register_DescriptorProto(upb_defbuilder *b, + upb_handlers *h) { + static upb_handlerset handlers = { + &upb_msgdef_startmsg, + &upb_msgdef_endmsg, + &upb_msgdef_value, + &upb_msgdef_startsubmsg, + }; + upb_register_handlerset(h, &handlers); + upb_set_handler_closure(h, b, &b->status); +} + +static void upb_msgdef_free(upb_msgdef *m) +{ + upb_msg_iter i; + for(i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) + upb_fielddef_free(upb_msg_iter_field(i)); + upb_strtable_free(&m->ntof); + upb_inttable_free(&m->itof); + upb_def_uninit(&m->base); + free(m); +} + +static void upb_msgdef_resolve(upb_msgdef *m, upb_fielddef *f, upb_def *def) { + (void)m; + if(f->owned) upb_def_unref(f->def); + f->def = def; + // We will later make the ref unowned if it is a part of a cycle. + f->owned = true; + upb_def_ref(def); +} + +upb_msg_iter upb_msg_begin(upb_msgdef *m) { + return upb_inttable_begin(&m->itof); +} + +upb_msg_iter upb_msg_next(upb_msgdef *m, upb_msg_iter iter) { + return upb_inttable_next(&m->itof, &iter->e); +} + +/* upb_symtab adding defs *****************************************************/ + +// This is a self-contained group of functions that, given a list of upb_defs +// whose references are not yet resolved, resolves references and adds them +// atomically to a upb_symtab. + +typedef struct { + upb_strtable_entry e; + upb_def *def; +} upb_symtab_ent; + +// Given a symbol and the base symbol inside which it is defined, find the +// symbol's definition in t. +static upb_symtab_ent *upb_resolve(upb_strtable *t, + upb_string *base, upb_string *sym) +{ + if(upb_string_len(base) + upb_string_len(sym) + 1 >= UPB_SYMBOL_MAXLEN || + upb_string_len(sym) == 0) return NULL; + + if(upb_string_getrobuf(sym)[0] == UPB_SYMBOL_SEPARATOR) { + // Symbols starting with '.' are absolute, so we do a single lookup. + // Slice to omit the leading '.' + upb_string *sym_str = upb_strslice(sym, 1, upb_string_len(sym) - 1); + upb_symtab_ent *e = upb_strtable_lookup(t, sym_str); + upb_string_unref(sym_str); + return e; + } else { + // Remove components from base until we find an entry or run out. + // TODO: This branch is totally broken, but currently not used. + upb_string *sym_str = upb_string_new(); + int baselen = upb_string_len(base); + while(1) { + // sym_str = base[0...base_len] + UPB_SYMBOL_SEPARATOR + sym + upb_strlen_t len = baselen + upb_string_len(sym) + 1; + char *buf = upb_string_getrwbuf(sym_str, len); + memcpy(buf, upb_string_getrobuf(base), baselen); + buf[baselen] = UPB_SYMBOL_SEPARATOR; + memcpy(buf + baselen + 1, upb_string_getrobuf(sym), upb_string_len(sym)); + + upb_symtab_ent *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(buf, UPB_SYMBOL_SEPARATOR, baselen); + } + } +} + +// Performs a pass over the type graph to find all cycles that include m. +static bool upb_symtab_findcycles(upb_msgdef *m, int depth, upb_status *status) +{ + if(depth > UPB_MAX_TYPE_DEPTH) { + // We have found a non-cyclic path from the base of the type tree that + // exceeds the maximum allowed depth. There are many situations in upb + // where we recurse over the type tree (like for example, right now) and an + // absurdly deep tree could cause us to stack overflow on systems with very + // limited stacks. + upb_seterr(status, UPB_ERROR, "Type " UPB_STRFMT " was found at " + "depth %d in the type graph, which exceeds the maximum type " + "depth of %d.", UPB_UPCAST(m)->fqname, depth, + UPB_MAX_TYPE_DEPTH); + return false; + } else if(UPB_UPCAST(m)->search_depth == 1) { + // Cycle! + int cycle_len = depth - 1; + if(cycle_len > UPB_MAX_TYPE_CYCLE_LEN) { + upb_seterr(status, UPB_ERROR, "Type " UPB_STRFMT " was involved " + "in a cycle of length %d, which exceeds the maximum type " + "cycle length of %d.", UPB_UPCAST(m)->fqname, cycle_len, + UPB_MAX_TYPE_CYCLE_LEN); + return false; + } + return true; + } else if(UPB_UPCAST(m)->search_depth > 0) { + // This was a cycle, but did not originate from the base of our search tree. + // We'll find it when we call find_cycles() on this node directly. + return false; + } else { + UPB_UPCAST(m)->search_depth = ++depth; + bool cycle_found = false; + upb_msg_iter i; + for(i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) { + upb_fielddef *f = upb_msg_iter_field(i); + if(!upb_issubmsg(f)) continue; + upb_def *sub_def = f->def; + upb_msgdef *sub_m = upb_downcast_msgdef(sub_def); + if(upb_symtab_findcycles(sub_m, depth, status)) { + cycle_found = true; + UPB_UPCAST(m)->is_cyclic = true; + if(f->owned) { + upb_atomic_unref(&sub_def->refcount); + f->owned = false; + } + } + } + UPB_UPCAST(m)->search_depth = 0; + return cycle_found; + } +} + +// Given a table of pending defs "tmptab" and a table of existing defs "symtab", +// resolves all of the unresolved refs for the defs in tmptab. +bool upb_resolverefs(upb_strtable *tmptab, upb_strtable *symtab, + upb_status *status) +{ + upb_symtab_ent *e; + for(e = upb_strtable_begin(tmptab); e; e = upb_strtable_next(tmptab, &e->e)) { + upb_msgdef *m = upb_dyncast_msgdef(e->def); + if(!m) continue; + // Type names are resolved relative to the message in which they appear. + upb_string *base = e->e.key; + + upb_msg_iter i; + for(i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) { + upb_fielddef *f = upb_msg_iter_field(i); + if(!upb_hasdef(f)) continue; // No resolving necessary. + upb_string *name = upb_downcast_unresolveddef(f->def)->name; + + // Resolve from either the tmptab (pending adds) or symtab (existing + // defs). If both exist, prefer the pending add, because it will be + // overwriting the existing def. + upb_symtab_ent *found; + if(!(found = upb_resolve(tmptab, base, name)) && + !(found = upb_resolve(symtab, base, name))) { + upb_seterr(status, UPB_ERROR, + "could not resolve symbol '" UPB_STRFMT "'" + " in context '" UPB_STRFMT "'", + UPB_STRARG(name), UPB_STRARG(base)); + return false; + } + + // Check the type of the found def. + upb_fieldtype_t expected = upb_issubmsg(f) ? UPB_DEF_MSG : UPB_DEF_ENUM; + if(found->def->type != expected) { + upb_seterr(status, UPB_ERROR, "Unexpected type"); + return false; + } + upb_msgdef_resolve(m, f, found->def); + } + } + + // Deal with type cycles. + for(e = upb_strtable_begin(tmptab); e; e = upb_strtable_next(tmptab, &e->e)) { + upb_msgdef *m = upb_dyncast_msgdef(e->def); + if(!m) continue; + // The findcycles() call will decrement the external refcount of the + upb_symtab_findcycles(m, 0, status); + upb_msgdef *open_defs[UPB_MAX_TYPE_CYCLE_LEN]; + upb_cycle_ref_or_unref(m, NULL, open_defs, 0, true); + } + + return true; +} + +// Given a list of defs, a list of extensions (in the future), and a flag +// indicating whether the new defs can overwrite existing defs in the symtab, +// attempts to add the given defs to the symtab. The whole operation either +// succeeds or fails. Ownership of "defs" and "exts" is taken. +bool upb_symtab_add_defs(upb_symtab *s, upb_def **defs, int num_defs, + bool allow_redef, upb_status *status) +{ + upb_rwlock_wrlock(&s->lock); + + // Build a table of the defs we mean to add, for duplicate detection and name + // resolution. + upb_strtable tmptab; + upb_strtable_init(&tmptab, num_defs, sizeof(upb_symtab_ent)); + for (int i = 0; i < num_defs; i++) { + upb_def *def = defs[i]; + upb_symtab_ent e = {{def->fqname, 0}, def}; + + // Redefinition is never allowed within a single FileDescriptorSet. + // Additionally, we only allow overwriting of an existing definition if + // allow_redef is set. + if (upb_strtable_lookup(&tmptab, def->fqname) || + (!allow_redef && upb_strtable_lookup(&s->symtab, def->fqname))) { + upb_seterr(status, UPB_ERROR, "Redefinition of symbol " UPB_STRFMT, + UPB_STRARG(def->fqname)); + goto err; + } + + // Pass ownership from the deflist to the strtable. + upb_strtable_insert(&tmptab, &e.e); + defs[i] = NULL; + } + + // TODO: process the list of extensions by modifying entries from + // tmptab in-place (copying them from the symtab first if necessary). + + if (!upb_resolverefs(&tmptab, &s->symtab, status)) goto err; + + // The defs in tmptab have been vetted, and can be added to the symtab + // without causing errors. Now add all tmptab defs to the symtab, + // overwriting (and releasing a ref on) any existing defs with the same + // names. Ownership for tmptab defs passes from the tmptab to the symtab. + upb_symtab_ent *tmptab_e; + for(tmptab_e = upb_strtable_begin(&tmptab); tmptab_e; + tmptab_e = upb_strtable_next(&tmptab, &tmptab_e->e)) { + upb_symtab_ent *symtab_e = + upb_strtable_lookup(&s->symtab, tmptab_e->def->fqname); + if(symtab_e) { + upb_def_unref(symtab_e->def); + symtab_e->def = tmptab_e->def; + } else { + upb_strtable_insert(&s->symtab, &tmptab_e->e); + } + } + + upb_rwlock_unlock(&s->lock); + upb_strtable_free(&tmptab); + return true; + +err: + // We need to free all defs from "tmptab." + upb_rwlock_unlock(&s->lock); + for(upb_symtab_ent *e = upb_strtable_begin(&tmptab); e; + e = upb_strtable_next(&tmptab, &e->e)) { + upb_def_unref(e->def); + } + upb_strtable_free(&tmptab); + for (int i = 0; i < num_defs; i++) upb_def_unref(defs[i]); + return false; +} + + +/* upb_symtab public interface ************************************************/ + +upb_symtab *upb_symtab_new() +{ + upb_symtab *s = malloc(sizeof(*s)); + upb_atomic_refcount_init(&s->refcount, 1); + upb_rwlock_init(&s->lock); + upb_strtable_init(&s->symtab, 16, sizeof(upb_symtab_ent)); + return s; +} + +static void upb_free_symtab(upb_strtable *t) +{ + upb_symtab_ent *e; + for(e = upb_strtable_begin(t); e; e = upb_strtable_next(t, &e->e)) + upb_def_unref(e->def); + upb_strtable_free(t); +} + +void _upb_symtab_free(upb_symtab *s) +{ + upb_free_symtab(&s->symtab); + upb_rwlock_destroy(&s->lock); + free(s); +} + +upb_def **upb_symtab_getdefs(upb_symtab *s, int *count, upb_deftype_t type) +{ + upb_rwlock_rdlock(&s->lock); + int total = upb_strtable_count(&s->symtab); + // We may only use part of this, depending on how many symbols are of the + // correct type. + upb_def **defs = malloc(sizeof(*defs) * total); + upb_symtab_ent *e = upb_strtable_begin(&s->symtab); + int i = 0; + for(; e; e = upb_strtable_next(&s->symtab, &e->e)) { + upb_def *def = e->def; + assert(def); + if(type == UPB_DEF_ANY || def->type == type) + defs[i++] = def; + } + upb_rwlock_unlock(&s->lock); + *count = i; + for(i = 0; i < *count; i++) + upb_def_ref(defs[i]); + return defs; +} + +upb_def *upb_symtab_lookup(upb_symtab *s, upb_string *sym) +{ + upb_rwlock_rdlock(&s->lock); + upb_symtab_ent *e = upb_strtable_lookup(&s->symtab, sym); + upb_def *ret = NULL; + if(e) { + ret = e->def; + upb_def_ref(ret); + } + upb_rwlock_unlock(&s->lock); + return ret; +} + + +upb_def *upb_symtab_resolve(upb_symtab *s, upb_string *base, upb_string *symbol) { + upb_rwlock_rdlock(&s->lock); + upb_symtab_ent *e = upb_resolve(&s->symtab, base, symbol); + upb_def *ret = NULL; + if(e) { + ret = e->def; + upb_def_ref(ret); + } + upb_rwlock_unlock(&s->lock); + return ret; +} + +void upb_symtab_addfds(upb_symtab *s, upb_src *src, upb_status *status) +{ + upb_defbuilder b; + upb_defbuilder_init(&b); + upb_handlers handlers; + upb_handlers_init(&handlers); + upb_defbuilder_register_FileDescriptorSet(&b, &handlers); + upb_src_sethandlers(src, &handlers); + upb_src_run(src, status); + if (upb_ok(status)) + upb_symtab_add_defs(s, b.defs.defs, b.defs.len, false, status); + upb_defbuilder_uninit(&b); +} + + +/* upb_baredecoder ************************************************************/ + +// upb_baredecoder is a upb_src that can parse a subset of the protocol buffer +// binary format. It is only used for bootstrapping. It can parse without +// having a upb_msgdef, which is why it is useful for bootstrapping the first +// msgdef. On the downside, it does not support: +// +// * having its input span multiple upb_strings. +// * reading any field of the returned upb_fielddef's except f->number. +// * keeping a pointer to the upb_fielddef* and reading it later (the same +// upb_fielddef is reused over and over). +// * detecting errors in the input (we trust that our input is known-good). +// * skipping the rest of the submessage (UPB_SKIPSUBMSG). +// +// It also does not support any of the follow protobuf features: +// * packed fields. +// * groups. +// * zig-zag-encoded types like sint32 and sint64. +// +// Since it cannot tell the difference between submessages and strings, it +// always reports them as strings first, but if the value callback returns +// UPB_TREAT_AS_SUBMSG this signals to the baredecoder that it should be +// treated like a submessage instead. +// +// TODO: for bootstrapping we should define a slightly different wire format +// that includes enough information to know the precise integer types and +// that distinguishes between strings and submessages. This will allow +// us to get rid of the UPB_TREAT_AS_SUBMSG hack. It will also allow us +// to get rid of the upb_value_setraw() scheme, which would be more +// complicated to support on big-endian machines. + +typedef struct { + upb_src src; + upb_string *input; + upb_strlen_t offset; + upb_dispatcher dispatcher; +} upb_baredecoder; + +static uint64_t upb_baredecoder_readv64(upb_baredecoder *d) +{ + const uint8_t *start = (uint8_t*)upb_string_getrobuf(d->input) + d->offset; + const uint8_t *buf = start; + uint8_t last = 0x80; + uint64_t val = 0; + for(int bitpos = 0; (last & 0x80); buf++, bitpos += 7) + val |= ((uint64_t)((last = *buf) & 0x7F)) << bitpos; + d->offset += buf - start; + return val; +} + +static uint32_t upb_baredecoder_readv32(upb_baredecoder *d) +{ + return (uint32_t)upb_baredecoder_readv64(d); // Truncate. +} + +static uint64_t upb_baredecoder_readf64(upb_baredecoder *d) +{ + uint64_t val; + memcpy(&val, upb_string_getrobuf(d->input) + d->offset, 8); + d->offset += 8; + return val; +} + +static uint32_t upb_baredecoder_readf32(upb_baredecoder *d) +{ + uint32_t val; + memcpy(&val, upb_string_getrobuf(d->input) + d->offset, 4); + d->offset += 4; + return val; +} + +static void upb_baredecoder_sethandlers(upb_src *src, upb_handlers *handlers) { + upb_baredecoder *d = (upb_baredecoder*)src; + upb_dispatcher_reset(&d->dispatcher, handlers); +} + +static void upb_baredecoder_run(upb_src *src, upb_status *status) { + upb_baredecoder *d = (upb_baredecoder*)src; + assert(!upb_handlers_isempty(&d->dispatcher.top->handlers)); + upb_string *str = NULL; + upb_strlen_t stack[UPB_MAX_NESTING] = {UPB_STRLEN_MAX}; + upb_strlen_t *top = &stack[0]; + d->offset = 0; + +#define CHECK(x) if (x != UPB_CONTINUE && x != BEGIN_SUBMSG) goto err; + + CHECK(upb_dispatch_startmsg(&d->dispatcher)); + while(d->offset < upb_string_len(d->input)) { + uint32_t key = upb_baredecoder_readv64(d); + upb_fielddef f; + f.number = key >> 3; + upb_wire_type_t wt = key & 0x7; + if(wt == UPB_WIRE_TYPE_DELIMITED) { + uint32_t delim_len = upb_baredecoder_readv32(d); + // We don't know if it's a string or a submessage; deliver first as + // string. + upb_string_recycle(&str); + upb_string_substr(str, d->input, d->offset, delim_len); + upb_value v; + upb_value_setstr(&v, str); + upb_flow_t ret = upb_dispatch_value(&d->dispatcher, &f, v); + CHECK(ret); + if(ret == BEGIN_SUBMSG) { + // Should deliver as a submessage instead. + CHECK(upb_dispatch_startsubmsg(&d->dispatcher, &f)); + *(++top) = d->offset + delim_len; + } else { + d->offset += delim_len; + } + } else { + upb_value v; + switch(wt) { + case UPB_WIRE_TYPE_VARINT: + upb_value_setraw(&v, upb_baredecoder_readv64(d)); + break; + case UPB_WIRE_TYPE_64BIT: + upb_value_setraw(&v, upb_baredecoder_readf64(d)); + break; + case UPB_WIRE_TYPE_32BIT: + upb_value_setraw(&v, upb_baredecoder_readf32(d)); + break; + default: + assert(false); + abort(); + } + CHECK(upb_dispatch_value(&d->dispatcher, &f, v)); + } + // Detect end-of-submessage. + while(d->offset >= *top) { + CHECK(upb_dispatch_endsubmsg(&d->dispatcher)); + d->offset = *(top--); + } + } + CHECK(upb_dispatch_endmsg(&d->dispatcher)); + upb_string_unref(str); + return; + +err: + upb_copyerr(status, d->dispatcher.top->handlers.status); + upb_string_unref(str); +} + +static upb_baredecoder *upb_baredecoder_new(upb_string *str) { + static upb_src_vtbl vtbl = { + &upb_baredecoder_sethandlers, + &upb_baredecoder_run, + }; + upb_baredecoder *d = malloc(sizeof(*d)); + upb_src_init(&d->src, &vtbl); + d->input = upb_string_getref(str); + d->offset = 0; + upb_dispatcher_init(&d->dispatcher); + return d; +} + +static void upb_baredecoder_free(upb_baredecoder *d) { + upb_string_unref(d->input); + free(d); +} + +static upb_src *upb_baredecoder_src(upb_baredecoder *d) { + return &d->src; +} + +void upb_symtab_add_descriptorproto(upb_symtab *symtab) { + // For the moment we silently decline to perform the operation if the symbols + // already exist in the symtab. Revisit this when we have a better story + // about whether syms in a table can be replaced. + upb_def *def = upb_symtab_lookup( + symtab, UPB_STRLIT("google.protobuf.FileDescriptorSet")); + if(def) { + upb_def_unref(def); + return; + } + + upb_baredecoder *decoder = upb_baredecoder_new(&descriptor_str); + upb_status status = UPB_STATUS_INIT; + upb_symtab_addfds(symtab, upb_baredecoder_src(decoder), &status); + upb_baredecoder_free(decoder); + + if(!upb_ok(&status)) { + // upb itself is corrupt. + upb_printerr(&status); + upb_clearerr(&status); + upb_symtab_unref(symtab); + abort(); + } + upb_status_uninit(&status); +} diff --git a/src/upb_def.h b/core/upb_def.h index 25c7ff6..e95aec3 100644 --- a/src/upb_def.h +++ b/core/upb_def.h @@ -1,17 +1,18 @@ /* * upb - a minimalist implementation of protocol buffers. * - * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. + * Copyright (c) 2009-2011 Joshua Haberman. See LICENSE for details. * - * Provides definitions of .proto constructs: + * Provides a mechanism for loading proto definitions from descriptors, and + * data structures to represent those definitions. These form the protobuf + * schema, and are used extensively throughout upb: * - upb_msgdef: describes a "message" construct. * - upb_fielddef: describes a message field. * - upb_enumdef: describes an enum. * (TODO: definitions of extensions and services). * * Defs are obtained from a upb_symtab object. A upb_symtab is empty when - * constructed, and definitions can be added by supplying serialized - * descriptors. + * constructed, and definitions can be added by supplying descriptors. * * Defs are immutable and reference-counted. Symbol tables reference any defs * that are the "current" definitions. If an extension is loaded that adds a @@ -27,6 +28,7 @@ #define UPB_DEF_H_ #include "upb_atomic.h" +#include "upb_stream.h" #include "upb_table.h" #ifdef __cplusplus @@ -37,7 +39,7 @@ extern "C" { // All the different kind of defs we support. These correspond 1:1 with // declarations in a .proto file. -enum upb_def_type { +typedef enum { UPB_DEF_MSG = 0, UPB_DEF_ENUM, UPB_DEF_SVC, @@ -47,15 +49,15 @@ enum upb_def_type { // For specifying that defs of any type are requsted from getdefs. UPB_DEF_ANY = -1 -}; +} upb_deftype; // This typedef is more space-efficient than declaring an enum var directly. -typedef int8_t upb_def_type_t; +typedef int8_t upb_deftype_t; typedef struct { - upb_strptr fqname; // Fully qualified. + upb_string *fqname; // Fully qualified. upb_atomic_refcount_t refcount; - upb_def_type_t type; + upb_deftype_t type; // The is_cyclic flag could go in upb_msgdef instead of here, because only // messages can be involved in cycles. However, putting them here is free @@ -76,7 +78,7 @@ INLINE void upb_def_ref(upb_def *def) { if(upb_atomic_ref(&def->refcount) && def->is_cyclic) _upb_def_cyclic_ref(def); } INLINE void upb_def_unref(upb_def *def) { - if(upb_atomic_unref(&def->refcount)) _upb_def_reftozero(def); + if(def && upb_atomic_unref(&def->refcount)) _upb_def_reftozero(def); } /* upb_fielddef ***************************************************************/ @@ -86,29 +88,35 @@ INLINE void upb_def_unref(upb_def *def) { // is either a field of a upb_msgdef or contained inside a upb_extensiondef. // It is also reference-counted. typedef struct _upb_fielddef { - upb_atomic_refcount_t refcount; - upb_field_type_t type; - upb_label_t label; - upb_field_number_t number; - upb_strptr name; upb_value default_value; - // These are set only when this fielddef is part of a msgdef. + upb_string *name; + + struct _upb_msgdef *msgdef; + + // For the case of an enum or a submessage, points to the def for that type. + upb_def *def; + + upb_atomic_refcount_t refcount; uint32_t byte_offset; // Where in a upb_msg to find the data. + + // These are set only when this fielddef is part of a msgdef. upb_field_count_t field_index; // Indicates set bit. - // For the case of an enum or a submessage, points to the def for that type. - // We own a ref on this def. + upb_field_number_t number; + upb_fieldtype_t type; + upb_label_t label; + // True if we own a ref on "def" (above). This is true unless this edge is + // part of a cycle. bool owned; - upb_def *def; } upb_fielddef; // A variety of tests about the type of a field. INLINE bool upb_issubmsg(upb_fielddef *f) { - return upb_issubmsgtype(f->type); + return f->type == UPB_TYPE(GROUP) || f->type == UPB_TYPE(MESSAGE); } INLINE bool upb_isstring(upb_fielddef *f) { - return upb_isstringtype(f->type); + return f->type == UPB_TYPE(STRING) || f->type == UPB_TYPE(BYTES); } INLINE bool upb_isarray(upb_fielddef *f) { return f->label == UPB_LABEL(REPEATED); @@ -118,6 +126,19 @@ INLINE bool upb_hasdef(upb_fielddef *f) { return upb_issubmsg(f) || f->type == UPB_TYPE(ENUM); } +INLINE upb_valuetype_t upb_field_valuetype(upb_fielddef *f) { + if (upb_isarray(f)) { + return UPB_VALUETYPE_ARRAY; + } else { + return f->type; + } +} + +INLINE upb_valuetype_t upb_elem_valuetype(upb_fielddef *f) { + assert(upb_isarray(f)); + return f->type; +} + INLINE bool upb_field_ismm(upb_fielddef *f) { return upb_isarray(f) || upb_isstring(f) || upb_issubmsg(f); } @@ -126,28 +147,14 @@ INLINE bool upb_elem_ismm(upb_fielddef *f) { return upb_isstring(f) || upb_issubmsg(f); } -// Internal-only interface for the upb compiler. -// Sorts the given fielddefs in-place, according to what we think is an optimal -// ordering of fields. This can change from upb release to upb release. -struct google_protobuf_FieldDescriptorProto; -void upb_fielddef_sortfds(struct google_protobuf_FieldDescriptorProto **fds, - size_t num); - /* upb_msgdef *****************************************************************/ -struct google_protobuf_EnumDescriptorProto; -struct google_protobuf_DescriptorProto; - // Structure that describes a single .proto message type. typedef struct _upb_msgdef { upb_def base; upb_atomic_refcount_t cycle_refcount; - upb_msg *default_msg; // Message with all default values set. - size_t size; - upb_field_count_t num_fields; + uint32_t size; uint32_t set_flags_bytes; - uint32_t num_required_fields; // Required fields have the lowest set bytemasks. - upb_fielddef *fields; // We have exclusive ownership of these. // Tables for looking up fields by number and name. upb_inttable itof; // int to field @@ -167,17 +174,37 @@ typedef struct { // Looks up a field by name or number. While these are written to be as fast // as possible, it will still be faster to cache the results of this lookup if // possible. These return NULL if no such field is found. -INLINE upb_fielddef *upb_msg_itof(upb_msgdef *m, uint32_t num) { +INLINE upb_fielddef *upb_msgdef_itof(upb_msgdef *m, uint32_t num) { upb_itof_ent *e = (upb_itof_ent*)upb_inttable_fastlookup(&m->itof, num, sizeof(*e)); return e ? e->f : NULL; } -INLINE upb_fielddef *upb_msg_ntof(upb_msgdef *m, upb_strptr name) { +INLINE upb_fielddef *upb_msgdef_ntof(upb_msgdef *m, upb_string *name) { upb_ntof_ent *e = (upb_ntof_ent*)upb_strtable_lookup(&m->ntof, name); return e ? e->f : NULL; } +INLINE upb_field_count_t upb_msgdef_numfields(upb_msgdef *m) { + return upb_strtable_count(&m->ntof); +} + +// Iteration over fields. The order is undefined. +// upb_msg_iter i; +// for(i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) { +// upb_fielddef *f = upb_msg_iter_field(i); +// // ... +// } +typedef upb_itof_ent *upb_msg_iter; + +upb_msg_iter upb_msg_begin(upb_msgdef *m); +upb_msg_iter upb_msg_next(upb_msgdef *m, upb_msg_iter iter); +INLINE bool upb_msg_done(upb_msg_iter iter) { return iter == NULL; } + +INLINE upb_fielddef *upb_msg_iter_field(upb_msg_iter iter) { + return iter->f; +} + /* upb_enumdef ****************************************************************/ typedef struct _upb_enumdef { @@ -186,26 +213,41 @@ typedef struct _upb_enumdef { upb_inttable iton; } upb_enumdef; +typedef struct { + upb_strtable_entry e; + uint32_t value; +} upb_ntoi_ent; + +typedef struct { + upb_inttable_entry e; + upb_string *string; +} upb_iton_ent; + typedef int32_t upb_enumval_t; // Lookups from name to integer and vice-versa. -bool upb_enumdef_ntoi(upb_enumdef *e, upb_strptr name, upb_enumval_t *num); -upb_strptr upb_enumdef_iton(upb_enumdef *e, upb_enumval_t num); +bool upb_enumdef_ntoi(upb_enumdef *e, upb_string *name, upb_enumval_t *num); +// Caller does not own a ref on the returned string. +upb_string *upb_enumdef_iton(upb_enumdef *e, upb_enumval_t num); // Iteration over name/value pairs. The order is undefined. // upb_enum_iter i; -// for(upb_enum_begin(&i, e); !upb_enum_done(&i); upb_enum_next(&i)) { +// for(i = upb_enum_begin(e); !upb_enum_done(i); i = upb_enum_next(e, i)) { // // ... // } -typedef struct { - upb_enumdef *e; - void *state; // Internal iteration state. - upb_strptr name; - upb_enumval_t val; -} upb_enum_iter; -void upb_enum_begin(upb_enum_iter *iter, upb_enumdef *e); -void upb_enum_next(upb_enum_iter *iter); -bool upb_enum_done(upb_enum_iter *iter); +typedef upb_iton_ent *upb_enum_iter; + +upb_enum_iter upb_enum_begin(upb_enumdef *e); +upb_enum_iter upb_enum_next(upb_enumdef *e, upb_enum_iter iter); +INLINE bool upb_enum_done(upb_enum_iter iter) { return iter == NULL; } + +INLINE upb_string *upb_enum_iter_name(upb_enum_iter iter) { + return iter->string; +} +INLINE int32_t upb_enum_iter_number(upb_enum_iter iter) { + return iter->e.key; +} + /* upb_symtab *****************************************************************/ @@ -215,11 +257,7 @@ bool upb_enum_done(upb_enum_iter *iter); typedef struct { upb_atomic_refcount_t refcount; upb_rwlock_t lock; // Protects all members except the refcount. - upb_msgdef *fds_msgdef; // In psymtab, ptr here for convenience. - - // Our symbol tables; we own refs to the defs therein. - upb_strtable symtab; // The main symbol table. - upb_strtable psymtab; // Private symbols, for internal use. + upb_strtable symtab; // The symbol table. } upb_symtab; // Initializes a upb_symtab. Contexts are not freed explicitly, but unref'd @@ -242,24 +280,32 @@ INLINE void upb_symtab_unref(upb_symtab *s) { // // If a def is found, the caller owns one ref on the returned def. Otherwise // returns NULL. -upb_def *upb_symtab_resolve(upb_symtab *s, upb_strptr base, upb_strptr symbol); +upb_def *upb_symtab_resolve(upb_symtab *s, upb_string *base, upb_string *sym); // Find an entry in the symbol table with this exact name. If a def is found, // the caller owns one ref on the returned def. Otherwise returns NULL. -upb_def *upb_symtab_lookup(upb_symtab *s, upb_strptr sym); +upb_def *upb_symtab_lookup(upb_symtab *s, upb_string *sym); // Gets an array of pointers to all currently active defs in this symtab. The // caller owns the returned array (which is of length *count) as well as a ref // to each symbol inside. If type is UPB_DEF_ANY then defs of all types are // returned, otherwise only defs of the required type are returned. -upb_def **upb_symtab_getdefs(upb_symtab *s, int *count, upb_def_type_t type); - -// Adds the definitions in the given serialized descriptor to this symtab. All -// types that are referenced from desc must have previously been defined (or be -// defined in desc). desc may not attempt to define any names that are already -// defined in this symtab. Caller retains ownership of desc. status indicates -// whether the operation was successful or not, and the error message (if any). -void upb_symtab_add_desc(upb_symtab *s, upb_strptr desc, upb_status *status); +upb_def **upb_symtab_getdefs(upb_symtab *s, int *count, upb_deftype_t type); + +// "fds" is a upb_src that will yield data from the +// google.protobuf.FileDescriptorSet message type. upb_symtab_addfds() adds +// all the definitions from the given FileDescriptorSet and adds them to the +// symtab. status indicates whether the operation was successful or not, and +// the error message (if any). +// +// TODO: should this allow redefinition? Either is possible, but which is +// more useful? Maybe it should be an option. +void upb_symtab_addfds(upb_symtab *s, upb_src *desc, upb_status *status); + +// Adds defs for google.protobuf.FileDescriptorSet and friends to this symtab. +// This is necessary for bootstrapping, since these are the upb_defs that +// specify other defs and allow them to be loaded. +void upb_symtab_add_descriptorproto(upb_symtab *s); /* upb_def casts **************************************************************/ diff --git a/core/upb_msg.c b/core/upb_msg.c new file mode 100644 index 0000000..e9f863d --- /dev/null +++ b/core/upb_msg.c @@ -0,0 +1,101 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2010 Joshua Haberman. See LICENSE for details. + * + * Data structure for storing a message of protobuf data. + */ + +#include "upb_msg.h" +#include "upb_decoder.h" +#include "upb_strstream.h" + +static void upb_elem_free(upb_value v, upb_fielddef *f) { + switch(f->type) { + case UPB_TYPE(MESSAGE): + case UPB_TYPE(GROUP): + _upb_msg_free(upb_value_getmsg(v), upb_downcast_msgdef(f->def)); + break; + case UPB_TYPE(STRING): + case UPB_TYPE(BYTES): + _upb_string_free(upb_value_getstr(v)); + break; + default: + abort(); + } +} + +static void upb_elem_unref(upb_value v, upb_fielddef *f) { + assert(upb_elem_ismm(f)); + upb_atomic_refcount_t *refcount = upb_value_getrefcount(v); + if (refcount && upb_atomic_unref(refcount)) + upb_elem_free(v, f); +} + +static void upb_field_free(upb_value v, upb_fielddef *f) { + if (upb_isarray(f)) { + _upb_array_free(upb_value_getarr(v), f); + } else { + upb_elem_free(v, f); + } +} + +static void upb_field_unref(upb_value v, upb_fielddef *f) { + assert(upb_field_ismm(f)); + upb_atomic_refcount_t *refcount = upb_value_getrefcount(v); + if (refcount && upb_atomic_unref(refcount)) + upb_field_free(v, f); +} + +upb_msg *upb_msg_new(upb_msgdef *md) { + upb_msg *msg = malloc(md->size); + // Clear all set bits and cached pointers. + memset(msg, 0, md->size); + upb_atomic_refcount_init(&msg->refcount, 1); + return msg; +} + +void _upb_msg_free(upb_msg *msg, upb_msgdef *md) { + // Need to release refs on all sub-objects. + upb_msg_iter i; + for(i = upb_msg_begin(md); !upb_msg_done(i); i = upb_msg_next(md, i)) { + upb_fielddef *f = upb_msg_iter_field(i); + upb_valueptr p = _upb_msg_getptr(msg, f); + upb_valuetype_t type = upb_field_valuetype(f); + if (upb_field_ismm(f)) upb_field_unref(upb_value_read(p, type), f); + } + free(msg); +} + +INLINE void upb_msg_sethas(upb_msg *msg, upb_fielddef *f) { + msg->data[f->field_index/8] |= (1 << (f->field_index % 8)); +} + + +upb_array *upb_array_new(void) { + upb_array *arr = malloc(sizeof(*arr)); + upb_atomic_refcount_init(&arr->refcount, 1); + arr->size = 0; + arr->len = 0; + arr->elements._void = NULL; + return arr; +} + +void _upb_array_free(upb_array *arr, upb_fielddef *f) { + if (upb_elem_ismm(f)) { + // Need to release refs on sub-objects. + upb_valuetype_t type = upb_elem_valuetype(f); + for (upb_arraylen_t i = 0; i < arr->size; i++) { + upb_valueptr p = _upb_array_getptr(arr, f, i); + upb_elem_unref(upb_value_read(p, type), f); + } + } + if (arr->elements._void) free(arr->elements._void); + free(arr); +} + +void upb_msg_register_handlers(upb_msg *msg, upb_msgdef *md, + upb_handlers *handlers, bool merge) { + static upb_handlerset handlerset = { + } +} diff --git a/core/upb_msg.h b/core/upb_msg.h new file mode 100644 index 0000000..0569039 --- /dev/null +++ b/core/upb_msg.h @@ -0,0 +1,96 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2010-2011 Joshua Haberman. See LICENSE for details. + * + * Data structure for storing a message of protobuf data. Unlike Google's + * protobuf, upb_msg and upb_array are reference counted instead of having + * exclusive ownership of their fields. This is a better match for dynamic + * languages where statements like a.b = other_b are normal. + * + * upb's parsers and serializers could also be used to populate and serialize + * other kinds of message objects (even one generated by Google's protobuf). + */ + +#ifndef UPB_MSG_H +#define UPB_MSG_H + +#include "upb.h" +#include "upb_def.h" +#include <stdlib.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* upb_array ******************************************************************/ + +typedef uint32_t upb_arraylen_t; +struct _upb_array { + upb_atomic_refcount_t refcount; + upb_arraylen_t len; + upb_arraylen_t size; + upb_valueptr elements; +}; + +void _upb_array_free(upb_array *a, upb_fielddef *f); +INLINE upb_valueptr _upb_array_getptr(upb_array *a, upb_fielddef *f, + uint32_t elem) { + upb_valueptr p; + p._void = &a->elements.uint8[elem * upb_types[f->type].size]; + return p; +} + +upb_array *upb_array_new(void); + +INLINE void upb_array_unref(upb_array *a, upb_fielddef *f) { + if (upb_atomic_unref(&a->refcount)) _upb_array_free(a, f); +} + +INLINE uint32_t upb_array_len(upb_array *a) { + return a->len; +} + +/* upb_msg ********************************************************************/ + +struct _upb_msg { + upb_atomic_refcount_t refcount; + uint8_t data[4]; // We allocate the appropriate amount per message. +}; + +void _upb_msg_free(upb_msg *msg, upb_msgdef *md); + +INLINE upb_valueptr _upb_msg_getptr(upb_msg *msg, upb_fielddef *f) { + upb_valueptr p; + p._void = &msg->data[f->byte_offset]; + return p; +} + +// Creates a new msg of the given type. +upb_msg *upb_msg_new(upb_msgdef *md); + +// Unrefs the given message. +INLINE void upb_msg_unref(upb_msg *msg, upb_msgdef *md) { + if (msg && upb_atomic_unref(&msg->refcount)) _upb_msg_free(msg, md); +} + +// Tests whether the given field is explicitly set, or whether it will return a +// default. +INLINE bool upb_msg_has(upb_msg *msg, upb_fielddef *f) { + return (msg->data[f->field_index/8] & (1 << (f->field_index % 8))) != 0; +} + +// Unsets all field values back to their defaults. +INLINE void upb_msg_clear(upb_msg *msg, upb_msgdef *md) { + memset(msg->data, 0, md->set_flags_bytes); +} + +// Registers a set of handlers that will populate this msgdef. +void upb_msg_register_handlers(upb_msg *msg, upb_msgdef *md, + upb_handlers *handlers); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/core/upb_stream.h b/core/upb_stream.h new file mode 100644 index 0000000..aa23549 --- /dev/null +++ b/core/upb_stream.h @@ -0,0 +1,275 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * This file defines four general-purpose streaming data interfaces. + * + * - upb_handlers: represents a set of callbacks, very much like in XML's SAX + * API, that a client can register to do a streaming tree traversal over a + * stream of structured protobuf data, without knowing where that data is + * coming from. There is only one upb_handlers type (it is not a virtual + * base class), but the object lets you register any set of handlers. + * + * The upb_handlers interface supports delegation: when entering a submessage, + * you can delegate to another set of upb_handlers instead of handling the + * submessage yourself. This allows upb_handlers objects to *compose* -- you + * can implement a set of upb_handlers without knowing or caring whether this + * is the top-level message or not. + * + * The other interfaces are the C equivalent of "virtual base classes" that + * anyone can implement: + * + * - upb_src: an interface that represents a source of streaming protobuf data. + * It lets you register a set of upb_handlers, and then call upb_src_run(), + * which pulls the protobuf data from somewhere and then calls the handlers. + * + * - upb_bytesrc: a pull interface for streams of bytes, basically an + * abstraction of read()/fread(), but it avoids copies where possible. + * + * - upb_bytesink: push interface for streams of bytes, basically an + * abstraction of write()/fwrite(), but it avoids copies where possible. + * + * All of the encoders and decoders are based on these generic interfaces, + * which lets you write streaming algorithms that do not depend on a specific + * serialization format; for example, you can write a pretty printer that works + * with input that came from protobuf binary format, protobuf text format, or + * even an in-memory upb_msg -- the pretty printer will not know the + * difference. + * + * Copyright (c) 2010-2011 Joshua Haberman. See LICENSE for details. + * + */ + +#ifndef UPB_STREAM_H +#define UPB_STREAM_H + +#include "upb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Forward-declare. We can't include upb_def.h; it would be circular. +struct _upb_fielddef; + +/* upb_handlers ***************************************************************/ + +// upb_handlers define the interface by which a upb_src passes data to a +// upb_sink. + +// Constants that a handler returns to indicate to its caller whether it should +// continue or not. +typedef enum { + // Caller should continue sending values to the sink. + UPB_CONTINUE, + + // Stop processing for now; check status for details. If no status was set, + // a generic error will be returned. If the error is resumable, it is not + // (yet) defined where processing will resume -- waiting for real-world + // examples of resumable decoders and resume-requiring clients. upb_src + // implementations that are not capable of resuming will override the return + // status to be non-resumable if a resumable status was set by the handlers. + UPB_BREAK, + + // Skips to the end of the current submessage (or if we are at the top + // level, skips to the end of the entire message). + UPB_SKIPSUBMSG, + + // When returned from a startsubmsg handler, indicates that the submessage + // should be handled by a different set of handlers, which have been + // registered on the provided upb_handlers object. This allows upb_handlers + // objects to compose; a set of upb_handlers need not know whether it is the + // top-level message or a sub-message. May not be returned from any other + // callback. + UPB_DELEGATE, +} upb_flow_t; + +// upb_handlers +struct _upb_handlers; +typedef struct _upb_handlers upb_handlers; + +typedef upb_flow_t (*upb_startmsg_handler_t)(void *closure); +typedef upb_flow_t (*upb_endmsg_handler_t)(void *closure); +typedef upb_flow_t (*upb_value_handler_t)(void *closure, + struct _upb_fielddef *f, + upb_value val); +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_unknownval_handler_t)(void *closure, + upb_field_number_t fieldnum, + upb_value val); + +// An empty set of handlers, for convenient copy/paste: +// +// static upb_flow_t startmsg(void *closure) { +// // Called when the top-level message begins. +// return UPB_CONTINUE; +// } +// +// static upb_flow_t endmsg(void *closure) { +// // Called when the top-level message ends. +// return UPB_CONTINUE; +// } +// +// static upb_flow_t value(void *closure, upb_fielddef *f, upb_value val) { +// // Called for every value in the stream. +// return UPB_CONTINUE; +// } +// +// static upb_flow_t startsubmsg(void *closure, upb_fielddef *f, +// upb_handlers *delegate_to) { +// // Called when a submessage begins; can delegate by returning UPB_DELEGATE. +// return UPB_CONTINUE; +// } +// +// static upb_flow_t endsubmsg(void *closure) { +// // Called when a submessage ends. +// return UPB_CONTINUE; +// } +// +// static upb_flow_t unknownval(void *closure, upb_field_number_t fieldnum, +// upb_value val) { +// // Called with an unknown value is encountered. +// return UPB_CONTINUE; +// } +// +// // Any handlers you don't need can be set to NULL. +// static upb_handlerset handlers = { +// startmsg, +// endmsg, +// value, +// startsubmsg, +// endsubmsg, +// unknownval, +// }; +typedef struct { + upb_startmsg_handler_t startmsg; + upb_endmsg_handler_t endmsg; + upb_value_handler_t value; + upb_startsubmsg_handler_t startsubmsg; + upb_endsubmsg_handler_t endsubmsg; + upb_unknownval_handler_t unknownval; +} upb_handlerset; + +// Functions to register handlers on a upb_handlers object. +INLINE void upb_handlers_init(upb_handlers *h); +INLINE void upb_handlers_uninit(upb_handlers *h); +INLINE void upb_handlers_reset(upb_handlers *h); +INLINE bool upb_handlers_isempty(upb_handlers *h); +INLINE void upb_register_handlerset(upb_handlers *h, upb_handlerset *set); + +// TODO: for clients that want to increase efficiency by preventing bytesrcs +// from automatically being converted to strings in the value callback. +// INLINE void upb_handlers_use_bytesrcs(bool use_bytesrcs); + +// The closure will be passed to every handler. The status will be read by the +// upb_src immediately after a handler has returned UPB_BREAK and used as the +// overall upb_src status; it will not be referenced at any other time. +INLINE void upb_set_handler_closure(upb_handlers *h, void *closure, + upb_status *status); + + +/* upb_src ********************************************************************/ + +struct _upb_src; +typedef struct _upb_src upb_src; + +// upb_src_sethandlers() must be called once and only once before upb_src_run() +// is called. This sets up the callbacks that will handle the parse. A +// upb_src that is fully initialized except for the call to +// upb_src_sethandlers() is called "prepared" -- this is useful for library +// functions that want to consume the output of a generic upb_src. +// Calling sethandlers() multiple times is an error and will trigger an abort(). +INLINE void upb_src_sethandlers(upb_src *src, upb_handlers *handlers); + +// Runs the src, calling the callbacks that were registered with +// upb_src_sethandlers(), and returning the status of the operation in +// "status." The status might indicate UPB_TRYAGAIN (indicating EAGAIN on a +// non-blocking socket) or a resumable error; in both cases upb_src_run can be +// called again later. TRYAGAIN could come from either the src (input buffers +// are empty) or the handlers (output buffers are full). +INLINE void upb_src_run(upb_src *src, upb_status *status); + + +// A convenience object that a upb_src can use to invoke handlers. It +// transparently handles delegation so that the upb_src needs only follow the +// protocol as if delegation did not exist. +struct _upb_dispatcher; +typedef struct _upb_dispatcher upb_dispatcher; +INLINE void upb_dispatcher_init(upb_dispatcher *d); +INLINE void upb_dispatcher_reset(upb_dispatcher *d, upb_handlers *h); +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_value(upb_dispatcher *d, struct _upb_fielddef *f, + upb_value val); +INLINE upb_flow_t upb_dispatch_unknownval(upb_dispatcher *d, + upb_field_number_t fieldnum, + upb_value val); + +/* upb_bytesrc ****************************************************************/ + +// Reads up to "count" bytes into "buf", returning the total number of bytes +// read. If 0, indicates error and puts details in "status". +INLINE upb_strlen_t upb_bytesrc_read(upb_bytesrc *src, void *buf, + upb_strlen_t count, upb_status *status); + +// Like upb_bytesrc_read(), but modifies "str" in-place. Caller must ensure +// that "str" is created or just recycled. Returns "false" if no data was +// returned, either due to error or EOF (check status for details). +// +// In comparison to upb_bytesrc_read(), this call can possibly alias existing +// string data (which avoids a copy). On the other hand, if the data was *not* +// already in an existing string, this copies it into a upb_string, and if the +// data needs to be put in a specific range of memory (because eg. you need to +// put it into a different kind of string object) then upb_bytesrc_get() could +// save you a copy. +INLINE bool upb_bytesrc_getstr(upb_bytesrc *src, upb_string *str, + upb_status *status); + +// A convenience function for getting all the remaining data in a upb_bytesrc +// as a upb_string. Returns false and sets "status" if the operation fails. +INLINE bool upb_bytesrc_getfullstr(upb_bytesrc *src, upb_string *str, + upb_status *status); +INLINE bool upb_value_getfullstr(upb_value val, upb_string *str, + upb_status *status) { + return upb_bytesrc_getfullstr(upb_value_getbytesrc(val), str, status); +} + + +/* upb_bytesink ***************************************************************/ + +struct _upb_bytesink; +typedef struct _upb_bytesink upb_bytesink; + +// TODO: Figure out how buffering should be handled. Should the caller buffer +// data and only call these functions when a buffer is full? Seems most +// efficient, but then buffering has to be configured in the caller, which +// could be anything, which makes it hard to have a standard interface for +// controlling buffering. +// +// The downside of having the bytesink buffer is efficiency: the caller is +// making more (virtual) function calls, and the caller can't arrange to have +// a big contiguous buffer. The bytesink can do this, but will have to copy +// to make the data contiguous. + +// Returns the number of bytes written. +INLINE upb_strlen_t upb_bytesink_printf(upb_bytesink *sink, upb_status *status, + const char *fmt, ...); + +// Puts the given string, returning true if the operation was successful, otherwise +// check "status" for details. Ownership of the string is *not* passed; if +// the callee wants a reference he must call upb_string_getref() on it. +INLINE upb_strlen_t upb_bytesink_putstr(upb_bytesink *sink, upb_string *str, + upb_status *status); + +#include "upb_stream_vtbl.h" + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/core/upb_stream_vtbl.h b/core/upb_stream_vtbl.h new file mode 100644 index 0000000..a6990bc --- /dev/null +++ b/core/upb_stream_vtbl.h @@ -0,0 +1,307 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * vtable declarations for types that are implementing any of the src or sink + * interfaces. Only components that are implementing these interfaces need + * to worry about this file. + * + * Copyright (c) 2010 Joshua Haberman. See LICENSE for details. + */ + +#ifndef UPB_SRCSINK_VTBL_H_ +#define UPB_SRCSINK_VTBL_H_ + +#include <assert.h> +#include "upb_stream.h" +#include "upb_string.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// Typedefs for function pointers to all of the virtual functions. + +// upb_src +typedef void (*upb_src_sethandlers_fptr)(upb_src *src, upb_handlers *handlers); +typedef void (*upb_src_run_fptr)(upb_src *src, upb_status *status); + +// upb_bytesrc. +typedef upb_strlen_t (*upb_bytesrc_read_fptr)( + upb_bytesrc *src, void *buf, upb_strlen_t count, upb_status *status); +typedef bool (*upb_bytesrc_getstr_fptr)( + upb_bytesrc *src, upb_string *str, upb_status *status); + +// upb_bytesink. +typedef upb_strlen_t (*upb_bytesink_write_fptr)( + upb_bytesink *bytesink, void *buf, upb_strlen_t count); +typedef upb_strlen_t (*upb_bytesink_putstr_fptr)( + upb_bytesink *bytesink, upb_string *str, upb_status *status); +typedef upb_strlen_t (*upb_bytesink_vprintf_fptr)( + upb_bytesink *bytesink, upb_status *status, const char *fmt, va_list args); + +// Vtables for the above interfaces. +typedef struct { + upb_bytesrc_read_fptr read; + upb_bytesrc_getstr_fptr getstr; +} upb_bytesrc_vtbl; + +typedef struct { + upb_bytesink_write_fptr write; + upb_bytesink_putstr_fptr putstr; + upb_bytesink_vprintf_fptr vprintf; +} upb_bytesink_vtbl; + +typedef struct { + upb_src_sethandlers_fptr sethandlers; + upb_src_run_fptr run; +} upb_src_vtbl; + + +// "Base Class" definitions; components that implement these interfaces should +// contain one of these structures. + +struct _upb_bytesrc { + upb_bytesrc_vtbl *vtbl; + upb_status status; + bool eof; +}; + +struct _upb_bytesink { + upb_bytesink_vtbl *vtbl; + upb_status status; + bool eof; +}; + +struct _upb_src { + upb_src_vtbl *vtbl; +}; + +INLINE void upb_bytesrc_init(upb_bytesrc *s, upb_bytesrc_vtbl *vtbl) { + s->vtbl = vtbl; + s->eof = false; + upb_status_init(&s->status); +} + +INLINE void upb_bytesink_init(upb_bytesink *s, upb_bytesink_vtbl *vtbl) { + s->vtbl = vtbl; + s->eof = false; + upb_status_init(&s->status); +} + +INLINE void upb_src_init(upb_src *s, upb_src_vtbl *vtbl) { + s->vtbl = vtbl; +} + +// Implementation of virtual function dispatch. + +// upb_src +INLINE void upb_src_sethandlers(upb_src *src, upb_handlers *handlers) { + src->vtbl->sethandlers(src, handlers); +} + +INLINE void upb_src_run(upb_src *src, upb_status *status) { + src->vtbl->run(src, status); +} + +// upb_bytesrc +INLINE upb_strlen_t upb_bytesrc_read(upb_bytesrc *src, void *buf, + upb_strlen_t count, upb_status *status) { + return src->vtbl->read(src, buf, count, status); +} + +INLINE bool upb_bytesrc_getstr(upb_bytesrc *src, upb_string *str, + upb_status *status) { + return src->vtbl->getstr(src, str, status); +} + +INLINE bool upb_bytesrc_getfullstr(upb_bytesrc *src, upb_string *str, + upb_status *status) { + // We start with a getstr, because that could possibly alias data instead of + // copying. + if (!upb_bytesrc_getstr(src, str, status)) return false; + // Trade-off between number of read calls and amount of overallocation. + const size_t bufsize = 4096; + do { + upb_strlen_t len = upb_string_len(str); + char *buf = upb_string_getrwbuf(str, len + bufsize); + upb_strlen_t read = upb_bytesrc_read(src, buf + len, bufsize, status); + if (read < 0) return false; + // Resize to proper size. + upb_string_getrwbuf(str, len + read); + } while (!status->code != UPB_EOF); + return true; +} + +INLINE upb_status *upb_bytesrc_status(upb_bytesrc *src) { return &src->status; } +INLINE bool upb_bytesrc_eof(upb_bytesrc *src) { return src->eof; } + + +// upb_bytesink +INLINE upb_strlen_t upb_bytesink_write(upb_bytesink *sink, void *buf, + upb_strlen_t count) { + return sink->vtbl->write(sink, buf, count); +} + +INLINE upb_strlen_t upb_bytesink_putstr(upb_bytesink *sink, upb_string *str, upb_status *status) { + return sink->vtbl->putstr(sink, str, status); +} + +INLINE upb_status *upb_bytesink_status(upb_bytesink *sink) { + return &sink->status; +} + +INLINE upb_strlen_t upb_bytesink_printf(upb_bytesink *sink, upb_status *status, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + upb_strlen_t ret = sink->vtbl->vprintf(sink, status, fmt, args); + va_end(args); + return ret; +} + +// upb_handlers +struct _upb_handlers { + upb_handlerset *set; + void *closure; + upb_status *status; // We don't own this. +}; + +INLINE void upb_handlers_init(upb_handlers *h) { + (void)h; +} +INLINE void upb_handlers_uninit(upb_handlers *h) { + (void)h; +} + +INLINE void upb_handlers_reset(upb_handlers *h) { + h->set = NULL; + h->closure = NULL; +} + +INLINE bool upb_handlers_isempty(upb_handlers *h) { + return !h->set && !h->closure; +} + +INLINE upb_flow_t upb_nop(void *closure) { + (void)closure; + return UPB_CONTINUE; +} + +INLINE upb_flow_t upb_value_nop(void *closure, struct _upb_fielddef *f, upb_value val) { + (void)closure; + (void)f; + (void)val; + return UPB_CONTINUE; +} + +INLINE upb_flow_t upb_startsubmsg_nop(void *closure, struct _upb_fielddef *f, + upb_handlers *delegate_to) { + (void)closure; + (void)f; + (void)delegate_to; + return UPB_CONTINUE; +} + +INLINE upb_flow_t upb_unknownval_nop(void *closure, upb_field_number_t fieldnum, + upb_value val) { + (void)closure; + (void)fieldnum; + (void)val; + return UPB_CONTINUE; +} + +INLINE void upb_register_handlerset(upb_handlers *h, upb_handlerset *set) { + if (!set->startmsg) set->startmsg = &upb_nop; + 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->unknownval) set->unknownval = &upb_unknownval_nop; + h->set = set; +} + +INLINE void upb_set_handler_closure(upb_handlers *h, void *closure, + upb_status *status) { + h->closure = closure; + h->status = status; +} + +// upb_dispatcher +typedef struct { + upb_handlers handlers; + int depth; +} upb_dispatcher_frame; + +struct _upb_dispatcher { + upb_dispatcher_frame stack[UPB_MAX_NESTING], *top, *limit; +}; + +INLINE void upb_dispatcher_init(upb_dispatcher *d) { + d->limit = d->stack + sizeof(d->stack); +} + +INLINE void upb_dispatcher_reset(upb_dispatcher *d, upb_handlers *h) { + d->top = d->stack; + d->top->depth = 1; // Never want to trigger end-of-delegation. + d->top->handlers = *h; +} + +INLINE upb_flow_t upb_dispatch_startmsg(upb_dispatcher *d) { + assert(d->stack == d->top); + return d->top->handlers.set->startmsg(d->top->handlers.closure); +} + +INLINE upb_flow_t upb_dispatch_endmsg(upb_dispatcher *d) { + assert(d->stack == d->top); + return d->top->handlers.set->endmsg(d->top->handlers.closure); +} + +// TODO: several edge cases to fix: +// - delegated start returns UPB_BREAK, should replay the start on resume. +// - endsubmsg returns UPB_BREAK, should NOT replay the delegated endmsg. +INLINE upb_flow_t upb_dispatch_startsubmsg(upb_dispatcher *d, + struct _upb_fielddef *f) { + upb_handlers handlers; + upb_handlers_init(&handlers); + upb_handlers_reset(&handlers); + upb_flow_t ret = d->top->handlers.set->startsubmsg(d->top->handlers.closure, f, &handlers); + assert((ret == UPB_DELEGATE) == !upb_handlers_isempty(&handlers)); + if (ret == UPB_DELEGATE) { + ++d->top; + d->top->handlers = handlers; + d->top->depth = 0; + ret = d->top->handlers.set->startmsg(d->top->handlers.closure); + } + if (ret == UPB_CONTINUE) ++d->top->depth; + upb_handlers_uninit(&handlers); + return ret; +} + +INLINE upb_flow_t upb_dispatch_endsubmsg(upb_dispatcher *d) { + upb_flow_t ret; + if (--d->top->depth == 0) { + ret = d->top->handlers.set->endmsg(d->top->handlers.closure); + if (ret != UPB_CONTINUE) return ret; + --d->top; + assert(d->top >= d->stack); + } + return d->top->handlers.set->endsubmsg(d->top->handlers.closure); +} + +INLINE upb_flow_t upb_dispatch_value(upb_dispatcher *d, + struct _upb_fielddef *f, + upb_value val) { + return d->top->handlers.set->value(d->top->handlers.closure, f, val); +} + +INLINE upb_flow_t upb_dispatch_unknownval(upb_dispatcher *d, + upb_field_number_t fieldnum, + upb_value val) { + return d->top->handlers.set->unknownval(d->top->handlers.closure, + fieldnum, val); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/core/upb_string.c b/core/upb_string.c new file mode 100644 index 0000000..c599728 --- /dev/null +++ b/core/upb_string.c @@ -0,0 +1,161 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2010 Joshua Haberman. See LICENSE for details. + */ + +#include "upb_string.h" + +#include <stdlib.h> +#ifdef __GLIBC__ +#include <malloc.h> +#elif defined(__APPLE__) +#include <malloc/malloc.h> +#endif + +static uint32_t upb_round_up_pow2(uint32_t v) { + // http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 + v--; + v |= v >> 1; + v |= v >> 2; + v |= v >> 4; + v |= v >> 8; + v |= v >> 16; + v++; + return v; +} + +upb_string *upb_string_new() { + upb_string *str = malloc(sizeof(*str)); + str->ptr = NULL; + str->cached_mem = NULL; + str->len = 0; +#ifndef UPB_HAVE_MSIZE + str->size = 0; +#endif + str->src = NULL; + upb_atomic_refcount_init(&str->refcount, 1); + return str; +} + +uint32_t upb_string_size(upb_string *str) { +#ifdef __GLIBC__ + return malloc_usable_size(str->cached_mem); +#elif defined(__APPLE__) + return malloc_size(str->cached_mem); +#else + return str->size; +#endif +} + +static void upb_string_release(upb_string *str) { + if(str->src) { + upb_string_unref(str->src); + str->src = NULL; + } +} + +void _upb_string_free(upb_string *str) { + if(str->cached_mem) free(str->cached_mem); + upb_string_release(str); + free(str); +} + +void upb_string_recycle(upb_string **_str) { + upb_string *str = *_str; + if(str && upb_atomic_read(&str->refcount) == 1) { + str->ptr = NULL; + upb_string_release(str); + } else { + upb_string_unref(str); + *_str = upb_string_new(); + } +} + +char *upb_string_getrwbuf(upb_string *str, upb_strlen_t len) { + // assert(str->ptr == NULL); + upb_strlen_t size = upb_string_size(str); + if (size < len) { + size = upb_round_up_pow2(len); + str->cached_mem = realloc(str->cached_mem, size); +#ifndef UPB_HAVE_MSIZE + str->size = size; +#endif + } + str->len = len; + str->ptr = str->cached_mem; + return str->cached_mem; +} + +void upb_string_substr(upb_string *str, upb_string *target_str, + upb_strlen_t start, upb_strlen_t len) { + if(str->ptr) *(char*)0 = 0; + assert(str->ptr == NULL); + str->src = upb_string_getref(target_str); + str->ptr = upb_string_getrobuf(target_str) + start; + str->len = len; +} + +void upb_string_vprintf(upb_string *str, const char *format, va_list args) { + // Try once without reallocating. We have to va_copy because we might have + // to call vsnprintf again. + uint32_t size = UPB_MAX(upb_string_size(str), 16); + char *buf = upb_string_getrwbuf(str, size); + va_list args_copy; + va_copy(args_copy, args); + uint32_t true_size = vsnprintf(buf, size, format, args_copy); + va_end(args_copy); + + if (true_size >= size) { + // Need to reallocate. We reallocate even if the sizes were equal, + // because snprintf excludes the terminating NULL from its count. + // We don't care about the terminating NULL, but snprintf might + // bail out of printing even other characters if it doesn't have + // enough space to write the NULL also. + upb_string_recycle(&str); + buf = upb_string_getrwbuf(str, true_size + 1); + vsnprintf(buf, true_size + 1, format, args); + } + str->len = true_size; +} + +upb_string *upb_string_asprintf(const char *format, ...) { + upb_string *str = upb_string_new(); + va_list args; + va_start(args, format); + upb_string_vprintf(str, format, args); + va_end(args); + return str; +} + +upb_string *upb_strdup(upb_string *s) { + upb_string *str = upb_string_new(); + upb_strcpy(str, s); + return str; +} + +void upb_strcat(upb_string *s, upb_string *append) { + uint32_t old_size = upb_string_len(s); + uint32_t append_size = upb_string_len(append); + uint32_t new_size = old_size + append_size; + char *buf = upb_string_getrwbuf(s, new_size); + memcpy(buf + old_size, upb_string_getrobuf(append), append_size); +} + +upb_string *upb_strreadfile(const char *filename) { + FILE *f = fopen(filename, "rb"); + if(!f) return NULL; + if(fseek(f, 0, SEEK_END) != 0) goto error; + long size = ftell(f); + if(size < 0) goto error; + if(fseek(f, 0, SEEK_SET) != 0) goto error; + upb_string *s = upb_string_new(); + char *buf = upb_string_getrwbuf(s, size); + if(fread(buf, size, 1, f) != 1) goto error; + fclose(f); + return s; + +error: + fclose(f); + return NULL; +} diff --git a/core/upb_string.h b/core/upb_string.h new file mode 100644 index 0000000..7d0ae87 --- /dev/null +++ b/core/upb_string.h @@ -0,0 +1,342 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2010 Joshua Haberman. See LICENSE for details. + * + * This file defines a simple string type which is length-delimited instead + * of NULL-terminated, and which has useful sharing semantics. + * + * The overriding goal of upb_string is to avoid memcpy(), malloc(), and free() + * wheverever possible, while keeping both CPU and memory overhead low. + * Throughout upb there are situations where one wants to reference all or part + * of another string without copying. upb_string provides APIs for doing this, + * and allows the referenced string to be kept alive for as long as anyone is + * referencing it. + * + * Characteristics of upb_string: + * - strings are reference-counted. + * - strings are immutable (can be mutated only when first created or recycled). + * - if a string has no other referents, it can be "recycled" into a new string + * without having to reallocate the upb_string. + * - strings can be substrings of other strings (owning a ref on the source + * string). + * + * Reference-counted strings have recently fallen out of favor because of the + * performance impacts of doing thread-safe reference counting with atomic + * operations. We side-step this issue by not performing atomic operations + * unless the string has been marked thread-safe. Time will tell whether this + * scheme is easy and convenient enough to be practical. + * + * Strings are expected to be 8-bit-clean, but "char*" is such an entrenched + * idiom that we go with it instead of making our pointers uint8_t*. + * + * WARNING: THE GETREF, UNREF, AND RECYCLE OPERATIONS ARE NOT THREAD_SAFE + * UNLESS THE STRING HAS BEEN MARKED SYNCHRONIZED! What this means is that if + * you are logically passing a reference to a upb_string to another thread + * (which implies that the other thread must eventually call unref of recycle), + * you have two options: + * + * - create a copy of the string that will be used in the other thread only. + * - call upb_string_get_synchronized_ref(), which will make getref, unref, and + * recycle thread-safe for this upb_string. + */ + +#ifndef UPB_STRING_H +#define UPB_STRING_H + +#include <assert.h> +#include <string.h> +#include <stdarg.h> +#include "upb_atomic.h" +#include "upb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// All members of this struct are private, and may only be read/written through +// the associated functions. +struct _upb_string { + // The pointer to our currently active data. This may be memory we own + // or a pointer into memory we don't own. + const char *ptr; + + // If non-NULL, this is a block of memory we own. We keep this cached even + // if "ptr" is currently aliasing memory we don't own. + char *cached_mem; + + // The effective length of the string (the bytes at ptr). + int32_t len; +#ifndef UPB_HAVE_MSIZE + // How many bytes are allocated in cached_mem. + // + // Many platforms have a function that can tell you the size of a block + // that was previously malloc'd. In this case we can avoid storing the + // size explicitly. + uint32_t size; +#endif + + // The string's refcount. + upb_atomic_refcount_t refcount; + + // Used if this is a slice of another string, NULL otherwise. We own a ref + // on src. + struct _upb_string *src; +}; + +// Internal-only initializer for upb_string instances. +#ifdef UPB_HAVE_MSIZE +#define _UPB_STRING_INIT(str, len, refcount) {(char*)str, NULL, len, {refcount}, NULL} +#else +#define _UPB_STRING_INIT(str, len, refcount) {(char*)str, NULL, len, 0, {refcount}, NULL} +#endif + +// Special pseudo-refcounts for static/stack-allocated strings, respectively. +#define _UPB_STRING_REFCOUNT_STATIC -1 +#define _UPB_STRING_REFCOUNT_STACK -2 + +// Returns a newly-created, empty, non-finalized string. When the string is no +// longer needed, it should be unref'd, never freed directly. +upb_string *upb_string_new(); + +// Internal-only; clients should call upb_string_unref(). +void _upb_string_free(upb_string *str); + +// Releases a ref on the given string, which may free the memory. "str" +// can be NULL, in which case this is a no-op. WARNING: NOT THREAD_SAFE +// UNLESS THE STRING IS SYNCHRONIZED. +INLINE void upb_string_unref(upb_string *str) { + if (str && upb_atomic_read(&str->refcount) > 0 && + upb_atomic_unref(&str->refcount)) { + _upb_string_free(str); + } +} + +upb_string *upb_strdup(upb_string *s); // Forward-declare. + +// Returns a string with the same contents as "str". The caller owns a ref on +// the returned string, which may or may not be the same object as "str. +// WARNING: NOT THREAD-SAFE UNLESS THE STRING IS SYNCHRONIZED! +INLINE upb_string *upb_string_getref(upb_string *str) { + int refcount = upb_atomic_read(&str->refcount); + if (refcount == _UPB_STRING_REFCOUNT_STACK) return upb_strdup(str); + // We don't ref the special <0 refcount for static strings. + if (refcount > 0) upb_atomic_ref(&str->refcount); + return str; +} + +// Returns the length of the string. +INLINE upb_strlen_t upb_string_len(upb_string *str) { return str->len; } + +// Use to read the bytes of the string. The caller *must* call +// upb_string_endread() after the data has been read. The window between +// upb_string_getrobuf() and upb_string_endread() should be kept as short as +// possible, because any pending upb_string_detach() may be blocked until +// upb_string_endread is called(). No other functions may be called on the +// string during this window except upb_string_len(). +INLINE const char *upb_string_getrobuf(upb_string *str) { return str->ptr; } +INLINE void upb_string_endread(upb_string *str) { (void)str; } + +// Convenience method for getting the end of the string. Calls +// upb_string_getrobuf() so inherits the caveats of calling that function. +INLINE const char *upb_string_getbufend(upb_string *str) { + return upb_string_getrobuf(str) + upb_string_len(str); +} + +// Attempts to recycle the string "str" so it may be reused and have different +// data written to it. After the function returns, "str" points to a writable +// string, which is either the original string if it had no other references +// or a newly created string if it did have other references. +// +// As a special case, passing a pointer to NULL will allocate a new string. +// This is convenient for the pattern: +// +// upb_string *str = NULL; +// while (x) { +// if (y) { +// upb_string_recycle(&str); +// upb_src_getstr(str); +// } +// } +void upb_string_recycle(upb_string **str); + +// The options for setting the contents of a string. These may only be called +// when a string is first created or recycled; once other functions have been +// called on the string, these functions are not allowed until the string is +// recycled. + +// Gets a pointer suitable for writing to the string, which is guaranteed to +// have at least "len" bytes of data available. The size of the string will +// become "len". +char *upb_string_getrwbuf(upb_string *str, upb_strlen_t len); + +// Replaces the contents of str with the contents of the given printf. +void upb_string_vprintf(upb_string *str, const char *format, va_list args); +INLINE void upb_string_printf(upb_string *str, const char *format, ...) { + va_list args; + va_start(args, format); + upb_string_vprintf(str, format, args); + va_end(args); +} + +// Sets the contents of "str" to be the given substring of "target_str", to +// which the caller must own a ref. +void upb_string_substr(upb_string *str, upb_string *target_str, + upb_strlen_t start, upb_strlen_t len); + +// Sketch of an API for allowing upb_strings to reference external, unowned +// data. Waiting for a clear use case before actually implementing it. +// +// Makes the string "str" a reference to the given string data. The caller +// guarantees that the given string data will not change or be deleted until a +// matching call to upb_string_detach(), which may block until any concurrent +// readers have finished reading. upb_string_detach() preserves the contents +// of the string by copying the referenced data if there are any other +// referents. +// void upb_string_attach(upb_string *str, char *ptr, upb_strlen_t len); +// void upb_string_detach(upb_string *str); + +// Allows using upb_strings in printf, ie: +// upb_strptr str = UPB_STRLIT("Hello, World!\n"); +// printf("String is: " UPB_STRFMT, UPB_STRARG(str)); */ +#define UPB_STRARG(str) upb_string_len(str), upb_string_getrobuf(str) +#define UPB_STRFMT "%.*s" + +// Macros for constructing upb_string objects statically or on the stack. These +// can be used like: +// +// upb_string static_str = UPB_STATIC_STRING("Foo"); +// +// int main() { +// upb_string stack_str = UPB_STACK_STRING("Foo"); +// // Now: +// // upb_streql(&static_str, &stack_str) == true +// // upb_streql(&static_str, UPB_STRLIT("Foo")) == true +// } +// +// You can also use UPB_STACK_STRING or UPB_STATIC_STRING with character arrays, +// but you must not change the underlying data once you've passed the string on: +// +// void foo() { +// char data[] = "ABC123"; +// upb_string stack_str = UPB_STACK_STR(data); +// bar(&stack_str); +// data[0] = "B"; // NOT ALLOWED!! +// } +// +// TODO: should the stack business just be like attach/detach? The latter seems +// more flexible, though it does require a stack allocation. Maybe put this off +// until there is a clear use case. +#define UPB_STATIC_STRING(str) \ + _UPB_STRING_INIT(str, sizeof(str)-1, _UPB_STRING_REFCOUNT_STATIC) +#define UPB_STATIC_STRING_LEN(str, len) \ + _UPB_STRING_INIT(str, len, _UPB_STRING_REFCOUNT_STATIC) +#define UPB_STACK_STRING(str) \ + _UPB_STRING_INIT(str, sizeof(str)-1, _UPB_STRING_REFCOUNT_STACK) +#define UPB_STACK_STRING_LEN(str, len) \ + _UPB_STRING_INIT(str, len, _UPB_STRING_REFCOUNT_STACK) + +// A convenient way of specifying upb_strings as literals, like: +// +// upb_streql(UPB_STRLIT("expected"), other_str); +// +// However, this requires either C99 compound initializers or C++. +// Must ONLY be called with a string literal as its argument! +//#ifdef __cplusplus +//namespace upb { +//class String : public upb_string { +// // This constructor must ONLY be called with a string literal. +// String(const char *str) : upb_string(UPB_STATIC_STRING(str)) {} +//}; +//} +//#define UPB_STRLIT(str) upb::String(str) +//#endif +#define UPB_STRLIT(str) &(upb_string)UPB_STATIC_STRING(str) + +/* upb_string library functions ***********************************************/ + +// Named like their <string.h> counterparts, these are all safe against buffer +// overflow. For the most part these only use the public upb_string interface. + +// More efficient than upb_strcmp if all you need is to test equality. +INLINE bool upb_streql(upb_string *s1, upb_string *s2) { + upb_strlen_t len = upb_string_len(s1); + if(len != upb_string_len(s2)) { + return false; + } else { + bool ret = + memcmp(upb_string_getrobuf(s1), upb_string_getrobuf(s2), len) == 0; + upb_string_endread(s1); + upb_string_endread(s2); + return ret; + } +} + +// Like strcmp(). +int upb_strcmp(upb_string *s1, upb_string *s2); + +// Compare a upb_string with memory or a NULL-terminated C string. +INLINE bool upb_streqllen(upb_string *str, const void *buf, upb_strlen_t len) { + return len == upb_string_len(str) && + memcmp(upb_string_getrobuf(str), buf, len) == 0; +} + +INLINE bool upb_streqlc(upb_string *str, const void *buf) { + // Could be made one-pass. + return upb_streqllen(str, buf, strlen((const char*)buf)); +} + +// Like upb_strcpy, but copies from a buffer and length. +INLINE void upb_strcpylen(upb_string *dest, const void *src, upb_strlen_t len) { + memcpy(upb_string_getrwbuf(dest, len), src, len); +} + +// Replaces the contents of "dest" with the contents of "src". +INLINE void upb_strcpy(upb_string *dest, upb_string *src) { + upb_strcpylen(dest, upb_string_getrobuf(src), upb_string_len(src)); + upb_string_endread(src); +} + +// Like upb_strcpy, but copies from a NULL-terminated string. +INLINE void upb_strcpyc(upb_string *dest, const void *src) { + // This does two passes over src, but that is necessary unless we want to + // repeatedly re-allocate dst, which seems worse. + upb_strcpylen(dest, src, strlen((const char*)src)); +} + +// Returns a new string whose contents are a copy of s. +upb_string *upb_strdup(upb_string *s); + +// Like upb_strdup(), but duplicates a given buffer and length. +INLINE upb_string *upb_strduplen(const void *src, upb_strlen_t len) { + upb_string *s = upb_string_new(); + upb_strcpylen(s, src, len); + return s; +} + +// Like upb_strdup(), but duplicates a C NULL-terminated string. +INLINE upb_string *upb_strdupc(const char *src) { + return upb_strduplen(src, strlen(src)); +} + +// Appends 'append' to 's' in-place, resizing s if necessary. +void upb_strcat(upb_string *s, upb_string *append); + +// Returns a new string that is a substring of the given string. +INLINE upb_string *upb_strslice(upb_string *s, int offset, int len) { + upb_string *str = upb_string_new(); + upb_string_substr(str, s, offset, len); + return str; +} + +// Reads an entire file into a newly-allocated string. +upb_string *upb_strreadfile(const char *filename); + +// Returns a new string with the contents of the given printf. +upb_string *upb_string_asprintf(const char *format, ...); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/src/upb_table.c b/core/upb_table.c index a477121..a6e0a56 100644 --- a/src/upb_table.c +++ b/core/upb_table.c @@ -5,7 +5,7 @@ */ #include "upb_table.h" -#include "upb_data.h" +#include "upb_string.h" #include <assert.h> #include <stdlib.h> @@ -28,7 +28,7 @@ void upb_table_init(upb_table *t, uint32_t size, uint16_t entry_size) { t->count = 0; t->entry_size = entry_size; - t->size_lg2 = 1; + t->size_lg2 = 0; while(size >>= 1) t->size_lg2++; size_t bytes = upb_table_size(t) * t->entry_size; t->mask = upb_table_size(t) - 1; @@ -57,19 +57,19 @@ void upb_strtable_free(upb_strtable *t) { upb_table_free(&t->t); } -static uint32_t strtable_bucket(upb_strtable *t, upb_strptr key) +static uint32_t strtable_bucket(upb_strtable *t, upb_string *key) { - uint32_t hash = MurmurHash2(upb_string_getrobuf(key), upb_strlen(key), 0); + uint32_t hash = MurmurHash2(upb_string_getrobuf(key), upb_string_len(key), 0); return (hash & (upb_strtable_size(t)-1)) + 1; } -void *upb_strtable_lookup(upb_strtable *t, upb_strptr key) +void *upb_strtable_lookup(upb_strtable *t, upb_string *key) { uint32_t bucket = strtable_bucket(t, key); upb_strtable_entry *e; do { e = strent(t, bucket); - if(!upb_string_isnull(e->key) && upb_streql(e->key, key)) return e; + if(e->key && upb_streql(e->key, key)) return e; } while((bucket = e->next) != UPB_END_OF_CHAIN); return NULL; } @@ -149,7 +149,7 @@ static uint32_t empty_strbucket(upb_strtable *table) /* TODO: does it matter that this is biased towards the front of the table? */ for(uint32_t i = 1; i <= upb_strtable_size(table); i++) { upb_strtable_entry *e = strent(table, i); - if(upb_string_isnull(e->key)) return i; + if(!e->key) return i; } assert(false); return 0; @@ -158,11 +158,11 @@ static uint32_t empty_strbucket(upb_strtable *table) static void strinsert(upb_strtable *t, upb_strtable_entry *e) { assert(upb_strtable_lookup(t, e->key) == NULL); - e->key = upb_string_getref(e->key, UPB_REF_FROZEN); + e->key = upb_string_getref(e->key); t->t.count++; uint32_t bucket = strtable_bucket(t, e->key); upb_strtable_entry *table_e = strent(t, bucket); - if(!upb_string_isnull(table_e->key)) { /* Collision. */ + if(table_e->key) { /* Collision. */ if(bucket == strtable_bucket(t, table_e->key)) { /* Existing element is in its main posisiton. Find an empty slot to * place our new element and append it to this key's chain. */ @@ -179,7 +179,7 @@ static void strinsert(upb_strtable *t, upb_strtable_entry *e) memcpy(strent(t, empty_bucket), table_e, t->t.entry_size); /* copies next */ upb_strtable_entry *evictee_e = strent(t, evictee_bucket); while(1) { - assert(!upb_string_isnull(evictee_e->key)); + assert(evictee_e->key); assert(evictee_e->next != UPB_END_OF_CHAIN); if(evictee_e->next == bucket) { evictee_e->next = empty_bucket; @@ -232,7 +232,7 @@ void *upb_strtable_next(upb_strtable *t, upb_strtable_entry *cur) { do { cur = (void*)((char*)cur + t->t.entry_size); if(cur == end) return NULL; - } while(upb_string_isnull(cur->key)); + } while(cur->key == NULL); return cur; } diff --git a/src/upb_table.h b/core/upb_table.h index 122aed3..20dae92 100644 --- a/src/upb_table.h +++ b/core/upb_table.h @@ -17,6 +17,7 @@ #include <assert.h> #include "upb.h" +#include "upb_string.h" #ifdef __cplusplus extern "C" { @@ -38,7 +39,7 @@ typedef struct { // performance by letting us compare hashes before comparing lengths or the // strings themselves. typedef struct { - upb_strptr key; // We own a frozen ref. + upb_string *key; // We own a ref. uint32_t next; // Internal chaining. } upb_strtable_entry; @@ -114,7 +115,7 @@ INLINE void *upb_inttable_lookup(upb_inttable *t, uint32_t key) { return upb_inttable_fastlookup(t, key, t->t.entry_size); } -void *upb_strtable_lookup(upb_strtable *t, upb_strptr key); +void *upb_strtable_lookup(upb_strtable *t, upb_string *key); /* Provides iteration over the table. The order in which the entries are * returned is undefined. Insertions invalidate iterators. The _next diff --git a/descriptor/descriptor.c b/descriptor/descriptor.c index c722b25..ee6b25b 100644 --- a/descriptor/descriptor.c +++ b/descriptor/descriptor.c @@ -1,2351 +1,297 @@ -/* - * This file is a data dump of a protocol buffer into a C structure. - * It was created by the upb compiler (upbc) with the following - * command-line: - * - * ./tools/upbc -i upb_file_descriptor_set -o descriptor/descriptor descriptor/descriptor.proto.pb - * - * This file is a dump of 'descriptor/descriptor.proto.pb'. - * It contains exactly the same data, but in a C structure form - * instead of a serialized protobuf. This file contains no code, - * only data. - * - * This file was auto-generated. Do not edit. */ +#include "descriptor.h" -#include "descriptor/descriptor.h" - -static char strdata[] = - ".google.protobuf.DescriptorProto.google.protobuf.DescriptorProto.ExtensionRan" - "ge.google.protobuf.EnumDescriptorProto.google.protobuf.EnumOptions.google.pro" - "tobuf.EnumValueDescriptorProto.google.protobuf.EnumValueOptions.google.protob" - "uf.FieldDescriptorProto.google.protobuf.FieldDescriptorProto.Label.google.pro" - "tobuf.FieldDescriptorProto.Type.google.protobuf.FieldOptions.google.protobuf." - "FieldOptions.CType.google.protobuf.FileDescriptorProto.google.protobuf.FileOp" - "tions.google.protobuf.FileOptions.OptimizeMode.google.protobuf.MessageOptions" - ".google.protobuf.MethodDescriptorProto.google.protobuf.MethodOptions.google.p" - "rotobuf.ServiceDescriptorProto.google.protobuf.ServiceOptions.google.protobuf" - ".UninterpretedOption.google.protobuf.UninterpretedOption.NamePartCODE_SIZECOR" - "DCTypeDescriptorProtoDescriptorProtosEnumDescriptorProtoEnumOptionsEnumValueD" - "escriptorProtoEnumValueOptionsExtensionRangeFieldDescriptorProtoFieldOptionsF" - "ileDescriptorProtoFileDescriptorSetFileOptionsLABEL_OPTIONALLABEL_REPEATEDLAB" - "EL_REQUIREDLabelMessageOptionsMethodDescriptorProtoMethodOptionsNamePartOptim" - "izeModeSPEEDSTRING_PIECEServiceDescriptorProtoServiceOptionsTYPE_BOOLTYPE_BYT" - "ESTYPE_DOUBLETYPE_ENUMTYPE_FIXED32TYPE_FIXED64TYPE_FLOATTYPE_GROUPTYPE_INT32T" - "YPE_INT64TYPE_MESSAGETYPE_SFIXED32TYPE_SFIXED64TYPE_SINT32TYPE_SINT64TYPE_STR" - "INGTYPE_UINT32TYPE_UINT64TypeUninterpretedOptioncom.google.protobufctypedefau" - "lt_valuedependencydeprecateddescriptor/descriptor.protodouble_valueendenum_ty" - "peexperimental_map_keyextendeeextensionextension_rangefalsefieldfilegoogle.pr" - "otobufidentifier_valueinput_typeis_extensionjava_multiple_filesjava_outer_cla" - "ssnamejava_packagelabelmessage_set_wire_formatmessage_typemethodnamename_part" - "negative_int_valuenested_typenumberoptimize_foroptionsoutput_typepackagepacke" - "dpositive_int_valueservicestartstring_valuetypetype_nameuninterpreted_optionv" - "alue"; - -static upb_static_string strings[] = { - UPB_STATIC_STRING_INIT_LEN(&strdata[0], 32), - UPB_STATIC_STRING_INIT_LEN(&strdata[32], 47), - UPB_STATIC_STRING_INIT_LEN(&strdata[79], 36), - UPB_STATIC_STRING_INIT_LEN(&strdata[115], 28), - UPB_STATIC_STRING_INIT_LEN(&strdata[143], 41), - UPB_STATIC_STRING_INIT_LEN(&strdata[184], 33), - UPB_STATIC_STRING_INIT_LEN(&strdata[217], 37), - UPB_STATIC_STRING_INIT_LEN(&strdata[254], 43), - UPB_STATIC_STRING_INIT_LEN(&strdata[297], 42), - UPB_STATIC_STRING_INIT_LEN(&strdata[339], 29), - UPB_STATIC_STRING_INIT_LEN(&strdata[368], 35), - UPB_STATIC_STRING_INIT_LEN(&strdata[403], 36), - UPB_STATIC_STRING_INIT_LEN(&strdata[439], 28), - UPB_STATIC_STRING_INIT_LEN(&strdata[467], 41), - UPB_STATIC_STRING_INIT_LEN(&strdata[508], 31), - UPB_STATIC_STRING_INIT_LEN(&strdata[539], 38), - UPB_STATIC_STRING_INIT_LEN(&strdata[577], 30), - UPB_STATIC_STRING_INIT_LEN(&strdata[607], 39), - UPB_STATIC_STRING_INIT_LEN(&strdata[646], 31), - UPB_STATIC_STRING_INIT_LEN(&strdata[677], 36), - UPB_STATIC_STRING_INIT_LEN(&strdata[713], 45), - UPB_STATIC_STRING_INIT_LEN(&strdata[758], 9), - UPB_STATIC_STRING_INIT_LEN(&strdata[767], 4), - UPB_STATIC_STRING_INIT_LEN(&strdata[771], 5), - UPB_STATIC_STRING_INIT_LEN(&strdata[776], 15), - UPB_STATIC_STRING_INIT_LEN(&strdata[791], 16), - UPB_STATIC_STRING_INIT_LEN(&strdata[807], 19), - UPB_STATIC_STRING_INIT_LEN(&strdata[826], 11), - UPB_STATIC_STRING_INIT_LEN(&strdata[837], 24), - UPB_STATIC_STRING_INIT_LEN(&strdata[861], 16), - UPB_STATIC_STRING_INIT_LEN(&strdata[877], 14), - UPB_STATIC_STRING_INIT_LEN(&strdata[891], 20), - UPB_STATIC_STRING_INIT_LEN(&strdata[911], 12), - UPB_STATIC_STRING_INIT_LEN(&strdata[923], 19), - UPB_STATIC_STRING_INIT_LEN(&strdata[942], 17), - UPB_STATIC_STRING_INIT_LEN(&strdata[959], 11), - UPB_STATIC_STRING_INIT_LEN(&strdata[970], 14), - UPB_STATIC_STRING_INIT_LEN(&strdata[984], 14), - UPB_STATIC_STRING_INIT_LEN(&strdata[998], 14), - UPB_STATIC_STRING_INIT_LEN(&strdata[1012], 5), - UPB_STATIC_STRING_INIT_LEN(&strdata[1017], 14), - UPB_STATIC_STRING_INIT_LEN(&strdata[1031], 21), - UPB_STATIC_STRING_INIT_LEN(&strdata[1052], 13), - UPB_STATIC_STRING_INIT_LEN(&strdata[1065], 8), - UPB_STATIC_STRING_INIT_LEN(&strdata[1073], 12), - UPB_STATIC_STRING_INIT_LEN(&strdata[1085], 5), - UPB_STATIC_STRING_INIT_LEN(&strdata[1090], 12), - UPB_STATIC_STRING_INIT_LEN(&strdata[1102], 22), - UPB_STATIC_STRING_INIT_LEN(&strdata[1124], 14), - UPB_STATIC_STRING_INIT_LEN(&strdata[1138], 9), - UPB_STATIC_STRING_INIT_LEN(&strdata[1147], 10), - UPB_STATIC_STRING_INIT_LEN(&strdata[1157], 11), - UPB_STATIC_STRING_INIT_LEN(&strdata[1168], 9), - UPB_STATIC_STRING_INIT_LEN(&strdata[1177], 12), - UPB_STATIC_STRING_INIT_LEN(&strdata[1189], 12), - UPB_STATIC_STRING_INIT_LEN(&strdata[1201], 10), - UPB_STATIC_STRING_INIT_LEN(&strdata[1211], 10), - UPB_STATIC_STRING_INIT_LEN(&strdata[1221], 10), - UPB_STATIC_STRING_INIT_LEN(&strdata[1231], 10), - UPB_STATIC_STRING_INIT_LEN(&strdata[1241], 12), - UPB_STATIC_STRING_INIT_LEN(&strdata[1253], 13), - UPB_STATIC_STRING_INIT_LEN(&strdata[1266], 13), - UPB_STATIC_STRING_INIT_LEN(&strdata[1279], 11), - UPB_STATIC_STRING_INIT_LEN(&strdata[1290], 11), - UPB_STATIC_STRING_INIT_LEN(&strdata[1301], 11), - UPB_STATIC_STRING_INIT_LEN(&strdata[1312], 11), - UPB_STATIC_STRING_INIT_LEN(&strdata[1323], 11), - UPB_STATIC_STRING_INIT_LEN(&strdata[1334], 4), - UPB_STATIC_STRING_INIT_LEN(&strdata[1338], 19), - UPB_STATIC_STRING_INIT_LEN(&strdata[1357], 19), - UPB_STATIC_STRING_INIT_LEN(&strdata[1376], 5), - UPB_STATIC_STRING_INIT_LEN(&strdata[1381], 13), - UPB_STATIC_STRING_INIT_LEN(&strdata[1394], 10), - UPB_STATIC_STRING_INIT_LEN(&strdata[1404], 10), - UPB_STATIC_STRING_INIT_LEN(&strdata[1414], 27), - UPB_STATIC_STRING_INIT_LEN(&strdata[1441], 12), - UPB_STATIC_STRING_INIT_LEN(&strdata[1453], 3), - UPB_STATIC_STRING_INIT_LEN(&strdata[1456], 9), - UPB_STATIC_STRING_INIT_LEN(&strdata[1465], 20), - UPB_STATIC_STRING_INIT_LEN(&strdata[1485], 8), - UPB_STATIC_STRING_INIT_LEN(&strdata[1493], 9), - UPB_STATIC_STRING_INIT_LEN(&strdata[1502], 15), - UPB_STATIC_STRING_INIT_LEN(&strdata[1517], 5), - UPB_STATIC_STRING_INIT_LEN(&strdata[1522], 5), - UPB_STATIC_STRING_INIT_LEN(&strdata[1527], 4), - UPB_STATIC_STRING_INIT_LEN(&strdata[1531], 15), - UPB_STATIC_STRING_INIT_LEN(&strdata[1546], 16), - UPB_STATIC_STRING_INIT_LEN(&strdata[1562], 10), - UPB_STATIC_STRING_INIT_LEN(&strdata[1572], 12), - UPB_STATIC_STRING_INIT_LEN(&strdata[1584], 19), - UPB_STATIC_STRING_INIT_LEN(&strdata[1603], 20), - UPB_STATIC_STRING_INIT_LEN(&strdata[1623], 12), - UPB_STATIC_STRING_INIT_LEN(&strdata[1635], 5), - UPB_STATIC_STRING_INIT_LEN(&strdata[1640], 23), - UPB_STATIC_STRING_INIT_LEN(&strdata[1663], 12), - UPB_STATIC_STRING_INIT_LEN(&strdata[1675], 6), - UPB_STATIC_STRING_INIT_LEN(&strdata[1681], 4), - UPB_STATIC_STRING_INIT_LEN(&strdata[1685], 9), - UPB_STATIC_STRING_INIT_LEN(&strdata[1694], 18), - UPB_STATIC_STRING_INIT_LEN(&strdata[1712], 11), - UPB_STATIC_STRING_INIT_LEN(&strdata[1723], 6), - UPB_STATIC_STRING_INIT_LEN(&strdata[1729], 12), - UPB_STATIC_STRING_INIT_LEN(&strdata[1741], 7), - UPB_STATIC_STRING_INIT_LEN(&strdata[1748], 11), - UPB_STATIC_STRING_INIT_LEN(&strdata[1759], 7), - UPB_STATIC_STRING_INIT_LEN(&strdata[1766], 6), - UPB_STATIC_STRING_INIT_LEN(&strdata[1772], 18), - UPB_STATIC_STRING_INIT_LEN(&strdata[1790], 7), - UPB_STATIC_STRING_INIT_LEN(&strdata[1797], 5), - UPB_STATIC_STRING_INIT_LEN(&strdata[1802], 12), - UPB_STATIC_STRING_INIT_LEN(&strdata[1814], 4), - UPB_STATIC_STRING_INIT_LEN(&strdata[1818], 9), - UPB_STATIC_STRING_INIT_LEN(&strdata[1827], 20), - UPB_STATIC_STRING_INIT_LEN(&strdata[1847], 5), -}; - -/* Forward declarations of messages, and array decls. */ -static google_protobuf_DescriptorProto google_protobuf_DescriptorProto_values[18]; - -static google_protobuf_DescriptorProto *google_protobuf_DescriptorProto_array_elems[] = { - &google_protobuf_DescriptorProto_values[0], - &google_protobuf_DescriptorProto_values[1], - &google_protobuf_DescriptorProto_values[2], - &google_protobuf_DescriptorProto_values[3], - &google_protobuf_DescriptorProto_values[4], - &google_protobuf_DescriptorProto_values[5], - &google_protobuf_DescriptorProto_values[6], - &google_protobuf_DescriptorProto_values[7], - &google_protobuf_DescriptorProto_values[8], - &google_protobuf_DescriptorProto_values[9], - &google_protobuf_DescriptorProto_values[10], - &google_protobuf_DescriptorProto_values[11], - &google_protobuf_DescriptorProto_values[12], - &google_protobuf_DescriptorProto_values[13], - &google_protobuf_DescriptorProto_values[14], - &google_protobuf_DescriptorProto_values[15], - &google_protobuf_DescriptorProto_values[16], - &google_protobuf_DescriptorProto_values[17], -}; -static upb_static_array google_protobuf_DescriptorProto_arrays[3] = { - UPB_STATIC_ARRAY_INIT(&google_protobuf_DescriptorProto_array_elems[0], 16), - UPB_STATIC_ARRAY_INIT(&google_protobuf_DescriptorProto_array_elems[16], 1), - UPB_STATIC_ARRAY_INIT(&google_protobuf_DescriptorProto_array_elems[17], 1), -}; -static google_protobuf_FileDescriptorProto google_protobuf_FileDescriptorProto_values[1]; - -static google_protobuf_FileDescriptorProto *google_protobuf_FileDescriptorProto_array_elems[] = { - &google_protobuf_FileDescriptorProto_values[0], -}; -static upb_static_array google_protobuf_FileDescriptorProto_arrays[1] = { - UPB_STATIC_ARRAY_INIT(&google_protobuf_FileDescriptorProto_array_elems[0], 1), -}; -static google_protobuf_FileDescriptorSet google_protobuf_FileDescriptorSet_values[1]; - -static google_protobuf_DescriptorProto_ExtensionRange google_protobuf_DescriptorProto_ExtensionRange_values[7]; - -static google_protobuf_DescriptorProto_ExtensionRange *google_protobuf_DescriptorProto_ExtensionRange_array_elems[] = { - &google_protobuf_DescriptorProto_ExtensionRange_values[0], - &google_protobuf_DescriptorProto_ExtensionRange_values[1], - &google_protobuf_DescriptorProto_ExtensionRange_values[2], - &google_protobuf_DescriptorProto_ExtensionRange_values[3], - &google_protobuf_DescriptorProto_ExtensionRange_values[4], - &google_protobuf_DescriptorProto_ExtensionRange_values[5], - &google_protobuf_DescriptorProto_ExtensionRange_values[6], -}; -static upb_static_array google_protobuf_DescriptorProto_ExtensionRange_arrays[7] = { - UPB_STATIC_ARRAY_INIT(&google_protobuf_DescriptorProto_ExtensionRange_array_elems[0], 1), - UPB_STATIC_ARRAY_INIT(&google_protobuf_DescriptorProto_ExtensionRange_array_elems[1], 1), - UPB_STATIC_ARRAY_INIT(&google_protobuf_DescriptorProto_ExtensionRange_array_elems[2], 1), - UPB_STATIC_ARRAY_INIT(&google_protobuf_DescriptorProto_ExtensionRange_array_elems[3], 1), - UPB_STATIC_ARRAY_INIT(&google_protobuf_DescriptorProto_ExtensionRange_array_elems[4], 1), - UPB_STATIC_ARRAY_INIT(&google_protobuf_DescriptorProto_ExtensionRange_array_elems[5], 1), - UPB_STATIC_ARRAY_INIT(&google_protobuf_DescriptorProto_ExtensionRange_array_elems[6], 1), -}; -static google_protobuf_FileOptions google_protobuf_FileOptions_values[1]; - -static google_protobuf_EnumDescriptorProto google_protobuf_EnumDescriptorProto_values[4]; - -static google_protobuf_EnumDescriptorProto *google_protobuf_EnumDescriptorProto_array_elems[] = { - &google_protobuf_EnumDescriptorProto_values[0], - &google_protobuf_EnumDescriptorProto_values[1], - &google_protobuf_EnumDescriptorProto_values[2], - &google_protobuf_EnumDescriptorProto_values[3], -}; -static upb_static_array google_protobuf_EnumDescriptorProto_arrays[3] = { - UPB_STATIC_ARRAY_INIT(&google_protobuf_EnumDescriptorProto_array_elems[0], 2), - UPB_STATIC_ARRAY_INIT(&google_protobuf_EnumDescriptorProto_array_elems[2], 1), - UPB_STATIC_ARRAY_INIT(&google_protobuf_EnumDescriptorProto_array_elems[3], 1), -}; -static google_protobuf_FieldDescriptorProto google_protobuf_FieldDescriptorProto_values[63]; - -static google_protobuf_FieldDescriptorProto *google_protobuf_FieldDescriptorProto_array_elems[] = { - &google_protobuf_FieldDescriptorProto_values[0], - &google_protobuf_FieldDescriptorProto_values[1], - &google_protobuf_FieldDescriptorProto_values[2], - &google_protobuf_FieldDescriptorProto_values[3], - &google_protobuf_FieldDescriptorProto_values[4], - &google_protobuf_FieldDescriptorProto_values[5], - &google_protobuf_FieldDescriptorProto_values[6], - &google_protobuf_FieldDescriptorProto_values[7], - &google_protobuf_FieldDescriptorProto_values[8], - &google_protobuf_FieldDescriptorProto_values[9], - &google_protobuf_FieldDescriptorProto_values[10], - &google_protobuf_FieldDescriptorProto_values[11], - &google_protobuf_FieldDescriptorProto_values[12], - &google_protobuf_FieldDescriptorProto_values[13], - &google_protobuf_FieldDescriptorProto_values[14], - &google_protobuf_FieldDescriptorProto_values[15], - &google_protobuf_FieldDescriptorProto_values[16], - &google_protobuf_FieldDescriptorProto_values[17], - &google_protobuf_FieldDescriptorProto_values[18], - &google_protobuf_FieldDescriptorProto_values[19], - &google_protobuf_FieldDescriptorProto_values[20], - &google_protobuf_FieldDescriptorProto_values[21], - &google_protobuf_FieldDescriptorProto_values[22], - &google_protobuf_FieldDescriptorProto_values[23], - &google_protobuf_FieldDescriptorProto_values[24], - &google_protobuf_FieldDescriptorProto_values[25], - &google_protobuf_FieldDescriptorProto_values[26], - &google_protobuf_FieldDescriptorProto_values[27], - &google_protobuf_FieldDescriptorProto_values[28], - &google_protobuf_FieldDescriptorProto_values[29], - &google_protobuf_FieldDescriptorProto_values[30], - &google_protobuf_FieldDescriptorProto_values[31], - &google_protobuf_FieldDescriptorProto_values[32], - &google_protobuf_FieldDescriptorProto_values[33], - &google_protobuf_FieldDescriptorProto_values[34], - &google_protobuf_FieldDescriptorProto_values[35], - &google_protobuf_FieldDescriptorProto_values[36], - &google_protobuf_FieldDescriptorProto_values[37], - &google_protobuf_FieldDescriptorProto_values[38], - &google_protobuf_FieldDescriptorProto_values[39], - &google_protobuf_FieldDescriptorProto_values[40], - &google_protobuf_FieldDescriptorProto_values[41], - &google_protobuf_FieldDescriptorProto_values[42], - &google_protobuf_FieldDescriptorProto_values[43], - &google_protobuf_FieldDescriptorProto_values[44], - &google_protobuf_FieldDescriptorProto_values[45], - &google_protobuf_FieldDescriptorProto_values[46], - &google_protobuf_FieldDescriptorProto_values[47], - &google_protobuf_FieldDescriptorProto_values[48], - &google_protobuf_FieldDescriptorProto_values[49], - &google_protobuf_FieldDescriptorProto_values[50], - &google_protobuf_FieldDescriptorProto_values[51], - &google_protobuf_FieldDescriptorProto_values[52], - &google_protobuf_FieldDescriptorProto_values[53], - &google_protobuf_FieldDescriptorProto_values[54], - &google_protobuf_FieldDescriptorProto_values[55], - &google_protobuf_FieldDescriptorProto_values[56], - &google_protobuf_FieldDescriptorProto_values[57], - &google_protobuf_FieldDescriptorProto_values[58], - &google_protobuf_FieldDescriptorProto_values[59], - &google_protobuf_FieldDescriptorProto_values[60], - &google_protobuf_FieldDescriptorProto_values[61], - &google_protobuf_FieldDescriptorProto_values[62], -}; -static upb_static_array google_protobuf_FieldDescriptorProto_arrays[18] = { - UPB_STATIC_ARRAY_INIT(&google_protobuf_FieldDescriptorProto_array_elems[0], 1), - UPB_STATIC_ARRAY_INIT(&google_protobuf_FieldDescriptorProto_array_elems[1], 8), - UPB_STATIC_ARRAY_INIT(&google_protobuf_FieldDescriptorProto_array_elems[9], 7), - UPB_STATIC_ARRAY_INIT(&google_protobuf_FieldDescriptorProto_array_elems[16], 2), - UPB_STATIC_ARRAY_INIT(&google_protobuf_FieldDescriptorProto_array_elems[18], 8), - UPB_STATIC_ARRAY_INIT(&google_protobuf_FieldDescriptorProto_array_elems[26], 3), - UPB_STATIC_ARRAY_INIT(&google_protobuf_FieldDescriptorProto_array_elems[29], 3), - UPB_STATIC_ARRAY_INIT(&google_protobuf_FieldDescriptorProto_array_elems[32], 3), - UPB_STATIC_ARRAY_INIT(&google_protobuf_FieldDescriptorProto_array_elems[35], 4), - UPB_STATIC_ARRAY_INIT(&google_protobuf_FieldDescriptorProto_array_elems[39], 5), - UPB_STATIC_ARRAY_INIT(&google_protobuf_FieldDescriptorProto_array_elems[44], 2), - UPB_STATIC_ARRAY_INIT(&google_protobuf_FieldDescriptorProto_array_elems[46], 5), - UPB_STATIC_ARRAY_INIT(&google_protobuf_FieldDescriptorProto_array_elems[51], 1), - UPB_STATIC_ARRAY_INIT(&google_protobuf_FieldDescriptorProto_array_elems[52], 1), - UPB_STATIC_ARRAY_INIT(&google_protobuf_FieldDescriptorProto_array_elems[53], 1), - UPB_STATIC_ARRAY_INIT(&google_protobuf_FieldDescriptorProto_array_elems[54], 1), - UPB_STATIC_ARRAY_INIT(&google_protobuf_FieldDescriptorProto_array_elems[55], 6), - UPB_STATIC_ARRAY_INIT(&google_protobuf_FieldDescriptorProto_array_elems[61], 2), -}; -static google_protobuf_EnumValueDescriptorProto google_protobuf_EnumValueDescriptorProto_values[25]; - -static google_protobuf_EnumValueDescriptorProto *google_protobuf_EnumValueDescriptorProto_array_elems[] = { - &google_protobuf_EnumValueDescriptorProto_values[0], - &google_protobuf_EnumValueDescriptorProto_values[1], - &google_protobuf_EnumValueDescriptorProto_values[2], - &google_protobuf_EnumValueDescriptorProto_values[3], - &google_protobuf_EnumValueDescriptorProto_values[4], - &google_protobuf_EnumValueDescriptorProto_values[5], - &google_protobuf_EnumValueDescriptorProto_values[6], - &google_protobuf_EnumValueDescriptorProto_values[7], - &google_protobuf_EnumValueDescriptorProto_values[8], - &google_protobuf_EnumValueDescriptorProto_values[9], - &google_protobuf_EnumValueDescriptorProto_values[10], - &google_protobuf_EnumValueDescriptorProto_values[11], - &google_protobuf_EnumValueDescriptorProto_values[12], - &google_protobuf_EnumValueDescriptorProto_values[13], - &google_protobuf_EnumValueDescriptorProto_values[14], - &google_protobuf_EnumValueDescriptorProto_values[15], - &google_protobuf_EnumValueDescriptorProto_values[16], - &google_protobuf_EnumValueDescriptorProto_values[17], - &google_protobuf_EnumValueDescriptorProto_values[18], - &google_protobuf_EnumValueDescriptorProto_values[19], - &google_protobuf_EnumValueDescriptorProto_values[20], - &google_protobuf_EnumValueDescriptorProto_values[21], - &google_protobuf_EnumValueDescriptorProto_values[22], - &google_protobuf_EnumValueDescriptorProto_values[23], - &google_protobuf_EnumValueDescriptorProto_values[24], -}; -static upb_static_array google_protobuf_EnumValueDescriptorProto_arrays[4] = { - UPB_STATIC_ARRAY_INIT(&google_protobuf_EnumValueDescriptorProto_array_elems[0], 18), - UPB_STATIC_ARRAY_INIT(&google_protobuf_EnumValueDescriptorProto_array_elems[18], 3), - UPB_STATIC_ARRAY_INIT(&google_protobuf_EnumValueDescriptorProto_array_elems[21], 2), - UPB_STATIC_ARRAY_INIT(&google_protobuf_EnumValueDescriptorProto_array_elems[23], 2), -}; -static google_protobuf_DescriptorProto google_protobuf_DescriptorProto_values[18] = { - - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .field = true, - .nested_type = false, - .enum_type = false, - .extension_range = false, - .extension = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[34]), /* "FileDescriptorSet" */ - .field = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FieldDescriptorProto_arrays[0]), - .nested_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .enum_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension_range = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .field = true, - .nested_type = false, - .enum_type = false, - .extension_range = false, - .extension = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[33]), /* "FileDescriptorProto" */ - .field = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FieldDescriptorProto_arrays[1]), - .nested_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .enum_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension_range = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .field = true, - .nested_type = true, - .enum_type = false, - .extension_range = false, - .extension = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[24]), /* "DescriptorProto" */ - .field = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FieldDescriptorProto_arrays[2]), - .nested_type = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_DescriptorProto_arrays[1]), - .enum_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension_range = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .field = true, - .nested_type = false, - .enum_type = true, - .extension_range = false, - .extension = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[31]), /* "FieldDescriptorProto" */ - .field = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FieldDescriptorProto_arrays[4]), - .nested_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .enum_type = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_EnumDescriptorProto_arrays[0]), - .extension_range = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .field = true, - .nested_type = false, - .enum_type = false, - .extension_range = false, - .extension = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[26]), /* "EnumDescriptorProto" */ - .field = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FieldDescriptorProto_arrays[5]), - .nested_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .enum_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension_range = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .field = true, - .nested_type = false, - .enum_type = false, - .extension_range = false, - .extension = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[28]), /* "EnumValueDescriptorProto" */ - .field = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FieldDescriptorProto_arrays[6]), - .nested_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .enum_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension_range = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .field = true, - .nested_type = false, - .enum_type = false, - .extension_range = false, - .extension = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[47]), /* "ServiceDescriptorProto" */ - .field = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FieldDescriptorProto_arrays[7]), - .nested_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .enum_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension_range = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .field = true, - .nested_type = false, - .enum_type = false, - .extension_range = false, - .extension = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[41]), /* "MethodDescriptorProto" */ - .field = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FieldDescriptorProto_arrays[8]), - .nested_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .enum_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension_range = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .field = true, - .nested_type = false, - .enum_type = true, - .extension_range = true, - .extension = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[35]), /* "FileOptions" */ - .field = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FieldDescriptorProto_arrays[9]), - .nested_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .enum_type = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_EnumDescriptorProto_arrays[1]), - .extension_range = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_DescriptorProto_ExtensionRange_arrays[0]), - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .field = true, - .nested_type = false, - .enum_type = false, - .extension_range = true, - .extension = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[40]), /* "MessageOptions" */ - .field = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FieldDescriptorProto_arrays[10]), - .nested_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .enum_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension_range = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_DescriptorProto_ExtensionRange_arrays[1]), - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .field = true, - .nested_type = false, - .enum_type = true, - .extension_range = true, - .extension = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[32]), /* "FieldOptions" */ - .field = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FieldDescriptorProto_arrays[11]), - .nested_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .enum_type = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_EnumDescriptorProto_arrays[2]), - .extension_range = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_DescriptorProto_ExtensionRange_arrays[2]), - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .field = true, - .nested_type = false, - .enum_type = false, - .extension_range = true, - .extension = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[27]), /* "EnumOptions" */ - .field = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FieldDescriptorProto_arrays[12]), - .nested_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .enum_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension_range = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_DescriptorProto_ExtensionRange_arrays[3]), - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .field = true, - .nested_type = false, - .enum_type = false, - .extension_range = true, - .extension = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[29]), /* "EnumValueOptions" */ - .field = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FieldDescriptorProto_arrays[13]), - .nested_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .enum_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension_range = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_DescriptorProto_ExtensionRange_arrays[4]), - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .field = true, - .nested_type = false, - .enum_type = false, - .extension_range = true, - .extension = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[48]), /* "ServiceOptions" */ - .field = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FieldDescriptorProto_arrays[14]), - .nested_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .enum_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension_range = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_DescriptorProto_ExtensionRange_arrays[5]), - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .field = true, - .nested_type = false, - .enum_type = false, - .extension_range = true, - .extension = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[42]), /* "MethodOptions" */ - .field = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FieldDescriptorProto_arrays[15]), - .nested_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .enum_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension_range = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_DescriptorProto_ExtensionRange_arrays[6]), - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .field = true, - .nested_type = true, - .enum_type = false, - .extension_range = false, - .extension = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[68]), /* "UninterpretedOption" */ - .field = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FieldDescriptorProto_arrays[16]), - .nested_type = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_DescriptorProto_arrays[2]), - .enum_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension_range = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .field = true, - .nested_type = false, - .enum_type = false, - .extension_range = false, - .extension = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[30]), /* "ExtensionRange" */ - .field = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FieldDescriptorProto_arrays[3]), - .nested_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .enum_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension_range = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .field = true, - .nested_type = false, - .enum_type = false, - .extension_range = false, - .extension = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[43]), /* "NamePart" */ - .field = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FieldDescriptorProto_arrays[17]), - .nested_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .enum_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension_range = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = 0, /* Not set. */ - }, -}; -static google_protobuf_FileDescriptorProto google_protobuf_FileDescriptorProto_values[1] = { - - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .package = true, - .dependency = false, - .message_type = true, - .enum_type = false, - .service = false, - .extension = false, - .options = true, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[74]), /* "descriptor/descriptor.proto" */ - .package = UPB_STATIC_STRING_PTR_INIT(strings[85]), /* "google.protobuf" */ - .dependency = UPB_ARRAY_NULL_INITIALIZER, /* Not set. */ - .message_type = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_DescriptorProto_arrays[0]), - .enum_type = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .service = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .extension = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - .options = &google_protobuf_FileOptions_values[0], - }, -}; -static google_protobuf_FileDescriptorSet google_protobuf_FileDescriptorSet_values[1] = { - - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .file = true, - }}, - .file = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_FileDescriptorProto_arrays[0]), - }, -}; -static google_protobuf_DescriptorProto_ExtensionRange google_protobuf_DescriptorProto_ExtensionRange_values[7] = { - - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .start = true, - .end = true, - }}, - .start = 1000, - .end = 536870912, - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .start = true, - .end = true, - }}, - .start = 1000, - .end = 536870912, - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .start = true, - .end = true, - }}, - .start = 1000, - .end = 536870912, - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .start = true, - .end = true, - }}, - .start = 1000, - .end = 536870912, - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .start = true, - .end = true, - }}, - .start = 1000, - .end = 536870912, - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .start = true, - .end = true, - }}, - .start = 1000, - .end = 536870912, - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .start = true, - .end = true, - }}, - .start = 1000, - .end = 536870912, - }, -}; -static google_protobuf_FileOptions google_protobuf_FileOptions_values[1] = { - - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .java_package = true, - .java_outer_classname = true, - .optimize_for = true, - .java_multiple_files = false, - .uninterpreted_option = false, - }}, - .java_package = UPB_STATIC_STRING_PTR_INIT(strings[69]), /* "com.google.protobuf" */ - .java_outer_classname = UPB_STATIC_STRING_PTR_INIT(strings[25]), /* "DescriptorProtos" */ - .optimize_for = 1, - .java_multiple_files = 0, /* Not set. */ - .uninterpreted_option = {UPB_ARRAY_NULL_INITIALIZER}, /* Not set. */ - }, -}; -static google_protobuf_EnumDescriptorProto google_protobuf_EnumDescriptorProto_values[4] = { - - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .value = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[67]), /* "Type" */ - .value = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_EnumValueDescriptorProto_arrays[0]), - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .value = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[39]), /* "Label" */ - .value = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_EnumValueDescriptorProto_arrays[1]), - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .value = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[44]), /* "OptimizeMode" */ - .value = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_EnumValueDescriptorProto_arrays[2]), - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .value = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[23]), /* "CType" */ - .value = UPB_STATIC_ARRAY_PTR_TYPED_INIT(google_protobuf_EnumValueDescriptorProto_arrays[3]), - .options = 0, /* Not set. */ - }, -}; -static google_protobuf_FieldDescriptorProto google_protobuf_FieldDescriptorProto_values[63] = { - - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[84]), /* "file" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 1, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[11]), /* ".google.protobuf.FileDescriptorProto" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[96]), /* "name" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 1, - .label = 1, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[104]), /* "package" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 2, - .label = 1, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[72]), /* "dependency" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 3, - .label = 3, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[94]), /* "message_type" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 4, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[0]), /* ".google.protobuf.DescriptorProto" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[77]), /* "enum_type" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 5, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[2]), /* ".google.protobuf.EnumDescriptorProto" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[107]), /* "service" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 6, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[17]), /* ".google.protobuf.ServiceDescriptorProto" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[80]), /* "extension" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 7, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[6]), /* ".google.protobuf.FieldDescriptorProto" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[102]), /* "options" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 8, - .label = 1, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[12]), /* ".google.protobuf.FileOptions" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[96]), /* "name" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 1, - .label = 1, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[83]), /* "field" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 2, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[6]), /* ".google.protobuf.FieldDescriptorProto" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[99]), /* "nested_type" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 3, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[0]), /* ".google.protobuf.DescriptorProto" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[77]), /* "enum_type" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 4, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[2]), /* ".google.protobuf.EnumDescriptorProto" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[81]), /* "extension_range" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 5, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[1]), /* ".google.protobuf.DescriptorProto.ExtensionRange" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[80]), /* "extension" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 6, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[6]), /* ".google.protobuf.FieldDescriptorProto" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[102]), /* "options" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 7, - .label = 1, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[14]), /* ".google.protobuf.MessageOptions" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[108]), /* "start" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 1, - .label = 1, - .type = 5, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[76]), /* "end" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 2, - .label = 1, - .type = 5, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[96]), /* "name" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 1, - .label = 1, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[79]), /* "extendee" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 2, - .label = 1, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[100]), /* "number" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 3, - .label = 1, - .type = 5, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[92]), /* "label" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 4, - .label = 1, - .type = 14, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[7]), /* ".google.protobuf.FieldDescriptorProto.Label" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[110]), /* "type" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 5, - .label = 1, - .type = 14, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[8]), /* ".google.protobuf.FieldDescriptorProto.Type" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[111]), /* "type_name" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 6, - .label = 1, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[71]), /* "default_value" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 7, - .label = 1, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[102]), /* "options" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 8, - .label = 1, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[9]), /* ".google.protobuf.FieldOptions" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[96]), /* "name" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 1, - .label = 1, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[113]), /* "value" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 2, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[4]), /* ".google.protobuf.EnumValueDescriptorProto" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[102]), /* "options" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 3, - .label = 1, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[3]), /* ".google.protobuf.EnumOptions" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[96]), /* "name" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 1, - .label = 1, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[100]), /* "number" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 2, - .label = 1, - .type = 5, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[102]), /* "options" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 3, - .label = 1, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[5]), /* ".google.protobuf.EnumValueOptions" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[96]), /* "name" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 1, - .label = 1, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[95]), /* "method" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 2, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[15]), /* ".google.protobuf.MethodDescriptorProto" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[102]), /* "options" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 3, - .label = 1, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[18]), /* ".google.protobuf.ServiceOptions" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[96]), /* "name" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 1, - .label = 1, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[87]), /* "input_type" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 2, - .label = 1, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[103]), /* "output_type" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 3, - .label = 1, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[102]), /* "options" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 4, - .label = 1, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[16]), /* ".google.protobuf.MethodOptions" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[91]), /* "java_package" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 1, - .label = 1, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[90]), /* "java_outer_classname" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 8, - .label = 1, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[101]), /* "optimize_for" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 9, - .label = 1, - .type = 14, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[13]), /* ".google.protobuf.FileOptions.OptimizeMode" */ - .default_value = UPB_STATIC_STRING_PTR_INIT(strings[45]), /* "SPEED" */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[89]), /* "java_multiple_files" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 10, - .label = 1, - .type = 8, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STATIC_STRING_PTR_INIT(strings[82]), /* "false" */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[112]), /* "uninterpreted_option" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 999, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[19]), /* ".google.protobuf.UninterpretedOption" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[93]), /* "message_set_wire_format" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 1, - .label = 1, - .type = 8, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STATIC_STRING_PTR_INIT(strings[82]), /* "false" */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[112]), /* "uninterpreted_option" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 999, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[19]), /* ".google.protobuf.UninterpretedOption" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[70]), /* "ctype" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 1, - .label = 1, - .type = 14, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[10]), /* ".google.protobuf.FieldOptions.CType" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[105]), /* "packed" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 2, - .label = 1, - .type = 8, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[73]), /* "deprecated" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 3, - .label = 1, - .type = 8, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STATIC_STRING_PTR_INIT(strings[82]), /* "false" */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[78]), /* "experimental_map_key" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 9, - .label = 1, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[112]), /* "uninterpreted_option" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 999, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[19]), /* ".google.protobuf.UninterpretedOption" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[112]), /* "uninterpreted_option" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 999, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[19]), /* ".google.protobuf.UninterpretedOption" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[112]), /* "uninterpreted_option" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 999, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[19]), /* ".google.protobuf.UninterpretedOption" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[112]), /* "uninterpreted_option" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 999, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[19]), /* ".google.protobuf.UninterpretedOption" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[112]), /* "uninterpreted_option" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 999, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[19]), /* ".google.protobuf.UninterpretedOption" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = true, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[96]), /* "name" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 2, - .label = 3, - .type = 11, - .type_name = UPB_STATIC_STRING_PTR_INIT(strings[20]), /* ".google.protobuf.UninterpretedOption.NamePart" */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[86]), /* "identifier_value" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 3, - .label = 1, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[106]), /* "positive_int_value" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 4, - .label = 1, - .type = 4, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[98]), /* "negative_int_value" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 5, - .label = 1, - .type = 3, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[75]), /* "double_value" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 6, - .label = 1, - .type = 1, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[109]), /* "string_value" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 7, - .label = 1, - .type = 12, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[97]), /* "name_part" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 1, - .label = 2, - .type = 9, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .extendee = false, - .number = true, - .label = true, - .type = true, - .type_name = false, - .default_value = false, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[88]), /* "is_extension" */ - .extendee = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .number = 2, - .label = 2, - .type = 8, - .type_name = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .default_value = UPB_STRING_NULL_INITIALIZER, /* Not set. */ - .options = 0, /* Not set. */ - }, -}; -static google_protobuf_EnumValueDescriptorProto google_protobuf_EnumValueDescriptorProto_values[25] = { - - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[51]), /* "TYPE_DOUBLE" */ - .number = 1, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[55]), /* "TYPE_FLOAT" */ - .number = 2, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[58]), /* "TYPE_INT64" */ - .number = 3, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[66]), /* "TYPE_UINT64" */ - .number = 4, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[57]), /* "TYPE_INT32" */ - .number = 5, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[54]), /* "TYPE_FIXED64" */ - .number = 6, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[53]), /* "TYPE_FIXED32" */ - .number = 7, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[49]), /* "TYPE_BOOL" */ - .number = 8, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[64]), /* "TYPE_STRING" */ - .number = 9, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[56]), /* "TYPE_GROUP" */ - .number = 10, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[59]), /* "TYPE_MESSAGE" */ - .number = 11, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[50]), /* "TYPE_BYTES" */ - .number = 12, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[65]), /* "TYPE_UINT32" */ - .number = 13, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[52]), /* "TYPE_ENUM" */ - .number = 14, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[60]), /* "TYPE_SFIXED32" */ - .number = 15, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[61]), /* "TYPE_SFIXED64" */ - .number = 16, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[62]), /* "TYPE_SINT32" */ - .number = 17, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[63]), /* "TYPE_SINT64" */ - .number = 18, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[36]), /* "LABEL_OPTIONAL" */ - .number = 1, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[38]), /* "LABEL_REQUIRED" */ - .number = 2, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[37]), /* "LABEL_REPEATED" */ - .number = 3, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[45]), /* "SPEED" */ - .number = 1, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[21]), /* "CODE_SIZE" */ - .number = 2, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[22]), /* "CORD" */ - .number = 1, - .options = 0, /* Not set. */ - }, - {.base = {UPB_DATA_FROZEN}, - .set_flags = {.has = { - .name = true, - .number = true, - .options = false, - }}, - .name = UPB_STATIC_STRING_PTR_INIT(strings[46]), /* "STRING_PIECE" */ - .number = 2, - .options = 0, /* Not set. */ - }, +static unsigned char descriptor_pb[] = { + 0x0a, 0x9b, 0x1b, 0x0a, 0x1b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x6f, 0x72, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x22, 0x47, 0x0a, 0x11, 0x46, 0x69, 0x6c, 0x65, 0x44, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x53, 0x65, 0x74, 0x12, 0x32, + 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0xdc, 0x02, 0x0a, 0x13, 0x46, 0x69, 0x6c, 0x65, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x0c, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x12, 0x0f, 0x0a, 0x07, 0x70, 0x61, 0x63, 0x6b, + 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x12, 0x12, 0x0a, + 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x09, 0x12, 0x36, 0x0a, 0x0c, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x37, 0x0a, 0x09, 0x65, 0x6e, 0x75, 0x6d, 0x5f, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x44, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x38, + 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x06, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x38, 0x0a, 0x09, + 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, + 0x65, 0x6c, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, + 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x2d, 0x0a, 0x07, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xa9, 0x03, 0x0a, 0x0f, 0x44, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x0c, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x12, 0x34, 0x0a, 0x05, 0x66, 0x69, 0x65, 0x6c, 0x64, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x38, 0x0a, + 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, + 0x69, 0x65, 0x6c, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x35, 0x0a, 0x0b, 0x6e, + 0x65, 0x73, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x37, 0x0a, 0x09, 0x65, 0x6e, 0x75, 0x6d, 0x5f, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x44, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x48, 0x0a, 0x0f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, + 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x45, + 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x61, 0x6e, 0x67, + 0x65, 0x12, 0x30, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x1a, 0x2c, 0x0a, 0x0e, 0x45, 0x78, 0x74, 0x65, 0x6e, + 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x0d, 0x0a, + 0x05, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, + 0x12, 0x0b, 0x0a, 0x03, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x05, 0x22, 0x94, 0x05, 0x0a, 0x14, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x0c, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x12, 0x0e, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, + 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x12, 0x3a, 0x0a, 0x05, + 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x2b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0x38, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x44, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x11, 0x0a, 0x09, 0x74, 0x79, + 0x70, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x12, 0x10, 0x0a, 0x08, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x12, 0x15, 0x0a, 0x0d, 0x64, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x12, 0x2e, 0x0a, 0x07, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xb6, 0x02, 0x0a, 0x04, 0x54, + 0x79, 0x70, 0x65, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x59, 0x50, 0x45, 0x5f, + 0x44, 0x4f, 0x55, 0x42, 0x4c, 0x45, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x4c, 0x4f, 0x41, 0x54, 0x10, 0x02, + 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x54, + 0x36, 0x34, 0x10, 0x03, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x55, 0x49, 0x4e, 0x54, 0x36, 0x34, 0x10, 0x04, 0x12, 0x0e, 0x0a, + 0x0a, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x54, 0x33, 0x32, 0x10, + 0x05, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x46, 0x49, + 0x58, 0x45, 0x44, 0x36, 0x34, 0x10, 0x06, 0x12, 0x10, 0x0a, 0x0c, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x46, 0x49, 0x58, 0x45, 0x44, 0x33, 0x32, 0x10, + 0x07, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x42, 0x4f, + 0x4f, 0x4c, 0x10, 0x08, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x10, 0x09, 0x12, 0x0e, 0x0a, + 0x0a, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x47, 0x52, 0x4f, 0x55, 0x50, 0x10, + 0x0a, 0x12, 0x10, 0x0a, 0x0c, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4d, 0x45, + 0x53, 0x53, 0x41, 0x47, 0x45, 0x10, 0x0b, 0x12, 0x0e, 0x0a, 0x0a, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x42, 0x59, 0x54, 0x45, 0x53, 0x10, 0x0c, 0x12, + 0x0f, 0x0a, 0x0b, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x49, 0x4e, 0x54, + 0x33, 0x32, 0x10, 0x0d, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x45, 0x4e, 0x55, 0x4d, 0x10, 0x0e, 0x12, 0x11, 0x0a, 0x0d, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x53, 0x46, 0x49, 0x58, 0x45, 0x44, 0x33, 0x32, + 0x10, 0x0f, 0x12, 0x11, 0x0a, 0x0d, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, + 0x46, 0x49, 0x58, 0x45, 0x44, 0x36, 0x34, 0x10, 0x10, 0x12, 0x0f, 0x0a, + 0x0b, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x49, 0x4e, 0x54, 0x33, 0x32, + 0x10, 0x11, 0x12, 0x0f, 0x0a, 0x0b, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, + 0x49, 0x4e, 0x54, 0x36, 0x34, 0x10, 0x12, 0x22, 0x43, 0x0a, 0x05, 0x4c, + 0x61, 0x62, 0x65, 0x6c, 0x12, 0x12, 0x0a, 0x0e, 0x4c, 0x41, 0x42, 0x45, + 0x4c, 0x5f, 0x4f, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x41, 0x4c, 0x10, 0x01, + 0x12, 0x12, 0x0a, 0x0e, 0x4c, 0x41, 0x42, 0x45, 0x4c, 0x5f, 0x52, 0x45, + 0x51, 0x55, 0x49, 0x52, 0x45, 0x44, 0x10, 0x02, 0x12, 0x12, 0x0a, 0x0e, + 0x4c, 0x41, 0x42, 0x45, 0x4c, 0x5f, 0x52, 0x45, 0x50, 0x45, 0x41, 0x54, + 0x45, 0x44, 0x10, 0x03, 0x22, 0x8c, 0x01, 0x0a, 0x13, 0x45, 0x6e, 0x75, + 0x6d, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x12, 0x38, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x2d, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x22, 0x6c, 0x0a, 0x18, 0x45, 0x6e, 0x75, 0x6d, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x12, 0x0e, 0x0a, + 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x05, 0x12, 0x32, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x90, 0x01, 0x0a, 0x16, 0x53, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x12, 0x36, + 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, + 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x30, 0x0a, 0x07, 0x6f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1f, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x7f, 0x0a, 0x15, + 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x12, + 0x12, 0x0a, 0x0a, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x74, 0x79, 0x70, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x12, 0x13, 0x0a, 0x0b, 0x6f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x12, 0x2f, 0x0a, 0x07, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xa7, 0x02, 0x0a, 0x0b, 0x46, 0x69, + 0x6c, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x14, 0x0a, + 0x0c, 0x6a, 0x61, 0x76, 0x61, 0x5f, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x12, 0x1c, 0x0a, 0x14, 0x6a, + 0x61, 0x76, 0x61, 0x5f, 0x6f, 0x75, 0x74, 0x65, 0x72, 0x5f, 0x63, 0x6c, + 0x61, 0x73, 0x73, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x09, 0x12, 0x22, 0x0a, 0x13, 0x6a, 0x61, 0x76, 0x61, 0x5f, 0x6d, 0x75, + 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, 0x73, + 0x65, 0x12, 0x46, 0x0a, 0x0c, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, + 0x65, 0x5f, 0x66, 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x29, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4f, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, + 0x7a, 0x65, 0x4d, 0x6f, 0x64, 0x65, 0x3a, 0x05, 0x53, 0x50, 0x45, 0x45, + 0x44, 0x12, 0x43, 0x0a, 0x14, 0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0xe7, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x55, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, + 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x28, + 0x0a, 0x0c, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x4d, 0x6f, + 0x64, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x50, 0x45, 0x45, 0x44, 0x10, + 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x44, 0x45, 0x5f, 0x53, 0x49, + 0x5a, 0x45, 0x10, 0x02, 0x2a, 0x09, 0x08, 0xe8, 0x07, 0x10, 0x80, 0x80, + 0x80, 0x80, 0x02, 0x22, 0x88, 0x01, 0x0a, 0x0e, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x26, + 0x0a, 0x17, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x65, + 0x74, 0x5f, 0x77, 0x69, 0x72, 0x65, 0x5f, 0x66, 0x6f, 0x72, 0x6d, 0x61, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, + 0x73, 0x65, 0x12, 0x43, 0x0a, 0x14, 0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0xe7, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x55, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, + 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2a, + 0x09, 0x08, 0xe8, 0x07, 0x10, 0x80, 0x80, 0x80, 0x80, 0x02, 0x22, 0x80, + 0x02, 0x0a, 0x0c, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x32, 0x0a, 0x05, 0x63, 0x74, 0x79, 0x70, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x43, 0x54, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x06, 0x70, + 0x61, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x12, + 0x19, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x3a, 0x05, 0x66, 0x61, 0x6c, + 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x14, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, + 0x6d, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x70, 0x5f, 0x6b, + 0x65, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x12, 0x43, 0x0a, 0x14, + 0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, + 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xe7, 0x07, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x6e, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x23, 0x0a, 0x05, 0x43, 0x54, 0x79, + 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x43, 0x4f, 0x52, 0x44, 0x10, 0x01, + 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x52, 0x49, 0x4e, 0x47, 0x5f, 0x50, + 0x49, 0x45, 0x43, 0x45, 0x10, 0x02, 0x2a, 0x09, 0x08, 0xe8, 0x07, 0x10, + 0x80, 0x80, 0x80, 0x80, 0x02, 0x22, 0x5d, 0x0a, 0x0b, 0x45, 0x6e, 0x75, + 0x6d, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x43, 0x0a, 0x14, + 0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, + 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0xe7, 0x07, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x6e, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2a, 0x09, 0x08, 0xe8, 0x07, 0x10, 0x80, + 0x80, 0x80, 0x80, 0x02, 0x22, 0x62, 0x0a, 0x10, 0x45, 0x6e, 0x75, 0x6d, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x43, 0x0a, 0x14, 0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, + 0x72, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0xe7, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x55, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, + 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2a, 0x09, 0x08, + 0xe8, 0x07, 0x10, 0x80, 0x80, 0x80, 0x80, 0x02, 0x22, 0x60, 0x0a, 0x0e, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4f, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x12, 0x43, 0x0a, 0x14, 0x75, 0x6e, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0xe7, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x55, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, + 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2a, + 0x09, 0x08, 0xe8, 0x07, 0x10, 0x80, 0x80, 0x80, 0x80, 0x02, 0x22, 0x5f, + 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4f, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x43, 0x0a, 0x14, 0x75, 0x6e, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x5f, 0x6f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0xe7, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x2a, 0x09, 0x08, 0xe8, 0x07, 0x10, 0x80, 0x80, 0x80, 0x80, 0x02, 0x22, + 0x85, 0x02, 0x0a, 0x13, 0x55, 0x6e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x70, + 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x3b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x55, 0x6e, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x70, 0x72, 0x65, 0x74, 0x65, 0x64, 0x4f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x50, 0x61, 0x72, 0x74, + 0x12, 0x18, 0x0a, 0x10, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x12, 0x1a, 0x0a, 0x12, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, + 0x76, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x12, 0x1a, 0x0a, 0x12, 0x6e, 0x65, + 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x69, 0x6e, 0x74, 0x5f, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x12, 0x14, + 0x0a, 0x0c, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x01, 0x12, 0x14, 0x0a, 0x0c, + 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x1a, 0x33, 0x0a, 0x08, 0x4e, 0x61, + 0x6d, 0x65, 0x50, 0x61, 0x72, 0x74, 0x12, 0x11, 0x0a, 0x09, 0x6e, 0x61, + 0x6d, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x18, 0x01, 0x20, 0x02, 0x28, + 0x09, 0x12, 0x14, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x65, 0x78, 0x74, 0x65, + 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x02, 0x28, 0x08, 0x42, + 0x29, 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x42, 0x10, + 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x50, 0x72, + 0x6f, 0x74, 0x6f, 0x73, 0x48, 0x01 }; -/* The externally-visible definition. */ -google_protobuf_FileDescriptorSet *upb_file_descriptor_set = &google_protobuf_FileDescriptorSet_values[0]; +static const unsigned int descriptor_pb_len = 3486; +upb_string descriptor_str = UPB_STATIC_STRING(descriptor_pb); diff --git a/descriptor/descriptor.h b/descriptor/descriptor.h index 8c59624..f6d3ca3 100644 --- a/descriptor/descriptor.h +++ b/descriptor/descriptor.h @@ -1,402 +1,26 @@ -/* This file was generated by upbc (the upb compiler). Do not edit. */ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. + * + * This file contains declarations for an array that contains the contents + * of descriptor.proto, serialized as a protobuf. xxd is used to create + * the actual definition. + */ -#ifndef DESCRIPTOR_DESCRIPTOR_H -#define DESCRIPTOR_DESCRIPTOR_H +#ifndef UPB_DESCRIPTOR_H_ +#define UPB_DESCRIPTOR_H_ -#include <upb_data.h> +#include "upb_string.h" #ifdef __cplusplus extern "C" { #endif -struct google_protobuf_FileDescriptorSet; -extern struct google_protobuf_FileDescriptorSet *upb_file_descriptor_set; - -/* Forward declarations of all message types. - * So they can refer to each other in possibly-recursive ways. */ - -struct google_protobuf_UninterpretedOption_NamePart; -typedef struct google_protobuf_UninterpretedOption_NamePart - google_protobuf_UninterpretedOption_NamePart; -UPB_DEFINE_MSG_ARRAY(google_protobuf_UninterpretedOption_NamePart) - -struct google_protobuf_DescriptorProto; -typedef struct google_protobuf_DescriptorProto - google_protobuf_DescriptorProto; -UPB_DEFINE_MSG_ARRAY(google_protobuf_DescriptorProto) - -struct google_protobuf_EnumDescriptorProto; -typedef struct google_protobuf_EnumDescriptorProto - google_protobuf_EnumDescriptorProto; -UPB_DEFINE_MSG_ARRAY(google_protobuf_EnumDescriptorProto) - -struct google_protobuf_UninterpretedOption; -typedef struct google_protobuf_UninterpretedOption - google_protobuf_UninterpretedOption; -UPB_DEFINE_MSG_ARRAY(google_protobuf_UninterpretedOption) - -struct google_protobuf_FileDescriptorProto; -typedef struct google_protobuf_FileDescriptorProto - google_protobuf_FileDescriptorProto; -UPB_DEFINE_MSG_ARRAY(google_protobuf_FileDescriptorProto) - -struct google_protobuf_MethodDescriptorProto; -typedef struct google_protobuf_MethodDescriptorProto - google_protobuf_MethodDescriptorProto; -UPB_DEFINE_MSG_ARRAY(google_protobuf_MethodDescriptorProto) - -struct google_protobuf_EnumValueOptions; -typedef struct google_protobuf_EnumValueOptions - google_protobuf_EnumValueOptions; -UPB_DEFINE_MSG_ARRAY(google_protobuf_EnumValueOptions) - -struct google_protobuf_EnumValueDescriptorProto; -typedef struct google_protobuf_EnumValueDescriptorProto - google_protobuf_EnumValueDescriptorProto; -UPB_DEFINE_MSG_ARRAY(google_protobuf_EnumValueDescriptorProto) - -struct google_protobuf_ServiceDescriptorProto; -typedef struct google_protobuf_ServiceDescriptorProto - google_protobuf_ServiceDescriptorProto; -UPB_DEFINE_MSG_ARRAY(google_protobuf_ServiceDescriptorProto) - -struct google_protobuf_FileDescriptorSet; -typedef struct google_protobuf_FileDescriptorSet - google_protobuf_FileDescriptorSet; -UPB_DEFINE_MSG_ARRAY(google_protobuf_FileDescriptorSet) - -struct google_protobuf_DescriptorProto_ExtensionRange; -typedef struct google_protobuf_DescriptorProto_ExtensionRange - google_protobuf_DescriptorProto_ExtensionRange; -UPB_DEFINE_MSG_ARRAY(google_protobuf_DescriptorProto_ExtensionRange) - -struct google_protobuf_FieldOptions; -typedef struct google_protobuf_FieldOptions - google_protobuf_FieldOptions; -UPB_DEFINE_MSG_ARRAY(google_protobuf_FieldOptions) - -struct google_protobuf_FileOptions; -typedef struct google_protobuf_FileOptions - google_protobuf_FileOptions; -UPB_DEFINE_MSG_ARRAY(google_protobuf_FileOptions) - -struct google_protobuf_MessageOptions; -typedef struct google_protobuf_MessageOptions - google_protobuf_MessageOptions; -UPB_DEFINE_MSG_ARRAY(google_protobuf_MessageOptions) - -struct google_protobuf_EnumOptions; -typedef struct google_protobuf_EnumOptions - google_protobuf_EnumOptions; -UPB_DEFINE_MSG_ARRAY(google_protobuf_EnumOptions) - -struct google_protobuf_FieldDescriptorProto; -typedef struct google_protobuf_FieldDescriptorProto - google_protobuf_FieldDescriptorProto; -UPB_DEFINE_MSG_ARRAY(google_protobuf_FieldDescriptorProto) - -struct google_protobuf_ServiceOptions; -typedef struct google_protobuf_ServiceOptions - google_protobuf_ServiceOptions; -UPB_DEFINE_MSG_ARRAY(google_protobuf_ServiceOptions) - -struct google_protobuf_MethodOptions; -typedef struct google_protobuf_MethodOptions - google_protobuf_MethodOptions; -UPB_DEFINE_MSG_ARRAY(google_protobuf_MethodOptions) - -/* The message definitions themselves. */ - -struct google_protobuf_UninterpretedOption_NamePart { - upb_data base; - union { - uint8_t bytes[1]; - struct { - bool name_part:1; /* = 1, required. */ - bool is_extension:1; /* = 2, required. */ - } has; - } set_flags; - upb_strptr name_part; - bool is_extension; -}; - -struct google_protobuf_DescriptorProto { - upb_data base; - union { - uint8_t bytes[1]; - struct { - bool name:1; /* = 1, optional. */ - bool field:1; /* = 2, repeated. */ - bool nested_type:1; /* = 3, repeated. */ - bool enum_type:1; /* = 4, repeated. */ - bool extension_range:1; /* = 5, repeated. */ - bool extension:1; /* = 6, repeated. */ - bool options:1; /* = 7, optional. */ - } has; - } set_flags; - upb_strptr name; - UPB_MSG_ARRAYPTR(google_protobuf_FieldDescriptorProto) field; - UPB_MSG_ARRAYPTR(google_protobuf_DescriptorProto) nested_type; - UPB_MSG_ARRAYPTR(google_protobuf_EnumDescriptorProto) enum_type; - UPB_MSG_ARRAYPTR(google_protobuf_DescriptorProto_ExtensionRange) extension_range; - UPB_MSG_ARRAYPTR(google_protobuf_FieldDescriptorProto) extension; - google_protobuf_MessageOptions* options; -}; - -struct google_protobuf_EnumDescriptorProto { - upb_data base; - union { - uint8_t bytes[1]; - struct { - bool name:1; /* = 1, optional. */ - bool value:1; /* = 2, repeated. */ - bool options:1; /* = 3, optional. */ - } has; - } set_flags; - upb_strptr name; - UPB_MSG_ARRAYPTR(google_protobuf_EnumValueDescriptorProto) value; - google_protobuf_EnumOptions* options; -}; - -struct google_protobuf_UninterpretedOption { - upb_data base; - union { - uint8_t bytes[1]; - struct { - bool name:1; /* = 2, repeated. */ - bool identifier_value:1; /* = 3, optional. */ - bool positive_int_value:1; /* = 4, optional. */ - bool negative_int_value:1; /* = 5, optional. */ - bool double_value:1; /* = 6, optional. */ - bool string_value:1; /* = 7, optional. */ - } has; - } set_flags; - UPB_MSG_ARRAYPTR(google_protobuf_UninterpretedOption_NamePart) name; - upb_strptr identifier_value; - uint64_t positive_int_value; - int64_t negative_int_value; - double double_value; - upb_strptr string_value; -}; - -struct google_protobuf_FileDescriptorProto { - upb_data base; - union { - uint8_t bytes[1]; - struct { - bool name:1; /* = 1, optional. */ - bool package:1; /* = 2, optional. */ - bool dependency:1; /* = 3, repeated. */ - bool message_type:1; /* = 4, repeated. */ - bool enum_type:1; /* = 5, repeated. */ - bool service:1; /* = 6, repeated. */ - bool extension:1; /* = 7, repeated. */ - bool options:1; /* = 8, optional. */ - } has; - } set_flags; - upb_strptr name; - upb_strptr package; - upb_arrayptr dependency; - UPB_MSG_ARRAYPTR(google_protobuf_DescriptorProto) message_type; - UPB_MSG_ARRAYPTR(google_protobuf_EnumDescriptorProto) enum_type; - UPB_MSG_ARRAYPTR(google_protobuf_ServiceDescriptorProto) service; - UPB_MSG_ARRAYPTR(google_protobuf_FieldDescriptorProto) extension; - google_protobuf_FileOptions* options; -}; - -struct google_protobuf_MethodDescriptorProto { - upb_data base; - union { - uint8_t bytes[1]; - struct { - bool name:1; /* = 1, optional. */ - bool input_type:1; /* = 2, optional. */ - bool output_type:1; /* = 3, optional. */ - bool options:1; /* = 4, optional. */ - } has; - } set_flags; - upb_strptr name; - upb_strptr input_type; - upb_strptr output_type; - google_protobuf_MethodOptions* options; -}; - -struct google_protobuf_EnumValueOptions { - upb_data base; - union { - uint8_t bytes[1]; - struct { - bool uninterpreted_option:1; /* = 999, repeated. */ - } has; - } set_flags; - UPB_MSG_ARRAYPTR(google_protobuf_UninterpretedOption) uninterpreted_option; -}; - -struct google_protobuf_EnumValueDescriptorProto { - upb_data base; - union { - uint8_t bytes[1]; - struct { - bool name:1; /* = 1, optional. */ - bool number:1; /* = 2, optional. */ - bool options:1; /* = 3, optional. */ - } has; - } set_flags; - upb_strptr name; - int32_t number; - google_protobuf_EnumValueOptions* options; -}; - -struct google_protobuf_ServiceDescriptorProto { - upb_data base; - union { - uint8_t bytes[1]; - struct { - bool name:1; /* = 1, optional. */ - bool method:1; /* = 2, repeated. */ - bool options:1; /* = 3, optional. */ - } has; - } set_flags; - upb_strptr name; - UPB_MSG_ARRAYPTR(google_protobuf_MethodDescriptorProto) method; - google_protobuf_ServiceOptions* options; -}; - -struct google_protobuf_FileDescriptorSet { - upb_data base; - union { - uint8_t bytes[1]; - struct { - bool file:1; /* = 1, repeated. */ - } has; - } set_flags; - UPB_MSG_ARRAYPTR(google_protobuf_FileDescriptorProto) file; -}; - -struct google_protobuf_DescriptorProto_ExtensionRange { - upb_data base; - union { - uint8_t bytes[1]; - struct { - bool start:1; /* = 1, optional. */ - bool end:1; /* = 2, optional. */ - } has; - } set_flags; - int32_t start; - int32_t end; -}; - -struct google_protobuf_FieldOptions { - upb_data base; - union { - uint8_t bytes[1]; - struct { - bool ctype:1; /* = 1, optional. */ - bool packed:1; /* = 2, optional. */ - bool deprecated:1; /* = 3, optional. */ - bool experimental_map_key:1; /* = 9, optional. */ - bool uninterpreted_option:1; /* = 999, repeated. */ - } has; - } set_flags; - int32_t ctype; - bool packed; - bool deprecated; - upb_strptr experimental_map_key; - UPB_MSG_ARRAYPTR(google_protobuf_UninterpretedOption) uninterpreted_option; -}; - -struct google_protobuf_FileOptions { - upb_data base; - union { - uint8_t bytes[1]; - struct { - bool java_package:1; /* = 1, optional. */ - bool java_outer_classname:1; /* = 8, optional. */ - bool optimize_for:1; /* = 9, optional. */ - bool java_multiple_files:1; /* = 10, optional. */ - bool uninterpreted_option:1; /* = 999, repeated. */ - } has; - } set_flags; - upb_strptr java_package; - upb_strptr java_outer_classname; - int32_t optimize_for; - bool java_multiple_files; - UPB_MSG_ARRAYPTR(google_protobuf_UninterpretedOption) uninterpreted_option; -}; - -struct google_protobuf_MessageOptions { - upb_data base; - union { - uint8_t bytes[1]; - struct { - bool message_set_wire_format:1; /* = 1, optional. */ - bool uninterpreted_option:1; /* = 999, repeated. */ - } has; - } set_flags; - bool message_set_wire_format; - UPB_MSG_ARRAYPTR(google_protobuf_UninterpretedOption) uninterpreted_option; -}; - -struct google_protobuf_EnumOptions { - upb_data base; - union { - uint8_t bytes[1]; - struct { - bool uninterpreted_option:1; /* = 999, repeated. */ - } has; - } set_flags; - UPB_MSG_ARRAYPTR(google_protobuf_UninterpretedOption) uninterpreted_option; -}; - -struct google_protobuf_FieldDescriptorProto { - upb_data base; - union { - uint8_t bytes[1]; - struct { - bool name:1; /* = 1, optional. */ - bool extendee:1; /* = 2, optional. */ - bool number:1; /* = 3, optional. */ - bool label:1; /* = 4, optional. */ - bool type:1; /* = 5, optional. */ - bool type_name:1; /* = 6, optional. */ - bool default_value:1; /* = 7, optional. */ - bool options:1; /* = 8, optional. */ - } has; - } set_flags; - upb_strptr name; - upb_strptr extendee; - int32_t number; - int32_t label; - int32_t type; - upb_strptr type_name; - upb_strptr default_value; - google_protobuf_FieldOptions* options; -}; - -struct google_protobuf_ServiceOptions { - upb_data base; - union { - uint8_t bytes[1]; - struct { - bool uninterpreted_option:1; /* = 999, repeated. */ - } has; - } set_flags; - UPB_MSG_ARRAYPTR(google_protobuf_UninterpretedOption) uninterpreted_option; -}; - -struct google_protobuf_MethodOptions { - upb_data base; - union { - uint8_t bytes[1]; - struct { - bool uninterpreted_option:1; /* = 999, repeated. */ - } has; - } set_flags; - UPB_MSG_ARRAYPTR(google_protobuf_UninterpretedOption) uninterpreted_option; -}; +extern upb_string descriptor_str; #ifdef __cplusplus } /* extern "C" */ #endif -#endif /* DESCRIPTOR_DESCRIPTOR_H */ +#endif /* UPB_DESCRIPTOR_H_ */ diff --git a/gen-deps.sh b/gen-deps.sh index 6c0ced3..2bc82f8 100755 --- a/gen-deps.sh +++ b/gen-deps.sh @@ -14,5 +14,5 @@ set -e rm -f deps for file in $@; do - gcc -MM $file -MT ${file%.*}.o -DUPB_THREAD_UNSAFE -Idescriptor -Isrc -I. >> deps + gcc -MM $file -MT ${file%.*}.o -DUPB_THREAD_UNSAFE -Idescriptor -Icore -Istream -I. >> deps done diff --git a/lang_ext/lua/upb.c b/lang_ext/lua/upb.c new file mode 100644 index 0000000..5ab07ba --- /dev/null +++ b/lang_ext/lua/upb.c @@ -0,0 +1,336 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. + * + * A Lua extension for upb. + */ + +#include <stdlib.h> +#include "lauxlib.h" +#include "upb_def.h" + +void lupb_pushstring(lua_State *L, upb_string *str) { + lua_pushlstring(L, upb_string_getrobuf(str), upb_string_len(str)); +} + +/* object cache ***************************************************************/ + +// We cache all the lua objects (userdata) we vend in a weak table, indexed by +// the C pointer of the object they are caching. + +typedef void (*lupb_cb)(void *cobj); + +static void lupb_nop(void *foo) { + (void)foo; +} + +static void lupb_cache_getorcreate(lua_State *L, void *cobj, const char *type, + lupb_cb ref, lupb_cb unref) { + // Lookup our cache in the registry (we don't put our objects in the registry + // directly because we need our cache to be a weak table). + lua_getfield(L, LUA_REGISTRYINDEX, "upb.objcache"); + assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb. + lua_pushlightuserdata(L, cobj); + lua_rawget(L, -2); + // Stack: objcache, cached value. + if (lua_isnil(L, -1)) { + // Remove bad cached value and push new value. + lua_pop(L, 1); + // We take advantage of the fact that all of our objects are currently a + // single pointer, and thus have the same layout. + void **obj = lua_newuserdata(L, sizeof(void*)); + *obj = cobj; + luaL_getmetatable(L, type); + assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb. + lua_setmetatable(L, -2); + + // Set it in the cache. + lua_pushlightuserdata(L, cobj); + lua_pushvalue(L, -2); + lua_rawset(L, -4); + ref(cobj); + } else { + unref(cobj); + } + lua_insert(L, -2); + lua_pop(L, 1); +} + + +/* lupb_def *******************************************************************/ + +// All the def types share the same C layout, even though they are different Lua +// types with different metatables. +typedef struct { + upb_def *def; +} lupb_def; + +static void lupb_def_unref(void *cobj) { + upb_def_unref((upb_def*)cobj); +} + +static void lupb_def_getorcreate(lua_State *L, upb_def *def) { + const char *type_name; + switch(def->type) { + case UPB_DEF_MSG: + type_name = "upb.msgdef"; + break; + case UPB_DEF_ENUM: + type_name = "upb.enumdef"; + break; + default: + luaL_error(L, "unknown deftype %d", def->type); + type_name = NULL; // Placate the compiler. + } + return lupb_cache_getorcreate(L, def, type_name, lupb_nop, lupb_def_unref); +} + +// msgdef + +static upb_msgdef *lupb_msgdef_check(lua_State *L, int narg) { + lupb_def *ldef = luaL_checkudata(L, narg, "upb.msgdef"); + return upb_downcast_msgdef(ldef->def); +} + +static int lupb_msgdef_gc(lua_State *L) { + lupb_def *ldef = luaL_checkudata(L, 1, "upb.msgdef"); + upb_def_unref(ldef->def); + return 0; +} + +static void lupb_fielddef_getorcreate(lua_State *L, upb_fielddef *f); + +static int lupb_msgdef_fieldbyname(lua_State *L) { + upb_msgdef *m = lupb_msgdef_check(L, 1); + size_t len; + const char *name = luaL_checklstring(L, 2, &len); + upb_string namestr = UPB_STACK_STRING_LEN(name, len); + upb_fielddef *f = upb_msgdef_ntof(m, &namestr); + if (f) { + lupb_fielddef_getorcreate(L, f); + } else { + lua_pushnil(L); + } + return 1; +} + +static int lupb_msgdef_fieldbynum(lua_State *L) { + upb_msgdef *m = lupb_msgdef_check(L, 1); + int num = luaL_checkint(L, 2); + upb_fielddef *f = upb_msgdef_itof(m, num); + if (f) { + lupb_fielddef_getorcreate(L, f); + } else { + lua_pushnil(L); + } + return 1; +} + +static const struct luaL_Reg lupb_msgdef_mm[] = { + {"__gc", lupb_msgdef_gc}, + {NULL, NULL} +}; + +static const struct luaL_Reg lupb_msgdef_m[] = { + {"fieldbyname", lupb_msgdef_fieldbyname}, + {"fieldbynum", lupb_msgdef_fieldbynum}, + {NULL, NULL} +}; + +// enumdef + +static lupb_def *lupb_enumdef_check(lua_State *L, int narg) { + return luaL_checkudata(L, narg, "upb.enumdef"); +} + +static int lupb_enumdef_gc(lua_State *L) { + lupb_def *ldef = lupb_enumdef_check(L, 1); + upb_def_unref(ldef->def); + return 0; +} + +static const struct luaL_Reg lupb_enumdef_mm[] = { + {"__gc", lupb_enumdef_gc}, + {NULL, NULL} +}; + +static const struct luaL_Reg lupb_enumdef_m[] = { + {NULL, NULL} +}; + + +/* lupb_fielddef **************************************************************/ + +typedef struct { + upb_fielddef *field; +} lupb_fielddef; + +static void lupb_fielddef_ref(void *cobj) { + upb_def_ref(UPB_UPCAST(((upb_fielddef*)cobj)->msgdef)); +} + +static void lupb_fielddef_getorcreate(lua_State *L, upb_fielddef *f) { + lupb_cache_getorcreate(L, f, "upb.fielddef", lupb_fielddef_ref, lupb_nop); +} + +static lupb_fielddef *lupb_fielddef_check(lua_State *L, int narg) { + return luaL_checkudata(L, narg, "upb.fielddef"); +} + +static int lupb_fielddef_index(lua_State *L) { + lupb_fielddef *f = lupb_fielddef_check(L, 1); + const char *str = luaL_checkstring(L, 2); + if (strcmp(str, "name") == 0) { + lupb_pushstring(L, f->field->name); + } else if (strcmp(str, "number") == 0) { + lua_pushinteger(L, f->field->number); + } else if (strcmp(str, "type") == 0) { + lua_pushinteger(L, f->field->type); + } else if (strcmp(str, "label") == 0) { + lua_pushinteger(L, f->field->label); + } else if (strcmp(str, "def") == 0) { + upb_def_ref(f->field->def); + lupb_def_getorcreate(L, f->field->def); + } else if (strcmp(str, "msgdef") == 0) { + upb_def_ref(UPB_UPCAST(f->field->msgdef)); + lupb_def_getorcreate(L, UPB_UPCAST(f->field->msgdef)); + } else { + lua_pushnil(L); + } + return 1; +} + +static int lupb_fielddef_gc(lua_State *L) { + lupb_fielddef *lfielddef = lupb_fielddef_check(L, 1); + upb_def_unref(UPB_UPCAST(lfielddef->field->msgdef)); + return 0; +} + +static const struct luaL_Reg lupb_fielddef_mm[] = { + {"__gc", lupb_fielddef_gc}, + {"__index", lupb_fielddef_index}, + {NULL, NULL} +}; + + +/* lupb_symtab ****************************************************************/ + +typedef struct { + upb_symtab *symtab; +} lupb_symtab; + +// Inherits a ref on the symtab. +// Checks that narg is a proper lupb_symtab object. If it is, leaves its +// metatable on the stack for cache lookups/updates. +lupb_symtab *lupb_symtab_check(lua_State *L, int narg) { + return luaL_checkudata(L, narg, "upb.symtab"); +} + +static int lupb_symtab_gc(lua_State *L) { + lupb_symtab *s = lupb_symtab_check(L, 1); + upb_symtab_unref(s->symtab); + return 0; +} + +static void lupb_symtab_unref(void *cobj) { + upb_symtab_unref((upb_symtab*)cobj); +} + +static int lupb_symtab_lookup(lua_State *L) { + lupb_symtab *s = lupb_symtab_check(L, 1); + size_t len; + const char *name = luaL_checklstring(L, 2, &len); + upb_string namestr = UPB_STACK_STRING_LEN(name, len); + upb_def *def = upb_symtab_lookup(s->symtab, &namestr); + if (def) { + lupb_def_getorcreate(L, def); + } else { + lua_pushnil(L); + } + return 1; +} + +static int lupb_symtab_getdefs(lua_State *L) { + lupb_symtab *s = lupb_symtab_check(L, 1); + upb_deftype_t type = luaL_checkint(L, 2); + int count; + upb_def **defs = upb_symtab_getdefs(s->symtab, &count, type); + + // Create the table in which we will return the defs. + lua_createtable(L, 0, count); + for (int i = 0; i < count; i++) { + upb_def *def = defs[i]; + upb_string *name = def->fqname; + lupb_pushstring(L, name); + lupb_def_getorcreate(L, def); + // Add it to our return table. + lua_settable(L, -3); + } + free(defs); + return 1; +} + +static int lupb_symtab_add_descriptorproto(lua_State *L) { + lupb_symtab *s = lupb_symtab_check(L, 1); + upb_symtab_add_descriptorproto(s->symtab); + return 0; // No args to return. +} + +static const struct luaL_Reg lupb_symtab_m[] = { + {"add_descriptorproto", lupb_symtab_add_descriptorproto}, + //{"addfds", lupb_symtab_addfds}, + {"getdefs", lupb_symtab_getdefs}, + {"lookup", lupb_symtab_lookup}, + //{"resolve", lupb_symtab_resolve}, + {NULL, NULL} +}; + +static const struct luaL_Reg lupb_symtab_mm[] = { + {"__gc", lupb_symtab_gc}, + {NULL, NULL} +}; + + +/* lupb toplevel **************************************************************/ + +static int lupb_symtab_new(lua_State *L) { + upb_symtab *s = upb_symtab_new(); + lupb_cache_getorcreate(L, s, "upb.symtab", lupb_nop, lupb_symtab_unref); + return 1; +} + +static const struct luaL_Reg lupb_toplevel_m[] = { + {"symtab", lupb_symtab_new}, + {NULL, NULL} +}; + +// Register the given type with the given methods and metamethods. +static void lupb_register_type(lua_State *L, const char *name, + const luaL_Reg *m, const luaL_Reg *mm) { + luaL_newmetatable(L, name); + luaL_register(L, NULL, mm); + lua_createtable(L, 0, 0); + if (m) { + luaL_register(L, NULL, m); + lua_setfield(L, -2, "__index"); + } + lua_pop(L, 1); // The mt. +} + +int luaopen_upb(lua_State *L) { + lupb_register_type(L, "upb.msgdef", lupb_msgdef_m, lupb_msgdef_mm); + lupb_register_type(L, "upb.enumdef", lupb_enumdef_m, lupb_enumdef_mm); + lupb_register_type(L, "upb.fielddef", NULL, lupb_fielddef_mm); + lupb_register_type(L, "upb.symtab", lupb_symtab_m, lupb_symtab_mm); + + // Create our object cache. TODO: need to make this table weak! + lua_createtable(L, 0, 0); + lua_createtable(L, 0, 1); // Cache metatable. + lua_pushstring(L, "v"); // Values are weak. + lua_setfield(L, -2, "__mode"); + lua_setfield(L, LUA_REGISTRYINDEX, "upb.objcache"); + + luaL_register(L, "upb", lupb_toplevel_m); + return 1; // Return package table. +} diff --git a/src/upb.c b/src/upb.c deleted file mode 100644 index 146a9a5..0000000 --- a/src/upb.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. - * - */ - -#include <stdarg.h> -#include <stddef.h> - -#include "upb.h" - -#define alignof(t) offsetof(struct { char c; t x; }, x) -#define TYPE_INFO(proto_type, wire_type, ctype) \ - [GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_TYPE_ ## proto_type] = \ - {alignof(ctype), sizeof(ctype), wire_type, #ctype}, - -upb_type_info upb_types[] = { - TYPE_INFO(DOUBLE, UPB_WIRE_TYPE_64BIT, double) - TYPE_INFO(FLOAT, UPB_WIRE_TYPE_32BIT, float) - TYPE_INFO(INT64, UPB_WIRE_TYPE_VARINT, int64_t) - TYPE_INFO(UINT64, UPB_WIRE_TYPE_VARINT, uint64_t) - TYPE_INFO(INT32, UPB_WIRE_TYPE_VARINT, int32_t) - TYPE_INFO(FIXED64, UPB_WIRE_TYPE_64BIT, uint64_t) - TYPE_INFO(FIXED32, UPB_WIRE_TYPE_32BIT, uint32_t) - TYPE_INFO(BOOL, UPB_WIRE_TYPE_VARINT, bool) - TYPE_INFO(MESSAGE, UPB_WIRE_TYPE_DELIMITED, void*) - TYPE_INFO(GROUP, UPB_WIRE_TYPE_START_GROUP, void*) - TYPE_INFO(UINT32, UPB_WIRE_TYPE_VARINT, uint32_t) - TYPE_INFO(ENUM, UPB_WIRE_TYPE_VARINT, uint32_t) - TYPE_INFO(SFIXED32, UPB_WIRE_TYPE_32BIT, int32_t) - TYPE_INFO(SFIXED64, UPB_WIRE_TYPE_64BIT, int64_t) - TYPE_INFO(SINT32, UPB_WIRE_TYPE_VARINT, int32_t) - TYPE_INFO(SINT64, UPB_WIRE_TYPE_VARINT, int64_t) - TYPE_INFO(STRING, UPB_WIRE_TYPE_DELIMITED, upb_strptr) - TYPE_INFO(BYTES, UPB_WIRE_TYPE_DELIMITED, upb_strptr) -}; - -void upb_seterr(upb_status *status, enum upb_status_code code, - const char *msg, ...) -{ - if(upb_ok(status)) { // The first error is the most interesting. - status->code = code; - va_list args; - va_start(args, msg); - vsnprintf(status->msg, UPB_ERRORMSG_MAXLEN, msg, args); - va_end(args); - } -} diff --git a/src/upb_data.c b/src/upb_data.c deleted file mode 100644 index 3b4f7ab..0000000 --- a/src/upb_data.c +++ /dev/null @@ -1,500 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. - */ - -#include <stdlib.h> -#include "upb_data.h" -#include "upb_decoder.h" -#include "upb_def.h" - -static uint32_t round_up_to_pow2(uint32_t v) -{ - /* cf. http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 */ - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v++; - return v; -} - -/* upb_data *******************************************************************/ - -static void data_elem_unref(upb_valueptr p, upb_fielddef *f) { - if(upb_issubmsg(f)) { - upb_msg_unref(*p.msg, upb_downcast_msgdef(f->def)); - } else if(upb_isstring(f)) { - upb_string_unref(*p.str); - } else { - assert(false); - } -} - -static void data_unref(upb_valueptr p, upb_fielddef *f) { - if(upb_isarray(f)) { - upb_array_unref(*p.arr, f); - } else { - data_elem_unref(p, f); - } -} - -INLINE void data_init(upb_data *d, int flags) { - d->v = REFCOUNT_ONE | flags; -} - -static void check_not_frozen(upb_data *d) { - // On one hand I am reluctant to put abort() calls in a low-level library - // that are enabled in a production build. On the other hand, this is a bug - // in the client code that we cannot recover from, and it seems better to get - // the error here than later. - if(upb_data_hasflag(d, UPB_DATA_FROZEN)) abort(); -} - - -/* upb_string *******************************************************************/ - -void _upb_string_setptr(upb_strptr s, char *ptr) { - if(upb_data_hasflag(s.base, UPB_DATA_REFCOUNTED)) - s.refcounted->ptr = ptr; - else - s.norefcount->ptr = ptr; -} - -static void _upb_string_set_bytelen(upb_strptr s, upb_strlen_t newlen) { - if(upb_data_hasflag(s.base, UPB_DATA_REFCOUNTED)) { - s.refcounted->byte_len = newlen; - } else { - s.norefcount->byte_len = newlen; - } -} - -upb_strptr upb_string_new() { - upb_strptr s; - s.refcounted = malloc(sizeof(struct upb_refcounted_string)); - data_init(s.base, UPB_DATA_HEAPALLOCATED | UPB_DATA_REFCOUNTED); - s.refcounted->byte_size = 0; - s.refcounted->byte_len = 0; - s.refcounted->ptr = NULL; - return s; -} - -static upb_strlen_t string_get_bytesize(upb_strptr s) { - if(upb_data_hasflag(s.base, UPB_DATA_REFCOUNTED)) { - return s.refcounted->byte_size; - } else { - return (s.norefcount->byte_size_and_flags & 0xFFFFFFF8) >> 3; - } -} - -static void string_set_bytesize(upb_strptr s, upb_strlen_t newsize) { - if(upb_data_hasflag(s.base, UPB_DATA_REFCOUNTED)) { - s.refcounted->byte_size = newsize; - } else { - s.norefcount->byte_size_and_flags &= 0x7; - s.norefcount->byte_size_and_flags |= (newsize << 3); - } -} - -void _upb_string_free(upb_strptr s) -{ - if(string_get_bytesize(s) != 0) free((void*)upb_string_getrobuf(s)); - free(s.base); -} - -void upb_string_resize(upb_strptr s, upb_strlen_t byte_len) { - check_not_frozen(s.base); - if(string_get_bytesize(s) < byte_len) { - // Need to resize. - size_t new_byte_size = round_up_to_pow2(byte_len); - _upb_string_setptr(s, realloc(_upb_string_getptr(s), new_byte_size)); - string_set_bytesize(s, new_byte_size); - } - _upb_string_set_bytelen(s, byte_len); -} - -upb_strptr upb_string_getref(upb_strptr s, int ref_flags) { - if(_upb_data_incref(s.base, ref_flags)) return s; - upb_strptr copy = upb_strdup(s); - if(ref_flags == UPB_REF_FROZEN) - upb_data_setflag(copy.base, UPB_DATA_FROZEN); - return copy; -} - -upb_strptr upb_strreadfile(const char *filename) { - FILE *f = fopen(filename, "rb"); - if(!f) return UPB_STRING_NULL; - if(fseek(f, 0, SEEK_END) != 0) goto error; - long size = ftell(f); - if(size < 0) goto error; - if(fseek(f, 0, SEEK_SET) != 0) goto error; - upb_strptr s = upb_string_new(); - char *buf = upb_string_getrwbuf(s, size); - if(fread(buf, size, 1, f) != 1) goto error; - fclose(f); - return s; - -error: - fclose(f); - return UPB_STRING_NULL; -} - -upb_strptr upb_strdupc(const char *src) { - upb_strptr copy = upb_string_new(); - upb_strlen_t len = strlen(src); - char *buf = upb_string_getrwbuf(copy, len); - memcpy(buf, src, len); - return copy; -} - -void upb_strcat(upb_strptr s, upb_strptr append) { - upb_strlen_t s_len = upb_strlen(s); - upb_strlen_t append_len = upb_strlen(append); - upb_strlen_t newlen = s_len + append_len; - memcpy(upb_string_getrwbuf(s, newlen) + s_len, - upb_string_getrobuf(append), append_len); -} - -upb_strptr upb_strslice(upb_strptr s, int offset, int len) { - upb_strptr slice = upb_string_new(); - len = UPB_MIN((upb_strlen_t)len, upb_strlen(s) - (upb_strlen_t)offset); - memcpy(upb_string_getrwbuf(slice, len), upb_string_getrobuf(s) + offset, len); - return slice; -} - -upb_strptr upb_strdup(upb_strptr s) { - upb_strptr copy = upb_string_new(); - upb_strcpy(copy, s); - return copy; -} - -int upb_strcmp(upb_strptr s1, upb_strptr s2) { - upb_strlen_t common_length = UPB_MIN(upb_strlen(s1), upb_strlen(s2)); - int common_diff = memcmp(upb_string_getrobuf(s1), upb_string_getrobuf(s2), - common_length); - return common_diff == - 0 ? ((int)upb_strlen(s1) - (int)upb_strlen(s2)) : common_diff; -} - - -/* upb_array ******************************************************************/ - -static void _upb_array_setptr(upb_arrayptr a, void *ptr) { - if(upb_data_hasflag(a.base, UPB_DATA_REFCOUNTED)) - a.refcounted->elements._void = ptr; - else - a.norefcount->elements._void = ptr; -} - -static void _upb_array_setlen(upb_arrayptr a, upb_strlen_t newlen) { - if(upb_data_hasflag(a.base, UPB_DATA_REFCOUNTED)) { - a.refcounted->len = newlen; - } else { - a.norefcount->len = newlen; - } -} - -upb_arrayptr upb_array_new() { - upb_arrayptr a; - a.refcounted = malloc(sizeof(struct upb_refcounted_array)); - data_init(a.base, UPB_DATA_HEAPALLOCATED | UPB_DATA_REFCOUNTED); - a.refcounted->size = 0; - a.refcounted->len = 0; - a.refcounted->elements._void = NULL; - return a; -} - -// ONLY handles refcounted arrays for the moment. -void _upb_array_free(upb_arrayptr a, upb_fielddef *f) -{ - if(upb_elem_ismm(f)) { - for(upb_arraylen_t i = 0; i < a.refcounted->size; i++) { - upb_valueptr p = _upb_array_getptr(a, f, i); - if(!*p.data) continue; - data_elem_unref(p, f); - } - } - if(a.refcounted->size != 0) free(a.refcounted->elements._void); - free(a.refcounted); -} - -static upb_arraylen_t array_get_size(upb_arrayptr a) { - if(upb_data_hasflag(a.base, UPB_DATA_REFCOUNTED)) { - return a.refcounted->size; - } else { - return (a.norefcount->base.v & 0xFFFFFFF8) >> 3; - } -} - -static void array_set_size(upb_arrayptr a, upb_arraylen_t newsize) { - if(upb_data_hasflag(a.base, UPB_DATA_REFCOUNTED)) { - a.refcounted->size = newsize; - } else { - a.norefcount->base.v &= 0x7; - a.norefcount->base.v |= (newsize << 3); - } -} - -void upb_array_resize(upb_arrayptr a, upb_fielddef *f, upb_strlen_t len) { - check_not_frozen(a.base); - size_t type_size = upb_types[f->type].size; - upb_arraylen_t old_size = array_get_size(a); - if(old_size < len) { - // Need to resize. - size_t new_size = round_up_to_pow2(len); - _upb_array_setptr(a, realloc(_upb_array_getptr_raw(a, 0, 0)._void, new_size * type_size)); - array_set_size(a, new_size); - memset(_upb_array_getptr_raw(a, old_size, type_size)._void, - 0, - (new_size - old_size) * type_size); - } - _upb_array_setlen(a, len); -} - - -/* upb_msg ********************************************************************/ - -static void upb_msg_sethas(upb_msg *msg, upb_fielddef *f) { - msg->data[f->field_index/8] |= (1 << (f->field_index % 8)); -} - -upb_msg *upb_msg_new(upb_msgdef *md) { - upb_msg *msg = malloc(md->size); - memset(msg, 0, md->size); - data_init(&msg->base, UPB_DATA_HEAPALLOCATED | UPB_DATA_REFCOUNTED); - upb_def_ref(UPB_UPCAST(md)); - return msg; -} - -// ONLY handles refcounted messages for the moment. -void _upb_msg_free(upb_msg *msg, upb_msgdef *md) -{ - for(int i = 0; i < md->num_fields; i++) { - upb_fielddef *f = &md->fields[i]; - upb_valueptr p = _upb_msg_getptr(msg, f); - if(!upb_field_ismm(f) || !*p.data) continue; - data_unref(p, f); - } - upb_def_unref(UPB_UPCAST(md)); - free(msg); -} - -void upb_msg_decodestr(upb_msg *msg, upb_msgdef *md, upb_strptr str, - upb_status *status) -{ - upb_decoder *d = upb_decoder_new(md); - upb_msgsink *s = upb_msgsink_new(md); - - upb_msgsink_reset(s, msg); - upb_decoder_reset(d, upb_msgsink_sink(s)); - upb_msg_clear(msg, md); - upb_decoder_decode(d, str, status); - - upb_decoder_free(d); - upb_msgsink_free(s); -} - -#if 0 -void upb_msg_encodestr(upb_msg *msg, upb_msgdef *md, upb_strptr str, - upb_status *status) -{ - upb_sizebuilder *sb = upb_sizebuilder_new(md); - upb_encoder *e = upb_encoder_new(md); - upb_strsink *sink = upb_strsink_new(); - - // Get sizes. We could avoid performing this step in some cases by having a - // bool in the msgdef indicating whether it or any of its children have - // submessages in the def (groups don't count). - upb_sizebuilder_reset(sb); - upb_msgsrc_produce(msg, md, upb_sizebuilder_sink(sb), true); - - upb_strsink_reset(); - upb_encoder_reset(e, sb, sink); - upb_msgsrc_produce(msg, md, sink, false); -} -#endif - -/* upb_msgsrc ****************************************************************/ - -static void _upb_msgsrc_produceval(upb_value v, upb_fielddef *f, upb_sink *sink, - bool reverse, upb_status *status) -{ - // TODO: We need to check status for failure, but how often? - if(upb_issubmsg(f)) { - upb_msgdef *md = upb_downcast_msgdef(f->def); - upb_sink_onstart(sink, f, status); - upb_msgsrc_produce(v.msg, md, sink, reverse, status); - upb_sink_onend(sink, f, status); - } else if(upb_isstring(f)) { - upb_sink_onstr(sink, f, v.str, 0, upb_strlen(v.str), status); - } else { - upb_sink_onvalue(sink, f, v, status); - } -} - -void upb_msgsrc_produce(upb_msg *msg, upb_msgdef *md, upb_sink *sink, - bool reverse, upb_status *status) -{ - for(int i = 0; i < md->num_fields; i++) { - upb_fielddef *f = &md->fields[reverse ? md->num_fields - i - 1 : i]; - if(!upb_msg_has(msg, f)) continue; - upb_value v = upb_msg_get(msg, f); - if(upb_isarray(f)) { - upb_arrayptr arr = v.arr; - upb_arraylen_t len = upb_array_len(arr); - for(upb_arraylen_t j = 0; j < upb_array_len(arr); j++) { - upb_value elem = upb_array_get(arr, f, reverse ? len - j - 1 : j); - _upb_msgsrc_produceval(elem, f, sink, reverse, status); - } - } else { - _upb_msgsrc_produceval(v, f, sink, reverse, status); - } - } -} - - -/* upb_msgsink ***************************************************************/ - -typedef struct { - upb_msg *msg; - upb_msgdef *md; -} upb_msgsink_frame; - -struct upb_msgsink { - upb_sink base; - upb_msgdef *toplevel_msgdef; - upb_msgsink_frame stack[UPB_MAX_NESTING], *top; -}; - -/* Helper function that returns a pointer to where the next value for field "f" - * should be stored, taking into account whether f is an array that may need to - * be allocated or resized. */ -static upb_valueptr get_valueptr(upb_msg *msg, upb_fielddef *f) -{ - upb_valueptr p = _upb_msg_getptr(msg, f); - if(upb_isarray(f)) { - if(!upb_msg_has(msg, f)) { - if(upb_array_isnull(*p.arr) || !upb_data_only(*p.data)) { - if(!upb_array_isnull(*p.arr)) - upb_array_unref(*p.arr, f); - *p.arr = upb_array_new(); - } - upb_array_truncate(*p.arr); - upb_msg_sethas(msg, f); - } else { - assert(!upb_array_isnull(*p.arr)); - } - upb_arraylen_t oldlen = upb_array_len(*p.arr); - upb_array_resize(*p.arr, f, oldlen + 1); - p = _upb_array_getptr(*p.arr, f, oldlen); - } - return p; -} - -// Callbacks for upb_sink. -// TODO: implement these in terms of public interfaces. - -static upb_sink_status _upb_msgsink_valuecb(upb_sink *s, upb_fielddef *f, - upb_value val, upb_status *status) -{ - (void)status; // No detectable errors can occur. - upb_msgsink *ms = (upb_msgsink*)s; - upb_msg *msg = ms->top->msg; - upb_valueptr p = get_valueptr(msg, f); - upb_msg_sethas(msg, f); - upb_value_write(p, val, f->type); - return UPB_SINK_CONTINUE; -} - -static upb_sink_status _upb_msgsink_strcb(upb_sink *s, upb_fielddef *f, - upb_strptr str, - int32_t start, uint32_t end, - upb_status *status) -{ - (void)status; // No detectable errors can occur. - upb_msgsink *ms = (upb_msgsink*)s; - upb_msg *msg = ms->top->msg; - upb_valueptr p = get_valueptr(msg, f); - upb_msg_sethas(msg, f); - if(end > upb_strlen(str)) abort(); /* TODO: support streaming. */ - if(upb_string_isnull(*p.str) || !upb_data_only(*p.data)) { - if(!upb_string_isnull(*p.str)) - upb_string_unref(*p.str); - *p.str = upb_string_new(); - } - upb_strcpylen(*p.str, upb_string_getrobuf(str) + start, end - start); - return UPB_SINK_CONTINUE; -} - -static upb_sink_status _upb_msgsink_startcb(upb_sink *s, upb_fielddef *f, - upb_status *status) -{ - (void)status; // No detectable errors can occur. - upb_msgsink *ms = (upb_msgsink*)s; - upb_msg *oldmsg = ms->top->msg; - upb_valueptr p = get_valueptr(oldmsg, f); - ms->top++; - - if(upb_isarray(f) || !upb_msg_has(oldmsg, f)) { - upb_msgdef *md = upb_downcast_msgdef(f->def); - if(!*p.msg || !upb_data_only(*p.data)) { - if(*p.msg) - upb_msg_unref(*p.msg, md); - *p.msg = upb_msg_new(md); - } - upb_msg_clear(*p.msg, md); - upb_msg_sethas(oldmsg, f); - } - - ms->top->msg = *p.msg; - return UPB_SINK_CONTINUE; -} - -static upb_sink_status _upb_msgsink_endcb(upb_sink *s, upb_fielddef *f, - upb_status *status) -{ - (void)status; // No detectable errors can occur. - (void)f; // Unused. - upb_msgsink *ms = (upb_msgsink*)s; - ms->top--; - return UPB_SINK_CONTINUE; -} - -static upb_sink_callbacks _upb_msgsink_vtbl = { - _upb_msgsink_valuecb, - _upb_msgsink_strcb, - _upb_msgsink_startcb, - _upb_msgsink_endcb -}; - -// -// External upb_msgsink interface. -// - -upb_msgsink *upb_msgsink_new(upb_msgdef *md) -{ - upb_msgsink *ms = malloc(sizeof(*ms)); - upb_sink_init(&ms->base, &_upb_msgsink_vtbl); - ms->toplevel_msgdef = md; - return ms; -} - -void upb_msgsink_free(upb_msgsink *sink) -{ - free(sink); -} - -upb_sink *upb_msgsink_sink(upb_msgsink *sink) -{ - return &sink->base; -} - -void upb_msgsink_reset(upb_msgsink *ms, upb_msg *msg) -{ - ms->top = ms->stack; - ms->top->msg = msg; - ms->top->md = ms->toplevel_msgdef; -} diff --git a/src/upb_data.h b/src/upb_data.h deleted file mode 100644 index cdb7af2..0000000 --- a/src/upb_data.h +++ /dev/null @@ -1,552 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. - * - * This file defines the in-memory format for messages, arrays, and strings - * (which are the three dynamically-allocated structures that make up all - * protobufs). - * - * The members of all structs should be considered private. Access should - * only happen through the provided functions. - * - * Unlike Google's protobuf, messages contain *pointers* to strings and arrays - * instead of including them by value. This makes unused strings and arrays - * use less memory, and lets the strings and arrays have multiple possible - * representations (for example, a string could be a slice). It also gives - * us more flexibility wrt refcounting. The cost is that when a field *is* - * being used, the net memory usage is one pointer more than if we had - * included the thing directly. */ - -#ifndef UPB_DATA_H -#define UPB_DATA_H - -#include <assert.h> -#include <string.h> -#include "upb.h" -#include "upb_atomic.h" -#include "upb_def.h" -#include "upb_sink.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* upb_data *******************************************************************/ - -// The "base class" of strings, arrays, and messages. Contains a few flags and -// possibly a reference count. None of the functions for upb_data are public, -// but some of the constants are. - -// typedef upb_atomic_refcount_t upb_data; - -// The flags in upb_data. -typedef enum { - // Set if the object itself was allocated with malloc() and should be freed - // with free(). This flag would be false if the object was allocated on the - // stack or is data from the static segment of an object file. Note that this - // flag does not apply to the data being referenced by a string or array. - // - // If this flag is false, UPB_FLAG_HAS_REFCOUNT must be false also; there is - // no sense refcounting something that does not need to be freed. - UPB_DATA_HEAPALLOCATED = 1, - - // Set if the object is frozen against modification. While an object is - // frozen, it is suitable for concurrent readonly access. Note that this - // flag alone is not a sufficient mechanism for preventing any kind of writes - // to the object's memory, because the object could still have a refcount. - UPB_DATA_FROZEN = (1<<1), - - // Set if the object has an embedded refcount. - UPB_DATA_REFCOUNTED = (1<<2) -} upb_data_flag; - -#define REFCOUNT_MASK 0xFFFFFFF8 -#define REFCOUNT_SHIFT 3 -#define REFCOUNT_ONE (1<<REFCOUNT_SHIFT) - -INLINE bool upb_data_hasflag(upb_data *d, upb_data_flag flag) { - // We read this unsynchronized, because the is_frozen flag (the only flag - // that can change during the life of a upb_data) may not change if the - // data has more than one owner. - return d->v & flag; -} - -// INTERNAL-ONLY -INLINE void upb_data_setflag(upb_data *d, upb_data_flag flag) { - d->v |= flag; -} - -INLINE uint32_t upb_data_getrefcount(upb_data *d) { - int data; - if(upb_data_hasflag(d, UPB_DATA_FROZEN)) - data = upb_atomic_read(d); - else - data = d->v; - return (data & REFCOUNT_MASK) >> REFCOUNT_SHIFT; -} - -// Returns true if the given data has only one owner. -INLINE bool upb_data_only(upb_data *data) { - return !upb_data_hasflag(data, UPB_DATA_REFCOUNTED) || - upb_data_getrefcount(data) == 1; -} - -// Specifies the type of ref that is requested based on the kind of access the -// caller needs to the object. -typedef enum { - // Use when the client plans to perform read-only access to the object, and - // only in one thread at a time. This imposes the least requirements on the - // object; it can be either frozen or not. As a result, requesting a - // reference of this type never performs a copy unless the object has no - // refcount. - // - // A ref of this type can always be explicitly converted to frozen or - // unfrozen later. - UPB_REF_THREADUNSAFE_READONLY = 0, - - // Use when the client plans to perform read-only access, but from multiple - // threads concurrently. This will force the object to eagerly perform any - // parsing that may have been lazily deferred, and will force a copy if the - // object is not current frozen. - // - // Asking for a reference of this type is equivalent to: - // x = getref(y, UPB_REF_THREADUNSAFE_READONLY); - // x = freeze(x); - // ...except it is more efficient. - UPB_REF_FROZEN = 1, - - // Use when the client plans to perform read/write access. As a result, the - // reference will not be thread-safe for concurrent reading *or* writing; the - // object must be externally synchronized if it is being accessed from more - // than one thread. This will force a copy if the object is currently frozen. - // - // Asking for a reference of this type is equivalent to: - // x = getref(y, UPB_REF_THREADUNSAFE_READONLY); - // x = thaw(x); - // ...except it is more efficient. - UPB_REF_MUTABLE = 2 -} upb_reftype; - -// INTERNAL-ONLY FUNCTION: -// Attempts to increment the reference on d with the given type of ref. If -// this is not possible, returns false. -INLINE bool _upb_data_incref(upb_data *d, upb_reftype reftype) { - bool frozen = upb_data_hasflag(d, UPB_DATA_FROZEN); - if((reftype == UPB_REF_FROZEN && !frozen) || - (reftype == UPB_REF_MUTABLE && frozen) || - (upb_data_hasflag(d, UPB_DATA_HEAPALLOCATED) && - !upb_data_hasflag(d, UPB_DATA_REFCOUNTED))) { - return false; - } - // Increment the ref. Only need to use atomic ops if the ref is frozen. - if(upb_data_hasflag(d, UPB_DATA_FROZEN)) upb_atomic_add(d, REFCOUNT_ONE); - else d->v += REFCOUNT_ONE; - return true; -} - -// INTERNAL-ONLY FUNCTION: -// Releases a reference on d, returning true if the object should be deleted. -INLINE bool _upb_data_unref(upb_data *d) { - if(upb_data_hasflag(d, UPB_DATA_HEAPALLOCATED)) { - // A heap-allocated object without a refcount should never be decref'd. - // Its owner owns it exlusively and should free it directly. - assert(upb_data_hasflag(d, UPB_DATA_REFCOUNTED)); - if(upb_data_hasflag(d, UPB_DATA_FROZEN)) { - int32_t old_val = upb_atomic_fetch_and_add(d, -REFCOUNT_ONE); - return (old_val & REFCOUNT_MASK) == REFCOUNT_ONE; - } else { - d->v -= REFCOUNT_ONE; - return (d->v & REFCOUNT_MASK) == 0; - } - } else { - // Non heap-allocated data never should be deleted. - return false; - } -} - -/* upb_string *****************************************************************/ - -// We have several different representations for string, depending on whether -// it has a refcount (and likely in the future, depending on whether it is a -// slice of another string). We could just have one representation with -// members that are sometimes unused, but this is wasteful in memory. The -// flags that are always part of the first word tell us which representation -// to use. -// -// In a way, this is like inheritance but instead of using a virtual pointer, -// we do switch/case in every "virtual" method. This may sound expensive but -// in many cases the different cases compile to exactly the same code, so there -// is no branch. - -struct upb_norefcount_string { - uint32_t byte_size_and_flags; - upb_strlen_t byte_len; - // We expect the data to be 8-bit clean (uint8_t), but char* is such an - // ingrained convention that we follow it. - char *ptr; -}; - -// Used for a string with a refcount. -struct upb_refcounted_string { - upb_data base; - upb_strlen_t byte_len; - char *ptr; - uint32_t byte_size; -}; - - -// Returns a newly constructed, refcounted string which starts out empty. -// Caller owns one ref on it. The returned string will not be frozen. -upb_strptr upb_string_new(void); - -// INTERNAL-ONLY: -// Frees the given string, alone with any memory the string owned. -void _upb_string_free(upb_strptr s); - -// Returns a string to which caller owns a ref, and contains the same contents -// as src. The returned value may be a copy of src, if the requested flags -// were incompatible with src's. -upb_strptr upb_string_getref(upb_strptr s, int ref_flags); - -#define UPB_STRING_NULL_INITIALIZER {NULL} -static const upb_strptr UPB_STRING_NULL = UPB_STRING_NULL_INITIALIZER; -INLINE bool upb_string_isnull(upb_strptr s) { return s.base == NULL; } - -// The caller releases a ref on src, which it must previously have owned a ref -// on. -INLINE void upb_string_unref(upb_strptr s) { - if(_upb_data_unref(s.base)) _upb_string_free(s); -} - -// The string is resized to byte_len. The string must not be frozen. -void upb_string_resize(upb_strptr s, upb_strlen_t len); - -// Returns a buffer to which the caller may write. The string is resized to -// byte_len (which may or may not trigger a reallocation). The string must not -// be frozen. -INLINE char *upb_string_getrwbuf(upb_strptr s, upb_strlen_t byte_len) { - upb_string_resize(s, byte_len); - if(upb_data_hasflag(s.base, UPB_DATA_REFCOUNTED)) - return s.refcounted->ptr; - else - return s.norefcount->ptr; -} - -INLINE void upb_string_clear(upb_strptr s) { - upb_string_getrwbuf(s, 0); -} - -// INTERNAL-ONLY: -// Gets/sets the pointer. -INLINE char *_upb_string_getptr(upb_strptr s) { - if(upb_data_hasflag(s.base, UPB_DATA_REFCOUNTED)) - return s.refcounted->ptr; - else - return s.norefcount->ptr; -} - -// Returns a buffer that the caller may use to read the current contents of -// the string. The number of bytes available is upb_strlen(s). -INLINE const char *upb_string_getrobuf(upb_strptr s) { - return _upb_string_getptr(s); -} - -// Returns the current length of the string. -INLINE upb_strlen_t upb_strlen(upb_strptr s) { - if(upb_data_hasflag(s.base, UPB_DATA_REFCOUNTED)) - return s.refcounted->byte_len; - else - return s.norefcount->byte_len; -} - -/* upb_string library functions ***********************************************/ - -// Named like their <string.h> counterparts, these are all safe against buffer -// overflow. These only use the public upb_string interface. - -// More efficient than upb_strcmp if all you need is to test equality. -INLINE bool upb_streql(upb_strptr s1, upb_strptr s2) { - upb_strlen_t len = upb_strlen(s1); - if(len != upb_strlen(s2)) { - return false; - } else { - return memcmp(upb_string_getrobuf(s1), upb_string_getrobuf(s2), len) == 0; - } -} - -// Like strcmp(). -int upb_strcmp(upb_strptr s1, upb_strptr s2); - -// Like upb_strcpy, but copies from a buffer and length. -INLINE void upb_strcpylen(upb_strptr dest, const void *src, upb_strlen_t len) { - memcpy(upb_string_getrwbuf(dest, len), src, len); -} - -// Replaces the contents of "dest" with the contents of "src". -INLINE void upb_strcpy(upb_strptr dest, upb_strptr src) { - upb_strcpylen(dest, upb_string_getrobuf(src), upb_strlen(src)); -} - -// Like upb_strcpy, but copies from a NULL-terminated string. -INLINE void upb_strcpyc(upb_strptr dest, const char *src) { - // This does two passes over src, but that is necessary unless we want to - // repeatedly re-allocate dst, which seems worse. - upb_strcpylen(dest, src, strlen(src)); -} - -// Returns a new string whose contents are a copy of s. -upb_strptr upb_strdup(upb_strptr s); - -// Like upb_strdup(), but duplicates a given buffer and length. -INLINE upb_strptr upb_strduplen(const void *src, upb_strlen_t len) { - upb_strptr s = upb_string_new(); - upb_strcpylen(s, src, len); - return s; -} - -// Like upb_strdup(), but duplicates a C NULL-terminated string. -upb_strptr upb_strdupc(const char *src); - -// Appends 'append' to 's' in-place, resizing s if necessary. -void upb_strcat(upb_strptr s, upb_strptr append); - -// Returns a string that is a substring of the given string. Currently this -// returns a copy, but in the future this may return an object that references -// the original string data instead of copying it. Both now and in the future, -// the caller owns a ref on whatever is returned. -upb_strptr upb_strslice(upb_strptr s, int offset, int len); - -// Reads an entire file into a newly-allocated string (caller owns one ref). -upb_strptr upb_strreadfile(const char *filename); - -// Typedef for a read-only string that is allocated statically or on the stack. -// Initialize with the given macro, which must resolve to a const char*. You -// must not dynamically allocate this type. Example usage: -// -// upb_static_string mystr = UPB_STATIC_STRING_INIT("biscuits"); -// upb_strptr mystr_ptr = UPB_STATIC_STRING_PTR_INIT(mystr); -// -// If C99 compund literals are available, the much nicer UPB_STRLIT macro is -// available instead: -// -// upb_strtr mystr_ptr = UPB_STRLIT("biscuits"); -// -typedef struct upb_norefcount_string upb_static_string; -#define UPB_STATIC_STRING_INIT_LEN(str, len) {0 | UPB_DATA_FROZEN, len, str} -#define UPB_STATIC_STRING_INIT(str) UPB_STATIC_STRING_INIT_LEN(str, sizeof(str)-1) -#define UPB_STATIC_STRING_PTR_INIT(static_string) {&static_string} -#define UPB_STRLIT(str) (upb_strptr){&(upb_static_string)UPB_STATIC_STRING_INIT(str)} - -// Allows using upb_strings in printf, ie: -// upb_strptr str = UPB_STRLIT("Hello, World!\n"); -// printf("String is: " UPB_STRFMT, UPB_STRARG(str)); */ -#define UPB_STRARG(str) upb_strlen(str), upb_string_getrobuf(str) -#define UPB_STRFMT "%.*s" - -/* upb_array ******************************************************************/ - -// The comments attached to upb_string above also apply here. -struct upb_norefcount_array { - upb_data base; // We co-opt the refcount for the size. - upb_arraylen_t len; - upb_valueptr elements; -}; - -struct upb_refcounted_array { - upb_data base; - upb_arraylen_t len; - upb_valueptr elements; - upb_arraylen_t size; -}; - -typedef struct upb_norefcount_array upb_static_array; -#define UPB_STATIC_ARRAY_INIT(arr, len) {{0 | UPB_DATA_FROZEN}, len, {._void=arr}} -#define UPB_STATIC_ARRAY_PTR_TYPED_INIT(static_arr) {{&static_arr}} - -#define UPB_ARRAY_NULL_INITIALIZER {NULL} -static const upb_arrayptr UPB_ARRAY_NULL = UPB_ARRAY_NULL_INITIALIZER; -INLINE bool upb_array_isnull(upb_arrayptr a) { return a.base == NULL; } -INLINE bool upb_array_ptreql(upb_arrayptr a1, upb_arrayptr a2) { - return a1.base == a2.base; -} - -#define UPB_MSG_ARRAYPTR(type) type ## _array -#define UPB_DEFINE_MSG_ARRAY(type) \ -typedef struct { upb_arrayptr ptr; } UPB_MSG_ARRAYPTR(type); \ -INLINE upb_arraylen_t type ## _array_len(UPB_MSG_ARRAYPTR(type) a) { \ - return upb_array_len(a.ptr); \ -} \ -INLINE type* type ## _array_get(UPB_MSG_ARRAYPTR(type) a, upb_arraylen_t elem) { \ - return *(type**)_upb_array_getptr_raw(a.ptr, elem, sizeof(void*))._void; \ -} - -// Constructs a newly-allocated, reference-counted array which starts out -// empty. Caller owns one ref on it. -upb_arrayptr upb_array_new(void); - -// Returns the current number of elements in the array. -INLINE size_t upb_array_len(upb_arrayptr a) { - if(upb_data_hasflag(a.base, UPB_DATA_REFCOUNTED)) - return a.refcounted->len; - else - return a.norefcount->len; -} - -// INTERNAL-ONLY: -// Frees the given message and releases references on members. -void _upb_array_free(upb_arrayptr a, upb_fielddef *f); - -// INTERNAL-ONLY: -// Returns a pointer to the given elem. -INLINE upb_valueptr _upb_array_getptr_raw(upb_arrayptr a, upb_arraylen_t elem, - size_t type_size) { - upb_valueptr p; - if(upb_data_hasflag(a.base, UPB_DATA_REFCOUNTED)) - p._void = &a.refcounted->elements.uint8[elem * type_size]; - else - p._void = &a.norefcount->elements.uint8[elem * type_size]; - return p; -} - -INLINE upb_valueptr _upb_array_getptr(upb_arrayptr a, upb_fielddef *f, - upb_arraylen_t elem) { - return _upb_array_getptr_raw(a, elem, upb_types[f->type].size); -} - -INLINE upb_value upb_array_get(upb_arrayptr a, upb_fielddef *f, - upb_arraylen_t elem) { - assert(elem < upb_array_len(a)); - return upb_value_read(_upb_array_getptr(a, f, elem), f->type); -} - -// The caller releases a ref on the given array, which it must previously have -// owned a ref on. -INLINE void upb_array_unref(upb_arrayptr a, upb_fielddef *f) { - if(_upb_data_unref(a.base)) _upb_array_free(a, f); -} - -#if 0 -// Returns an array to which caller owns a ref, and contains the same contents -// as src. The returned value may be a copy of src, if the requested flags -// were incompatible with src's. -INLINE upb_arrayptr upb_array_getref(upb_arrayptr src, int ref_flags); - -// Sets the given element in the array to val. The current length of the array -// must be greater than elem. If the field type is dynamic, the array will -// take a ref on val and release a ref on what was previously in the array. -INLINE void upb_array_set(upb_arrayptr a, upb_fielddef *f, int elem, - upb_value val); - - -// Note that array_append will attempt to take a reference on the given value, -// so to avoid a copy use append_default and get. -INLINE void upb_array_append(upb_arrayptr a, upb_fielddef *f, - upb_value val); -INLINE void upb_array_append_default(upb_arrayptr a, upb_fielddef *f, - upb_value val); -#endif - -INLINE void upb_array_truncate(upb_arrayptr a) { - if(upb_data_hasflag(a.base, UPB_DATA_REFCOUNTED)) - a.refcounted->len = 0; - else - a.norefcount->len = 0; -} - - -/* upb_msg ********************************************************************/ - -// Note that some inline functions for upb_msg are defined in upb_def.h since -// they rely on the defs. - -struct _upb_msg { - upb_data base; - uint8_t data[4]; // We allocate the appropriate amount per message. -}; - -// Creates a new msg of the given type. -upb_msg *upb_msg_new(upb_msgdef *md); - -// INTERNAL-ONLY: -// Frees the given message and releases references on members. -void _upb_msg_free(upb_msg *msg, upb_msgdef *md); - -// INTERNAL-ONLY: -// Returns a pointer to the given field. -INLINE upb_valueptr _upb_msg_getptr(upb_msg *msg, upb_fielddef *f) { - upb_valueptr p; - p._void = &msg->data[f->byte_offset]; - return p; -} - -// Releases a references on msg. -INLINE void upb_msg_unref(upb_msg *msg, upb_msgdef *md) { - if(_upb_data_unref(&msg->base)) _upb_msg_free(msg, md); -} - -// Tests whether the given field is explicitly set, or whether it will return -// a default. -INLINE bool upb_msg_has(upb_msg *msg, upb_fielddef *f) { - return (msg->data[f->field_index/8] & (1 << (f->field_index % 8))) != 0; -} - -// Returns the current value if set, or the default value if not set, of the -// specified field. The caller does *not* own a ref. -INLINE upb_value upb_msg_get(upb_msg *msg, upb_fielddef *f) { - if(upb_msg_has(msg, f)) { - return upb_value_read(_upb_msg_getptr(msg, f), f->type); - } else { - return f->default_value; - } -} - -// Sets the given field to the given value. The msg will take a ref on val, -// and will drop a ref on whatever was there before. -void upb_msg_set(upb_msg *msg, upb_fielddef *f, upb_value val); - -INLINE void upb_msg_clear(upb_msg *msg, upb_msgdef *md) { - memset(msg->data, 0, md->set_flags_bytes); -} - -// A convenience function for decoding an entire protobuf all at once, without -// having to worry about setting up the appropriate objects. -void upb_msg_decodestr(upb_msg *msg, upb_msgdef *md, upb_strptr str, - upb_status *status); - -// A convenience function for encoding an entire protobuf all at once. If an -// error occurs, the null string is returned and the status object contains -// the error. -void upb_msg_encodestr(upb_msg *msg, upb_msgdef *md, upb_strptr str, - upb_status *status); - - -/* upb_msgsrc *****************************************************************/ - -// A nonresumable, non-interruptable (but simple and fast) source for pushing -// the data of a upb_msg to a upb_sink. -void upb_msgsrc_produce(upb_msg *msg, upb_msgdef *md, upb_sink *sink, - bool reverse, upb_status *status); - - -/* upb_msgsink ****************************************************************/ - -// A upb_msgsink can accept the data from a source and write it into a message. -struct upb_msgsink; -typedef struct upb_msgsink upb_msgsink; - -// Allocate and free a msgsink, respectively. -upb_msgsink *upb_msgsink_new(upb_msgdef *md); -void upb_msgsink_free(upb_msgsink *sink); - -// Returns the upb_sink (like an upcast). -upb_sink *upb_msgsink_sink(upb_msgsink *sink); - -// Resets the msgsink for the given msg. -void upb_msgsink_reset(upb_msgsink *sink, upb_msg *msg); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/src/upb_decoder.c b/src/upb_decoder.c deleted file mode 100644 index 209db56..0000000 --- a/src/upb_decoder.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2008-2009 Joshua Haberman. See LICENSE for details. - */ - -#include "upb_decoder.h" - -#include <inttypes.h> -#include <stddef.h> -#include <stdlib.h> -#include "upb_def.h" - -/* Functions to read wire values. *********************************************/ - -// These functions are internal to the decode, but might be moved into an -// internal header file if we at some point in the future opt to do code -// generation, because the generated code would want to inline these functions. -// The same applies to the functions to read .proto values below. - -const uint8_t *upb_get_v_uint64_t_full(const uint8_t *buf, const uint8_t *end, - uint64_t *val, upb_status *status); - -// Gets a varint (wire type: UPB_WIRE_TYPE_VARINT). -INLINE const uint8_t *upb_get_v_uint64_t(const uint8_t *buf, const uint8_t *end, - uint64_t *val, upb_status *status) -{ - // We inline this common case (1-byte varints), if that fails we dispatch to - // the full (non-inlined) version. - if((*buf & 0x80) == 0) { - *val = *buf & 0x7f; - return buf + 1; - } else { - return upb_get_v_uint64_t_full(buf, end, val, status); - } -} - -// Gets a varint -- called when we only need 32 bits of it. Note that a 32-bit -// varint is not a true wire type. -INLINE const uint8_t *upb_get_v_uint32_t(const uint8_t *buf, const uint8_t *end, - uint32_t *val, upb_status *status) -{ - uint64_t val64; - const uint8_t *ret = upb_get_v_uint64_t(buf, end, &val64, status); - *val = (uint32_t)val64; // Discard the high bits. - return ret; -} - -// Gets a fixed-length 32-bit integer (wire type: UPB_WIRE_TYPE_32BIT). -INLINE const uint8_t *upb_get_f_uint32_t(const uint8_t *buf, const uint8_t *end, - uint32_t *val, upb_status *status) -{ - const uint8_t *uint32_end = buf + sizeof(uint32_t); - if(uint32_end > end) { - status->code = UPB_STATUS_NEED_MORE_DATA; - return end; - } -#if UPB_UNALIGNED_READS_OK - *val = *(uint32_t*)buf; -#else -#define SHL(val, bits) ((uint32_t)val << bits) - *val = SHL(buf[0], 0) | SHL(buf[1], 8) | SHL(buf[2], 16) | SHL(buf[3], 24); -#undef SHL -#endif - return uint32_end; -} - -// Gets a fixed-length 64-bit integer (wire type: UPB_WIRE_TYPE_64BIT). -INLINE const uint8_t *upb_get_f_uint64_t(const uint8_t *buf, const uint8_t *end, - uint64_t *val, upb_status *status) -{ - const uint8_t *uint64_end = buf + sizeof(uint64_t); - if(uint64_end > end) { - status->code = UPB_STATUS_NEED_MORE_DATA; - return end; - } -#if UPB_UNALIGNED_READS_OK - *val = *(uint64_t*)buf; -#else -#define SHL(val, bits) ((uint64_t)val << bits) - *val = SHL(buf[0], 0) | SHL(buf[1], 8) | SHL(buf[2], 16) | SHL(buf[3], 24) | - SHL(buf[4], 32) | SHL(buf[5], 40) | SHL(buf[6], 48) | SHL(buf[7], 56); -#undef SHL -#endif - return uint64_end; -} - -INLINE const uint8_t *upb_skip_v_uint64_t(const uint8_t *buf, - const uint8_t *end, - upb_status *status) -{ - const uint8_t *const maxend = buf + 10; - uint8_t last = 0x80; - for(; buf < (uint8_t*)end && (last & 0x80); buf++) - last = *buf; - - if(buf >= end && buf <= maxend && (last & 0x80)) { - status->code = UPB_STATUS_NEED_MORE_DATA; - buf = end; - } else if(buf > maxend) { - status->code = UPB_ERROR_UNTERMINATED_VARINT; - buf = end; - } - return buf; -} - -INLINE const uint8_t *upb_skip_f_uint32_t(const uint8_t *buf, - const uint8_t *end, - upb_status *status) -{ - const uint8_t *uint32_end = buf + sizeof(uint32_t); - if(uint32_end > end) { - status->code = UPB_STATUS_NEED_MORE_DATA; - return end; - } - return uint32_end; -} - -INLINE const uint8_t *upb_skip_f_uint64_t(const uint8_t *buf, - const uint8_t *end, - upb_status *status) -{ - const uint8_t *uint64_end = buf + sizeof(uint64_t); - if(uint64_end > end) { - status->code = UPB_STATUS_NEED_MORE_DATA; - return end; - } - return uint64_end; -} - -/* Functions to read .proto values. *******************************************/ - -// Performs zig-zag decoding, which is used by sint32 and sint64. -INLINE int32_t upb_zzdec_32(uint32_t n) { return (n >> 1) ^ -(int32_t)(n & 1); } -INLINE int64_t upb_zzdec_64(uint64_t n) { return (n >> 1) ^ -(int64_t)(n & 1); } - -// Use macros to define a set of two functions for each .proto type: -// -// // Reads and converts a .proto value from buf, placing it in d. -// // "end" indicates the end of the current buffer (if the buffer does -// // not contain the entire value UPB_STATUS_NEED_MORE_DATA is returned). -// // On success, a pointer will be returned to the first byte that was -// // not consumed. -// const uint8_t *upb_get_INT32(const uint8_t *buf, const uint8_t *end, -// int32_t *d, upb_status *status); -// -// // Given an already read wire value s (source), convert it to a .proto -// // value and return it. -// int32_t upb_wvtov_INT32(uint32_t s); -// -// These are the most efficient functions to call if you want to decode a value -// for a known type. - -#define WVTOV(type, wire_t, val_t) \ - INLINE val_t upb_wvtov_ ## type(wire_t s) - -#define GET(type, v_or_f, wire_t, val_t, member_name) \ - INLINE const uint8_t *upb_get_ ## type(const uint8_t *buf, const uint8_t *end, \ - val_t *d, upb_status *status) { \ - wire_t tmp = 0; \ - const uint8_t *ret = upb_get_ ## v_or_f ## _ ## wire_t(buf, end, &tmp, status); \ - *d = upb_wvtov_ ## type(tmp); \ - return ret; \ - } - -#define T(type, v_or_f, wire_t, val_t, member_name) \ - WVTOV(type, wire_t, val_t); /* prototype for GET below */ \ - GET(type, v_or_f, wire_t, val_t, member_name) \ - WVTOV(type, wire_t, val_t) - -T(INT32, v, uint32_t, int32_t, int32) { return (int32_t)s; } -T(INT64, v, uint64_t, int64_t, int64) { return (int64_t)s; } -T(UINT32, v, uint32_t, uint32_t, uint32) { return s; } -T(UINT64, v, uint64_t, uint64_t, uint64) { return s; } -T(SINT32, v, uint32_t, int32_t, int32) { return upb_zzdec_32(s); } -T(SINT64, v, uint64_t, int64_t, int64) { return upb_zzdec_64(s); } -T(FIXED32, f, uint32_t, uint32_t, uint32) { return s; } -T(FIXED64, f, uint64_t, uint64_t, uint64) { return s; } -T(SFIXED32, f, uint32_t, int32_t, int32) { return (int32_t)s; } -T(SFIXED64, f, uint64_t, int64_t, int64) { return (int64_t)s; } -T(BOOL, v, uint32_t, bool, _bool) { return (bool)s; } -T(ENUM, v, uint32_t, int32_t, int32) { return (int32_t)s; } -T(DOUBLE, f, uint64_t, double, _double) { - upb_value v; - v.uint64 = s; - return v._double; -} -T(FLOAT, f, uint32_t, float, _float) { - upb_value v; - v.uint32 = s; - return v._float; -} - -#undef WVTOV -#undef GET -#undef T - -// Parses a tag, places the result in *tag. -INLINE const uint8_t *decode_tag(const uint8_t *buf, const uint8_t *end, - upb_tag *tag, upb_status *status) -{ - uint32_t tag_int; - const uint8_t *ret = upb_get_v_uint32_t(buf, end, &tag_int, status); - tag->wire_type = (upb_wire_type_t)(tag_int & 0x07); - tag->field_number = tag_int >> 3; - return ret; -} - - -// Parses a 64-bit varint that is known to be >= 2 bytes (the inline version -// handles 1 and 2 byte varints). -const uint8_t *upb_get_v_uint64_t_full(const uint8_t *buf, const uint8_t *end, - uint64_t *val, upb_status *status) -{ - const uint8_t *const maxend = buf + 10; - uint8_t last = 0x80; - *val = 0; - int bitpos; - - for(bitpos = 0; buf < (uint8_t*)end && (last & 0x80); buf++, bitpos += 7) - *val |= ((uint64_t)((last = *buf) & 0x7F)) << bitpos; - - if(buf >= end && buf <= maxend && (last & 0x80)) { - upb_seterr(status, UPB_STATUS_NEED_MORE_DATA, - "Provided data ended in the middle of a varint.\n"); - buf = end; - } else if(buf > maxend) { - upb_seterr(status, UPB_ERROR_UNTERMINATED_VARINT, - "Varint was unterminated after 10 bytes.\n"); - buf = 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, - upb_wire_type_t wt, upb_status *status) -{ - switch(wt) { - case UPB_WIRE_TYPE_VARINT: - return upb_skip_v_uint64_t(buf, end, status); - case UPB_WIRE_TYPE_64BIT: - return upb_skip_f_uint64_t(buf, end, status); - case UPB_WIRE_TYPE_32BIT: - return upb_skip_f_uint32_t(buf, end, status); - case UPB_WIRE_TYPE_START_GROUP: - // TODO: skip to matching end group. - case UPB_WIRE_TYPE_END_GROUP: - return buf; - default: - status->code = UPB_STATUS_ERROR; - return end; - } -} - -static const uint8_t *upb_decode_value(const uint8_t *buf, const uint8_t *end, - upb_field_type_t ft, upb_valueptr v, - upb_status *status) -{ -#define CASE(t, member_name) \ - case UPB_TYPE(t): return upb_get_ ## t(buf, end, v.member_name, status); - - switch(ft) { - CASE(DOUBLE, _double) - CASE(FLOAT, _float) - CASE(INT32, int32) - CASE(INT64, int64) - CASE(UINT32, uint32) - CASE(UINT64, uint64) - CASE(SINT32, int32) - CASE(SINT64, int64) - CASE(FIXED32, uint32) - CASE(FIXED64, uint64) - CASE(SFIXED32, int32) - CASE(SFIXED64, int64) - CASE(BOOL, _bool) - CASE(ENUM, int32) - default: return end; - } - -#undef CASE -} - -// 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 *field; - size_t end_offset; // For groups, 0. -} upb_decoder_frame; - -struct upb_decoder { - // Immutable state of the decoder. - upb_msgdef *toplevel_msgdef; - upb_sink *sink; - - // 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; - void *udata; -}; - -upb_decoder *upb_decoder_new(upb_msgdef *msgdef) -{ - upb_decoder *d = malloc(sizeof(*d)); - d->toplevel_msgdef = msgdef; - d->limit = &d->stack[UPB_MAX_NESTING]; - return d; -} - -void upb_decoder_free(upb_decoder *d) -{ - free(d); -} - -void upb_decoder_reset(upb_decoder *d, upb_sink *sink) -{ - d->top = d->stack; - d->completed_offset = 0; - d->sink = sink; - d->top->msgdef = d->toplevel_msgdef; - // 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; -} - -static const void *get_msgend(upb_decoder *d, const uint8_t *start) -{ - if(d->top->end_offset > 0) - return start + (d->top->end_offset - d->completed_offset); - else - return (void*)UINTPTR_MAX; // group. -} - -static bool isgroup(const void *submsg_end) -{ - return submsg_end == (void*)UINTPTR_MAX; -} - -extern upb_wire_type_t upb_expected_wire_types[]; -// Returns true if wt is the correct on-the-wire type for ft. -INLINE bool upb_check_type(upb_wire_type_t wt, upb_field_type_t ft) { - // This doesn't currently support packed arrays. - return upb_types[ft].expected_wire_type == wt; -} - - -// Pushes a new stack frame for a submessage with the given len (which will -// be zero if the submessage is a group). -static const uint8_t *push(upb_decoder *d, const uint8_t *start, - uint32_t submsg_len, upb_fielddef *f, - upb_status *status) -{ - d->top->field = f; - d->top++; - if(d->top >= d->limit) { - upb_seterr(status, UPB_ERROR_MAX_NESTING_EXCEEDED, - "Nesting exceeded maximum (%d levels)\n", - UPB_MAX_NESTING); - return NULL; - } - upb_decoder_frame *frame = d->top; - frame->end_offset = d->completed_offset + submsg_len; - frame->msgdef = upb_downcast_msgdef(f->def); - - upb_sink_onstart(d->sink, f, status); - return get_msgend(d, start); -} - -// Pops a stack frame, returning a pointer for where the next submsg should -// end (or a pointer that is out of range for a group). -static const void *pop(upb_decoder *d, const uint8_t *start, upb_status *status) -{ - d->top--; - upb_sink_onend(d->sink, d->top->field, status); - return get_msgend(d, start); -} - - -size_t upb_decoder_decode(upb_decoder *d, upb_strptr str, upb_status *status) -{ - // 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 - const uint8_t *const end = buf + upb_strlen(str); - - // When we have fully decoded a tag/value pair, we advance this. - const uint8_t *completed = buf; - - const uint8_t *submsg_end = get_msgend(d, start); - upb_msgdef *msgdef = d->top->msgdef; - upb_sink_status sink_status = UPB_SINK_CONTINUE; - - // We need to check the status of operations that can fail, but we do so as - // late as possible to avoid introducing branches that have to wait on - // (status->code) which must be loaded from memory. We must always check - // before calling a user callback. -#define CHECK_STATUS() do { if(!upb_ok(status)) goto err; } while(0) - - // Main loop: executed once per tag/field pair. - while(sink_status == UPB_SINK_CONTINUE && buf < end) { - // 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; -err: - read = (char*)completed - (char*)start; - d->completed_offset += read; - return read; -} diff --git a/src/upb_decoder.h b/src/upb_decoder.h deleted file mode 100644 index b84c149..0000000 --- a/src/upb_decoder.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * upb_decoder implements a high performance, callback-based, stream-oriented - * decoder (comparable to the SAX model in XML parsers). For parsing protobufs - * into in-memory messages (a more DOM-like model), see the routines in - * upb_msg.h, which are layered on top of this decoder. - * - * TODO: the decoder currently does not support returning unknown values. This - * can easily be added when it is needed. - * - * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. - */ - -#ifndef UPB_DECODER_H_ -#define UPB_DECODER_H_ - -#include <stdbool.h> -#include <stdint.h> -#include "upb.h" -#include "descriptor.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* upb_decoder *****************************************************************/ - -// A upb_decoder decodes the binary protocol buffer format, writing the data it -// decodes to a upb_sink. -struct upb_decoder; -typedef struct upb_decoder upb_decoder; - -// Allocates and frees a upb_decoder, respectively. -upb_decoder *upb_decoder_new(upb_msgdef *md); -void upb_decoder_free(upb_decoder *p); - -// Resets the internal state of an already-allocated decoder. This puts it in a -// state where it has not seen any data, and expects the next data to be from -// the beginning of a new protobuf. Parsers must be reset before they can be -// used. A decoder can be reset multiple times. -void upb_decoder_reset(upb_decoder *p, upb_sink *sink); - -// Decodes protobuf data out of str, returning how much data was decoded. The -// next call to upb_decoder_decode should begin with the first byte that was -// not decoded. "status" indicates whether an error occurred. -// -// TODO: provide the following guarantee: -// retval will always be >= len. -size_t upb_decoder_decode(upb_decoder *p, upb_strptr str, upb_status *status); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* UPB_DECODER_H_ */ diff --git a/src/upb_def.c b/src/upb_def.c deleted file mode 100644 index 7c9777d..0000000 --- a/src/upb_def.c +++ /dev/null @@ -1,823 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2008-2009 Joshua Haberman. See LICENSE for details. - */ - -#include <stdlib.h> -#include <limits.h> -#include "descriptor.h" -#include "upb_def.h" -#include "upb_data.h" - -/* Rounds p up to the next multiple of t. */ -#define ALIGN_UP(p, t) ((p) % (t) == 0 ? (p) : (p) + ((t) - ((p) % (t)))) - -static int div_round_up(int numerator, int denominator) { - /* cf. http://stackoverflow.com/questions/17944/how-to-round-up-the-result-of-integer-division */ - return numerator > 0 ? (numerator - 1) / denominator + 1 : 0; -} - -/* upb_def ********************************************************************/ - -// Defs are reference counted, but can have cycles when types are -// self-recursive or mutually recursive, so we need to be capable of collecting -// the cycles. In our situation defs are immutable (so cycles cannot be -// created or destroyed post-initialization). We need to be thread-safe but -// want to avoid locks if at all possible and rely only on atomic operations. -// -// Our scheme is as follows. First we give each def a flag indicating whether -// it is part of a cycle or not. Because defs are immutable, this flag will -// never change. For acyclic defs, we can use a naive algorithm and avoid the -// overhead of dealing with cycles. Most defs will be acyclic, and most cycles -// will be very short. -// -// For defs that participate in cycles we keep two reference counts. One -// tracks references that come from outside the cycle (we call these external -// references), and is incremented and decremented like a regular refcount. -// The other is a cycle refcount, and works as follows. Every cycle is -// considered distinct, even if two cycles share members. For example, this -// graph has two distinct cycles: -// -// A-->B-->C -// ^ | | -// +---+---+ -// -// The cycles in this graph are AB and ABC. When A's external refcount -// transitions from 0->1, we say that A takes "cycle references" on both -// cycles. Taking a cycle reference means incrementing the cycle refcount of -// all defs in the cycle. Since A and B are common to both cycles, A and B's -// cycle refcounts will be incremented by two, and C's will be incremented by -// one. Likewise, when A's external refcount transitions from 1->0, we -// decrement A and B's cycle refcounts by two and C's by one. We collect a -// cyclic type when its cycle refcount drops to zero. A precondition for this -// is that the external refcount has dropped to zero also. -// -// This algorithm is relatively cheap, since it only requires extra work when -// the external refcount on a cyclic type transitions from 0->1 or 1->0. - -static void msgdef_free(upb_msgdef *m); -static void enumdef_free(upb_enumdef *e); -static void unresolveddef_free(struct _upb_unresolveddef *u); - -static void def_free(upb_def *def) -{ - switch(def->type) { - case UPB_DEF_MSG: - msgdef_free(upb_downcast_msgdef(def)); - break; - case UPB_DEF_ENUM: - enumdef_free(upb_downcast_enumdef(def)); - break; - case UPB_DEF_SVC: - assert(false); /* Unimplemented. */ - break; - case UPB_DEF_EXT: - assert(false); /* Unimplemented. */ - break; - case UPB_DEF_UNRESOLVED: - unresolveddef_free(upb_downcast_unresolveddef(def)); - break; - default: - assert(false); - } -} - -// Depth-first search for all cycles that include cycle_base. Returns the -// number of paths from def that lead to cycle_base, which is equivalent to the -// number of cycles def is in that include cycle_base. -// -// open_defs tracks the set of nodes that are currently being visited in the -// search so we can stop the search if we detect a cycles that do not involve -// cycle_base. We can't color the nodes as we go by writing to a member of the -// def, because another thread could be performing the search concurrently. -static int cycle_ref_or_unref(upb_msgdef *m, upb_msgdef *cycle_base, - upb_msgdef **open_defs, int num_open_defs, - bool ref) { - bool found = false; - for(int i = 0; i < num_open_defs; i++) { - if(open_defs[i] == m) { - // We encountered a cycle that did not involve cycle_base. - found = true; - break; - } - } - - if(found || num_open_defs == UPB_MAX_TYPE_CYCLE_LEN) { - return 0; - } else if(m == cycle_base) { - return 1; - } else { - int path_count = 0; - if(cycle_base == NULL) { - cycle_base = m; - } else { - open_defs[num_open_defs++] = m; - } - for(int i = 0; i < m->num_fields; i++) { - upb_fielddef *f = &m->fields[i]; - upb_def *def = f->def; - if(upb_issubmsg(f) && def->is_cyclic) { - upb_msgdef *sub_m = upb_downcast_msgdef(def); - path_count += cycle_ref_or_unref(sub_m, cycle_base, open_defs, - num_open_defs, ref); - } - } - if(ref) { - upb_atomic_add(&m->cycle_refcount, path_count); - } else { - if(upb_atomic_add(&m->cycle_refcount, -path_count)) - def_free(UPB_UPCAST(m)); - } - return path_count; - } -} - -void _upb_def_reftozero(upb_def *def) { - if(def->is_cyclic) { - upb_msgdef *m = upb_downcast_msgdef(def); - upb_msgdef *open_defs[UPB_MAX_TYPE_CYCLE_LEN]; - cycle_ref_or_unref(m, NULL, open_defs, 0, false); - } else { - def_free(def); - } -} - -void _upb_def_cyclic_ref(upb_def *def) { - upb_msgdef *open_defs[UPB_MAX_TYPE_CYCLE_LEN]; - cycle_ref_or_unref(upb_downcast_msgdef(def), NULL, open_defs, 0, true); -} - -static void upb_def_init(upb_def *def, enum upb_def_type type, - upb_strptr fqname) { - def->type = type; - def->is_cyclic = 0; // We detect this later, after resolving refs. - def->search_depth = 0; - def->fqname = upb_string_getref(fqname, UPB_REF_FROZEN); - upb_atomic_refcount_init(&def->refcount, 1); -} - -static void upb_def_uninit(upb_def *def) { - upb_string_unref(def->fqname); -} - -/* upb_unresolveddef **********************************************************/ - -typedef struct _upb_unresolveddef { - upb_def base; - upb_strptr name; -} upb_unresolveddef; - -static upb_unresolveddef *upb_unresolveddef_new(upb_strptr str) { - upb_unresolveddef *def = malloc(sizeof(*def)); - upb_strptr name = upb_string_getref(str, UPB_REF_THREADUNSAFE_READONLY); - upb_def_init(&def->base, UPB_DEF_UNRESOLVED, name); - def->name = name; - return def; -} - -static void unresolveddef_free(struct _upb_unresolveddef *def) { - upb_string_unref(def->name); - upb_def_uninit(&def->base); - free(def); -} - -/* upb_fielddef ***************************************************************/ - -static void fielddef_init(upb_fielddef *f, - google_protobuf_FieldDescriptorProto *fd) -{ - f->type = fd->type; - f->label = fd->label; - f->number = fd->number; - f->name = upb_string_getref(fd->name, UPB_REF_FROZEN); - f->def = NULL; - f->owned = false; - assert(fd->set_flags.has.type_name == upb_hasdef(f)); - if(fd->set_flags.has.type_name) { - f->def = UPB_UPCAST(upb_unresolveddef_new(fd->type_name)); - f->owned = true; - } -} - -static upb_fielddef *fielddef_new(google_protobuf_FieldDescriptorProto *fd) -{ - upb_fielddef *f = malloc(sizeof(*f)); - fielddef_init(f, fd); - return f; -} - -static void fielddef_uninit(upb_fielddef *f) -{ - upb_string_unref(f->name); - if(upb_hasdef(f) && f->owned) { - upb_def_unref(f->def); - } -} - -static void fielddef_free(upb_fielddef *f) { - fielddef_uninit(f); - free(f); -} - -static void fielddef_copy(upb_fielddef *dst, upb_fielddef *src) -{ - *dst = *src; - dst->name = upb_string_getref(src->name, UPB_REF_FROZEN); - if(upb_hasdef(src)) { - upb_def_ref(dst->def); - dst->owned = true; - } -} - -// Callback for sorting fields. -static int compare_fields(upb_fielddef *f1, upb_fielddef *f2) { - // Required fields go before non-required. - bool req1 = f1->label == GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REQUIRED; - bool req2 = f2->label == GOOGLE_PROTOBUF_FIELDDESCRIPTORPROTO_LABEL_REQUIRED; - if(req1 != req2) { - return req2 - req1; - } else { - // Within required and non-required field lists, list in number order. - // TODO: consider ordering by data size to reduce padding. */ - return f1->number - f2->number; - } -} - -static int compare_fielddefs(const void *e1, const void *e2) { - return compare_fields(*(void**)e1, *(void**)e2); -} - -static int compare_fds(const void *e1, const void *e2) { - upb_fielddef f1, f2; - fielddef_init(&f1, *(void**)e1); - fielddef_init(&f2, *(void**)e2); - int ret = compare_fields(&f1, &f2); - fielddef_uninit(&f1); - fielddef_uninit(&f2); - return ret; -} - -void upb_fielddef_sortfds(google_protobuf_FieldDescriptorProto **fds, size_t num) -{ - qsort(fds, num, sizeof(*fds), compare_fds); -} - -static void fielddef_sort(upb_fielddef **defs, size_t num) -{ - qsort(defs, num, sizeof(*defs), compare_fielddefs); -} - -/* upb_msgdef *****************************************************************/ - -static upb_msgdef *msgdef_new(upb_fielddef **fields, int num_fields, - upb_strptr fqname, upb_status *status) -{ - if(num_fields > UPB_MAX_FIELDS) { - upb_seterr(status, UPB_STATUS_ERROR, - "Tried to create a msgdef with more than %d fields", num_fields); - free(fields); - return NULL; - } - upb_msgdef *m = malloc(sizeof(*m)); - upb_def_init(&m->base, UPB_DEF_MSG, fqname); - upb_atomic_refcount_init(&m->cycle_refcount, 0); - upb_inttable_init(&m->itof, num_fields, sizeof(upb_itof_ent)); - upb_strtable_init(&m->ntof, num_fields, sizeof(upb_ntof_ent)); - - m->num_fields = num_fields; - m->set_flags_bytes = div_round_up(m->num_fields, 8); - // These are incremented in the loop. - m->num_required_fields = 0; - m->size = m->set_flags_bytes + 4; // 4 for the refcount. - m->fields = malloc(sizeof(upb_fielddef) * num_fields); - - size_t max_align = 0; - for(int i = 0; i < num_fields; i++) { - upb_fielddef *f = &m->fields[i]; - upb_type_info *type_info = &upb_types[fields[i]->type]; - fielddef_copy(f, fields[i]); - - // General alignment rules are: each member must be at an address that is a - // multiple of that type's alignment. Also, the size of the structure as - // a whole must be a multiple of the greatest alignment of any member. */ - f->field_index = i; - size_t offset = ALIGN_UP(m->size, type_info->align); - f->byte_offset = offset - 4; // Offsets are relative to the refcount. - m->size = offset + type_info->size; - max_align = UPB_MAX(max_align, type_info->align); - if(f->label == UPB_LABEL(REQUIRED)) { - // We currently rely on the fact that required fields are always sorted - // to occur before non-required fields. - m->num_required_fields++; - } - - // Insert into the tables. - upb_itof_ent itof_ent = {{f->number, 0}, f}; - upb_ntof_ent ntof_ent = {{f->name, 0}, f}; - upb_inttable_insert(&m->itof, &itof_ent.e); - upb_strtable_insert(&m->ntof, &ntof_ent.e); - } - - if(max_align > 0) m->size = ALIGN_UP(m->size, max_align); - return m; -} - -static void msgdef_free(upb_msgdef *m) -{ - for (upb_field_count_t i = 0; i < m->num_fields; i++) - fielddef_uninit(&m->fields[i]); - free(m->fields); - upb_strtable_free(&m->ntof); - upb_inttable_free(&m->itof); - upb_def_uninit(&m->base); - free(m); -} - -static void upb_msgdef_resolve(upb_msgdef *m, upb_fielddef *f, upb_def *def) { - (void)m; - if(f->owned) upb_def_unref(f->def); - f->def = def; - // We will later make the ref unowned if it is a part of a cycle. - f->owned = true; - upb_def_ref(def); -} - -/* upb_enumdef ****************************************************************/ - -typedef struct { - upb_strtable_entry e; - uint32_t value; -} ntoi_ent; - -typedef struct { - upb_inttable_entry e; - upb_strptr string; -} iton_ent; - -static upb_enumdef *enumdef_new(google_protobuf_EnumDescriptorProto *ed, - upb_strptr fqname) -{ - upb_enumdef *e = malloc(sizeof(*e)); - upb_def_init(&e->base, UPB_DEF_ENUM, fqname); - int num_values = ed->set_flags.has.value ? - google_protobuf_EnumValueDescriptorProto_array_len(ed->value) : 0; - upb_strtable_init(&e->ntoi, num_values, sizeof(ntoi_ent)); - upb_inttable_init(&e->iton, num_values, sizeof(iton_ent)); - - for(int i = 0; i < num_values; i++) { - google_protobuf_EnumValueDescriptorProto *value = - google_protobuf_EnumValueDescriptorProto_array_get(ed->value, i); - ntoi_ent ntoi_ent = {{value->name, 0}, value->number}; - iton_ent iton_ent = {{value->number, 0}, value->name}; - upb_strtable_insert(&e->ntoi, &ntoi_ent.e); - upb_inttable_insert(&e->iton, &iton_ent.e); - } - return e; -} - -static void enumdef_free(upb_enumdef *e) { - upb_strtable_free(&e->ntoi); - upb_inttable_free(&e->iton); - upb_def_uninit(&e->base); - free(e); -} - -static void fill_iter(upb_enum_iter *iter, ntoi_ent *ent) { - iter->state = ent; - iter->name = ent->e.key; - iter->val = ent->value; -} - -void upb_enum_begin(upb_enum_iter *iter, upb_enumdef *e) { - // We could iterate over either table here; the choice is arbitrary. - ntoi_ent *ent = upb_strtable_begin(&e->ntoi); - iter->e = e; - fill_iter(iter, ent); -} - -void upb_enum_next(upb_enum_iter *iter) { - ntoi_ent *ent = iter->state; - assert(ent); - ent = upb_strtable_next(&iter->e->ntoi, &ent->e); - iter->state = ent; - if(ent) fill_iter(iter, ent); -} - -bool upb_enum_done(upb_enum_iter *iter) { - return iter->state == NULL; -} - -/* symtab internal ***********************************************************/ - -typedef struct { - upb_strtable_entry e; - upb_def *def; -} symtab_ent; - -/* 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; -} - -/* Given a symbol and the base symbol inside which it is defined, find the - * symbol's definition in t. */ -static symtab_ent *resolve(upb_strtable *t, upb_strptr base, upb_strptr symbol) -{ - if(upb_strlen(base) + upb_strlen(symbol) + 1 >= UPB_SYMBOL_MAXLEN || - upb_strlen(symbol) == 0) return NULL; - - if(upb_string_getrobuf(symbol)[0] == UPB_SYMBOL_SEPARATOR) { - // Symbols starting with '.' are absolute, so we do a single lookup. - // Slice to omit the leading '.' - upb_strptr sym_str = upb_strslice(symbol, 1, INT_MAX); - symtab_ent *e = upb_strtable_lookup(t, sym_str); - upb_string_unref(sym_str); - return e; - } else { - // Remove components from base until we find an entry or run out. - upb_strptr sym_str = upb_string_new(); - int baselen = upb_strlen(base); - while(1) { - // sym_str = base[0...base_len] + UPB_SYMBOL_SEPARATOR + symbol - upb_strlen_t len = baselen + upb_strlen(symbol) + 1; - char *buf = upb_string_getrwbuf(sym_str, len); - memcpy(buf, upb_string_getrobuf(base), baselen); - buf[baselen] = UPB_SYMBOL_SEPARATOR; - memcpy(buf + baselen + 1, upb_string_getrobuf(symbol), upb_strlen(symbol)); - - symtab_ent *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(buf, UPB_SYMBOL_SEPARATOR, baselen); - } - } -} - -/* Joins strings together, for example: - * join("Foo.Bar", "Baz") -> "Foo.Bar.Baz" - * join("", "Baz") -> "Baz" - * Caller owns a ref on the returned string. */ -static upb_strptr join(upb_strptr base, upb_strptr name) { - upb_strptr joined = upb_strdup(base); - upb_strlen_t len = upb_strlen(joined); - if(len > 0) { - upb_string_getrwbuf(joined, len + 1)[len] = UPB_SYMBOL_SEPARATOR; - } - upb_strcat(joined, name); - return joined; -} - -static upb_strptr try_define(upb_strtable *t, upb_strptr base, - upb_strptr name, upb_status *status) -{ - if(upb_string_isnull(name)) { - upb_seterr(status, UPB_STATUS_ERROR, - "symbol in context '" UPB_STRFMT "' does not have a name", - UPB_STRARG(base)); - return UPB_STRING_NULL; - } - upb_strptr fqname = join(base, 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 UPB_STRING_NULL; - } - return fqname; -} - -static void insert_enum(upb_strtable *t, - google_protobuf_EnumDescriptorProto *ed, - upb_strptr base, upb_status *status) -{ - upb_strptr name = ed->set_flags.has.name ? ed->name : UPB_STRING_NULL; - upb_strptr fqname = try_define(t, base, name, status); - if(upb_string_isnull(fqname)) return; - - symtab_ent e; - e.e.key = fqname; - e.def = UPB_UPCAST(enumdef_new(ed, fqname)); - upb_strtable_insert(t, &e.e); - upb_string_unref(fqname); -} - -static void insert_message(upb_strtable *t, google_protobuf_DescriptorProto *d, - upb_strptr base, bool sort, upb_status *status) -{ - upb_strptr name = d->set_flags.has.name ? d->name : UPB_STRING_NULL; - upb_strptr fqname = try_define(t, base, name, status); - if(upb_string_isnull(fqname)) return; - - int num_fields = d->set_flags.has.field ? - google_protobuf_FieldDescriptorProto_array_len(d->field) : 0; - symtab_ent e; - e.e.key = fqname; - - // Gather our list of fields, sorting if necessary. - upb_fielddef **fielddefs = malloc(sizeof(*fielddefs) * num_fields); - for (int i = 0; i < num_fields; i++) { - google_protobuf_FieldDescriptorProto *fd = - google_protobuf_FieldDescriptorProto_array_get(d->field, i); - fielddefs[i] = fielddef_new(fd); - } - if(sort) fielddef_sort(fielddefs, num_fields); - - // Create the msgdef with that list of fields. - e.def = UPB_UPCAST(msgdef_new(fielddefs, num_fields, fqname, status)); - - // Cleanup. - for (int i = 0; i < num_fields; i++) fielddef_free(fielddefs[i]); - free(fielddefs); - - if(!upb_ok(status)) goto error; - - upb_strtable_insert(t, &e.e); - - /* Add nested messages and enums. */ - if(d->set_flags.has.nested_type) - for(unsigned int i = 0; i < google_protobuf_DescriptorProto_array_len(d->nested_type); i++) - insert_message(t, google_protobuf_DescriptorProto_array_get(d->nested_type, i), fqname, sort, status); - - if(d->set_flags.has.enum_type) - for(unsigned int i = 0; i < google_protobuf_EnumDescriptorProto_array_len(d->enum_type); i++) - insert_enum(t, google_protobuf_EnumDescriptorProto_array_get(d->enum_type, i), fqname, status); - -error: - // Free the ref we got from try_define(). - upb_string_unref(fqname); -} - -static bool find_cycles(upb_msgdef *m, int search_depth, upb_status *status) -{ - if(search_depth > UPB_MAX_TYPE_DEPTH) { - // There are many situations in upb where we recurse over the type tree - // (like for example, right now) and an absurdly deep tree could cause us - // to stack overflow on systems with very limited stacks. - upb_seterr(status, UPB_STATUS_ERROR, "Type " UPB_STRFMT " was found at " - "depth %d in the type graph, which exceeds the maximum type " - "depth of %d.", UPB_UPCAST(m)->fqname, search_depth, - UPB_MAX_TYPE_DEPTH); - return false; - } else if(UPB_UPCAST(m)->search_depth == 1) { - // Cycle! - int cycle_len = search_depth - 1; - if(cycle_len > UPB_MAX_TYPE_CYCLE_LEN) { - upb_seterr(status, UPB_STATUS_ERROR, "Type " UPB_STRFMT " was involved " - "in a cycle of length %d, which exceeds the maximum type " - "cycle length of %d.", UPB_UPCAST(m)->fqname, cycle_len, - UPB_MAX_TYPE_CYCLE_LEN); - } - return true; - } else if(UPB_UPCAST(m)->search_depth > 0) { - // This was a cycle, but did not originate from the base of our search tree. - // We'll find it when we call find_cycles() on this node directly. - return false; - } else { - UPB_UPCAST(m)->search_depth = ++search_depth; - bool cycle_found = false; - for(upb_field_count_t i = 0; i < m->num_fields; i++) { - upb_fielddef *f = &m->fields[i]; - if(!upb_issubmsg(f)) continue; - upb_def *sub_def = f->def; - upb_msgdef *sub_m = upb_downcast_msgdef(sub_def); - if(find_cycles(sub_m, search_depth, status)) { - cycle_found = true; - UPB_UPCAST(m)->is_cyclic = true; - if(f->owned) { - upb_atomic_unref(&sub_def->refcount); - f->owned = false; - } - } - } - UPB_UPCAST(m)->search_depth = 0; - return cycle_found; - } -} - -static void addfd(upb_strtable *addto, upb_strtable *existingdefs, - google_protobuf_FileDescriptorProto *fd, bool sort, - upb_status *status) -{ - upb_strptr pkg; - if(fd->set_flags.has.package) { - pkg = upb_string_getref(fd->package, UPB_REF_FROZEN); - } else { - pkg = upb_string_new(); - } - - if(fd->set_flags.has.message_type) - for(unsigned int i = 0; i < google_protobuf_DescriptorProto_array_len(fd->message_type); i++) - insert_message(addto, google_protobuf_DescriptorProto_array_get(fd->message_type, i), pkg, sort, status); - - if(fd->set_flags.has.enum_type) - for(unsigned int i = 0; i < google_protobuf_EnumDescriptorProto_array_len(fd->enum_type); i++) - insert_enum(addto, google_protobuf_EnumDescriptorProto_array_get(fd->enum_type, i), pkg, status); - - upb_string_unref(pkg); - - if(!upb_ok(status)) { - // TODO: make sure we don't leak any memory in this case. - return; - } - - /* TODO: handle extensions and services. */ - - // Attempt to resolve all references. - symtab_ent *e; - for(e = upb_strtable_begin(addto); e; e = upb_strtable_next(addto, &e->e)) { - upb_msgdef *m = upb_dyncast_msgdef(e->def); - if(!m) continue; - upb_strptr base = e->e.key; - for(upb_field_count_t i = 0; i < m->num_fields; i++) { - upb_fielddef *f = &m->fields[i]; - if(!upb_hasdef(f)) continue; // No resolving necessary. - upb_strptr name = upb_downcast_unresolveddef(f->def)->name; - symtab_ent *found = resolve(existingdefs, base, name); - if(!found) found = resolve(addto, base, name); - upb_field_type_t expected = upb_issubmsg(f) ? UPB_DEF_MSG : UPB_DEF_ENUM; - if(!found) { - upb_seterr(status, UPB_STATUS_ERROR, - "could not resolve symbol '" UPB_STRFMT "'" - " in context '" UPB_STRFMT "'", - UPB_STRARG(name), UPB_STRARG(base)); - return; - } else if(found->def->type != expected) { - upb_seterr(status, UPB_STATUS_ERROR, "Unexpected type"); - return; - } - upb_msgdef_resolve(m, f, found->def); - } - } - - // Deal with type cycles. - for(e = upb_strtable_begin(addto); e; e = upb_strtable_next(addto, &e->e)) { - upb_msgdef *m = upb_dyncast_msgdef(e->def); - if(!m) continue; - - // Do an initial pass over the graph to check that there are no cycles - // longer than the maximum length. We also mark all cyclic defs as such, - // and decrement refs on cyclic defs. - find_cycles(m, 0, status); - upb_msgdef *open_defs[UPB_MAX_TYPE_CYCLE_LEN]; - cycle_ref_or_unref(m, NULL, open_defs, 0, true); - } -} - -/* upb_symtab *****************************************************************/ - -upb_symtab *upb_symtab_new() -{ - upb_symtab *s = malloc(sizeof(*s)); - upb_atomic_refcount_init(&s->refcount, 1); - upb_rwlock_init(&s->lock); - upb_strtable_init(&s->symtab, 16, sizeof(symtab_ent)); - upb_strtable_init(&s->psymtab, 16, sizeof(symtab_ent)); - - // Add descriptor.proto types to private symtable so we can parse descriptors. - // We know there is only 1. - google_protobuf_FileDescriptorProto *fd = - google_protobuf_FileDescriptorProto_array_get(upb_file_descriptor_set->file, 0); - upb_status status = UPB_STATUS_INIT; - addfd(&s->psymtab, &s->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. - } - upb_static_string name = - UPB_STATIC_STRING_INIT("google.protobuf.FileDescriptorSet"); - upb_strptr nameptr = UPB_STATIC_STRING_PTR_INIT(name); - symtab_ent *e = upb_strtable_lookup(&s->psymtab, nameptr); - assert(e); - s->fds_msgdef = upb_downcast_msgdef(e->def); - return s; -} - -static void free_symtab(upb_strtable *t) -{ - symtab_ent *e; - for(e = upb_strtable_begin(t); e; e = upb_strtable_next(t, &e->e)) - upb_def_unref(e->def); - upb_strtable_free(t); -} - -void _upb_symtab_free(upb_symtab *s) -{ - free_symtab(&s->symtab); - free_symtab(&s->psymtab); - upb_rwlock_destroy(&s->lock); - free(s); -} - -upb_def **upb_symtab_getdefs(upb_symtab *s, int *count, upb_def_type_t type) -{ - upb_rwlock_rdlock(&s->lock); - int total = upb_strtable_count(&s->symtab); - // We may only use part of this, depending on how many symbols are of the - // correct type. - upb_def **defs = malloc(sizeof(*defs) * total); - symtab_ent *e = upb_strtable_begin(&s->symtab); - int i = 0; - for(; e; e = upb_strtable_next(&s->symtab, &e->e)) { - upb_def *def = e->def; - assert(def); - if(type == UPB_DEF_ANY || def->type == type) - defs[i++] = def; - } - upb_rwlock_unlock(&s->lock); - *count = i; - for(i = 0; i < *count; i++) - upb_def_ref(defs[i]); - return defs; -} - -upb_def *upb_symtab_lookup(upb_symtab *s, upb_strptr sym) -{ - upb_rwlock_rdlock(&s->lock); - symtab_ent *e = upb_strtable_lookup(&s->symtab, sym); - upb_def *ret = NULL; - if(e) { - ret = e->def; - upb_def_ref(ret); - } - upb_rwlock_unlock(&s->lock); - return ret; -} - - -upb_def *upb_symtab_resolve(upb_symtab *s, upb_strptr base, upb_strptr symbol) { - upb_rwlock_rdlock(&s->lock); - symtab_ent *e = resolve(&s->symtab, base, symbol); - upb_def *ret = NULL; - if(e) { - ret = e->def; - upb_def_ref(ret); - } - upb_rwlock_unlock(&s->lock); - return ret; -} - -void upb_symtab_addfds(upb_symtab *s, google_protobuf_FileDescriptorSet *fds, - 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. - upb_strtable tmp; - upb_strtable_init(&tmp, 0, sizeof(symtab_ent)); - - { // Read lock scope - upb_rwlock_rdlock(&s->lock); - for(uint32_t i = 0; i < google_protobuf_FileDescriptorProto_array_len(fds->file); i++) { - addfd(&tmp, &s->symtab, google_protobuf_FileDescriptorProto_array_get(fds->file, i), true, status); - if(!upb_ok(status)) { - free_symtab(&tmp); - upb_rwlock_unlock(&s->lock); - return; - } - } - upb_rwlock_unlock(&s->lock); - } - - // Everything was successfully added, copy from the tmp symtable. - { // Write lock scope - upb_rwlock_wrlock(&s->lock); - symtab_ent *e; - for(e = upb_strtable_begin(&tmp); e; e = upb_strtable_next(&tmp, &e->e)) { - // We checked for duplicates when we had only the read lock, but it is - // theoretically possible that a duplicate symbol when we dropped the - // read lock to acquire a write lock. - if(upb_strtable_lookup(&s->symtab, e->e.key)) { - upb_seterr(status, UPB_STATUS_ERROR, "Attempted to insert duplicate " - "symbol: " UPB_STRFMT, UPB_STRARG(e->e.key)); - // To truly handle this situation we would need to remove any symbols - // from tmp that were successfully inserted into s->symtab. Because - // this case is exceedingly unlikely, and because our hashtable - // doesn't support deletions right now, we leave them in there, which - // means we must not call free_symtab(&s->symtab), so we will leak it. - break; - } - upb_strtable_insert(&s->symtab, &e->e); - } - upb_rwlock_unlock(&s->lock); - } - upb_strtable_free(&tmp); - } - return; -} - -void upb_symtab_add_desc(upb_symtab *s, upb_strptr desc, upb_status *status) -{ - upb_msg *fds = upb_msg_new(s->fds_msgdef); - upb_msg_decodestr(fds, s->fds_msgdef, desc, status); - if(!upb_ok(status)) return; - upb_symtab_addfds(s, (google_protobuf_FileDescriptorSet*)fds, status); - upb_msg_unref(fds, s->fds_msgdef); - return; -} diff --git a/src/upb_encoder.h b/src/upb_encoder.h deleted file mode 100644 index b4d0c98..0000000 --- a/src/upb_encoder.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Implements a upb_sink that writes protobuf data to the binary wire format. - * - * For messages that have any submessages, the encoder needs a buffer - * containing the submessage sizes, so they can be properly written at the - * front of each message. Note that groups do *not* have this requirement. - * - * Copyright (c) 2009-2010 Joshua Haberman. See LICENSE for details. - */ - -#ifndef UPB_ENCODER_H_ -#define UPB_ENCODER_H_ - -#include "upb.h" -#include "upb_sink.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* upb_sizebuilder ************************************************************/ - -// A upb_sizebuilder performs a pre-pass on data to be serialized that gathers -// the sizes of submessages. This size data is required for serialization, -// because we have to know at the beginning of a submessage how many encoded -// bytes the submessage will represent. -struct upb_sizebuilder; -typedef struct upb_sizebuilder upb_sizebuilder; - -upb_sizebuilder *upb_sizebuilder_new(upb_msgdef *md); -void upb_sizebuilder_free(upb_sizebuilder *sb); - -void upb_sizebuilder_reset(upb_sizebuilder *sb); - -// Returns a sink that must be used to perform the pre-pass. Note that the -// pre-pass *must* occur in the opposite order from the actual encode that -// follows, and the data *must* be identical both times (except for the -// reversed order. -upb_sink *upb_sizebuilder_sink(upb_sizebuilder *sb); - - -/* upb_encoder ****************************************************************/ - -// A upb_encoder is a upb_sink that emits data to a upb_bytesink in the protocol -// buffer binary wire format. -struct upb_encoder; -typedef struct upb_encoder upb_encoder; - -upb_encoder *upb_encoder_new(upb_msgdef *md); -void upb_encoder_free(upb_encoder *e); - -// Resets the given upb_encoder such that is is ready to begin encoding. The -// upb_sizebuilder "sb" is used to determine submessage sizes; it must have -// previously been initialized by feeding it the same data in reverse order. -// "sb" may be null if and only if the data contains no submessages; groups -// are ok and do not require sizes to be precalculated. The upb_bytesink -// "out" is where the encoded output data will be sent. -// -// Both "sb" and "out" must live until the encoder is either reset or freed. -void upb_encoder_reset(upb_encoder *e, upb_sizebuilder *sb, upb_bytesink *out); - -// The upb_sink to which data can be sent to be encoded. Note that this data -// must be identical to the data that was previously given to the sizebuilder -// (if any). -upb_sink *upb_encoder_sink(upb_encoder *e); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* UPB_ENCODER_H_ */ diff --git a/src/upb_inlinedefs.c b/src/upb_inlinedefs.c deleted file mode 100644 index 5db04f6..0000000 --- a/src/upb_inlinedefs.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * This file, if compiled, will contain standalone (non-inlined) versions of - * all inline functions defined in header files. We don't generally use this - * file since we use "static inline" for inline functions (which will put a - * standalone version of the function in any .o file that needs it, but - * compiling this file and dumping the object file will let us inspect how - * inline functions are compiled, so we keep it around. - * - * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. - */ - -#define INLINE -#include "upb.h" -#include "upb_data.h" -#include "upb_def.h" -#include "upb_parse.h" -#include "upb_table.h" -#include "upb_text.h" diff --git a/src/upb_sink.h b/src/upb_sink.h deleted file mode 100644 index 5dc5b52..0000000 --- a/src/upb_sink.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2010 Joshua Haberman. See LICENSE for details. - * - * upb_sink is a general purpose interface for pushing the contents of a - * protobuf from one component to another in a streaming fashion. We call the - * component that calls a upb_sink a "source". By "pushing" we mean that the - * source calls into the sink; the opposite (where a sink calls into the - * source) is known as "pull". In the push model the source gets the main - * loop; in a pull model the sink does. - * - * This interface is used as general-purpose glue in upb. For example, the - * parser interface works by implementing a source. Likewise the serialization - * simply implements a sink. Copying one protobuf to another is just a matter - * of using one message as a source and another as a sink. - * - * In terms of efficiency, we would generally expect "push" to be faster if the - * source had more state to track, and "pull" to be faster if the sink had more - * state. The reason is that whoever has the main loop can keep state on the - * stack (and possibly even in callee-save registers), whereas the the - * component that is "called into" always needs to reload its state from - * memory. - * - * In terms of programming complexity, it is easier and simpler to have the - * main loop, because you can store state in local variables. - * - * So the assumption inherent in using the push model is that sources are - * generally more complicated and stateful than consumers. For example, in the - * parser case, it has to deal with malformed input and associated errors; in - * comparison, the serializer deals with known-good input. - */ - -#ifndef UPB_SINK_H -#define UPB_SINK_H - -#include "upb_def.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// Each of the upb_sink callbacks returns a status of this type. -typedef enum { - // The normal case, where the consumer wants to continue consuming. - UPB_SINK_CONTINUE, - - // The sink did not consume this value, and wants to halt further processing. - // If the source is resumable, it should save the current state so that when - // resumed, the value that was just provided will be replayed. - UPB_SINK_STOP, - - // The consumer wants to skip to the end of the current submessage and - // continue consuming. If we are at the top-level, the rest of the - // data is discarded. - UPB_SINK_SKIP -} upb_sink_status; - - -typedef struct { - struct upb_sink_callbacks *vtbl; -} upb_sink; - -/* upb_sink callbacks *********************************************************/ - -// The value callback is called for a regular value (ie. not a string or -// submessage). -typedef upb_sink_status (*upb_value_cb)(upb_sink *s, upb_fielddef *f, - upb_value val, upb_status *status); - -// The string callback is called for string data. "str" is the string in which -// the data lives, but it may contain more data than the effective string. -// "start" and "end" indicate the substring of "str" that is the effective -// string. If "start" is <0, this string is a continuation of the previous -// string for this field. If end > upb_strlen(str) then there is more data to -// follow for this string. "end" can also be used as a hint for how much data -// follows, but this is only a hint and is not guaranteed. -// -// The data is supplied this way to give you the opportunity to reference this -// data instead of copying it (perhaps using upb_strslice), or to minimize -// copying if it is unavoidable. -typedef upb_sink_status (*upb_str_cb)(upb_sink *s, upb_fielddef *f, - upb_strptr str, - int32_t start, uint32_t end, - upb_status *status); - -// The start and end callbacks are called when a submessage begins and ends, -// respectively. The caller is responsible for ensuring that the nesting -// level never exceeds UPB_MAX_NESTING. -typedef upb_sink_status (*upb_start_cb)(upb_sink *s, upb_fielddef *f, - upb_status *status); -typedef upb_sink_status (*upb_end_cb)(upb_sink *s, upb_fielddef *f, - upb_status *status); - - -/* upb_sink implementation ****************************************************/ - -typedef struct upb_sink_callbacks { - upb_value_cb value_cb; - upb_str_cb str_cb; - upb_start_cb start_cb; - upb_end_cb end_cb; -} upb_sink_callbacks; - -// These macros implement a mini virtual function dispatch for upb_sink instances. -// This allows functions that call upb_sinks to just write: -// -// upb_sink_onvalue(sink, field, val); -// -// The macro will handle the virtual function lookup and dispatch. We could -// potentially define these later to also be capable of calling a C++ virtual -// method instead of doing the virtual dispatch manually. This would make it -// possible to write C++ sinks in a more natural style without loss of -// efficiency. We could have a flag in upb_sink defining whether it is a C -// sink or a C++ one. -#define upb_sink_onvalue(s, f, val, status) s->vtbl->value_cb(s, f, val, status) -#define upb_sink_onstr(s, f, str, start, end, status) s->vtbl->str_cb(s, f, str, start, end, status) -#define upb_sink_onstart(s, f, status) s->vtbl->start_cb(s, f, status) -#define upb_sink_onend(s, f, status) s->vtbl->end_cb(s, f, status) - -// Initializes a plain C visitor with the given vtbl. The sink must have been -// allocated separately. -INLINE void upb_sink_init(upb_sink *s, upb_sink_callbacks *vtbl) { - s->vtbl = vtbl; -} - - -/* upb_bytesink ***************************************************************/ - -// A upb_bytesink is like a upb_sync, but for bytes instead of structured -// protobuf data. Parsers implement upb_bytesink and push to a upb_sink, -// serializers do the opposite (implement upb_sink and push to upb_bytesink). -// -// The two simplest kinds of sinks are "write to string" and "write to FILE*". - -// A forward declaration solely for the benefit of declaring upb_byte_cb below. -// Always prefer upb_bytesink (without the "struct" keyword) instead. -struct _upb_bytesink; - -// The single bytesink callback; it takes the bytes to be written and returns -// how many were successfully written. If the return value is <0, the caller -// should stop processing. -typedef int32_t (*upb_byte_cb)(struct _upb_bytesink *s, upb_strptr str, - uint32_t start, uint32_t end, - upb_status *status); - -typedef struct _upb_bytesink { - upb_byte_cb *cb; -} upb_bytesink; - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/src/upb_string.h b/src/upb_string.h deleted file mode 100644 index 0516377..0000000 --- a/src/upb_string.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2010 Joshua Haberman. See LICENSE for details. - * - * This file defines a simple string type. The overriding goal of upb_string - * is to avoid memcpy(), malloc(), and free() wheverever possible, while - * keeping both CPU and memory overhead low. Throughout upb there are - * situations where one wants to reference all or part of another string - * without copying. upb_string provides APIs for doing this. - * - * Characteristics of upb_string: - * - strings are reference-counted. - * - strings are logically immutable. - * - if a string has no other referents, it can be "recycled" into a new string - * without having to reallocate the upb_string. - * - strings can be substrings of other strings (owning a ref on the source - * string). - * - strings can refer to memory that they do not own, in which case we avoid - * copies if possible (the exact strategy for doing this can vary). - * - strings are not thread-safe by default, but can be made so by calling a - * function. This is not the default because it causes extra CPU overhead. - */ - -#ifndef UPB_STRING_H -#define UPB_STRING_H - -#include <assert.h> -#include <string.h> -#include "upb_atomic.h" - -#ifdef __cplusplus -extern "C" { -#endif - -// All members of this struct are private, and may only be read/written through -// the associated functions. Also, strings may *only* be allocated on the heap. -typedef struct _upb_string { - char *ptr; - uint32_t len; - uint32_t size; - upb_atomic_refcount_t refcount; - union { - // Used if this is a slice of another string. - struct _upb_string *src; - // Used if this string is referencing external unowned memory. - upb_stomic_refcount_t reader_count; - } extra; -} upb_string; - -// Returns a newly-created, empty, non-finalized string. When the string is no -// longer needed, it should be unref'd, never freed directly. -upb_string *upb_string_new(); - -// Releases a ref on the given string, which may free the memory. -void upb_string_unref(upb_string *str); - -// Returns a string with the same contents as "str". The caller owns a ref on -// the returned string, which may or may not be the same object as "str. -upb_string *upb_string_getref(upb_string *str); - -// Returns the length of the string. -INLINE upb_strlen_t upb_string_len(upb_string *str) { return str->len; } - -// Use to read the bytes of the string. The caller *must* call -// upb_string_endread() after the data has been read. The window between -// upb_string_getrobuf() and upb_string_endread() should be kept as short -// as possible. No other functions may be called on the string during this -// window except upb_string_len(). -INLINE const char *upb_string_getrobuf(upb_string *str) { return str->ptr; } -INLINE void upb_string_endread(upb_string *str); - -// Attempts to recycle the string "str" so it may be reused and have different -// data written to it. The returned string is either "str" if it could be -// recycled or a newly created string if "str" has other references. -upb_string *upb_string_tryrecycle(upb_string *str); - -// The three options for setting the contents of a string. These may only be -// called when a string is first created or recycled; once other functions have -// been called on the string, these functions are not allowed until the string -// is recycled. - -// Gets a pointer suitable for writing to the string, which is guaranteed to -// have at least "len" bytes of data available. The size of the string will -// become "len". -char *upb_string_getrwbuf(upb_string *str, upb_strlen_t len); - -// Sets the contents of "str" to be the given substring of "target_str", to -// which the caller must own a ref. -void upb_string_substr(upb_string *str, upb_string *target_str, - upb_strlen_t start, upb_strlen_t len); - -// Makes the string "str" a reference to the given string data. The caller -// guarantees that the given string data will not change or be deleted until -// a matching call to upb_string_detach(). -void upb_string_attach(upb_string *str, char *ptr, upb_strlen_t len); -void upb_string_detach(upb_string *str); - -/* upb_string library functions ***********************************************/ - -// Named like their <string.h> counterparts, these are all safe against buffer -// overflow. These only use the public upb_string interface. - -// More efficient than upb_strcmp if all you need is to test equality. -INLINE bool upb_streql(upb_string *s1, upb_string *s2) { - upb_strlen_t len = upb_string_len(s1); - if(len != upb_string_len(s2)) { - return false; - } else { - bool ret = - memcmp(upb_string_getrobuf(s1), upb_string_getrobuf(s2), len) == 0; - upb_string_endread(s1); - upb_string_endread(s2); - return ret; - } -} - -// Like strcmp(). -int upb_strcmp(upb_string *s1, upb_string *s2); - -// Like upb_strcpy, but copies from a buffer and length. -INLINE void upb_strcpylen(upb_string *dest, const void *src, upb_strlen_t len) { - memcpy(upb_string_getrwbuf(dest, len), src, len); -} - -// Replaces the contents of "dest" with the contents of "src". -INLINE void upb_strcpy(upb_string *dest, upb_string *src) { - upb_strcpylen(dest, upb_string_getrobuf(src), upb_strlen(src)); - upb_string_endread(src); -} - -// Like upb_strcpy, but copies from a NULL-terminated string. -INLINE void upb_strcpyc(upb_string *dest, const char *src) { - // This does two passes over src, but that is necessary unless we want to - // repeatedly re-allocate dst, which seems worse. - upb_strcpylen(dest, src, strlen(src)); -} - -// Returns a new string whose contents are a copy of s. -upb_string *upb_strdup(upb_string *s); - -// Like upb_strdup(), but duplicates a given buffer and length. -INLINE upb_string *upb_strduplen(const void *src, upb_strlen_t len) { - upb_string *s = upb_string_new(); - upb_strcpylen(s, src, len); - return s; -} - -// Like upb_strdup(), but duplicates a C NULL-terminated string. -upb_string *upb_strdupc(const char *src); - -// Appends 'append' to 's' in-place, resizing s if necessary. -void upb_strcat(upb_string *s, upb_string *append); - -// Returns a new string that is a substring of the given string. -upb_string *upb_strslice(upb_string *s, int offset, int len); - -// Reads an entire file into a newly-allocated string. -upb_string *upb_strreadfile(const char *filename); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif diff --git a/src/upb_text.c b/src/upb_text.c deleted file mode 100644 index 8662269..0000000 --- a/src/upb_text.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. - */ - -#include <inttypes.h> -#include "descriptor.h" -#include "upb_text.h" -#include "upb_data.h" - -void upb_text_printval(upb_field_type_t type, upb_value val, FILE *file) -{ -#define CASE(fmtstr, member) fprintf(file, fmtstr, val.member); break; - switch(type) { - case UPB_TYPE(DOUBLE): - CASE("%0.f", _double); - case UPB_TYPE(FLOAT): - CASE("%0.f", _float) - case UPB_TYPE(INT64): - case UPB_TYPE(SFIXED64): - case UPB_TYPE(SINT64): - CASE("%" PRId64, int64) - case UPB_TYPE(UINT64): - case UPB_TYPE(FIXED64): - CASE("%" PRIu64, uint64) - case UPB_TYPE(INT32): - case UPB_TYPE(SFIXED32): - case UPB_TYPE(SINT32): - CASE("%" PRId32, int32) - case UPB_TYPE(UINT32): - case UPB_TYPE(FIXED32): - case UPB_TYPE(ENUM): - CASE("%" PRIu32, uint32); - case UPB_TYPE(BOOL): - CASE("%hhu", _bool); - case UPB_TYPE(STRING): - case UPB_TYPE(BYTES): - /* TODO: escaping. */ - fprintf(file, "\"" UPB_STRFMT "\"", UPB_STRARG(val.str)); break; - } -} - -static void print_indent(upb_text_printer *p, FILE *stream) -{ - if(!p->single_line) - for(int i = 0; i < p->indent_depth; i++) - fprintf(stream, " "); -} - -void upb_text_printfield(upb_text_printer *p, upb_strptr name, - upb_field_type_t valtype, upb_value val, - FILE *stream) -{ - print_indent(p, stream); - fprintf(stream, UPB_STRFMT ":", UPB_STRARG(name)); - upb_text_printval(valtype, val, stream); - if(p->single_line) - fputc(' ', stream); - else - fputc('\n', stream); -} - -void upb_text_push(upb_text_printer *p, upb_strptr submsg_type, FILE *stream) -{ - print_indent(p, stream); - fprintf(stream, UPB_STRFMT " {", UPB_STRARG(submsg_type)); - if(!p->single_line) fputc('\n', stream); - p->indent_depth++; -} - -void upb_text_pop(upb_text_printer *p, FILE *stream) -{ - p->indent_depth--; - print_indent(p, stream); - fprintf(stream, "}\n"); -} - -static void printval(upb_text_printer *printer, upb_value v, upb_fielddef *f, - FILE *stream); - -static void printmsg(upb_text_printer *printer, upb_msg *msg, upb_msgdef *md, - FILE *stream) -{ - for(upb_field_count_t i = 0; i < md->num_fields; i++) { - upb_fielddef *f = &md->fields[i]; - if(!upb_msg_has(msg, f)) continue; - upb_value v = upb_msg_get(msg, f); - if(upb_isarray(f)) { - upb_arrayptr arr = v.arr; - for(uint32_t j = 0; j < upb_array_len(arr); j++) { - upb_value elem = upb_array_get(arr, f, j); - printval(printer, elem, f, stream); - } - } else { - printval(printer, v, f, stream); - } - } -} - -static void printval(upb_text_printer *printer, upb_value v, upb_fielddef *f, - FILE *stream) -{ - if(upb_issubmsg(f)) { - upb_text_push(printer, f->name, stream); - printmsg(printer, v.msg, upb_downcast_msgdef(f->def), stream); - upb_text_pop(printer, stream); - } else { - upb_text_printfield(printer, f->name, f->type, v, stream); - } -} - - -void upb_msg_print(upb_msg *msg, upb_msgdef *md, bool single_line, - FILE *stream) -{ - upb_text_printer printer; - upb_text_printer_init(&printer, single_line); - printmsg(&printer, msg, md, stream); -} - diff --git a/src/upb_text.h b/src/upb_text.h deleted file mode 100644 index d89c9d6..0000000 --- a/src/upb_text.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. - */ - -#ifndef UPB_TEXT_H_ -#define UPB_TEXT_H_ - -#include "upb.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - int indent_depth; - bool single_line; -} upb_text_printer; - -INLINE void upb_text_printer_init(upb_text_printer *p, bool single_line) { - p->indent_depth = 0; - p->single_line = single_line; -} -void upb_text_printval(upb_field_type_t type, upb_value p, FILE *file); -void upb_text_printfield(upb_text_printer *p, upb_strptr name, - upb_field_type_t valtype, upb_value val, FILE *stream); -void upb_text_push(upb_text_printer *p, upb_strptr submsg_type, - FILE *stream); -void upb_text_pop(upb_text_printer *p, FILE *stream); - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#endif /* UPB_TEXT_H_ */ diff --git a/stream/upb_decoder.c b/stream/upb_decoder.c new file mode 100644 index 0000000..3a279a1 --- /dev/null +++ b/stream/upb_decoder.c @@ -0,0 +1,429 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2008-2009 Joshua Haberman. See LICENSE for details. + */ + +#include "upb_decoder.h" + +#include <inttypes.h> +#include <stddef.h> +#include <stdlib.h> +#include "upb_def.h" + +/* Pure Decoding **************************************************************/ + +// The key fast-path varint-decoding routine. Here we can assume we have at +// least UPB_MAX_VARINT_ENCODED_SIZE bytes available. There are a lot of +// possibilities for optimization/experimentation here. +INLINE bool upb_decode_varint_fast(const char **ptr, uint64_t *val, + upb_status *status) { + const char *p = *ptr; + uint32_t low, high = 0; + uint32_t b; + b = *(p++); low = (b & 0x7f) ; if(!(b & 0x80)) goto done; + b = *(p++); low |= (b & 0x7f) << 7; if(!(b & 0x80)) goto done; + b = *(p++); low |= (b & 0x7f) << 14; if(!(b & 0x80)) goto done; + b = *(p++); low |= (b & 0x7f) << 21; if(!(b & 0x80)) goto done; + b = *(p++); low |= (b & 0x7f) << 28; + high = (b & 0x7f) >> 3; if(!(b & 0x80)) goto done; + b = *(p++); high |= (b & 0x7f) << 4; if(!(b & 0x80)) goto done; + b = *(p++); high |= (b & 0x7f) << 11; if(!(b & 0x80)) goto done; + b = *(p++); high |= (b & 0x7f) << 18; if(!(b & 0x80)) goto done; + b = *(p++); high |= (b & 0x7f) << 25; if(!(b & 0x80)) goto done; + + upb_seterr(status, UPB_ERROR, "Unterminated varint"); + return false; +done: + *ptr = p; + *val = ((uint64_t)high << 32) | low; + return true; +} + + +/* Decoding/Buffering of individual values ************************************/ + +// Performs zig-zag decoding, which is used by sint32 and sint64. +INLINE int32_t upb_zzdec_32(uint32_t n) { return (n >> 1) ^ -(int32_t)(n & 1); } +INLINE int64_t upb_zzdec_64(uint64_t n) { return (n >> 1) ^ -(int64_t)(n & 1); } + +// 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; + size_t end_offset; // For groups, 0. +} upb_decoder_frame; + +struct upb_decoder { + // Immutable state of the decoder. + upb_src src; + upb_dispatcher dispatcher; + upb_bytesrc *bytesrc; + upb_msgdef *toplevel_msgdef; + upb_decoder_frame stack[UPB_MAX_NESTING]; + + // Mutable state of the decoder. + + // Where we will store any errors that occur. + upb_status *status; + + // Stack entries store the offset where the submsg ends (for groups, 0). + upb_decoder_frame *top, *limit; + + // Current input buffer. + upb_string *buf; + + // The offset within the overall stream represented by the *beginning* of buf. + size_t buf_stream_offset; +}; + +typedef struct { + // Our current position in the data buffer. + const char *ptr; + + // End of this submessage, relative to *ptr. + const char *submsg_end; + + // Number of bytes available at ptr. + size_t len; + + // Msgdef for the current level. + upb_msgdef *msgdef; +} upb_dstate; + +// Constant used to signal that the submessage is a group and therefore we +// don't know its end offset. This cannot be the offset of a real submessage +// end because it takes at least one byte to begin a submessage. +#define UPB_GROUP_END_OFFSET 0 +#define UPB_MAX_VARINT_ENCODED_SIZE 10 + +INLINE void upb_dstate_advance(upb_dstate *s, size_t len) { + s->ptr += len; + s->len -= len; +} + +INLINE void upb_dstate_setmsgend(upb_decoder *d, upb_dstate *s) { + s->submsg_end = (d->top->end_offset == UPB_GROUP_END_OFFSET) ? + (void*)UINTPTR_MAX : + upb_string_getrobuf(d->buf) + (d->top->end_offset - d->buf_stream_offset); +} + +static upb_flow_t upb_pop(upb_decoder *d, upb_dstate *s); + +// Called only from the slow path, this function copies the next "len" bytes +// from the stream to "data", adjusting the dstate appropriately. +static bool upb_getbuf(upb_decoder *d, void *data, size_t bytes_wanted, + upb_dstate *s) { + while (1) { + size_t to_copy = UPB_MIN(bytes_wanted, s->len); + memcpy(data, s->ptr, to_copy); + upb_dstate_advance(s, to_copy); + bytes_wanted -= to_copy; + if (bytes_wanted == 0) { + upb_dstate_setmsgend(d, s); + return true; + } + + // Get next buffer. + if (d->buf) d->buf_stream_offset += upb_string_len(d->buf); + upb_string_recycle(&d->buf); + if (!upb_bytesrc_getstr(d->bytesrc, d->buf, d->status)) return false; + s->ptr = upb_string_getrobuf(d->buf); + s->len = upb_string_len(d->buf); + } +} + +// We use this path when we don't have UPB_MAX_VARINT_ENCODED_SIZE contiguous +// bytes available in our current buffer. We don't inline this because we +// accept that it will be slow and we don't want to pay for two copies of it. +static bool upb_decode_varint_slow(upb_decoder *d, upb_dstate *s, + upb_value *val) { + char byte = 0x80; + uint64_t val64 = 0; + int bitpos; + for(bitpos = 0; + bitpos < 70 && (byte & 0x80) && upb_getbuf(d, &byte, 1, s); + bitpos += 7) + val64 |= ((uint64_t)byte & 0x7F) << bitpos; + + if(bitpos == 70) { + upb_seterr(d->status, UPB_ERROR, + "Varint was unterminated after 10 bytes.\n"); + return false; + } else if (d->status->code == UPB_EOF && bitpos == 0) { + // Regular EOF. + return false; + } else if (d->status->code == UPB_EOF && (byte & 0x80)) { + upb_seterr(d->status, UPB_ERROR, + "Provided data ended in the middle of a varint.\n"); + return false; + } else { + // Success. + upb_value_setraw(val, val64); + return true; + } +} + +typedef struct { + upb_wire_type_t wire_type; + upb_field_number_t field_number; +} upb_tag; + +INLINE bool upb_decode_tag(upb_decoder *d, upb_dstate *s, upb_tag *tag) { + const char *p = s->ptr; + uint32_t tag_int; + upb_value val; + // Nearly all tag varints will be either 1 byte (1-16) or 2 bytes (17-2048). + if (s->len < 2) goto slow; // unlikely. + tag_int = *p & 0x7f; + if ((*(p++) & 0x80) == 0) goto done; // predictable if fields are in order + tag_int |= (*p & 0x7f) << 7; + if ((*(p++) & 0x80) == 0) goto done; // likely +slow: + // Decode a full varint starting over from ptr. + if (!upb_decode_varint_slow(d, s, &val)) return false; + tag_int = upb_value_getint64(val); + p = s->ptr; // Trick the next line into not overwriting us. +done: + upb_dstate_advance(s, p - s->ptr); + tag->wire_type = (upb_wire_type_t)(tag_int & 0x07); + tag->field_number = tag_int >> 3; + return true; +} + +INLINE bool upb_decode_varint(upb_decoder *d, upb_dstate *s, upb_value *val) { + if (s->len >= UPB_MAX_VARINT_ENCODED_SIZE) { + // Common (fast) case. + uint64_t val64; + const char *p = s->ptr; + if (!upb_decode_varint_fast(&p, &val64, d->status)) return false; + upb_dstate_advance(s, p - s->ptr); + upb_value_setraw(val, val64); + return true; + } else { + return upb_decode_varint_slow(d, s, val); + } +} + +INLINE bool upb_decode_fixed(upb_decoder *d, upb_wire_type_t wt, + upb_dstate *s, upb_value *val) { + static const char table[] = {0, 8, 0, 0, 0, 4}; + size_t bytes = table[wt]; + if (s->len >= bytes) { + // Common (fast) case. + memcpy(&val, s->ptr, bytes); + upb_dstate_advance(s, bytes); + } else { + if (!upb_getbuf(d, &val, bytes, s)) return false; + } + return true; +} + +// "val" initially holds the length of the string, this is replaced by the +// contents of the string. +INLINE bool upb_decode_string(upb_decoder *d, upb_value *val, upb_string **str, + upb_dstate *s) { + upb_string_recycle(str); + uint32_t strlen = upb_value_getint32(*val); + if (s->len >= strlen) { + // Common (fast) case. + upb_string_substr(*str, d->buf, s->ptr - upb_string_getrobuf(d->buf), strlen); + upb_dstate_advance(s, strlen); + } else { + if (!upb_getbuf(d, upb_string_getrwbuf(*str, strlen), strlen, s)) + return false; + } + upb_value_setstr(val, *str); + return true; +} + + +/* The main decoding loop *****************************************************/ + +extern upb_wire_type_t upb_expected_wire_types[]; +// Returns true if wt is the correct on-the-wire type for ft. +INLINE bool upb_check_type(upb_wire_type_t wt, upb_fieldtype_t ft) { + // This doesn't currently support packed arrays. + return upb_types[ft].native_wire_type == wt; +} + +static upb_flow_t upb_push(upb_decoder *d, upb_dstate *s, upb_fielddef *f, + upb_value submsg_len, upb_fieldtype_t type) { + d->top++; + if(d->top >= d->limit) { + upb_seterr(d->status, UPB_ERROR, "Nesting too deep."); + return UPB_ERROR; + } + d->top->end_offset = (type == UPB_TYPE(GROUP)) ? + UPB_GROUP_END_OFFSET : + d->buf_stream_offset + (s->ptr - upb_string_getrobuf(d->buf)) + + upb_value_getint32(submsg_len); + d->top->msgdef = upb_downcast_msgdef(f->def); + upb_dstate_setmsgend(d, s); + return upb_dispatch_startsubmsg(&d->dispatcher, f); +} + +static upb_flow_t upb_pop(upb_decoder *d, upb_dstate *s) { + d->top--; + upb_dstate_setmsgend(d, s); + return upb_dispatch_endsubmsg(&d->dispatcher); +} + +void upb_decoder_run(upb_src *src, upb_status *status) { + upb_decoder *d = (upb_decoder*)src; + d->status = status; + // We put our dstate on the stack so the compiler knows they can't be changed + // by external code (like when we dispatch a callback). We must be sure not + // to let its address escape this source file. + upb_dstate state = {NULL, (void*)0x1, 0, d->top->msgdef}; + upb_string *str = NULL; + +// TODO: handle UPB_SKIPSUBMSG +#define CHECK_FLOW(expr) if ((expr) != UPB_CONTINUE) goto err +#define CHECK(expr) if (!expr) goto err; + + CHECK_FLOW(upb_dispatch_startmsg(&d->dispatcher)); + + // Main loop: executed once per tag/field pair. + while(1) { + // Check for end-of-submessage. + while (state.ptr >= state.submsg_end) { + if (state.ptr > state.submsg_end) { + upb_seterr(d->status, UPB_ERROR, "Bad submessage end."); + goto err; + } + CHECK_FLOW(upb_pop(d, &state)); + } + + // Parse/handle tag. + upb_tag tag; + if (!upb_decode_tag(d, &state, &tag)) { + if (status->code == UPB_EOF && d->top == d->stack) { + // Normal end-of-file. + upb_clearerr(status); + CHECK_FLOW(upb_dispatch_endmsg(&d->dispatcher)); + upb_string_unref(str); + return; + } else { + if (status->code == UPB_EOF) { + upb_seterr(status, UPB_ERROR, + "Input ended in the middle of a submessage."); + } + goto err; + } + } + + // Decode wire data. Hopefully this branch will predict pretty well + // since most types will read a varint here. + upb_value val; + switch (tag.wire_type) { + case UPB_WIRE_TYPE_START_GROUP: + break; // Nothing to do now, below we will push appropriately. + case UPB_WIRE_TYPE_END_GROUP: + if(d->top->end_offset != UPB_GROUP_END_OFFSET) { + upb_seterr(status, UPB_ERROR, "Unexpected END_GROUP tag."); + goto err; + } + CHECK_FLOW(upb_pop(d, &state)); + continue; // We have no value to dispatch. + case UPB_WIRE_TYPE_VARINT: + case UPB_WIRE_TYPE_DELIMITED: + // For the delimited case we are parsing the length. + CHECK(upb_decode_varint(d, &state, &val)); + break; + case UPB_WIRE_TYPE_32BIT: + case UPB_WIRE_TYPE_64BIT: + CHECK(upb_decode_fixed(d, tag.wire_type, &state, &val)); + break; + } + + // Look up field by tag number. + upb_fielddef *f = upb_msgdef_itof(d->top->msgdef, tag.field_number); + + if (!f) { + if (tag.wire_type == UPB_WIRE_TYPE_DELIMITED) + CHECK(upb_decode_string(d, &val, &str, &state)); + CHECK_FLOW(upb_dispatch_unknownval(&d->dispatcher, tag.field_number, val)); + } else if (!upb_check_type(tag.wire_type, f->type)) { + // TODO: put more details in this error msg. + upb_seterr(status, UPB_ERROR, "Field had incorrect type."); + goto err; + } + + // Perform any further massaging of the data now that we have the fielddef. + // Now we can distinguish strings from submessages, and we know about + // zig-zag-encoded types. + // TODO: handle packed encoding. + // TODO: if we were being paranoid, we could check for 32-bit-varint types + // that the top 32 bits all match the highest bit of the low 32 bits. + // If this is not true we are losing data. But the main protobuf library + // doesn't check this, and it would slow us down, so pass for now. + switch (f->type) { + case UPB_TYPE(MESSAGE): + case UPB_TYPE(GROUP): + CHECK_FLOW(upb_push(d, &state, f, val, f->type)); + continue; // We have no value to dispatch. + case UPB_TYPE(STRING): + case UPB_TYPE(BYTES): + CHECK(upb_decode_string(d, &val, &str, &state)); + break; + case UPB_TYPE(SINT32): + upb_value_setint32(&val, upb_zzdec_32(upb_value_getint32(val))); + break; + case UPB_TYPE(SINT64): + upb_value_setint64(&val, upb_zzdec_64(upb_value_getint64(val))); + break; + default: + break; // Other types need no further processing at this point. + } + CHECK_FLOW(upb_dispatch_value(&d->dispatcher, f, val)); + } + +err: + upb_string_unref(str); + if (upb_ok(status)) { + upb_seterr(status, UPB_ERROR, "Callback returned UPB_BREAK"); + } +} + +void upb_decoder_sethandlers(upb_src *src, upb_handlers *handlers) { + upb_decoder *d = (upb_decoder*)src; + upb_dispatcher_reset(&d->dispatcher, handlers); + d->top = d->stack; + d->buf_stream_offset = 0; + d->top->msgdef = d->toplevel_msgdef; + // 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; +} + +upb_decoder *upb_decoder_new(upb_msgdef *msgdef) { + static upb_src_vtbl vtbl = { + &upb_decoder_sethandlers, + &upb_decoder_run, + }; + upb_decoder *d = malloc(sizeof(*d)); + upb_src_init(&d->src, &vtbl); + upb_dispatcher_init(&d->dispatcher); + d->toplevel_msgdef = msgdef; + d->limit = &d->stack[UPB_MAX_NESTING]; + d->buf = NULL; + return d; +} + +void upb_decoder_reset(upb_decoder *d, upb_bytesrc *bytesrc) { + d->bytesrc = bytesrc; + d->top = &d->stack[0]; + d->top->msgdef = d->toplevel_msgdef; + // Never want to end top-level message, so treat it like a group. + d->top->end_offset = UPB_GROUP_END_OFFSET; + upb_string_unref(d->buf); + d->buf = NULL; +} + +void upb_decoder_free(upb_decoder *d) { + upb_string_unref(d->buf); + free(d); +} + +upb_src *upb_decoder_src(upb_decoder *d) { return &d->src; } diff --git a/stream/upb_decoder.h b/stream/upb_decoder.h new file mode 100644 index 0000000..6ba4d77 --- /dev/null +++ b/stream/upb_decoder.h @@ -0,0 +1,53 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * upb_decoder implements a high performance, streaming decoder for protobuf + * data that works by implementing upb_src and getting its data from a + * upb_bytesrc. + * + * The decoder does not currently support non-blocking I/O, in the sense that + * if the bytesrc returns UPB_STATUS_TRYAGAIN it is not possible to resume the + * decoder when data becomes available again. Support for this could be added, + * but it would add complexity and perhaps cost efficiency also. + * + * Copyright (c) 2009-2010 Joshua Haberman. See LICENSE for details. + */ + +#ifndef UPB_DECODER_H_ +#define UPB_DECODER_H_ + +#include <stdbool.h> +#include <stdint.h> +#include "upb_def.h" +#include "upb_stream.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* upb_decoder *****************************************************************/ + +// A upb_decoder decodes the binary protocol buffer format, writing the data it +// decodes to a upb_sink. +struct upb_decoder; +typedef struct upb_decoder upb_decoder; + +// Allocates and frees a upb_decoder, respectively. +upb_decoder *upb_decoder_new(upb_msgdef *md); +void upb_decoder_free(upb_decoder *d); + +// Resets the internal state of an already-allocated decoder. This puts it in a +// state where it has not seen any data, and expects the next data to be from +// the beginning of a new protobuf. Parsers must be reset before they can be +// used. A decoder can be reset multiple times. +void upb_decoder_reset(upb_decoder *d, upb_bytesrc *bytesrc); + +// Returns a upb_src pointer by which the decoder can be used. The returned +// upb_src is invalidated by upb_decoder_reset() or upb_decoder_free(). +upb_src *upb_decoder_src(upb_decoder *d); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_DECODER_H_ */ diff --git a/src/upb_encoder.c b/stream/upb_encoder.c index f1156a8..304a423 100644 --- a/src/upb_encoder.c +++ b/stream/upb_encoder.c @@ -38,9 +38,6 @@ static size_t upb_f_uint32_t_size(uint32_t val) { return sizeof(uint32_t); } -// The biggest possible single value is a 10-byte varint. -#define UPB_MAX_ENCODED_SIZE 10 - /* Functions to write wire values. ********************************************/ diff --git a/stream/upb_encoder.h b/stream/upb_encoder.h new file mode 100644 index 0000000..e879b0b --- /dev/null +++ b/stream/upb_encoder.h @@ -0,0 +1,56 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Implements a upb_sink that writes protobuf data to the binary wire format. + * + * For messages that have any submessages, the encoder needs a buffer + * containing the submessage sizes, so they can be properly written at the + * front of each message. Note that groups do *not* have this requirement. + * + * Copyright (c) 2009-2010 Joshua Haberman. See LICENSE for details. + */ + +#ifndef UPB_ENCODER_H_ +#define UPB_ENCODER_H_ + +#include "upb.h" +#include "upb_srcsink.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* upb_encoder ****************************************************************/ + +// A upb_encoder is a upb_sink that emits data to a upb_bytesink in the protocol +// buffer binary wire format. +struct upb_encoder; +typedef struct upb_encoder upb_encoder; + +upb_encoder *upb_encoder_new(upb_msgdef *md); +void upb_encoder_free(upb_encoder *e); + +// Resets the given upb_encoder such that is is ready to begin encoding, +// outputting data to "bytesink" (which must live until the encoder is +// reset or destroyed). +void upb_encoder_reset(upb_encoder *e, upb_bytesink *bytesink); + +// Returns the upb_sink to which data can be written. The sink is invalidated +// when the encoder is reset or destroyed. Note that if the client wants to +// encode any length-delimited submessages it must first call +// upb_encoder_buildsizes() below. +upb_sink *upb_encoder_sink(upb_encoder *e); + +// Call prior to pushing any data with embedded submessages. "src" must yield +// exactly the same data as what will next be encoded, but in reverse order. +// The encoder iterates over this data in order to determine the sizes of the +// submessages. If any errors are returned by the upb_src, the status will +// be saved in *status. If the client is sure that the upb_src will not throw +// any errors, "status" may be NULL. +void upb_encoder_buildsizes(upb_encoder *e, upb_src *src, upb_status *status); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_ENCODER_H_ */ diff --git a/stream/upb_stdio.c b/stream/upb_stdio.c new file mode 100644 index 0000000..8857677 --- /dev/null +++ b/stream/upb_stdio.c @@ -0,0 +1,104 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2010 Joshua Haberman. See LICENSE for details. + */ + +#include "upb_stdio.h" + +#include <stddef.h> +#include <stdlib.h> +#include "upb_string.h" + +// We can make this configurable if necessary. +#define BLOCK_SIZE 4096 + +struct upb_stdio { + upb_bytesrc bytesrc; + upb_bytesink bytesink; + FILE *file; +}; + +void upb_stdio_reset(upb_stdio *stdio, FILE* file) { + stdio->file = file; +} + + +/* upb_bytesrc methods ********************************************************/ + +static upb_strlen_t upb_stdio_read(upb_bytesrc *src, void *buf, + upb_strlen_t count, upb_status *status) { + upb_stdio *stdio = (upb_stdio*)src; + assert(count > 0); + size_t read = fread(buf, 1, count, stdio->file); + if(read < (size_t)count) { + // Error or EOF. + if(feof(stdio->file)) { + upb_seterr(status, UPB_EOF, ""); + return read; + } else if(ferror(stdio->file)) { + upb_seterr(status, UPB_ERROR, "Error reading from stdio stream."); + return -1; + } + } + return read; +} + +static bool upb_stdio_getstr(upb_bytesrc *src, upb_string *str, + upb_status *status) { + upb_strlen_t read = upb_stdio_read( + src, upb_string_getrwbuf(str, BLOCK_SIZE), BLOCK_SIZE, status); + if (read <= 0) return false; + upb_string_getrwbuf(str, read); + return true; +} + + +/* upb_bytesink methods *******************************************************/ + +upb_strlen_t upb_stdio_putstr(upb_bytesink *sink, upb_string *str, upb_status *status) { + upb_stdio *stdio = (upb_stdio*)((char*)sink - offsetof(upb_stdio, bytesink)); + upb_strlen_t len = upb_string_len(str); + upb_strlen_t written = fwrite(upb_string_getrobuf(str), 1, len, stdio->file); + if(written < len) { + upb_seterr(status, UPB_ERROR, "Error writing to stdio stream."); + return -1; + } + return written; +} + +upb_strlen_t upb_stdio_vprintf(upb_bytesink *sink, upb_status *status, + const char *fmt, va_list args) { + upb_stdio *stdio = (upb_stdio*)((char*)sink - offsetof(upb_stdio, bytesink)); + upb_strlen_t written = vfprintf(stdio->file, fmt, args); + if (written < 0) { + upb_seterr(status, UPB_ERROR, "Error writing to stdio stream."); + return -1; + } + return written; +} + +upb_stdio *upb_stdio_new() { + static upb_bytesrc_vtbl bytesrc_vtbl = { + upb_stdio_read, + upb_stdio_getstr, + }; + + static upb_bytesink_vtbl bytesink_vtbl = { + NULL, + upb_stdio_putstr, + upb_stdio_vprintf + }; + + upb_stdio *stdio = malloc(sizeof(*stdio)); + upb_bytesrc_init(&stdio->bytesrc, &bytesrc_vtbl); + upb_bytesink_init(&stdio->bytesink, &bytesink_vtbl); + return stdio; +} + +void upb_stdio_free(upb_stdio *stdio) { + free(stdio); +} + +upb_bytesrc* upb_stdio_bytesrc(upb_stdio *stdio) { return &stdio->bytesrc; } +upb_bytesink* upb_stdio_bytesink(upb_stdio *stdio) { return &stdio->bytesink; } diff --git a/stream/upb_stdio.h b/stream/upb_stdio.h new file mode 100644 index 0000000..fd71fdd --- /dev/null +++ b/stream/upb_stdio.h @@ -0,0 +1,42 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * This file provides upb_bytesrc and upb_bytesink implementations for + * ANSI C stdio. + * + * Copyright (c) 2010 Joshua Haberman. See LICENSE for details. + */ + +#include <stdio.h> +#include "upb_stream.h" + +#ifndef UPB_STDIO_H_ +#define UPB_STDIO_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct upb_stdio; +typedef struct upb_stdio upb_stdio; + +// Creation/deletion. +upb_stdio *upb_stdio_new(); +void upb_stdio_free(upb_stdio *stdio); + +// Reset/initialize the object for use. The src or sink will call +// fread()/fwrite()/etc. on the given FILE*. +void upb_stdio_reset(upb_stdio *stdio, FILE* file); + +// Gets a bytesrc or bytesink for the given stdio. The returned pointer is +// invalidated by upb_stdio_reset above. It is perfectly valid to get both +// a bytesrc and a bytesink for the same stdio if the FILE* is open for reading +// and writing. +upb_bytesrc* upb_stdio_bytesrc(upb_stdio *stdio); +upb_bytesink* upb_stdio_bytesink(upb_stdio *stdio); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/stream/upb_strstream.c b/stream/upb_strstream.c new file mode 100644 index 0000000..d3fd4e0 --- /dev/null +++ b/stream/upb_strstream.c @@ -0,0 +1,71 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2010 Joshua Haberman. See LICENSE for details. + */ + +#include "upb_strstream.h" + +#include <stdlib.h> +#include "upb_string.h" + +struct upb_stringsrc { + upb_bytesrc bytesrc; + upb_string *str; + upb_strlen_t offset; +}; + +void upb_stringsrc_reset(upb_stringsrc *s, upb_string *str) { + if (str != s->str) { + if (s->str) upb_string_unref(s->str); + s->str = upb_string_getref(str); + } + s->bytesrc.eof = false; +} + +void upb_stringsrc_free(upb_stringsrc *s) { + if (s->str) upb_string_unref(s->str); + free(s); +} + +static upb_strlen_t upb_stringsrc_read(upb_bytesrc *_src, void *buf, + upb_strlen_t count, upb_status *status) { + upb_stringsrc *src = (upb_stringsrc*)_src; + if (src->offset == upb_string_len(src->str)) { + upb_seterr(status, UPB_EOF, ""); + return -1; + } else { + upb_strlen_t to_read = UPB_MIN(count, upb_string_len(src->str) - src->offset); + memcpy(buf, upb_string_getrobuf(src->str) + src->offset, to_read); + src->offset += to_read; + return to_read; + } +} + +static bool upb_stringsrc_getstr(upb_bytesrc *_src, upb_string *str, + upb_status *status) { + upb_stringsrc *src = (upb_stringsrc*)_src; + if (src->offset == upb_string_len(str)) { + upb_seterr(status, UPB_EOF, ""); + return false; + } else { + upb_string_substr(str, src->str, 0, upb_string_len(src->str)); + return true; + } +} + +upb_stringsrc *upb_stringsrc_new() { + static upb_bytesrc_vtbl bytesrc_vtbl = { + upb_stringsrc_read, + upb_stringsrc_getstr, + }; + + upb_stringsrc *s = malloc(sizeof(*s)); + s->str = NULL; + upb_bytesrc_init(&s->bytesrc, &bytesrc_vtbl); + return s; +} + +upb_bytesrc *upb_stringsrc_bytesrc(upb_stringsrc *s) { + return &s->bytesrc; +} diff --git a/stream/upb_strstream.h b/stream/upb_strstream.h new file mode 100644 index 0000000..d01d21f --- /dev/null +++ b/stream/upb_strstream.h @@ -0,0 +1,61 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * This file contains upb_bytesrc and upb_bytesink implementations for + * upb_string. + * + * Copyright (c) 2009-2010 Joshua Haberman. See LICENSE for details. + */ + +#ifndef UPB_STRSTREAM_H +#define UPB_STRSTREAM_H + +#include "upb_stream.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* upb_stringsrc **************************************************************/ + +struct upb_stringsrc; +typedef struct upb_stringsrc upb_stringsrc; + +// Create/free a stringsrc. +upb_stringsrc *upb_stringsrc_new(); +void upb_stringsrc_free(upb_stringsrc *s); + +// Resets the stringsrc to a state where it will vend the given string. The +// stringsrc will take a reference on the string, so the caller need not ensure +// that it outlives the stringsrc. A stringsrc can be reset multiple times. +void upb_stringsrc_reset(upb_stringsrc *s, upb_string *str); + +// Returns the upb_bytesrc* for this stringsrc. Invalidated by reset above. +upb_bytesrc *upb_stringsrc_bytesrc(upb_stringsrc *s); + + +/* upb_stringsink *************************************************************/ + +struct upb_stringsink; +typedef struct upb_stringsink upb_stringsink; + +// Create/free a stringsrc. +upb_stringsink *upb_stringsink_new(); +void upb_stringsink_free(upb_stringsink *s); + +// Gets a string containing the data that has been written to this stringsink. +// The caller does *not* own any references to this string. +upb_string *upb_stringsink_getstring(upb_stringsink *s); + +// Clears the internal string of accumulated data, resetting it to empty. +void upb_stringsink_reset(upb_stringsink *s); + +// Returns the upb_bytesrc* for this stringsrc. Invalidated by reset above. +upb_bytesink *upb_stringsrc_bytesink(); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/stream/upb_textprinter.c b/stream/upb_textprinter.c new file mode 100644 index 0000000..894a1ea --- /dev/null +++ b/stream/upb_textprinter.c @@ -0,0 +1,143 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. + */ + +#include "upb_textprinter.h" + +#include <inttypes.h> +#include <stdlib.h> +#include "upb_def.h" +#include "upb_string.h" + +struct _upb_textprinter { + upb_bytesink *bytesink; + int indent_depth; + bool single_line; + upb_status status; +}; + +#define CHECK(x) if ((x) < 0) goto err; + +static int upb_textprinter_indent(upb_textprinter *p) +{ + if(!p->single_line) + for(int i = 0; i < p->indent_depth; i++) + CHECK(upb_bytesink_putstr(p->bytesink, UPB_STRLIT(" "), &p->status)); + return 0; +err: + return -1; +} + +static int upb_textprinter_endfield(upb_textprinter *p) { + if(p->single_line) { + CHECK(upb_bytesink_putstr(p->bytesink, UPB_STRLIT(" "), &p->status)); + } else { + CHECK(upb_bytesink_putstr(p->bytesink, UPB_STRLIT("\n"), &p->status)); + } + return 0; +err: + return -1; +} + +static upb_flow_t upb_textprinter_value(void *_p, upb_fielddef *f, + upb_value val) { + upb_textprinter *p = _p; + upb_textprinter_indent(p); + CHECK(upb_bytesink_printf(p->bytesink, &p->status, UPB_STRFMT ": ", UPB_STRARG(f->name))); +#define CASE(fmtstr, member) \ + CHECK(upb_bytesink_printf(p->bytesink, &p->status, fmtstr, upb_value_get ## member(val))); break; + switch(f->type) { + case UPB_TYPE(DOUBLE): + CASE("%0.f", double); + case UPB_TYPE(FLOAT): + CASE("%0.f", float) + case UPB_TYPE(INT64): + case UPB_TYPE(SFIXED64): + case UPB_TYPE(SINT64): + CASE("%" PRId64, int64) + case UPB_TYPE(UINT64): + case UPB_TYPE(FIXED64): + CASE("%" PRIu64, uint64) + case UPB_TYPE(UINT32): + case UPB_TYPE(FIXED32): + CASE("%" PRIu32, uint32); + case UPB_TYPE(ENUM): { + upb_enumdef *enum_def = upb_downcast_enumdef(f->def); + upb_string *enum_label = + upb_enumdef_iton(enum_def, upb_value_getint32(val)); + if (enum_label) { + // We found a corresponding string for this enum. Otherwise we fall + // through to the int32 code path. + CHECK(upb_bytesink_putstr(p->bytesink, enum_label, &p->status)); + break; + } + } + case UPB_TYPE(INT32): + case UPB_TYPE(SFIXED32): + case UPB_TYPE(SINT32): + CASE("%" PRId32, int32) + case UPB_TYPE(BOOL): + CASE("%hhu", bool); + case UPB_TYPE(STRING): + case UPB_TYPE(BYTES): + // TODO: escaping. + CHECK(upb_bytesink_putstr(p->bytesink, UPB_STRLIT("\""), &p->status)); + CHECK(upb_bytesink_putstr(p->bytesink, upb_value_getstr(val), &p->status)) + CHECK(upb_bytesink_putstr(p->bytesink, UPB_STRLIT("\""), &p->status)); + break; + } + upb_textprinter_endfield(p); + return UPB_CONTINUE; +err: + return UPB_BREAK; +} + +static upb_flow_t upb_textprinter_startsubmsg(void *_p, upb_fielddef *f, + upb_handlers *delegate_to) { + (void)delegate_to; + upb_textprinter *p = _p; + upb_textprinter_indent(p); + CHECK(upb_bytesink_printf(p->bytesink, &p->status, UPB_STRFMT " {", UPB_STRARG(f->name))); + if(!p->single_line) upb_bytesink_putstr(p->bytesink, UPB_STRLIT("\n"), &p->status); + p->indent_depth++; + return UPB_CONTINUE; +err: + return UPB_BREAK; +} + +static upb_flow_t upb_textprinter_endsubmsg(void *_p) +{ + upb_textprinter *p = _p; + p->indent_depth--; + upb_textprinter_indent(p); + upb_bytesink_putstr(p->bytesink, UPB_STRLIT("}"), &p->status); + upb_textprinter_endfield(p); + return UPB_CONTINUE; +} + +upb_textprinter *upb_textprinter_new() { + upb_textprinter *p = malloc(sizeof(*p)); + return p; +} + +void upb_textprinter_free(upb_textprinter *p) { + free(p); +} + +void upb_textprinter_reset(upb_textprinter *p, upb_handlers *handlers, + upb_bytesink *sink, bool single_line) { + static upb_handlerset handlerset = { + NULL, // startmsg + NULL, // endmsg + upb_textprinter_value, + upb_textprinter_startsubmsg, + upb_textprinter_endsubmsg, + }; + p->bytesink = sink; + p->single_line = single_line; + p->indent_depth = 0; + upb_register_handlerset(handlers, &handlerset); + upb_set_handler_closure(handlers, p, &p->status); +} diff --git a/stream/upb_textprinter.h b/stream/upb_textprinter.h new file mode 100644 index 0000000..a880626 --- /dev/null +++ b/stream/upb_textprinter.h @@ -0,0 +1,29 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2009 Joshua Haberman. See LICENSE for details. + */ + +#ifndef UPB_TEXT_H_ +#define UPB_TEXT_H_ + +#include "upb_stream.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct _upb_textprinter; +typedef struct _upb_textprinter upb_textprinter; + +upb_textprinter *upb_textprinter_new(); +void upb_textprinter_free(upb_textprinter *p); +void upb_textprinter_reset(upb_textprinter *p, upb_handlers *handlers, + upb_bytesink *sink, bool single_line); +void upb_textprinter_sethandlers(upb_textprinter *p, upb_handlers *h); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* UPB_TEXT_H_ */ diff --git a/tests/test_decoder.c b/tests/test_decoder.c new file mode 100644 index 0000000..f48472d --- /dev/null +++ b/tests/test_decoder.c @@ -0,0 +1,42 @@ + +#include "upb_decoder.h" +#include "upb_textprinter.h" +#include "upb_stdio.h" + +int main() { + upb_symtab *symtab = upb_symtab_new(); + upb_symtab_add_descriptorproto(symtab); + upb_def *fds = upb_symtab_lookup( + symtab, UPB_STRLIT("google.protobuf.FileDescriptorSet")); + + upb_stdio *in = upb_stdio_new(); + upb_stdio_reset(in, stdin); + upb_stdio *out = upb_stdio_new(); + upb_stdio_reset(out, stdout); + upb_decoder *d = upb_decoder_new(upb_downcast_msgdef(fds)); + upb_decoder_reset(d, upb_stdio_bytesrc(in)); + upb_textprinter *p = upb_textprinter_new(); + upb_handlers handlers; + upb_handlers_init(&handlers); + upb_textprinter_reset(p, &handlers, upb_stdio_bytesink(out), false); + upb_src *src = upb_decoder_src(d); + upb_src_sethandlers(src, &handlers); + + upb_status status = UPB_STATUS_INIT; + upb_src_run(src, &status); + + assert(upb_ok(&status)); + + upb_status_uninit(&status); + upb_stdio_free(in); + upb_stdio_free(out); + upb_decoder_free(d); + upb_textprinter_free(p); + upb_def_unref(fds); + upb_symtab_unref(symtab); + + // Prevent C library from holding buffers open, so Valgrind doesn't see + // memory leaks. + fclose(stdin); + fclose(stdout); +} diff --git a/tests/test_def.c b/tests/test_def.c new file mode 100644 index 0000000..2d2658f --- /dev/null +++ b/tests/test_def.c @@ -0,0 +1,25 @@ + +#undef NDEBUG /* ensure tests always assert. */ +#include "upb_def.h" +#include <stdlib.h> + +int main() { + upb_symtab *s = upb_symtab_new(); + upb_symtab_add_descriptorproto(s); + + int count; + upb_def **defs = upb_symtab_getdefs(s, &count, UPB_DEF_ANY); + for (int i = 0; i < count; i++) { + upb_def_unref(defs[i]); + } + free(defs); + + upb_string *str = upb_strdupc("google.protobuf.FileDescriptorSet"); + upb_def *fds = upb_symtab_lookup(s, str); + assert(fds != NULL); + assert(upb_dyncast_msgdef(fds) != NULL); + upb_def_unref(fds); + upb_string_unref(str); + upb_symtab_unref(s); + return 0; +} diff --git a/tests/test_stream.c b/tests/test_stream.c new file mode 100644 index 0000000..b6d511c --- /dev/null +++ b/tests/test_stream.c @@ -0,0 +1,127 @@ + +#undef NDEBUG /* ensure tests always assert. */ +#include "upb_stream.h" +#include "upb_string.h" + +typedef struct { + upb_string *str; + bool should_delegate; +} test_data; + +extern upb_handlerset test_handlers; + +static void strappendf(upb_string *s, const char *format, ...) { + upb_string *str = upb_string_new(); + va_list args; + va_start(args, format); + upb_string_vprintf(str, format, args); + va_end(args); + upb_strcat(s, str); + upb_string_unref(str); +} + +static upb_flow_t startmsg(void *closure) { + test_data *d = closure; + strappendf(d->str, "startmsg\n"); + return UPB_CONTINUE; +} + +static upb_flow_t endmsg(void *closure) { + test_data *d = closure; + strappendf(d->str, "endmsg\n"); + return UPB_CONTINUE; +} + +static upb_flow_t value(void *closure, struct _upb_fielddef *f, upb_value val) { + (void)f; + test_data *d = closure; + strappendf(d->str, "value, %lld\n", upb_value_getint64(val)); + return UPB_CONTINUE; +} + +static upb_flow_t startsubmsg(void *closure, struct _upb_fielddef *f, + upb_handlers *delegate_to) { + (void)f; + test_data *d = closure; + strappendf(d->str, "startsubmsg\n"); + if (d->should_delegate) { + upb_register_handlerset(delegate_to, &test_handlers); + upb_set_handler_closure(delegate_to, closure, NULL); + return UPB_DELEGATE; + } else { + return UPB_CONTINUE; + } +} + +static upb_flow_t endsubmsg(void *closure) { + test_data *d = closure; + strappendf(d->str, "endsubmsg\n"); + return UPB_CONTINUE; +} + +static upb_flow_t unknownval(void *closure, upb_field_number_t fieldnum, + upb_value val) { + (void)val; + test_data *d = closure; + strappendf(d->str, "unknownval, %d\n", fieldnum); + return UPB_CONTINUE; +} + +upb_handlerset test_handlers = { + &startmsg, + &endmsg, + &value, + &startsubmsg, + &endsubmsg, + &unknownval, +}; + +static void test_dispatcher() { + test_data data; + data.should_delegate = false; + data.str = upb_string_new(); + upb_handlers h; + upb_handlers_init(&h); + upb_handlers_reset(&h); + upb_register_handlerset(&h, &test_handlers); + upb_set_handler_closure(&h, &data, NULL); + upb_dispatcher d; + upb_dispatcher_init(&d); + upb_dispatcher_reset(&d, &h); + + upb_dispatch_startmsg(&d); + upb_value val; + upb_value_setint64(&val, 5); + upb_dispatch_value(&d, NULL, val); + upb_dispatch_startsubmsg(&d, NULL); + data.should_delegate = true; + upb_dispatch_startsubmsg(&d, NULL); + 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_endmsg(&d); + + upb_string expected = UPB_STACK_STRING( + "startmsg\n" + "value, 5\n" + "startsubmsg\n" + "startsubmsg\n" + "startmsg\n" // Because of the delegation. + "startsubmsg\n" + "value, 5\n" + "endsubmsg\n" + "endmsg\n" // Because of the delegation. + "endsubmsg\n" + "endsubmsg\n" + "endmsg\n"); + assert(upb_streql(data.str, &expected)); + upb_string_unref(data.str); +} + +int main() { + test_dispatcher(); + return 0; +} diff --git a/tests/test_string.c b/tests/test_string.c new file mode 100644 index 0000000..ef0e2a9 --- /dev/null +++ b/tests/test_string.c @@ -0,0 +1,126 @@ + +#undef NDEBUG /* ensure tests always assert. */ +#include "upb_string.h" + +char static_str[] = "Static string."; +upb_string static_upbstr = UPB_STATIC_STRING(static_str); + +static void test_static() { + // Static string is initialized appropriately. + assert(upb_streql(&static_upbstr, UPB_STRLIT("Static string."))); + + // Taking a ref on a static string returns the same string, and repeated + // refs don't get the string in a confused state. + assert(upb_string_getref(&static_upbstr) == &static_upbstr); + assert(upb_string_getref(&static_upbstr) == &static_upbstr); + assert(upb_string_getref(&static_upbstr) == &static_upbstr); + + // Unreffing a static string does nothing (is not harmful). + upb_string_unref(&static_upbstr); + upb_string_unref(&static_upbstr); + upb_string_unref(&static_upbstr); + upb_string_unref(&static_upbstr); + upb_string_unref(&static_upbstr); + + // Recycling a static string returns a new string (that can be modified). + upb_string *str = &static_upbstr; + upb_string_recycle(&str); + assert(str != &static_upbstr); + + upb_string_unref(str); +} + +static void test_dynamic() { + upb_string *str = upb_string_new(); + assert(str != NULL); + upb_string_unref(str); + + // Can also create a string by recycle(NULL). + str = NULL; + upb_string_recycle(&str); + assert(str != NULL); + + // Take a ref and recycle; should create a new string and release a ref + // on the old one. + upb_string *strcp = upb_string_getref(str); + assert(strcp == str); + assert(upb_atomic_read(&str->refcount) == 2); + upb_string_recycle(&str); + assert(strcp != str); + assert(upb_atomic_read(&str->refcount) == 1); + assert(upb_atomic_read(&strcp->refcount) == 1); + upb_string_unref(strcp); + + upb_strcpyc(str, static_str); + assert(upb_string_len(str) == (sizeof(static_str) - 1)); + const char *robuf = upb_string_getrobuf(str); + assert(robuf != NULL); + assert(upb_streqlc(str, static_str)); + upb_string_endread(str); + + upb_string *str2 = str; + upb_string_recycle(&str2); + // No other referents, so should return the same string. + assert(str2 == str); + + // Write a shorter string, the same memory should be reused. + upb_strcpyc(str, "XX"); + const char *robuf2 = upb_string_getrobuf(str); + assert(robuf2 == robuf); + assert(upb_streqlc(str, "XX")); + assert(upb_streql(str, UPB_STRLIT("XX"))); + + // Make string alias part of another string. + str2 = upb_strdupc("WXYZ"); + upb_string_recycle(&str); + upb_string_substr(str, str2, 1, 2); + assert(upb_string_len(str) == 2); + assert(upb_string_len(str2) == 4); + // The two string should be aliasing the same data. + const char *robuf3 = upb_string_getrobuf(str); + const char *robuf4 = upb_string_getrobuf(str2); + assert(robuf3 == robuf4 + 1); + // The aliased string should have an extra ref. + assert(upb_atomic_read(&str2->refcount) == 2); + + // Recycling str should eliminate the extra ref. + upb_string_recycle(&str); + assert(upb_atomic_read(&str2->refcount) == 1); + + // Resetting str should reuse its old data. + upb_strcpyc(str, "XX"); + const char *robuf5 = upb_string_getrobuf(str); + assert(robuf5 == robuf); + + // Resetting str to something very long should require new data to be + // allocated. + upb_string_recycle(&str); + const char longstring[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; + upb_strcpyc(str, longstring); + const char *robuf6 = upb_string_getrobuf(str); + assert(robuf6 != robuf); + assert(upb_streqlc(str, longstring)); + + // Test printf. + upb_string_recycle(&str); + upb_string_printf(str, "Number: %d, String: %s", 5, "YO!"); + assert(upb_streqlc(str, "Number: 5, String: YO!")); + + // Test asprintf + upb_string *str3 = upb_string_asprintf("Yo %s: " UPB_STRFMT "\n", + "Josh", UPB_STRARG(str)); + const char expected[] = "Yo Josh: Number: 5, String: YO!\n"; + assert(upb_streqlc(str3, expected)); + + upb_string_unref(str); + upb_string_unref(str2); + upb_string_unref(str3); + + // Unref of NULL is harmless. + upb_string_unref(NULL); +} + +int main() { + test_static(); + test_dynamic(); +} diff --git a/tests/test_table.cc b/tests/test_table.cc index 47d806c..47d5e57 100644 --- a/tests/test_table.cc +++ b/tests/test_table.cc @@ -1,7 +1,7 @@ #undef NDEBUG /* ensure tests always assert. */ #include "upb_table.h" -#include "upb_data.h" +#include "upb_string.h" #include "test_util.h" #include <assert.h> #include <map> @@ -12,6 +12,8 @@ #include <sys/resource.h> #include <iostream> +bool benchmark = false; + using std::string; using std::vector; @@ -45,7 +47,7 @@ void test_strtable(const vector<string>& keys, uint32_t num_to_insert) all.insert(key); strtable_entry e; e.value = key[0]; - upb_strptr str = upb_strduplen(key.c_str(), key.size()); + upb_string *str = upb_strduplen(key.c_str(), key.size()); e.e.key = str; upb_strtable_insert(&table, &e.e); upb_string_unref(str); // The table still owns a ref. @@ -55,7 +57,7 @@ void test_strtable(const vector<string>& keys, uint32_t num_to_insert) /* Test correctness. */ for(uint32_t i = 0; i < keys.size(); i++) { const string& key = keys[i]; - upb_strptr str = upb_strduplen(key.c_str(), key.size()); + upb_string *str = upb_strduplen(key.c_str(), key.size()); strtable_entry *e = (strtable_entry*)upb_strtable_lookup(&table, str); if(m.find(key) != m.end()) { /* Assume map implementation is correct. */ assert(e); @@ -71,7 +73,7 @@ void test_strtable(const vector<string>& keys, uint32_t num_to_insert) strtable_entry *e; for(e = (strtable_entry*)upb_strtable_begin(&table); e; e = (strtable_entry*)upb_strtable_next(&table, &e->e)) { - string tmp(upb_string_getrobuf(e->e.key), upb_strlen(e->e.key)); + string tmp(upb_string_getrobuf(e->e.key), upb_string_len(e->e.key)); std::set<string>::iterator i = all.find(tmp); assert(i != all.end()); all.erase(i); @@ -116,6 +118,11 @@ void test_inttable(int32_t *keys, size_t num_entries) } } + if(!benchmark) { + upb_inttable_free(&table); + return; + } + /* Test performance. We only test lookups for keys that are known to exist. */ uintptr_t x = 0; const unsigned int iterations = 0xFFFFFF; @@ -219,8 +226,12 @@ int32_t *get_contiguous_keys(int32_t num) return buf; } -int main() +int main(int argc, char *argv[]) { + for (int i = 1; i < argc; i++) { + if (strcmp(argv[i], "--benchmark") == 0) benchmark = true; + } + vector<string> keys; keys.push_back("google.protobuf.FileDescriptorSet"); keys.push_back("google.protobuf.FileDescriptorProto"); diff --git a/tests/test_vs_proto2.cc b/tests/test_vs_proto2.cc index 9083788..9446b8f 100644 --- a/tests/test_vs_proto2.cc +++ b/tests/test_vs_proto2.cc @@ -4,9 +4,10 @@ #include <stdio.h> #include <stdlib.h> #include <google/protobuf/descriptor.h> -#include "upb_data.h" +#include "upb_msg.h" #include "upb_def.h" #include "upb_decoder.h" +#include "upb_strstream.h" int num_assertions = 0; #define ASSERT(expr) do { \ @@ -25,7 +26,7 @@ void compare_arrays(const google::protobuf::Reflection *r, upb_msg *upb_msg, upb_fielddef *upb_f) { ASSERT(upb_msg_has(upb_msg, upb_f)); - upb_arrayptr arr = upb_msg_get(upb_msg, upb_f).arr; + upb_array *arr = upb_msg_get(upb_msg, upb_f).arr; ASSERT(upb_array_len(arr) == (upb_arraylen_t)r->FieldSize(proto2_msg, proto2_f)); for(upb_arraylen_t i = 0; i < upb_array_len(arr); i++) { upb_value v = upb_array_get(arr, upb_f, i); @@ -63,7 +64,7 @@ void compare_arrays(const google::protobuf::Reflection *r, case UPB_TYPE(STRING): case UPB_TYPE(BYTES): { std::string str = r->GetRepeatedString(proto2_msg, proto2_f, i); - std::string str2(upb_string_getrobuf(v.str), upb_strlen(v.str)); + std::string str2(upb_string_getrobuf(v.str), upb_string_len(v.str)); ASSERT(str == str2); break; } @@ -116,7 +117,7 @@ void compare_values(const google::protobuf::Reflection *r, case UPB_TYPE(STRING): case UPB_TYPE(BYTES): { std::string str = r->GetString(proto2_msg, proto2_f); - std::string str2(upb_string_getrobuf(v.str), upb_strlen(v.str)); + std::string str2(upb_string_getrobuf(v.str), upb_string_len(v.str)); ASSERT(str == str2); break; } @@ -133,9 +134,10 @@ void compare(const google::protobuf::Message& proto2_msg, const google::protobuf::Reflection *r = proto2_msg.GetReflection(); const google::protobuf::Descriptor *d = proto2_msg.GetDescriptor(); - ASSERT((upb_field_count_t)d->field_count() == upb_md->num_fields); - for(upb_field_count_t i = 0; i < upb_md->num_fields; i++) { - upb_fielddef *upb_f = &upb_md->fields[i]; + ASSERT((upb_field_count_t)d->field_count() == upb_msgdef_numfields(upb_md)); + upb_msg_iter i; + for(i = upb_msg_begin(upb_md); !upb_msg_done(i); i = upb_msg_next(upb_md, i)) { + upb_fielddef *upb_f = upb_msg_iter_field(i); const google::protobuf::FieldDescriptor *proto2_f = d->FindFieldByNumber(upb_f->number); // Make sure the definitions are equal. @@ -143,7 +145,7 @@ void compare(const google::protobuf::Message& proto2_msg, ASSERT(proto2_f); ASSERT(upb_f->number == proto2_f->number()); ASSERT(std::string(upb_string_getrobuf(upb_f->name), - upb_strlen(upb_f->name)) == + upb_string_len(upb_f->name)) == proto2_f->name()); ASSERT(upb_f->type == proto2_f->type()); ASSERT(upb_isarray(upb_f) == proto2_f->is_repeated()); @@ -166,10 +168,10 @@ void compare(const google::protobuf::Message& proto2_msg, void parse_and_compare(MESSAGE_CIDENT *proto2_msg, upb_msg *upb_msg, upb_msgdef *upb_md, - upb_strptr str) + upb_string *str) { // Parse to both proto2 and upb. - ASSERT(proto2_msg->ParseFromArray(upb_string_getrobuf(str), upb_strlen(str))); + ASSERT(proto2_msg->ParseFromArray(upb_string_getrobuf(str), upb_string_len(str))); upb_status status = UPB_STATUS_INIT; upb_msg_decodestr(upb_msg, upb_md, str, &status); ASSERT(upb_ok(&status)); @@ -194,22 +196,32 @@ int main(int argc, char *argv[]) // Initialize upb state, parse descriptor. upb_status status = UPB_STATUS_INIT; - upb_symtab *c = upb_symtab_new(); - upb_strptr fds = upb_strreadfile(MESSAGE_DESCRIPTOR_FILE); - if(upb_string_isnull(fds)) { + upb_symtab *symtab = upb_symtab_new(); + upb_string *fds = upb_strreadfile(MESSAGE_DESCRIPTOR_FILE); + if(fds == NULL) { fprintf(stderr, "Couldn't read " MESSAGE_DESCRIPTOR_FILE ".\n"); return 1; } - upb_symtab_add_desc(c, fds, &status); + upb_symtab_add_descriptorproto(symtab); + upb_def *fds_msgdef = upb_symtab_lookup( + symtab, UPB_STRLIT("google.protobuf.FileDescriptorSet")); + + upb_stringsrc *ssrc = upb_stringsrc_new(); + upb_stringsrc_reset(ssrc, fds); + upb_decoder *decoder = upb_decoder_new(upb_downcast_msgdef(fds_msgdef)); + upb_decoder_reset(decoder, upb_stringsrc_bytesrc(ssrc)); + upb_symtab_addfds(symtab, upb_decoder_src(decoder), &status); if(!upb_ok(&status)) { - fprintf(stderr, "Error importing " MESSAGE_DESCRIPTOR_FILE ": %s.\n", - status.msg); + fprintf(stderr, "Error importing " MESSAGE_DESCRIPTOR_FILE ": "); + upb_printerr(&status); return 1; } upb_string_unref(fds); + upb_decoder_free(decoder); + upb_stringsrc_free(ssrc); - upb_strptr proto_name = upb_strdupc(MESSAGE_NAME); - upb_msgdef *def = upb_downcast_msgdef(upb_symtab_lookup(c, proto_name)); + upb_string *proto_name = upb_strdupc(MESSAGE_NAME); + upb_msgdef *def = upb_downcast_msgdef(upb_symtab_lookup(symtab, proto_name)); if(!def) { fprintf(stderr, "Error finding symbol '" UPB_STRFMT "'.\n", UPB_STRARG(proto_name)); @@ -218,8 +230,8 @@ int main(int argc, char *argv[]) upb_string_unref(proto_name); // Read the message data itself. - upb_strptr str = upb_strreadfile(MESSAGE_FILE); - if(upb_string_isnull(str)) { + upb_string *str = upb_strreadfile(MESSAGE_FILE); + if(str == NULL) { fprintf(stderr, "Error reading " MESSAGE_FILE "\n"); return 1; } @@ -234,7 +246,7 @@ int main(int argc, char *argv[]) upb_msg_unref(upb_msg, def); upb_def_unref(UPB_UPCAST(def)); upb_string_unref(str); - upb_symtab_unref(c); + upb_symtab_unref(symtab); return 0; } diff --git a/upb.xcodeproj/project.pbxproj b/upb.xcodeproj/project.pbxproj new file mode 100644 index 0000000..8b4eb4e --- /dev/null +++ b/upb.xcodeproj/project.pbxproj @@ -0,0 +1,497 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 420E6F1C11F258AE001DA8FE /* test_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D4F11F24F3E0076AD28 /* test_decoder.c */; }; + 420E6F3B11F259B3001DA8FE /* liblibupbcore.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42BD1D5C11F24F920076AD28 /* liblibupbcore.a */; }; + 420E6F3C11F259B3001DA8FE /* liblibupbstream.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 42BD1D6411F24FBA0076AD28 /* liblibupbstream.a */; }; + 42BD1D6E11F2500D0076AD28 /* upb.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D3211F24E4C0076AD28 /* upb.c */; }; + 42BD1D7011F2500D0076AD28 /* upb_def.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D2911F24E4C0076AD28 /* upb_def.c */; }; + 42BD1D7211F2500D0076AD28 /* upb_stream.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D2C11F24E4C0076AD28 /* upb_stream.c */; }; + 42BD1D7311F2500D0076AD28 /* upb_string.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D2E11F24E4C0076AD28 /* upb_string.c */; }; + 42BD1D7411F2500D0076AD28 /* upb_table.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D3011F24E4C0076AD28 /* upb_table.c */; }; + 42BD1D7611F250B90076AD28 /* upb_decoder.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D3E11F24EA30076AD28 /* upb_decoder.c */; }; + 42BD1D7711F250B90076AD28 /* upb_stdio.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D4011F24EA30076AD28 /* upb_stdio.c */; }; + 42BD1D7811F250B90076AD28 /* upb_textprinter.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D4211F24EA30076AD28 /* upb_textprinter.c */; }; + 42BD1D9011F251820076AD28 /* descriptor_const.h in Headers */ = {isa = PBXBuildFile; fileRef = 42BD1D8D11F251820076AD28 /* descriptor_const.h */; }; + 42BD1D9111F251820076AD28 /* descriptor.c in Sources */ = {isa = PBXBuildFile; fileRef = 42BD1D8E11F251820076AD28 /* descriptor.c */; }; + 42BD1D9211F251820076AD28 /* descriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = 42BD1D8F11F251820076AD28 /* descriptor.h */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 420E6F3311F2598D001DA8FE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 42BD1D5B11F24F920076AD28 /* upbcore */; + remoteInfo = upbcore; + }; + 420E6F3511F2598D001DA8FE /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 42BD1D6311F24FBA0076AD28 /* upbstream */; + remoteInfo = upbstream; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 420E6F1811F2589F001DA8FE /* test_decoder */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = test_decoder; sourceTree = BUILT_PRODUCTS_DIR; }; + 42BD1D2811F24E4C0076AD28 /* upb_atomic.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb_atomic.h; path = core/upb_atomic.h; sourceTree = "<group>"; }; + 42BD1D2911F24E4C0076AD28 /* upb_def.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = upb_def.c; path = core/upb_def.c; sourceTree = "<group>"; }; + 42BD1D2A11F24E4C0076AD28 /* upb_def.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb_def.h; path = core/upb_def.h; sourceTree = "<group>"; }; + 42BD1D2B11F24E4C0076AD28 /* upb_stream_vtbl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb_stream_vtbl.h; path = core/upb_stream_vtbl.h; sourceTree = "<group>"; }; + 42BD1D2C11F24E4C0076AD28 /* upb_stream.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = upb_stream.c; path = core/upb_stream.c; sourceTree = "<group>"; }; + 42BD1D2D11F24E4C0076AD28 /* upb_stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb_stream.h; path = core/upb_stream.h; sourceTree = "<group>"; }; + 42BD1D2E11F24E4C0076AD28 /* upb_string.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = upb_string.c; path = core/upb_string.c; sourceTree = "<group>"; }; + 42BD1D2F11F24E4C0076AD28 /* upb_string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb_string.h; path = core/upb_string.h; sourceTree = "<group>"; }; + 42BD1D3011F24E4C0076AD28 /* upb_table.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = upb_table.c; path = core/upb_table.c; sourceTree = "<group>"; }; + 42BD1D3111F24E4C0076AD28 /* upb_table.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb_table.h; path = core/upb_table.h; sourceTree = "<group>"; }; + 42BD1D3211F24E4C0076AD28 /* upb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = upb.c; path = core/upb.c; sourceTree = "<group>"; }; + 42BD1D3311F24E4C0076AD28 /* upb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb.h; path = core/upb.h; sourceTree = "<group>"; }; + 42BD1D3E11F24EA30076AD28 /* upb_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = upb_decoder.c; path = stream/upb_decoder.c; sourceTree = "<group>"; }; + 42BD1D3F11F24EA30076AD28 /* upb_decoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb_decoder.h; path = stream/upb_decoder.h; sourceTree = "<group>"; }; + 42BD1D4011F24EA30076AD28 /* upb_stdio.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = upb_stdio.c; path = stream/upb_stdio.c; sourceTree = "<group>"; }; + 42BD1D4111F24EA30076AD28 /* upb_stdio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb_stdio.h; path = stream/upb_stdio.h; sourceTree = "<group>"; }; + 42BD1D4211F24EA30076AD28 /* upb_textprinter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = upb_textprinter.c; path = stream/upb_textprinter.c; sourceTree = "<group>"; }; + 42BD1D4311F24EA30076AD28 /* upb_textprinter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = upb_textprinter.h; path = stream/upb_textprinter.h; sourceTree = "<group>"; }; + 42BD1D4F11F24F3E0076AD28 /* test_decoder.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = test_decoder.c; path = tests/test_decoder.c; sourceTree = "<group>"; }; + 42BD1D5011F24F3E0076AD28 /* test_def.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = test_def.c; path = tests/test_def.c; sourceTree = "<group>"; }; + 42BD1D5111F24F3E0076AD28 /* test_string.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = test_string.c; path = tests/test_string.c; sourceTree = "<group>"; }; + 42BD1D5211F24F3E0076AD28 /* test_table.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test_table.cc; path = tests/test_table.cc; sourceTree = "<group>"; }; + 42BD1D5311F24F3E0076AD28 /* test_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = test_util.h; path = tests/test_util.h; sourceTree = "<group>"; }; + 42BD1D5C11F24F920076AD28 /* liblibupbcore.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = liblibupbcore.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 42BD1D6411F24FBA0076AD28 /* liblibupbstream.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = liblibupbstream.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 42BD1D8D11F251820076AD28 /* descriptor_const.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = descriptor_const.h; path = descriptor/descriptor_const.h; sourceTree = "<group>"; }; + 42BD1D8E11F251820076AD28 /* descriptor.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = descriptor.c; path = descriptor/descriptor.c; sourceTree = "<group>"; }; + 42BD1D8F11F251820076AD28 /* descriptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = descriptor.h; path = descriptor/descriptor.h; sourceTree = "<group>"; }; + C6A0FF2C0290799A04C91782 /* upb.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = upb.1; sourceTree = "<group>"; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 420E6F1611F2589F001DA8FE /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 420E6F3B11F259B3001DA8FE /* liblibupbcore.a in Frameworks */, + 420E6F3C11F259B3001DA8FE /* liblibupbstream.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 42BD1D5A11F24F920076AD28 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 42BD1D6211F24FBA0076AD28 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* upb */ = { + isa = PBXGroup; + children = ( + 08FB7795FE84155DC02AAC07 /* Source */, + C6A0FF2B0290797F04C91782 /* Documentation */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = upb; + sourceTree = "<group>"; + }; + 08FB7795FE84155DC02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 42BD1D8A11F251670076AD28 /* descriptor */, + 42BD1D4711F24EB20076AD28 /* tests */, + 42BD1D3B11F24E810076AD28 /* stream */, + 42BD1D3A11F24E5F0076AD28 /* core */, + ); + name = Source; + sourceTree = "<group>"; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 42BD1D5C11F24F920076AD28 /* liblibupbcore.a */, + 42BD1D6411F24FBA0076AD28 /* liblibupbstream.a */, + 420E6F1811F2589F001DA8FE /* test_decoder */, + ); + name = Products; + sourceTree = "<group>"; + }; + 42BD1D3A11F24E5F0076AD28 /* core */ = { + isa = PBXGroup; + children = ( + 42BD1D2811F24E4C0076AD28 /* upb_atomic.h */, + 42BD1D2911F24E4C0076AD28 /* upb_def.c */, + 42BD1D2A11F24E4C0076AD28 /* upb_def.h */, + 42BD1D2B11F24E4C0076AD28 /* upb_stream_vtbl.h */, + 42BD1D2C11F24E4C0076AD28 /* upb_stream.c */, + 42BD1D2D11F24E4C0076AD28 /* upb_stream.h */, + 42BD1D2E11F24E4C0076AD28 /* upb_string.c */, + 42BD1D2F11F24E4C0076AD28 /* upb_string.h */, + 42BD1D3011F24E4C0076AD28 /* upb_table.c */, + 42BD1D3111F24E4C0076AD28 /* upb_table.h */, + 42BD1D3211F24E4C0076AD28 /* upb.c */, + 42BD1D3311F24E4C0076AD28 /* upb.h */, + ); + name = core; + sourceTree = "<group>"; + }; + 42BD1D3B11F24E810076AD28 /* stream */ = { + isa = PBXGroup; + children = ( + 42BD1D3E11F24EA30076AD28 /* upb_decoder.c */, + 42BD1D3F11F24EA30076AD28 /* upb_decoder.h */, + 42BD1D4011F24EA30076AD28 /* upb_stdio.c */, + 42BD1D4111F24EA30076AD28 /* upb_stdio.h */, + 42BD1D4211F24EA30076AD28 /* upb_textprinter.c */, + 42BD1D4311F24EA30076AD28 /* upb_textprinter.h */, + ); + name = stream; + sourceTree = "<group>"; + }; + 42BD1D4711F24EB20076AD28 /* tests */ = { + isa = PBXGroup; + children = ( + 42BD1D4F11F24F3E0076AD28 /* test_decoder.c */, + 42BD1D5011F24F3E0076AD28 /* test_def.c */, + 42BD1D5111F24F3E0076AD28 /* test_string.c */, + 42BD1D5211F24F3E0076AD28 /* test_table.cc */, + 42BD1D5311F24F3E0076AD28 /* test_util.h */, + ); + name = tests; + sourceTree = "<group>"; + }; + 42BD1D8A11F251670076AD28 /* descriptor */ = { + isa = PBXGroup; + children = ( + 42BD1D8D11F251820076AD28 /* descriptor_const.h */, + 42BD1D8E11F251820076AD28 /* descriptor.c */, + 42BD1D8F11F251820076AD28 /* descriptor.h */, + ); + name = descriptor; + sourceTree = "<group>"; + }; + C6A0FF2B0290797F04C91782 /* Documentation */ = { + isa = PBXGroup; + children = ( + C6A0FF2C0290799A04C91782 /* upb.1 */, + ); + name = Documentation; + sourceTree = "<group>"; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 42BD1D5811F24F920076AD28 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 42BD1D9011F251820076AD28 /* descriptor_const.h in Headers */, + 42BD1D9211F251820076AD28 /* descriptor.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 42BD1D6011F24FBA0076AD28 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 420E6F1711F2589F001DA8FE /* test_decoder */ = { + isa = PBXNativeTarget; + buildConfigurationList = 420E6F1F11F258CC001DA8FE /* Build configuration list for PBXNativeTarget "test_decoder" */; + buildPhases = ( + 420E6F1511F2589F001DA8FE /* Sources */, + 420E6F1611F2589F001DA8FE /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 420E6F3411F2598D001DA8FE /* PBXTargetDependency */, + 420E6F3611F2598D001DA8FE /* PBXTargetDependency */, + ); + name = test_decoder; + productName = test_decoder; + productReference = 420E6F1811F2589F001DA8FE /* test_decoder */; + productType = "com.apple.product-type.tool"; + }; + 42BD1D5B11F24F920076AD28 /* upbcore */ = { + isa = PBXNativeTarget; + buildConfigurationList = 42BD1D5F11F24FB10076AD28 /* Build configuration list for PBXNativeTarget "upbcore" */; + buildPhases = ( + 42BD1D5811F24F920076AD28 /* Headers */, + 42BD1D5911F24F920076AD28 /* Sources */, + 42BD1D5A11F24F920076AD28 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = upbcore; + productName = libupbcore; + productReference = 42BD1D5C11F24F920076AD28 /* liblibupbcore.a */; + productType = "com.apple.product-type.library.static"; + }; + 42BD1D6311F24FBA0076AD28 /* upbstream */ = { + isa = PBXNativeTarget; + buildConfigurationList = 42BD1D6911F24FED0076AD28 /* Build configuration list for PBXNativeTarget "upbstream" */; + buildPhases = ( + 42BD1D6011F24FBA0076AD28 /* Headers */, + 42BD1D6111F24FBA0076AD28 /* Sources */, + 42BD1D6211F24FBA0076AD28 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = upbstream; + productName = libupbstream; + productReference = 42BD1D6411F24FBA0076AD28 /* liblibupbstream.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "upb" */; + compatibilityVersion = "Xcode 3.1"; + hasScannedForEncodings = 1; + mainGroup = 08FB7794FE84155DC02AAC07 /* upb */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 42BD1D5B11F24F920076AD28 /* upbcore */, + 42BD1D6311F24FBA0076AD28 /* upbstream */, + 420E6F1711F2589F001DA8FE /* test_decoder */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 420E6F1511F2589F001DA8FE /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 420E6F1C11F258AE001DA8FE /* test_decoder.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 42BD1D5911F24F920076AD28 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 42BD1D6E11F2500D0076AD28 /* upb.c in Sources */, + 42BD1D7011F2500D0076AD28 /* upb_def.c in Sources */, + 42BD1D7211F2500D0076AD28 /* upb_stream.c in Sources */, + 42BD1D7311F2500D0076AD28 /* upb_string.c in Sources */, + 42BD1D7411F2500D0076AD28 /* upb_table.c in Sources */, + 42BD1D9111F251820076AD28 /* descriptor.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 42BD1D6111F24FBA0076AD28 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 42BD1D7611F250B90076AD28 /* upb_decoder.c in Sources */, + 42BD1D7711F250B90076AD28 /* upb_stdio.c in Sources */, + 42BD1D7811F250B90076AD28 /* upb_textprinter.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 420E6F3411F2598D001DA8FE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 42BD1D5B11F24F920076AD28 /* upbcore */; + targetProxy = 420E6F3311F2598D001DA8FE /* PBXContainerItemProxy */; + }; + 420E6F3611F2598D001DA8FE /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 42BD1D6311F24FBA0076AD28 /* upbstream */; + targetProxy = 420E6F3511F2598D001DA8FE /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + 1DEB928A08733DD80010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = UPB_THREAD_UNSAFE; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; + PREBINDING = NO; + SDKROOT = macosx10.6; + }; + name = Debug; + }; + 1DEB928B08733DD80010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_PREPROCESSOR_DEFINITIONS = UPB_THREAD_UNSAFE; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + PREBINDING = NO; + SDKROOT = macosx10.6; + }; + name = Release; + }; + 420E6F1A11F258A0001DA8FE /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + INSTALL_PATH = /usr/local/bin; + PREBINDING = NO; + PRODUCT_NAME = test_decoder; + }; + name = Debug; + }; + 420E6F1B11F258A0001DA8FE /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_MODEL_TUNING = G5; + INSTALL_PATH = /usr/local/bin; + PREBINDING = NO; + PRODUCT_NAME = test_decoder; + ZERO_LINK = NO; + }; + name = Release; + }; + 42BD1D5D11F24F930076AD28 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + INSTALL_PATH = /usr/local/lib; + PREBINDING = NO; + PRODUCT_NAME = libupbcore; + }; + name = Debug; + }; + 42BD1D5E11F24F930076AD28 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_MODEL_TUNING = G5; + INSTALL_PATH = /usr/local/lib; + PREBINDING = NO; + PRODUCT_NAME = libupbcore; + ZERO_LINK = NO; + }; + name = Release; + }; + 42BD1D6511F24FBA0076AD28 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + INSTALL_PATH = /usr/local/lib; + PREBINDING = NO; + PRODUCT_NAME = libupbstream; + }; + name = Debug; + }; + 42BD1D6611F24FBA0076AD28 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_MODEL_TUNING = G5; + INSTALL_PATH = /usr/local/lib; + PREBINDING = NO; + PRODUCT_NAME = libupbstream; + ZERO_LINK = NO; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "upb" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB928A08733DD80010E9CD /* Debug */, + 1DEB928B08733DD80010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 420E6F1F11F258CC001DA8FE /* Build configuration list for PBXNativeTarget "test_decoder" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 420E6F1A11F258A0001DA8FE /* Debug */, + 420E6F1B11F258A0001DA8FE /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 42BD1D5F11F24FB10076AD28 /* Build configuration list for PBXNativeTarget "upbcore" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 42BD1D5D11F24F930076AD28 /* Debug */, + 42BD1D5E11F24F930076AD28 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 42BD1D6911F24FED0076AD28 /* Build configuration list for PBXNativeTarget "upbstream" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 42BD1D6511F24FBA0076AD28 /* Debug */, + 42BD1D6611F24FBA0076AD28 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} |