| /* Amalgamated source file */ | |
| #include "ruby-upb.h" | |
| /* | |
| * This is where we define internal portability macros used across upb. | |
| * | |
| * All of these macros are undef'd in undef.inc to avoid leaking them to users. | |
| * | |
| * The correct usage is: | |
| * | |
| * #include "upb/foobar.h" | |
| * #include "upb/baz.h" | |
| * | |
| * // MUST be last included header. | |
| * #include "upb/port/def.inc" | |
| * | |
| * // Code for this file. | |
| * // <...> | |
| * | |
| * // Can be omitted for .c files, required for .h. | |
| * #include "upb/port/undef.inc" | |
| * | |
| * This file is private and must not be included by users! | |
| */ | |
| #if !((defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \ | |
| (defined(__cplusplus) && __cplusplus >= 201703L) || \ | |
| (defined(_MSC_VER) && _MSC_VER >= 1900)) | |
| #error upb requires C99 or C++17 or MSVC >= 2015. | |
| #endif | |
| // Portable check for GCC minimum version: | |
| // https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html | |
| #if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) | |
| #define UPB_GNUC_MIN(x, y) \ | |
| (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y)) | |
| #else | |
| #define UPB_GNUC_MIN(x, y) 0 | |
| #endif | |
| #if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__) | |
| #define UPB_CLANG_MIN(x, y) \ | |
| (__clang_major__ > (x) || __clang_major__ == (x) && __clang_minor__ >= (y)) | |
| #else | |
| #define UPB_CLANG_MIN(x, y) 0 | |
| #endif | |
| // Macros for checking for compiler attributes, defined here to avoid the | |
| // problem described in | |
| // https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fattribute.html. | |
| #ifdef __has_attribute | |
| #define UPB_HAS_ATTRIBUTE(x) __has_attribute(x) | |
| #else | |
| #define UPB_HAS_ATTRIBUTE(x) 0 | |
| #endif | |
| #ifdef __has_c_attribute | |
| #define UPB_HAS_C_ATTRIBUTE(x) __has_c_attribute(x) | |
| #else | |
| #define UPB_HAS_C_ATTRIBUTE(x) 0 | |
| #endif | |
| #if defined(__cplusplus) && defined(__has_cpp_attribute) | |
| // NOTE: requiring __cplusplus above should not be necessary, but | |
| // works around https://bugs.llvm.org/show_bug.cgi?id=23435. | |
| #define UPB_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) | |
| #else | |
| #define UPB_HAS_CPP_ATTRIBUTE(x) 0 | |
| #endif | |
| // Once in a while we want to use this macro in a C++-only portion of an | |
| // otherwise C-compatible header, so we copy and paste this from ABSL. | |
| #if UPB_HAS_CPP_ATTRIBUTE(deprecated) && UPB_HAS_CPP_ATTRIBUTE(clang::annotate) | |
| #define UPB_DEPRECATE_AND_INLINE() [[deprecated, clang::annotate("inline-me")]] | |
| #elif UPB_HAS_CPP_ATTRIBUTE(deprecated) | |
| #define UPB_DEPRECATE_AND_INLINE() [[deprecated]] | |
| #else | |
| #define UPB_DEPRECATE_AND_INLINE() | |
| #endif | |
| #ifdef __has_builtin | |
| #define UPB_HAS_BUILTIN(x) __has_builtin(x) | |
| #else | |
| #define UPB_HAS_BUILTIN(x) 0 | |
| #endif | |
| // UPB_MEMCPY_INLINE(dst, src, n): memcpy() of a compile-time constant number | |
| // of bytes `n`, which the compiler never turns into a call to the library | |
| // memcpy(). A plain memcpy() of a constant size is usually inlined as loads and | |
| // stores too, but the compiler can merge such copies of different sizes (e.g. | |
| // the cases of a switch on the size) into one copy of a variable size, which | |
| // it then can't inline; the merge can even happen before the compiler uses the | |
| // UPB_ASSUME()s about the size. | |
| #if UPB_HAS_BUILTIN(__builtin_memcpy_inline) | |
| #define UPB_MEMCPY_INLINE(dst, src, n) __builtin_memcpy_inline(dst, src, n) | |
| #else | |
| #define UPB_MEMCPY_INLINE(dst, src, n) memcpy(dst, src, n) | |
| #endif | |
| #ifdef __has_extension | |
| #define UPB_HAS_EXTENSION(x) __has_extension(x) | |
| #else | |
| #define UPB_HAS_EXTENSION(x) 0 | |
| #endif | |
| #ifdef __has_feature | |
| #define UPB_HAS_FEATURE(x) __has_feature(x) | |
| #else | |
| #define UPB_HAS_FEATURE(x) 0 | |
| #endif | |
| #include <assert.h> | |
| #include <setjmp.h> | |
| #include <stdbool.h> | |
| #include <stdint.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #ifndef UINTPTR_MAX | |
| Error, UINTPTR_MAX is undefined | |
| #endif | |
| #if UINTPTR_MAX == 0xffffffff | |
| #define UPB_SIZE(size32, size64) size32 | |
| #else | |
| #define UPB_SIZE(size32, size64) size64 | |
| #endif | |
| /* If we always read/write as a consistent type to each address, this shouldn't | |
| * violate aliasing. | |
| */ | |
| #define UPB_PTR_AT(msg, ofs, type) ((type*)((char*)(msg) + (ofs))) | |
| // A flexible array member may have lower alignment requirements than the struct | |
| // overall - in that case, it can overlap with the trailing padding of the rest | |
| // of the struct, and a naive sizeof(base) + sizeof(flex) * count calculation | |
| // will not take into account that overlap, and allocate more than is required. | |
| #define UPB_SIZEOF_FLEX(type, member, count) \ | |
| UPB_MAX(sizeof(type), offsetof(type, member[count])) | |
| #define UPB_SIZEOF_FLEX_WOULD_OVERFLOW(type, member, count) \ | |
| (((SIZE_MAX - offsetof(type, member[0])) / \ | |
| (offsetof(type, member[1]) - offsetof(type, member[0]))) < (size_t)count) | |
| // Inverse of UPB_SIZEOF_FLEX; given the size in memory, how many elements can | |
| // the flexible array member store? | |
| #define UPB_FLEX_CAPACITY(type, member, size) \ | |
| ((size) < sizeof(type) \ | |
| ? (size_t)0 \ | |
| : ((size) - offsetof(type, member[0])) / \ | |
| (offsetof(type, member[1]) - offsetof(type, member[0]))) | |
| #define UPB_ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) | |
| #define UPB_MAPTYPE_STRING 0 | |
| // UPB_EXPORT: always generate a public symbol. | |
| #if defined(__GNUC__) || defined(__clang__) | |
| #define UPB_EXPORT __attribute__((visibility("default"))) __attribute__((used)) | |
| #else | |
| #define UPB_EXPORT | |
| #endif | |
| // UPB_INLINE: inline if possible, emit standalone code if required. | |
| #ifdef __cplusplus | |
| #define UPB_INLINE inline | |
| #elif defined(__GNUC__) || defined(__clang__) | |
| #define UPB_INLINE static __inline__ | |
| #else | |
| #define UPB_INLINE static | |
| #endif | |
| // UPB_INLINE_IF_NOT_GCC: because gcc can be very noisy at times. | |
| #if defined(__GNUC__) && !defined(__clang__) | |
| #define UPB_INLINE_IF_NOT_GCC static | |
| #else | |
| #define UPB_INLINE_IF_NOT_GCC UPB_INLINE | |
| #endif | |
| #ifdef UPB_BUILD_API | |
| #define UPB_API UPB_EXPORT | |
| #define UPB_API_INLINE UPB_EXPORT | |
| #else | |
| #define UPB_API | |
| #define UPB_API_INLINE UPB_INLINE | |
| #endif | |
| #ifdef EXPORT_UPBC | |
| #define UPBC_API UPB_EXPORT | |
| #else | |
| #define UPBC_API | |
| #endif | |
| #if UPB_HAS_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__) | |
| #define UPB_ASAN 1 | |
| #else | |
| #define UPB_ASAN 0 | |
| #endif | |
| #if UPB_HAS_FEATURE(hwaddress_sanitizer) | |
| #define UPB_HWASAN 1 | |
| #define UPB_HWASAN_POISON_TAG 17 | |
| #define UPB_MALLOC_ALIGN 16 | |
| #else | |
| #define UPB_HWASAN 0 | |
| #define UPB_MALLOC_ALIGN 8 | |
| #endif | |
| #if UPB_HAS_FEATURE(thread_sanitizer) || defined(__SANITIZE_THREAD__) | |
| #define UPB_TSAN 1 | |
| #else | |
| #define UPB_TSAN 0 | |
| #endif | |
| #if UPB_HAS_FEATURE(memory_sanitizer) | |
| #define UPB_MSAN 1 | |
| #else | |
| #define UPB_MSAN 0 | |
| #endif | |
| // An unfortunate concession to C++17 and MSVC, which don't support zero-sized | |
| // structs. | |
| #if UPB_ASAN || UPB_HWASAN || UPB_TSAN | |
| #define UPB_XSAN_MEMBER upb_Xsan xsan; | |
| #define UPB_XSAN(st) (&(st)->xsan) | |
| #define UPB_XSAN_STRUCT_SIZE 1 | |
| #else | |
| #define UPB_XSAN_MEMBER | |
| #define UPB_XSAN(st) (NULL) | |
| #define UPB_XSAN_STRUCT_SIZE 0 | |
| #endif | |
| #define UPB_ALIGN_UP(size, align) (((size) + (align) - 1) / (align) * (align)) | |
| #define UPB_ALIGN_DOWN(size, align) ((size) / (align) * (align)) | |
| #define UPB_ALIGN_MALLOC(size) UPB_ALIGN_UP(size, UPB_MALLOC_ALIGN) | |
| #if __STDC_VERSION__ >= 202311L || UPB_HAS_EXTENSION(cxx_alignof) || \ | |
| defined(__cplusplus) | |
| #define UPB_ALIGN_OF(type) alignof(type) | |
| #elif __STDC_VERSION__ >= 201112L || UPB_HAS_EXTENSION(c_alignof) | |
| #define UPB_ALIGN_OF(type) _Alignof(type) | |
| #elif UPB_GNUC_MIN(2, 95) | |
| #define UPB_ALIGN_OF(type) __alignof__(type) | |
| #elif defined(_MSC_VER) | |
| #define UPB_ALIGN_OF(type) __alignof(type) | |
| #else | |
| #define UPB_ALIGN_OF(type) \ | |
| offsetof( \ | |
| struct { \ | |
| char c; \ | |
| type member; \ | |
| }, \ | |
| member) | |
| #endif | |
| #ifdef _MSC_VER | |
| // Some versions of our Windows compiler don't support the C11 syntax. | |
| #define UPB_ALIGN_AS(x) __declspec(align(x)) | |
| #elif defined(__GNUC__) | |
| #define UPB_ALIGN_AS(x) __attribute__((aligned(x))) | |
| #else | |
| #define UPB_ALIGN_AS(x) _Alignas(x) | |
| #endif | |
| #if __STDC_VERSION__ >= 202311L || UPB_HAS_EXTENSION(cxx_static_assert) || \ | |
| defined(__cplusplus) | |
| #define UPB_STATIC_ASSERT(val, msg) static_assert((val), msg) | |
| #elif __STDC_VERSION__ >= 201112L || UPB_HAS_EXTENSION(c_static_assert) || \ | |
| UPB_GNUC_MIN(4, 6) | |
| #define UPB_STATIC_ASSERT(val, msg) _Static_assert((val), msg) | |
| #else | |
| // Unfortunately this hack doesn't work inside struct declarations, but it works | |
| // everywhere else | |
| #define UPB_STATIC_ASSERT_CONCAT_IMPL(s1, s2) s1##s2 | |
| #define UPB_STATIC_ASSERT_CONCAT(s1, s2) UPB_STATIC_ASSERT_CONCAT_IMPL(s1, s2) | |
| #ifdef __COUNTER__ | |
| #define UPB_STATIC_ASSERT(condition, message) \ | |
| typedef char UPB_STATIC_ASSERT_CONCAT(static_assertion_failure_, \ | |
| __COUNTER__)[(condition) ? 1 : -1] | |
| #else | |
| #define UPB_STATIC_ASSERT(condition, message) \ | |
| typedef char UPB_STATIC_ASSERT_CONCAT(static_assertion_failure_, \ | |
| __LINE__)[(condition) ? 1 : -1] | |
| #endif | |
| #endif | |
| // Hints to the compiler about likely/unlikely branches. | |
| #if defined(__GNUC__) || defined(__clang__) | |
| #define UPB_LIKELY(x) __builtin_expect((bool)(x), 1) | |
| #define UPB_UNLIKELY(x) __builtin_expect((bool)(x), 0) | |
| #else | |
| #define UPB_LIKELY(x) (x) | |
| #define UPB_UNLIKELY(x) (x) | |
| #endif | |
| #if UPB_HAS_BUILTIN(__builtin_expect_with_probability) | |
| #define UPB_UNPREDICTABLE(x) \ | |
| __builtin_expect_with_probability((bool)(x), 1, 0.5) | |
| #else | |
| #define UPB_UNPREDICTABLE(x) (x) | |
| #endif | |
| // Macros for function attributes on compilers that support them. | |
| #if defined(__GNUC__) || defined(__clang__) | |
| #define UPB_FORCEINLINE __inline__ __attribute__((always_inline)) static | |
| #define UPB_NOINLINE __attribute__((noinline)) | |
| #define UPB_NORETURN __attribute__((__noreturn__)) | |
| #define UPB_PRINTF(str, first_vararg) \ | |
| __attribute__((format(printf, str, first_vararg))) | |
| #elif defined(_MSC_VER) | |
| #define UPB_NOINLINE | |
| #define UPB_FORCEINLINE static | |
| #define UPB_NORETURN __declspec(noreturn) | |
| #define UPB_PRINTF(str, first_vararg) | |
| #else /* !defined(__GNUC__) */ | |
| #define UPB_FORCEINLINE static | |
| #define UPB_NOINLINE | |
| #define UPB_NORETURN | |
| #define UPB_PRINTF(str, first_vararg) | |
| #endif | |
| #if UPB_HAS_ATTRIBUTE(noderef) | |
| #define UPB_NODEREF __attribute__((noderef)) | |
| #else | |
| #define UPB_NODEREF | |
| #endif | |
| #if UPB_HAS_C_ATTRIBUTE(nodiscard) | |
| #define UPB_NODISCARD [[nodiscard]] | |
| #elif UPB_HAS_ATTRIBUTE(warn_unused_result) | |
| #define UPB_NODISCARD __attribute__((warn_unused_result)) | |
| #elif UPB_HAS_CPP_ATTRIBUTE(nodiscard) | |
| #define UPB_NODISCARD [[nodiscard]] | |
| #else | |
| #define UPB_NODISCARD | |
| #endif | |
| #define UPB_MAX(x, y) ((x) > (y) ? (x) : (y)) | |
| #define UPB_MIN(x, y) ((x) < (y) ? (x) : (y)) | |
| #define UPB_UNUSED(var) (void)(var) | |
| // UPB_ASSUME(): in release mode, we tell the compiler to assume this is true. | |
| #ifdef NDEBUG | |
| #ifdef __GNUC__ | |
| #define UPB_ASSUME(expr) \ | |
| if (!(expr)) __builtin_unreachable() | |
| #elif defined _MSC_VER | |
| #define UPB_ASSUME(expr) \ | |
| if (!(expr)) __assume(0) | |
| #else | |
| #define UPB_ASSUME(expr) \ | |
| do { \ | |
| } while (false && (expr)) | |
| #endif | |
| #else | |
| #define UPB_ASSUME(expr) assert(expr) | |
| #endif | |
| #if UPB_HAS_BUILTIN(__builtin_constant_p) && UPB_HAS_ATTRIBUTE(const) | |
| #define UPB_MAYBE_ASSUME(pred, x) \ | |
| if (__builtin_constant_p(pred) && pred) UPB_ASSUME(x) | |
| #define UPB_ATTR_CONST __attribute__((const)) | |
| #else | |
| #define UPB_MAYBE_ASSUME(pred, x) | |
| #define UPB_ATTR_CONST | |
| #endif | |
| /* UPB_ASSERT(): in release mode, we use the expression without letting it be | |
| * evaluated. This prevents "unused variable" warnings. */ | |
| #ifdef NDEBUG | |
| #define UPB_ASSERT(expr) \ | |
| do { \ | |
| } while (false && (expr)) | |
| #else | |
| #define UPB_ASSERT(expr) assert(expr) | |
| #endif | |
| #if !defined(NDEBUG) && !defined(UPB_TSAN) | |
| #define UPB_ENABLE_REF_CYCLE_CHECKS 1 | |
| #else | |
| #define UPB_ENABLE_REF_CYCLE_CHECKS 0 | |
| #endif | |
| #if defined(__GNUC__) || defined(__clang__) | |
| #define UPB_PRETTY_FUNCTION __PRETTY_FUNCTION__ | |
| #else | |
| #define UPB_PRETTY_FUNCTION NULL | |
| #endif | |
| #ifdef __cplusplus | |
| extern "C" { | |
| #endif | |
| UPB_NORETURN void _upb_UnreachableFailure(const char* file, int line, | |
| const char* function_name); | |
| #if !defined(NDEBUG) | |
| #define UPB_UNREACHABLE_FAILURE() \ | |
| _upb_UnreachableFailure(__FILE__, __LINE__, UPB_PRETTY_FUNCTION); | |
| #else | |
| #define UPB_UNREACHABLE_FAILURE() | |
| #endif | |
| #ifdef __cplusplus | |
| } /* extern "C" */ | |
| #endif | |
| #if defined(__GNUC__) || defined(__clang__) | |
| #define UPB_UNREACHABLE() \ | |
| do { \ | |
| UPB_UNREACHABLE_FAILURE(); \ | |
| __builtin_unreachable(); \ | |
| } while (0) | |
| #elif defined(_MSC_VER) | |
| #define UPB_UNREACHABLE() \ | |
| do { \ | |
| UPB_UNREACHABLE_FAILURE(); \ | |
| __assume(0); \ | |
| } while (0) | |
| #else | |
| #define UPB_UNREACHABLE() \ | |
| do { \ | |
| UPB_UNREACHABLE_FAILURE(); \ | |
| } while (0) | |
| #endif | |
| #ifdef __ANDROID__ | |
| #define UPB_DEFAULT_MAX_BLOCK_SIZE 8192 | |
| #else | |
| #define UPB_DEFAULT_MAX_BLOCK_SIZE 32768 | |
| #endif | |
| /* UPB_SETJMP() / UPB_LONGJMP() */ | |
| // Android uses a custom libc that does not implement all of posix, but it has | |
| // had sigsetjmp/siglongjmp forever on arm and since API 12 on x86. Apple has | |
| // sigsetjmp, but does not define the posix feature test macro. | |
| #if defined(__APPLE__) || defined(_POSIX_C_SOURCE) || defined(__ANDROID__) | |
| // avoid setting/restoring signal mask, which involves costly syscalls | |
| #define UPB_SETJMP(buf) sigsetjmp(buf, 0) | |
| #define UPB_LONGJMP(buf, val) siglongjmp(buf, val) | |
| #elif defined(WASM_WAMR) | |
| #define UPB_SETJMP(buf) 0 | |
| #define UPB_LONGJMP(buf, val) abort() | |
| #else | |
| #define UPB_SETJMP(buf) setjmp(buf) | |
| #define UPB_LONGJMP(buf, val) longjmp(buf, val) | |
| #endif | |
| #if ((__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_ATOMICS__)) || \ | |
| UPB_HAS_EXTENSION(c_atomic) || \ | |
| defined(__GNUC__) // GCC supported atomics as an extension before it | |
| // supported __has_extension | |
| #define UPB_USE_C11_ATOMICS | |
| #elif defined(_MSC_VER) | |
| #define UPB_USE_MSC_ATOMICS | |
| #endif | |
| #if defined(UPB_USE_C11_ATOMICS) | |
| #define UPB_ATOMIC(T) _Atomic(T) | |
| #elif defined(UPB_USE_MSC_ATOMICS) | |
| #define UPB_ATOMIC(T) volatile T | |
| #else | |
| #define UPB_ATOMIC(T) T | |
| #endif | |
| /* UPB_PTRADD(ptr, ofs): add pointer while avoiding "NULL + 0" UB */ | |
| #define UPB_PTRADD(ptr, ofs) ((ofs) ? (ptr) + (ofs) : (ptr)) | |
| #define UPB_PRIVATE(x) x##_dont_copy_me__upb_internal_use_only | |
| #ifdef UPB_ALLOW_PRIVATE_ACCESS__FOR_BITS_ONLY | |
| #define UPB_ONLYBITS(x) x | |
| #else | |
| #define UPB_ONLYBITS(x) UPB_PRIVATE(x) | |
| #endif | |
| /* Configure whether fasttable is switched on or not. *************************/ | |
| #if UPB_HAS_ATTRIBUTE(musttail) | |
| #define UPB_MUSTTAIL __attribute__((musttail)) | |
| #else | |
| #define UPB_MUSTTAIL | |
| #endif | |
| #if UPB_HAS_ATTRIBUTE(preserve_most) && !defined(__i386__) | |
| #define UPB_PRESERVE_MOST __attribute__((preserve_most)) | |
| #else | |
| #define UPB_PRESERVE_MOST | |
| #endif | |
| #if UPB_HAS_ATTRIBUTE(preserve_none) | |
| #define UPB_PRESERVE_NONE __attribute__((preserve_none)) | |
| #else | |
| #define UPB_PRESERVE_NONE | |
| #endif | |
| #if defined(__aarch64__) && (defined(__GNUC__) || defined(__clang__)) | |
| #define UPB_ARM64_ASM 1 | |
| #else | |
| #define UPB_ARM64_ASM 0 | |
| #endif | |
| /* When compiling with branch protection, we need to ensure that all branch | |
| * targets in assembly use the appropriate landing pad instruction. These | |
| * instructions are backwards compatible with processors that don't have | |
| * FEAT_BTI and are treated as nops. | |
| */ | |
| #if UPB_ARM64_ASM && defined(__ARM_FEATURE_BTI_DEFAULT) | |
| #if __ARM_FEATURE_BTI_DEFAULT == 1 | |
| #define UPB_ARM64_BTI_DEFAULT 1 | |
| #else | |
| #define UPB_ARM64_BTI_DEFAULT 0 | |
| #endif | |
| #else | |
| #define UPB_ARM64_BTI_DEFAULT 0 | |
| #endif | |
| /* aarch64 supports big and little endian modes; fasttable performs multibyte | |
| * tag loads assumes the tag of a varint is in the low bits. */ | |
| #if !defined(_WIN32) && (defined(__x86_64__) || defined(__AARCH64EL__)) && \ | |
| UPB_HAS_ATTRIBUTE(preserve_none) && UPB_HAS_ATTRIBUTE(musttail) | |
| #define UPB_FASTTABLE_SUPPORTED 1 | |
| #else | |
| #define UPB_FASTTABLE_SUPPORTED 0 | |
| #endif | |
| /* define UPB_ENABLE_FASTTABLE to force fast table support. | |
| * This is useful when we want to ensure we are really getting fasttable, | |
| * for example for testing or benchmarking. */ | |
| #if defined(UPB_ENABLE_FASTTABLE) | |
| #if !UPB_FASTTABLE_SUPPORTED | |
| #error fasttable is x86-64/ARM64le only and requires preserve_none and musttail. | |
| #endif | |
| #define UPB_FASTTABLE 1 | |
| /* Define UPB_TRY_ENABLE_FASTTABLE to use fasttable if possible. | |
| * This is useful for releasing code that might be used on multiple platforms, | |
| * for example the PHP or Ruby C extensions. */ | |
| #elif defined(UPB_TRY_ENABLE_FASTTABLE) | |
| #if UPB_FASTTABLE_SUPPORTED | |
| #define UPB_FASTTABLE 1 | |
| #else | |
| #define UPB_FASTTABLE 0 | |
| #endif | |
| #else | |
| #define UPB_FASTTABLE 0 | |
| #endif | |
| /* UPB_FASTTABLE_INIT() allows protos compiled for fasttable to gracefully | |
| * degrade to non-fasttable if the runtime or platform do not support it. */ | |
| #if !UPB_FASTTABLE | |
| #define UPB_FASTTABLE_INIT(...) | |
| #define UPB_FASTTABLE_MASK(mask) -1 | |
| #else | |
| #define UPB_FASTTABLE_INIT(...) __VA_ARGS__ | |
| #define UPB_FASTTABLE_MASK(mask) mask | |
| #endif | |
| #undef UPB_FASTTABLE_SUPPORTED | |
| #if defined(__cplusplus) | |
| #if defined(__clang__) || UPB_GNUC_MIN(6, 0) | |
| // https://gcc.gnu.org/gcc-6/changes.html | |
| #define UPB_DEPRECATED [[deprecated]] | |
| #else | |
| #define UPB_DEPRECATED | |
| #endif | |
| #else | |
| #define UPB_DEPRECATED | |
| #endif | |
| #if defined(__clang__) | |
| #define UPB_IGNORE_DEPRECATION_START \ | |
| _Pragma("clang diagnostic push") \ | |
| _Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"") | |
| #define UPB_IGNORE_DEPRECATION_STOP _Pragma("clang diagnostic pop") | |
| #elif defined(__GNUC__) | |
| #define UPB_IGNORE_DEPRECATION_START \ | |
| _Pragma("GCC diagnostic push") \ | |
| _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") | |
| #define UPB_IGNORE_DEPRECATION_STOP _Pragma("GCC diagnostic pop") | |
| #elif defined(_MSC_VER) | |
| #define UPB_IGNORE_DEPRECATION_START \ | |
| __pragma(warning(push)) __pragma(warning(disable : 4996)) | |
| #define UPB_IGNORE_DEPRECATION_STOP __pragma(warning(pop)) | |
| #else | |
| #define UPB_IGNORE_DEPRECATION_START | |
| #define UPB_IGNORE_DEPRECATION_STOP | |
| #endif | |
| #if defined(UPB_IS_GOOGLE3) && \ | |
| (!defined(UPB_BOOTSTRAP_STAGE) || UPB_BOOTSTRAP_STAGE != 0) | |
| #define UPB_DESC_MINITABLE(sym) &proto2__##sym##_msg_init | |
| #elif defined(UPB_IS_GOOGLE3) && defined(UPB_BOOTSTRAP_STAGE) && \ | |
| UPB_BOOTSTRAP_STAGE == 0 | |
| #define UPB_DESC_MINITABLE(sym) proto2__##sym##_msg_init() | |
| #elif defined(UPB_BOOTSTRAP_STAGE) && UPB_BOOTSTRAP_STAGE == 0 | |
| #define UPB_DESC_MINITABLE(sym) google__protobuf__##sym##_msg_init() | |
| #else | |
| #define UPB_DESC_MINITABLE(sym) &google__protobuf__##sym##_msg_init | |
| #endif | |
| #undef UPB_IS_GOOGLE3 | |
| #ifdef __clang__ | |
| #define UPB_NO_SANITIZE_ADDRESS __attribute__((no_sanitize("address"))) | |
| #else | |
| #define UPB_NO_SANITIZE_ADDRESS | |
| #endif | |
| #if defined(__GNUC__) && (defined(__clang__) || UPB_GNUC_MIN(11, 0)) | |
| #define UPB_RETAIN __attribute__((retain)) | |
| #else | |
| #define UPB_RETAIN | |
| #endif | |
| #if defined(__GNUC__) || defined(__clang__) | |
| #define UPB_HIDDEN __attribute__((visibility("hidden"))) | |
| #else | |
| #define UPB_HIDDEN | |
| #endif | |
| // Linker arrays combine elements from multiple translation units into a single | |
| // array that can be iterated over at runtime. | |
| // | |
| // It is an alternative to pre-main "registration" functions. | |
| // | |
| // Usage: | |
| // | |
| // // In N translation units. | |
| // UPB_LINKARR_APPEND(foo_array) static int elems[3] = {1, 2, 3}; | |
| // | |
| // // At runtime: | |
| // UPB_LINKARR_DECLARE(foo_array, int); | |
| // | |
| // void f() { | |
| // const int* start = UPB_LINKARR_START(foo_array); | |
| // const int* stop = UPB_LINKARR_STOP(foo_array); | |
| // for (const int* p = start; p < stop; p++) { | |
| // // Windows can introduce zero padding, so we have to skip zeroes. | |
| // if (*p != 0) { | |
| // vec.push_back(*p); | |
| // } | |
| // } | |
| // } | |
| #if defined(__GNUC__) && !defined(__clang__) | |
| // GCC can't handle mismatched retain attributes in the same section: | |
| // https://github.com/protocolbuffers/protobuf/issues/26385 | |
| // To work around this, we retain all linker array elements, even though this | |
| // effectively disables tree-shaking of unused extensions when using GCC. | |
| #define UPB_LINKARR_ATTR UPB_RETAIN | |
| #else | |
| #define UPB_LINKARR_ATTR | |
| #endif | |
| #define UPB_LINKARR_SENTINEL UPB_RETAIN __attribute__((weak, used)) | |
| #if defined(__ELF__) || defined(__wasm__) | |
| #define UPB_LINKARR_APPEND(name) \ | |
| __attribute__(( \ | |
| section("linkarr_" #name))) UPB_LINKARR_ATTR UPB_NO_SANITIZE_ADDRESS | |
| #define UPB_LINKARR_DECLARE(name, type) \ | |
| UPB_STATIC_ASSERT(sizeof("__la_" #name) <= 17, \ | |
| "Linker array name too long for Mach-O (16-char limit)"); \ | |
| extern type __start_linkarr_##name; \ | |
| extern type __stop_linkarr_##name; \ | |
| UPB_LINKARR_APPEND(name) \ | |
| UPB_LINKARR_SENTINEL type UPB_linkarr_internal_empty_##name[1] | |
| #define UPB_LINKARR_START(name) (&__start_linkarr_##name) | |
| #define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name) | |
| #elif defined(__MACH__) | |
| /* As described in: https://stackoverflow.com/a/22366882 */ | |
| #define UPB_LINKARR_APPEND(name) \ | |
| __attribute__(( \ | |
| section("__DATA,__la_" #name))) UPB_LINKARR_ATTR UPB_NO_SANITIZE_ADDRESS | |
| #define UPB_LINKARR_DECLARE(name, type) \ | |
| UPB_STATIC_ASSERT(sizeof("__la_" #name) <= 17, \ | |
| "Linker array name too long for Mach-O (16-char limit)"); \ | |
| extern type __start_linkarr_##name __asm( \ | |
| "section$start$__DATA$__la_" #name); \ | |
| extern type __stop_linkarr_##name __asm( \ | |
| "section$end$__DATA$" \ | |
| "__la_" #name); \ | |
| UPB_LINKARR_APPEND(name) \ | |
| UPB_LINKARR_SENTINEL type UPB_linkarr_internal_empty_##name[1] | |
| #define UPB_LINKARR_START(name) (&__start_linkarr_##name) | |
| #define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name) | |
| #elif defined(_MSC_VER) | |
| /* See: | |
| * https://devblogs.microsoft.com/oldnewthing/20181107-00/?p=100155 | |
| * https://devblogs.microsoft.com/oldnewthing/20181108-00/?p=100165 | |
| * https://devblogs.microsoft.com/oldnewthing/20181109-00/?p=100175 */ | |
| #define UPB_STRINGIFY_INTERNAL(x) #x | |
| #define UPB_STRINGIFY(x) UPB_STRINGIFY_INTERNAL(x) | |
| #define UPB_CONCAT(a, b, c) a##b##c | |
| #define UPB_LINKARR_NAME(name, index) \ | |
| UPB_STRINGIFY(UPB_CONCAT(la_, name, index)) | |
| #define UPB_LINKARR_APPEND(name) \ | |
| __pragma(section(UPB_LINKARR_NAME(name, $j), read)) \ | |
| __declspec(allocate(UPB_LINKARR_NAME(name, $j))) | |
| // clang-format off | |
| #define UPB_LINKARR_DECLARE(name, type) \ | |
| __pragma(message(UPB_LINKARR_NAME(name, $j))) \ | |
| __pragma(section(UPB_LINKARR_NAME(name, $a), read)) \ | |
| __pragma(section(UPB_LINKARR_NAME(name, $z), read)) \ | |
| __declspec(allocate(UPB_LINKARR_NAME(name, $a)), selectany) \ | |
| type __start_linkarr_##name; \ | |
| __declspec(allocate(UPB_LINKARR_NAME(name, $z)), selectany) \ | |
| type __stop_linkarr_##name; \ | |
| UPB_LINKARR_APPEND(name) \ | |
| __declspec(selectany) type UPB_linkarr_internal_empty_##name[1] = {0} | |
| // clang-format on | |
| #define UPB_LINKARR_START(name) (&__start_linkarr_##name) | |
| #define UPB_LINKARR_STOP(name) (&__stop_linkarr_##name) | |
| #else | |
| // Linker arrays are not supported on this platform. Make macros no-ops. | |
| #define UPB_LINKARR_APPEND(name) | |
| #define UPB_LINKARR_DECLARE(name, type) \ | |
| UPB_STATIC_ASSERT(sizeof("__la_" #name) <= 17, \ | |
| "Linker array name too long for Mach-O (16-char limit)") | |
| #define UPB_LINKARR_START(name) (NULL) | |
| #define UPB_LINKARR_STOP(name) (NULL) | |
| #endif | |
| // Workaround for https://github.com/llvm/llvm-project/issues/167577 until it's | |
| // fixed. Some function must exist for the constructor to work properly. | |
| // TODO Remove this or gate it on a future version of clang. | |
| #if defined(__clang__) && defined(__arm__) | |
| #define _UPB_CONSTRUCTOR_PLACEHOLDER(unique_name) \ | |
| __attribute__((used, visibility("hidden"))) void UPB_PRIVATE(unique_name)( \ | |
| void) {} | |
| #else | |
| #define _UPB_CONSTRUCTOR_PLACEHOLDER(unique_name) | |
| #endif | |
| #define _UPB_STRINGIFY2(x) #x | |
| #define _UPB_STRINGIFY(x) _UPB_STRINGIFY2(x) | |
| #if defined(__ELF__) && (UPB_GNUC_MIN(15, 1) || UPB_CLANG_MIN(21, 1)) | |
| /* | |
| * Workaround for b/456308964 and b/456317163. Although weak constructors | |
| * resolve to a single function body, Clang still emits a pointer into | |
| * .init_array for every translation unit, causing the constructor to be | |
| * executed multiple times and inflating binary size. We wrap the .init_array | |
| * entry in a COMDAT group (using inline assembly) to force the linker to | |
| * deduplicate the pointer to exactly one instance. %cc is used in preference to | |
| * the more widely available %c because %c may under some circumstances still | |
| * output a function name including relocation information, which will then | |
| * confuse the linker. This was only a problem on gcc; when %cc was introduced | |
| * to clang it was just an alias to %c, and clang's %c had already done the | |
| * checks that %cc introduced to gcc. | |
| * References: | |
| * https://github.com/gcc-mirror/gcc/commit/74d6a676034b3ab20c387f12f19f5597e4f1c9fa | |
| * https://github.com/llvm/llvm-project/pull/127719#issuecomment-2686276305 | |
| */ | |
| #define UPB_CONSTRUCTOR(name, unique_name, ...) \ | |
| _UPB_CONSTRUCTOR_PLACEHOLDER(unique_name) \ | |
| __attribute__((weak, used, visibility("hidden"))) void UPB_PRIVATE(name)( \ | |
| void) { \ | |
| __asm__ volatile( \ | |
| ".pushsection .init_array,\"awG\",%%init_array, %cc0, comdat\n" \ | |
| ".dc.a %cc0\n" \ | |
| ".popsection\n" \ | |
| : \ | |
| : "X"(UPB_PRIVATE(name))); \ | |
| __VA_ARGS__ \ | |
| } | |
| #elif defined(__ELF__) || defined(__wasm__) || defined(__MACH__) || \ | |
| defined(__MINGW32__) | |
| #define UPB_CONSTRUCTOR(name, unique_name, ...) \ | |
| _UPB_CONSTRUCTOR_PLACEHOLDER(unique_name) \ | |
| __attribute__((weak, visibility("hidden"), constructor)) void UPB_PRIVATE( \ | |
| name)(void) { \ | |
| __VA_ARGS__ \ | |
| } | |
| #elif defined(_MSC_VER) | |
| /* | |
| * See: https://stackoverflow.com/questions/1113409 | |
| * | |
| * The /include pragma suggested in the link above doesn't work in our case | |
| * because it requires globally unique names. We need a different solution | |
| * to prevent optimizers from removing the constructor. Our solution is to | |
| * create a dummy exported weak symbol that prevent this stripping. | |
| */ | |
| #pragma section(".CRT$XCT", read) | |
| #define UPB_CONSTRUCTOR(name, unique_name, ...) \ | |
| static void __cdecl UPB_PRIVATE(name)(void); \ | |
| __declspec(allocate(".CRT$XCT"), selectany) void( \ | |
| __cdecl * UPB_PRIVATE(name##_))(void) = UPB_PRIVATE(name); \ | |
| __declspec(selectany, dllexport) void* UPB_PRIVATE(name##_force_linkage) = \ | |
| &UPB_PRIVATE(name##_); \ | |
| static void __cdecl UPB_PRIVATE(name)(void) { __VA_ARGS__ } | |
| #else | |
| // No constructor support, nothing we can do except not break builds. | |
| #if defined(__GNUC__) || defined(__clang__) | |
| #define UPB_CONSTRUCTOR(name, unique_name, ...) \ | |
| static __attribute__((used)) void UPB_PRIVATE(name)(void) { __VA_ARGS__ } | |
| #else | |
| #define UPB_CONSTRUCTOR(name, unique_name, ...) \ | |
| static void UPB_PRIVATE(name)(void) { __VA_ARGS__ } | |
| #endif | |
| #endif | |
| // | |
| // Weak alias platform support. Theoretically this should be possible to do with | |
| // only C using attributes like __attribute__((weak, alias("foo"))), but | |
| // Clang doesn't support this properly on macOS. So we have to use assembly. | |
| #if defined(__APPLE__) | |
| // TODO: once https://github.com/llvm/llvm-project/issues/167262 is fixed | |
| // in the LLVM linker, we should have all weak variables point to a single | |
| // "default" empty MiniTable instead of having each leaf define its own, like | |
| // we do with ELF below. This will reduce binary size if many messages are tree | |
| // shaken. | |
| #define UPB_WEAK_SINGLETON_PLACEHOLDER_MINITABLE() | |
| #define UPB_WEAK_PLACEHOLDER_MINITABLE(name) \ | |
| __attribute__((weak)) const upb_MiniTable name = { \ | |
| .UPB_PRIVATE(fields) = NULL, \ | |
| .UPB_PRIVATE(size) = sizeof(struct upb_Message), \ | |
| .UPB_PRIVATE(field_count) = 0, \ | |
| .UPB_PRIVATE(ext) = kUpb_ExtMode_NonExtendable, \ | |
| .UPB_PRIVATE(dense_below) = 0, \ | |
| .UPB_PRIVATE(table_mask) = -1, \ | |
| .UPB_PRIVATE(required_count) = 0, \ | |
| }; | |
| #define UPB_WEAK_ALIAS(type, from, to) \ | |
| extern type to; \ | |
| __asm__(".globl _" #to); \ | |
| __asm__(".private_extern _" #to); \ | |
| __asm__(".set _" #to ", _" #from); \ | |
| __asm__(".weak_definition _" #to); | |
| #define UPB_STRONG_ALIAS(type, from, to) \ | |
| __asm__(".globl _" #to); \ | |
| __asm__(".private_extern _" #to); \ | |
| __asm__(".set _" #to ", _" #from); | |
| #elif defined(__ELF__) || defined(__wasm__) | |
| // On ELF, weak aliases work properly, so we can have all weak MiniTables | |
| // point to the same empty singleton MiniTable. This reduces code size if many | |
| // MiniTables are tree shaken. | |
| #define UPB_WEAK_SINGLETON_PLACEHOLDER_MINITABLE() \ | |
| __attribute__((weak)) \ | |
| const upb_MiniTable kUpb_WeakSingletonPlaceholderMiniTable = { \ | |
| .UPB_PRIVATE(fields) = NULL, \ | |
| .UPB_PRIVATE(size) = sizeof(struct upb_Message), \ | |
| .UPB_PRIVATE(field_count) = 0, \ | |
| .UPB_PRIVATE(ext) = kUpb_ExtMode_NonExtendable, \ | |
| .UPB_PRIVATE(dense_below) = 0, \ | |
| .UPB_PRIVATE(table_mask) = -1, \ | |
| .UPB_PRIVATE(required_count) = 0, \ | |
| }; | |
| #define UPB_WEAK_PLACEHOLDER_MINITABLE(name) | |
| #define UPB_WEAK_ALIAS(type, from, to) \ | |
| extern type to \ | |
| __attribute__((weak, alias("kUpb_WeakSingletonPlaceholderMiniTable"))); | |
| #define UPB_STRONG_ALIAS(type, from, to) \ | |
| extern type to __attribute__((alias(#from))); | |
| #else | |
| #define UPB_WEAK_SINGLETON_PLACEHOLDER_MINITABLE() | |
| #define UPB_WEAK_PLACEHOLDER_MINITABLE(name) | |
| #define UPB_WEAK_ALIAS(type, from, to) weak_alias_not_supported_on_this_platform | |
| #define UPB_STRONG_ALIAS(type, from, to) \ | |
| strong_alias_not_supported_on_this_platform | |
| #endif | |
| /* This file was generated by upb_generator from the input file: | |
| * | |
| * google/protobuf/descriptor.proto | |
| * | |
| * Do not edit -- your changes will be discarded when the file is | |
| * regenerated. | |
| * NO CHECKED-IN PROTOBUF GENCODE */ | |
| #include <stddef.h> | |
| // Must be last. | |
| extern const UPB_PRIVATE(upb_GeneratedExtensionListEntry)* UPB_PRIVATE(upb_generated_extension_list); | |
| typedef struct { | |
| upb_MiniTableField fields[1]; | |
| upb_MiniTableSubInternal subs[1]; | |
| } google__protobuf__FileDescriptorSet_msg_init_Fields; | |
| static const google__protobuf__FileDescriptorSet_msg_init_Fields google_protobuf_FileDescriptorSet__fields = {{ | |
| {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FileDescriptorProto_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__FileDescriptorSet_msg_init = { | |
| &google_protobuf_FileDescriptorSet__fields.fields[0], | |
| 16, 1, kUpb_ExtMode_Extendable, 1, UPB_FASTTABLE_MASK(8), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.FileDescriptorSet", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x000800003f02000a, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[14]; | |
| upb_MiniTableSubInternal subs[7]; | |
| } google__protobuf__FileDescriptorProto_msg_init_Fields; | |
| static const google__protobuf__FileDescriptorProto_msg_init_Fields google_protobuf_FileDescriptorProto__fields = {{ | |
| {1, UPB_SIZE(56, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {2, UPB_SIZE(64, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {3, UPB_SIZE(12, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {4, UPB_SIZE(16, 72), 0, 33, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {5, UPB_SIZE(20, 80), 0, UPB_SIZE(31, 32), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {6, UPB_SIZE(24, 88), 0, UPB_SIZE(29, 31), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {7, UPB_SIZE(28, 96), 0, UPB_SIZE(27, 30), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {8, UPB_SIZE(32, 104), 66, UPB_SIZE(25, 29), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {9, UPB_SIZE(36, 112), 67, UPB_SIZE(23, 28), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {10, UPB_SIZE(40, 120), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {11, UPB_SIZE(44, 128), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {12, UPB_SIZE(72, 48), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {14, UPB_SIZE(48, 12), 69, UPB_SIZE(12, 18), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {15, UPB_SIZE(52, 136), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__DescriptorProto_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__EnumDescriptorProto_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__ServiceDescriptorProto_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FieldDescriptorProto_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FileOptions_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__SourceCodeInfo_msg_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__FileDescriptorProto_msg_init = { | |
| &google_protobuf_FileDescriptorProto__fields.fields[0], | |
| UPB_SIZE(80, 144), 14, kUpb_ExtMode_NonExtendable, 12, UPB_FASTTABLE_MASK(120), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.FileDescriptorProto", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x001000000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0020000001000012, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x004000003f00001a, &upb_DecodeFast_Bytes_Repeated_Tag1Byte}, | |
| {0x004800003f150022, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| {0x005000003f16002a, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| {0x005800003f170032, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| {0x006000003f18003a, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| {0x0068000002190042, &upb_DecodeFast_Message_Scalar_Tag1Byte}, | |
| {0x00700000031a004a, &upb_DecodeFast_Message_Scalar_Tag1Byte}, | |
| {0x007800003f000050, &upb_DecodeFast_Varint32_Repeated_Tag1Byte}, | |
| {0x008000003f000058, &upb_DecodeFast_Varint32_Repeated_Tag1Byte}, | |
| {0x0030000004000062, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x000c0000051b0070, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x008800003f00007a, &upb_DecodeFast_Bytes_Repeated_Tag1Byte}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[11]; | |
| upb_MiniTableSubInternal subs[9]; | |
| } google__protobuf__DescriptorProto_msg_init_Fields; | |
| static const google__protobuf__DescriptorProto_msg_init_Fields google_protobuf_DescriptorProto__fields = {{ | |
| {1, UPB_SIZE(52, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {2, UPB_SIZE(12, 32), 0, UPB_SIZE(30, 31), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {3, UPB_SIZE(16, 40), 0, UPB_SIZE(28, 30), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {4, UPB_SIZE(20, 48), 0, UPB_SIZE(26, 29), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {5, UPB_SIZE(24, 56), 0, UPB_SIZE(24, 28), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {6, UPB_SIZE(28, 64), 0, UPB_SIZE(22, 27), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {7, UPB_SIZE(32, 72), 65, UPB_SIZE(20, 26), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {8, UPB_SIZE(36, 80), 0, UPB_SIZE(18, 25), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {9, UPB_SIZE(40, 88), 0, UPB_SIZE(16, 24), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {10, UPB_SIZE(44, 96), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {11, UPB_SIZE(48, 12), 66, UPB_SIZE(11, 20), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FieldDescriptorProto_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__DescriptorProto_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__EnumDescriptorProto_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__DescriptorProto__ExtensionRange_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FieldDescriptorProto_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__MessageOptions_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__OneofDescriptorProto_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__DescriptorProto__ReservedRange_msg_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__SymbolVisibility_enum_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__DescriptorProto_msg_init = { | |
| &google_protobuf_DescriptorProto__fields.fields[0], | |
| UPB_SIZE(64, 104), 11, kUpb_ExtMode_NonExtendable, 11, UPB_FASTTABLE_MASK(120), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.DescriptorProto", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x001000000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x002000003f110012, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| {0x002800003f12001a, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| {0x003000003f130022, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| {0x003800003f14002a, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| {0x004000003f150032, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| {0x004800000116003a, &upb_DecodeFast_Message_Scalar_Tag1Byte}, | |
| {0x005000003f170042, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| {0x005800003f18004a, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| {0x006000003f000052, &upb_DecodeFast_Bytes_Repeated_Tag1Byte}, | |
| {0x000c000002190058, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[3]; | |
| upb_MiniTableSubInternal subs[1]; | |
| } google__protobuf__DescriptorProto__ExtensionRange_msg_init_Fields; | |
| static const google__protobuf__DescriptorProto__ExtensionRange_msg_init_Fields google_protobuf_DescriptorProto_ExtensionRange__fields = {{ | |
| {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {3, UPB_SIZE(20, 24), 66, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__ExtensionRangeOptions_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__DescriptorProto__ExtensionRange_msg_init = { | |
| &google_protobuf_DescriptorProto_ExtensionRange__fields.fields[0], | |
| UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 3, UPB_FASTTABLE_MASK(24), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.DescriptorProto.ExtensionRange", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x000c000000000008, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, | |
| {0x0010000001000010, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, | |
| {0x001800000205001a, &upb_DecodeFast_Message_Scalar_Tag1Byte}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[2]; | |
| } google__protobuf__DescriptorProto__ReservedRange_msg_init_Fields; | |
| static const google__protobuf__DescriptorProto__ReservedRange_msg_init_Fields google_protobuf_DescriptorProto_ReservedRange__fields = {{ | |
| {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| }}; | |
| const upb_MiniTable google__protobuf__DescriptorProto__ReservedRange_msg_init = { | |
| &google_protobuf_DescriptorProto_ReservedRange__fields.fields[0], | |
| 24, 2, kUpb_ExtMode_NonExtendable, 2, UPB_FASTTABLE_MASK(24), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.DescriptorProto.ReservedRange", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x000c000000000008, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, | |
| {0x0010000001000010, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[4]; | |
| upb_MiniTableSubInternal subs[4]; | |
| } google__protobuf__ExtensionRangeOptions_msg_init_Fields; | |
| static const google__protobuf__ExtensionRangeOptions_msg_init_Fields google_protobuf_ExtensionRangeOptions__fields = {{ | |
| {2, UPB_SIZE(12, 16), 0, 12, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {3, UPB_SIZE(16, 12), 64, UPB_SIZE(10, 11), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {50, UPB_SIZE(20, 24), 65, UPB_SIZE(8, 10), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {999, UPB_SIZE(24, 32), 0, UPB_SIZE(6, 9), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__ExtensionRangeOptions__Declaration_msg_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__ExtensionRangeOptions__VerificationState_enum_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__ExtensionRangeOptions_msg_init = { | |
| &google_protobuf_ExtensionRangeOptions__fields.fields[0], | |
| UPB_SIZE(32, 40), 4, kUpb_ExtMode_Extendable, 0, UPB_FASTTABLE_MASK(248), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.ExtensionRangeOptions", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x001000003f060012, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| {0x000c000000070018, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0018000001080392, &upb_DecodeFast_Message_Scalar_Tag2Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x002000003f093eba, &upb_DecodeFast_Message_Repeated_Tag2Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[5]; | |
| } google__protobuf__ExtensionRangeOptions__Declaration_msg_init_Fields; | |
| static const google__protobuf__ExtensionRangeOptions__Declaration_msg_init_Fields google_protobuf_ExtensionRangeOptions_Declaration__fields = {{ | |
| {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {2, 16, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {3, UPB_SIZE(24, 32), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {5, 9, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {6, 10, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| }}; | |
| const upb_MiniTable google__protobuf__ExtensionRangeOptions__Declaration_msg_init = { | |
| &google_protobuf_ExtensionRangeOptions_Declaration__fields.fields[0], | |
| UPB_SIZE(32, 48), 5, kUpb_ExtMode_NonExtendable, 3, UPB_FASTTABLE_MASK(56), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.ExtensionRangeOptions.Declaration", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x000c000000000008, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, | |
| {0x0010000001000012, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x002000000200001a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0009000003000028, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x000a000004000030, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[11]; | |
| upb_MiniTableSubInternal subs[3]; | |
| } google__protobuf__FieldDescriptorProto_msg_init_Fields; | |
| static const google__protobuf__FieldDescriptorProto_msg_init_Fields google_protobuf_FieldDescriptorProto__fields = {{ | |
| {1, 32, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {2, UPB_SIZE(40, 48), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {3, 12, 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {4, 16, 67, UPB_SIZE(24, 25), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {5, 20, 68, UPB_SIZE(22, 24), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {6, UPB_SIZE(48, 64), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {7, UPB_SIZE(56, 80), 70, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {8, UPB_SIZE(24, 112), 71, UPB_SIZE(14, 17), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {9, UPB_SIZE(28, 24), 72, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {10, UPB_SIZE(64, 96), 73, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {17, 10, 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__FieldDescriptorProto__Label_enum_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__FieldDescriptorProto__Type_enum_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FieldOptions_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__FieldDescriptorProto_msg_init = { | |
| &google_protobuf_FieldDescriptorProto__fields.fields[0], | |
| UPB_SIZE(72, 120), 11, kUpb_ExtMode_NonExtendable, 10, UPB_FASTTABLE_MASK(248), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.FieldDescriptorProto", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x002000000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0030000001000012, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x000c000002000018, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, | |
| {0x0010000003110020, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x0014000004120028, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x0040000005000032, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x005000000600003a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0070000007130042, &upb_DecodeFast_Message_Scalar_Tag1Byte}, | |
| {0x0018000008000048, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, | |
| {0x0060000009000052, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x000a00000a000188, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[2]; | |
| upb_MiniTableSubInternal subs[1]; | |
| } google__protobuf__OneofDescriptorProto_msg_init_Fields; | |
| static const google__protobuf__OneofDescriptorProto_msg_init_Fields google_protobuf_OneofDescriptorProto__fields = {{ | |
| {1, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {2, UPB_SIZE(12, 32), 65, 3, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__OneofOptions_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__OneofDescriptorProto_msg_init = { | |
| &google_protobuf_OneofDescriptorProto__fields.fields[0], | |
| UPB_SIZE(24, 40), 2, kUpb_ExtMode_NonExtendable, 2, UPB_FASTTABLE_MASK(24), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.OneofDescriptorProto", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x001000000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0020000001030012, &upb_DecodeFast_Message_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[6]; | |
| upb_MiniTableSubInternal subs[4]; | |
| } google__protobuf__EnumDescriptorProto_msg_init_Fields; | |
| static const google__protobuf__EnumDescriptorProto_msg_init_Fields google_protobuf_EnumDescriptorProto__fields = {{ | |
| {1, UPB_SIZE(32, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {2, UPB_SIZE(12, 32), 0, 15, 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {3, UPB_SIZE(16, 40), 65, UPB_SIZE(13, 14), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {4, UPB_SIZE(20, 48), 0, UPB_SIZE(11, 13), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {5, UPB_SIZE(24, 56), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {6, UPB_SIZE(28, 12), 66, UPB_SIZE(6, 9), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__EnumValueDescriptorProto_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__EnumOptions_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__SymbolVisibility_enum_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__EnumDescriptorProto_msg_init = { | |
| &google_protobuf_EnumDescriptorProto__fields.fields[0], | |
| UPB_SIZE(40, 64), 6, kUpb_ExtMode_NonExtendable, 6, UPB_FASTTABLE_MASK(56), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.EnumDescriptorProto", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x001000000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x002000003f090012, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| {0x00280000010a001a, &upb_DecodeFast_Message_Scalar_Tag1Byte}, | |
| {0x003000003f0b0022, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| {0x003800003f00002a, &upb_DecodeFast_Bytes_Repeated_Tag1Byte}, | |
| {0x000c0000020c0030, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[2]; | |
| } google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init_Fields; | |
| static const google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init_Fields google_protobuf_EnumDescriptorProto_EnumReservedRange__fields = {{ | |
| {1, 12, 64, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {2, 16, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| }}; | |
| const upb_MiniTable google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init = { | |
| &google_protobuf_EnumDescriptorProto_EnumReservedRange__fields.fields[0], | |
| 24, 2, kUpb_ExtMode_NonExtendable, 2, UPB_FASTTABLE_MASK(24), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.EnumDescriptorProto.EnumReservedRange", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x000c000000000008, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, | |
| {0x0010000001000010, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[3]; | |
| upb_MiniTableSubInternal subs[1]; | |
| } google__protobuf__EnumValueDescriptorProto_msg_init_Fields; | |
| static const google__protobuf__EnumValueDescriptorProto_msg_init_Fields google_protobuf_EnumValueDescriptorProto__fields = {{ | |
| {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {2, 12, 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {3, UPB_SIZE(16, 32), 66, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__EnumValueOptions_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__EnumValueDescriptorProto_msg_init = { | |
| &google_protobuf_EnumValueDescriptorProto__fields.fields[0], | |
| UPB_SIZE(32, 40), 3, kUpb_ExtMode_NonExtendable, 3, UPB_FASTTABLE_MASK(24), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.EnumValueDescriptorProto", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x001000000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x000c000001000010, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, | |
| {0x002000000205001a, &upb_DecodeFast_Message_Scalar_Tag1Byte}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[3]; | |
| upb_MiniTableSubInternal subs[2]; | |
| } google__protobuf__ServiceDescriptorProto_msg_init_Fields; | |
| static const google__protobuf__ServiceDescriptorProto_msg_init_Fields google_protobuf_ServiceDescriptorProto__fields = {{ | |
| {1, UPB_SIZE(20, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {2, UPB_SIZE(12, 32), 0, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {3, UPB_SIZE(16, 40), 65, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__MethodDescriptorProto_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__ServiceOptions_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__ServiceDescriptorProto_msg_init = { | |
| &google_protobuf_ServiceDescriptorProto__fields.fields[0], | |
| UPB_SIZE(32, 48), 3, kUpb_ExtMode_NonExtendable, 3, UPB_FASTTABLE_MASK(24), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.ServiceDescriptorProto", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x001000000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x002000003f050012, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| {0x002800000106001a, &upb_DecodeFast_Message_Scalar_Tag1Byte}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[6]; | |
| upb_MiniTableSubInternal subs[1]; | |
| } google__protobuf__MethodDescriptorProto_msg_init_Fields; | |
| static const google__protobuf__MethodDescriptorProto_msg_init_Fields google_protobuf_MethodDescriptorProto__fields = {{ | |
| {1, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {2, UPB_SIZE(24, 32), 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {3, UPB_SIZE(32, 48), 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {4, UPB_SIZE(12, 64), 67, 9, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {5, 9, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {6, 10, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__MethodOptions_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__MethodDescriptorProto_msg_init = { | |
| &google_protobuf_MethodDescriptorProto__fields.fields[0], | |
| UPB_SIZE(40, 72), 6, kUpb_ExtMode_NonExtendable, 6, UPB_FASTTABLE_MASK(56), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.MethodDescriptorProto", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x001000000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0020000001000012, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x003000000200001a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0040000003090022, &upb_DecodeFast_Message_Scalar_Tag1Byte}, | |
| {0x0009000004000028, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x000a000005000030, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[21]; | |
| upb_MiniTableSubInternal subs[3]; | |
| } google__protobuf__FileOptions_msg_init_Fields; | |
| static const google__protobuf__FileOptions_msg_init_Fields google_protobuf_FileOptions__fields = {{ | |
| {1, UPB_SIZE(32, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {8, 40, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {9, 20, 66, UPB_SIZE(57, 58), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {10, 11, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {11, UPB_SIZE(48, 56), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {16, 12, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {17, 13, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {18, 14, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {20, 15, 72, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {23, 16, 73, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {27, 17, 74, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {31, 18, 75, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {36, UPB_SIZE(56, 72), 76, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {37, UPB_SIZE(64, 88), 77, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {39, UPB_SIZE(72, 104), 78, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {40, UPB_SIZE(80, 120), 79, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {41, UPB_SIZE(88, 136), 80, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {44, UPB_SIZE(96, 152), 81, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {45, UPB_SIZE(104, 168), 82, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {50, UPB_SIZE(24, 184), 83, UPB_SIZE(7, 9), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {999, UPB_SIZE(28, 192), 0, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__FileOptions__OptimizeMode_enum_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__FileOptions_msg_init = { | |
| &google_protobuf_FileOptions__fields.fields[0], | |
| UPB_SIZE(112, 200), 21, kUpb_ExtMode_Extendable, 1, UPB_FASTTABLE_MASK(248), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.FileOptions", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x001800000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0028000001000042, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0014000002200048, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x000b000003000050, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x003800000400005a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x000c000005000180, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, | |
| {0x000d000006000188, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, | |
| {0x000e000007000190, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x000f0000080001a0, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, | |
| {0x005800000d0002aa, &upb_DecodeFast_Bytes_Scalar_Tag2Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x00100000090001b8, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, | |
| {0x007800000f0002c2, &upb_DecodeFast_Bytes_Scalar_Tag2Byte}, | |
| {0x00880000100002ca, &upb_DecodeFast_Bytes_Scalar_Tag2Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x001100000a0001d8, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, | |
| {0x00980000110002e2, &upb_DecodeFast_Bytes_Scalar_Tag2Byte}, | |
| {0x00a80000120002ea, &upb_DecodeFast_Bytes_Scalar_Tag2Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x001200000b0001f8, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[7]; | |
| upb_MiniTableSubInternal subs[2]; | |
| } google__protobuf__MessageOptions_msg_init_Fields; | |
| static const google__protobuf__MessageOptions_msg_init_Fields google_protobuf_MessageOptions__fields = {{ | |
| {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {2, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {3, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {7, 12, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {11, 13, 68, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {12, 16, 69, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {999, UPB_SIZE(20, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__MessageOptions_msg_init = { | |
| &google_protobuf_MessageOptions__fields.fields[0], | |
| UPB_SIZE(24, 32), 7, kUpb_ExtMode_Extendable, 3, UPB_FASTTABLE_MASK(248), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.MessageOptions", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0009000000000008, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x000a000001000010, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x000b000002000018, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x000c000003000038, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x000d000004000058, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x00100000050b0062, &upb_DecodeFast_Message_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x001800003f0c3eba, &upb_DecodeFast_Message_Repeated_Tag2Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[14]; | |
| upb_MiniTableSubInternal subs[8]; | |
| } google__protobuf__FieldOptions_msg_init_Fields; | |
| static const google__protobuf__FieldOptions_msg_init_Fields google_protobuf_FieldOptions__fields = {{ | |
| {1, 16, 64, 42, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {2, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {3, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {5, 12, 67, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {6, 20, 68, UPB_SIZE(31, 32), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {10, 13, 69, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {15, 14, 70, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {16, 15, 71, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {17, 24, 72, UPB_SIZE(20, 22), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {19, UPB_SIZE(28, 32), 0, UPB_SIZE(18, 21), 14, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {20, UPB_SIZE(32, 40), 0, UPB_SIZE(16, 20), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {21, UPB_SIZE(36, 48), 73, UPB_SIZE(14, 19), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {22, UPB_SIZE(40, 56), 74, UPB_SIZE(12, 18), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {999, UPB_SIZE(44, 64), 0, UPB_SIZE(10, 17), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__FieldOptions__CType_enum_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__FieldOptions__JSType_enum_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__FieldOptions__OptionRetention_enum_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__FieldOptions__OptionTargetType_enum_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FieldOptions__EditionDefault_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FieldOptions__FeatureSupport_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__FieldOptions_msg_init = { | |
| &google_protobuf_FieldOptions__fields.fields[0], | |
| UPB_SIZE(48, 72), 14, kUpb_ExtMode_Extendable, 3, UPB_FASTTABLE_MASK(248), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.FieldOptions", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0010000000150008, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x000a000001000010, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x000b000002000018, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x000c000003000028, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x0014000004160030, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x000d000005000050, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x000e000006000078, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x000f000007000180, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, | |
| {0x0018000008170188, &upb_DecodeFast_ClosedEnum_Scalar_Tag2Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x002000003f180198, &upb_DecodeFast_ClosedEnum_Repeated_Tag2Byte}, | |
| {0x002800003f1901a2, &upb_DecodeFast_Message_Repeated_Tag2Byte}, | |
| {0x00300000091a01aa, &upb_DecodeFast_Message_Scalar_Tag2Byte}, | |
| {0x003800000a1b01b2, &upb_DecodeFast_Message_Scalar_Tag2Byte}, | |
| {0x004000003f1c3eba, &upb_DecodeFast_Message_Repeated_Tag2Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[2]; | |
| upb_MiniTableSubInternal subs[1]; | |
| } google__protobuf__FieldOptions__EditionDefault_msg_init_Fields; | |
| static const google__protobuf__FieldOptions__EditionDefault_msg_init_Fields google_protobuf_FieldOptions_EditionDefault__fields = {{ | |
| {2, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {3, 12, 65, 3, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__FieldOptions__EditionDefault_msg_init = { | |
| &google_protobuf_FieldOptions_EditionDefault__fields.fields[0], | |
| UPB_SIZE(24, 32), 2, kUpb_ExtMode_NonExtendable, 0, UPB_FASTTABLE_MASK(24), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.FieldOptions.EditionDefault", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0010000000000012, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x000c000001030018, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[5]; | |
| upb_MiniTableSubInternal subs[3]; | |
| } google__protobuf__FieldOptions__FeatureSupport_msg_init_Fields; | |
| static const google__protobuf__FieldOptions__FeatureSupport_msg_init_Fields google_protobuf_FieldOptions_FeatureSupport__fields = {{ | |
| {1, 12, 64, UPB_SIZE(15, 16), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {2, 16, 65, UPB_SIZE(13, 15), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {3, 24, 66, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {4, 20, 67, UPB_SIZE(8, 11), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {5, UPB_SIZE(32, 40), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__FieldOptions__FeatureSupport_msg_init = { | |
| &google_protobuf_FieldOptions_FeatureSupport__fields.fields[0], | |
| UPB_SIZE(40, 56), 5, kUpb_ExtMode_NonExtendable, 5, UPB_FASTTABLE_MASK(56), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.FieldOptions.FeatureSupport", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x000c000000080008, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x0010000001090010, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x001800000200001a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x00140000030a0020, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x002800000400002a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[2]; | |
| upb_MiniTableSubInternal subs[2]; | |
| } google__protobuf__OneofOptions_msg_init_Fields; | |
| static const google__protobuf__OneofOptions_msg_init_Fields google_protobuf_OneofOptions__fields = {{ | |
| {1, UPB_SIZE(12, 16), 64, 6, 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 5), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__OneofOptions_msg_init = { | |
| &google_protobuf_OneofOptions__fields.fields[0], | |
| UPB_SIZE(24, 32), 2, kUpb_ExtMode_Extendable, 1, UPB_FASTTABLE_MASK(248), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.OneofOptions", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x001000000003000a, &upb_DecodeFast_Message_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x001800003f043eba, &upb_DecodeFast_Message_Repeated_Tag2Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[5]; | |
| upb_MiniTableSubInternal subs[2]; | |
| } google__protobuf__EnumOptions_msg_init_Fields; | |
| static const google__protobuf__EnumOptions_msg_init_Fields google_protobuf_EnumOptions__fields = {{ | |
| {2, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {3, 10, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {6, 11, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {7, UPB_SIZE(12, 16), 67, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__EnumOptions_msg_init = { | |
| &google_protobuf_EnumOptions__fields.fields[0], | |
| UPB_SIZE(24, 32), 5, kUpb_ExtMode_Extendable, 0, UPB_FASTTABLE_MASK(248), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.EnumOptions", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0009000000000010, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x000a000001000018, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x000b000002000030, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x001000000308003a, &upb_DecodeFast_Message_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x001800003f093eba, &upb_DecodeFast_Message_Repeated_Tag2Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[5]; | |
| upb_MiniTableSubInternal subs[3]; | |
| } google__protobuf__EnumValueOptions_msg_init_Fields; | |
| static const google__protobuf__EnumValueOptions_msg_init_Fields google_protobuf_EnumValueOptions__fields = {{ | |
| {1, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {2, UPB_SIZE(12, 16), 65, UPB_SIZE(12, 13), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {3, 10, 66, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {4, UPB_SIZE(16, 24), 67, UPB_SIZE(7, 9), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {999, UPB_SIZE(20, 32), 0, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FieldOptions__FeatureSupport_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__EnumValueOptions_msg_init = { | |
| &google_protobuf_EnumValueOptions__fields.fields[0], | |
| UPB_SIZE(24, 40), 5, kUpb_ExtMode_Extendable, 4, UPB_FASTTABLE_MASK(248), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.EnumValueOptions", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0009000000000008, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x0010000001080012, &upb_DecodeFast_Message_Scalar_Tag1Byte}, | |
| {0x000a000002000018, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x0018000003090022, &upb_DecodeFast_Message_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x002000003f0a3eba, &upb_DecodeFast_Message_Repeated_Tag2Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[3]; | |
| upb_MiniTableSubInternal subs[2]; | |
| } google__protobuf__ServiceOptions_msg_init_Fields; | |
| static const google__protobuf__ServiceOptions_msg_init_Fields google_protobuf_ServiceOptions__fields = {{ | |
| {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {34, UPB_SIZE(12, 16), 65, UPB_SIZE(6, 7), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {999, UPB_SIZE(16, 24), 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__ServiceOptions_msg_init = { | |
| &google_protobuf_ServiceOptions__fields.fields[0], | |
| UPB_SIZE(24, 32), 3, kUpb_ExtMode_Extendable, 0, UPB_FASTTABLE_MASK(248), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.ServiceOptions", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0009000000000288, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, | |
| {0x0010000001050292, &upb_DecodeFast_Message_Scalar_Tag2Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x001800003f063eba, &upb_DecodeFast_Message_Repeated_Tag2Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[4]; | |
| upb_MiniTableSubInternal subs[3]; | |
| } google__protobuf__MethodOptions_msg_init_Fields; | |
| static const google__protobuf__MethodOptions_msg_init_Fields google_protobuf_MethodOptions__fields = {{ | |
| {33, 9, 64, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| {34, 12, 65, 9, 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {35, 16, 66, UPB_SIZE(7, 8), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {999, UPB_SIZE(20, 24), 0, UPB_SIZE(5, 7), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__MethodOptions__IdempotencyLevel_enum_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__MethodOptions_msg_init = { | |
| &google_protobuf_MethodOptions__fields.fields[0], | |
| UPB_SIZE(24, 32), 4, kUpb_ExtMode_Extendable, 0, UPB_FASTTABLE_MASK(248), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.MethodOptions", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0009000000000288, &upb_DecodeFast_Bool_Scalar_Tag2Byte}, | |
| {0x000c000001060290, &upb_DecodeFast_ClosedEnum_Scalar_Tag2Byte}, | |
| {0x001000000207029a, &upb_DecodeFast_Message_Scalar_Tag2Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x001800003f083eba, &upb_DecodeFast_Message_Repeated_Tag2Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[7]; | |
| upb_MiniTableSubInternal subs[1]; | |
| } google__protobuf__UninterpretedOption_msg_init_Fields; | |
| static const google__protobuf__UninterpretedOption_msg_init_Fields google_protobuf_UninterpretedOption__fields = {{ | |
| {2, UPB_SIZE(12, 64), 0, UPB_SIZE(21, 22), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {3, 16, 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {4, UPB_SIZE(40, 72), 65, kUpb_NoSub, 4, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, | |
| {5, UPB_SIZE(48, 80), 66, kUpb_NoSub, 3, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, | |
| {6, UPB_SIZE(56, 88), 67, kUpb_NoSub, 1, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_8Byte << kUpb_FieldRep_Shift)}, | |
| {7, UPB_SIZE(24, 32), 68, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {8, UPB_SIZE(32, 48), 69, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__UninterpretedOption__NamePart_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__UninterpretedOption_msg_init = { | |
| &google_protobuf_UninterpretedOption__fields.fields[0], | |
| UPB_SIZE(64, 96), 7, kUpb_ExtMode_NonExtendable, 0, UPB_FASTTABLE_MASK(120), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.UninterpretedOption", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x004000003f0b0012, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| {0x001000000000001a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0048000001000020, &upb_DecodeFast_Varint64_Scalar_Tag1Byte}, | |
| {0x0050000002000028, &upb_DecodeFast_Varint64_Scalar_Tag1Byte}, | |
| {0x0058000003000031, &upb_DecodeFast_Fixed64_Scalar_Tag1Byte}, | |
| {0x002000000400003a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0030000005000042, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[2]; | |
| } google__protobuf__UninterpretedOption__NamePart_msg_init_Fields; | |
| static const google__protobuf__UninterpretedOption__NamePart_msg_init_Fields google_protobuf_UninterpretedOption_NamePart__fields = {{ | |
| {1, UPB_SIZE(12, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {2, 9, 65, kUpb_NoSub, 8, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_1Byte << kUpb_FieldRep_Shift)}, | |
| }}; | |
| const upb_MiniTable google__protobuf__UninterpretedOption__NamePart_msg_init = { | |
| &google_protobuf_UninterpretedOption_NamePart__fields.fields[0], | |
| UPB_SIZE(24, 32), 2, kUpb_ExtMode_NonExtendable, 2, UPB_FASTTABLE_MASK(24), 2, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.UninterpretedOption.NamePart", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x001000000000000a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0009000001000010, &upb_DecodeFast_Bool_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[9]; | |
| upb_MiniTableSubInternal subs[9]; | |
| } google__protobuf__FeatureSet_msg_init_Fields; | |
| static const google__protobuf__FeatureSet_msg_init_Fields google_protobuf_FeatureSet__fields = {{ | |
| {1, 12, 64, UPB_SIZE(27, 28), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {2, 16, 65, UPB_SIZE(25, 27), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {3, 20, 66, UPB_SIZE(23, 26), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {4, 24, 67, UPB_SIZE(21, 25), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {5, 28, 68, UPB_SIZE(19, 24), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {6, 32, 69, UPB_SIZE(17, 23), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {7, 36, 70, UPB_SIZE(15, 22), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {8, 40, 71, UPB_SIZE(13, 21), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {9, 44, 72, UPB_SIZE(11, 20), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__FieldPresence_enum_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__EnumType_enum_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__RepeatedFieldEncoding_enum_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__Utf8Validation_enum_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__MessageEncoding_enum_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__JsonFormat_enum_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__EnforceNamingStyle_enum_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__VisibilityFeature__DefaultSymbolVisibility_enum_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__FeatureSet__ProtoLimitsFeature__EnforceProtoLimits_enum_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__FeatureSet_msg_init = { | |
| &google_protobuf_FeatureSet__fields.fields[0], | |
| 48, 9, kUpb_ExtMode_Extendable, 9, UPB_FASTTABLE_MASK(120), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.FeatureSet", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x000c0000000e0008, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x00100000010f0010, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x0014000002100018, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x0018000003110020, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x001c000004120028, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x0020000005130030, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x0024000006140038, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x0028000007150040, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x002c000008160048, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| }) | |
| }; | |
| const upb_MiniTable google__protobuf__FeatureSet__VisibilityFeature_msg_init = { | |
| NULL, | |
| 8, 0, kUpb_ExtMode_NonExtendable, 0, UPB_FASTTABLE_MASK(255), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.FeatureSet.VisibilityFeature", | |
| #endif | |
| }; | |
| const upb_MiniTable google__protobuf__FeatureSet__ProtoLimitsFeature_msg_init = { | |
| NULL, | |
| 8, 0, kUpb_ExtMode_NonExtendable, 0, UPB_FASTTABLE_MASK(255), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.FeatureSet.ProtoLimitsFeature", | |
| #endif | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[3]; | |
| upb_MiniTableSubInternal subs[3]; | |
| } google__protobuf__FeatureSetDefaults_msg_init_Fields; | |
| static const google__protobuf__FeatureSetDefaults_msg_init_Fields google_protobuf_FeatureSetDefaults__fields = {{ | |
| {1, UPB_SIZE(12, 24), 0, UPB_SIZE(9, 10), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {4, UPB_SIZE(16, 12), 64, UPB_SIZE(7, 9), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {5, UPB_SIZE(20, 16), 65, UPB_SIZE(5, 8), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__FeatureSetDefaults_msg_init = { | |
| &google_protobuf_FeatureSetDefaults__fields.fields[0], | |
| UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 1, UPB_FASTTABLE_MASK(56), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.FeatureSetDefaults", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x001800003f05000a, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x000c000000060020, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x0010000001070028, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[3]; | |
| upb_MiniTableSubInternal subs[3]; | |
| } google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init_Fields; | |
| static const google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init_Fields google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault__fields = {{ | |
| {3, 12, 64, UPB_SIZE(9, 10), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {4, 16, 65, UPB_SIZE(7, 9), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {5, UPB_SIZE(20, 24), 66, UPB_SIZE(5, 8), 11, (int)kUpb_FieldMode_Scalar | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__Edition_enum_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__FeatureSet_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init = { | |
| &google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault__fields.fields[0], | |
| UPB_SIZE(24, 32), 3, kUpb_ExtMode_NonExtendable, 0, UPB_FASTTABLE_MASK(56), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.FeatureSetDefaults.FeatureSetEditionDefault", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x000c000000050018, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x0010000001060022, &upb_DecodeFast_Message_Scalar_Tag1Byte}, | |
| {0x001800000207002a, &upb_DecodeFast_Message_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[1]; | |
| upb_MiniTableSubInternal subs[1]; | |
| } google__protobuf__SourceCodeInfo_msg_init_Fields; | |
| static const google__protobuf__SourceCodeInfo_msg_init_Fields google_protobuf_SourceCodeInfo__fields = {{ | |
| {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__SourceCodeInfo__Location_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__SourceCodeInfo_msg_init = { | |
| &google_protobuf_SourceCodeInfo__fields.fields[0], | |
| 16, 1, kUpb_ExtMode_Extendable, 1, UPB_FASTTABLE_MASK(8), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.SourceCodeInfo", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeExtensionOrUnknown}, | |
| {0x000800003f02000a, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[5]; | |
| } google__protobuf__SourceCodeInfo__Location_msg_init_Fields; | |
| static const google__protobuf__SourceCodeInfo__Location_msg_init_Fields google_protobuf_SourceCodeInfo_Location__fields = {{ | |
| {1, UPB_SIZE(12, 48), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {2, UPB_SIZE(16, 56), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {3, UPB_SIZE(24, 16), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {4, 32, 65, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {6, UPB_SIZE(20, 64), 0, kUpb_NoSub, 12, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsAlternate | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }}; | |
| const upb_MiniTable google__protobuf__SourceCodeInfo__Location_msg_init = { | |
| &google_protobuf_SourceCodeInfo_Location__fields.fields[0], | |
| UPB_SIZE(40, 72), 5, kUpb_ExtMode_NonExtendable, 4, UPB_FASTTABLE_MASK(56), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.SourceCodeInfo.Location", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x003000003f00000a, &upb_DecodeFast_Varint32_Packed_Tag1Byte}, | |
| {0x003800003f000012, &upb_DecodeFast_Varint32_Packed_Tag1Byte}, | |
| {0x001000000000001a, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0020000001000022, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x004000003f000032, &upb_DecodeFast_Bytes_Repeated_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[1]; | |
| upb_MiniTableSubInternal subs[1]; | |
| } google__protobuf__GeneratedCodeInfo_msg_init_Fields; | |
| static const google__protobuf__GeneratedCodeInfo_msg_init_Fields google_protobuf_GeneratedCodeInfo__fields = {{ | |
| {1, 8, 0, UPB_SIZE(3, 4), 11, (int)kUpb_FieldMode_Array | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(submsg) = &google__protobuf__GeneratedCodeInfo__Annotation_msg_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__GeneratedCodeInfo_msg_init = { | |
| &google_protobuf_GeneratedCodeInfo__fields.fields[0], | |
| 16, 1, kUpb_ExtMode_NonExtendable, 1, UPB_FASTTABLE_MASK(8), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.GeneratedCodeInfo", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x000800003f02000a, &upb_DecodeFast_Message_Repeated_Tag1Byte}, | |
| }) | |
| }; | |
| typedef struct { | |
| upb_MiniTableField fields[5]; | |
| upb_MiniTableSubInternal subs[1]; | |
| } google__protobuf__GeneratedCodeInfo__Annotation_msg_init_Fields; | |
| static const google__protobuf__GeneratedCodeInfo__Annotation_msg_init_Fields google_protobuf_GeneratedCodeInfo_Annotation__fields = {{ | |
| {1, UPB_SIZE(12, 40), 0, kUpb_NoSub, 5, (int)kUpb_FieldMode_Array | (int)kUpb_LabelFlags_IsPacked | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| {2, UPB_SIZE(28, 24), 64, kUpb_NoSub, 12, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsAlternate | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| {3, UPB_SIZE(16, 12), 65, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {4, UPB_SIZE(20, 16), 66, kUpb_NoSub, 5, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| {5, UPB_SIZE(24, 20), 67, UPB_SIZE(3, 4), 14, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_4Byte << kUpb_FieldRep_Shift)}, | |
| }, | |
| { | |
| {.UPB_PRIVATE(subenum) = &google__protobuf__GeneratedCodeInfo__Annotation__Semantic_enum_init}, | |
| }}; | |
| const upb_MiniTable google__protobuf__GeneratedCodeInfo__Annotation_msg_init = { | |
| &google_protobuf_GeneratedCodeInfo_Annotation__fields.fields[0], | |
| UPB_SIZE(40, 48), 5, kUpb_ExtMode_NonExtendable, 5, UPB_FASTTABLE_MASK(56), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "google.protobuf.GeneratedCodeInfo.Annotation", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x002800003f00000a, &upb_DecodeFast_Varint32_Packed_Tag1Byte}, | |
| {0x0018000000000012, &upb_DecodeFast_Bytes_Scalar_Tag1Byte}, | |
| {0x000c000001000018, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, | |
| {0x0010000002000020, &upb_DecodeFast_Varint32_Scalar_Tag1Byte}, | |
| {0x0014000003080028, &upb_DecodeFast_ClosedEnum_Scalar_Tag1Byte}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| }) | |
| }; | |
| const upb_MiniTableEnum google__protobuf__Edition_enum_init = { | |
| 64, | |
| 11, | |
| { | |
| 0x7, | |
| 0x0, | |
| 0x384, | |
| 0x3e6, | |
| 0x3e7, | |
| 0x3e8, | |
| 0x3e9, | |
| 0x3ea, | |
| 0x270f, | |
| 0x1869d, | |
| 0x1869e, | |
| 0x1869f, | |
| 0x7fffffff, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__ExtensionRangeOptions__VerificationState_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0x3, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__FeatureSet__EnforceNamingStyle_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0xf, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__FeatureSet__EnumType_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0x7, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__FeatureSet__FieldPresence_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0xf, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__FeatureSet__JsonFormat_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0x7, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__FeatureSet__MessageEncoding_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0x7, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__FeatureSet__ProtoLimitsFeature__EnforceProtoLimits_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0x7, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__FeatureSet__RepeatedFieldEncoding_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0x7, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__FeatureSet__Utf8Validation_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0xd, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__FeatureSet__VisibilityFeature__DefaultSymbolVisibility_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0x1f, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__FieldDescriptorProto__Label_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0xe, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__FieldDescriptorProto__Type_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0x7fffe, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__FieldOptions__CType_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0x7, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__FieldOptions__JSType_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0x7, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__FieldOptions__OptionRetention_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0x7, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__FieldOptions__OptionTargetType_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0x3ff, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__FileOptions__OptimizeMode_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0xe, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__GeneratedCodeInfo__Annotation__Semantic_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0x7, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__MethodOptions__IdempotencyLevel_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0x7, | |
| 0x0, | |
| }, | |
| }; | |
| const upb_MiniTableEnum google__protobuf__SymbolVisibility_enum_init = { | |
| 64, | |
| 0, | |
| { | |
| 0x7, | |
| 0x0, | |
| }, | |
| }; | |
| static const upb_MiniTable *messages_layout_google_protobuf_descriptor_proto_upb_file_layout[35] = { | |
| &google__protobuf__FileDescriptorSet_msg_init, | |
| &google__protobuf__FileDescriptorProto_msg_init, | |
| &google__protobuf__DescriptorProto_msg_init, | |
| &google__protobuf__DescriptorProto__ExtensionRange_msg_init, | |
| &google__protobuf__DescriptorProto__ReservedRange_msg_init, | |
| &google__protobuf__ExtensionRangeOptions_msg_init, | |
| &google__protobuf__ExtensionRangeOptions__Declaration_msg_init, | |
| &google__protobuf__FieldDescriptorProto_msg_init, | |
| &google__protobuf__OneofDescriptorProto_msg_init, | |
| &google__protobuf__EnumDescriptorProto_msg_init, | |
| &google__protobuf__EnumDescriptorProto__EnumReservedRange_msg_init, | |
| &google__protobuf__EnumValueDescriptorProto_msg_init, | |
| &google__protobuf__ServiceDescriptorProto_msg_init, | |
| &google__protobuf__MethodDescriptorProto_msg_init, | |
| &google__protobuf__FileOptions_msg_init, | |
| &google__protobuf__MessageOptions_msg_init, | |
| &google__protobuf__FieldOptions_msg_init, | |
| &google__protobuf__FieldOptions__EditionDefault_msg_init, | |
| &google__protobuf__FieldOptions__FeatureSupport_msg_init, | |
| &google__protobuf__OneofOptions_msg_init, | |
| &google__protobuf__EnumOptions_msg_init, | |
| &google__protobuf__EnumValueOptions_msg_init, | |
| &google__protobuf__ServiceOptions_msg_init, | |
| &google__protobuf__MethodOptions_msg_init, | |
| &google__protobuf__UninterpretedOption_msg_init, | |
| &google__protobuf__UninterpretedOption__NamePart_msg_init, | |
| &google__protobuf__FeatureSet_msg_init, | |
| &google__protobuf__FeatureSet__VisibilityFeature_msg_init, | |
| &google__protobuf__FeatureSet__ProtoLimitsFeature_msg_init, | |
| &google__protobuf__FeatureSetDefaults_msg_init, | |
| &google__protobuf__FeatureSetDefaults__FeatureSetEditionDefault_msg_init, | |
| &google__protobuf__SourceCodeInfo_msg_init, | |
| &google__protobuf__SourceCodeInfo__Location_msg_init, | |
| &google__protobuf__GeneratedCodeInfo_msg_init, | |
| &google__protobuf__GeneratedCodeInfo__Annotation_msg_init, | |
| }; | |
| static const upb_MiniTableEnum *enums_layout_google_protobuf_descriptor_proto_upb_file_layout[21] = { | |
| &google__protobuf__Edition_enum_init, | |
| &google__protobuf__ExtensionRangeOptions__VerificationState_enum_init, | |
| &google__protobuf__FeatureSet__EnforceNamingStyle_enum_init, | |
| &google__protobuf__FeatureSet__EnumType_enum_init, | |
| &google__protobuf__FeatureSet__FieldPresence_enum_init, | |
| &google__protobuf__FeatureSet__JsonFormat_enum_init, | |
| &google__protobuf__FeatureSet__MessageEncoding_enum_init, | |
| &google__protobuf__FeatureSet__ProtoLimitsFeature__EnforceProtoLimits_enum_init, | |
| &google__protobuf__FeatureSet__RepeatedFieldEncoding_enum_init, | |
| &google__protobuf__FeatureSet__Utf8Validation_enum_init, | |
| &google__protobuf__FeatureSet__VisibilityFeature__DefaultSymbolVisibility_enum_init, | |
| &google__protobuf__FieldDescriptorProto__Label_enum_init, | |
| &google__protobuf__FieldDescriptorProto__Type_enum_init, | |
| &google__protobuf__FieldOptions__CType_enum_init, | |
| &google__protobuf__FieldOptions__JSType_enum_init, | |
| &google__protobuf__FieldOptions__OptionRetention_enum_init, | |
| &google__protobuf__FieldOptions__OptionTargetType_enum_init, | |
| &google__protobuf__FileOptions__OptimizeMode_enum_init, | |
| &google__protobuf__GeneratedCodeInfo__Annotation__Semantic_enum_init, | |
| &google__protobuf__MethodOptions__IdempotencyLevel_enum_init, | |
| &google__protobuf__SymbolVisibility_enum_init, | |
| }; | |
| const upb_MiniTableFile google_protobuf_descriptor_proto_upb_file_layout = { | |
| messages_layout_google_protobuf_descriptor_proto_upb_file_layout, | |
| enums_layout_google_protobuf_descriptor_proto_upb_file_layout, | |
| NULL, | |
| 35, | |
| 21, | |
| 0, | |
| }; | |
| /* This file was generated by upb_generator from the input file: | |
| * | |
| * google/protobuf/json_enumvalue_options.proto | |
| * | |
| * Do not edit -- your changes will be discarded when the file is | |
| * regenerated. | |
| * NO CHECKED-IN PROTOBUF GENCODE */ | |
| #include <stddef.h> | |
| // Must be last. | |
| extern const UPB_PRIVATE(upb_GeneratedExtensionListEntry)* UPB_PRIVATE(upb_generated_extension_list); | |
| typedef struct { | |
| upb_MiniTableField fields[1]; | |
| } pb__enumvalue__JsonEnumValueOptions_msg_init_Fields; | |
| static const pb__enumvalue__JsonEnumValueOptions_msg_init_Fields pb_enumvalue_JsonEnumValueOptions__fields = {{ | |
| {1, UPB_SIZE(12, 16), 64, kUpb_NoSub, 9, (int)kUpb_FieldMode_Scalar | ((int)kUpb_FieldRep_StringView << kUpb_FieldRep_Shift)}, | |
| }}; | |
| const upb_MiniTable pb__enumvalue__JsonEnumValueOptions_msg_init = { | |
| &pb_enumvalue_JsonEnumValueOptions__fields.fields[0], | |
| UPB_SIZE(24, 32), 1, kUpb_ExtMode_NonExtendable, 1, UPB_FASTTABLE_MASK(8), 0, | |
| #ifdef UPB_TRACING_ENABLED | |
| "pb.enumvalue.JsonEnumValueOptions", | |
| #endif | |
| UPB_FASTTABLE_INIT({ | |
| {0x0000000000000000, &_upb_FastDecoder_DecodeUnknown}, | |
| {0x001000000000000a, &upb_DecodeFast_String_Scalar_Tag1Byte}, | |
| }) | |
| }; | |
| UPB_STATIC_ASSERT(offsetof(upb_MiniTableExtensionWithSub, UPB_PRIVATE(sub)) == UPB_SIZE(16, 24), | |
| "extension sub offset mismatch"); | |
| static const upb_MiniTableExtensionWithSub pb_enumvalue_json_ext_obj = { | |
| { | |
| {998, 0, 0, UPB_SIZE(4, 6), 11, (int)kUpb_FieldMode_Scalar | (int)kUpb_LabelFlags_IsExtension | ((int)UPB_SIZE(kUpb_FieldRep_4Byte, kUpb_FieldRep_8Byte) << kUpb_FieldRep_Shift)}, | |
| &google__protobuf__EnumValueOptions_msg_init, | |
| }, | |
| {.UPB_PRIVATE(submsg) = &pb__enumvalue__JsonEnumValueOptions_msg_init}, | |
| }; | |
| UPB_LINKARR_APPEND(upb_AllExts) | |
| const upb_MiniTableExtension* pb_enumvalue_json_ext = (const upb_MiniTableExtension*)&pb_enumvalue_json_ext_obj; | |
| static const upb_MiniTable *messages_layout_google_protobuf_json_enumvalue_options_proto_upb_file_layout[1] = { | |
| &pb__enumvalue__JsonEnumValueOptions_msg_init, | |
| }; | |
| static const upb_MiniTableExtension *extensions_layout_google_protobuf_json_enumvalue_options_proto_upb_file_layout[1] = { | |
| (const upb_MiniTableExtension*)&pb_enumvalue_json_ext_obj, | |
| }; | |
| UPB_LINKARR_DECLARE(upb_AllExts, const upb_MiniTableExtension*); | |
| UPB_CONSTRUCTOR(upb_GeneratedRegistry_Constructor, google_protobuf_json_enumvalue_options_proto_ext_constructor, { | |
| static bool finished = false; | |
| if (finished) return; | |
| finished = true; | |
| static UPB_PRIVATE(upb_GeneratedExtensionListEntry) entry = { | |
| UPB_LINKARR_START(upb_AllExts), | |
| UPB_LINKARR_STOP(upb_AllExts), | |
| NULL | |
| }; | |
| UPB_ASSERT(entry.next == NULL); | |
| entry.next = UPB_PRIVATE(upb_generated_extension_list); | |
| UPB_PRIVATE(upb_generated_extension_list) = &entry; | |
| }) | |
| const upb_MiniTableFile google_protobuf_json_enumvalue_options_proto_upb_file_layout = { | |
| messages_layout_google_protobuf_json_enumvalue_options_proto_upb_file_layout, | |
| NULL, | |
| extensions_layout_google_protobuf_json_enumvalue_options_proto_upb_file_layout, | |
| 1, | |
| 0, | |
| 1, | |
| }; | |
| #include <errno.h> | |
| #include <float.h> | |
| #include <stdarg.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| // Must be last. | |
| void upb_Status_Clear(upb_Status* status) { | |
| if (!status) return; | |
| status->ok = true; | |
| status->msg[0] = '\0'; | |
| } | |
| bool upb_Status_IsOk(const upb_Status* status) { return status->ok; } | |
| const char* upb_Status_ErrorMessage(const upb_Status* status) { | |
| return status->msg; | |
| } | |
| void upb_Status_SetErrorMessage(upb_Status* status, const char* msg) { | |
| if (!status) return; | |
| status->ok = false; | |
| strncpy(status->msg, msg, _kUpb_Status_MaxMessage - 1); | |
| status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; | |
| } | |
| void upb_Status_SetErrorFormat(upb_Status* status, const char* fmt, ...) { | |
| va_list args; | |
| va_start(args, fmt); | |
| upb_Status_VSetErrorFormat(status, fmt, args); | |
| va_end(args); | |
| } | |
| void upb_Status_VSetErrorFormat(upb_Status* status, const char* fmt, | |
| va_list args) { | |
| if (!status) return; | |
| status->ok = false; | |
| vsnprintf(status->msg, sizeof(status->msg), fmt, args); | |
| status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; | |
| } | |
| void upb_Status_VAppendErrorFormat(upb_Status* status, const char* fmt, | |
| va_list args) { | |
| size_t len; | |
| if (!status) return; | |
| status->ok = false; | |
| len = strlen(status->msg); | |
| vsnprintf(status->msg + len, sizeof(status->msg) - len, fmt, args); | |
| status->msg[_kUpb_Status_MaxMessage - 1] = '\0'; | |
| } | |
| /* | |
| * upb_table Implementation | |
| * | |
| * Implementation is heavily inspired by Lua's ltable.c. | |
| */ | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| #if defined(__has_builtin) | |
| #if __has_builtin(__builtin_popcount) | |
| #define UPB_FAST_POPCOUNT32(i) __builtin_popcount(i) | |
| #endif | |
| #elif defined(__GNUC__) | |
| #define UPB_FAST_POPCOUNT32(i) __builtin_popcount(i) | |
| #elif defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64)) | |
| // Only use __popcnt on x86/x64 architectures for MSVC | |
| #define UPB_FAST_POPCOUNT32(i) __popcnt(i) | |
| #endif | |
| UPB_INLINE int _upb_popcnt32(uint32_t i) { | |
| #ifdef UPB_FAST_POPCOUNT32 | |
| return UPB_FAST_POPCOUNT32(i); | |
| #else | |
| int count = 0; | |
| while (i != 0) { | |
| count += i & 1; | |
| i >>= 1; | |
| } | |
| return count; | |
| #endif | |
| } | |
| #undef UPB_FAST_POPCOUNT32 | |
| UPB_INLINE uint8_t _upb_log2_table_size(const upb_table* t) { | |
| return _upb_popcnt32(t->mask); | |
| } | |
| /* A type to represent the lookup key of either a strtable, inttable or | |
| * exttable. */ | |
| typedef union { | |
| uintptr_t num; | |
| upb_StringView str; | |
| struct { | |
| const void* ptr; | |
| uint32_t ext_num; | |
| } ext; | |
| } lookupkey_t; | |
| static lookupkey_t strkey2(const char* str, size_t len) { | |
| return (lookupkey_t){.str = upb_StringView_FromDataAndSize(str, len)}; | |
| } | |
| static lookupkey_t intkey(uintptr_t key) { return (lookupkey_t){.num = key}; } | |
| static lookupkey_t extkey(const void* ptr, uint32_t ext_num) { | |
| return (lookupkey_t){.ext = {ptr, ext_num}}; | |
| } | |
| // Conceptually the hash and equal functions should only take the key, not the | |
| // value, but the extension table stores part of its logical key in the value | |
| // slot. This is a sign that we have outgrown the original architecture. | |
| typedef uint32_t hashfunc_t(upb_key key, upb_value val); | |
| typedef bool eqlfunc_t(upb_key k1, upb_value v1, lookupkey_t k2); | |
| /* Base table (shared code) ***************************************************/ | |
| static bool isfull(upb_table* t) { return upb_table_isfull(t); } | |
| static bool init(upb_table* t, uint8_t size_lg2, upb_Arena* a) { | |
| if (size_lg2 >= 32) { | |
| return false; | |
| } | |
| t->count = 0; | |
| uint32_t size = 1U << size_lg2; | |
| t->mask = size - 1; // 0 mask if size_lg2 is 0 | |
| size_t bytes; | |
| if (upb_MulOverflow(upb_table_size(t), sizeof(upb_tabent), &bytes)) { | |
| return false; | |
| } | |
| if (bytes > 0) { | |
| t->entries = upb_Arena_Malloc(a, bytes); | |
| if (!t->entries) return false; | |
| memset(t->entries, 0, bytes); | |
| } else { | |
| t->entries = NULL; | |
| } | |
| return true; | |
| } | |
| static upb_tabent* emptyent(upb_table* t, upb_tabent* e) { | |
| upb_tabent* begin = t->entries; | |
| upb_tabent* end = begin + upb_table_size(t); | |
| for (e = e + 1; e < end; e++) { | |
| if (upb_tabent_isempty(e)) return e; | |
| } | |
| for (e = begin; e < end; e++) { | |
| if (upb_tabent_isempty(e)) return e; | |
| } | |
| UPB_ASSERT(false); | |
| return NULL; | |
| } | |
| static upb_tabent* getentry_mutable(upb_table* t, uint32_t hash) { | |
| return upb_getentry(t, hash); | |
| } | |
| static upb_tabent* findentry(const upb_table* t, lookupkey_t key, uint32_t hash, | |
| eqlfunc_t* eql) { | |
| upb_tabent* e; | |
| if (t->count == 0) return NULL; | |
| e = upb_getentry(t, hash); | |
| if (upb_tabent_isempty(e)) return NULL; | |
| while (1) { | |
| if (eql(e->key, e->val, key)) return e; | |
| if (!upb_tabent_hasnext(e)) return NULL; | |
| e = upb_tabent_next(e); | |
| } | |
| } | |
| static upb_tabent* findentry_mutable(upb_table* t, lookupkey_t key, | |
| uint32_t hash, eqlfunc_t* eql) { | |
| return findentry(t, key, hash, eql); | |
| } | |
| static bool lookup(const upb_table* t, lookupkey_t key, upb_value* v, | |
| uint32_t hash, eqlfunc_t* eql) { | |
| const upb_tabent* e = findentry(t, key, hash, eql); | |
| if (e) { | |
| if (v) *v = e->val; | |
| return true; | |
| } else { | |
| return false; | |
| } | |
| } | |
| /* The given key must not already exist in the table. */ | |
| static void insert(upb_table* t, lookupkey_t key, upb_key tabkey, upb_value val, | |
| uint32_t hash, hashfunc_t* hashfunc, eqlfunc_t* eql) { | |
| upb_tabent* mainpos_e; | |
| upb_tabent* our_e; | |
| UPB_ASSERT(findentry(t, key, hash, eql) == NULL); | |
| t->count++; | |
| mainpos_e = getentry_mutable(t, hash); | |
| our_e = mainpos_e; | |
| if (upb_tabent_isempty(mainpos_e)) { | |
| /* Our main position is empty; use it. */ | |
| upb_tabent_clearnext(our_e); | |
| } else { | |
| /* Collision. */ | |
| upb_tabent* new_e = emptyent(t, mainpos_e); | |
| /* Head of collider's chain. */ | |
| upb_tabent* chain = | |
| getentry_mutable(t, hashfunc(mainpos_e->key, mainpos_e->val)); | |
| if (chain == mainpos_e) { | |
| /* Existing ent is in its main position (it has the same hash as us, and | |
| * is the head of our chain). Insert to new ent and append to this chain. | |
| */ | |
| if (upb_tabent_hasnext(mainpos_e)) { | |
| upb_tabent_setnext(new_e, upb_tabent_next(mainpos_e)); | |
| } else { | |
| upb_tabent_clearnext(new_e); | |
| } | |
| upb_tabent_setnext(mainpos_e, new_e); | |
| our_e = new_e; | |
| } else { | |
| /* Existing ent is not in its main position (it is a node in some other | |
| * chain). This implies that no existing ent in the table has our hash. | |
| * Evict it (updating its chain) and use its ent for head of our chain. */ | |
| new_e->key = mainpos_e->key; | |
| new_e->val = mainpos_e->val; | |
| if (upb_tabent_hasnext(mainpos_e)) { | |
| upb_tabent_setnext(new_e, upb_tabent_next(mainpos_e)); | |
| } else { | |
| upb_tabent_clearnext(new_e); | |
| } | |
| while (upb_tabent_hasnext(chain) && upb_tabent_next(chain) != mainpos_e) { | |
| chain = upb_tabent_next(chain); | |
| UPB_ASSERT(chain); | |
| } | |
| upb_tabent_setnext(chain, new_e); | |
| our_e = mainpos_e; | |
| upb_tabent_clearnext(our_e); | |
| } | |
| } | |
| our_e->key = tabkey; | |
| our_e->val = val; | |
| UPB_ASSERT(findentry(t, key, hash, eql) == our_e); | |
| } | |
| static bool rm(upb_table* t, lookupkey_t key, upb_value* val, uint32_t hash, | |
| eqlfunc_t* eql) { | |
| upb_tabent* chain = getentry_mutable(t, hash); | |
| if (upb_tabent_isempty(chain)) return false; | |
| if (eql(chain->key, chain->val, key)) { | |
| /* Element to remove is at the head of its chain. */ | |
| t->count--; | |
| if (val) *val = chain->val; | |
| if (upb_tabent_hasnext(chain)) { | |
| upb_tabent* move = upb_tabent_next(chain); | |
| chain->key = move->key; | |
| chain->val = move->val; | |
| if (upb_tabent_hasnext(move)) { | |
| upb_tabent_setnext(chain, upb_tabent_next(move)); | |
| } else { | |
| upb_tabent_clearnext(chain); | |
| } | |
| upb_tabent_clear(move); | |
| } else { | |
| upb_tabent_clear(chain); | |
| } | |
| return true; | |
| } else { | |
| /* Element to remove is either in a non-head position or not in the | |
| * table. */ | |
| while ( | |
| upb_tabent_hasnext(chain) && | |
| !eql(upb_tabent_next(chain)->key, upb_tabent_next(chain)->val, key)) { | |
| chain = upb_tabent_next(chain); | |
| } | |
| if (upb_tabent_hasnext(chain)) { | |
| /* Found element to remove. */ | |
| upb_tabent* rm = upb_tabent_next(chain); | |
| t->count--; | |
| if (val) *val = rm->val; | |
| if (upb_tabent_hasnext(rm)) { | |
| upb_tabent_setnext(chain, upb_tabent_next(rm)); | |
| } else { | |
| upb_tabent_clearnext(chain); | |
| } | |
| upb_tabent_clear(rm); | |
| return true; | |
| } else { | |
| /* Element to remove is not in the table. */ | |
| return false; | |
| } | |
| } | |
| } | |
| static size_t next(const upb_table* t, size_t i) { | |
| do { | |
| if (++i >= upb_table_size(t)) return SIZE_MAX - 1; /* Distinct from -1. */ | |
| } while (upb_tabent_isempty(&t->entries[i])); | |
| return i; | |
| } | |
| static size_t begin(const upb_table* t) { return next(t, -1); } | |
| UPB_FORCEINLINE | |
| bool _upb_tablenext(const upb_table* t, upb_tabent** ent, intptr_t* iter) { | |
| size_t tab_idx = next(t, *iter); | |
| if (tab_idx < upb_table_size(t)) { | |
| *ent = &t->entries[tab_idx]; | |
| *iter = tab_idx; | |
| return true; | |
| } | |
| return false; | |
| } | |
| UPB_FORCEINLINE | |
| bool _upb_table_done(const upb_table* t, intptr_t iter) { | |
| if (iter == INTPTR_MAX - 1 || (size_t)iter >= upb_table_size(t)) { | |
| return true; | |
| } | |
| return upb_tabent_isempty(&t->entries[iter]); | |
| } | |
| static void removeiter(upb_table* t, intptr_t* iter) { | |
| intptr_t i = *iter; | |
| upb_tabent* ent = &t->entries[i]; | |
| upb_tabent* prev = NULL; | |
| // Linear search, not great. | |
| upb_tabent* end = &t->entries[upb_table_size(t)]; | |
| for (upb_tabent* e = t->entries; e != end; e++) { | |
| if (!upb_tabent_isempty(e) && upb_tabent_hasnext(e) && | |
| upb_tabent_next(e) == ent) { | |
| prev = e; | |
| break; | |
| } | |
| } | |
| if (prev) { | |
| if (upb_tabent_hasnext(ent)) { | |
| upb_tabent_setnext(prev, upb_tabent_next(ent)); | |
| } else { | |
| upb_tabent_clearnext(prev); | |
| } | |
| } else { | |
| // ent is the head of the chain, so we need to move its next element into | |
| // its slot if there is one. | |
| if (upb_tabent_hasnext(ent)) { | |
| upb_tabent* move = upb_tabent_next(ent); | |
| ent->key = move->key; | |
| ent->val = move->val; | |
| if (upb_tabent_hasnext(move)) { | |
| upb_tabent_setnext(ent, upb_tabent_next(move)); | |
| } else { | |
| upb_tabent_clearnext(ent); | |
| } | |
| // If we moved an element from a higher index to a lower index, then we've | |
| // moved an element we haven't visited yet into the slot of the one that | |
| // was just removed; decrement iter so that the iterator visits it. | |
| if (move > ent) { | |
| *iter = i - 1; | |
| } | |
| ent = move; | |
| } | |
| } | |
| t->count--; | |
| upb_tabent_clear(ent); | |
| } | |
| /* upb_strtable ***************************************************************/ | |
| // A simple "subclass" of upb_table that only adds a hash function for strings. | |
| static upb_SizePrefixString* upb_SizePrefixString_Copy(upb_StringView s, | |
| upb_Arena* a) { | |
| // A 2GB string will fail at serialization time, but we accept up to 4GB in | |
| // memory here. | |
| if (s.size > UINT32_MAX) return NULL; | |
| upb_SizePrefixString* str = | |
| upb_Arena_Malloc(a, sizeof(uint32_t) + s.size + 1); | |
| if (str == NULL) return NULL; | |
| str->size = s.size; | |
| char* data = (char*)str->data; | |
| if (s.size) memcpy(data, s.data, s.size); | |
| data[s.size] = '\0'; | |
| return str; | |
| } | |
| /* Adapted from ABSL's wyhash. */ | |
| static uint64_t UnalignedLoad64(const void* p) { | |
| uint64_t val; | |
| memcpy(&val, p, 8); | |
| return val; | |
| } | |
| static uint32_t UnalignedLoad32(const void* p) { | |
| uint32_t val; | |
| memcpy(&val, p, 4); | |
| return val; | |
| } | |
| #if defined(_MSC_VER) && defined(_M_X64) | |
| #include <intrin.h> | |
| #endif | |
| /* Computes a * b, returning the low 64 bits of the result and storing the high | |
| * 64 bits in |*high|. */ | |
| static uint64_t upb_umul128(uint64_t v0, uint64_t v1, uint64_t* out_high) { | |
| #ifdef __SIZEOF_INT128__ | |
| __uint128_t p = v0; | |
| p *= v1; | |
| *out_high = (uint64_t)(p >> 64); | |
| return (uint64_t)p; | |
| #elif defined(_MSC_VER) && defined(_M_X64) | |
| return _umul128(v0, v1, out_high); | |
| #else | |
| uint64_t a32 = v0 >> 32; | |
| uint64_t a00 = v0 & 0xffffffff; | |
| uint64_t b32 = v1 >> 32; | |
| uint64_t b00 = v1 & 0xffffffff; | |
| uint64_t high = a32 * b32; | |
| uint64_t low = a00 * b00; | |
| uint64_t mid1 = a32 * b00; | |
| uint64_t mid2 = a00 * b32; | |
| low += (mid1 << 32) + (mid2 << 32); | |
| // Omit carry bit, for mixing we do not care about exact numerical precision. | |
| high += (mid1 >> 32) + (mid2 >> 32); | |
| *out_high = high; | |
| return low; | |
| #endif | |
| } | |
| static uint64_t WyhashMix(uint64_t v0, uint64_t v1) { | |
| uint64_t high; | |
| uint64_t low = upb_umul128(v0, v1, &high); | |
| return low ^ high; | |
| } | |
| static uint64_t Wyhash(const void* data, size_t len, uint64_t seed, | |
| const uint64_t salt[]) { | |
| const uint8_t* ptr = (const uint8_t*)data; | |
| uint64_t starting_length = (uint64_t)len; | |
| uint64_t current_state = seed ^ salt[0]; | |
| if (len > 64) { | |
| // If we have more than 64 bytes, we're going to handle chunks of 64 | |
| // bytes at a time. We're going to build up two separate hash states | |
| // which we will then hash together. | |
| uint64_t duplicated_state = current_state; | |
| do { | |
| uint64_t a = UnalignedLoad64(ptr); | |
| uint64_t b = UnalignedLoad64(ptr + 8); | |
| uint64_t c = UnalignedLoad64(ptr + 16); | |
| uint64_t d = UnalignedLoad64(ptr + 24); | |
| uint64_t e = UnalignedLoad64(ptr + 32); | |
| uint64_t f = UnalignedLoad64(ptr + 40); | |
| uint64_t g = UnalignedLoad64(ptr + 48); | |
| uint64_t h = UnalignedLoad64(ptr + 56); | |
| uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state); | |
| uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state); | |
| current_state = (cs0 ^ cs1); | |
| uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state); | |
| uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state); | |
| duplicated_state = (ds0 ^ ds1); | |
| ptr += 64; | |
| len -= 64; | |
| } while (len > 64); | |
| current_state = current_state ^ duplicated_state; | |
| } | |
| // We now have a data `ptr` with at most 64 bytes and the current state | |
| // of the hashing state machine stored in current_state. | |
| while (len > 16) { | |
| uint64_t a = UnalignedLoad64(ptr); | |
| uint64_t b = UnalignedLoad64(ptr + 8); | |
| current_state = WyhashMix(a ^ salt[1], b ^ current_state); | |
| ptr += 16; | |
| len -= 16; | |
| } | |
| // We now have a data `ptr` with at most 16 bytes. | |
| uint64_t a = 0; | |
| uint64_t b = 0; | |
| if (len > 8) { | |
| // When we have at least 9 and at most 16 bytes, set A to the first 64 | |
| // bits of the input and B to the last 64 bits of the input. Yes, they will | |
| // overlap in the middle if we are working with less than the full 16 | |
| // bytes. | |
| a = UnalignedLoad64(ptr); | |
| b = UnalignedLoad64(ptr + len - 8); | |
| } else if (len > 3) { | |
| // If we have at least 4 and at most 8 bytes, set A to the first 32 | |
| // bits and B to the last 32 bits. | |
| a = UnalignedLoad32(ptr); | |
| b = UnalignedLoad32(ptr + len - 4); | |
| } else if (len > 0) { | |
| // If we have at least 1 and at most 3 bytes, read all of the provided | |
| // bits into A, with some adjustments. | |
| a = ((ptr[0] << 16) | (ptr[len >> 1] << 8) | ptr[len - 1]); | |
| b = 0; | |
| } else { | |
| a = 0; | |
| b = 0; | |
| } | |
| uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state); | |
| uint64_t z = salt[1] ^ starting_length; | |
| return WyhashMix(w, z); | |
| } | |
| const uint64_t kWyhashSalt[5] = { | |
| 0x243F6A8885A308D3ULL, 0x13198A2E03707344ULL, 0xA4093822299F31D0ULL, | |
| 0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL, | |
| }; | |
| uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed) { | |
| return Wyhash(p, n, seed, kWyhashSalt); | |
| } | |
| static const void* const _upb_seed; | |
| // Returns a random seed for upb's hash function. This does not provide | |
| // high-quality randomness, but it should be enough to prevent unit tests from | |
| // relying on a deterministic map ordering. By returning the address of a | |
| // variable, we are able to get some randomness for free provided that ASLR is | |
| // enabled. | |
| static uint64_t _upb_Seed(void) { return (uint64_t)&_upb_seed; } | |
| static uint32_t _upb_Hash_NoSeed(const char* p, size_t n) { | |
| return _upb_Hash(p, n, _upb_Seed()); | |
| } | |
| static uint32_t strhash(upb_key key, upb_value val) { | |
| UPB_UNUSED(val); | |
| return _upb_Hash_NoSeed(key.str->data, key.str->size); | |
| } | |
| static bool streql(upb_key k1, upb_value v1, lookupkey_t k2) { | |
| UPB_UNUSED(v1); | |
| const upb_SizePrefixString* k1s = k1.str; | |
| const upb_StringView k2s = k2.str; | |
| return k1s->size == k2s.size && | |
| (k1s->size == 0 || memcmp(k1s->data, k2s.data, k1s->size) == 0); | |
| } | |
| bool upb_strtable_init(upb_strtable* t, size_t expected_size, upb_Arena* a) { | |
| int size_lg2 = upb_Log2Ceiling(_upb_entries_needed_for(expected_size)); | |
| return init(&t->t, size_lg2, a); | |
| } | |
| void upb_strtable_clear(upb_strtable* t) { | |
| size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent); | |
| t->t.count = 0; | |
| memset((char*)t->t.entries, 0, bytes); | |
| } | |
| bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a) { | |
| if (t->t.entries != NULL && _upb_log2_table_size(&t->t) >= size_lg2) { | |
| return true; | |
| } | |
| upb_strtable new_table; | |
| if (!init(&new_table.t, size_lg2, a)) return false; | |
| if (t->t.count > 0) { | |
| intptr_t iter = UPB_STRTABLE_BEGIN; | |
| upb_StringView sv; | |
| upb_value val; | |
| while (upb_strtable_next2(t, &sv, &val, &iter)) { | |
| // Unlike normal insert, does not copy string data or possibly reallocate | |
| // the table | |
| // The data pointer used in the table is guaranteed to point at a | |
| // upb_SizePrefixString, we just need to back up by the size of the | |
| // uint32_t length prefix. | |
| const upb_SizePrefixString* keystr = | |
| (const upb_SizePrefixString*)(sv.data - sizeof(uint32_t)); | |
| UPB_ASSERT(keystr->data == sv.data); | |
| UPB_ASSERT(keystr->size == sv.size); | |
| lookupkey_t lookupkey = {.str = sv}; | |
| upb_key tabkey = {.str = keystr}; | |
| uint32_t hash = _upb_Hash_NoSeed(sv.data, sv.size); | |
| insert(&new_table.t, lookupkey, tabkey, val, hash, &strhash, &streql); | |
| } | |
| } | |
| *t = new_table; | |
| return true; | |
| } | |
| bool upb_strtable_copy(upb_strtable* dest, const upb_strtable* src, | |
| upb_Arena* a) { | |
| if (src->t.count == 0) { | |
| return upb_strtable_init(dest, 0, a); | |
| } | |
| dest->t.count = src->t.count; | |
| dest->t.mask = src->t.mask; | |
| dest->t.entries = | |
| upb_Arena_Malloc(a, upb_table_size(&src->t) * sizeof(upb_tabent)); | |
| if (!dest->t.entries) return false; | |
| upb_tabent* restrict dest_entries = dest->t.entries; | |
| const upb_tabent* restrict src_entries = src->t.entries; | |
| size_t table_size = upb_table_size(&src->t); | |
| for (size_t i = 0; i < table_size; i++) { | |
| upb_tabent* dest_ent = &dest_entries[i]; | |
| const upb_tabent* src_ent = &src_entries[i]; | |
| if (!upb_tabent_isempty(src_ent)) { | |
| upb_StringView sv = upb_key_strview(src_ent->key); | |
| upb_SizePrefixString* size_prefix_string = | |
| upb_SizePrefixString_Copy(sv, a); | |
| if (!size_prefix_string) return false; | |
| dest_ent->key.str = size_prefix_string; | |
| // The caller is responsible for cloning values if they are not | |
| // primitives. | |
| dest_ent->val = src_ent->val; | |
| if (UPB_UNPREDICTABLE(upb_tabent_hasnext(src_ent))) { | |
| size_t offset = upb_tabent_next(src_ent) - src_entries; | |
| upb_tabent_setnext(dest_ent, dest_entries + offset); | |
| } else { | |
| upb_tabent_clearnext(dest_ent); | |
| } | |
| } else { | |
| *dest_ent = (upb_tabent){}; | |
| } | |
| } | |
| return true; | |
| } | |
| // Inserts `k`, whose hash is `hash`, which must not already be in the table. | |
| UPB_FORCEINLINE bool strtable_insert(upb_strtable* t, const char* k, size_t len, | |
| upb_value v, uint32_t hash, upb_Arena* a) { | |
| if (isfull(&t->t)) { | |
| /* Need to resize. New table of double the size, add old elements to it. */ | |
| if (!upb_strtable_resize(t, _upb_log2_table_size(&t->t) + 1, a)) { | |
| return false; | |
| } | |
| } | |
| upb_StringView sv = upb_StringView_FromDataAndSize(k, len); | |
| upb_SizePrefixString* size_prefix_string = upb_SizePrefixString_Copy(sv, a); | |
| if (!size_prefix_string) return false; | |
| lookupkey_t lookupkey = {.str = sv}; | |
| upb_key key = {.str = size_prefix_string}; | |
| insert(&t->t, lookupkey, key, v, hash, &strhash, &streql); | |
| return true; | |
| } | |
| bool upb_strtable_insert(upb_strtable* t, const char* k, size_t len, | |
| upb_value v, upb_Arena* a) { | |
| return strtable_insert(t, k, len, v, _upb_Hash_NoSeed(k, len), a); | |
| } | |
| bool upb_strtable_insert_or_replace(upb_strtable* t, const char* k, size_t len, | |
| upb_value v, bool* replaced, upb_Arena* a) { | |
| uint32_t hash = _upb_Hash_NoSeed(k, len); | |
| upb_tabent* e = findentry_mutable(&t->t, strkey2(k, len), hash, &streql); | |
| if (e) { | |
| e->val = v; | |
| *replaced = true; | |
| return true; | |
| } | |
| *replaced = false; | |
| if (UPB_UNLIKELY(t->t.entries == NULL) && !init(&t->t, 3, a)) return false; | |
| return strtable_insert(t, k, len, v, hash, a); | |
| } | |
| bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len, | |
| upb_value* v) { | |
| uint32_t hash = _upb_Hash_NoSeed(key, len); | |
| return lookup(&t->t, strkey2(key, len), v, hash, &streql); | |
| } | |
| bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len, | |
| upb_value* val) { | |
| uint32_t hash = _upb_Hash_NoSeed(key, len); | |
| return rm(&t->t, strkey2(key, len), val, hash, &streql); | |
| } | |
| /* Iteration */ | |
| void upb_strtable_begin(upb_strtable_iter* i, const upb_strtable* t) { | |
| i->t = t; | |
| i->index = begin(&t->t); | |
| } | |
| void upb_strtable_next(upb_strtable_iter* i) { | |
| i->index = next(&i->t->t, i->index); | |
| } | |
| bool upb_strtable_done(const upb_strtable_iter* i) { | |
| if (!i->t) return true; | |
| return _upb_table_done(&i->t->t, i->index); | |
| } | |
| upb_StringView upb_strtable_iter_key(const upb_strtable_iter* i) { | |
| UPB_ASSERT(!upb_strtable_done(i)); | |
| return upb_key_strview(str_tabent(i)->key); | |
| } | |
| upb_value upb_strtable_iter_value(const upb_strtable_iter* i) { | |
| UPB_ASSERT(!upb_strtable_done(i)); | |
| return str_tabent(i)->val; | |
| } | |
| void upb_strtable_iter_setdone(upb_strtable_iter* i) { | |
| i->t = NULL; | |
| i->index = SIZE_MAX; | |
| } | |
| bool upb_strtable_iter_isequal(const upb_strtable_iter* i1, | |
| const upb_strtable_iter* i2) { | |
| if (upb_strtable_done(i1) && upb_strtable_done(i2)) return true; | |
| return i1->t == i2->t && i1->index == i2->index; | |
| } | |
| bool upb_strtable_next2(const upb_strtable* t, upb_StringView* key, | |
| upb_value* val, intptr_t* iter) { | |
| upb_tabent* ent; | |
| if (_upb_tablenext(&t->t, &ent, iter)) { | |
| *key = upb_key_strview(ent->key); | |
| *val = ent->val; | |
| return true; | |
| } | |
| return false; | |
| } | |
| void upb_strtable_removeiter(upb_strtable* t, intptr_t* iter) { | |
| removeiter(&t->t, iter); | |
| } | |
| void upb_strtable_setentryvalue(upb_strtable* t, intptr_t iter, upb_value v) { | |
| t->t.entries[iter].val = v; | |
| } | |
| /* upb_exttable ***************************************************************/ | |
| static uint32_t _upb_exttable_hash(const void* ptr, uint32_t ext_num) { | |
| uint64_t a = (uintptr_t)ptr; | |
| uint64_t b = ext_num; | |
| return (uint32_t)WyhashMix(a ^ kWyhashSalt[1], b ^ _upb_Seed()); | |
| } | |
| static uint32_t exthash(upb_key key, upb_value val) { | |
| const void* ptr = (const void*)key.num; | |
| uint32_t ext_num = *(const uint32_t*)upb_value_getconstptr(val); | |
| return _upb_exttable_hash(ptr, ext_num); | |
| } | |
| static bool exteql(upb_key k1, upb_value v1, lookupkey_t k2) { | |
| if ((const void*)k1.num == k2.ext.ptr) { | |
| uint32_t ext_num1 = *(const uint32_t*)upb_value_getconstptr(v1); | |
| return ext_num1 == k2.ext.ext_num; | |
| } | |
| return false; | |
| } | |
| bool upb_exttable_init(upb_exttable* t, size_t expected_size, upb_Arena* a) { | |
| int size_lg2 = upb_Log2Ceiling(_upb_entries_needed_for(expected_size)); | |
| return init(&t->t, size_lg2, a); | |
| } | |
| void upb_exttable_clear(upb_exttable* t) { | |
| size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent); | |
| t->t.count = 0; | |
| memset((char*)t->t.entries, 0, bytes); | |
| } | |
| bool upb_exttable_resize(upb_exttable* t, size_t size_lg2, upb_Arena* a) { | |
| upb_exttable new_table; | |
| if (!init(&new_table.t, size_lg2, a)) return false; | |
| size_t i; | |
| for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) { | |
| const upb_tabent* e = &t->t.entries[i]; | |
| uint32_t hash = exthash(e->key, e->val); | |
| uint32_t ext_num = *(const uint32_t*)upb_value_getconstptr(e->val); | |
| lookupkey_t lookupkey = extkey((const void*)e->key.num, ext_num); | |
| insert(&new_table.t, lookupkey, e->key, e->val, hash, &exthash, &exteql); | |
| } | |
| *t = new_table; | |
| return true; | |
| } | |
| bool upb_exttable_insert(upb_exttable* t, const void* k, const uint32_t* v, | |
| upb_Arena* a) { | |
| UPB_ASSERT(k != NULL); | |
| UPB_ASSERT(v != NULL); | |
| UPB_ASSERT(*v != 0); | |
| if (isfull(&t->t)) { | |
| if (!upb_exttable_resize(t, _upb_log2_table_size(&t->t) + 1, a)) { | |
| return false; | |
| } | |
| } | |
| lookupkey_t lookupkey = extkey(k, *v); | |
| upb_key key = {.num = (uintptr_t)k}; | |
| upb_value val = upb_value_constptr(v); | |
| uint32_t hash = _upb_exttable_hash(k, *v); | |
| insert(&t->t, lookupkey, key, val, hash, &exthash, &exteql); | |
| return true; | |
| } | |
| const uint32_t* upb_exttable_lookup(const upb_exttable* t, const void* k, | |
| uint32_t ext_number) { | |
| uint32_t hash = _upb_exttable_hash(k, ext_number); | |
| upb_value val; | |
| if (lookup(&t->t, extkey(k, ext_number), &val, hash, &exteql)) { | |
| return (const uint32_t*)upb_value_getconstptr(val); | |
| } | |
| return NULL; | |
| } | |
| const uint32_t* upb_exttable_remove(upb_exttable* t, const void* k, | |
| uint32_t ext_number) { | |
| uint32_t hash = _upb_exttable_hash(k, ext_number); | |
| upb_value val; | |
| if (rm(&t->t, extkey(k, ext_number), &val, hash, &exteql)) { | |
| return (const uint32_t*)upb_value_getconstptr(val); | |
| } | |
| return NULL; | |
| } | |
| size_t upb_exttable_size(const upb_exttable* t) { return t->t.count; } | |
| /* upb_inttable ***************************************************************/ | |
| static uint32_t inthash(upb_key key, upb_value val) { | |
| UPB_UNUSED(val); | |
| return upb_inthash(key.num); | |
| } | |
| static bool inteql(upb_key k1, upb_value v1, lookupkey_t k2) { | |
| UPB_UNUSED(v1); | |
| return k1.num == k2.num; | |
| } | |
| static void check(upb_inttable* t) { | |
| UPB_UNUSED(t); | |
| #if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG) | |
| { | |
| // This check is very expensive (makes inserts/deletes O(N)). | |
| size_t count = 0; | |
| intptr_t iter = UPB_INTTABLE_BEGIN; | |
| uintptr_t key; | |
| upb_value val; | |
| while (upb_inttable_next(t, &key, &val, &iter)) { | |
| UPB_ASSERT(upb_inttable_lookup(t, key, NULL)); | |
| count++; | |
| } | |
| UPB_ASSERT(count == upb_inttable_count(t)); | |
| } | |
| #endif | |
| } | |
| static bool upb_inttable_sizedinit(upb_inttable* t, int hsize_lg2, | |
| upb_Arena* a) { | |
| if (!init(&t->t, hsize_lg2, a)) return false; | |
| check(t); | |
| return true; | |
| } | |
| bool upb_inttable_init(upb_inttable* t, upb_Arena* a) { | |
| return upb_inttable_sizedinit(t, 3, a); | |
| } | |
| bool upb_inttable_copy(upb_inttable* dest, const upb_inttable* src, | |
| upb_Arena* a) { | |
| if (src->t.count == 0) { | |
| return upb_inttable_sizedinit(dest, 0, a); | |
| } | |
| if (!upb_inttable_sizedinit( | |
| dest, src->t.mask ? _upb_log2_table_size(&src->t) : 0, a)) { | |
| return false; | |
| } | |
| dest->t.count = src->t.count; | |
| upb_tabent* restrict dest_entries = dest->t.entries; | |
| const upb_tabent* restrict src_entries = src->t.entries; | |
| size_t table_size = upb_table_size(&src->t); | |
| for (size_t i = 0; i < table_size; i++) { | |
| upb_tabent* dest_ent = &dest_entries[i]; | |
| const upb_tabent* src_ent = &src_entries[i]; | |
| if (!upb_tabent_isempty(src_ent)) { | |
| // The caller is responsible for cloning these if they are not primitives. | |
| dest_ent->key = src_ent->key; | |
| dest_ent->val = src_ent->val; | |
| if (UPB_UNPREDICTABLE(upb_tabent_hasnext(src_ent))) { | |
| size_t offset = upb_tabent_next(src_ent) - src_entries; | |
| upb_tabent_setnext(dest_ent, dest_entries + offset); | |
| } else { | |
| upb_tabent_clearnext(dest_ent); | |
| } | |
| } else { | |
| *dest_ent = (upb_tabent){}; | |
| } | |
| } | |
| return true; | |
| } | |
| // Attempts to grow the inttable in-place. If a table has primitive keys and | |
| // values, insertions generally don't allocate anything in between the table's | |
| // allocations; in that case, growing the table in place uses half the total | |
| // memory compared to allocating new chunks and copying over. | |
| static bool upb_inttable_trygrow(upb_inttable* t, size_t size_lg2, | |
| upb_Arena* a) { | |
| if (size_lg2 >= 32) { | |
| return false; | |
| } | |
| size_t old_size = upb_table_size(&t->t); | |
| size_t old_bytes = old_size * sizeof(upb_tabent); | |
| size_t new_size = (size_t)1 << size_lg2; | |
| size_t new_bytes = new_size * sizeof(upb_tabent); | |
| if (new_bytes <= old_bytes || !t->t.entries) { | |
| return false; | |
| } | |
| if (!upb_Arena_TryExtend(a, t->t.entries, old_bytes, new_bytes)) { | |
| return false; | |
| } | |
| // Zero out the newly extended region of the table buffer. | |
| memset(t->t.entries + old_size, 0, | |
| (new_size - old_size) * sizeof(upb_tabent)); | |
| // This one-past-the-end pointer is guaranteed to be distinct from NULL and | |
| // any valid internal collision chain pointer in the entire table. | |
| upb_tabent* unhashed_marker = t->t.entries + new_size; | |
| // Mark all existing occupied entries as UNHASHED using the distinct | |
| // marker. Because e->next != NULL, these pending slots are fully protected | |
| // from being claimed by emptyent() during collision chain formation. | |
| for (size_t i = 0; i < old_size; i++) { | |
| upb_tabent* e = &t->t.entries[i]; | |
| if (!upb_tabent_isempty(e)) { | |
| upb_tabent_setnext(e, unhashed_marker); | |
| } | |
| } | |
| const uint32_t mask = new_size - 1; | |
| t->t.mask = mask; | |
| t->t.count = 0; // Reset count as insert will increment it back up | |
| // Trace and resolve all destinations. | |
| for (size_t i = 0; i < old_size; i++) { | |
| upb_tabent* current = &t->t.entries[i]; | |
| if (!upb_tabent_hasnext(current) || | |
| upb_tabent_next(current) != unhashed_marker) { | |
| continue; // Slot is already hashed or empty. | |
| } | |
| // Pop the leading unhashed entry to begin our trace cycle. | |
| upb_key tabkey = current->key; | |
| upb_value val = current->val; | |
| upb_tabent_clear(current); | |
| // This inner loop clears at least one unhashed slot per iteration, for | |
| // total O(n) time across the whole rehash. | |
| while (true) { | |
| uint32_t hash = inthash(tabkey, val); | |
| upb_tabent* target_bucket = &t->t.entries[hash & mask]; | |
| if (upb_tabent_hasnext(target_bucket) && | |
| upb_tabent_next(target_bucket) == unhashed_marker) { | |
| // Primary bucket contains a pending unhashed entry. Extract it, clear | |
| // the bucket, place our entry, and trace the evicted one. | |
| upb_key next_tabkey = target_bucket->key; | |
| upb_value next_val = target_bucket->val; | |
| upb_tabent_clear(target_bucket); | |
| insert(&t->t, intkey(tabkey.num), tabkey, val, hash, &inthash, &inteql); | |
| tabkey = next_tabkey; | |
| val = next_val; | |
| } else { | |
| // Primary bucket is either empty or holds an already-hashed chain. | |
| // The standard insert() function perfectly resolves both cases. | |
| insert(&t->t, intkey(tabkey.num), tabkey, val, hash, &inthash, &inteql); | |
| break; | |
| } | |
| } | |
| } | |
| return true; | |
| } | |
| bool upb_inttable_resize(upb_inttable* t, size_t size_lg2, upb_Arena* a) { | |
| if (t->t.entries != NULL && _upb_log2_table_size(&t->t) >= size_lg2) { | |
| return true; | |
| } | |
| if (t->t.entries != NULL && upb_inttable_trygrow(t, size_lg2, a)) { | |
| return true; | |
| } | |
| upb_table new_table; | |
| if (!init(&new_table, size_lg2, a)) return false; | |
| if (t->t.count > 0) { | |
| for (size_t i = begin(&t->t); i < upb_table_size(&t->t); | |
| i = next(&t->t, i)) { | |
| const upb_tabent* e = &t->t.entries[i]; | |
| insert(&new_table, intkey(e->key.num), e->key, e->val, | |
| inthash(e->key, e->val), &inthash, &inteql); | |
| } | |
| } | |
| UPB_ASSERT(t->t.count == new_table.count); | |
| t->t = new_table; | |
| return true; | |
| } | |
| UPB_NOINLINE static bool upb_inttable_grow(upb_inttable* t, upb_Arena* a) { | |
| size_t new_size = _upb_log2_table_size(&t->t) + 1; | |
| return upb_inttable_resize(t, new_size, a); | |
| } | |
| bool upb_inttable_insert(upb_inttable* t, uintptr_t key, upb_value val, | |
| upb_Arena* a) { | |
| if (UPB_UNLIKELY(isfull(&t->t))) { | |
| if (!upb_inttable_grow(t, a)) return false; | |
| } | |
| upb_key tabkey = {.num = key}; | |
| insert(&t->t, intkey(key), tabkey, val, upb_inthash(key), &inthash, &inteql); | |
| check(t); | |
| return true; | |
| } | |
| bool upb_inttable_insert_or_replace_slow(upb_inttable* t, uintptr_t key, | |
| upb_value val, bool* replaced, | |
| upb_Arena* a) { | |
| upb_tabent* e = | |
| findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql); | |
| if (e) { | |
| e->val = val; | |
| *replaced = true; | |
| return true; | |
| } | |
| *replaced = false; | |
| if (UPB_UNLIKELY(t->t.entries == NULL) && !upb_inttable_init(t, a)) { | |
| return false; | |
| } | |
| return upb_inttable_insert(t, key, val, a); | |
| } | |
| bool upb_inttable_lookup(const upb_inttable* t, uintptr_t key, upb_value* v) { | |
| return lookup(&t->t, intkey(key), v, upb_inthash(key), &inteql); | |
| } | |
| bool upb_inttable_replace(upb_inttable* t, uintptr_t key, upb_value val) { | |
| upb_tabent* e = | |
| findentry_mutable(&t->t, intkey(key), upb_inthash(key), &inteql); | |
| if (!e) return false; | |
| e->val = val; | |
| return true; | |
| } | |
| bool upb_inttable_remove(upb_inttable* t, uintptr_t key, upb_value* val) { | |
| bool success = rm(&t->t, intkey(key), val, upb_inthash(key), &inteql); | |
| check(t); | |
| return success; | |
| } | |
| void upb_inttable_clear(upb_inttable* t) { | |
| size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent); | |
| t->t.count = 0; | |
| memset((char*)t->t.entries, 0, bytes); | |
| } | |
| bool upb_inttable_next(const upb_inttable* t, uintptr_t* key, upb_value* val, | |
| intptr_t* iter) { | |
| upb_tabent* ent; | |
| if (_upb_tablenext(&t->t, &ent, iter)) { | |
| *key = ent->key.num; | |
| *val = ent->val; | |
| return true; | |
| } | |
| *iter = INTPTR_MAX - 1; | |
| return false; | |
| } | |
| void upb_inttable_removeiter(upb_inttable* t, intptr_t* iter) { | |
| removeiter(&t->t, iter); | |
| } | |
| void upb_inttable_setentryvalue(upb_inttable* t, intptr_t iter, upb_value v) { | |
| t->t.entries[iter].val = v; | |
| } | |
| bool upb_inttable_done(const upb_inttable* t, intptr_t iter) { | |
| return _upb_table_done(&t->t, iter); | |
| } | |
| uintptr_t upb_inttable_iter_key(const upb_inttable* t, intptr_t iter) { | |
| UPB_ASSERT(!upb_inttable_done(t, iter)); | |
| return t->t.entries[iter].key.num; | |
| } | |
| upb_value upb_inttable_iter_value(const upb_inttable* t, intptr_t iter) { | |
| UPB_ASSERT(!upb_inttable_done(t, iter)); | |
| return t->t.entries[iter].val; | |
| } | |
| #include <errno.h> | |
| #include <float.h> | |
| #include <inttypes.h> | |
| #include <limits.h> | |
| #include <math.h> | |
| #include <setjmp.h> | |
| #include <stdarg.h> | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #include "utf8_range.h" | |
| // Must be last. | |
| typedef struct { | |
| const char *ptr, *end; | |
| upb_Arena* arena; /* TODO: should we have a tmp arena for tmp data? */ | |
| const upb_DefPool* symtab; | |
| int depth; | |
| int result; | |
| upb_Status* status; | |
| jmp_buf err; | |
| int line; | |
| const char* line_begin; | |
| bool is_first; | |
| int options; | |
| const upb_FieldDef* debug_field; | |
| } jsondec; | |
| typedef struct { | |
| upb_MessageValue value; | |
| bool ignore; | |
| } upb_JsonMessageValue; | |
| enum { JD_OBJECT, JD_ARRAY, JD_STRING, JD_NUMBER, JD_TRUE, JD_FALSE, JD_NULL }; | |
| /* Forward declarations of mutually-recursive functions. */ | |
| static void jsondec_wellknown(jsondec* d, upb_Message* msg, | |
| const upb_MessageDef* m); | |
| static upb_JsonMessageValue jsondec_value(jsondec* d, const upb_FieldDef* f); | |
| static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, | |
| const upb_MessageDef* m); | |
| static void jsondec_object(jsondec* d, upb_Message* msg, | |
| const upb_MessageDef* m); | |
| static bool jsondec_streql(upb_StringView str, const char* lit) { | |
| return str.size == strlen(lit) && memcmp(str.data, lit, str.size) == 0; | |
| } | |
| static bool jsondec_isnullvalue(const upb_FieldDef* f) { | |
| return upb_FieldDef_CType(f) == kUpb_CType_Enum && | |
| strcmp(upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(f)), | |
| "google.protobuf.NullValue") == 0; | |
| } | |
| static bool jsondec_isvalue(const upb_FieldDef* f) { | |
| return (upb_FieldDef_CType(f) == kUpb_CType_Message && | |
| upb_MessageDef_WellKnownType(upb_FieldDef_MessageSubDef(f)) == | |
| kUpb_WellKnown_Value) || | |
| jsondec_isnullvalue(f); | |
| } | |
| static void jsondec_seterrmsg(jsondec* d, const char* msg) { | |
| upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: %s", d->line, | |
| (int)(d->ptr - d->line_begin), msg); | |
| } | |
| UPB_NORETURN static void jsondec_err(jsondec* d, const char* msg) { | |
| jsondec_seterrmsg(d, msg); | |
| UPB_LONGJMP(d->err, 1); | |
| } | |
| static void jsondec_checkoom(jsondec* d, bool ok) { | |
| if (UPB_UNLIKELY(!ok)) { | |
| jsondec_err(d, "Out of memory"); | |
| } | |
| } | |
| UPB_PRINTF(2, 3) | |
| UPB_NORETURN static void jsondec_errf(jsondec* d, const char* fmt, ...) { | |
| va_list argp; | |
| upb_Status_SetErrorFormat(d->status, "Error parsing JSON @%d:%d: ", d->line, | |
| (int)(d->ptr - d->line_begin)); | |
| va_start(argp, fmt); | |
| upb_Status_VAppendErrorFormat(d->status, fmt, argp); | |
| va_end(argp); | |
| UPB_LONGJMP(d->err, 1); | |
| } | |
| // Advances d->ptr until the next non-whitespace character or to the end of | |
| // the buffer. | |
| static void jsondec_consumews(jsondec* d) { | |
| while (d->ptr != d->end) { | |
| switch (*d->ptr) { | |
| case '\n': | |
| d->line++; | |
| d->line_begin = d->ptr; | |
| /* Fallthrough. */ | |
| case '\r': | |
| case '\t': | |
| case ' ': | |
| d->ptr++; | |
| break; | |
| default: | |
| return; | |
| } | |
| } | |
| } | |
| // Advances d->ptr until the next non-whitespace character. Postcondition that | |
| // d->ptr is pointing at a valid non-whitespace character (will err if end of | |
| // buffer is reached). | |
| static void jsondec_skipws(jsondec* d) { | |
| jsondec_consumews(d); | |
| if (d->ptr == d->end) { | |
| jsondec_err(d, "Unexpected EOF"); | |
| } | |
| } | |
| static bool jsondec_tryparsech(jsondec* d, char ch) { | |
| if (d->ptr == d->end || *d->ptr != ch) return false; | |
| d->ptr++; | |
| return true; | |
| } | |
| static void jsondec_parselit(jsondec* d, const char* lit) { | |
| size_t avail = d->end - d->ptr; | |
| size_t len = strlen(lit); | |
| if (avail < len || memcmp(d->ptr, lit, len) != 0) { | |
| jsondec_errf(d, "Expected: '%s'", lit); | |
| } | |
| d->ptr += len; | |
| } | |
| static void jsondec_wsch(jsondec* d, char ch) { | |
| jsondec_skipws(d); | |
| if (!jsondec_tryparsech(d, ch)) { | |
| jsondec_errf(d, "Expected: '%c'", ch); | |
| } | |
| } | |
| static void jsondec_true(jsondec* d) { jsondec_parselit(d, "true"); } | |
| static void jsondec_false(jsondec* d) { jsondec_parselit(d, "false"); } | |
| static void jsondec_null(jsondec* d) { jsondec_parselit(d, "null"); } | |
| static void jsondec_entrysep(jsondec* d) { | |
| jsondec_skipws(d); | |
| jsondec_parselit(d, ":"); | |
| } | |
| static int jsondec_rawpeek(jsondec* d) { | |
| if (d->ptr == d->end) { | |
| jsondec_err(d, "Unexpected EOF"); | |
| } | |
| switch (*d->ptr) { | |
| case '{': | |
| return JD_OBJECT; | |
| case '[': | |
| return JD_ARRAY; | |
| case '"': | |
| return JD_STRING; | |
| case '-': | |
| case '0': | |
| case '1': | |
| case '2': | |
| case '3': | |
| case '4': | |
| case '5': | |
| case '6': | |
| case '7': | |
| case '8': | |
| case '9': | |
| return JD_NUMBER; | |
| case 't': | |
| return JD_TRUE; | |
| case 'f': | |
| return JD_FALSE; | |
| case 'n': | |
| return JD_NULL; | |
| default: | |
| jsondec_errf(d, "Unexpected character: '%c'", *d->ptr); | |
| } | |
| } | |
| /* JSON object/array **********************************************************/ | |
| /* These are used like so: | |
| * | |
| * jsondec_objstart(d); | |
| * while (jsondec_objnext(d)) { | |
| * ... | |
| * } | |
| * jsondec_objend(d) */ | |
| static int jsondec_peek(jsondec* d) { | |
| jsondec_skipws(d); | |
| return jsondec_rawpeek(d); | |
| } | |
| static void jsondec_push(jsondec* d) { | |
| if (--d->depth < 0) { | |
| jsondec_err(d, "Recursion limit exceeded"); | |
| } | |
| d->is_first = true; | |
| } | |
| static bool jsondec_seqnext(jsondec* d, char end_ch) { | |
| bool is_first = d->is_first; | |
| d->is_first = false; | |
| jsondec_skipws(d); | |
| if (*d->ptr == end_ch) return false; | |
| if (!is_first) jsondec_parselit(d, ","); | |
| return true; | |
| } | |
| static void jsondec_arrstart(jsondec* d) { | |
| jsondec_push(d); | |
| jsondec_wsch(d, '['); | |
| } | |
| static void jsondec_arrend(jsondec* d) { | |
| d->depth++; | |
| jsondec_wsch(d, ']'); | |
| } | |
| static bool jsondec_arrnext(jsondec* d) { return jsondec_seqnext(d, ']'); } | |
| static void jsondec_objstart(jsondec* d) { | |
| jsondec_push(d); | |
| jsondec_wsch(d, '{'); | |
| } | |
| static void jsondec_objend(jsondec* d) { | |
| d->depth++; | |
| jsondec_wsch(d, '}'); | |
| } | |
| static bool jsondec_objnext(jsondec* d) { | |
| if (!jsondec_seqnext(d, '}')) return false; | |
| if (jsondec_peek(d) != JD_STRING) { | |
| jsondec_err(d, "Object must start with string"); | |
| } | |
| return true; | |
| } | |
| /* JSON number ****************************************************************/ | |
| static bool jsondec_tryskipdigits(jsondec* d) { | |
| const char* start = d->ptr; | |
| while (d->ptr < d->end) { | |
| if (*d->ptr < '0' || *d->ptr > '9') { | |
| break; | |
| } | |
| d->ptr++; | |
| } | |
| return d->ptr != start; | |
| } | |
| static void jsondec_skipdigits(jsondec* d) { | |
| if (!jsondec_tryskipdigits(d)) { | |
| jsondec_err(d, "Expected one or more digits"); | |
| } | |
| } | |
| static double jsondec_number(jsondec* d) { | |
| const char* start = d->ptr; | |
| UPB_ASSERT(jsondec_rawpeek(d) == JD_NUMBER); | |
| /* Skip over the syntax of a number, as specified by JSON. */ | |
| if (*d->ptr == '-') d->ptr++; | |
| if (jsondec_tryparsech(d, '0')) { | |
| if (jsondec_tryskipdigits(d)) { | |
| jsondec_err(d, "number cannot have leading zero"); | |
| } | |
| } else { | |
| jsondec_skipdigits(d); | |
| } | |
| if (d->ptr == d->end) goto parse; | |
| if (jsondec_tryparsech(d, '.')) { | |
| jsondec_skipdigits(d); | |
| } | |
| if (d->ptr == d->end) goto parse; | |
| if (*d->ptr == 'e' || *d->ptr == 'E') { | |
| d->ptr++; | |
| if (d->ptr == d->end) { | |
| jsondec_err(d, "Unexpected EOF in number"); | |
| } | |
| if (*d->ptr == '+' || *d->ptr == '-') { | |
| d->ptr++; | |
| } | |
| jsondec_skipdigits(d); | |
| } | |
| parse: | |
| /* Having verified the syntax of a JSON number, use strtod() to parse | |
| * (strtod() accepts a superset of JSON syntax). */ | |
| errno = 0; | |
| { | |
| // Copy the number into a null-terminated scratch buffer since strtod | |
| // expects a null-terminated string. | |
| char nullz[64]; | |
| ptrdiff_t len = d->ptr - start; | |
| if (len > (ptrdiff_t)(sizeof(nullz) - 1)) { | |
| jsondec_err(d, "excessively long number"); | |
| } | |
| memcpy(nullz, start, len); | |
| nullz[len] = '\0'; | |
| char* end; | |
| double val = strtod(nullz, &end); | |
| UPB_ASSERT(end - nullz == len); | |
| /* Currently the min/max-val conformance tests fail if we check this. Does | |
| * this mean the conformance tests are wrong or strtod() is wrong, or | |
| * something else? Investigate further. */ | |
| /* | |
| if (errno == ERANGE) { | |
| jsondec_err(d, "Number out of range"); | |
| } | |
| */ | |
| if (val > DBL_MAX || val < -DBL_MAX) { | |
| jsondec_err(d, "Number out of range"); | |
| } | |
| return val; | |
| } | |
| } | |
| /* JSON string ****************************************************************/ | |
| static char jsondec_escape(jsondec* d) { | |
| switch (*d->ptr++) { | |
| case '"': | |
| return '\"'; | |
| case '\\': | |
| return '\\'; | |
| case '/': | |
| return '/'; | |
| case 'b': | |
| return '\b'; | |
| case 'f': | |
| return '\f'; | |
| case 'n': | |
| return '\n'; | |
| case 'r': | |
| return '\r'; | |
| case 't': | |
| return '\t'; | |
| default: | |
| jsondec_err(d, "Invalid escape char"); | |
| } | |
| } | |
| static uint32_t jsondec_codepoint(jsondec* d) { | |
| uint32_t cp = 0; | |
| const char* end; | |
| if (d->end - d->ptr < 4) { | |
| jsondec_err(d, "EOF inside string"); | |
| } | |
| end = d->ptr + 4; | |
| while (d->ptr < end) { | |
| char ch = *d->ptr++; | |
| if (ch >= '0' && ch <= '9') { | |
| ch -= '0'; | |
| } else if (ch >= 'a' && ch <= 'f') { | |
| ch = ch - 'a' + 10; | |
| } else if (ch >= 'A' && ch <= 'F') { | |
| ch = ch - 'A' + 10; | |
| } else { | |
| jsondec_err(d, "Invalid hex digit"); | |
| } | |
| cp = (cp << 4) | ch; | |
| } | |
| return cp; | |
| } | |
| /* Parses a \uXXXX unicode escape (possibly a surrogate pair). */ | |
| static size_t jsondec_unicode(jsondec* d, char* out) { | |
| uint32_t cp = jsondec_codepoint(d); | |
| if (upb_Unicode_IsHigh(cp)) { | |
| /* Surrogate pair: two 16-bit codepoints become a 32-bit codepoint. */ | |
| jsondec_parselit(d, "\\u"); | |
| uint32_t low = jsondec_codepoint(d); | |
| if (!upb_Unicode_IsLow(low)) jsondec_err(d, "Invalid low surrogate"); | |
| cp = upb_Unicode_FromPair(cp, low); | |
| } else if (upb_Unicode_IsLow(cp)) { | |
| jsondec_err(d, "Unpaired low surrogate"); | |
| } | |
| /* Write to UTF-8 */ | |
| int bytes = upb_Unicode_ToUTF8(cp, out); | |
| if (bytes == 0) jsondec_err(d, "Invalid codepoint"); | |
| return bytes; | |
| } | |
| static void jsondec_resize(jsondec* d, char** buf, char** end, char** buf_end) { | |
| size_t oldsize = *buf_end - *buf; | |
| size_t len = *end - *buf; | |
| size_t size; | |
| jsondec_checkoom(d, !upb_MulOverflow(oldsize, (size_t)2, &size)); | |
| size = UPB_MAX(8, size); | |
| *buf = upb_Arena_Realloc(d->arena, *buf, len, size); | |
| jsondec_checkoom(d, *buf); | |
| *end = *buf + len; | |
| *buf_end = *buf + size; | |
| } | |
| static upb_StringView jsondec_string(jsondec* d) { | |
| char* buf = NULL; | |
| char* end = NULL; | |
| char* buf_end = NULL; | |
| jsondec_skipws(d); | |
| if (*d->ptr++ != '"') { | |
| jsondec_err(d, "Expected string"); | |
| } | |
| while (d->ptr < d->end) { | |
| char ch = *d->ptr++; | |
| if (end == buf_end) { | |
| jsondec_resize(d, &buf, &end, &buf_end); | |
| } | |
| switch (ch) { | |
| case '"': { | |
| upb_StringView ret; | |
| ret.data = buf; | |
| ret.size = end - buf; | |
| *end = '\0'; /* Needed for possible strtod(). */ | |
| return ret; | |
| } | |
| case '\\': | |
| if (d->ptr == d->end) goto eof; | |
| if (*d->ptr == 'u') { | |
| d->ptr++; | |
| if (buf_end - end < 4) { | |
| /* Allow space for maximum-sized codepoint (4 bytes). */ | |
| jsondec_resize(d, &buf, &end, &buf_end); | |
| } | |
| end += jsondec_unicode(d, end); | |
| } else { | |
| *end++ = jsondec_escape(d); | |
| } | |
| break; | |
| default: | |
| if ((unsigned char)ch < 0x20) { | |
| jsondec_err(d, "Invalid char in JSON string"); | |
| } | |
| *end++ = ch; | |
| break; | |
| } | |
| } | |
| eof: | |
| jsondec_err(d, "EOF inside string"); | |
| } | |
| static void jsondec_skipval(jsondec* d) { | |
| switch (jsondec_peek(d)) { | |
| case JD_OBJECT: | |
| jsondec_objstart(d); | |
| while (jsondec_objnext(d)) { | |
| jsondec_string(d); | |
| jsondec_entrysep(d); | |
| jsondec_skipval(d); | |
| } | |
| jsondec_objend(d); | |
| break; | |
| case JD_ARRAY: | |
| jsondec_arrstart(d); | |
| while (jsondec_arrnext(d)) { | |
| jsondec_skipval(d); | |
| } | |
| jsondec_arrend(d); | |
| break; | |
| case JD_TRUE: | |
| jsondec_true(d); | |
| break; | |
| case JD_FALSE: | |
| jsondec_false(d); | |
| break; | |
| case JD_NULL: | |
| jsondec_null(d); | |
| break; | |
| case JD_STRING: | |
| jsondec_string(d); | |
| break; | |
| case JD_NUMBER: | |
| jsondec_number(d); | |
| break; | |
| } | |
| } | |
| /* Base64 decoding for bytes fields. ******************************************/ | |
| static unsigned int jsondec_base64_tablelookup(const char ch) { | |
| /* Table includes the normal base64 chars plus the URL-safe variant. */ | |
| const signed char table[256] = { | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, 62 /*+*/, -1, 62 /*-*/, -1, 63 /*/ */, 52 /*0*/, | |
| 53 /*1*/, 54 /*2*/, 55 /*3*/, 56 /*4*/, 57 /*5*/, 58 /*6*/, 59 /*7*/, | |
| 60 /*8*/, 61 /*9*/, -1, -1, -1, -1, -1, | |
| -1, -1, 0 /*A*/, 1 /*B*/, 2 /*C*/, 3 /*D*/, 4 /*E*/, | |
| 5 /*F*/, 6 /*G*/, 07 /*H*/, 8 /*I*/, 9 /*J*/, 10 /*K*/, 11 /*L*/, | |
| 12 /*M*/, 13 /*N*/, 14 /*O*/, 15 /*P*/, 16 /*Q*/, 17 /*R*/, 18 /*S*/, | |
| 19 /*T*/, 20 /*U*/, 21 /*V*/, 22 /*W*/, 23 /*X*/, 24 /*Y*/, 25 /*Z*/, | |
| -1, -1, -1, -1, 63 /*_*/, -1, 26 /*a*/, | |
| 27 /*b*/, 28 /*c*/, 29 /*d*/, 30 /*e*/, 31 /*f*/, 32 /*g*/, 33 /*h*/, | |
| 34 /*i*/, 35 /*j*/, 36 /*k*/, 37 /*l*/, 38 /*m*/, 39 /*n*/, 40 /*o*/, | |
| 41 /*p*/, 42 /*q*/, 43 /*r*/, 44 /*s*/, 45 /*t*/, 46 /*u*/, 47 /*v*/, | |
| 48 /*w*/, 49 /*x*/, 50 /*y*/, 51 /*z*/, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1, -1, -1, -1, | |
| -1, -1, -1, -1}; | |
| /* Sign-extend return value so high bit will be set on any unexpected char. */ | |
| return table[(unsigned char)ch]; | |
| } | |
| static char* jsondec_partialbase64(jsondec* d, const char* ptr, const char* end, | |
| char* out) { | |
| int32_t val = -1; | |
| switch (end - ptr) { | |
| case 2: | |
| val = jsondec_base64_tablelookup(ptr[0]) << 18 | | |
| jsondec_base64_tablelookup(ptr[1]) << 12; | |
| out[0] = val >> 16; | |
| out += 1; | |
| break; | |
| case 3: | |
| val = jsondec_base64_tablelookup(ptr[0]) << 18 | | |
| jsondec_base64_tablelookup(ptr[1]) << 12 | | |
| jsondec_base64_tablelookup(ptr[2]) << 6; | |
| out[0] = val >> 16; | |
| out[1] = (val >> 8) & 0xff; | |
| out += 2; | |
| break; | |
| } | |
| if (val < 0) { | |
| jsondec_err(d, "Corrupt base64"); | |
| } | |
| return out; | |
| } | |
| static size_t jsondec_base64(jsondec* d, upb_StringView str) { | |
| /* We decode in place. This is safe because this is a new buffer (not | |
| * aliasing the input) and because base64 decoding shrinks 4 bytes into 3. */ | |
| char* out = (char*)str.data; | |
| const char* ptr = str.data; | |
| const char* end = ptr + str.size; | |
| const char* end4 = ptr + (str.size & -4); /* Round down to multiple of 4. */ | |
| for (; ptr < end4; ptr += 4, out += 3) { | |
| int val = jsondec_base64_tablelookup(ptr[0]) << 18 | | |
| jsondec_base64_tablelookup(ptr[1]) << 12 | | |
| jsondec_base64_tablelookup(ptr[2]) << 6 | | |
| jsondec_base64_tablelookup(ptr[3]) << 0; | |
| if (val < 0) { | |
| /* Junk chars or padding. Remove trailing padding, if any. */ | |
| if (end - ptr == 4 && ptr[3] == '=') { | |
| if (ptr[2] == '=') { | |
| end -= 2; | |
| } else { | |
| end -= 1; | |
| } | |
| } | |
| break; | |
| } | |
| out[0] = val >> 16; | |
| out[1] = (val >> 8) & 0xff; | |
| out[2] = val & 0xff; | |
| } | |
| if (ptr < end) { | |
| /* Process remaining chars. We do not require padding. */ | |
| out = jsondec_partialbase64(d, ptr, end, out); | |
| } | |
| return out - str.data; | |
| } | |
| /* Low-level integer parsing **************************************************/ | |
| static const char* jsondec_buftouint64(jsondec* d, const char* ptr, | |
| const char* end, uint64_t* val) { | |
| const char* out = upb_BufToUint64(ptr, end, val); | |
| if (!out) jsondec_err(d, "Integer overflow"); | |
| return out; | |
| } | |
| static const char* jsondec_buftoint64(jsondec* d, const char* ptr, | |
| const char* end, int64_t* val, | |
| bool* is_neg) { | |
| const char* out = upb_BufToInt64(ptr, end, val, is_neg); | |
| if (!out) jsondec_err(d, "Integer overflow"); | |
| return out; | |
| } | |
| static uint64_t jsondec_strtouint64(jsondec* d, upb_StringView str) { | |
| const char* end = str.data + str.size; | |
| uint64_t ret; | |
| if (jsondec_buftouint64(d, str.data, end, &ret) != end) { | |
| jsondec_err(d, "Non-number characters in quoted integer"); | |
| } | |
| return ret; | |
| } | |
| static int64_t jsondec_strtoint64(jsondec* d, upb_StringView str) { | |
| const char* end = str.data + str.size; | |
| int64_t ret; | |
| if (jsondec_buftoint64(d, str.data, end, &ret, NULL) != end) { | |
| jsondec_err(d, "Non-number characters in quoted integer"); | |
| } | |
| return ret; | |
| } | |
| static void jsondec_checkempty(jsondec* d, upb_StringView str, | |
| const upb_FieldDef* f) { | |
| if (str.size != 0) return; | |
| d->result = kUpb_JsonDecodeResult_Error; | |
| upb_Status_SetErrorFormat(d->status, | |
| "Empty string is not a valid number (field: %s). " | |
| "This will be an error in a future version.", | |
| upb_FieldDef_FullName(f)); | |
| } | |
| /* Primitive value types ******************************************************/ | |
| /* Parse INT32 or INT64 value. */ | |
| static upb_MessageValue jsondec_int(jsondec* d, const upb_FieldDef* f) { | |
| upb_MessageValue val; | |
| switch (jsondec_peek(d)) { | |
| case JD_NUMBER: { | |
| double dbl = jsondec_number(d); | |
| if (dbl > 9223372036854774784.0 || dbl < -9223372036854775808.0) { | |
| jsondec_err(d, "JSON number is out of range."); | |
| } | |
| val.int64_val = dbl; /* must be guarded, overflow here is UB */ | |
| if (val.int64_val != dbl) { | |
| jsondec_errf(d, "JSON number was not integral (%f != %" PRId64 ")", dbl, | |
| val.int64_val); | |
| } | |
| break; | |
| } | |
| case JD_STRING: { | |
| upb_StringView str = jsondec_string(d); | |
| jsondec_checkempty(d, str, f); | |
| val.int64_val = jsondec_strtoint64(d, str); | |
| break; | |
| } | |
| default: | |
| jsondec_err(d, "Expected number or string"); | |
| } | |
| if (upb_FieldDef_CType(f) == kUpb_CType_Int32 || | |
| upb_FieldDef_CType(f) == kUpb_CType_Enum) { | |
| if (val.int64_val > INT32_MAX || val.int64_val < INT32_MIN) { | |
| jsondec_err(d, "Integer out of range."); | |
| } | |
| val.int32_val = (int32_t)val.int64_val; | |
| } | |
| return val; | |
| } | |
| /* Parse UINT32 or UINT64 value. */ | |
| static upb_MessageValue jsondec_uint(jsondec* d, const upb_FieldDef* f) { | |
| upb_MessageValue val; | |
| switch (jsondec_peek(d)) { | |
| case JD_NUMBER: { | |
| double dbl = jsondec_number(d); | |
| if (dbl > 18446744073709549568.0 || dbl < 0) { | |
| jsondec_err(d, "JSON number is out of range."); | |
| } | |
| val.uint64_val = dbl; /* must be guarded, overflow here is UB */ | |
| if (val.uint64_val != dbl) { | |
| jsondec_errf(d, "JSON number was not integral (%f != %" PRIu64 ")", dbl, | |
| val.uint64_val); | |
| } | |
| break; | |
| } | |
| case JD_STRING: { | |
| upb_StringView str = jsondec_string(d); | |
| jsondec_checkempty(d, str, f); | |
| val.uint64_val = jsondec_strtouint64(d, str); | |
| break; | |
| } | |
| default: | |
| jsondec_err(d, "Expected number or string"); | |
| } | |
| if (upb_FieldDef_CType(f) == kUpb_CType_UInt32) { | |
| if (val.uint64_val > UINT32_MAX) { | |
| jsondec_err(d, "Integer out of range."); | |
| } | |
| val.uint32_val = (uint32_t)val.uint64_val; | |
| } | |
| return val; | |
| } | |
| /* Parse DOUBLE or FLOAT value. */ | |
| static upb_MessageValue jsondec_double(jsondec* d, const upb_FieldDef* f) { | |
| upb_StringView str; | |
| upb_MessageValue val; | |
| switch (jsondec_peek(d)) { | |
| case JD_NUMBER: | |
| val.double_val = jsondec_number(d); | |
| break; | |
| case JD_STRING: | |
| str = jsondec_string(d); | |
| if (str.size == 0) { | |
| jsondec_checkempty(d, str, f); | |
| val.double_val = 0.0; | |
| } else if (jsondec_streql(str, "NaN")) { | |
| val.double_val = NAN; | |
| } else if (jsondec_streql(str, "Infinity")) { | |
| val.double_val = INFINITY; | |
| } else if (jsondec_streql(str, "-Infinity")) { | |
| val.double_val = -INFINITY; | |
| } else { | |
| char* end; | |
| val.double_val = strtod(str.data, &end); | |
| if (end != str.data + str.size) { | |
| d->result = kUpb_JsonDecodeResult_Error; | |
| upb_Status_SetErrorFormat( | |
| d->status, | |
| "Non-number characters in quoted number (field: %s). " | |
| "This will be an error in a future version.", | |
| upb_FieldDef_FullName(f)); | |
| } | |
| } | |
| break; | |
| default: | |
| jsondec_err(d, "Expected number or string"); | |
| } | |
| if (upb_FieldDef_CType(f) == kUpb_CType_Float) { | |
| float f = val.double_val; | |
| if (val.double_val != INFINITY && val.double_val != -INFINITY) { | |
| if (f == INFINITY || f == -INFINITY) jsondec_err(d, "Float out of range"); | |
| } | |
| val.float_val = f; | |
| } | |
| return val; | |
| } | |
| /* Parse STRING or BYTES value. */ | |
| static upb_MessageValue jsondec_strfield(jsondec* d, const upb_FieldDef* f) { | |
| upb_MessageValue val; | |
| val.str_val = jsondec_string(d); | |
| if (upb_FieldDef_CType(f) == kUpb_CType_Bytes) { | |
| val.str_val.size = jsondec_base64(d, val.str_val); | |
| } | |
| return val; | |
| } | |
| static upb_JsonMessageValue jsondec_enum(jsondec* d, const upb_FieldDef* f) { | |
| switch (jsondec_peek(d)) { | |
| case JD_STRING: { | |
| upb_StringView str = jsondec_string(d); | |
| const upb_EnumDef* e = upb_FieldDef_EnumSubDef(f); | |
| const upb_EnumValueDef* ev = | |
| upb_EnumDef_FindByJsonNameWithSize(e, str.data, str.size); | |
| upb_JsonMessageValue val = {.ignore = false}; | |
| if (ev) { | |
| val.value.int32_val = upb_EnumValueDef_Number(ev); | |
| } else { | |
| if (d->options & upb_JsonDecode_IgnoreUnknown) { | |
| val.ignore = true; | |
| } else { | |
| jsondec_errf(d, "Unknown enumerator: '" UPB_STRINGVIEW_FORMAT "'", | |
| UPB_STRINGVIEW_ARGS(str)); | |
| } | |
| } | |
| return val; | |
| } | |
| case JD_NULL: { | |
| if (jsondec_isnullvalue(f)) { | |
| upb_JsonMessageValue val = {.ignore = false}; | |
| jsondec_null(d); | |
| val.value.int32_val = 0; | |
| return val; | |
| } | |
| } | |
| /* Fallthrough. */ | |
| default: | |
| return (upb_JsonMessageValue){.value = jsondec_int(d, f), | |
| .ignore = false}; | |
| } | |
| } | |
| static upb_MessageValue jsondec_bool(jsondec* d, const upb_FieldDef* f) { | |
| bool is_map_key = upb_FieldDef_Number(f) == 1 && | |
| upb_MessageDef_IsMapEntry(upb_FieldDef_ContainingType(f)); | |
| upb_MessageValue val; | |
| if (is_map_key) { | |
| upb_StringView str = jsondec_string(d); | |
| if (jsondec_streql(str, "true")) { | |
| val.bool_val = true; | |
| } else if (jsondec_streql(str, "false")) { | |
| val.bool_val = false; | |
| } else { | |
| jsondec_err(d, "Invalid boolean map key"); | |
| } | |
| } else { | |
| switch (jsondec_peek(d)) { | |
| case JD_TRUE: | |
| val.bool_val = true; | |
| jsondec_true(d); | |
| break; | |
| case JD_FALSE: | |
| val.bool_val = false; | |
| jsondec_false(d); | |
| break; | |
| default: | |
| jsondec_err(d, "Expected true or false"); | |
| } | |
| } | |
| return val; | |
| } | |
| /* Composite types (array/message/map) ****************************************/ | |
| static void jsondec_array(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| upb_Array* arr = upb_Message_Mutable(msg, f, d->arena).array; | |
| jsondec_checkoom(d, arr); | |
| jsondec_arrstart(d); | |
| while (jsondec_arrnext(d)) { | |
| upb_JsonMessageValue elem = jsondec_value(d, f); | |
| if (!elem.ignore) { | |
| jsondec_checkoom(d, upb_Array_Append(arr, elem.value, d->arena)); | |
| } | |
| } | |
| jsondec_arrend(d); | |
| } | |
| static void jsondec_map(jsondec* d, upb_Message* msg, const upb_FieldDef* f) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| upb_Map* map = upb_Message_Mutable(msg, f, d->arena).map; | |
| jsondec_checkoom(d, map); | |
| const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); | |
| const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); | |
| const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); | |
| jsondec_objstart(d); | |
| while (jsondec_objnext(d)) { | |
| upb_JsonMessageValue key, val; | |
| key = jsondec_value(d, key_f); | |
| UPB_ASSUME(!key.ignore); // Map key cannot be enum. | |
| jsondec_entrysep(d); | |
| val = jsondec_value(d, val_f); | |
| if (!val.ignore) { | |
| jsondec_checkoom(d, upb_Map_Set(map, key.value, val.value, d->arena)); | |
| } | |
| } | |
| jsondec_objend(d); | |
| } | |
| static void jsondec_tomsg(jsondec* d, upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { | |
| jsondec_object(d, msg, m); | |
| } else { | |
| jsondec_wellknown(d, msg, m); | |
| } | |
| } | |
| static upb_MessageValue jsondec_msg(jsondec* d, const upb_FieldDef* f) { | |
| const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); | |
| const upb_MiniTable* layout = upb_MessageDef_MiniTable(m); | |
| upb_Message* msg = upb_Message_New(layout, d->arena); | |
| jsondec_checkoom(d, msg); | |
| upb_MessageValue val; | |
| jsondec_tomsg(d, msg, m); | |
| val.msg_val = msg; | |
| return val; | |
| } | |
| static void jsondec_field(jsondec* d, upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| upb_StringView name; | |
| const upb_FieldDef* f; | |
| const upb_FieldDef* preserved; | |
| name = jsondec_string(d); | |
| jsondec_entrysep(d); | |
| if (name.size >= 2 && name.data[0] == '[' && | |
| name.data[name.size - 1] == ']') { | |
| f = upb_DefPool_FindExtensionByNameWithSize(d->symtab, name.data + 1, | |
| name.size - 2); | |
| if (f && upb_FieldDef_ContainingType(f) != m) { | |
| jsondec_errf( | |
| d, "Extension %s extends message %s, but was seen in message %s", | |
| upb_FieldDef_FullName(f), | |
| upb_MessageDef_FullName(upb_FieldDef_ContainingType(f)), | |
| upb_MessageDef_FullName(m)); | |
| } | |
| } else { | |
| f = upb_MessageDef_FindByJsonNameWithSize(m, name.data, name.size); | |
| } | |
| if (!f) { | |
| if ((d->options & upb_JsonDecode_IgnoreUnknown) == 0) { | |
| jsondec_errf(d, "No such field: " UPB_STRINGVIEW_FORMAT, | |
| UPB_STRINGVIEW_ARGS(name)); | |
| } | |
| jsondec_skipval(d); | |
| return; | |
| } | |
| if (jsondec_peek(d) == JD_NULL && !jsondec_isvalue(f)) { | |
| /* JSON "null" indicates a default value, so no need to set anything. */ | |
| jsondec_null(d); | |
| return; | |
| } | |
| if (upb_FieldDef_RealContainingOneof(f) && | |
| upb_Message_WhichOneofByDef(msg, upb_FieldDef_ContainingOneof(f))) { | |
| jsondec_err(d, "More than one field for this oneof."); | |
| } | |
| preserved = d->debug_field; | |
| d->debug_field = f; | |
| if (upb_FieldDef_IsMap(f)) { | |
| jsondec_map(d, msg, f); | |
| } else if (upb_FieldDef_IsRepeated(f)) { | |
| jsondec_array(d, msg, f); | |
| } else if (upb_FieldDef_IsSubMessage(f)) { | |
| upb_Message* submsg = upb_Message_Mutable(msg, f, d->arena).msg; | |
| jsondec_checkoom(d, submsg); | |
| const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); | |
| jsondec_tomsg(d, submsg, subm); | |
| } else { | |
| upb_JsonMessageValue val = jsondec_value(d, f); | |
| if (!val.ignore) { | |
| jsondec_checkoom(d, | |
| upb_Message_SetFieldByDef(msg, f, val.value, d->arena)); | |
| } | |
| } | |
| d->debug_field = preserved; | |
| } | |
| static void jsondec_object(jsondec* d, upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| jsondec_objstart(d); | |
| while (jsondec_objnext(d)) { | |
| jsondec_field(d, msg, m); | |
| } | |
| jsondec_objend(d); | |
| } | |
| static upb_MessageValue jsondec_nonenum(jsondec* d, const upb_FieldDef* f) { | |
| switch (upb_FieldDef_CType(f)) { | |
| case kUpb_CType_Bool: | |
| return jsondec_bool(d, f); | |
| case kUpb_CType_Float: | |
| case kUpb_CType_Double: | |
| return jsondec_double(d, f); | |
| case kUpb_CType_UInt32: | |
| case kUpb_CType_UInt64: | |
| return jsondec_uint(d, f); | |
| case kUpb_CType_Int32: | |
| case kUpb_CType_Int64: | |
| return jsondec_int(d, f); | |
| case kUpb_CType_String: | |
| case kUpb_CType_Bytes: | |
| return jsondec_strfield(d, f); | |
| case kUpb_CType_Message: | |
| return jsondec_msg(d, f); | |
| case kUpb_CType_Enum: | |
| default: | |
| UPB_UNREACHABLE(); | |
| } | |
| } | |
| static upb_JsonMessageValue jsondec_value(jsondec* d, const upb_FieldDef* f) { | |
| if (upb_FieldDef_CType(f) == kUpb_CType_Enum) { | |
| return jsondec_enum(d, f); | |
| } else { | |
| return (upb_JsonMessageValue){.value = jsondec_nonenum(d, f), | |
| .ignore = false}; | |
| } | |
| } | |
| /* Well-known types ***********************************************************/ | |
| static int jsondec_tsdigits(jsondec* d, const char** ptr, size_t digits, | |
| const char* after) { | |
| uint64_t val; | |
| const char* p = *ptr; | |
| const char* end = p + digits; | |
| size_t after_len = after ? strlen(after) : 0; | |
| UPB_ASSERT(digits <= 9); /* int can't overflow. */ | |
| if (jsondec_buftouint64(d, p, end, &val) != end || | |
| (after_len && memcmp(end, after, after_len) != 0)) { | |
| jsondec_err(d, "Malformed timestamp"); | |
| } | |
| UPB_ASSERT(val < INT_MAX); | |
| *ptr = end + after_len; | |
| return (int)val; | |
| } | |
| static int jsondec_nanos(jsondec* d, const char** ptr, const char* end) { | |
| uint64_t nanos = 0; | |
| const char* p = *ptr; | |
| if (p != end && *p == '.') { | |
| const char* nano_end = jsondec_buftouint64(d, p + 1, end, &nanos); | |
| int digits = (int)(nano_end - p - 1); | |
| int exp_lg10 = 9 - digits; | |
| if (digits > 9) { | |
| jsondec_err(d, "Too many digits for partial seconds"); | |
| } | |
| while (exp_lg10--) nanos *= 10; | |
| *ptr = nano_end; | |
| } | |
| UPB_ASSERT(nanos < INT_MAX); | |
| return (int)nanos; | |
| } | |
| /* jsondec_epochdays(1970, 1, 1) == 1970-01-01 == 0. */ | |
| int jsondec_epochdays(int y, int m, int d) { | |
| const uint32_t year_base = 4800; /* Before min year, multiple of 400. */ | |
| const uint32_t m_adj = m - 3; /* March-based month. */ | |
| const uint32_t carry = m_adj > (uint32_t)m ? 1 : 0; | |
| const uint32_t adjust = carry ? 12 : 0; | |
| const uint32_t y_adj = y + year_base - carry; | |
| const uint32_t month_days = ((m_adj + adjust) * 62719 + 769) / 2048; | |
| const uint32_t leap_days = y_adj / 4 - y_adj / 100 + y_adj / 400; | |
| return y_adj * 365 + leap_days + month_days + (d - 1) - 2472632; | |
| } | |
| static int64_t jsondec_unixtime(int y, int m, int d, int h, int min, int s) { | |
| return (int64_t)jsondec_epochdays(y, m, d) * 86400 + h * 3600 + min * 60 + s; | |
| } | |
| static void jsondec_timestamp(jsondec* d, upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| upb_MessageValue seconds; | |
| upb_MessageValue nanos; | |
| upb_StringView str = jsondec_string(d); | |
| const char* ptr = str.data; | |
| const char* end = ptr + str.size; | |
| if (str.size < 20) goto malformed; | |
| { | |
| /* 1972-01-01T01:00:00 */ | |
| int year = jsondec_tsdigits(d, &ptr, 4, "-"); | |
| int mon = jsondec_tsdigits(d, &ptr, 2, "-"); | |
| int day = jsondec_tsdigits(d, &ptr, 2, "T"); | |
| int hour = jsondec_tsdigits(d, &ptr, 2, ":"); | |
| int min = jsondec_tsdigits(d, &ptr, 2, ":"); | |
| int sec = jsondec_tsdigits(d, &ptr, 2, NULL); | |
| seconds.int64_val = jsondec_unixtime(year, mon, day, hour, min, sec); | |
| } | |
| nanos.int32_val = jsondec_nanos(d, &ptr, end); | |
| { | |
| /* [+-]08:00 or Z */ | |
| int ofs_hour = 0; | |
| int ofs_min = 0; | |
| bool neg = false; | |
| if (ptr == end) goto malformed; | |
| switch (*ptr++) { | |
| case '-': | |
| neg = true; | |
| /* fallthrough */ | |
| case '+': | |
| if ((end - ptr) != 5) goto malformed; | |
| ofs_hour = jsondec_tsdigits(d, &ptr, 2, ":"); | |
| ofs_min = jsondec_tsdigits(d, &ptr, 2, NULL); | |
| ofs_min = ((ofs_hour * 60) + ofs_min) * 60; | |
| seconds.int64_val += (neg ? ofs_min : -ofs_min); | |
| break; | |
| case 'Z': | |
| if (ptr != end) goto malformed; | |
| break; | |
| default: | |
| goto malformed; | |
| } | |
| } | |
| if (seconds.int64_val < -62135596800) { | |
| jsondec_err(d, "Timestamp out of range"); | |
| } | |
| jsondec_checkoom( | |
| d, upb_Message_SetFieldByDef(msg, upb_MessageDef_FindFieldByNumber(m, 1), | |
| seconds, d->arena)); | |
| jsondec_checkoom( | |
| d, upb_Message_SetFieldByDef(msg, upb_MessageDef_FindFieldByNumber(m, 2), | |
| nanos, d->arena)); | |
| return; | |
| malformed: | |
| jsondec_err(d, "Malformed timestamp"); | |
| } | |
| static void jsondec_duration(jsondec* d, upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| upb_MessageValue seconds; | |
| upb_MessageValue nanos; | |
| upb_StringView str = jsondec_string(d); | |
| const char* ptr = str.data; | |
| const char* end = ptr + str.size; | |
| const int64_t max = (uint64_t)3652500 * 86400; | |
| bool neg = false; | |
| /* "3.000000001s", "3s", etc. */ | |
| ptr = jsondec_buftoint64(d, ptr, end, &seconds.int64_val, &neg); | |
| nanos.int32_val = jsondec_nanos(d, &ptr, end); | |
| if (end - ptr != 1 || *ptr != 's') { | |
| jsondec_err(d, "Malformed duration"); | |
| } | |
| if (seconds.int64_val < -max || seconds.int64_val > max) { | |
| jsondec_err(d, "Duration out of range"); | |
| } | |
| if (neg) { | |
| nanos.int32_val = -nanos.int32_val; | |
| } | |
| jsondec_checkoom( | |
| d, upb_Message_SetFieldByDef(msg, upb_MessageDef_FindFieldByNumber(m, 1), | |
| seconds, d->arena)); | |
| jsondec_checkoom( | |
| d, upb_Message_SetFieldByDef(msg, upb_MessageDef_FindFieldByNumber(m, 2), | |
| nanos, d->arena)); | |
| } | |
| static void jsondec_listvalue(jsondec* d, upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); | |
| const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(values_f); | |
| const upb_MiniTable* value_layout = upb_MessageDef_MiniTable(value_m); | |
| upb_Array* values = upb_Message_Mutable(msg, values_f, d->arena).array; | |
| jsondec_checkoom(d, values); | |
| jsondec_arrstart(d); | |
| while (jsondec_arrnext(d)) { | |
| upb_Message* value_msg = upb_Message_New(value_layout, d->arena); | |
| jsondec_checkoom(d, value_msg); | |
| upb_MessageValue value; | |
| value.msg_val = value_msg; | |
| jsondec_checkoom(d, upb_Array_Append(values, value, d->arena)); | |
| jsondec_wellknownvalue(d, value_msg, value_m); | |
| } | |
| jsondec_arrend(d); | |
| } | |
| static void jsondec_struct(jsondec* d, upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); | |
| const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); | |
| const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); | |
| const upb_MessageDef* value_m = upb_FieldDef_MessageSubDef(value_f); | |
| const upb_MiniTable* value_layout = upb_MessageDef_MiniTable(value_m); | |
| upb_Map* fields = upb_Message_Mutable(msg, fields_f, d->arena).map; | |
| jsondec_checkoom(d, fields); | |
| jsondec_objstart(d); | |
| while (jsondec_objnext(d)) { | |
| upb_MessageValue key, value; | |
| upb_Message* value_msg = upb_Message_New(value_layout, d->arena); | |
| jsondec_checkoom(d, value_msg); | |
| key.str_val = jsondec_string(d); | |
| value.msg_val = value_msg; | |
| jsondec_checkoom(d, upb_Map_Set(fields, key, value, d->arena)); | |
| jsondec_entrysep(d); | |
| jsondec_wellknownvalue(d, value_msg, value_m); | |
| } | |
| jsondec_objend(d); | |
| } | |
| static void jsondec_wellknownvalue(jsondec* d, upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| upb_MessageValue val; | |
| const upb_FieldDef* f; | |
| upb_Message* submsg; | |
| switch (jsondec_peek(d)) { | |
| case JD_NUMBER: | |
| /* double number_value = 2; */ | |
| f = upb_MessageDef_FindFieldByNumber(m, 2); | |
| val.double_val = jsondec_number(d); | |
| break; | |
| case JD_STRING: | |
| /* string string_value = 3; */ | |
| f = upb_MessageDef_FindFieldByNumber(m, 3); | |
| val.str_val = jsondec_string(d); | |
| break; | |
| case JD_FALSE: | |
| /* bool bool_value = 4; */ | |
| f = upb_MessageDef_FindFieldByNumber(m, 4); | |
| val.bool_val = false; | |
| jsondec_false(d); | |
| break; | |
| case JD_TRUE: | |
| /* bool bool_value = 4; */ | |
| f = upb_MessageDef_FindFieldByNumber(m, 4); | |
| val.bool_val = true; | |
| jsondec_true(d); | |
| break; | |
| case JD_NULL: | |
| /* NullValue null_value = 1; */ | |
| f = upb_MessageDef_FindFieldByNumber(m, 1); | |
| val.int32_val = 0; | |
| jsondec_null(d); | |
| break; | |
| /* Note: these cases return, because upb_Message_Mutable() is enough. */ | |
| case JD_OBJECT: | |
| /* Struct struct_value = 5; */ | |
| f = upb_MessageDef_FindFieldByNumber(m, 5); | |
| submsg = upb_Message_Mutable(msg, f, d->arena).msg; | |
| jsondec_checkoom(d, submsg); | |
| jsondec_struct(d, submsg, upb_FieldDef_MessageSubDef(f)); | |
| return; | |
| case JD_ARRAY: | |
| /* ListValue list_value = 6; */ | |
| f = upb_MessageDef_FindFieldByNumber(m, 6); | |
| submsg = upb_Message_Mutable(msg, f, d->arena).msg; | |
| jsondec_checkoom(d, submsg); | |
| jsondec_listvalue(d, submsg, upb_FieldDef_MessageSubDef(f)); | |
| return; | |
| default: | |
| UPB_UNREACHABLE(); | |
| } | |
| jsondec_checkoom(d, upb_Message_SetFieldByDef(msg, f, val, d->arena)); | |
| } | |
| static upb_StringView jsondec_mask(jsondec* d, const char* buf, | |
| const char* end) { | |
| /* FieldMask fields grow due to inserted '_' characters, so we can't do the | |
| * transform in place. */ | |
| const char* ptr = buf; | |
| upb_StringView ret; | |
| char* out; | |
| ret.size = end - ptr; | |
| while (ptr < end) { | |
| ret.size += (*ptr >= 'A' && *ptr <= 'Z'); | |
| ptr++; | |
| } | |
| out = upb_Arena_Malloc(d->arena, ret.size); | |
| jsondec_checkoom(d, out); | |
| ptr = buf; | |
| ret.data = out; | |
| while (ptr < end) { | |
| char ch = *ptr++; | |
| if (ch >= 'A' && ch <= 'Z') { | |
| *out++ = '_'; | |
| *out++ = ch + 32; | |
| } else if (ch == '_') { | |
| jsondec_err(d, "field mask may not contain '_'"); | |
| } else { | |
| *out++ = ch; | |
| } | |
| } | |
| return ret; | |
| } | |
| static void jsondec_fieldmask(jsondec* d, upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| /* repeated string paths = 1; */ | |
| const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); | |
| upb_Array* arr = upb_Message_Mutable(msg, paths_f, d->arena).array; | |
| jsondec_checkoom(d, arr); | |
| upb_StringView str = jsondec_string(d); | |
| const char* ptr = str.data; | |
| const char* end = ptr + str.size; | |
| upb_MessageValue val; | |
| while (ptr < end) { | |
| const char* elem_end = memchr(ptr, ',', end - ptr); | |
| if (elem_end) { | |
| val.str_val = jsondec_mask(d, ptr, elem_end); | |
| ptr = elem_end + 1; | |
| } else { | |
| val.str_val = jsondec_mask(d, ptr, end); | |
| ptr = end; | |
| } | |
| jsondec_checkoom(d, upb_Array_Append(arr, val, d->arena)); | |
| } | |
| } | |
| static void jsondec_anyfield(jsondec* d, upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| if (upb_MessageDef_WellKnownType(m) == kUpb_WellKnown_Unspecified) { | |
| /* For regular types: {"@type": "[user type]", "f1": <V1>, "f2": <V2>} | |
| * where f1, f2, etc. are the normal fields of this type. */ | |
| jsondec_field(d, msg, m); | |
| } else { | |
| /* For well-known types: {"@type": "[well-known type]", "value": <X>} | |
| * where <X> is whatever encoding the WKT normally uses. */ | |
| upb_StringView str = jsondec_string(d); | |
| jsondec_entrysep(d); | |
| if (!jsondec_streql(str, "value")) { | |
| jsondec_err(d, "Key for well-known type must be 'value'"); | |
| } | |
| jsondec_wellknown(d, msg, m); | |
| } | |
| } | |
| static const upb_MessageDef* jsondec_typeurl(jsondec* d, upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); | |
| const upb_MessageDef* type_m; | |
| upb_StringView type_url = jsondec_string(d); | |
| const char* end = type_url.data + type_url.size; | |
| const char* ptr = end; | |
| upb_MessageValue val; | |
| val.str_val = type_url; | |
| jsondec_checkoom(d, | |
| upb_Message_SetFieldByDef(msg, type_url_f, val, d->arena)); | |
| /* Find message name after the last '/' */ | |
| while (ptr > type_url.data && *--ptr != '/') { | |
| } | |
| if (ptr == type_url.data || ptr == end) { | |
| jsondec_err(d, "Type url must have at least one '/' and non-empty host"); | |
| } | |
| ptr++; | |
| type_m = upb_DefPool_FindMessageByNameWithSize(d->symtab, ptr, end - ptr); | |
| if (!type_m) { | |
| jsondec_err(d, "Type was not found"); | |
| } | |
| return type_m; | |
| } | |
| static void jsondec_any(jsondec* d, upb_Message* msg, const upb_MessageDef* m) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| /* string type_url = 1; | |
| * bytes value = 2; */ | |
| const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); | |
| upb_Message* any_msg; | |
| const upb_MessageDef* any_m = NULL; | |
| const char* pre_type_data = NULL; | |
| const char* pre_type_end = NULL; | |
| upb_MessageValue encoded; | |
| jsondec_objstart(d); | |
| /* Scan looking for "@type", which is not necessarily first. */ | |
| while (!any_m && jsondec_objnext(d)) { | |
| const char* start = d->ptr; | |
| upb_StringView name = jsondec_string(d); | |
| jsondec_entrysep(d); | |
| if (jsondec_streql(name, "@type")) { | |
| any_m = jsondec_typeurl(d, msg, m); | |
| if (pre_type_data) { | |
| pre_type_end = start; | |
| while (*pre_type_end != ',') pre_type_end--; | |
| } | |
| } else { | |
| if (!pre_type_data) pre_type_data = start; | |
| jsondec_skipval(d); | |
| } | |
| } | |
| if (!any_m) { | |
| jsondec_err(d, "Any object didn't contain a '@type' field"); | |
| } | |
| const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); | |
| any_msg = upb_Message_New(any_layout, d->arena); | |
| jsondec_checkoom(d, any_msg); | |
| if (pre_type_data) { | |
| size_t len = pre_type_end - pre_type_data + 1; | |
| char* tmp = upb_Arena_Malloc(d->arena, len); | |
| jsondec_checkoom(d, tmp); | |
| const char* saved_ptr = d->ptr; | |
| const char* saved_end = d->end; | |
| memcpy(tmp, pre_type_data, len - 1); | |
| tmp[len - 1] = '}'; | |
| d->ptr = tmp; | |
| d->end = tmp + len; | |
| d->is_first = true; | |
| while (jsondec_objnext(d)) { | |
| jsondec_anyfield(d, any_msg, any_m); | |
| } | |
| d->ptr = saved_ptr; | |
| d->end = saved_end; | |
| } | |
| while (jsondec_objnext(d)) { | |
| jsondec_anyfield(d, any_msg, any_m); | |
| } | |
| jsondec_objend(d); | |
| upb_EncodeStatus status = | |
| upb_Encode(any_msg, upb_MessageDef_MiniTable(any_m), 0, d->arena, | |
| (char**)&encoded.str_val.data, &encoded.str_val.size); | |
| if (status != kUpb_EncodeStatus_Ok) { | |
| jsondec_errf(d, "Encode failed: %s", upb_EncodeStatus_String(status)); | |
| } | |
| jsondec_checkoom(d, | |
| upb_Message_SetFieldByDef(msg, value_f, encoded, d->arena)); | |
| } | |
| static void jsondec_wrapper(jsondec* d, upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 1); | |
| upb_JsonMessageValue val = jsondec_value(d, value_f); | |
| UPB_ASSUME(val.ignore == false); // Wrapper cannot be an enum. | |
| jsondec_checkoom( | |
| d, upb_Message_SetFieldByDef(msg, value_f, val.value, d->arena)); | |
| } | |
| static void jsondec_wellknown(jsondec* d, upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| switch (upb_MessageDef_WellKnownType(m)) { | |
| case kUpb_WellKnown_Any: | |
| jsondec_any(d, msg, m); | |
| break; | |
| case kUpb_WellKnown_FieldMask: | |
| jsondec_fieldmask(d, msg, m); | |
| break; | |
| case kUpb_WellKnown_Duration: | |
| jsondec_duration(d, msg, m); | |
| break; | |
| case kUpb_WellKnown_Timestamp: | |
| jsondec_timestamp(d, msg, m); | |
| break; | |
| case kUpb_WellKnown_Value: | |
| jsondec_wellknownvalue(d, msg, m); | |
| break; | |
| case kUpb_WellKnown_ListValue: | |
| jsondec_listvalue(d, msg, m); | |
| break; | |
| case kUpb_WellKnown_Struct: | |
| jsondec_struct(d, msg, m); | |
| break; | |
| case kUpb_WellKnown_DoubleValue: | |
| case kUpb_WellKnown_FloatValue: | |
| case kUpb_WellKnown_Int64Value: | |
| case kUpb_WellKnown_UInt64Value: | |
| case kUpb_WellKnown_Int32Value: | |
| case kUpb_WellKnown_UInt32Value: | |
| case kUpb_WellKnown_StringValue: | |
| case kUpb_WellKnown_BytesValue: | |
| case kUpb_WellKnown_BoolValue: | |
| jsondec_wrapper(d, msg, m); | |
| break; | |
| default: | |
| UPB_UNREACHABLE(); | |
| } | |
| } | |
| static int upb_JsonDecoder_Decode(jsondec* const d, upb_Message* const msg, | |
| const upb_MessageDef* const m) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| if (UPB_SETJMP(d->err)) return kUpb_JsonDecodeResult_Error; | |
| jsondec_tomsg(d, msg, m); | |
| // Consume any trailing whitespace before checking if we read the entire | |
| // input. | |
| jsondec_consumews(d); | |
| if (d->ptr == d->end) { | |
| return d->result; | |
| } else { | |
| jsondec_seterrmsg(d, "unexpected trailing characters"); | |
| return kUpb_JsonDecodeResult_Error; | |
| } | |
| } | |
| int upb_JsonDecodeDetectingNonconformance(const char* buf, size_t size, | |
| upb_Message* msg, | |
| const upb_MessageDef* m, | |
| const upb_DefPool* symtab, | |
| int options, upb_Arena* arena, | |
| upb_Status* status) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| jsondec d; | |
| if (size == 0) return true; | |
| UPB_ASSERT(!((options & upb_JsonDecode_ValidateUtf8_Disable) && | |
| (options & upb_JsonDecode_ValidateUtf8_Enforce))); | |
| if (!(options & upb_JsonDecode_ValidateUtf8_Disable)) { | |
| if (!utf8_range_IsValid(buf, size)) { | |
| if (options & upb_JsonDecode_ValidateUtf8_Enforce) { | |
| upb_Status_SetErrorMessage(status, "Invalid UTF-8 in JSON input"); | |
| return kUpb_JsonDecodeResult_Error; | |
| } else { | |
| fprintf( | |
| stderr, | |
| "Invalid UTF-8 in JSON input. This will be rejected starting in " | |
| "the 2027-Q1 breaking change\n"); | |
| } | |
| } | |
| } | |
| d.ptr = buf; | |
| d.end = buf + size; | |
| d.arena = arena; | |
| d.symtab = symtab; | |
| d.status = status; | |
| d.options = options; | |
| d.depth = 64; | |
| d.result = kUpb_JsonDecodeResult_Ok; | |
| d.line = 1; | |
| d.line_begin = d.ptr; | |
| d.debug_field = NULL; | |
| d.is_first = false; | |
| return upb_JsonDecoder_Decode(&d, msg, m); | |
| } | |
| #include <float.h> | |
| #include <inttypes.h> | |
| #include <math.h> | |
| #include <setjmp.h> | |
| #include <stdarg.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| typedef struct { | |
| char *buf, *ptr, *end; | |
| size_t overflow; | |
| int indent_depth; | |
| int options; | |
| const upb_DefPool* ext_pool; | |
| jmp_buf err; | |
| upb_Status* status; | |
| upb_Arena* arena; | |
| } jsonenc; | |
| static void jsonenc_msg(jsonenc* e, const upb_Message* msg, | |
| const upb_MessageDef* m); | |
| static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, | |
| const upb_FieldDef* f); | |
| static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, | |
| const upb_MessageDef* m); | |
| static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, | |
| const upb_MessageDef* m, bool first); | |
| static void jsonenc_value(jsonenc* e, const upb_Message* msg, | |
| const upb_MessageDef* m); | |
| static void jsonenc_string(jsonenc* e, upb_StringView str); | |
| UPB_NORETURN static void jsonenc_err(jsonenc* e, const char* msg) { | |
| upb_Status_SetErrorMessage(e->status, msg); | |
| UPB_LONGJMP(e->err, 1); | |
| } | |
| UPB_PRINTF(2, 3) | |
| UPB_NORETURN static void jsonenc_errf(jsonenc* e, const char* fmt, ...) { | |
| va_list argp; | |
| va_start(argp, fmt); | |
| upb_Status_VSetErrorFormat(e->status, fmt, argp); | |
| va_end(argp); | |
| UPB_LONGJMP(e->err, 1); | |
| } | |
| static upb_Arena* jsonenc_arena(jsonenc* e) { | |
| /* Create lazily, since it's only needed for Any */ | |
| if (!e->arena) { | |
| e->arena = upb_Arena_New(); | |
| if (!e->arena) { | |
| jsonenc_err(e, "Out of memory"); | |
| } | |
| } | |
| return e->arena; | |
| } | |
| static void jsonenc_putbytes(jsonenc* e, const void* data, size_t len) { | |
| size_t have = e->end - e->ptr; | |
| if (UPB_LIKELY(have >= len)) { | |
| memcpy(e->ptr, data, len); | |
| e->ptr += len; | |
| } else { | |
| if (have) { | |
| memcpy(e->ptr, data, have); | |
| e->ptr += have; | |
| } | |
| e->overflow += (len - have); | |
| } | |
| } | |
| static void jsonenc_putstr(jsonenc* e, const char* str) { | |
| jsonenc_putbytes(e, str, strlen(str)); | |
| } | |
| UPB_PRINTF(2, 3) | |
| static void jsonenc_printf(jsonenc* e, const char* fmt, ...) { | |
| size_t n; | |
| size_t have = e->end - e->ptr; | |
| va_list args; | |
| va_start(args, fmt); | |
| n = _upb_vsnprintf(e->ptr, have, fmt, args); | |
| va_end(args); | |
| if (UPB_LIKELY(have > n)) { | |
| e->ptr += n; | |
| } else { | |
| e->ptr = UPB_PTRADD(e->ptr, have); | |
| e->overflow += (n - have); | |
| } | |
| } | |
| static void jsonenc_nanos(jsonenc* e, int32_t nanos) { | |
| int digits = 9; | |
| if (nanos == 0) return; | |
| if (nanos < 0 || nanos >= 1000000000) { | |
| jsonenc_err(e, "error formatting timestamp as JSON: invalid nanos"); | |
| } | |
| while (nanos % 1000 == 0) { | |
| nanos /= 1000; | |
| digits -= 3; | |
| } | |
| jsonenc_printf(e, ".%.*" PRId32, digits, nanos); | |
| } | |
| static void jsonenc_timestamp(jsonenc* e, const upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); | |
| const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); | |
| int64_t seconds = upb_Message_GetFieldByDef(msg, seconds_f).int64_val; | |
| int32_t nanos = upb_Message_GetFieldByDef(msg, nanos_f).int32_val; | |
| int L, N, I, J, K, hour, min, sec; | |
| if (seconds < -62135596800) { | |
| jsonenc_err(e, | |
| "error formatting timestamp as JSON: minimum acceptable value " | |
| "is 0001-01-01T00:00:00Z"); | |
| } else if (seconds > 253402300799) { | |
| jsonenc_err(e, | |
| "error formatting timestamp as JSON: maximum acceptable value " | |
| "is 9999-12-31T23:59:59Z"); | |
| } | |
| /* Julian Day -> Y/M/D, Algorithm from: | |
| * Fliegel, H. F., and Van Flandern, T. C., "A Machine Algorithm for | |
| * Processing Calendar Dates," Communications of the Association of | |
| * Computing Machines, vol. 11 (1968), p. 657. */ | |
| seconds += 62135596800; // Ensure seconds is positive. | |
| L = (int)(seconds / 86400) - 719162 + 68569 + 2440588; | |
| N = 4 * L / 146097; | |
| L = L - (146097 * N + 3) / 4; | |
| I = 4000 * (L + 1) / 1461001; | |
| L = L - 1461 * I / 4 + 31; | |
| J = 80 * L / 2447; | |
| K = L - 2447 * J / 80; | |
| L = J / 11; | |
| J = J + 2 - 12 * L; | |
| I = 100 * (N - 49) + I + L; | |
| sec = seconds % 60; | |
| min = (seconds / 60) % 60; | |
| hour = (seconds / 3600) % 24; | |
| jsonenc_printf(e, "\"%04d-%02d-%02dT%02d:%02d:%02d", I, J, K, hour, min, sec); | |
| jsonenc_nanos(e, nanos); | |
| jsonenc_putstr(e, "Z\""); | |
| } | |
| static void jsonenc_duration(jsonenc* e, const upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| const upb_FieldDef* seconds_f = upb_MessageDef_FindFieldByNumber(m, 1); | |
| const upb_FieldDef* nanos_f = upb_MessageDef_FindFieldByNumber(m, 2); | |
| int64_t seconds = upb_Message_GetFieldByDef(msg, seconds_f).int64_val; | |
| int32_t nanos = upb_Message_GetFieldByDef(msg, nanos_f).int32_val; | |
| bool negative = false; | |
| if (seconds > 315576000000 || seconds < -315576000000 || | |
| (seconds != 0 && nanos != 0 && (seconds < 0) != (nanos < 0))) { | |
| jsonenc_err(e, "bad duration"); | |
| } | |
| if (seconds < 0) { | |
| negative = true; | |
| seconds = -seconds; | |
| } | |
| if (nanos < 0) { | |
| negative = true; | |
| nanos = -nanos; | |
| } | |
| jsonenc_putstr(e, "\""); | |
| if (negative) { | |
| jsonenc_putstr(e, "-"); | |
| } | |
| jsonenc_printf(e, "%" PRId64, seconds); | |
| jsonenc_nanos(e, nanos); | |
| jsonenc_putstr(e, "s\""); | |
| } | |
| static void jsonenc_enum(int32_t val, const upb_FieldDef* f, jsonenc* e) { | |
| const upb_EnumDef* e_def = upb_FieldDef_EnumSubDef(f); | |
| if (strcmp(upb_EnumDef_FullName(e_def), "google.protobuf.NullValue") == 0) { | |
| jsonenc_putstr(e, "null"); | |
| } else { | |
| const upb_EnumValueDef* ev = | |
| (e->options & upb_JsonEncode_FormatEnumsAsIntegers) | |
| ? NULL | |
| : upb_EnumDef_FindValueByNumber(e_def, val); | |
| if (ev) { | |
| const char* name = upb_EnumValueDef_JsonName(ev); | |
| jsonenc_string(e, upb_StringView_FromString(name)); | |
| } else { | |
| jsonenc_printf(e, "%" PRId32, val); | |
| } | |
| } | |
| } | |
| static void jsonenc_bytes(jsonenc* e, upb_StringView str) { | |
| /* Regular base64 (RFC 4648 section 4) by default; the URL- and filename-safe | |
| * alphabet (RFC 4648 section 5) when upb_JsonEncode_WebSafeBase64 is set. */ | |
| static const char kBase64[] = | |
| "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
| static const char kWebSafeBase64[] = | |
| "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; | |
| const char* base64 = | |
| (e->options & upb_JsonEncode_WebSafeBase64) ? kWebSafeBase64 : kBase64; | |
| const unsigned char* ptr = (unsigned char*)str.data; | |
| const unsigned char* end = UPB_PTRADD(ptr, str.size); | |
| char buf[4]; | |
| jsonenc_putstr(e, "\""); | |
| while (end - ptr >= 3) { | |
| buf[0] = base64[ptr[0] >> 2]; | |
| buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; | |
| buf[2] = base64[((ptr[1] & 0xf) << 2) | (ptr[2] >> 6)]; | |
| buf[3] = base64[ptr[2] & 0x3f]; | |
| jsonenc_putbytes(e, buf, 4); | |
| ptr += 3; | |
| } | |
| switch (end - ptr) { | |
| case 2: | |
| buf[0] = base64[ptr[0] >> 2]; | |
| buf[1] = base64[((ptr[0] & 0x3) << 4) | (ptr[1] >> 4)]; | |
| buf[2] = base64[(ptr[1] & 0xf) << 2]; | |
| buf[3] = '='; | |
| jsonenc_putbytes(e, buf, 4); | |
| break; | |
| case 1: | |
| buf[0] = base64[ptr[0] >> 2]; | |
| buf[1] = base64[((ptr[0] & 0x3) << 4)]; | |
| buf[2] = '='; | |
| buf[3] = '='; | |
| jsonenc_putbytes(e, buf, 4); | |
| break; | |
| } | |
| jsonenc_putstr(e, "\""); | |
| } | |
| static void jsonenc_put_escaped_char(jsonenc* e, char ch) { | |
| switch (ch) { | |
| case '\n': | |
| jsonenc_putstr(e, "\\n"); | |
| break; | |
| case '\r': | |
| jsonenc_putstr(e, "\\r"); | |
| break; | |
| case '\t': | |
| jsonenc_putstr(e, "\\t"); | |
| break; | |
| case '\"': | |
| jsonenc_putstr(e, "\\\""); | |
| break; | |
| case '\f': | |
| jsonenc_putstr(e, "\\f"); | |
| break; | |
| case '\b': | |
| jsonenc_putstr(e, "\\b"); | |
| break; | |
| case '\\': | |
| jsonenc_putstr(e, "\\\\"); | |
| break; | |
| default: | |
| if ((uint8_t)ch < 0x20) { | |
| jsonenc_printf(e, "\\u%04x", (int)(uint8_t)ch); | |
| } else { | |
| /* This could be a non-ASCII byte. We rely on the string being valid | |
| * UTF-8. */ | |
| jsonenc_putbytes(e, &ch, 1); | |
| } | |
| break; | |
| } | |
| } | |
| static void jsonenc_stringbody(jsonenc* e, upb_StringView str) { | |
| const char* ptr = str.data; | |
| const char* end = UPB_PTRADD(ptr, str.size); | |
| while (ptr < end) { | |
| jsonenc_put_escaped_char(e, *ptr); | |
| ptr++; | |
| } | |
| } | |
| static void jsonenc_string(jsonenc* e, upb_StringView str) { | |
| jsonenc_putstr(e, "\""); | |
| jsonenc_stringbody(e, str); | |
| jsonenc_putstr(e, "\""); | |
| } | |
| static bool upb_JsonEncode_HandleSpecialDoubles(jsonenc* e, double val) { | |
| if (val == INFINITY) { | |
| jsonenc_putstr(e, "\"Infinity\""); | |
| } else if (val == -INFINITY) { | |
| jsonenc_putstr(e, "\"-Infinity\""); | |
| } else if (val != val) { | |
| jsonenc_putstr(e, "\"NaN\""); | |
| } else { | |
| return false; | |
| } | |
| return true; | |
| } | |
| static void upb_JsonEncode_Double(jsonenc* e, double val) { | |
| if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; | |
| char buf[32]; | |
| _upb_EncodeRoundTripDouble(val, buf, sizeof(buf)); | |
| jsonenc_putstr(e, buf); | |
| } | |
| static void upb_JsonEncode_Float(jsonenc* e, float val) { | |
| if (upb_JsonEncode_HandleSpecialDoubles(e, val)) return; | |
| char buf[32]; | |
| _upb_EncodeRoundTripFloat(val, buf, sizeof(buf)); | |
| jsonenc_putstr(e, buf); | |
| } | |
| static void jsonenc_wrapper(jsonenc* e, const upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(m, 1); | |
| upb_MessageValue val = upb_Message_GetFieldByDef(msg, val_f); | |
| jsonenc_scalar(e, val, val_f); | |
| } | |
| static const upb_MessageDef* jsonenc_getanymsg(jsonenc* e, | |
| upb_StringView type_url) { | |
| /* Find last '/', if any. */ | |
| const char* end = type_url.data + type_url.size; | |
| const char* ptr = end; | |
| const upb_MessageDef* ret; | |
| if (!e->ext_pool) { | |
| jsonenc_err(e, "Tried to encode Any, but no symtab was provided"); | |
| } | |
| if (type_url.size == 0) goto badurl; | |
| while (true) { | |
| if (--ptr == type_url.data) { | |
| /* Type URL must contain at least one '/', with host before. */ | |
| goto badurl; | |
| } | |
| if (*ptr == '/') { | |
| ptr++; | |
| break; | |
| } | |
| } | |
| ret = upb_DefPool_FindMessageByNameWithSize(e->ext_pool, ptr, end - ptr); | |
| if (!ret) { | |
| jsonenc_errf(e, "Couldn't find Any type: %.*s", (int)(end - ptr), ptr); | |
| } | |
| return ret; | |
| badurl: | |
| jsonenc_errf(e, "Bad type URL: " UPB_STRINGVIEW_FORMAT, | |
| UPB_STRINGVIEW_ARGS(type_url)); | |
| } | |
| static void jsonenc_any(jsonenc* e, const upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| const upb_FieldDef* type_url_f = upb_MessageDef_FindFieldByNumber(m, 1); | |
| const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(m, 2); | |
| upb_StringView type_url = upb_Message_GetFieldByDef(msg, type_url_f).str_val; | |
| upb_StringView value = upb_Message_GetFieldByDef(msg, value_f).str_val; | |
| const upb_MessageDef* any_m = jsonenc_getanymsg(e, type_url); | |
| const upb_MiniTable* any_layout = upb_MessageDef_MiniTable(any_m); | |
| upb_Arena* arena = jsonenc_arena(e); | |
| upb_Message* any = upb_Message_New(any_layout, arena); | |
| if (!any) { | |
| jsonenc_err(e, "Out of memory"); | |
| return; | |
| } | |
| if (upb_Decode(value.data, value.size, any, any_layout, NULL, 0, arena) != | |
| kUpb_DecodeStatus_Ok) { | |
| jsonenc_err(e, "Error decoding message in Any"); | |
| } | |
| jsonenc_putstr(e, "{\"@type\":"); | |
| jsonenc_string(e, type_url); | |
| if (upb_MessageDef_WellKnownType(any_m) == kUpb_WellKnown_Unspecified) { | |
| /* Regular messages: {"@type": "...","foo": 1, "bar": 2} */ | |
| jsonenc_msgfields(e, any, any_m, false); | |
| } else { | |
| /* Well-known type: {"@type": "...","value": <well-known encoding>} */ | |
| jsonenc_putstr(e, ",\"value\":"); | |
| jsonenc_msgfield(e, any, any_m); | |
| } | |
| jsonenc_putstr(e, "}"); | |
| } | |
| static void jsonenc_putsep(jsonenc* e, const char* str, bool* first) { | |
| if (*first) { | |
| *first = false; | |
| } else { | |
| jsonenc_putstr(e, str); | |
| } | |
| } | |
| static void jsonenc_fieldpath(jsonenc* e, upb_StringView path) { | |
| const char* ptr = path.data; | |
| const char* end = ptr + path.size; | |
| while (ptr < end) { | |
| char ch = *ptr; | |
| if (ch >= 'A' && ch <= 'Z') { | |
| jsonenc_err(e, | |
| "Field mask path containing an uppercase letter cannot be " | |
| "successfully round tripped through JSON format. See " | |
| "https://github.com/protocolbuffers/protobuf/issues/25786"); | |
| } else if (ch == '_') { | |
| if (ptr == end - 1 || *(ptr + 1) < 'a' || *(ptr + 1) > 'z') { | |
| jsonenc_err(e, | |
| "Underscore in FieldMask path must be followed by a " | |
| "lowercase letter to successfully round trip through JSON " | |
| "format. See " | |
| "https://github.com/protocolbuffers/protobuf/issues/25786"); | |
| } | |
| ch = *++ptr - 32; | |
| } | |
| jsonenc_put_escaped_char(e, ch); | |
| ptr++; | |
| } | |
| } | |
| static void jsonenc_fieldmask(jsonenc* e, const upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| const upb_FieldDef* paths_f = upb_MessageDef_FindFieldByNumber(m, 1); | |
| const upb_Array* paths = upb_Message_GetFieldByDef(msg, paths_f).array_val; | |
| bool first = true; | |
| size_t i, n = 0; | |
| if (paths) n = upb_Array_Size(paths); | |
| jsonenc_putstr(e, "\""); | |
| for (i = 0; i < n; i++) { | |
| jsonenc_putsep(e, ",", &first); | |
| jsonenc_fieldpath(e, upb_Array_Get(paths, i).str_val); | |
| } | |
| jsonenc_putstr(e, "\""); | |
| } | |
| static void jsonenc_struct(jsonenc* e, const upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| jsonenc_putstr(e, "{"); | |
| const upb_FieldDef* fields_f = upb_MessageDef_FindFieldByNumber(m, 1); | |
| const upb_Map* fields = upb_Message_GetFieldByDef(msg, fields_f).map_val; | |
| if (fields) { | |
| const upb_MessageDef* entry_m = upb_FieldDef_MessageSubDef(fields_f); | |
| const upb_FieldDef* value_f = upb_MessageDef_FindFieldByNumber(entry_m, 2); | |
| size_t iter = kUpb_Map_Begin; | |
| bool first = true; | |
| upb_MessageValue key, val; | |
| while (upb_Map_Next(fields, &key, &val, &iter)) { | |
| jsonenc_putsep(e, ",", &first); | |
| jsonenc_string(e, key.str_val); | |
| jsonenc_putstr(e, ":"); | |
| jsonenc_value(e, val.msg_val, upb_FieldDef_MessageSubDef(value_f)); | |
| } | |
| } | |
| jsonenc_putstr(e, "}"); | |
| } | |
| static void jsonenc_listvalue(jsonenc* e, const upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| const upb_FieldDef* values_f = upb_MessageDef_FindFieldByNumber(m, 1); | |
| const upb_MessageDef* values_m = upb_FieldDef_MessageSubDef(values_f); | |
| const upb_Array* values = upb_Message_GetFieldByDef(msg, values_f).array_val; | |
| size_t i; | |
| bool first = true; | |
| jsonenc_putstr(e, "["); | |
| if (values) { | |
| const size_t size = upb_Array_Size(values); | |
| for (i = 0; i < size; i++) { | |
| upb_MessageValue elem = upb_Array_Get(values, i); | |
| jsonenc_putsep(e, ",", &first); | |
| jsonenc_value(e, elem.msg_val, values_m); | |
| } | |
| } | |
| jsonenc_putstr(e, "]"); | |
| } | |
| static void jsonenc_value(jsonenc* e, const upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| /* TODO: do we want a reflection method to get oneof case? */ | |
| size_t iter = kUpb_Message_Begin; | |
| const upb_FieldDef* f; | |
| upb_MessageValue val; | |
| if (!upb_Message_Next(msg, m, NULL, &f, &val, &iter)) { | |
| jsonenc_err(e, "No value set in Value proto"); | |
| } | |
| switch (upb_FieldDef_Number(f)) { | |
| case 1: | |
| jsonenc_putstr(e, "null"); | |
| break; | |
| case 2: | |
| if (upb_JsonEncode_HandleSpecialDoubles(e, val.double_val)) { | |
| jsonenc_err( | |
| e, | |
| "google.protobuf.Value cannot encode double values for " | |
| "infinity or nan, because they would be parsed as a string"); | |
| } | |
| upb_JsonEncode_Double(e, val.double_val); | |
| break; | |
| case 3: | |
| jsonenc_string(e, val.str_val); | |
| break; | |
| case 4: | |
| jsonenc_putstr(e, val.bool_val ? "true" : "false"); | |
| break; | |
| case 5: | |
| jsonenc_struct(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); | |
| break; | |
| case 6: | |
| jsonenc_listvalue(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); | |
| break; | |
| } | |
| } | |
| static void jsonenc_msgfield(jsonenc* e, const upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| switch (upb_MessageDef_WellKnownType(m)) { | |
| case kUpb_WellKnown_Unspecified: | |
| jsonenc_msg(e, msg, m); | |
| break; | |
| case kUpb_WellKnown_Any: | |
| jsonenc_any(e, msg, m); | |
| break; | |
| case kUpb_WellKnown_FieldMask: | |
| jsonenc_fieldmask(e, msg, m); | |
| break; | |
| case kUpb_WellKnown_Duration: | |
| jsonenc_duration(e, msg, m); | |
| break; | |
| case kUpb_WellKnown_Timestamp: | |
| jsonenc_timestamp(e, msg, m); | |
| break; | |
| case kUpb_WellKnown_DoubleValue: | |
| case kUpb_WellKnown_FloatValue: | |
| case kUpb_WellKnown_Int64Value: | |
| case kUpb_WellKnown_UInt64Value: | |
| case kUpb_WellKnown_Int32Value: | |
| case kUpb_WellKnown_UInt32Value: | |
| case kUpb_WellKnown_StringValue: | |
| case kUpb_WellKnown_BytesValue: | |
| case kUpb_WellKnown_BoolValue: | |
| jsonenc_wrapper(e, msg, m); | |
| break; | |
| case kUpb_WellKnown_Value: | |
| jsonenc_value(e, msg, m); | |
| break; | |
| case kUpb_WellKnown_ListValue: | |
| jsonenc_listvalue(e, msg, m); | |
| break; | |
| case kUpb_WellKnown_Struct: | |
| jsonenc_struct(e, msg, m); | |
| break; | |
| } | |
| } | |
| static void jsonenc_scalar(jsonenc* e, upb_MessageValue val, | |
| const upb_FieldDef* f) { | |
| switch (upb_FieldDef_CType(f)) { | |
| case kUpb_CType_Bool: | |
| jsonenc_putstr(e, val.bool_val ? "true" : "false"); | |
| break; | |
| case kUpb_CType_Float: | |
| upb_JsonEncode_Float(e, val.float_val); | |
| break; | |
| case kUpb_CType_Double: | |
| upb_JsonEncode_Double(e, val.double_val); | |
| break; | |
| case kUpb_CType_Int32: | |
| jsonenc_printf(e, "%" PRId32, val.int32_val); | |
| break; | |
| case kUpb_CType_UInt32: | |
| jsonenc_printf(e, "%" PRIu32, val.uint32_val); | |
| break; | |
| case kUpb_CType_Int64: | |
| jsonenc_printf(e, "\"%" PRId64 "\"", val.int64_val); | |
| break; | |
| case kUpb_CType_UInt64: | |
| jsonenc_printf(e, "\"%" PRIu64 "\"", val.uint64_val); | |
| break; | |
| case kUpb_CType_String: | |
| jsonenc_string(e, val.str_val); | |
| break; | |
| case kUpb_CType_Bytes: | |
| jsonenc_bytes(e, val.str_val); | |
| break; | |
| case kUpb_CType_Enum: | |
| jsonenc_enum(val.int32_val, f, e); | |
| break; | |
| case kUpb_CType_Message: | |
| jsonenc_msgfield(e, val.msg_val, upb_FieldDef_MessageSubDef(f)); | |
| break; | |
| } | |
| } | |
| static void jsonenc_mapkey(jsonenc* e, upb_MessageValue val, | |
| const upb_FieldDef* f) { | |
| jsonenc_putstr(e, "\""); | |
| switch (upb_FieldDef_CType(f)) { | |
| case kUpb_CType_Bool: | |
| jsonenc_putstr(e, val.bool_val ? "true" : "false"); | |
| break; | |
| case kUpb_CType_Int32: | |
| jsonenc_printf(e, "%" PRId32, val.int32_val); | |
| break; | |
| case kUpb_CType_UInt32: | |
| jsonenc_printf(e, "%" PRIu32, val.uint32_val); | |
| break; | |
| case kUpb_CType_Int64: | |
| jsonenc_printf(e, "%" PRId64, val.int64_val); | |
| break; | |
| case kUpb_CType_UInt64: | |
| jsonenc_printf(e, "%" PRIu64, val.uint64_val); | |
| break; | |
| case kUpb_CType_String: | |
| jsonenc_stringbody(e, val.str_val); | |
| break; | |
| default: | |
| UPB_UNREACHABLE(); | |
| } | |
| jsonenc_putstr(e, "\":"); | |
| } | |
| static void jsonenc_array(jsonenc* e, const upb_Array* arr, | |
| const upb_FieldDef* f) { | |
| size_t i; | |
| size_t size = arr ? upb_Array_Size(arr) : 0; | |
| bool first = true; | |
| jsonenc_putstr(e, "["); | |
| for (i = 0; i < size; i++) { | |
| jsonenc_putsep(e, ",", &first); | |
| jsonenc_scalar(e, upb_Array_Get(arr, i), f); | |
| } | |
| jsonenc_putstr(e, "]"); | |
| } | |
| static void jsonenc_map(jsonenc* e, const upb_Map* map, const upb_FieldDef* f) { | |
| jsonenc_putstr(e, "{"); | |
| const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); | |
| const upb_FieldDef* key_f = upb_MessageDef_FindFieldByNumber(entry, 1); | |
| const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(entry, 2); | |
| if (map) { | |
| size_t iter = kUpb_Map_Begin; | |
| bool first = true; | |
| upb_MessageValue key, val; | |
| while (upb_Map_Next(map, &key, &val, &iter)) { | |
| jsonenc_putsep(e, ",", &first); | |
| jsonenc_mapkey(e, key, key_f); | |
| jsonenc_scalar(e, val, val_f); | |
| } | |
| } | |
| jsonenc_putstr(e, "}"); | |
| } | |
| static void jsonenc_fieldval(jsonenc* e, const upb_FieldDef* f, | |
| upb_MessageValue val, bool* first) { | |
| const char* name; | |
| jsonenc_putsep(e, ",", first); | |
| if (upb_FieldDef_IsExtension(f)) { | |
| // TODO: For MessageSet, I would have expected this to print the message | |
| // name here, but Python doesn't appear to do this. We should do more | |
| // research here about what various implementations do. | |
| jsonenc_printf(e, "\"[%s]\":", upb_FieldDef_FullName(f)); | |
| } else { | |
| if (e->options & upb_JsonEncode_UseProtoNames) { | |
| name = upb_FieldDef_Name(f); | |
| } else { | |
| name = upb_FieldDef_JsonName(f); | |
| } | |
| jsonenc_printf(e, "\"%s\":", name); | |
| } | |
| if (upb_FieldDef_IsMap(f)) { | |
| jsonenc_map(e, val.map_val, f); | |
| } else if (upb_FieldDef_IsRepeated(f)) { | |
| jsonenc_array(e, val.array_val, f); | |
| } else { | |
| jsonenc_scalar(e, val, f); | |
| } | |
| } | |
| static void jsonenc_msgfields(jsonenc* e, const upb_Message* msg, | |
| const upb_MessageDef* m, bool first) { | |
| upb_MessageValue val; | |
| const upb_FieldDef* f; | |
| if (e->options & upb_JsonEncode_EmitDefaults) { | |
| /* Iterate over all fields. */ | |
| int i = 0; | |
| int n = upb_MessageDef_FieldCount(m); | |
| for (i = 0; i < n; i++) { | |
| f = upb_MessageDef_Field(m, i); | |
| if (!upb_FieldDef_HasPresence(f) || upb_Message_HasFieldByDef(msg, f)) { | |
| jsonenc_fieldval(e, f, upb_Message_GetFieldByDef(msg, f), &first); | |
| } | |
| } | |
| } else { | |
| /* Iterate over non-empty fields. */ | |
| size_t iter = kUpb_Message_Begin; | |
| while (upb_Message_Next(msg, m, e->ext_pool, &f, &val, &iter)) { | |
| jsonenc_fieldval(e, f, val, &first); | |
| } | |
| } | |
| } | |
| static void jsonenc_msg(jsonenc* e, const upb_Message* msg, | |
| const upb_MessageDef* m) { | |
| jsonenc_putstr(e, "{"); | |
| jsonenc_msgfields(e, msg, m, true); | |
| jsonenc_putstr(e, "}"); | |
| } | |
| static size_t jsonenc_nullz(jsonenc* e, size_t size) { | |
| size_t ret = e->ptr - e->buf + e->overflow; | |
| if (size > 0) { | |
| if (e->ptr == e->end) e->ptr--; | |
| *e->ptr = '\0'; | |
| } | |
| return ret; | |
| } | |
| static size_t upb_JsonEncoder_Encode(jsonenc* const e, | |
| const upb_Message* const msg, | |
| const upb_MessageDef* const m, | |
| const size_t size) { | |
| if (UPB_SETJMP(e->err) != 0) return -1; | |
| jsonenc_msgfield(e, msg, m); | |
| if (e->arena) upb_Arena_Free(e->arena); | |
| return jsonenc_nullz(e, size); | |
| } | |
| size_t upb_JsonEncode(const upb_Message* msg, const upb_MessageDef* m, | |
| const upb_DefPool* ext_pool, int options, char* buf, | |
| size_t size, upb_Status* status) { | |
| jsonenc e; | |
| e.buf = buf; | |
| e.ptr = buf; | |
| e.end = UPB_PTRADD(buf, size); | |
| e.overflow = 0; | |
| e.options = options; | |
| e.ext_pool = ext_pool; | |
| e.status = status; | |
| e.arena = NULL; | |
| return upb_JsonEncoder_Encode(&e, msg, m, size); | |
| } | |
| // Must be last. | |
| const char* upb_BufToUint64(const char* ptr, const char* end, uint64_t* val) { | |
| uint64_t u64 = 0; | |
| while (ptr < end) { | |
| unsigned ch = *ptr - '0'; | |
| if (ch >= 10) break; | |
| if (u64 > UINT64_MAX / 10 || u64 * 10 > UINT64_MAX - ch) { | |
| return NULL; // integer overflow | |
| } | |
| u64 *= 10; | |
| u64 += ch; | |
| ptr++; | |
| } | |
| *val = u64; | |
| return ptr; | |
| } | |
| const char* upb_BufToInt64(const char* ptr, const char* end, int64_t* val, | |
| bool* is_neg) { | |
| bool neg = false; | |
| uint64_t u64; | |
| if (ptr != end && *ptr == '-') { | |
| ptr++; | |
| neg = true; | |
| } | |
| ptr = upb_BufToUint64(ptr, end, &u64); | |
| if (!ptr || u64 > (uint64_t)INT64_MAX + neg) { | |
| return NULL; // integer overflow | |
| } | |
| *val = neg ? -u64 : u64; | |
| if (is_neg) *is_neg = neg; | |
| return ptr; | |
| } | |
| #include <float.h> | |
| #include <math.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| // Must be last. | |
| /* Miscellaneous utilities ****************************************************/ | |
| static void upb_FixLocale(char* p) { | |
| /* printf() is dependent on locales; sadly there is no easy and portable way | |
| * to avoid this. This little post-processing step will translate 1,2 -> 1.2 | |
| * since JSON needs the latter. Arguably a hack, but it is simple and the | |
| * alternatives are far more complicated, platform-dependent, and/or larger | |
| * in code size. */ | |
| for (; *p; p++) { | |
| if (*p == ',') *p = '.'; | |
| } | |
| } | |
| void _upb_EncodeRoundTripDouble(double val, char* buf, size_t size) { | |
| assert(size >= kUpb_RoundTripBufferSize); | |
| if (isnan(val)) { | |
| snprintf(buf, size, "%s", "nan"); | |
| return; | |
| } | |
| snprintf(buf, size, "%.*g", DBL_DIG, val); | |
| if (strtod(buf, NULL) != val) { | |
| snprintf(buf, size, "%.*g", DBL_DIG + 2, val); | |
| assert(strtod(buf, NULL) == val); | |
| } | |
| upb_FixLocale(buf); | |
| } | |
| void _upb_EncodeRoundTripFloat(float val, char* buf, size_t size) { | |
| assert(size >= kUpb_RoundTripBufferSize); | |
| if (isnan(val)) { | |
| snprintf(buf, size, "%s", "nan"); | |
| return; | |
| } | |
| snprintf(buf, size, "%.*g", FLT_DIG, val); | |
| if (strtof(buf, NULL) != val) { | |
| snprintf(buf, size, "%.*g", FLT_DIG + 3, val); | |
| assert(strtof(buf, NULL) == val); | |
| } | |
| upb_FixLocale(buf); | |
| } | |
| // Must be last. | |
| int upb_Unicode_ToUTF8(uint32_t cp, char* out) { | |
| if (cp <= 0x7f) { | |
| out[0] = cp; | |
| return 1; | |
| } | |
| if (cp <= 0x07ff) { | |
| out[0] = (cp >> 6) | 0xc0; | |
| out[1] = (cp & 0x3f) | 0x80; | |
| return 2; | |
| } | |
| if (cp <= 0xffff) { | |
| out[0] = (cp >> 12) | 0xe0; | |
| out[1] = ((cp >> 6) & 0x3f) | 0x80; | |
| out[2] = (cp & 0x3f) | 0x80; | |
| return 3; | |
| } | |
| if (cp <= 0x10ffff) { | |
| out[0] = (cp >> 18) | 0xf0; | |
| out[1] = ((cp >> 12) & 0x3f) | 0x80; | |
| out[2] = ((cp >> 6) & 0x3f) | 0x80; | |
| out[3] = (cp & 0x3f) | 0x80; | |
| return 4; | |
| } | |
| return 0; | |
| } | |
| #include <stdint.h> | |
| #include <stdlib.h> | |
| // Must be last. | |
| static void* upb_global_allocfunc(upb_alloc* alloc, void* ptr, size_t oldsize, | |
| size_t size, size_t* actual_size) { | |
| UPB_UNUSED(alloc); | |
| UPB_UNUSED(oldsize); | |
| UPB_UNUSED(actual_size); | |
| if (size == 0) { | |
| free(ptr); | |
| return NULL; | |
| } else { | |
| return realloc(ptr, size); | |
| } | |
| } | |
| #ifdef UPB_ALLOCATION_COUNT | |
| #if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && \ | |
| !defined(__STDC_NO_THREADS__)) || \ | |
| UPB_HAS_EXTENSION(c_thread_local) | |
| #define UPB_THREAD_LOCAL _Thread_local | |
| #elif defined(_MSC_VER) | |
| #define UPB_THREAD_LOCAL __declspec(thread) | |
| #elif defined(__GNUC__) || defined(__clang__) | |
| #define UPB_THREAD_LOCAL __thread | |
| #else | |
| #define UPB_THREAD_LOCAL | |
| #endif | |
| UPB_THREAD_LOCAL size_t upb_arena_alloc_count = 0; | |
| UPB_THREAD_LOCAL size_t upb_arena_alloc_fail_on = SIZE_MAX; | |
| #undef UPB_THREAD_LOCAL | |
| #endif | |
| UPB_NODISCARD bool upb_AllocationCount_IsAvailable(void) { | |
| #ifdef UPB_ALLOCATION_COUNT | |
| return true; | |
| #else | |
| return false; | |
| #endif | |
| } | |
| UPB_NODISCARD size_t upb_AllocationCount_Get(void) { | |
| #ifdef UPB_ALLOCATION_COUNT | |
| return upb_arena_alloc_count; | |
| #else | |
| return 0; | |
| #endif | |
| } | |
| void upb_AllocationCount_Reset(void) { | |
| #ifdef UPB_ALLOCATION_COUNT | |
| upb_arena_alloc_count = 0; | |
| upb_arena_alloc_fail_on = SIZE_MAX; | |
| #endif | |
| } | |
| void upb_AllocationCount_FailOn(size_t n) { | |
| #ifdef UPB_ALLOCATION_COUNT | |
| upb_arena_alloc_fail_on = n; | |
| #endif | |
| } | |
| upb_alloc upb_alloc_global = {&upb_global_allocfunc, NULL}; | |
| #include <limits.h> | |
| #include <string.h> | |
| #ifdef UPB_TRACING_ENABLED | |
| #include <stdatomic.h> | |
| #endif | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| static UPB_ATOMIC(size_t) g_max_block_size = UPB_DEFAULT_MAX_BLOCK_SIZE; | |
| void upb_Arena_SetMaxBlockSize(size_t max) { | |
| UPB_ASSERT(max <= UINT32_MAX); | |
| upb_Atomic_Store(&g_max_block_size, max, memory_order_relaxed); | |
| } | |
| typedef struct upb_MemBlock { | |
| struct upb_MemBlock* next; | |
| // Size of the actual allocation. | |
| // Size of 0 means this is a upb_ArenaRef. | |
| size_t size; | |
| // Data follows. | |
| } upb_MemBlock; | |
| // A special block type that indicates a reference to another arena. | |
| // When this arena is freed, a ref is released on the referenced arena. | |
| // size must be 0. | |
| typedef struct upb_ArenaRef { | |
| upb_MemBlock prefix; // size is always zero | |
| const upb_Arena* arena; | |
| #ifndef NDEBUG | |
| const struct upb_ArenaRef* next_ref; | |
| #endif | |
| } upb_ArenaRef; | |
| typedef struct upb_ArenaInternal { | |
| // upb_alloc* together with a low bit which signals if there is an initial | |
| // block. | |
| uintptr_t block_alloc; | |
| // Linked list of blocks to free/cleanup. | |
| upb_MemBlock* blocks; | |
| #ifndef NDEBUG | |
| // Stack of pointers to other arenas that this arena owns. | |
| // Used for debug-only ref cycle checks. | |
| UPB_ATOMIC(const upb_ArenaRef*) refs; | |
| #endif | |
| // Size of the last block we allocated in the normal exponential scheme. | |
| uint32_t last_block_size; | |
| // A hint that grows whenever we perform a "one-off" allocation into a a | |
| // dedicated block. This helps us determine if these outlier blocks are | |
| // actually common enough that we should switch back to the normal exponential | |
| // scheme at the larger size. | |
| uint32_t size_hint; | |
| // All non atomic members used during allocation must be above this point, and | |
| // are used by _SwapIn/_SwapOut | |
| // Total space allocated in blocks, atomic only for SpaceAllocated | |
| UPB_ATOMIC(uintptr_t) space_allocated; | |
| // When multiple arenas are fused together, each arena points to a parent | |
| // arena (root points to itself). The root tracks how many live arenas | |
| // reference it. | |
| // The low bit is tagged: | |
| // 0: pointer to parent | |
| // 1: count, left shifted by one | |
| UPB_ATOMIC(uintptr_t) parent_or_count; | |
| // All nodes that are fused together are in a singly-linked list. | |
| // == NULL at end of list. | |
| UPB_ATOMIC(struct upb_ArenaInternal*) next; | |
| // - If the low bit is set, is a pointer to the tail of the list (populated | |
| // for roots, set to self for roots with no fused arenas). This is best | |
| // effort, and it may not always reflect the true tail, but it will always | |
| // be a valid node in the list. This is useful for finding the list tail | |
| // without having to walk the entire list. | |
| // - If the low bit is not set, is a pointer to the previous node in the list, | |
| // such that a->previous_or_tail->next == a. | |
| UPB_ATOMIC(uintptr_t) previous_or_tail; | |
| // We use a different UPB_XSAN_MEMBER than the one in upb_Arena because the | |
| // two are distinct synchronization domains. The upb_Arena.ptr member is | |
| // not published in the allocation path, so it is not synchronized with | |
| // respect to operations performed in this file such as Fuse, Free, | |
| // SpaceAllocated, etc. This means that it is not safe to read or write | |
| // the upb_Arena.ptr member in those functions. | |
| UPB_XSAN_MEMBER | |
| } upb_ArenaInternal; | |
| // All public + private state for an arena. | |
| typedef struct { | |
| upb_Arena head; | |
| upb_ArenaInternal body; | |
| } upb_ArenaState; | |
| typedef struct { | |
| upb_ArenaInternal* root; | |
| uintptr_t tagged_count; | |
| } upb_ArenaRoot; | |
| static const size_t kUpb_MemblockReserve = | |
| UPB_ALIGN_MALLOC(sizeof(upb_MemBlock)); | |
| static const size_t kUpb_ArenaStateReserve = | |
| UPB_ALIGN_MALLOC(sizeof(upb_ArenaState)); | |
| static const size_t kUpb_ArenaRefReserve = | |
| UPB_ALIGN_MALLOC(sizeof(upb_ArenaRef)); | |
| // Extracts the (upb_ArenaInternal*) from a (upb_Arena*) | |
| static upb_ArenaInternal* upb_Arena_Internal(const upb_Arena* a) { | |
| return &((upb_ArenaState*)a)->body; | |
| } | |
| static bool _upb_Arena_IsTaggedRefcount(uintptr_t parent_or_count) { | |
| return (parent_or_count & 1) == 1; | |
| } | |
| static bool _upb_Arena_IsTaggedPointer(uintptr_t parent_or_count) { | |
| return (parent_or_count & 1) == 0; | |
| } | |
| static uintptr_t _upb_Arena_RefCountFromTagged(uintptr_t parent_or_count) { | |
| UPB_ASSERT(_upb_Arena_IsTaggedRefcount(parent_or_count)); | |
| return parent_or_count >> 1; | |
| } | |
| static uintptr_t _upb_Arena_TaggedFromRefcount(uintptr_t refcount) { | |
| uintptr_t parent_or_count = (refcount << 1) | 1; | |
| UPB_ASSERT(_upb_Arena_IsTaggedRefcount(parent_or_count)); | |
| return parent_or_count; | |
| } | |
| static upb_ArenaInternal* _upb_Arena_PointerFromTagged( | |
| uintptr_t parent_or_count) { | |
| UPB_ASSERT(_upb_Arena_IsTaggedPointer(parent_or_count)); | |
| return (upb_ArenaInternal*)parent_or_count; | |
| } | |
| static uintptr_t _upb_Arena_TaggedFromPointer(upb_ArenaInternal* ai) { | |
| uintptr_t parent_or_count = (uintptr_t)ai; | |
| UPB_ASSERT(_upb_Arena_IsTaggedPointer(parent_or_count)); | |
| return parent_or_count; | |
| } | |
| static bool _upb_Arena_IsTaggedTail(uintptr_t previous_or_tail) { | |
| return (previous_or_tail & 1) == 1; | |
| } | |
| static bool _upb_Arena_IsTaggedPrevious(uintptr_t previous_or_tail) { | |
| return (previous_or_tail & 1) == 0; | |
| } | |
| static upb_ArenaInternal* _upb_Arena_TailFromTagged( | |
| uintptr_t previous_or_tail) { | |
| UPB_ASSERT(_upb_Arena_IsTaggedTail(previous_or_tail)); | |
| return (upb_ArenaInternal*)(previous_or_tail ^ 1); | |
| } | |
| static uintptr_t _upb_Arena_TaggedFromTail(upb_ArenaInternal* tail) { | |
| uintptr_t previous_or_tail = (uintptr_t)tail | 1; | |
| UPB_ASSERT(_upb_Arena_IsTaggedTail(previous_or_tail)); | |
| return previous_or_tail; | |
| } | |
| static upb_ArenaInternal* _upb_Arena_PreviousFromTagged( | |
| uintptr_t previous_or_tail) { | |
| UPB_ASSERT(_upb_Arena_IsTaggedPrevious(previous_or_tail)); | |
| return (upb_ArenaInternal*)previous_or_tail; | |
| } | |
| static uintptr_t _upb_Arena_TaggedFromPrevious(upb_ArenaInternal* ai) { | |
| uintptr_t previous = (uintptr_t)ai; | |
| UPB_ASSERT(_upb_Arena_IsTaggedPrevious(previous)); | |
| return previous; | |
| } | |
| static upb_alloc* _upb_ArenaInternal_BlockAlloc(upb_ArenaInternal* ai) { | |
| return (upb_alloc*)(ai->block_alloc & ~0x1); | |
| } | |
| static uintptr_t _upb_Arena_MakeBlockAlloc(upb_alloc* alloc, bool has_initial) { | |
| uintptr_t alloc_uint = (uintptr_t)alloc; | |
| UPB_ASSERT((alloc_uint & 1) == 0); | |
| return alloc_uint | (has_initial ? 1 : 0); | |
| } | |
| static bool _upb_ArenaInternal_HasInitialBlock(upb_ArenaInternal* ai) { | |
| return ai->block_alloc & 0x1; | |
| } | |
| #ifdef UPB_TRACING_ENABLED | |
| static void (*_init_arena_trace_handler)(const upb_Arena*, size_t size) = NULL; | |
| static void (*_fuse_arena_trace_handler)(const upb_Arena*, | |
| const upb_Arena*) = NULL; | |
| static void (*_free_arena_trace_handler)(const upb_Arena*) = NULL; | |
| void upb_Arena_SetTraceHandler( | |
| void (*initArenaTraceHandler)(const upb_Arena*, size_t size), | |
| void (*fuseArenaTraceHandler)(const upb_Arena*, const upb_Arena*), | |
| void (*freeArenaTraceHandler)(const upb_Arena*)) { | |
| _init_arena_trace_handler = initArenaTraceHandler; | |
| _fuse_arena_trace_handler = fuseArenaTraceHandler; | |
| _free_arena_trace_handler = freeArenaTraceHandler; | |
| } | |
| void upb_Arena_LogInit(const upb_Arena* arena, size_t size) { | |
| if (_init_arena_trace_handler) { | |
| _init_arena_trace_handler(arena, size); | |
| } | |
| } | |
| void upb_Arena_LogFuse(const upb_Arena* arena1, const upb_Arena* arena2) { | |
| if (_fuse_arena_trace_handler) { | |
| _fuse_arena_trace_handler(arena1, arena2); | |
| } | |
| } | |
| void upb_Arena_LogFree(const upb_Arena* arena) { | |
| if (_free_arena_trace_handler) { | |
| _free_arena_trace_handler(arena); | |
| } | |
| } | |
| #endif // UPB_TRACING_ENABLED | |
| // If the param a is already the root, provides no memory order of refcount. | |
| // If it has a parent, then acquire memory order is provided for both the root | |
| // and the refcount. Thread safe. | |
| static upb_ArenaRoot _upb_Arena_FindRoot(upb_ArenaInternal* ai) { | |
| uintptr_t poc = upb_Atomic_Load(&ai->parent_or_count, memory_order_relaxed); | |
| if (_upb_Arena_IsTaggedRefcount(poc)) { | |
| // Fast, relaxed path - arenas that have never been fused to a parent only | |
| // need relaxed memory order, since they're returning themselves and the | |
| // refcount. | |
| return (upb_ArenaRoot){.root = ai, .tagged_count = poc}; | |
| } | |
| // Slow path needs acquire order; reloading is cheaper than a fence on ARM | |
| // (LDA vs DMB ISH). Even though this is a reread, we know it must be a tagged | |
| // pointer because if this Arena isn't a root, it can't ever become one. | |
| poc = upb_Atomic_Load(&ai->parent_or_count, memory_order_acquire); | |
| do { | |
| upb_ArenaInternal* next = _upb_Arena_PointerFromTagged(poc); | |
| UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(next)); | |
| UPB_ASSERT(ai != next); | |
| poc = upb_Atomic_Load(&next->parent_or_count, memory_order_acquire); | |
| if (_upb_Arena_IsTaggedPointer(poc)) { | |
| // To keep complexity down, we lazily collapse levels of the tree. This | |
| // keeps it flat in the final case, but doesn't cost much incrementally. | |
| // | |
| // Path splitting keeps time complexity down, see: | |
| // https://en.wikipedia.org/wiki/Disjoint-set_data_structure | |
| UPB_ASSERT(ai != _upb_Arena_PointerFromTagged(poc)); | |
| upb_Atomic_Store(&ai->parent_or_count, poc, memory_order_release); | |
| } | |
| ai = next; | |
| } while (_upb_Arena_IsTaggedPointer(poc)); | |
| return (upb_ArenaRoot){.root = ai, .tagged_count = poc}; | |
| } | |
| uintptr_t upb_Arena_SpaceAllocated(const upb_Arena* arena, | |
| size_t* fused_count) { | |
| upb_ArenaInternal* ai = upb_Arena_Internal(arena); | |
| uintptr_t memsize = 0; | |
| size_t local_fused_count = 0; | |
| // Our root would get updated by any racing fuses before our target arena | |
| // became reachable from the root via the linked list; in order to preserve | |
| // monotonic output (any arena counted by a previous invocation is counted by | |
| // this one), we instead iterate forwards and backwards so that we only see | |
| // the results of completed fuses. | |
| uintptr_t previous_or_tail = | |
| upb_Atomic_Load(&ai->previous_or_tail, memory_order_acquire); | |
| while (_upb_Arena_IsTaggedPrevious(previous_or_tail)) { | |
| upb_ArenaInternal* previous = | |
| _upb_Arena_PreviousFromTagged(previous_or_tail); | |
| UPB_ASSERT(previous != ai); | |
| UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(previous)); | |
| // Unfortunate macro behavior; prior to C11 when using nonstandard atomics | |
| // this returns a void* and can't be used with += without an intermediate | |
| // conversion to an integer. | |
| // Relaxed is safe - no subsequent reads depend this one | |
| uintptr_t allocated = | |
| upb_Atomic_Load(&previous->space_allocated, memory_order_relaxed); | |
| memsize += allocated; | |
| previous_or_tail = | |
| upb_Atomic_Load(&previous->previous_or_tail, memory_order_acquire); | |
| local_fused_count++; | |
| } | |
| while (ai != NULL) { | |
| UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(ai)); | |
| // Unfortunate macro behavior; prior to C11 when using nonstandard atomics | |
| // this returns a void* and can't be used with += without an intermediate | |
| // conversion to an integer. | |
| // Relaxed is safe - no subsequent reads depend this one | |
| uintptr_t allocated = | |
| upb_Atomic_Load(&ai->space_allocated, memory_order_relaxed); | |
| memsize += allocated; | |
| ai = upb_Atomic_Load(&ai->next, memory_order_acquire); | |
| local_fused_count++; | |
| } | |
| if (fused_count) *fused_count = local_fused_count; | |
| return memsize; | |
| } | |
| uint32_t upb_Arena_DebugRefCount(const upb_Arena* a) { | |
| uintptr_t tagged = _upb_Arena_FindRoot(upb_Arena_Internal(a)).tagged_count; | |
| return (uint32_t)_upb_Arena_RefCountFromTagged(tagged); | |
| } | |
| #if UPB_ENABLE_REF_CYCLE_CHECKS | |
| bool upb_Arena_HasRefChain(const upb_Arena* from, const upb_Arena* to) { | |
| upb_ArenaInternal* ai = upb_Arena_Internal(from); | |
| upb_ArenaInternal* current; | |
| if (upb_Arena_IsFused(from, to)) return true; | |
| // 1. Traverse backward to the start of a consistent segment. | |
| uintptr_t previous_or_tail = | |
| upb_Atomic_Load(&ai->previous_or_tail, memory_order_acquire); | |
| while (_upb_Arena_IsTaggedPrevious(previous_or_tail)) { | |
| ai = _upb_Arena_PreviousFromTagged(previous_or_tail); | |
| UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(ai)); | |
| previous_or_tail = | |
| upb_Atomic_Load(&ai->previous_or_tail, memory_order_acquire); | |
| } | |
| // 2. Traverse forward through all arenas in the fuse group. | |
| current = ai; | |
| while (current != NULL) { | |
| UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(current)); | |
| const upb_ArenaRef* ref = | |
| upb_Atomic_Load(¤t->refs, memory_order_acquire); | |
| while (ref != NULL) { | |
| if (ref->arena == to || upb_Arena_HasRefChain(ref->arena, to)) { | |
| return true; | |
| } | |
| ref = ref->next_ref; | |
| } | |
| current = upb_Atomic_Load(¤t->next, memory_order_acquire); | |
| } | |
| return false; | |
| } | |
| #endif | |
| static void* _upb_Arena_AllocBlockInternal(upb_alloc* alloc, size_t* size) { | |
| size_t sz = *size + kUpb_MemblockReserve; | |
| upb_SizedPtr alloc_result = upb_SizeReturningMalloc(alloc, sz); | |
| if (!alloc_result.p) return NULL; | |
| upb_MemBlock* block = alloc_result.p; | |
| block->size = alloc_result.n; | |
| *size = alloc_result.n - kUpb_MemblockReserve; | |
| return UPB_PTR_AT(block, kUpb_MemblockReserve, void); | |
| } | |
| void* UPB_PRIVATE(_upb_Arena_AllocBlock)(upb_Arena* a, size_t* size) { | |
| upb_ArenaInternal* ai = upb_Arena_Internal(a); | |
| #if UPB_HWASAN | |
| *size = UPB_ALIGN_UP(*size, UPB_MALLOC_ALIGN); | |
| #endif | |
| void* ret = | |
| _upb_Arena_AllocBlockInternal(_upb_ArenaInternal_BlockAlloc(ai), size); | |
| #if UPB_HWASAN | |
| if (ret) *size = UPB_ALIGN_DOWN(*size, UPB_MALLOC_ALIGN); | |
| #endif | |
| return ret; | |
| } | |
| void UPB_PRIVATE(_upb_Arena_AddBlock)(upb_Arena* a, void* block) { | |
| upb_MemBlock* b = (upb_MemBlock*)((char*)block - kUpb_MemblockReserve); | |
| upb_ArenaInternal* ai = upb_Arena_Internal(a); | |
| // Atomic add not required here, as threads won't race allocating blocks, plus | |
| // atomic fetch-add is slower than load/add/store on arm devices compiled | |
| // targeting pre-v8.1. Relaxed order is safe as nothing depends on order of | |
| // size allocated. | |
| uintptr_t old_space_allocated = | |
| upb_Atomic_Load(&ai->space_allocated, memory_order_relaxed); | |
| upb_Atomic_Store(&ai->space_allocated, old_space_allocated + b->size, | |
| memory_order_relaxed); | |
| b->next = ai->blocks; | |
| ai->blocks = b; | |
| } | |
| void UPB_PRIVATE(_upb_Arena_UseBlock)(upb_Arena* a, void* ptr, size_t size) { | |
| UPB_ASSERT(UPB_ALIGN_DOWN((uintptr_t)ptr, UPB_MALLOC_ALIGN) == | |
| (uintptr_t)ptr); | |
| #if UPB_HWASAN | |
| size = UPB_ALIGN_DOWN(size, UPB_MALLOC_ALIGN); | |
| #endif | |
| if (size <= UPB_PRIVATE(_upb_ArenaHas)(a)) return; | |
| // Harvest remaining space from the retired active block into power-of-2 | |
| // pool bins. | |
| if (a->UPB_ONLYBITS(ptr) && a->UPB_ONLYBITS(end)) { | |
| char* curr = (char*)a->UPB_ONLYBITS(ptr); | |
| char* end = (char*)a->UPB_ONLYBITS(end); | |
| if (end > curr) { | |
| UPB_PRIVATE(_upb_Arena_Harvest)(a, curr, end - curr); | |
| } | |
| } | |
| a->UPB_ONLYBITS(ptr) = ptr; | |
| a->UPB_ONLYBITS(end) = UPB_PTR_AT(ptr, size, char); | |
| UPB_PRIVATE(upb_Xsan_PoisonRegion)(ptr, size); | |
| } | |
| static bool _upb_Arena_WouldReduceFreeSpace(upb_Arena* a, size_t span, | |
| size_t block_size) { | |
| upb_ArenaInternal* ai = upb_Arena_Internal(a); | |
| size_t current_free = | |
| ai->blocks ? a->UPB_PRIVATE(end) - a->UPB_PRIVATE(ptr) : 0; | |
| size_t future_free = block_size - span; | |
| return current_free >= future_free; | |
| } | |
| size_t UPB_PRIVATE(_upb_Arena_NextBlockSize)(upb_Arena* a, size_t span, | |
| bool* one_off) { | |
| upb_ArenaInternal* ai = upb_Arena_Internal(a); | |
| bool is_one_off = false; | |
| size_t max_block_size = | |
| upb_Atomic_Load(&g_max_block_size, memory_order_relaxed); | |
| size_t block_size = UPB_MIN(ai->last_block_size * 2, max_block_size); | |
| if (span > block_size) { | |
| block_size = UPB_MIN(ai->size_hint * 2, max_block_size); | |
| if (span > block_size) { | |
| is_one_off = true; | |
| } | |
| } | |
| is_one_off = | |
| is_one_off || _upb_Arena_WouldReduceFreeSpace(a, span, block_size); | |
| if (is_one_off) { | |
| block_size = span; | |
| } | |
| if (one_off) *one_off = is_one_off; | |
| return block_size; | |
| } | |
| void UPB_PRIVATE(_upb_Arena_UpdateGrowthState)(upb_Arena* a, size_t span, | |
| size_t block_size, | |
| bool one_off) { | |
| upb_ArenaInternal* ai = upb_Arena_Internal(a); | |
| size_t max_block_size = | |
| upb_Atomic_Load(&g_max_block_size, memory_order_relaxed); | |
| if (one_off) { | |
| ai->size_hint = UPB_MIN(ai->size_hint + (span >> 1), max_block_size >> 1); | |
| } else { | |
| ai->last_block_size = UPB_MIN(block_size, UINT32_MAX); | |
| ai->size_hint = ai->last_block_size; | |
| } | |
| } | |
| // Fulfills the allocation request by allocating a new block. Returns NULL on | |
| // allocation failure. | |
| void* UPB_PRIVATE(_upb_Arena_SlowMalloc)(upb_Arena* a, size_t span) { | |
| upb_ArenaInternal* ai = upb_Arena_Internal(a); | |
| if (!_upb_ArenaInternal_BlockAlloc(ai)) return NULL; | |
| bool one_off = false; | |
| size_t block_size = UPB_PRIVATE(_upb_Arena_NextBlockSize)(a, span, &one_off); | |
| void* block = UPB_PRIVATE(_upb_Arena_AllocBlock)(a, &block_size); | |
| if (!block) return NULL; | |
| UPB_PRIVATE(_upb_Arena_AddBlock)(a, block); | |
| size_t size = span - UPB_PRIVATE(kUpb_Asan_GuardSize); | |
| // Recheck size, in case the allocator gave us a much larger block than we | |
| // requested and we want to make it the new allocating region. | |
| if (one_off && !_upb_Arena_WouldReduceFreeSpace(a, span, block_size)) { | |
| one_off = false; | |
| } | |
| UPB_PRIVATE(_upb_Arena_UpdateGrowthState)(a, span, block_size, one_off); | |
| if (one_off) { | |
| UPB_PRIVATE(upb_Xsan_PoisonRegion)(UPB_PTR_AT(block, size, void), | |
| block_size - size); | |
| return block; | |
| } else { | |
| UPB_PRIVATE(_upb_Arena_UseBlock)(a, block, block_size); | |
| UPB_ASSERT(UPB_PRIVATE(_upb_ArenaHas)(a) >= span); | |
| return _upb_Arena_Malloc_Unchecked(a, size); | |
| } | |
| } | |
| // Having a sentinel empty pool allows us to unconditionally load the bin count, | |
| // avoiding a branch to check for null on the hot path. | |
| const UPB_PRIVATE(_upb_ArenaPool) UPB_PRIVATE(_upb_Arena_EmptyPool) = {0}; | |
| static size_t _upb_Arena_PoolCapacity(size_t size) { | |
| UPB_ASSERT(size >= sizeof(UPB_PRIVATE(_upb_ArenaPool))); | |
| return (size - offsetof(UPB_PRIVATE(_upb_ArenaPool), UPB_PRIVATE(bins)[0])) / | |
| sizeof(void*); | |
| } | |
| void UPB_PRIVATE(_upb_Arena_GrowPool)(upb_Arena* a, void* ptr, size_t size) { | |
| UPB_ASSERT(a); | |
| UPB_ASSERT(ptr); | |
| UPB_PRIVATE(upb_Xsan_PoisonRegion)(ptr, size); | |
| UPB_ASSERT(size >= UPB_PRIVATE(kUpb_Arena_MinPoolBlockSize)); | |
| const size_t kMaxBins = | |
| (sizeof(size_t) * CHAR_BIT) - _UPB_ARENA_MIN_POOL_BIN_LG2; | |
| size_t new_cap = UPB_MIN(kMaxBins, _upb_Arena_PoolCapacity(size)); | |
| UPB_PRIVATE(_upb_ArenaPool)* new_pool = | |
| (UPB_PRIVATE(_upb_ArenaPool)*)UPB_PRIVATE(upb_Xsan_NewUnpoisonedRegion)( | |
| UPB_XSAN(a), ptr, | |
| UPB_SIZEOF_FLEX(UPB_PRIVATE(_upb_ArenaPool), UPB_PRIVATE(bins), | |
| new_cap)); | |
| UPB_PRIVATE(_upb_ArenaPool)* old_pool = a->UPB_ONLYBITS(pool); | |
| size_t old_num_bins = old_pool->UPB_PRIVATE(num_bins); | |
| UPB_PRIVATE(_upb_ArenaFreeBlock)** dst = new_pool->UPB_PRIVATE(bins); | |
| UPB_PRIVATE(_upb_ArenaFreeBlock)** src = old_pool->UPB_PRIVATE(bins); | |
| size_t i; | |
| for (i = 0; i < old_num_bins; i++) { | |
| *dst++ = *src++; | |
| } | |
| if (old_pool != &UPB_PRIVATE(_upb_Arena_EmptyPool)) { | |
| UPB_PRIVATE(upb_Xsan_PoisonRegion)( | |
| old_pool, UPB_SIZEOF_FLEX(UPB_PRIVATE(_upb_ArenaPool), | |
| UPB_PRIVATE(bins), old_num_bins)); | |
| } | |
| for (i = old_num_bins; i < new_cap; i++) { | |
| *dst++ = NULL; | |
| } | |
| new_pool->UPB_PRIVATE(num_bins) = new_cap; | |
| a->UPB_ONLYBITS(pool) = new_pool; | |
| } | |
| static upb_Arena* _upb_Arena_InitSlow(upb_alloc* alloc, size_t first_size) { | |
| if (!upb_AllocationCount_IncrementAndCheck()) { | |
| return NULL; | |
| } | |
| if (!alloc) return NULL; | |
| // We need to malloc the initial block. | |
| size_t block_size = kUpb_ArenaStateReserve + | |
| UPB_MAX(256, UPB_ALIGN_MALLOC(first_size) + | |
| UPB_PRIVATE(kUpb_Asan_GuardSize)); | |
| void* block = _upb_Arena_AllocBlockInternal(alloc, &block_size); | |
| if (!block) return NULL; | |
| // Initialize the arena state in the first block. We "borrow" the memory from | |
| // the block, because we can't yet call upb_Arena_Malloc. | |
| upb_ArenaState* a = block; | |
| a->body.block_alloc = _upb_Arena_MakeBlockAlloc(alloc, 0); | |
| a->body.last_block_size = UPB_MIN(block_size, UINT32_MAX); | |
| a->body.size_hint = UPB_MIN(block_size, UINT32_MAX); | |
| a->head.UPB_ONLYBITS(ptr) = NULL; | |
| a->head.UPB_ONLYBITS(end) = NULL; | |
| a->head.UPB_ONLYBITS(pool) = | |
| (UPB_PRIVATE(_upb_ArenaPool)*)&UPB_PRIVATE(_upb_Arena_EmptyPool); | |
| upb_Atomic_Init(&a->body.parent_or_count, _upb_Arena_TaggedFromRefcount(1)); | |
| upb_Atomic_Init(&a->body.next, NULL); | |
| upb_Atomic_Init(&a->body.previous_or_tail, | |
| _upb_Arena_TaggedFromTail(&a->body)); | |
| upb_Atomic_Init(&a->body.space_allocated, 0); | |
| a->body.blocks = NULL; | |
| #ifndef NDEBUG | |
| a->body.refs = NULL; | |
| #endif | |
| UPB_PRIVATE(upb_Xsan_Init)(UPB_XSAN(&a->body)); | |
| UPB_PRIVATE(_upb_Arena_AddBlock)(&a->head, block); | |
| block = UPB_PTR_AT(block, kUpb_ArenaStateReserve, void); | |
| block_size -= kUpb_ArenaStateReserve; | |
| UPB_PRIVATE(_upb_Arena_UseBlock)(&a->head, block, block_size); | |
| return &a->head; | |
| } | |
| upb_Arena* upb_Arena_Init(void* mem, size_t n, upb_alloc* alloc) { | |
| UPB_STATIC_ASSERT(UPB_ARENA_SIZE_HACK >= sizeof(upb_ArenaState), | |
| "Need to update UPB_ARENA_SIZE_HACK"); | |
| upb_ArenaState* a; | |
| if (mem) { | |
| /* Align initial pointer up so that we return properly-aligned pointers. */ | |
| void* aligned = (void*)UPB_ALIGN_MALLOC((uintptr_t)mem); | |
| size_t delta = (uintptr_t)aligned - (uintptr_t)mem; | |
| n = delta <= n ? n - delta : 0; | |
| mem = aligned; | |
| } | |
| if (UPB_UNLIKELY(n < sizeof(upb_ArenaState) || !mem)) { | |
| upb_Arena* ret = _upb_Arena_InitSlow(alloc, mem ? 0 : n); | |
| #ifdef UPB_TRACING_ENABLED | |
| upb_Arena_LogInit(ret, n); | |
| #endif | |
| return ret; | |
| } | |
| a = mem; | |
| upb_Atomic_Init(&a->body.parent_or_count, _upb_Arena_TaggedFromRefcount(1)); | |
| upb_Atomic_Init(&a->body.next, NULL); | |
| upb_Atomic_Init(&a->body.previous_or_tail, | |
| _upb_Arena_TaggedFromTail(&a->body)); | |
| upb_Atomic_Init(&a->body.space_allocated, 0); | |
| a->body.blocks = NULL; | |
| #ifndef NDEBUG | |
| a->body.refs = NULL; | |
| #endif | |
| a->body.size_hint = 128; | |
| a->body.last_block_size = 128; | |
| a->body.block_alloc = _upb_Arena_MakeBlockAlloc(alloc, 1); | |
| a->head.UPB_PRIVATE(ptr) = (void*)UPB_ALIGN_MALLOC((uintptr_t)(a + 1)); | |
| a->head.UPB_PRIVATE(end) = UPB_PTR_AT(mem, n, char); | |
| a->head.UPB_ONLYBITS(pool) = | |
| (UPB_PRIVATE(_upb_ArenaPool)*)&UPB_PRIVATE(_upb_Arena_EmptyPool); | |
| UPB_PRIVATE(upb_Xsan_Init)(UPB_XSAN(&a->body)); | |
| #ifdef UPB_TRACING_ENABLED | |
| upb_Arena_LogInit(&a->head, n); | |
| #endif | |
| return &a->head; | |
| } | |
| static void _upb_Arena_DoFree(upb_ArenaInternal* ai) { | |
| UPB_ASSERT(_upb_Arena_RefCountFromTagged(ai->parent_or_count) == 1); | |
| while (ai != NULL) { | |
| UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(ai)); | |
| // Load first since arena itself is likely from one of its blocks. Relaxed | |
| // order is safe because fused arena ordering is provided by the reference | |
| // count, and fuse is not permitted to race with the final decrement. | |
| upb_ArenaInternal* next_arena = | |
| (upb_ArenaInternal*)upb_Atomic_Load(&ai->next, memory_order_relaxed); | |
| // Freeing may have memory barriers that confuse tsan, so assert immediately | |
| // after load here | |
| if (next_arena) { | |
| UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(next_arena)); | |
| } | |
| upb_alloc* block_alloc = _upb_ArenaInternal_BlockAlloc(ai); | |
| upb_MemBlock* block = ai->blocks; | |
| while (block != NULL) { | |
| // Load first since we are deleting block. | |
| upb_MemBlock* next_block = block->next; | |
| if (block->size == 0) { | |
| // If the block is an arena ref, then we need to release our ref on the | |
| // referenced arena. | |
| upb_ArenaRef* ref = (upb_ArenaRef*)block; | |
| upb_Arena_DecRefFor((upb_Arena*)ref->arena, ai); | |
| } else { | |
| upb_free_sized(block_alloc, block, block->size); | |
| } | |
| block = next_block; | |
| } | |
| if (block_alloc && block_alloc->cleanup != NULL) { | |
| block_alloc->cleanup(block_alloc); | |
| } | |
| ai = next_arena; | |
| } | |
| } | |
| void upb_Arena_Free(upb_Arena* a) { | |
| upb_ArenaInternal* ai = upb_Arena_Internal(a); | |
| // Cannot be replaced with _upb_Arena_FindRoot, as that provides only a | |
| // relaxed read of the refcount if ai is already the root. | |
| uintptr_t poc = upb_Atomic_Load(&ai->parent_or_count, memory_order_acquire); | |
| retry: | |
| while (_upb_Arena_IsTaggedPointer(poc)) { | |
| ai = _upb_Arena_PointerFromTagged(poc); | |
| UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(ai)); | |
| poc = upb_Atomic_Load(&ai->parent_or_count, memory_order_acquire); | |
| } | |
| // compare_exchange or fetch_sub are RMW operations, which are more | |
| // expensive then direct loads. As an optimization, we only do RMW ops | |
| // when we need to update things for other threads to see. | |
| if (poc == _upb_Arena_TaggedFromRefcount(1)) { | |
| #ifdef UPB_TRACING_ENABLED | |
| upb_Arena_LogFree(a); | |
| #endif | |
| _upb_Arena_DoFree(ai); | |
| return; | |
| } | |
| if (upb_Atomic_CompareExchangeWeak( | |
| &ai->parent_or_count, &poc, | |
| _upb_Arena_TaggedFromRefcount(_upb_Arena_RefCountFromTagged(poc) - 1), | |
| memory_order_release, memory_order_acquire)) { | |
| // We were >1 and we decremented it successfully, so we are done. | |
| return; | |
| } | |
| // We failed our update, so someone has done something, retry the whole | |
| // process, but the failed exchange reloaded `poc` for us. | |
| goto retry; | |
| } | |
| // Logically performs the following operation, in a way that is safe against | |
| // racing fuses: | |
| // ret = TAIL(parent) | |
| // ret->next = child | |
| // return ret | |
| // | |
| // The caller is therefore guaranteed that ret->next == child. | |
| static upb_ArenaInternal* _upb_Arena_LinkForward( | |
| upb_ArenaInternal* const parent, upb_ArenaInternal* child) { | |
| UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(parent)); | |
| uintptr_t parent_previous_or_tail = | |
| upb_Atomic_Load(&parent->previous_or_tail, memory_order_acquire); | |
| // Optimization: use parent->previous_or_tail to skip to TAIL(parent) in O(1) | |
| // time when possible. This is the common case because we just fused into | |
| // parent, suggesting that it should be a root with a cached tail. | |
| // | |
| // However, if there was a racing fuse, parent may no longer be a root, in | |
| // which case we need to walk the entire list to find the tail. The tail | |
| // pointer is also not guaranteed to be the true tail, so even when the | |
| // optimization is taken, we still need to walk list nodes to find the true | |
| // tail. | |
| upb_ArenaInternal* parent_tail = | |
| _upb_Arena_IsTaggedTail(parent_previous_or_tail) | |
| ? _upb_Arena_TailFromTagged(parent_previous_or_tail) | |
| : parent; | |
| UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(parent_tail)); | |
| upb_ArenaInternal* parent_tail_next = | |
| upb_Atomic_Load(&parent_tail->next, memory_order_acquire); | |
| do { | |
| // Walk the list to find the true tail (a node with next == NULL). | |
| while (parent_tail_next != NULL) { | |
| parent_tail = parent_tail_next; | |
| UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(parent_tail)); | |
| parent_tail_next = | |
| upb_Atomic_Load(&parent_tail->next, memory_order_acquire); | |
| } | |
| } while (!upb_Atomic_CompareExchangeWeak( // Replace a NULL next with child. | |
| &parent_tail->next, &parent_tail_next, child, memory_order_release, | |
| memory_order_acquire)); | |
| return parent_tail; | |
| } | |
| // Updates parent->previous_or_tail = child->previous_or_tail in hopes that the | |
| // latter represents the true tail of the newly-combined list. | |
| // | |
| // This is a best-effort operation that may set the tail to a stale value, and | |
| // may fail to update the tail at all. | |
| void _upb_Arena_UpdateParentTail(upb_ArenaInternal* parent, | |
| upb_ArenaInternal* child) { | |
| // We are guaranteed that child->previous_or_tail is tagged, because we have | |
| // just transitioned child from root -> non-root, which is an exclusive | |
| // operation that can only happen once. So we are the exclusive updater of | |
| // child->previous_or_tail that can transition it from tagged to untagged. | |
| // | |
| // However, we are not guaranteed that child->previous_or_tail is the true | |
| // tail. A racing fuse may have appended to child's list but not yet updated | |
| // child->previous_or_tail. | |
| uintptr_t child_previous_or_tail = | |
| upb_Atomic_Load(&child->previous_or_tail, memory_order_acquire); | |
| upb_ArenaInternal* new_parent_tail = | |
| _upb_Arena_TailFromTagged(child_previous_or_tail); | |
| UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(new_parent_tail)); | |
| // If another thread fused with parent, such that it is no longer a root, | |
| // don't overwrite their previous pointer with our tail. Relaxed order is fine | |
| // here as we only inspect the tag bit. | |
| uintptr_t parent_previous_or_tail = | |
| upb_Atomic_Load(&parent->previous_or_tail, memory_order_relaxed); | |
| if (_upb_Arena_IsTaggedTail(parent_previous_or_tail)) { | |
| upb_Atomic_CompareExchangeStrong( | |
| &parent->previous_or_tail, &parent_previous_or_tail, | |
| _upb_Arena_TaggedFromTail(new_parent_tail), memory_order_release, | |
| memory_order_relaxed); | |
| } | |
| } | |
| static void _upb_Arena_LinkBackward(upb_ArenaInternal* child, | |
| upb_ArenaInternal* old_parent_tail) { | |
| // Link child to parent going backwards, for SpaceAllocated. This transitions | |
| // child->previous_or_tail from tail (tagged) to previous (untagged), after | |
| // which its value is immutable. | |
| // | |
| // - We are guaranteed that no other threads are also attempting to perform | |
| // this transition (tail -> previous), because we just updated | |
| // old_parent_tail->next from NULL to non-NULL, an exclusive operation that | |
| // can only happen once. | |
| // | |
| // - _upb_Arena_UpdateParentTail() uses CAS to ensure that it | |
| // does not perform the reverse transition (previous -> tail). | |
| // | |
| // - We are guaranteed that old_parent_tail is the correct "previous" pointer, | |
| // even in the presence of racing fuses that are adding more nodes to the | |
| // list, because _upb_Arena_LinkForward() guarantees that: | |
| // old_parent_tail->next == child. | |
| upb_Atomic_Store(&child->previous_or_tail, | |
| _upb_Arena_TaggedFromPrevious(old_parent_tail), | |
| memory_order_release); | |
| } | |
| static void _upb_Arena_DoFuseArenaLists(upb_ArenaInternal* const parent, | |
| upb_ArenaInternal* child) { | |
| upb_ArenaInternal* old_parent_tail = _upb_Arena_LinkForward(parent, child); | |
| _upb_Arena_UpdateParentTail(parent, child); | |
| _upb_Arena_LinkBackward(child, old_parent_tail); | |
| } | |
| // Thread safe. | |
| static upb_ArenaInternal* _upb_Arena_DoFuse(upb_ArenaInternal** ai1, | |
| upb_ArenaInternal** ai2, | |
| uintptr_t* ref_delta) { | |
| // `parent_or_count` has two distinct modes | |
| // - parent pointer mode | |
| // - refcount mode | |
| // | |
| // In parent pointer mode, it may change what pointer it refers to in the | |
| // tree, but it will always approach a root. Any operation that walks the | |
| // tree to the root may collapse levels of the tree concurrently. | |
| upb_ArenaRoot r1 = _upb_Arena_FindRoot(*ai1); | |
| upb_ArenaRoot r2 = _upb_Arena_FindRoot(*ai2); | |
| if (r1.root == r2.root) return r1.root; // Already fused. | |
| *ai1 = r1.root; | |
| *ai2 = r2.root; | |
| // Avoid cycles by always fusing into the root with the lower address. | |
| if ((uintptr_t)r1.root > (uintptr_t)r2.root) { | |
| upb_ArenaRoot tmp = r1; | |
| r1 = r2; | |
| r2 = tmp; | |
| } | |
| // The moment we install `r1` as the parent for `r2` all racing frees may | |
| // immediately begin decrementing `r1`'s refcount (including pending | |
| // increments to that refcount and their frees!). We need to add `r2`'s refs | |
| // now, so that `r1` can withstand any unrefs that come from r2. | |
| // | |
| // Note that while it is possible for `r2`'s refcount to increase | |
| // asynchronously, we will not actually do the reparenting operation below | |
| // unless `r2`'s refcount is unchanged from when we read it. | |
| // | |
| // Note that we may have done this previously, either to this node or a | |
| // different node, during a previous and failed DoFuse() attempt. But we will | |
| // not lose track of these refs because we always add them to our overall | |
| // delta. | |
| uintptr_t r2_untagged_count = r2.tagged_count & ~1; | |
| uintptr_t with_r2_refs = r1.tagged_count + r2_untagged_count; | |
| if (!upb_Atomic_CompareExchangeStrong( | |
| &r1.root->parent_or_count, &r1.tagged_count, with_r2_refs, | |
| memory_order_release, memory_order_acquire)) { | |
| return NULL; | |
| } | |
| // Perform the actual fuse by removing the refs from `r2` and swapping in the | |
| // parent pointer. | |
| if (!upb_Atomic_CompareExchangeStrong( | |
| &r2.root->parent_or_count, &r2.tagged_count, | |
| _upb_Arena_TaggedFromPointer(r1.root), memory_order_release, | |
| memory_order_acquire)) { | |
| // We'll need to remove the excess refs we added to r1 previously. | |
| *ref_delta += r2_untagged_count; | |
| return NULL; | |
| } | |
| // Now that the fuse has been performed (and can no longer fail) we need to | |
| // append `r2` to `r1`'s linked list. | |
| _upb_Arena_DoFuseArenaLists(r1.root, r2.root); | |
| return r1.root; | |
| } | |
| // Thread safe. | |
| static bool _upb_Arena_FixupRefs(upb_ArenaInternal* new_root, | |
| uintptr_t ref_delta) { | |
| if (ref_delta == 0) return true; // No fixup required. | |
| // Relaxed order is safe here as if the value is a pointer, we don't deref it | |
| // or publish it anywhere else. The refcount does provide memory order | |
| // between allocations on arenas and the eventual free and thus normally | |
| // requires acquire/release; but in this case any edges provided by the refs | |
| // we are cleaning up were already provided by the fuse operation itself. It's | |
| // not valid for a decrement that could cause the overall fused arena to reach | |
| // a zero refcount to race with this function, as that could result in a | |
| // use-after-free anyway. | |
| uintptr_t poc = | |
| upb_Atomic_Load(&new_root->parent_or_count, memory_order_relaxed); | |
| if (_upb_Arena_IsTaggedPointer(poc)) return false; | |
| uintptr_t with_refs = poc - ref_delta; | |
| UPB_ASSERT(!_upb_Arena_IsTaggedPointer(with_refs)); | |
| // Relaxed order on success is safe here, for the same reasons as the relaxed | |
| // read above. Relaxed order is safe on failure because the updated value is | |
| // stored in a local variable which goes immediately out of scope; the retry | |
| // loop will reread what it needs with proper memory order. | |
| return upb_Atomic_CompareExchangeStrong(&new_root->parent_or_count, &poc, | |
| with_refs, memory_order_relaxed, | |
| memory_order_relaxed); | |
| } | |
| bool upb_Arena_Fuse(const upb_Arena* a1, const upb_Arena* a2) { | |
| if (a1 == a2) return true; // trivial fuse | |
| #ifdef UPB_TRACING_ENABLED | |
| upb_Arena_LogFuse(a1, a2); | |
| #endif | |
| upb_ArenaInternal* ai1 = upb_Arena_Internal(a1); | |
| upb_ArenaInternal* ai2 = upb_Arena_Internal(a2); | |
| // Do not fuse initial blocks since we cannot lifetime extend them. | |
| // Any other fuse scenario is allowed. | |
| if (_upb_ArenaInternal_HasInitialBlock(ai1) || | |
| _upb_ArenaInternal_HasInitialBlock(ai2)) { | |
| return false; | |
| } | |
| // The number of refs we ultimately need to transfer to the new root. | |
| uintptr_t ref_delta = 0; | |
| while (true) { | |
| upb_ArenaInternal* new_root = _upb_Arena_DoFuse(&ai1, &ai2, &ref_delta); | |
| if (new_root != NULL && _upb_Arena_FixupRefs(new_root, ref_delta)) { | |
| #if UPB_ENABLE_REF_CYCLE_CHECKS | |
| UPB_ASSERT(!upb_Arena_HasRefChain(a1, a2)); | |
| #endif | |
| return true; | |
| } | |
| } | |
| } | |
| bool upb_Arena_IsFused(const upb_Arena* a, const upb_Arena* b) { | |
| if (a == b) return true; // trivial fuse | |
| upb_ArenaInternal* ra = _upb_Arena_FindRoot(upb_Arena_Internal(a)).root; | |
| upb_ArenaInternal* rb = upb_Arena_Internal(b); | |
| while (true) { | |
| rb = _upb_Arena_FindRoot(rb).root; | |
| if (ra == rb) return true; | |
| upb_ArenaInternal* tmp = _upb_Arena_FindRoot(ra).root; | |
| if (ra == tmp) return false; | |
| // a's root changed since we last checked. Retry. | |
| ra = tmp; | |
| } | |
| } | |
| bool upb_Arena_IncRefFor(const upb_Arena* a, const void* owner) { | |
| upb_ArenaInternal* ai = upb_Arena_Internal(a); | |
| if (_upb_ArenaInternal_HasInitialBlock(ai)) return false; | |
| upb_ArenaRoot r; | |
| r.root = ai; | |
| retry: | |
| r = _upb_Arena_FindRoot(r.root); | |
| if (upb_Atomic_CompareExchangeWeak( | |
| &r.root->parent_or_count, &r.tagged_count, | |
| _upb_Arena_TaggedFromRefcount( | |
| _upb_Arena_RefCountFromTagged(r.tagged_count) + 1), | |
| // Relaxed order is safe on success, incrementing the refcount | |
| // need not perform any synchronization with the eventual free of the | |
| // arena - that's provided by decrements. | |
| memory_order_relaxed, | |
| // Relaxed order is safe on failure as r.tagged_count is immediately | |
| // overwritten by retrying the find root operation. | |
| memory_order_relaxed)) { | |
| // We incremented it successfully, so we are done. | |
| return true; | |
| } | |
| // We failed update due to parent switching on the arena. | |
| goto retry; | |
| } | |
| void upb_Arena_DecRefFor(const upb_Arena* a, const void* owner) { | |
| upb_Arena_Free((upb_Arena*)a); | |
| } | |
| bool upb_Arena_RefArena(upb_Arena* from, const upb_Arena* to) { | |
| UPB_ASSERT(!upb_Arena_IsFused(from, to)); | |
| if (_upb_ArenaInternal_HasInitialBlock(upb_Arena_Internal(to))) { | |
| // We can't increment a ref to `to`, so return early. | |
| return false; | |
| } | |
| upb_ArenaInternal* ai = upb_Arena_Internal(from); | |
| upb_ArenaRef* ref = upb_Arena_Malloc(from, kUpb_ArenaRefReserve); | |
| if (!ref) { | |
| return false; | |
| } | |
| // When 'from' is freed, a ref on 'to' will be released. | |
| // Intentionally ignore return value, since we already check up above if this | |
| // call will succeed. | |
| bool result = upb_Arena_IncRefFor(to, from); | |
| UPB_ASSERT(result); | |
| // When we add a reference from `from` to `to`, we need to keep track of the | |
| // ref in the `from` arena's linked list of refs. This allows us to | |
| // walk all refs for `from` when `from` is freed, and thus allows us to | |
| // decrement the refcount on `to` when `from` is freed. | |
| ref->prefix.next = ai->blocks; | |
| ref->prefix.size = 0; | |
| ref->arena = to; | |
| ai->blocks = (upb_MemBlock*)ref; | |
| #ifndef NDEBUG | |
| // Add to the dedicated list of refs. | |
| // This function is not thread-safe from `from`, so a simple load/store is | |
| // sufficient. | |
| ref->next_ref = upb_Atomic_Load(&ai->refs, memory_order_relaxed); | |
| upb_Atomic_Store(&ai->refs, ref, memory_order_release); | |
| #endif | |
| #if UPB_ENABLE_REF_CYCLE_CHECKS | |
| UPB_ASSERT(!upb_Arena_HasRefChain(to, from)); // Forbid cycles. | |
| #endif | |
| return true; | |
| } | |
| #ifndef NDEBUG | |
| bool upb_Arena_HasRef(const upb_Arena* from, const upb_Arena* to) { | |
| const upb_ArenaInternal* ai = upb_Arena_Internal(from); | |
| const upb_ArenaRef* ref = upb_Atomic_Load(&ai->refs, memory_order_acquire); | |
| while (ref != NULL) { | |
| if (upb_Arena_IsFused(ref->arena, to)) { | |
| return true; | |
| } | |
| ref = ref->next_ref; | |
| } | |
| return false; | |
| } | |
| #endif | |
| upb_alloc* upb_Arena_GetUpbAlloc(upb_Arena* a) { | |
| UPB_PRIVATE(upb_Xsan_AccessReadOnly)(UPB_XSAN(a)); | |
| upb_ArenaInternal* ai = upb_Arena_Internal(a); | |
| return _upb_ArenaInternal_BlockAlloc(ai); | |
| } | |
| void UPB_PRIVATE(_upb_Arena_SwapIn)(upb_Arena* des, const upb_Arena* src) { | |
| memcpy(des, src, offsetof(upb_ArenaState, body.space_allocated)); | |
| upb_ArenaInternal* desi = upb_Arena_Internal(des); | |
| upb_ArenaInternal* srci = upb_Arena_Internal(src); | |
| uintptr_t new_space_allocated = | |
| upb_Atomic_Load(&srci->space_allocated, memory_order_relaxed); | |
| upb_Atomic_Store(&desi->space_allocated, new_space_allocated, | |
| memory_order_relaxed); | |
| } | |
| void UPB_PRIVATE(_upb_Arena_SwapOut)(upb_Arena* des, const upb_Arena* src) { | |
| UPB_PRIVATE(_upb_Arena_SwapIn)(des, src); | |
| } | |
| bool _upb_Arena_WasLastAllocFromPreviousBlock(struct upb_Arena* a, void* ptr, | |
| size_t oldsize) { | |
| upb_ArenaInternal* ai = upb_Arena_Internal(a); | |
| upb_MemBlock* block = ai->blocks; | |
| // Skip any arena refs. | |
| while (block != NULL && block->size == 0) { | |
| block = block->next; | |
| } | |
| if (block == NULL) return false; | |
| char* start = UPB_PTR_AT(block, kUpb_MemblockReserve, char); | |
| // We don't actually track the final pointer value, so we can only check that | |
| // the span is within the previous block. | |
| return UPB_PRIVATE(upb_Xsan_PtrEq)(ptr, start) && | |
| UPB_PRIVATE(_upb_Arena_AllocSpan)(oldsize) == | |
| block->size - kUpb_MemblockReserve; | |
| } | |
| void* UPB_PRIVATE(_upb_Arena_Steal)(struct upb_Arena* a, size_t* size) { | |
| UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(a)); | |
| size_t have = UPB_PRIVATE(_upb_ArenaHas)(a); | |
| if (have < *size) return NULL; | |
| *size = have; | |
| void* ptr = a->UPB_ONLYBITS(ptr); | |
| a->UPB_ONLYBITS(ptr) += have; | |
| return UPB_PRIVATE(upb_Xsan_NewUnpoisonedRegion)(UPB_XSAN(a), ptr, have); | |
| } | |
| // Frees a block previously allocated with _upb_Arena_AllocBlock. | |
| void UPB_PRIVATE(_upb_Arena_FreeBlock)(upb_Arena* a, void* block) { | |
| UPB_PRIVATE(upb_Xsan_AccessReadWrite)(UPB_XSAN(a)); | |
| upb_MemBlock* b = | |
| UPB_PTR_AT(block, -(ptrdiff_t)kUpb_MemblockReserve, upb_MemBlock); | |
| upb_alloc* alloc = upb_Arena_GetUpbAlloc(a); | |
| upb_free_sized(alloc, b, b->size); | |
| } | |
| // Must be last. | |
| bool upb_Message_SetMapEntry(upb_Map* map, const upb_MiniTableField* f, | |
| upb_Message* map_entry_message, upb_Arena* arena) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(map_entry_message)); | |
| const upb_MiniTable* map_entry_mini_table = | |
| upb_MiniTable_MapEntrySubMessage(f); | |
| UPB_ASSERT(map_entry_mini_table); | |
| const upb_MiniTableField* map_entry_key_field = | |
| upb_MiniTable_MapKey(map_entry_mini_table); | |
| const upb_MiniTableField* map_entry_value_field = | |
| upb_MiniTable_MapValue(map_entry_mini_table); | |
| // Map key/value cannot have explicit defaults, | |
| // hence assuming a zero default is valid. | |
| upb_MessageValue default_val = upb_MessageValue_Zero(); | |
| upb_MessageValue map_entry_key = | |
| upb_Message_GetField(map_entry_message, map_entry_key_field, default_val); | |
| upb_MessageValue map_entry_value = upb_Message_GetField( | |
| map_entry_message, map_entry_value_field, default_val); | |
| return upb_Map_Set(map, map_entry_key, map_entry_value, arena); | |
| } | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| upb_Array* upb_Array_New(upb_Arena* a, upb_CType type) { | |
| const int lg2 = UPB_PRIVATE(_upb_CType_SizeLg2)(type); | |
| return UPB_PRIVATE(_upb_Array_New)(a, _UPB_ARRAY_DEFAULT_INITIAL_SIZE, lg2); | |
| } | |
| upb_MessageValue upb_Array_Get(const upb_Array* arr, size_t i) { | |
| UPB_ASSERT(i < upb_Array_Size(arr)); | |
| upb_MessageValue ret; | |
| const char* data = upb_Array_DataPtr(arr); | |
| const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr); | |
| UPB_PRIVATE(_upb_Array_CopyElem)(&ret, data + (i << lg2), lg2); | |
| return ret; | |
| } | |
| upb_Message* upb_Array_GetMutable(upb_Array* arr, size_t i) { | |
| UPB_ASSERT(i < upb_Array_Size(arr)); | |
| size_t elem_size = sizeof(upb_Message*); | |
| UPB_ASSERT(elem_size == (1 << UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr))); | |
| char* data = upb_Array_MutableDataPtr(arr); | |
| upb_Message* ret; | |
| memcpy(&ret, data + (i * elem_size), elem_size); | |
| UPB_ASSERT(!upb_Message_IsFrozen(ret)); | |
| return ret; | |
| } | |
| void upb_Array_Set(upb_Array* arr, size_t i, upb_MessageValue val) { | |
| UPB_ASSERT(!upb_Array_IsFrozen(arr)); | |
| UPB_ASSERT(i < upb_Array_Size(arr)); | |
| char* data = upb_Array_MutableDataPtr(arr); | |
| const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr); | |
| UPB_PRIVATE(_upb_Array_CopyElem)(data + (i << lg2), &val, lg2); | |
| } | |
| bool upb_Array_Append(upb_Array* arr, upb_MessageValue val, upb_Arena* arena) { | |
| UPB_ASSERT(!upb_Array_IsFrozen(arr)); | |
| UPB_ASSERT(arena); | |
| if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)( | |
| arr, arr->UPB_PRIVATE(size) + 1, arena)) { | |
| return false; | |
| } | |
| upb_Array_Set(arr, arr->UPB_PRIVATE(size) - 1, val); | |
| return true; | |
| } | |
| bool upb_Array_Copy(upb_Array* dst, const upb_Array* src, upb_Arena* arena) { | |
| UPB_ASSERT(dst); | |
| UPB_ASSERT(src); | |
| UPB_ASSERT(!upb_Array_IsFrozen(dst)); | |
| if (dst == src) return true; | |
| size_t len = upb_Array_Size(src); | |
| if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)(dst, len, arena)) { | |
| return false; | |
| } | |
| if (len == 0) return true; | |
| const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(dst); | |
| const int src_lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(src); | |
| UPB_ASSERT(lg2 == src_lg2); | |
| char* dst_data = upb_Array_MutableDataPtr(dst); | |
| const char* src_data = upb_Array_DataPtr(src); | |
| memcpy(dst_data, src_data, len << lg2); | |
| return true; | |
| } | |
| bool upb_Array_AppendAll(upb_Array* dst, const upb_Array* src, | |
| upb_Arena* arena) { | |
| UPB_ASSERT(!upb_Array_IsFrozen(dst)); | |
| UPB_ASSERT(src); | |
| size_t src_len = upb_Array_Size(src); | |
| if (src_len == 0) return true; | |
| size_t dst_len = upb_Array_Size(dst); | |
| size_t len; | |
| if (UPB_UNLIKELY(upb_AddOverflow(dst_len, src_len, &len))) return false; | |
| if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)(dst, len, arena)) { | |
| return false; | |
| } | |
| const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(dst); | |
| const int src_lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(src); | |
| UPB_ASSERT(lg2 == src_lg2); | |
| char* dst_data = upb_Array_MutableDataPtr(dst); | |
| const char* src_data = upb_Array_DataPtr(src); | |
| memcpy(dst_data + (dst_len << lg2), src_data, src_len << lg2); | |
| return true; | |
| } | |
| void upb_Array_Move(upb_Array* arr, size_t dst_idx, size_t src_idx, | |
| size_t count) { | |
| UPB_ASSERT(!upb_Array_IsFrozen(arr)); | |
| const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr); | |
| char* data = upb_Array_MutableDataPtr(arr); | |
| memmove(&data[dst_idx << lg2], &data[src_idx << lg2], count << lg2); | |
| } | |
| bool upb_Array_Insert(upb_Array* arr, size_t i, size_t count, | |
| upb_Arena* arena) { | |
| UPB_ASSERT(!upb_Array_IsFrozen(arr)); | |
| UPB_ASSERT(arena); | |
| UPB_ASSERT(i <= arr->UPB_PRIVATE(size)); | |
| size_t new_size; | |
| const bool ok = !upb_AddOverflow(arr->UPB_PRIVATE(size), count, &new_size); | |
| UPB_ASSERT(ok); | |
| const size_t oldsize = arr->UPB_PRIVATE(size); | |
| if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)(arr, new_size, arena)) { | |
| return false; | |
| } | |
| upb_Array_Move(arr, i + count, i, oldsize - i); | |
| return true; | |
| } | |
| /* | |
| * i end arr->size | |
| * |------------|XXXXXXXX|--------| | |
| */ | |
| void upb_Array_Delete(upb_Array* arr, size_t i, size_t count) { | |
| UPB_ASSERT(!upb_Array_IsFrozen(arr)); | |
| size_t end; | |
| const bool ok = !upb_AddOverflow(i, count, &end); | |
| UPB_ASSERT(ok); | |
| UPB_ASSERT(end <= arr->UPB_PRIVATE(size)); | |
| upb_Array_Move(arr, i, end, arr->UPB_PRIVATE(size) - end); | |
| arr->UPB_PRIVATE(size) -= count; | |
| } | |
| bool upb_Array_Resize(upb_Array* arr, size_t size, upb_Arena* arena) { | |
| UPB_ASSERT(!upb_Array_IsFrozen(arr)); | |
| const size_t oldsize = arr->UPB_PRIVATE(size); | |
| if (UPB_UNLIKELY( | |
| !UPB_PRIVATE(_upb_Array_ResizeUninitialized)(arr, size, arena))) { | |
| return false; | |
| } | |
| const size_t newsize = arr->UPB_PRIVATE(size); | |
| if (newsize > oldsize) { | |
| const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(arr); | |
| char* data = upb_Array_MutableDataPtr(arr); | |
| memset(data + (oldsize << lg2), 0, (newsize - oldsize) << lg2); | |
| } | |
| return true; | |
| } | |
| bool UPB_PRIVATE(_upb_Array_Realloc)(upb_Array* array, size_t min_capacity, | |
| upb_Arena* arena) { | |
| size_t target_capacity = UPB_MAX(min_capacity, 4); | |
| size_t new_capacity = upb_RoundUpToPowerOfTwo(target_capacity); | |
| if (new_capacity == SIZE_MAX) return false; | |
| const int lg2 = UPB_PRIVATE(_upb_Array_ElemSizeLg2)(array); | |
| size_t old_bytes = array->UPB_PRIVATE(capacity) << lg2; | |
| void* ptr = upb_Array_MutableDataPtr(array); | |
| UPB_ASSERT(ptr); | |
| size_t new_bytes = new_capacity; | |
| if (upb_ShlOverflow(&new_bytes, lg2)) { | |
| return false; | |
| } | |
| if (upb_Arena_TryExtend(arena, ptr, old_bytes, new_bytes)) { | |
| array->UPB_PRIVATE(capacity) = new_capacity; | |
| } else { | |
| size_t pool_bytes = | |
| UPB_MAX(new_bytes, UPB_PRIVATE(kUpb_Arena_MinPoolBlockSize)); | |
| void* new_ptr = upb_Arena_AllocPool(arena, pool_bytes); | |
| if (!new_ptr) return false; | |
| if (old_bytes > 0) { | |
| memcpy(new_ptr, ptr, old_bytes); | |
| } | |
| const size_t array_size = | |
| UPB_ALIGN_UP(sizeof(struct upb_Array), UPB_MALLOC_ALIGN); | |
| bool is_contiguous = (ptr == UPB_PTR_AT(array, array_size, void)); | |
| if (!is_contiguous) { | |
| UPB_PRIVATE(_upb_Arena_Harvest)(arena, ptr, old_bytes); | |
| } | |
| ptr = new_ptr; | |
| UPB_PRIVATE(_upb_Array_SetTaggedPtr)(array, ptr, lg2); | |
| array->UPB_PRIVATE(capacity) = pool_bytes >> lg2; | |
| } | |
| return true; | |
| } | |
| void upb_Array_Freeze(upb_Array* arr, const upb_MiniTable* m) { | |
| if (upb_Array_IsFrozen(arr)) return; | |
| UPB_PRIVATE(_upb_Array_ShallowFreeze)(arr); | |
| if (m) { | |
| const size_t size = upb_Array_Size(arr); | |
| for (size_t i = 0; i < size; i++) { | |
| upb_MessageValue val = upb_Array_Get(arr, i); | |
| upb_Message_Freeze((upb_Message*)val.msg_val, m); | |
| } | |
| } | |
| } | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| // Must be last. | |
| bool upb_Message_NextExtensionReverse(const upb_Message* msg, | |
| const upb_MiniTableExtension** result, | |
| uintptr_t* iter) { | |
| upb_MessageValue val; | |
| return UPB_PRIVATE(_upb_Message_NextExtensionReverse)(msg, result, &val, | |
| iter); | |
| } | |
| const upb_MiniTableExtension* upb_Message_FindExtensionByNumber( | |
| const upb_Message* msg, uint32_t field_number) { | |
| uintptr_t iter = kUpb_Message_ExtensionBegin; | |
| const upb_MiniTableExtension* result; | |
| while (upb_Message_NextExtensionReverse(msg, &result, &iter)) { | |
| if (upb_MiniTableExtension_Number(result) == field_number) return result; | |
| } | |
| return NULL; | |
| } | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| // Strings/bytes are special-cased in maps. | |
| char _upb_Map_CTypeSizeTable[12] = { | |
| [kUpb_CType_Bool] = 1, | |
| [kUpb_CType_Float] = 4, | |
| [kUpb_CType_Int32] = 4, | |
| [kUpb_CType_UInt32] = 4, | |
| [kUpb_CType_Enum] = 4, | |
| [kUpb_CType_Message] = sizeof(void*), | |
| [kUpb_CType_Double] = 8, | |
| [kUpb_CType_Int64] = 8, | |
| [kUpb_CType_UInt64] = 8, | |
| [kUpb_CType_String] = UPB_MAPTYPE_STRING, | |
| [kUpb_CType_Bytes] = UPB_MAPTYPE_STRING, | |
| }; | |
| upb_Map* upb_Map_New(upb_Arena* a, upb_CType key_type, upb_CType value_type) { | |
| return _upb_Map_New(a, _upb_Map_CTypeSize(key_type), | |
| _upb_Map_CTypeSize(value_type)); | |
| } | |
| size_t upb_Map_Size(const upb_Map* map) { return _upb_Map_Size(map); } | |
| bool upb_Map_Get(const upb_Map* map, upb_MessageValue key, | |
| upb_MessageValue* val) { | |
| return _upb_Map_Get(map, &key, map->key_size, val, map->val_size); | |
| } | |
| struct upb_Message* upb_Map_GetMutable(upb_Map* map, upb_MessageValue key) { | |
| UPB_ASSERT(map->val_size == sizeof(upb_Message*)); | |
| upb_Message* val = NULL; | |
| if (_upb_Map_Get(map, &key, map->key_size, &val, sizeof(upb_Message*))) { | |
| return val; | |
| } else { | |
| return NULL; | |
| } | |
| } | |
| void upb_Map_Clear(upb_Map* map) { _upb_Map_Clear(map); } | |
| upb_MapInsertStatus upb_Map_Insert(upb_Map* map, upb_MessageValue key, | |
| upb_MessageValue val, upb_Arena* arena) { | |
| UPB_ASSERT(arena); | |
| return (upb_MapInsertStatus)_upb_Map_Insert(map, &key, map->key_size, &val, | |
| map->val_size, arena); | |
| } | |
| bool upb_Map_Delete(upb_Map* map, upb_MessageValue key, upb_MessageValue* val) { | |
| upb_value v; | |
| const bool removed = _upb_Map_Delete(map, &key, map->key_size, &v); | |
| if (removed && val) _upb_map_fromvalue(v, val, map->val_size); | |
| return removed; | |
| } | |
| bool upb_Map_Next(const upb_Map* map, upb_MessageValue* key, | |
| upb_MessageValue* val, size_t* iter) { | |
| if (_upb_Map_Size(map) == 0) return false; | |
| upb_value v; | |
| bool ret; | |
| if (map->UPB_PRIVATE(is_strtable)) { | |
| upb_StringView strkey; | |
| ret = upb_strtable_next2(&map->t.strtable, &strkey, &v, (intptr_t*)iter); | |
| if (ret) { | |
| _upb_map_fromkey(strkey, key, map->key_size); | |
| } | |
| } else { | |
| uintptr_t intkey; | |
| ret = upb_inttable_next(&map->t.inttable, &intkey, &v, (intptr_t*)iter); | |
| if (ret) { | |
| _upb_map_memcpy(key, &intkey, map->key_size); | |
| } | |
| } | |
| if (ret) { | |
| _upb_map_fromvalue(v, val, map->val_size); | |
| } | |
| return ret; | |
| } | |
| UPB_API void upb_Map_SetEntryValue(upb_Map* map, size_t iter, | |
| upb_MessageValue val) { | |
| upb_value v; | |
| _upb_map_tovalue(&val, map->val_size, &v, NULL); | |
| if (map->UPB_PRIVATE(is_strtable)) { | |
| upb_strtable_setentryvalue(&map->t.strtable, iter, v); | |
| } else { | |
| upb_inttable_setentryvalue(&map->t.inttable, iter, v); | |
| } | |
| } | |
| bool upb_MapIterator_Next(const upb_Map* map, size_t* iter) { | |
| return _upb_map_next(map, iter); | |
| } | |
| // Returns the key and value for this entry of the map. | |
| upb_MessageValue upb_MapIterator_Key(const upb_Map* map, size_t iter) { | |
| upb_MessageValue ret; | |
| if (map->UPB_PRIVATE(is_strtable)) { | |
| upb_strtable_iter i; | |
| i.t = &map->t.strtable; | |
| i.index = iter; | |
| _upb_map_fromkey(upb_strtable_iter_key(&i), &ret, map->key_size); | |
| } else { | |
| uintptr_t intkey = upb_inttable_iter_key(&map->t.inttable, iter); | |
| _upb_map_memcpy(&ret, &intkey, map->key_size); | |
| } | |
| return ret; | |
| } | |
| upb_MessageValue upb_MapIterator_Value(const upb_Map* map, size_t iter) { | |
| upb_value v; | |
| if (map->UPB_PRIVATE(is_strtable)) { | |
| upb_strtable_iter i; | |
| i.t = &map->t.strtable; | |
| i.index = iter; | |
| v = upb_strtable_iter_value(&i); | |
| } else { | |
| v = upb_inttable_iter_value(&map->t.inttable, iter); | |
| } | |
| upb_MessageValue ret; | |
| _upb_map_fromvalue(v, &ret, map->val_size); | |
| return ret; | |
| } | |
| void upb_Map_Freeze(upb_Map* map, const upb_MiniTable* m) { | |
| if (upb_Map_IsFrozen(map)) return; | |
| UPB_PRIVATE(_upb_Map_ShallowFreeze)(map); | |
| if (m && _upb_Map_Size(map) > 0) { | |
| size_t iter = kUpb_Map_Begin; | |
| upb_MessageValue key, val; | |
| while (upb_Map_Next(map, &key, &val, &iter)) { | |
| upb_Message_Freeze((upb_Message*)val.msg_val, m); | |
| } | |
| } | |
| } | |
| // EVERYTHING BELOW THIS LINE IS INTERNAL - DO NOT USE ///////////////////////// | |
| upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size) { | |
| upb_Map* map = upb_Arena_Malloc(a, sizeof(upb_Map)); | |
| if (!map) return NULL; | |
| memset(&map->t, 0, sizeof(map->t)); | |
| if (key_size <= sizeof(uintptr_t) && key_size != UPB_MAPTYPE_STRING) { | |
| map->UPB_PRIVATE(is_strtable) = false; | |
| } else { | |
| map->UPB_PRIVATE(is_strtable) = true; | |
| } | |
| map->key_size = key_size; | |
| map->val_size = value_size; | |
| map->UPB_PRIVATE(is_frozen) = false; | |
| return map; | |
| } | |
| bool _upb_Map_Reserve(upb_Map* map, size_t size, upb_Arena* arena) { | |
| UPB_ASSERT(!upb_Map_IsFrozen(map)); | |
| if (size == 0) return true; | |
| size_t target = _upb_entries_needed_for(size); | |
| if (target < 8) target = 8; | |
| int size_lg2 = upb_Log2Ceiling(target); | |
| if (_upb_Map_Capacity(map) >= ((size_t)1 << size_lg2)) { | |
| return true; | |
| } | |
| if (map->UPB_PRIVATE(is_strtable)) { | |
| return upb_strtable_resize(&map->t.strtable, size_lg2, arena); | |
| } else { | |
| return upb_inttable_resize(&map->t.inttable, size_lg2, arena); | |
| } | |
| } | |
| bool upb_Map_Reserve(upb_Map* map, size_t size, upb_Arena* arena) { | |
| return _upb_Map_Reserve(map, size, arena); | |
| } | |
| #include <stdint.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| // Must be last. | |
| static int _upb_mapsorter_intkeys(const void* _a, const void* _b) { | |
| const upb_tabent* const* a = _a; | |
| const upb_tabent* const* b = _b; | |
| uintptr_t a_key = (*a)->key.num; | |
| uintptr_t b_key = (*b)->key.num; | |
| return a_key < b_key ? -1 : a_key > b_key; | |
| } | |
| static void _upb_mapsorter_getkeys(const void* _a, const void* _b, void* a_key, | |
| void* b_key, size_t size) { | |
| const upb_tabent* const* a = _a; | |
| const upb_tabent* const* b = _b; | |
| upb_StringView a_tabkey = upb_key_strview((*a)->key); | |
| upb_StringView b_tabkey = upb_key_strview((*b)->key); | |
| _upb_map_fromkey(a_tabkey, a_key, size); | |
| _upb_map_fromkey(b_tabkey, b_key, size); | |
| } | |
| static int _upb_mapsorter_cmpi64(const void* _a, const void* _b) { | |
| int64_t a, b; | |
| _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); | |
| return a < b ? -1 : a > b; | |
| } | |
| static int _upb_mapsorter_cmpu64(const void* _a, const void* _b) { | |
| uint64_t a, b; | |
| _upb_mapsorter_getkeys(_a, _b, &a, &b, 8); | |
| return a < b ? -1 : a > b; | |
| } | |
| static int _upb_mapsorter_cmpi32(const void* _a, const void* _b) { | |
| int32_t a, b; | |
| _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); | |
| return a < b ? -1 : a > b; | |
| } | |
| static int _upb_mapsorter_cmpu32(const void* _a, const void* _b) { | |
| uint32_t a, b; | |
| _upb_mapsorter_getkeys(_a, _b, &a, &b, 4); | |
| return a < b ? -1 : a > b; | |
| } | |
| static int _upb_mapsorter_cmpbool(const void* _a, const void* _b) { | |
| bool a, b; | |
| _upb_mapsorter_getkeys(_a, _b, &a, &b, 1); | |
| return a < b ? -1 : a > b; | |
| } | |
| static int _upb_mapsorter_cmpstr(const void* _a, const void* _b) { | |
| upb_StringView a, b; | |
| _upb_mapsorter_getkeys(_a, _b, &a, &b, UPB_MAPTYPE_STRING); | |
| size_t common_size = UPB_MIN(a.size, b.size); | |
| int cmp = memcmp(a.data, b.data, common_size); | |
| if (cmp) return -cmp; | |
| return a.size < b.size ? -1 : a.size > b.size; | |
| } | |
| static int (*const compar[kUpb_FieldType_SizeOf])(const void*, const void*) = { | |
| [kUpb_FieldType_Int64] = _upb_mapsorter_cmpi64, | |
| [kUpb_FieldType_SFixed64] = _upb_mapsorter_cmpi64, | |
| [kUpb_FieldType_SInt64] = _upb_mapsorter_cmpi64, | |
| [kUpb_FieldType_UInt64] = _upb_mapsorter_cmpu64, | |
| [kUpb_FieldType_Fixed64] = _upb_mapsorter_cmpu64, | |
| [kUpb_FieldType_Int32] = _upb_mapsorter_cmpi32, | |
| [kUpb_FieldType_SInt32] = _upb_mapsorter_cmpi32, | |
| [kUpb_FieldType_SFixed32] = _upb_mapsorter_cmpi32, | |
| [kUpb_FieldType_Enum] = _upb_mapsorter_cmpi32, | |
| [kUpb_FieldType_UInt32] = _upb_mapsorter_cmpu32, | |
| [kUpb_FieldType_Fixed32] = _upb_mapsorter_cmpu32, | |
| [kUpb_FieldType_Bool] = _upb_mapsorter_cmpbool, | |
| [kUpb_FieldType_String] = _upb_mapsorter_cmpstr, | |
| [kUpb_FieldType_Bytes] = _upb_mapsorter_cmpstr, | |
| }; | |
| static bool _upb_mapsorter_resize(_upb_mapsorter* s, _upb_sortedmap* sorted, | |
| size_t size) { | |
| sorted->start = s->size; | |
| sorted->pos = sorted->start; | |
| sorted->end = sorted->start + size; | |
| if (sorted->end > s->cap) { | |
| const size_t oldsize = s->cap * sizeof(*s->entries); | |
| s->cap = upb_RoundUpToPowerOfTwo(sorted->end); | |
| const size_t newsize = s->cap * sizeof(*s->entries); | |
| s->entries = upb_grealloc(s->entries, oldsize, newsize); | |
| if (!s->entries) return false; | |
| } | |
| s->size = sorted->end; | |
| return true; | |
| } | |
| bool _upb_mapsorter_pushmap(_upb_mapsorter* s, upb_FieldType key_type, | |
| const upb_Map* map, _upb_sortedmap* sorted) { | |
| size_t map_size = _upb_Map_Size(map); | |
| if (!_upb_mapsorter_resize(s, sorted, map_size)) return false; | |
| // Copy non-empty entries from the table to s->entries. | |
| const void** dst = &s->entries[sorted->start]; | |
| const upb_tabent* src; | |
| const upb_tabent* end; | |
| if (map->UPB_PRIVATE(is_strtable)) { | |
| src = map->t.strtable.t.entries; | |
| end = src + upb_table_size(&map->t.strtable.t); | |
| } else { | |
| src = map->t.inttable.t.entries; | |
| end = src + upb_table_size(&map->t.inttable.t); | |
| } | |
| for (; src < end; src++) { | |
| if (!upb_tabent_isempty(src)) { | |
| *dst = src; | |
| dst++; | |
| } | |
| } | |
| UPB_ASSERT(dst == &s->entries[sorted->end]); | |
| // Sort entries according to the key type. | |
| qsort(&s->entries[sorted->start], map_size, sizeof(*s->entries), | |
| map->UPB_PRIVATE(is_strtable) ? compar[key_type] | |
| : _upb_mapsorter_intkeys); | |
| return true; | |
| } | |
| static int _upb_mapsorter_cmpext(const void* _a, const void* _b) { | |
| const upb_Extension* const* a = _a; | |
| const upb_Extension* const* b = _b; | |
| uint32_t a_num = upb_MiniTableField_Number(upb_Extension_MiniTableField(*a)); | |
| uint32_t b_num = upb_MiniTableField_Number(upb_Extension_MiniTableField(*b)); | |
| UPB_ASSERT(a_num != b_num); | |
| return a_num < b_num ? -1 : 1; | |
| } | |
| bool _upb_mapsorter_pushexts(_upb_mapsorter* s, const upb_Message_Internal* in, | |
| _upb_sortedmap* sorted) { | |
| size_t count = 0; | |
| for (size_t i = 0; i < in->size; i++) { | |
| count += upb_TaggedAuxPtr_IsCanonicalExtension(in->aux_data[i]); | |
| } | |
| if (!_upb_mapsorter_resize(s, sorted, count)) return false; | |
| if (count == 0) return true; | |
| const upb_Extension** entry = | |
| (const upb_Extension**)&s->entries[sorted->start]; | |
| for (size_t i = 0; i < in->size; i++) { | |
| upb_TaggedAuxPtr tagged_ptr = in->aux_data[i]; | |
| if (upb_TaggedAuxPtr_IsCanonicalExtension(tagged_ptr)) { | |
| *entry++ = upb_TaggedAuxPtr_CanonicalExtension(tagged_ptr); | |
| } | |
| } | |
| qsort(&s->entries[sorted->start], count, sizeof(*s->entries), | |
| _upb_mapsorter_cmpext); | |
| return true; | |
| } | |
| #include <stdarg.h> | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| upb_Message* upb_Message_New(const upb_MiniTable* m, upb_Arena* a) { | |
| return _upb_Message_New(m, a); | |
| } | |
| UPB_NOINLINE bool UPB_PRIVATE(_upb_Message_AddUnknownSlowPath)(upb_Message* msg, | |
| const char* data, | |
| size_t len, | |
| upb_Arena* arena, | |
| bool alias) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| { | |
| upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); | |
| // Alias fast path was already checked in the inline function that calls | |
| // this one | |
| if (!alias && in && in->size) { | |
| upb_TaggedAuxPtr ptr = in->aux_data[in->size - 1]; | |
| if (upb_TaggedAuxPtr_IsUnknownStringView(ptr)) { | |
| upb_StringView* existing = upb_TaggedPtrAux_StringViewRepr(ptr); | |
| if (!upb_TaggedAuxPtr_IsUnknownAliased(ptr)) { | |
| // If part of the existing field was deleted at the beginning, we can | |
| // reconstruct it by comparing the address of the end with the address | |
| // of the entry itself; having the non-aliased tag means that the | |
| // string_view and the data it points to are part of the same original | |
| // upb_Arena_Malloc allocation, and the end of the string view | |
| // represents the end of that allocation. | |
| size_t prev_alloc_size = | |
| (existing->data + existing->size) - (char*)existing; | |
| size_t new_alloc_size; | |
| if (!upb_AddOverflow(prev_alloc_size, len, &new_alloc_size)) { | |
| if (upb_Arena_TryExtend(arena, existing, prev_alloc_size, | |
| new_alloc_size)) { | |
| memcpy(UPB_PTR_AT(existing, prev_alloc_size, void), data, len); | |
| existing->size += len; | |
| return true; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| // TODO: b/376969853 - Add debug check that the unknown field is an overall | |
| // valid proto field | |
| if (!UPB_PRIVATE(_upb_Message_ReserveSlot)(msg, arena)) { | |
| return false; | |
| } | |
| upb_StringView* view; | |
| if (alias) { | |
| view = upb_Arena_Malloc(arena, sizeof(upb_StringView)); | |
| if (!view) return false; | |
| view->data = data; | |
| } else { | |
| size_t total_size; | |
| if (upb_AddOverflow(sizeof(upb_StringView), len, &total_size)) return false; | |
| view = upb_Arena_Malloc(arena, total_size); | |
| if (!view) return false; | |
| char* copy = UPB_PTR_AT(view, sizeof(upb_StringView), char); | |
| memcpy(copy, data, len); | |
| view->data = copy; | |
| } | |
| view->size = len; | |
| upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); | |
| in->aux_data[in->size++] = alias | |
| ? upb_TaggedAuxPtr_MakeUnknownDataAliased(view) | |
| : upb_TaggedAuxPtr_MakeUnknownData(view); | |
| return true; | |
| } | |
| bool UPB_PRIVATE(_upb_Message_AddUnknownV)(struct upb_Message* msg, | |
| upb_Arena* arena, | |
| upb_StringView data[], | |
| size_t count) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| UPB_ASSERT(count > 0); | |
| size_t total_len = 0; | |
| for (size_t i = 0; i < count; i++) { | |
| if (upb_AddOverflow(total_len, data[i].size, &total_len)) { | |
| return false; | |
| } | |
| } | |
| { | |
| upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); | |
| if (in && in->size) { | |
| upb_TaggedAuxPtr ptr = in->aux_data[in->size - 1]; | |
| if (upb_TaggedAuxPtr_IsUnknownStringView(ptr)) { | |
| upb_StringView* existing = upb_TaggedPtrAux_StringViewRepr(ptr); | |
| if (!upb_TaggedAuxPtr_IsUnknownAliased(ptr)) { | |
| size_t prev_alloc_size = | |
| (existing->data + existing->size) - (char*)existing; | |
| size_t new_alloc_size; | |
| if (!upb_AddOverflow(prev_alloc_size, total_len, &new_alloc_size)) { | |
| if (upb_Arena_TryExtend(arena, existing, prev_alloc_size, | |
| new_alloc_size)) { | |
| char* copy = UPB_PTR_AT(existing, prev_alloc_size, char); | |
| for (size_t i = 0; i < count; i++) { | |
| memcpy(copy, data[i].data, data[i].size); | |
| copy += data[i].size; | |
| } | |
| existing->size += total_len; | |
| return true; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| size_t total_size; | |
| if (upb_AddOverflow(sizeof(upb_StringView), total_len, &total_size)) { | |
| return false; | |
| } | |
| if (!UPB_PRIVATE(_upb_Message_ReserveSlot)(msg, arena)) return false; | |
| upb_StringView* view = upb_Arena_Malloc(arena, total_size); | |
| if (!view) return false; | |
| char* copy = UPB_PTR_AT(view, sizeof(upb_StringView), char); | |
| view->data = copy; | |
| view->size = total_len; | |
| for (size_t i = 0; i < count; i++) { | |
| memcpy(copy, data[i].data, data[i].size); | |
| copy += data[i].size; | |
| } | |
| // TODO: b/376969853 - Add debug check that the unknown field is an overall | |
| // valid proto field | |
| upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); | |
| in->aux_data[in->size++] = upb_TaggedAuxPtr_MakeUnknownData(view); | |
| return true; | |
| } | |
| void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); | |
| if (!in) return; | |
| uint32_t size = 0; | |
| for (uint32_t i = 0; i < in->size; i++) { | |
| upb_TaggedAuxPtr tagged_ptr = in->aux_data[i]; | |
| // Only keep semantically known fields (i.e., canonical extensions). | |
| if (upb_TaggedAuxPtr_IsSemanticallyKnown(tagged_ptr)) { | |
| in->aux_data[size++] = tagged_ptr; | |
| } | |
| } | |
| in->size = size; | |
| } | |
| size_t upb_Message_ExtensionCount(const upb_Message* msg) { | |
| upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); | |
| if (!in) return 0; | |
| const upb_MiniTableExtension* ext; | |
| upb_MessageValue val; | |
| uintptr_t iter = kUpb_Message_ExtensionBegin; | |
| size_t count = 0; | |
| while (upb_Message_NextExtension(msg, &ext, &val, &iter)) { | |
| count++; | |
| } | |
| return count; | |
| } | |
| void upb_Message_Freeze(upb_Message* msg, const upb_MiniTable* m) { | |
| if (upb_Message_IsFrozen(msg)) return; | |
| UPB_PRIVATE(_upb_Message_ShallowFreeze)(msg); | |
| // Base Fields. | |
| const size_t field_count = upb_MiniTable_FieldCount(m); | |
| for (size_t i = 0; i < field_count; i++) { | |
| const upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, i); | |
| const upb_MiniTable* m2 = upb_MiniTable_SubMessage(f); | |
| switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f)) { | |
| case kUpb_FieldMode_Array: { | |
| upb_Array* arr = upb_Message_GetMutableArray(msg, f); | |
| if (arr) upb_Array_Freeze(arr, m2); | |
| break; | |
| } | |
| case kUpb_FieldMode_Map: { | |
| upb_Map* map = upb_Message_GetMutableMap(msg, f); | |
| if (map) { | |
| const upb_MiniTableField* f2 = upb_MiniTable_MapValue(m2); | |
| const upb_MiniTable* m3 = upb_MiniTable_SubMessage(f2); | |
| upb_Map_Freeze(map, m3); | |
| } | |
| break; | |
| } | |
| case kUpb_FieldMode_Scalar: { | |
| if (m2) { | |
| upb_Message* msg2 = upb_Message_GetMutableMessage(msg, f); | |
| if (msg2) upb_Message_Freeze(msg2, m2); | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| // Extensions. | |
| upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); | |
| // TODO: b/376969853 - use iterator API | |
| uint32_t size = in ? in->size : 0; | |
| for (size_t i = 0; i < size; i++) { | |
| const upb_Extension* ext = | |
| upb_TaggedAuxPtr_TryGetExtension(in->aux_data[i]); | |
| if (!ext) continue; | |
| const upb_MiniTableField* f = upb_Extension_MiniTableField(ext); | |
| const upb_MiniTable* m2 = upb_MiniTable_SubMessage(f); | |
| upb_MessageValue val = upb_Extension_GetValue(ext); | |
| switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f)) { | |
| case kUpb_FieldMode_Array: { | |
| upb_Array* arr = (upb_Array*)val.array_val; | |
| if (arr) upb_Array_Freeze(arr, m2); | |
| break; | |
| } | |
| case kUpb_FieldMode_Map: | |
| UPB_UNREACHABLE(); | |
| break; | |
| case kUpb_FieldMode_Scalar: | |
| if (upb_MiniTableField_IsSubMessage(f)) { | |
| upb_Message* msg2 = (upb_Message*)val.msg_val; | |
| if (msg2) upb_Message_Freeze(msg2, m2); | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| bool upb_Message_NextSerializableField(const upb_Message* msg, | |
| const upb_MiniTable* mt, | |
| const upb_MiniTableField** f, | |
| uintptr_t* iter) { | |
| const size_t field_count = upb_MiniTable_FieldCount(mt); | |
| uintptr_t i = *iter; | |
| while (i < field_count) { | |
| const upb_MiniTableField* field = upb_MiniTable_GetFieldByIndex(mt, i); | |
| if (UPB_PRIVATE(_upb_Message_FieldIsSet)(msg, field)) { | |
| *f = field; | |
| *iter = i + 1; | |
| return true; | |
| } | |
| i++; | |
| } | |
| *iter = i; | |
| return false; | |
| } | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| bool upb_Message_NextWireFormatUnknown(const struct upb_Message* msg, | |
| struct upb_Arena** arena, | |
| upb_StringView* data, uintptr_t* iter) { | |
| upb_MessageUnknown unknown; | |
| if (!upb_Message_NextUnknown2(msg, &unknown, iter)) { | |
| return false; | |
| } | |
| if (unknown.type == kUpb_MessageUnknownType_StringView) { | |
| *data = unknown.value.bytes; | |
| return true; | |
| } | |
| UPB_ASSERT(unknown.type == kUpb_MessageUnknownType_NonCanonicalExtension); | |
| if (!*arena) { | |
| *arena = upb_Arena_New(); | |
| if (!*arena) { | |
| return false; | |
| } | |
| } | |
| upb_EncodeStatus status = | |
| upb_EncodeExtension(unknown.value.extension, *arena, data, | |
| /*encode_options=*/0); | |
| if (status != kUpb_EncodeStatus_Ok) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| static upb_FindUnknownRet2 upb_FindUnknownRet2_ParseError(void) { | |
| return (upb_FindUnknownRet2){.status = kUpb_FindUnknown_ParseError}; | |
| } | |
| upb_FindUnknownRet2 upb_Message_FindUnknown2(const struct upb_Message* msg, | |
| uint32_t field_number, | |
| int depth_limit) { | |
| depth_limit = depth_limit ? depth_limit : 100; | |
| upb_FindUnknownRet2 ret; | |
| ret.iter = kUpb_Message_UnknownBegin; | |
| while (upb_Message_NextUnknown2(msg, &ret.unknown, &ret.iter)) { | |
| if (ret.unknown.type == kUpb_MessageUnknownType_StringView) { | |
| upb_EpsCopyInputStream stream; | |
| const char* ptr = ret.unknown.value.bytes.data; | |
| upb_EpsCopyInputStream_Init(&stream, &ptr, ret.unknown.value.bytes.size); | |
| while (!upb_EpsCopyInputStream_IsDone(&stream, &ptr)) { | |
| uint32_t tag; | |
| const char* unknown_begin = ptr; | |
| ptr = upb_WireReader_ReadTag(ptr, &tag, &stream); | |
| if (!ptr) return upb_FindUnknownRet2_ParseError(); | |
| if (field_number == upb_WireReader_GetFieldNumber(tag)) { | |
| upb_StringView data; | |
| ret.status = kUpb_FindUnknown_Ok; | |
| upb_EpsCopyCapture capture; | |
| upb_EpsCopyCapture_Start(&capture, &stream, unknown_begin); | |
| ptr = _upb_WireReader_SkipValue(ptr, tag, depth_limit, &stream); | |
| if (!ptr || !upb_EpsCopyCapture_End(&capture, &stream, ptr, &data)) { | |
| return upb_FindUnknownRet2_ParseError(); | |
| } | |
| ret.unknown.value.bytes = data; | |
| return ret; | |
| } | |
| ptr = _upb_WireReader_SkipValue(ptr, tag, depth_limit, &stream); | |
| if (!ptr) return upb_FindUnknownRet2_ParseError(); | |
| } | |
| } else if (ret.unknown.type == | |
| kUpb_MessageUnknownType_NonCanonicalExtension) { | |
| uint32_t ext_field_number = upb_MiniTableField_Number( | |
| upb_Extension_MiniTableField(ret.unknown.value.extension)); | |
| if (ext_field_number == field_number) { | |
| ret.status = kUpb_FindUnknown_Ok; | |
| return ret; | |
| } | |
| } | |
| } | |
| ret.status = kUpb_FindUnknown_NotPresent; | |
| ret.unknown.type = kUpb_MessageUnknownType_StringView; | |
| ret.unknown.value.bytes.data = NULL; | |
| ret.unknown.value.bytes.size = 0; | |
| ret.iter = kUpb_Message_UnknownBegin; | |
| return ret; | |
| } | |
| upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown2( | |
| struct upb_Message* msg, struct upb_MessageUnknown* data, uintptr_t* iter, | |
| struct upb_Arena* arena) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| UPB_ASSERT(*iter != kUpb_Message_UnknownBegin); | |
| upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); | |
| UPB_ASSERT(in); | |
| UPB_ASSERT(*iter <= in->size); | |
| upb_TaggedAuxPtr unknown_ptr = in->aux_data[*iter - 1]; | |
| if (data->type == kUpb_MessageUnknownType_NonCanonicalExtension) { | |
| UPB_ASSERT(upb_TaggedAuxPtr_IsNonCanonicalExtension(unknown_ptr)); | |
| // When the unknown is a non-canonical extension, we just remove it from the | |
| // aux data array. | |
| in->aux_data[*iter - 1] = upb_TaggedAuxPtr_Null(); | |
| return upb_Message_NextUnknown2(msg, data, iter) | |
| ? kUpb_DeleteUnknown_IterUpdated | |
| : kUpb_DeleteUnknown_DeletedLast; | |
| } | |
| UPB_ASSERT(upb_TaggedAuxPtr_IsUnknownStringView(unknown_ptr)); | |
| upb_StringView* unknown = upb_TaggedPtrAux_StringViewRepr(unknown_ptr); | |
| UPB_ASSERT(data->type == kUpb_MessageUnknownType_StringView); | |
| upb_StringView* data_bytes = &data->value.bytes; | |
| if (unknown->data == data_bytes->data && unknown->size == data_bytes->size) { | |
| // Remove whole field | |
| in->aux_data[*iter - 1] = upb_TaggedAuxPtr_Null(); | |
| } else if (unknown->data == data_bytes->data) { | |
| // Strip prefix | |
| unknown->data += data_bytes->size; | |
| unknown->size -= data_bytes->size; | |
| *data_bytes = *unknown; | |
| return kUpb_DeleteUnknown_IterUpdated; | |
| } else if (unknown->data + unknown->size == | |
| data_bytes->data + data_bytes->size) { | |
| // Truncate existing field | |
| unknown->size -= data_bytes->size; | |
| if (!upb_TaggedAuxPtr_IsUnknownAliased(unknown_ptr)) { | |
| in->aux_data[*iter - 1] = | |
| upb_TaggedAuxPtr_MakeUnknownDataAliased(unknown); | |
| } | |
| } else { | |
| UPB_ASSERT(unknown->data < data_bytes->data && | |
| unknown->data + unknown->size > | |
| data_bytes->data + data_bytes->size); | |
| // Split in the middle | |
| upb_StringView* prefix = unknown; | |
| upb_StringView* suffix = upb_Arena_Malloc(arena, sizeof(upb_StringView)); | |
| if (!suffix) { | |
| return kUpb_DeleteUnknown_AllocFail; | |
| } | |
| if (!UPB_PRIVATE(_upb_Message_ReserveSlot)(msg, arena)) { | |
| return kUpb_DeleteUnknown_AllocFail; | |
| } | |
| in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); | |
| if (*iter != in->size) { | |
| // Shift later entries down so that unknown field ordering is preserved | |
| memmove(&in->aux_data[*iter + 1], &in->aux_data[*iter], | |
| sizeof(upb_TaggedAuxPtr) * (in->size - *iter)); | |
| } | |
| in->aux_data[*iter] = upb_TaggedAuxPtr_MakeUnknownDataAliased(suffix); | |
| if (!upb_TaggedAuxPtr_IsUnknownAliased(unknown_ptr)) { | |
| in->aux_data[*iter - 1] = upb_TaggedAuxPtr_MakeUnknownDataAliased(prefix); | |
| } | |
| in->size++; | |
| suffix->data = data_bytes->data + data_bytes->size; | |
| suffix->size = (prefix->data + prefix->size) - suffix->data; | |
| prefix->size = data_bytes->data - prefix->data; | |
| } | |
| return upb_Message_NextUnknown2(msg, data, iter) | |
| ? kUpb_DeleteUnknown_IterUpdated | |
| : kUpb_DeleteUnknown_DeletedLast; | |
| } | |
| upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown( | |
| struct upb_Message* msg, upb_StringView* data, uintptr_t* iter, | |
| struct upb_Arena* arena) { | |
| upb_MessageUnknown unknown; | |
| unknown.type = kUpb_MessageUnknownType_StringView; | |
| unknown.value.bytes = *data; | |
| upb_Message_DeleteUnknownStatus res = | |
| upb_Message_DeleteUnknown2(msg, &unknown, iter, arena); | |
| UPB_ASSERT(unknown.type == kUpb_MessageUnknownType_StringView); | |
| if (res == kUpb_DeleteUnknown_IterUpdated || | |
| res == kUpb_DeleteUnknown_DeletedLast) { | |
| // the unknown data remains the same on the result of | |
| // kUpb_DeleteUnknown_AllocFail. | |
| *data = unknown.value.bytes; | |
| } | |
| return res; | |
| } | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| // Must be last. | |
| #ifdef __cplusplus | |
| extern "C" { | |
| #endif | |
| bool upb_Message_IsEmpty(const upb_Message* msg, const upb_MiniTable* m) { | |
| if (upb_Message_ExtensionCount(msg)) return false; | |
| const upb_MiniTableField* f; | |
| upb_MessageValue v; | |
| size_t iter = kUpb_BaseField_Begin; | |
| return !UPB_PRIVATE(_upb_Message_NextBaseField)(msg, m, &f, &v, &iter); | |
| } | |
| static bool _upb_Array_IsEqual(const upb_Array* arr1, const upb_Array* arr2, | |
| upb_CType ctype, const upb_MiniTable* m, | |
| int options) { | |
| // Check for trivial equality. | |
| if (arr1 == arr2) return true; | |
| // Must have identical element counts. | |
| const size_t size1 = arr1 ? upb_Array_Size(arr1) : 0; | |
| const size_t size2 = arr2 ? upb_Array_Size(arr2) : 0; | |
| if (size1 != size2) return false; | |
| for (size_t i = 0; i < size1; i++) { | |
| const upb_MessageValue val1 = upb_Array_Get(arr1, i); | |
| const upb_MessageValue val2 = upb_Array_Get(arr2, i); | |
| if (!upb_MessageValue_IsEqual(val1, val2, ctype, m, options)) return false; | |
| } | |
| return true; | |
| } | |
| static bool _upb_Map_IsEqual(const upb_Map* map1, const upb_Map* map2, | |
| const upb_MiniTable* m, int options) { | |
| // Check for trivial equality. | |
| if (map1 == map2) return true; | |
| // Must have identical element counts, unless we are doing a partial | |
| // comparison. | |
| size_t size1 = map1 ? upb_Map_Size(map1) : 0; | |
| size_t size2 = map2 ? upb_Map_Size(map2) : 0; | |
| if (options & kUpb_CompareOption_Partial) { | |
| if (size1 < size2) return false; | |
| } else { | |
| if (size1 != size2) return false; | |
| } | |
| const upb_MiniTableField* f = upb_MiniTable_MapValue(m); | |
| const upb_MiniTable* m2_value = upb_MiniTable_SubMessage(f); | |
| const upb_CType ctype = upb_MiniTableField_CType(f); | |
| upb_MessageValue key, val1, val2; | |
| size_t iter = kUpb_Map_Begin; | |
| while (upb_Map_Next(map2, &key, &val2, &iter)) { | |
| if (!upb_Map_Get(map1, key, &val1)) return false; | |
| if (!upb_MessageValue_IsEqual(val1, val2, ctype, m2_value, options)) | |
| return false; | |
| } | |
| return true; | |
| } | |
| static bool _upb_Message_BaseFieldsArePartiallyEqual(const upb_Message* msg1, | |
| const upb_Message* msg2, | |
| const upb_MiniTable* m, | |
| int options) { | |
| size_t iter2 = kUpb_BaseField_Begin; | |
| const upb_MiniTableField* f2; | |
| upb_MessageValue val2; | |
| // Iterate through all base fields present/set in msg2 (expected). | |
| while (UPB_PRIVATE(_upb_Message_NextBaseField)(msg2, m, &f2, &val2, &iter2)) { | |
| // Get the corresponding field data from msg1 (actual). | |
| const void* src1 = UPB_PRIVATE(_upb_Message_DataPtr)(msg1, f2); | |
| upb_MessageValue val1; | |
| UPB_PRIVATE(_upb_MiniTableField_DataCopy)(f2, &val1, src1); | |
| // Verify presence in msg1 (actual): | |
| // - For fields with explicit presence, msg1 must also have the field set. | |
| // - For non-presence fields (proto3 scalars), msg1's field must not be | |
| // zero/default. | |
| if (upb_MiniTableField_HasPresence(f2)) { | |
| if (!upb_Message_HasBaseField(msg1, f2)) return false; | |
| } else { | |
| if (UPB_PRIVATE(_upb_MiniTableField_DataIsZero)(f2, src1)) return false; | |
| } | |
| const upb_MiniTable* subm = upb_MiniTable_SubMessage(f2); | |
| const upb_CType ctype = upb_MiniTableField_CType(f2); | |
| // Compare field values according to the field mode (array, map, or | |
| // scalar), passing comparison options recursively for submessages. | |
| bool eq; | |
| switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f2)) { | |
| case kUpb_FieldMode_Array: | |
| eq = _upb_Array_IsEqual(val1.array_val, val2.array_val, ctype, subm, | |
| options); | |
| break; | |
| case kUpb_FieldMode_Map: | |
| eq = _upb_Map_IsEqual(val1.map_val, val2.map_val, subm, options); | |
| break; | |
| case kUpb_FieldMode_Scalar: | |
| eq = upb_MessageValue_IsEqual(val1, val2, ctype, subm, options); | |
| break; | |
| } | |
| if (!eq) return false; | |
| } | |
| return true; | |
| } | |
| static bool _upb_Message_BaseFieldsAreEqual(const upb_Message* msg1, | |
| const upb_Message* msg2, | |
| const upb_MiniTable* m, | |
| int options) { | |
| // In partial comparison mode, we only check fields that are present in msg2 | |
| // (the expected message). Any extra fields present in msg1 (the actual | |
| // message) are ignored. | |
| if (options & kUpb_CompareOption_Partial) { | |
| return _upb_Message_BaseFieldsArePartiallyEqual(msg1, msg2, m, options); | |
| } | |
| // Iterate over all base fields for each message. | |
| // The order will always match if the messages are equal. | |
| size_t iter1 = kUpb_BaseField_Begin; | |
| size_t iter2 = kUpb_BaseField_Begin; | |
| for (;;) { | |
| const upb_MiniTableField *f1, *f2; | |
| upb_MessageValue val1, val2; | |
| const bool got1 = | |
| UPB_PRIVATE(_upb_Message_NextBaseField)(msg1, m, &f1, &val1, &iter1); | |
| const bool got2 = | |
| UPB_PRIVATE(_upb_Message_NextBaseField)(msg2, m, &f2, &val2, &iter2); | |
| if (got1 != got2) return false; // Must have identical field counts. | |
| if (!got1) return true; // Loop termination condition. | |
| if (f1 != f2) return false; // Must have identical fields set. | |
| const upb_MiniTable* subm = upb_MiniTable_SubMessage(f1); | |
| const upb_CType ctype = upb_MiniTableField_CType(f1); | |
| bool eq; | |
| switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f1)) { | |
| case kUpb_FieldMode_Array: | |
| eq = _upb_Array_IsEqual(val1.array_val, val2.array_val, ctype, subm, | |
| options); | |
| break; | |
| case kUpb_FieldMode_Map: | |
| eq = _upb_Map_IsEqual(val1.map_val, val2.map_val, subm, options); | |
| break; | |
| case kUpb_FieldMode_Scalar: | |
| eq = upb_MessageValue_IsEqual(val1, val2, ctype, subm, options); | |
| break; | |
| } | |
| if (!eq) return false; | |
| } | |
| } | |
| static bool _upb_Message_ExtensionsAreEqual(const upb_Message* msg1, | |
| const upb_Message* msg2, | |
| const upb_MiniTable* m, | |
| int options) { | |
| const upb_MiniTableExtension* e; | |
| upb_MessageValue val2; | |
| // Iterate over all extensions for msg2, and search msg1 for each extension. | |
| size_t count1 = 0; | |
| size_t iter2 = kUpb_Message_ExtensionBegin; | |
| while (upb_Message_NextExtension(msg2, &e, &val2, &iter2)) { | |
| const upb_Extension* ext1 = UPB_PRIVATE(_upb_Message_Getext)(msg1, e); | |
| if (!ext1) return false; | |
| count1++; | |
| const upb_MessageValue val1 = upb_Extension_GetValue(ext1); | |
| const upb_MiniTableField* f = &e->UPB_PRIVATE(field); | |
| const upb_MiniTable* subm = upb_MiniTableField_IsSubMessage(f) | |
| ? upb_MiniTableExtension_GetSubMessage(e) | |
| : NULL; | |
| const upb_CType ctype = upb_MiniTableField_CType(f); | |
| bool eq; | |
| switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(f)) { | |
| case kUpb_FieldMode_Array: | |
| eq = _upb_Array_IsEqual(val1.array_val, val2.array_val, ctype, subm, | |
| options); | |
| break; | |
| case kUpb_FieldMode_Map: | |
| UPB_UNREACHABLE(); | |
| break; | |
| case kUpb_FieldMode_Scalar: { | |
| eq = upb_MessageValue_IsEqual(val1, val2, ctype, subm, options); | |
| break; | |
| } | |
| } | |
| if (!eq) return false; | |
| } | |
| if (!(options & kUpb_CompareOption_Partial)) { | |
| // Must have identical extension counts (this catches the case where msg1 | |
| // has extensions that msg2 doesn't). | |
| if (count1 != upb_Message_ExtensionCount(msg1)) return false; | |
| } | |
| return true; | |
| } | |
| bool upb_Message_IsEqual(const upb_Message* msg1, const upb_Message* msg2, | |
| const upb_MiniTable* m, int options) { | |
| if (UPB_UNLIKELY(msg1 == msg2)) return true; | |
| if (!_upb_Message_BaseFieldsAreEqual(msg1, msg2, m, options)) return false; | |
| if (!_upb_Message_ExtensionsAreEqual(msg1, msg2, m, options)) return false; | |
| if (!(options & kUpb_CompareOption_IncludeUnknownFields)) return true; | |
| // The wire encoder enforces a maximum depth of 100 so we match that here. | |
| return _upb_Message_UnknownFieldsAreEqual(msg1, msg2, 100) == | |
| kUpb_UnknownCompareResult_Equal; | |
| } | |
| #include <setjmp.h> | |
| #include <stdint.h> | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| // Must be last. | |
| typedef struct upb_UnknownFields upb_UnknownFields; | |
| typedef struct { | |
| uint32_t tag; | |
| union { | |
| uint64_t varint; | |
| uint64_t uint64; | |
| uint32_t uint32; | |
| upb_StringView delimited; | |
| upb_UnknownFields* group; | |
| } data; | |
| } upb_UnknownField; | |
| struct upb_UnknownFields { | |
| size_t size; | |
| size_t capacity; | |
| upb_UnknownField* fields; | |
| }; | |
| typedef struct { | |
| upb_EpsCopyInputStream stream; | |
| upb_encstate encoder; // For encoding non-canonical extensions. | |
| upb_Arena* arena; | |
| upb_UnknownField* tmp; | |
| size_t tmp_size; | |
| int depth; | |
| upb_UnknownCompareResult status; | |
| jmp_buf err; | |
| } upb_UnknownField_Context; | |
| typedef struct { | |
| upb_UnknownField* arr_base; | |
| upb_UnknownField* arr_ptr; | |
| upb_UnknownField* arr_end; | |
| uint32_t last_tag; | |
| bool sorted; | |
| } upb_UnknownFields_Builder; | |
| UPB_NORETURN static void upb_UnknownFields_OutOfMemory( | |
| upb_UnknownField_Context* ctx) { | |
| ctx->status = kUpb_UnknownCompareResult_OutOfMemory; | |
| UPB_LONGJMP(ctx->err, 1); | |
| } | |
| static void upb_UnknownFields_Grow(upb_UnknownField_Context* ctx, | |
| upb_UnknownField** base, | |
| upb_UnknownField** ptr, | |
| upb_UnknownField** end) { | |
| size_t old = (*ptr - *base); | |
| size_t new; | |
| if (upb_MulOverflow((uint32_t)2, old, &new)) { | |
| upb_UnknownFields_OutOfMemory(ctx); | |
| } | |
| new = UPB_MAX(4, new); | |
| size_t new_bytes; | |
| if (upb_MulOverflow(new, sizeof(**base), &new_bytes)) { | |
| upb_UnknownFields_OutOfMemory(ctx); | |
| } | |
| *base = upb_Arena_Realloc(ctx->arena, *base, old * sizeof(**base), new_bytes); | |
| if (!*base) upb_UnknownFields_OutOfMemory(ctx); | |
| *ptr = *base + old; | |
| *end = *base + new; | |
| } | |
| // We have to implement our own sort here, since qsort() is not an in-order | |
| // sort. Here we use merge sort, the simplest in-order sort. | |
| static void upb_UnknownFields_Merge(upb_UnknownField* arr, size_t start, | |
| size_t mid, size_t end, | |
| upb_UnknownField* tmp) { | |
| memcpy(tmp, &arr[start], (end - start) * sizeof(*tmp)); | |
| upb_UnknownField* ptr1 = tmp; | |
| upb_UnknownField* end1 = &tmp[mid - start]; | |
| upb_UnknownField* ptr2 = &tmp[mid - start]; | |
| upb_UnknownField* end2 = &tmp[end - start]; | |
| upb_UnknownField* out = &arr[start]; | |
| while (ptr1 < end1 && ptr2 < end2) { | |
| if (ptr1->tag <= ptr2->tag) { | |
| *out++ = *ptr1++; | |
| } else { | |
| *out++ = *ptr2++; | |
| } | |
| } | |
| if (ptr1 < end1) { | |
| memcpy(out, ptr1, (end1 - ptr1) * sizeof(*out)); | |
| } else if (ptr2 < end2) { | |
| memcpy(out, ptr2, (end2 - ptr2) * sizeof(*out)); | |
| } | |
| } | |
| static void upb_UnknownFields_SortRecursive(upb_UnknownField* arr, size_t start, | |
| size_t end, upb_UnknownField* tmp) { | |
| if (end - start > 1) { | |
| size_t mid = start + ((end - start) / 2); | |
| upb_UnknownFields_SortRecursive(arr, start, mid, tmp); | |
| upb_UnknownFields_SortRecursive(arr, mid, end, tmp); | |
| upb_UnknownFields_Merge(arr, start, mid, end, tmp); | |
| } | |
| } | |
| static void upb_UnknownFields_Sort(upb_UnknownField_Context* ctx, | |
| upb_UnknownFields* fields) { | |
| if (ctx->tmp_size < fields->size) { | |
| size_t oldsize; | |
| if (upb_MulOverflow(sizeof(*ctx->tmp), ctx->tmp_size, &oldsize)) { | |
| upb_UnknownFields_OutOfMemory(ctx); | |
| } | |
| ctx->tmp_size = UPB_MAX(8, ctx->tmp_size); | |
| while (ctx->tmp_size < fields->size) { | |
| if (upb_MulOverflow((uint32_t)2, ctx->tmp_size, &ctx->tmp_size)) { | |
| upb_UnknownFields_OutOfMemory(ctx); | |
| } | |
| } | |
| size_t newsize; | |
| if (upb_MulOverflow(ctx->tmp_size, sizeof(*ctx->tmp), &newsize)) { | |
| upb_UnknownFields_OutOfMemory(ctx); | |
| } | |
| upb_UnknownField* tmp = upb_grealloc(ctx->tmp, oldsize, newsize); | |
| if (!tmp) { | |
| upb_UnknownFields_OutOfMemory(ctx); | |
| } | |
| ctx->tmp = tmp; | |
| } | |
| upb_UnknownFields_SortRecursive(fields->fields, 0, fields->size, ctx->tmp); | |
| } | |
| static upb_UnknownFields* upb_UnknownFields_BuildFromBuffer( | |
| upb_UnknownField_Context* ctx, const char** buf); | |
| // Combines two unknown fields into one. | |
| static void upb_CombineUnknownFields(upb_UnknownField_Context* ctx, | |
| upb_UnknownFields_Builder* builder, | |
| const char** buf) { | |
| upb_UnknownField* arr_base = builder->arr_base; | |
| upb_UnknownField* arr_ptr = builder->arr_ptr; | |
| upb_UnknownField* arr_end = builder->arr_end; | |
| const char* ptr = *buf; | |
| uint32_t last_tag = builder->last_tag; | |
| bool sorted = builder->sorted; | |
| // Parse the unknown field data. It is an invariant of the data structure that | |
| // unknown field data is valid, so parse errors here should be impossible. | |
| while (!upb_EpsCopyInputStream_IsDone(&ctx->stream, &ptr)) { | |
| uint32_t tag; | |
| ptr = upb_WireReader_ReadTag(ptr, &tag, &ctx->stream); | |
| UPB_ASSERT(tag <= UINT32_MAX); | |
| int wire_type = upb_WireReader_GetWireType(tag); | |
| if (wire_type == kUpb_WireType_EndGroup) break; | |
| if (tag < last_tag) sorted = false; | |
| last_tag = tag; | |
| if (arr_ptr == arr_end) { | |
| upb_UnknownFields_Grow(ctx, &arr_base, &arr_ptr, &arr_end); | |
| } | |
| upb_UnknownField* field = arr_ptr; | |
| field->tag = tag; | |
| arr_ptr++; | |
| switch (wire_type) { | |
| case kUpb_WireType_Varint: | |
| ptr = upb_WireReader_ReadVarint(ptr, &field->data.varint, &ctx->stream); | |
| UPB_ASSERT(ptr); | |
| break; | |
| case kUpb_WireType_64Bit: | |
| ptr = | |
| upb_WireReader_ReadFixed64(ptr, &field->data.uint64, &ctx->stream); | |
| UPB_ASSERT(ptr); | |
| break; | |
| case kUpb_WireType_32Bit: | |
| ptr = | |
| upb_WireReader_ReadFixed32(ptr, &field->data.uint32, &ctx->stream); | |
| UPB_ASSERT(ptr); | |
| break; | |
| case kUpb_WireType_Delimited: { | |
| int size; | |
| upb_StringView sv; | |
| ptr = upb_WireReader_ReadSize(ptr, &size, &ctx->stream); | |
| UPB_ASSERT(ptr); | |
| ptr = upb_EpsCopyInputStream_ReadStringAlwaysAlias(&ctx->stream, ptr, | |
| size, &sv); | |
| UPB_ASSERT(ptr); | |
| field->data.delimited.data = sv.data; | |
| field->data.delimited.size = sv.size; | |
| break; | |
| } | |
| case kUpb_WireType_StartGroup: | |
| if (--ctx->depth < 0) { | |
| ctx->status = kUpb_UnknownCompareResult_MaxDepthExceeded; | |
| UPB_LONGJMP(ctx->err, 1); | |
| } | |
| field->data.group = upb_UnknownFields_BuildFromBuffer(ctx, &ptr); | |
| ctx->depth++; | |
| break; | |
| default: | |
| UPB_UNREACHABLE(); | |
| } | |
| } | |
| *buf = ptr; | |
| builder->arr_base = arr_base; | |
| builder->arr_ptr = arr_ptr; | |
| builder->arr_end = arr_end; | |
| builder->sorted = sorted; | |
| builder->last_tag = last_tag; | |
| } | |
| static upb_UnknownFields* upb_UnknownFields_DoBuild( | |
| upb_UnknownField_Context* ctx, upb_UnknownFields_Builder* builder) { | |
| upb_UnknownFields* ret = upb_Arena_Malloc(ctx->arena, sizeof(*ret)); | |
| if (!ret) upb_UnknownFields_OutOfMemory(ctx); | |
| ret->fields = builder->arr_base; | |
| ret->size = builder->arr_ptr - builder->arr_base; | |
| ret->capacity = builder->arr_end - builder->arr_base; | |
| if (!builder->sorted) { | |
| upb_UnknownFields_Sort(ctx, ret); | |
| } | |
| return ret; | |
| } | |
| // Builds a upb_UnknownFields data structure from the binary data in buf. | |
| static upb_UnknownFields* upb_UnknownFields_BuildFromBuffer( | |
| upb_UnknownField_Context* ctx, const char** buf) { | |
| upb_UnknownFields_Builder builder = { | |
| .arr_base = NULL, | |
| .arr_ptr = NULL, | |
| .arr_end = NULL, | |
| .sorted = true, | |
| .last_tag = 0, | |
| }; | |
| const char* ptr = *buf; | |
| upb_CombineUnknownFields(ctx, &builder, &ptr); | |
| upb_UnknownFields* fields = upb_UnknownFields_DoBuild(ctx, &builder); | |
| *buf = ptr; | |
| return fields; | |
| } | |
| // Builds a upb_UnknownFields data structure from the unknown fields of a | |
| // upb_Message. | |
| static upb_UnknownFields* upb_UnknownFields_Build(upb_UnknownField_Context* ctx, | |
| const upb_Message* msg) { | |
| upb_UnknownFields_Builder builder = { | |
| .arr_base = NULL, | |
| .arr_ptr = NULL, | |
| .arr_end = NULL, | |
| .sorted = true, | |
| .last_tag = 0, | |
| }; | |
| uintptr_t iter = kUpb_Message_UnknownBegin; | |
| upb_MessageUnknown data; | |
| while (upb_Message_NextUnknown2(msg, &data, &iter)) { | |
| const char* ptr; | |
| size_t size; | |
| if (data.type == kUpb_MessageUnknownType_StringView) { | |
| upb_StringView view = data.value.bytes; | |
| ptr = view.data; | |
| size = view.size; | |
| } else { | |
| UPB_ASSERT(data.type == kUpb_MessageUnknownType_NonCanonicalExtension); | |
| char* enc_buf = upb_BackAlloc_Init(&ctx->encoder.alloc, ctx->arena); | |
| ctx->encoder.status = kUpb_EncodeStatus_Ok; | |
| // Encode non-canonical extension to buffer. | |
| const upb_Extension* ext = (const upb_Extension*)data.value.extension; | |
| bool is_message_set = false; | |
| const upb_MiniTableExtension* ext_mt = | |
| upb_Extension_MiniTableExtension(ext); | |
| const upb_MiniTable* extendee = upb_MiniTableExtension_Extendee(ext_mt); | |
| if (extendee) { | |
| is_message_set = upb_MiniTable_IsMessageSet(extendee); | |
| } | |
| UPB_PRIVATE(_upb_Encode_Extension)(&ctx->encoder, ext_mt, | |
| upb_Extension_GetValue(ext), | |
| is_message_set, &enc_buf, &size, | |
| /*options=*/0); | |
| ptr = enc_buf; | |
| } | |
| upb_EpsCopyInputStream_Init(&ctx->stream, &ptr, size); | |
| upb_CombineUnknownFields(ctx, &builder, &ptr); | |
| UPB_ASSERT(upb_EpsCopyInputStream_IsDone(&ctx->stream, &ptr) && | |
| !upb_EpsCopyInputStream_IsError(&ctx->stream)); | |
| } | |
| upb_UnknownFields* fields = upb_UnknownFields_DoBuild(ctx, &builder); | |
| return fields; | |
| } | |
| // Compares two sorted upb_UnknownFields structures for equality. | |
| static bool upb_UnknownFields_IsEqual(const upb_UnknownFields* uf1, | |
| const upb_UnknownFields* uf2) { | |
| if (uf1->size != uf2->size) return false; | |
| for (size_t i = 0, n = uf1->size; i < n; i++) { | |
| upb_UnknownField* f1 = &uf1->fields[i]; | |
| upb_UnknownField* f2 = &uf2->fields[i]; | |
| if (f1->tag != f2->tag) return false; | |
| int wire_type = f1->tag & 7; | |
| switch (wire_type) { | |
| case kUpb_WireType_Varint: | |
| if (f1->data.varint != f2->data.varint) return false; | |
| break; | |
| case kUpb_WireType_64Bit: | |
| if (f1->data.uint64 != f2->data.uint64) return false; | |
| break; | |
| case kUpb_WireType_32Bit: | |
| if (f1->data.uint32 != f2->data.uint32) return false; | |
| break; | |
| case kUpb_WireType_Delimited: | |
| if (!upb_StringView_IsEqual(f1->data.delimited, f2->data.delimited)) { | |
| return false; | |
| } | |
| break; | |
| case kUpb_WireType_StartGroup: | |
| if (!upb_UnknownFields_IsEqual(f1->data.group, f2->data.group)) { | |
| return false; | |
| } | |
| break; | |
| default: | |
| UPB_UNREACHABLE(); | |
| } | |
| } | |
| return true; | |
| } | |
| static upb_UnknownCompareResult upb_UnknownField_DoCompare( | |
| upb_UnknownField_Context* ctx, const upb_Message* msg1, | |
| const upb_Message* msg2) { | |
| upb_UnknownCompareResult ret; | |
| // First build both unknown fields into a sorted data structure (similar | |
| // to the UnknownFieldSet in C++). | |
| upb_UnknownFields* uf1 = upb_UnknownFields_Build(ctx, msg1); | |
| upb_UnknownFields* uf2 = upb_UnknownFields_Build(ctx, msg2); | |
| // Now perform the equality check on the sorted structures. | |
| if (upb_UnknownFields_IsEqual(uf1, uf2)) { | |
| ret = kUpb_UnknownCompareResult_Equal; | |
| } else { | |
| ret = kUpb_UnknownCompareResult_NotEqual; | |
| } | |
| return ret; | |
| } | |
| static upb_UnknownCompareResult upb_UnknownField_Compare( | |
| upb_UnknownField_Context* const ctx, const upb_Message* msg1, | |
| const upb_Message* msg2) { | |
| upb_UnknownCompareResult ret; | |
| if (UPB_SETJMP(ctx->err) == 0) { | |
| ret = upb_UnknownField_DoCompare(ctx, msg1, msg2); | |
| } else { | |
| // If status is still Equal, the jump must have originated from the Encoder | |
| // (which only updates ctx->encoder.status). We must map it to a context | |
| // error. | |
| if (ctx->status == kUpb_UnknownCompareResult_Equal) { | |
| if (ctx->encoder.status == kUpb_EncodeStatus_OutOfMemory) { | |
| ctx->status = kUpb_UnknownCompareResult_OutOfMemory; | |
| } else if (ctx->encoder.status == kUpb_EncodeStatus_MaxDepthExceeded) { | |
| ctx->status = kUpb_UnknownCompareResult_MaxDepthExceeded; | |
| } else { | |
| ctx->status = kUpb_UnknownCompareResult_OutOfMemory; | |
| } | |
| upb_BackAlloc_Abort(&ctx->encoder.alloc); | |
| } | |
| ret = ctx->status; | |
| UPB_ASSERT(ret != kUpb_UnknownCompareResult_Equal); | |
| } | |
| UPB_PRIVATE(_upb_encstate_destroy)(&ctx->encoder); | |
| upb_Arena_Free(ctx->arena); | |
| upb_gfree(ctx->tmp); | |
| return ret; | |
| } | |
| upb_UnknownCompareResult _upb_Message_UnknownFieldsAreEqual( | |
| const upb_Message* msg1, const upb_Message* msg2, int max_depth) { | |
| bool msg1_empty = !upb_Message_HasUnknown(msg1); | |
| bool msg2_empty = !upb_Message_HasUnknown(msg2); | |
| if (msg1_empty && msg2_empty) return kUpb_UnknownCompareResult_Equal; | |
| if (msg1_empty || msg2_empty) return kUpb_UnknownCompareResult_NotEqual; | |
| upb_UnknownField_Context ctx = { | |
| .arena = upb_Arena_New(), | |
| .depth = max_depth, | |
| .tmp = NULL, | |
| .tmp_size = 0, | |
| .status = kUpb_UnknownCompareResult_Equal, | |
| }; | |
| if (!ctx.arena) return kUpb_UnknownCompareResult_OutOfMemory; | |
| UPB_PRIVATE(_upb_encstate_init)(&ctx.encoder, &ctx.err, ctx.arena); | |
| return upb_UnknownField_Compare(&ctx, msg1, msg2); | |
| } | |
| #include <stdbool.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| static upb_StringView upb_Clone_StringView(upb_StringView str, | |
| upb_Arena* arena) { | |
| if (str.size == 0) { | |
| return upb_StringView_FromDataAndSize(NULL, 0); | |
| } | |
| void* cloned_data = upb_Arena_Malloc(arena, str.size); | |
| if (cloned_data == NULL) { | |
| return upb_StringView_FromDataAndSize(NULL, 0); | |
| } | |
| memcpy(cloned_data, str.data, str.size); | |
| return upb_StringView_FromDataAndSize(cloned_data, str.size); | |
| } | |
| static bool upb_Clone_MessageValue(void* value, upb_CType value_type, | |
| const upb_MiniTable* sub, upb_Arena* arena) { | |
| switch (value_type) { | |
| case kUpb_CType_Bool: | |
| case kUpb_CType_Float: | |
| case kUpb_CType_Int32: | |
| case kUpb_CType_UInt32: | |
| case kUpb_CType_Enum: | |
| case kUpb_CType_Double: | |
| case kUpb_CType_Int64: | |
| case kUpb_CType_UInt64: | |
| return true; | |
| case kUpb_CType_String: | |
| case kUpb_CType_Bytes: { | |
| upb_StringView source = *(upb_StringView*)value; | |
| size_t size = source.size; | |
| void* cloned_data = upb_Arena_Malloc(arena, size); | |
| if (cloned_data == NULL) { | |
| return false; | |
| } | |
| *(upb_StringView*)value = | |
| upb_StringView_FromDataAndSize(cloned_data, size); | |
| memcpy(cloned_data, source.data, size); | |
| return true; | |
| } break; | |
| case kUpb_CType_Message: { | |
| UPB_ASSERT(sub); | |
| const upb_Message* source = *(upb_Message**)value; | |
| UPB_ASSERT(source); | |
| upb_Message* clone = upb_Message_DeepClone(source, sub, arena); | |
| *(upb_Message**)value = clone; | |
| return clone != NULL; | |
| } break; | |
| } | |
| UPB_UNREACHABLE(); | |
| } | |
| static bool upb_Clone_MapValue(upb_value* tabval, size_t map_val_size, | |
| upb_CType value_field_type, | |
| const upb_MiniTable* value_sub, upb_Arena* arena, | |
| upb_value* cloned_tabval) { | |
| upb_MessageValue val; | |
| _upb_map_fromvalue(*tabval, &val, map_val_size); | |
| if (!upb_Clone_MessageValue(&val, value_field_type, value_sub, arena)) { | |
| return false; | |
| } | |
| *cloned_tabval = (upb_value){0}; // Initialize | |
| if (!_upb_map_tovalue(&val, map_val_size, cloned_tabval, arena)) { | |
| return false; | |
| } | |
| return true; | |
| } | |
| upb_Map* upb_Map_DeepClone(const upb_Map* map, upb_CType key_type, | |
| upb_CType value_type, | |
| const upb_MiniTable* map_entry_table, | |
| upb_Arena* arena) { | |
| upb_Map* cloned_map = upb_Arena_Malloc(arena, sizeof(upb_Map)); | |
| if (cloned_map == NULL) { | |
| return NULL; | |
| } | |
| cloned_map->key_size = map->key_size; | |
| cloned_map->val_size = map->val_size; | |
| cloned_map->UPB_PRIVATE(is_frozen) = false; | |
| cloned_map->UPB_PRIVATE(is_strtable) = map->UPB_PRIVATE(is_strtable); | |
| const upb_MiniTableField* value_field = | |
| upb_MiniTable_MapValue(map_entry_table); | |
| const upb_MiniTable* value_sub = upb_MiniTable_SubMessage(value_field); | |
| upb_CType value_field_type = upb_MiniTableField_CType(value_field); | |
| bool is_primitive = value_field_type != kUpb_CType_Message && | |
| value_field_type != kUpb_CType_String && | |
| value_field_type != kUpb_CType_Bytes; | |
| if (map->UPB_PRIVATE(is_strtable)) { | |
| if (!upb_strtable_copy(&cloned_map->t.strtable, &map->t.strtable, arena)) { | |
| return NULL; | |
| } | |
| if (!is_primitive) { | |
| intptr_t iter = UPB_STRTABLE_BEGIN; | |
| upb_StringView key; | |
| upb_value tabval; | |
| while ( | |
| upb_strtable_next2(&cloned_map->t.strtable, &key, &tabval, &iter)) { | |
| upb_value cloned_tabval; | |
| if (!upb_Clone_MapValue(&tabval, map->val_size, value_field_type, | |
| value_sub, arena, &cloned_tabval)) { | |
| return NULL; | |
| } | |
| upb_strtable_setentryvalue(&cloned_map->t.strtable, iter, | |
| cloned_tabval); | |
| } | |
| } | |
| } else { | |
| if (!upb_inttable_copy(&cloned_map->t.inttable, &map->t.inttable, arena)) { | |
| return NULL; | |
| } | |
| if (!is_primitive) { | |
| intptr_t iter = UPB_INTTABLE_BEGIN; | |
| uintptr_t key; | |
| upb_value tabval; | |
| while (upb_inttable_next(&cloned_map->t.inttable, &key, &tabval, &iter)) { | |
| upb_value cloned_tabval; | |
| if (!upb_Clone_MapValue(&tabval, map->val_size, value_field_type, | |
| value_sub, arena, &cloned_tabval)) { | |
| return NULL; | |
| } | |
| upb_inttable_setentryvalue(&cloned_map->t.inttable, iter, | |
| cloned_tabval); | |
| } | |
| } | |
| } | |
| return cloned_map; | |
| } | |
| static upb_Map* upb_Message_Map_DeepClone(const upb_Map* map, | |
| const upb_MiniTable* mini_table, | |
| const upb_MiniTableField* f, | |
| upb_Message* clone, | |
| upb_Arena* arena) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(clone)); | |
| const upb_MiniTable* map_entry_table = upb_MiniTable_MapEntrySubMessage(f); | |
| UPB_ASSERT(map_entry_table); | |
| const upb_MiniTableField* key_field = upb_MiniTable_MapKey(map_entry_table); | |
| const upb_MiniTableField* value_field = | |
| upb_MiniTable_MapValue(map_entry_table); | |
| upb_Map* cloned_map = upb_Map_DeepClone( | |
| map, upb_MiniTableField_CType(key_field), | |
| upb_MiniTableField_CType(value_field), map_entry_table, arena); | |
| if (!cloned_map) { | |
| return NULL; | |
| } | |
| upb_Message_SetBaseField(clone, f, &cloned_map); | |
| return cloned_map; | |
| } | |
| upb_Array* upb_Array_DeepClone(const upb_Array* array, upb_CType value_type, | |
| const upb_MiniTable* sub, upb_Arena* arena) { | |
| const size_t size = upb_Array_Size(array); | |
| const int lg2 = UPB_PRIVATE(_upb_CType_SizeLg2)(value_type); | |
| upb_Array* cloned_array = UPB_PRIVATE(_upb_Array_New)(arena, size, lg2); | |
| if (!cloned_array) { | |
| return NULL; | |
| } | |
| if (!UPB_PRIVATE(_upb_Array_ResizeUninitialized)(cloned_array, size, arena)) { | |
| return NULL; | |
| } | |
| for (size_t i = 0; i < size; ++i) { | |
| upb_MessageValue val = upb_Array_Get(array, i); | |
| if (!upb_Clone_MessageValue(&val, value_type, sub, arena)) { | |
| return NULL; | |
| } | |
| upb_Array_Set(cloned_array, i, val); | |
| } | |
| return cloned_array; | |
| } | |
| static bool upb_Message_Array_DeepClone(const upb_Array* array, | |
| const upb_MiniTable* mini_table, | |
| const upb_MiniTableField* field, | |
| upb_Message* clone, upb_Arena* arena) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(clone)); | |
| UPB_PRIVATE(_upb_MiniTableField_CheckIsArray)(field); | |
| upb_Array* cloned_array = | |
| upb_Array_DeepClone(array, upb_MiniTableField_CType(field), | |
| upb_MiniTableField_CType(field) == kUpb_CType_Message | |
| ? upb_MiniTable_GetSubMessageTable(field) | |
| : NULL, | |
| arena); | |
| if (!cloned_array) return false; | |
| // Clear out upb_Array* due to parent memcpy. | |
| upb_Message_SetBaseField(clone, field, &cloned_array); | |
| return true; | |
| } | |
| static bool upb_Clone_ExtensionValue(const upb_MiniTableField* field, | |
| const upb_Extension* source, | |
| upb_Extension* dest, upb_Arena* arena) { | |
| upb_MessageValue val = upb_Extension_GetValue(source); | |
| if (!upb_Clone_MessageValue(&val, upb_MiniTableField_CType(field), | |
| upb_MiniTable_SubMessage(field), arena)) { | |
| return false; | |
| } | |
| upb_Extension_SetValue(dest, val); | |
| return true; | |
| } | |
| upb_Message* _upb_Message_Copy(upb_Message* dst, const upb_Message* src, | |
| const upb_MiniTable* mini_table, | |
| upb_Arena* arena) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(dst)); | |
| upb_StringView empty_string = upb_StringView_FromDataAndSize(NULL, 0); | |
| // Only copy message area skipping upb_Message_Internal. | |
| memcpy(dst + 1, src + 1, mini_table->UPB_PRIVATE(size) - sizeof(upb_Message)); | |
| for (int i = 0; i < upb_MiniTable_FieldCount(mini_table); ++i) { | |
| const upb_MiniTableField* field = | |
| upb_MiniTable_GetFieldByIndex(mini_table, i); | |
| if (upb_MiniTableField_IsScalar(field)) { | |
| switch (upb_MiniTableField_CType(field)) { | |
| case kUpb_CType_Message: { | |
| const upb_Message* sub_message = upb_Message_GetMessage(src, field); | |
| if (sub_message != NULL) { | |
| const upb_MiniTable* sub_message_table = | |
| upb_MiniTable_GetSubMessageTable(field); | |
| upb_Message* dst_sub_message = | |
| upb_Message_DeepClone(sub_message, sub_message_table, arena); | |
| if (dst_sub_message == NULL) goto err; | |
| upb_Message_SetBaseFieldMessage(dst, field, dst_sub_message); | |
| } | |
| } break; | |
| case kUpb_CType_String: | |
| case kUpb_CType_Bytes: { | |
| upb_StringView str = upb_Message_GetString(src, field, empty_string); | |
| if (str.size != 0) { | |
| upb_StringView cloned_str = upb_Clone_StringView(str, arena); | |
| if (cloned_str.data == NULL) goto err; | |
| if (!upb_Message_SetString(dst, field, cloned_str, arena)) goto err; | |
| } | |
| } break; | |
| default: | |
| // Scalar, already copied. | |
| break; | |
| } | |
| } else { | |
| if (upb_MiniTableField_IsMap(field)) { | |
| const upb_Map* map = upb_Message_GetMap(src, field); | |
| if (map != NULL) { | |
| if (!upb_Message_Map_DeepClone(map, mini_table, field, dst, arena)) { | |
| goto err; | |
| } | |
| } | |
| } else { | |
| const upb_Array* array = upb_Message_GetArray(src, field); | |
| if (array != NULL) { | |
| if (!upb_Message_Array_DeepClone(array, mini_table, field, dst, | |
| arena)) { | |
| goto err; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| // Clone extensions. | |
| upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(src); | |
| if (!in) return dst; | |
| for (size_t i = 0; i < in->size; i++) { | |
| upb_TaggedAuxPtr tagged_ptr = in->aux_data[i]; | |
| if (upb_TaggedAuxPtr_IsExtension(tagged_ptr)) { | |
| // Clone a canonical or non-canonical upb_Extension*. | |
| const upb_Extension* msg_ext = upb_TaggedAuxPtr_Extension(tagged_ptr); | |
| const upb_MiniTableField* field = upb_Extension_MiniTableField(msg_ext); | |
| upb_Extension* dst_ext = | |
| UPB_PRIVATE(_upb_Message_GetOrCreateExtensionWithTag)( | |
| dst, upb_Extension_MiniTableExtension(msg_ext), arena, | |
| upb_TaggedAuxPtr_Type(tagged_ptr)); | |
| if (!dst_ext) goto err; | |
| if (upb_MiniTableField_IsScalar(field)) { | |
| if (!upb_Clone_ExtensionValue(field, msg_ext, dst_ext, arena)) { | |
| goto err; | |
| } | |
| } else { | |
| // Extensions (canonical or non-canonical) cannot be maps. | |
| UPB_ASSERT(upb_MiniTableField_IsArray(field)); | |
| const upb_Array* msg_array = upb_Extension_GetArray(msg_ext); | |
| UPB_ASSERT(msg_array); | |
| upb_Array* cloned_array = | |
| upb_Array_DeepClone(msg_array, upb_MiniTableField_CType(field), | |
| upb_MiniTable_SubMessage(field), arena); | |
| if (!cloned_array) goto err; | |
| upb_Extension_SetArray(dst_ext, cloned_array); | |
| } | |
| } else if (upb_TaggedAuxPtr_IsUnknownStringView(tagged_ptr)) { | |
| // Clone an aliased or non-aliased unknown upb_StringView. | |
| upb_StringView* unknown = upb_TaggedPtrAux_StringViewRepr(tagged_ptr); | |
| // Make a copy into destination arena. | |
| if (!UPB_PRIVATE(_upb_Message_AddUnknown)( | |
| dst, unknown->data, unknown->size, arena, kUpb_AddUnknown_Copy)) { | |
| goto err; | |
| } | |
| } | |
| } | |
| return dst; | |
| err: | |
| upb_Message_Clear(dst, mini_table); | |
| return NULL; | |
| } | |
| bool upb_Message_DeepCopy(upb_Message* dst, const upb_Message* src, | |
| const upb_MiniTable* mini_table, upb_Arena* arena) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(dst)); | |
| upb_Message_Clear(dst, mini_table); | |
| return _upb_Message_Copy(dst, src, mini_table, arena) != NULL; | |
| } | |
| // Deep clones a message using the provided target arena. | |
| // | |
| // Returns NULL on failure. | |
| upb_Message* upb_Message_DeepClone(const upb_Message* msg, | |
| const upb_MiniTable* m, upb_Arena* arena) { | |
| upb_Message* clone = upb_Message_New(m, arena); | |
| if (!clone) return NULL; | |
| return _upb_Message_Copy(clone, msg, m, arena); | |
| } | |
| // Performs a shallow copy. | |
| bool upb_Message_ShallowCopy(upb_Message* dst, const upb_Message* src, | |
| const upb_MiniTable* m, upb_Arena* arena) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(dst)); | |
| memcpy(dst, src, m->UPB_PRIVATE(size)); | |
| return UPB_PRIVATE(_upb_Message_CopyInternal)(dst, src, arena); | |
| } | |
| // Performs a shallow clone. | |
| upb_Message* upb_Message_ShallowClone(const upb_Message* msg, | |
| const upb_MiniTable* m, | |
| upb_Arena* arena) { | |
| upb_Message* clone = upb_Message_New(m, arena); | |
| if (!clone) return NULL; | |
| if (!upb_Message_ShallowCopy(clone, msg, m, arena)) return NULL; | |
| return clone; | |
| } | |
| #include "stddef.h" | |
| // Must be last. | |
| bool upb_Message_MergeFrom(upb_Message* dst, const upb_Message* src, | |
| const upb_MiniTable* mt, | |
| const upb_ExtensionRegistry* extreg, | |
| upb_Arena* arena) { | |
| char* buf = NULL; | |
| size_t size = 0; | |
| // This tmp arena is used to hold the bytes for `src` serialized. This bends | |
| // the typical "no hidden allocations" design of upb, but under a properly | |
| // optimized implementation this extra allocation would not be necessary and | |
| // so we don't want to unnecessarily have the bad API or bloat the passed-in | |
| // arena with this very-short-term allocation. | |
| upb_Arena* encode_arena = upb_Arena_New(); | |
| if (!encode_arena) return false; | |
| upb_EncodeStatus e_status = upb_Encode(src, mt, 0, encode_arena, &buf, &size); | |
| if (e_status != kUpb_EncodeStatus_Ok) { | |
| upb_Arena_Free(encode_arena); | |
| return false; | |
| } | |
| upb_DecodeStatus d_status = upb_Decode(buf, size, dst, mt, extreg, 0, arena); | |
| if (d_status != kUpb_DecodeStatus_Ok) { | |
| upb_Arena_Free(encode_arena); | |
| return false; | |
| } | |
| upb_Arena_Free(encode_arena); | |
| return true; | |
| } | |
| #include <stdint.h> | |
| // Must be last. | |
| const upb_Extension* UPB_PRIVATE(_upb_Message_Getext)( | |
| const struct upb_Message* msg, const upb_MiniTableExtension* e) { | |
| upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); | |
| if (!in) return NULL; | |
| for (size_t i = 0; i < in->size; i++) { | |
| upb_TaggedAuxPtr tagged_ptr = in->aux_data[i]; | |
| if (upb_TaggedAuxPtr_IsCanonicalExtension(tagged_ptr)) { | |
| const upb_Extension* ext = | |
| upb_TaggedAuxPtr_CanonicalExtension(tagged_ptr); | |
| if (upb_Extension_MiniTableExtension(ext) == e) { | |
| return ext; | |
| } | |
| } | |
| } | |
| return NULL; | |
| } | |
| upb_Extension* UPB_PRIVATE(_upb_Message_GetOrCreateExtensionWithTag)( | |
| struct upb_Message* msg, const upb_MiniTableExtension* e, upb_Arena* a, | |
| upb_TaggedAuxType tag) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| UPB_ASSERT(!upb_MiniTableField_IsMap(upb_MiniTableExtension_ToField(e))); | |
| // For Canonical Extensions, we check whether the extension has already been | |
| // set. If we find an extension with the same pointer and tag, we reuse it to | |
| // prevent duplicate entries for the same extension. | |
| // | |
| // For Non-Canonical Extensions, we do NOT reuse them, matching the behavior | |
| // of adding a unknown StringView (through `_upb_Message_AddUnknown`) which | |
| // accumulates. | |
| if (tag == kUpb_TaggedAuxType_CanonicalExtension) { | |
| upb_Extension* ext = | |
| (upb_Extension*)UPB_PRIVATE(_upb_Message_Getext)(msg, e); | |
| if (ext) return ext; | |
| } | |
| if (!UPB_PRIVATE(_upb_Message_ReserveSlot)(msg, a)) return NULL; | |
| upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); | |
| upb_Extension* ext = UPB_PRIVATE(_upb_Extension_New)(e, a); | |
| if (!ext) return NULL; | |
| in->aux_data[in->size++] = upb_TaggedAuxPtr_MakeExtension(ext, tag); | |
| return ext; | |
| } | |
| upb_Extension* UPB_PRIVATE(_upb_Message_GetOrCreateExtension)( | |
| struct upb_Message* msg, const upb_MiniTableExtension* e, upb_Arena* a) { | |
| return UPB_PRIVATE(_upb_Message_GetOrCreateExtensionWithTag)( | |
| msg, e, a, kUpb_TaggedAuxType_CanonicalExtension); | |
| } | |
| upb_Extension* UPB_PRIVATE(_upb_Message_CreateNonCanonicalExtension)( | |
| struct upb_Message* msg, const upb_MiniTableExtension* e, upb_Arena* a) { | |
| return UPB_PRIVATE(_upb_Message_GetOrCreateExtensionWithTag)( | |
| msg, e, a, kUpb_TaggedAuxType_NonCanonicalExtension); | |
| } | |
| #include <math.h> | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| // The latest win32 SDKs have an invalid definition of NAN. | |
| // https://developercommunity.visualstudio.com/t/NAN-is-no-longer-compile-time-constant-i/10688907 | |
| // | |
| // Unfortunately, the `0.0 / 0.0` workaround doesn't work in Clang under C23, so | |
| // try __builtin_nan first, if that exists. | |
| #ifdef _WIN32 | |
| #ifdef __has_builtin | |
| #if __has_builtin(__builtin_nan) | |
| #define UPB_NAN __builtin_nan("0") | |
| #endif | |
| #if __has_builtin(__builtin_inf) | |
| #define UPB_INFINITY __builtin_inf() | |
| #endif | |
| #endif | |
| #ifndef UPB_NAN | |
| #define UPB_NAN 0.0 / 0.0 | |
| #endif | |
| #ifndef UPB_INFINITY | |
| #define UPB_INFINITY 1.0 / 0.0 | |
| #endif | |
| #else | |
| // For !_WIN32, assume math.h works. | |
| #define UPB_NAN NAN | |
| #define UPB_INFINITY INFINITY | |
| #endif | |
| const float kUpb_FltInfinity = UPB_INFINITY; | |
| const double kUpb_Infinity = UPB_INFINITY; | |
| const double kUpb_NaN = UPB_NAN; | |
| UPB_INLINE size_t _upb_Message_InternalBlockSize(uint32_t count) { | |
| size_t bytes = UPB_SIZEOF_FLEX(upb_Message_Internal, aux_data, count); | |
| return upb_RoundUpToPowerOfTwo( | |
| UPB_MAX(bytes, UPB_PRIVATE(kUpb_Arena_MinPoolBlockSize))); | |
| } | |
| UPB_INLINE uint32_t _upb_Message_InternalCapacity(size_t block_bytes) { | |
| size_t capacity = | |
| UPB_FLEX_CAPACITY(upb_Message_Internal, aux_data, block_bytes); | |
| if (capacity > UINT32_MAX) { | |
| return UINT32_MAX; | |
| } | |
| return (uint32_t)capacity; | |
| } | |
| bool UPB_PRIVATE(_upb_Message_ReserveSlot)(struct upb_Message* msg, | |
| upb_Arena* a) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); | |
| if (!in) { | |
| // No internal data, allocate from scratch. | |
| size_t block_bytes = _upb_Message_InternalBlockSize(1); | |
| in = (upb_Message_Internal*)upb_Arena_AllocPool(a, block_bytes); | |
| if (!in) return false; | |
| in->size = 0; | |
| in->capacity = _upb_Message_InternalCapacity(block_bytes); | |
| UPB_PRIVATE(_upb_Message_SetInternal)(msg, in); | |
| } else if (in->capacity == in->size) { | |
| if (in->size == UINT32_MAX) return false; | |
| // Internal data is too small, reallocate. | |
| if (UPB_SIZEOF_FLEX_WOULD_OVERFLOW(upb_Message_Internal, aux_data, | |
| in->size + 1)) { | |
| return false; | |
| } | |
| size_t old_bytes = | |
| UPB_SIZEOF_FLEX(upb_Message_Internal, aux_data, in->capacity); | |
| size_t new_bytes = _upb_Message_InternalBlockSize(in->size + 1); | |
| if (new_bytes == SIZE_MAX || | |
| _upb_Message_InternalCapacity(new_bytes) > UINT32_MAX) { | |
| return false; | |
| } | |
| if (upb_Arena_TryExtend(a, in, old_bytes, new_bytes)) { | |
| in->capacity = _upb_Message_InternalCapacity(new_bytes); | |
| } else { | |
| upb_Message_Internal* new_in = | |
| (upb_Message_Internal*)upb_Arena_AllocPool(a, new_bytes); | |
| if (!new_in) return false; | |
| memcpy(new_in, in, | |
| UPB_SIZEOF_FLEX(upb_Message_Internal, aux_data, in->size)); | |
| new_in->capacity = _upb_Message_InternalCapacity(new_bytes); | |
| UPB_PRIVATE(_upb_Arena_Harvest)(a, in, old_bytes); | |
| in = new_in; | |
| UPB_PRIVATE(_upb_Message_SetInternal)(msg, in); | |
| } | |
| } | |
| UPB_ASSERT(in->capacity - in->size >= 1); | |
| return true; | |
| } | |
| bool UPB_PRIVATE(_upb_Message_CopyInternal)(struct upb_Message* dst, | |
| const struct upb_Message* src, | |
| upb_Arena* arena) { | |
| const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(src); | |
| if (!in) return true; | |
| size_t needed_bytes = | |
| UPB_SIZEOF_FLEX(upb_Message_Internal, aux_data, in->size); | |
| size_t block_bytes = _upb_Message_InternalBlockSize(in->size); | |
| upb_Message_Internal* dst_in = NULL; | |
| if (block_bytes != SIZE_MAX) { | |
| dst_in = (upb_Message_Internal*)upb_Arena_TryAllocPool(arena, block_bytes); | |
| } | |
| if (!dst_in) { | |
| block_bytes = needed_bytes; | |
| dst_in = upb_Arena_Malloc(arena, block_bytes); | |
| if (!dst_in) return false; | |
| } | |
| dst_in->size = 0; | |
| dst_in->capacity = _upb_Message_InternalCapacity(block_bytes); | |
| for (size_t i = 0; i < in->size; i++) { | |
| upb_TaggedAuxPtr tagged_ptr = in->aux_data[i]; | |
| if (upb_TaggedAuxPtr_IsExtension(tagged_ptr)) { | |
| const upb_Extension* msg_ext = upb_TaggedAuxPtr_Extension(tagged_ptr); | |
| upb_Extension* dst_ext = | |
| UPB_PRIVATE(_upb_Extension_Clone)(msg_ext, arena); | |
| if (!dst_ext) return false; | |
| dst_in->aux_data[dst_in->size++] = upb_TaggedAuxPtr_MakeExtension( | |
| dst_ext, upb_TaggedAuxPtr_Type(tagged_ptr)); | |
| } else if (upb_TaggedAuxPtr_IsUnknownStringView(tagged_ptr)) { | |
| upb_StringView* dst_sv = upb_Arena_Malloc(arena, sizeof(upb_StringView)); | |
| if (!dst_sv) return false; | |
| *dst_sv = *upb_TaggedPtrAux_StringViewRepr(tagged_ptr); | |
| dst_in->aux_data[dst_in->size++] = | |
| upb_TaggedAuxPtr_MakeUnknownDataAliased(dst_sv); | |
| } | |
| } | |
| UPB_PRIVATE(_upb_Message_SetInternal)(dst, dst_in); | |
| return true; | |
| } | |
| #ifdef UPB_TRACING_ENABLED | |
| static void (*_message_trace_handler)(const upb_MiniTable*, const upb_Arena*); | |
| void upb_Message_LogNewMessage(const upb_MiniTable* m, const upb_Arena* arena) { | |
| if (_message_trace_handler) { | |
| _message_trace_handler(m, arena); | |
| } | |
| } | |
| void upb_Message_SetNewMessageTraceHandler(void (*handler)(const upb_MiniTable*, | |
| const upb_Arena*)) { | |
| _message_trace_handler = handler; | |
| } | |
| #endif // UPB_TRACING_ENABLED | |
| #include <stddef.h> | |
| // Must be last. | |
| bool UPB_PRIVATE(_upb_Message_NextBaseField)(const upb_Message* msg, | |
| const upb_MiniTable* m, | |
| const upb_MiniTableField** out_f, | |
| upb_MessageValue* out_v, | |
| size_t* iter) { | |
| const size_t count = upb_MiniTable_FieldCount(m); | |
| size_t i = *iter; | |
| while (++i < count) { | |
| const upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, i); | |
| const void* src = UPB_PRIVATE(_upb_Message_DataPtr)(msg, f); | |
| upb_MessageValue val; | |
| UPB_PRIVATE(_upb_MiniTableField_DataCopy)(f, &val, src); | |
| // Skip field if unset or empty. | |
| if (upb_MiniTableField_HasPresence(f)) { | |
| if (!upb_Message_HasBaseField(msg, f)) continue; | |
| } else { | |
| if (UPB_PRIVATE(_upb_MiniTableField_DataIsZero)(f, src)) continue; | |
| if (upb_MiniTableField_IsArray(f)) { | |
| if (upb_Array_Size(val.array_val) == 0) continue; | |
| } else if (upb_MiniTableField_IsMap(f)) { | |
| if (upb_Map_Size(val.map_val) == 0) continue; | |
| } | |
| } | |
| *out_f = f; | |
| *out_v = val; | |
| *iter = i; | |
| return true; | |
| } | |
| return false; | |
| } | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| // Must be last. | |
| typedef struct { | |
| upb_MdDecoder base; | |
| upb_Arena* arena; | |
| upb_MiniTableEnum* enum_table; | |
| uint32_t enum_value_count; | |
| uint32_t enum_data_count; | |
| uint32_t enum_data_capacity; | |
| } upb_MdEnumDecoder; | |
| static size_t upb_MiniTableEnum_Size(uint32_t count) { | |
| return UPB_SIZEOF_FLEX(upb_MiniTableEnum, UPB_PRIVATE(data), count); | |
| } | |
| static upb_MiniTableEnum* _upb_MiniTable_AddEnumDataMember(upb_MdEnumDecoder* d, | |
| uint32_t val) { | |
| if (d->enum_data_count == d->enum_data_capacity) { | |
| size_t old_sz = upb_MiniTableEnum_Size(d->enum_data_capacity); | |
| if (d->enum_data_capacity > UINT32_MAX / 2) { | |
| upb_MdDecoder_ErrorJmp(&d->base, "Out of memory"); | |
| } | |
| uint32_t new_capacity = UPB_MAX(2, d->enum_data_capacity * 2); | |
| if (UPB_SIZEOF_FLEX_WOULD_OVERFLOW(upb_MiniTableEnum, UPB_PRIVATE(data), | |
| new_capacity)) { | |
| upb_MdDecoder_ErrorJmp(&d->base, "Out of memory"); | |
| } | |
| size_t new_sz = upb_MiniTableEnum_Size(new_capacity); | |
| d->enum_table = upb_Arena_Realloc(d->arena, d->enum_table, old_sz, new_sz); | |
| upb_MdDecoder_CheckOutOfMemory(&d->base, d->enum_table); | |
| d->enum_data_capacity = new_capacity; | |
| } | |
| d->enum_table->UPB_PRIVATE(data)[d->enum_data_count++] = val; | |
| return d->enum_table; | |
| } | |
| static void upb_MiniTableEnum_BuildValue(upb_MdEnumDecoder* d, uint32_t val) { | |
| upb_MiniTableEnum* table = d->enum_table; | |
| d->enum_value_count++; | |
| if (table->UPB_PRIVATE(value_count) || | |
| (val > 512 && d->enum_value_count < val / 32)) { | |
| if (table->UPB_PRIVATE(value_count) == 0) { | |
| UPB_ASSERT(d->enum_data_count == table->UPB_PRIVATE(mask_limit) / 32); | |
| } | |
| table = _upb_MiniTable_AddEnumDataMember(d, val); | |
| table->UPB_PRIVATE(value_count)++; | |
| } else { | |
| uint32_t new_mask_limit = ((val / 32) + 1) * 32; | |
| while (table->UPB_PRIVATE(mask_limit) < new_mask_limit) { | |
| table = _upb_MiniTable_AddEnumDataMember(d, 0); | |
| table->UPB_PRIVATE(mask_limit) += 32; | |
| } | |
| table->UPB_PRIVATE(data)[val / 32] |= 1ULL << (val % 32); | |
| } | |
| } | |
| static upb_MiniTableEnum* upb_MtDecoder_DoBuildMiniTableEnum( | |
| upb_MdEnumDecoder* d, const char* data, size_t len) { | |
| // If the string is non-empty then it must begin with a version tag. | |
| if (len) { | |
| if (*data != kUpb_EncodedVersion_EnumV1) { | |
| upb_MdDecoder_ErrorJmp(&d->base, "Invalid enum version: %c", *data); | |
| } | |
| data++; | |
| len--; | |
| } | |
| upb_MdDecoder_CheckOutOfMemory(&d->base, d->enum_table); | |
| // Guarantee at least 64 bits of mask without checking mask size. | |
| d->enum_table->UPB_PRIVATE(mask_limit) = 64; | |
| d->enum_table = _upb_MiniTable_AddEnumDataMember(d, 0); | |
| d->enum_table = _upb_MiniTable_AddEnumDataMember(d, 0); | |
| d->enum_table->UPB_PRIVATE(value_count) = 0; | |
| const char* ptr = data; | |
| uint32_t base = 0; | |
| while (ptr < d->base.end) { | |
| char ch = *ptr++; | |
| if (ch <= kUpb_EncodedValue_MaxEnumMask) { | |
| uint32_t mask = _upb_FromBase92(ch); | |
| for (int i = 0; i < 5; i++, base++, mask >>= 1) { | |
| if (mask & 1) upb_MiniTableEnum_BuildValue(d, base); | |
| } | |
| } else if (kUpb_EncodedValue_MinSkip <= ch && | |
| ch <= kUpb_EncodedValue_MaxSkip) { | |
| uint32_t skip; | |
| ptr = upb_MdDecoder_DecodeBase92Varint(&d->base, ptr, ch, | |
| kUpb_EncodedValue_MinSkip, | |
| kUpb_EncodedValue_MaxSkip, &skip); | |
| base += skip; | |
| } else { | |
| upb_MdDecoder_ErrorJmp(&d->base, "Unexpected character: %c", ch); | |
| } | |
| } | |
| return d->enum_table; | |
| } | |
| static upb_MiniTableEnum* upb_MtDecoder_BuildMiniTableEnum( | |
| upb_MdEnumDecoder* const decoder, const char* const data, | |
| size_t const len) { | |
| if (UPB_SETJMP(decoder->base.err) != 0) return NULL; | |
| return upb_MtDecoder_DoBuildMiniTableEnum(decoder, data, len); | |
| } | |
| upb_MiniTableEnum* upb_MiniTableEnum_Build(const char* data, size_t len, | |
| upb_Arena* arena, | |
| upb_Status* status) { | |
| uint32_t initial_capacity = 2; | |
| upb_MdEnumDecoder decoder = { | |
| .base = | |
| { | |
| .end = UPB_PTRADD(data, len), | |
| .status = status, | |
| }, | |
| .arena = arena, | |
| .enum_table = | |
| upb_Arena_Malloc(arena, upb_MiniTableEnum_Size(initial_capacity)), | |
| .enum_value_count = 0, | |
| .enum_data_count = 0, | |
| .enum_data_capacity = initial_capacity, | |
| }; | |
| return upb_MtDecoder_BuildMiniTableEnum(&decoder, data, len); | |
| } | |
| #include <inttypes.h> | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| // Our awkward dance for including fasttable only when it is enabled. | |
| #if UPB_FASTTABLE | |
| #define UPB_INCLUDE_FAST_DECODE | |
| #endif | |
| #ifdef UPB_INCLUDE_FAST_DECODE | |
| #endif | |
| #undef UPB_INCLUDE_FAST_DECODE | |
| // Must be last. | |
| // We reserve unused hasbits to make room for upb_Message fields. | |
| #define kUpb_Reserved_Hasbytes sizeof(struct upb_Message) | |
| // 64 is the first hasbit that we currently use. | |
| #define kUpb_Reserved_Hasbits (kUpb_Reserved_Hasbytes * 8) | |
| #define kUpb_OneOfLayoutItem_IndexSentinel ((uint16_t)-1) | |
| // Stores the field number of the present value of the oneof | |
| #define kUpb_OneOf_CaseFieldRep (kUpb_FieldRep_4Byte) | |
| // The maximum field number that can be encoded on the wire. | |
| // Note that this limit does not apply to MessageSet, which can have field | |
| // numbers up to INT32_MAX. | |
| #define kUpb_MaxFieldNumber ((1 << 29) - 1) | |
| typedef struct { | |
| // Index of the corresponding field. The field's offset will be the index of | |
| // the next field in a linked list. | |
| uint16_t field_index; | |
| // This enum is stored in bytes to avoid trailing padding while preserving | |
| // two-byte alignment. | |
| uint8_t /* upb_FieldRep*/ rep; | |
| } upb_OneOfLayoutItem; | |
| typedef struct { | |
| upb_OneOfLayoutItem* data; | |
| size_t size; | |
| size_t buf_capacity_bytes; | |
| } upb_OneOfLayoutItemVector; | |
| typedef struct { | |
| upb_MdDecoder base; | |
| upb_MiniTableField* fields; | |
| upb_MiniTablePlatform platform; | |
| upb_OneOfLayoutItemVector oneofs; | |
| upb_Arena* arena; | |
| // Initially tracks the count of each field rep type; then, during assignment, | |
| // tracks the base offset for the next processed field of the given rep. | |
| uint16_t rep_counts_offsets[kUpb_FieldRep_Max + 1]; | |
| uint32_t sub_count; | |
| bool is_extension; | |
| // When building fasttables, we don't know the total size of the table until | |
| // we're done decoding, so we allocate a temporary table on the stack and | |
| // allocate the real thing from the arena later. | |
| upb_MiniTable table; | |
| } upb_MtDecoder; | |
| // In each field's offset, we temporarily store a presence classifier: | |
| enum PresenceClass { | |
| kNoPresence = 0, | |
| kHasbitPresence = 1, | |
| kRequiredPresence = 2, | |
| kOneofBase = 3, | |
| // Negative values refer to a specific oneof with that number. Positive | |
| // values >= kOneofBase indicate that this field is in a oneof, and specify | |
| // the next field in this oneof's linked list. | |
| }; | |
| static bool upb_MtDecoder_FieldIsPackable(upb_MiniTableField* field) { | |
| return (field->UPB_PRIVATE(mode) & kUpb_FieldMode_Array) && | |
| upb_FieldType_IsPackable(field->UPB_PRIVATE(descriptortype)); | |
| } | |
| typedef struct { | |
| uint16_t submsg_count; | |
| uint16_t subenum_count; | |
| } upb_SubCounts; | |
| static void upb_MiniTable_SetTypeAndSub(upb_MtDecoder* d, | |
| upb_MiniTableField* field, | |
| upb_FieldType type, | |
| uint64_t msg_modifiers, | |
| bool is_proto3_enum) { | |
| if (is_proto3_enum) { | |
| UPB_ASSERT(type == kUpb_FieldType_Enum); | |
| type = kUpb_FieldType_Int32; | |
| field->UPB_PRIVATE(mode) |= kUpb_LabelFlags_IsAlternate; | |
| } else if (type == kUpb_FieldType_String && | |
| !(msg_modifiers & kUpb_MessageModifier_ValidateUtf8)) { | |
| type = kUpb_FieldType_Bytes; | |
| field->UPB_PRIVATE(mode) |= kUpb_LabelFlags_IsAlternate; | |
| } | |
| field->UPB_PRIVATE(descriptortype) = type; | |
| if (upb_MtDecoder_FieldIsPackable(field) && | |
| (msg_modifiers & kUpb_MessageModifier_DefaultIsPacked)) { | |
| field->UPB_PRIVATE(mode) |= kUpb_LabelFlags_IsPacked; | |
| } | |
| // We initially set `submsg_ofs` to the index of the sub in the list of subs. | |
| // Later, we'll update it to be a relative byte offset. | |
| if (UPB_PRIVATE(_upb_MiniTableField_HasSub)(field)) { | |
| field->UPB_PRIVATE(submsg_ofs) = d->sub_count++; | |
| } else { | |
| field->UPB_PRIVATE(submsg_ofs) = kUpb_NoSub; | |
| } | |
| } | |
| static const char kUpb_EncodedToType[] = { | |
| [kUpb_EncodedType_Double] = kUpb_FieldType_Double, | |
| [kUpb_EncodedType_Float] = kUpb_FieldType_Float, | |
| [kUpb_EncodedType_Int64] = kUpb_FieldType_Int64, | |
| [kUpb_EncodedType_UInt64] = kUpb_FieldType_UInt64, | |
| [kUpb_EncodedType_Int32] = kUpb_FieldType_Int32, | |
| [kUpb_EncodedType_Fixed64] = kUpb_FieldType_Fixed64, | |
| [kUpb_EncodedType_Fixed32] = kUpb_FieldType_Fixed32, | |
| [kUpb_EncodedType_Bool] = kUpb_FieldType_Bool, | |
| [kUpb_EncodedType_String] = kUpb_FieldType_String, | |
| [kUpb_EncodedType_Group] = kUpb_FieldType_Group, | |
| [kUpb_EncodedType_Message] = kUpb_FieldType_Message, | |
| [kUpb_EncodedType_Bytes] = kUpb_FieldType_Bytes, | |
| [kUpb_EncodedType_UInt32] = kUpb_FieldType_UInt32, | |
| [kUpb_EncodedType_OpenEnum] = kUpb_FieldType_Enum, | |
| [kUpb_EncodedType_SFixed32] = kUpb_FieldType_SFixed32, | |
| [kUpb_EncodedType_SFixed64] = kUpb_FieldType_SFixed64, | |
| [kUpb_EncodedType_SInt32] = kUpb_FieldType_SInt32, | |
| [kUpb_EncodedType_SInt64] = kUpb_FieldType_SInt64, | |
| [kUpb_EncodedType_ClosedEnum] = kUpb_FieldType_Enum, | |
| }; | |
| static void upb_MiniTable_SetField(upb_MtDecoder* d, uint8_t ch, | |
| upb_MiniTableField* field, | |
| uint64_t msg_modifiers) { | |
| static const char kUpb_EncodedToFieldRep[] = { | |
| [kUpb_EncodedType_Double] = kUpb_FieldRep_8Byte, | |
| [kUpb_EncodedType_Float] = kUpb_FieldRep_4Byte, | |
| [kUpb_EncodedType_Int64] = kUpb_FieldRep_8Byte, | |
| [kUpb_EncodedType_UInt64] = kUpb_FieldRep_8Byte, | |
| [kUpb_EncodedType_Int32] = kUpb_FieldRep_4Byte, | |
| [kUpb_EncodedType_Fixed64] = kUpb_FieldRep_8Byte, | |
| [kUpb_EncodedType_Fixed32] = kUpb_FieldRep_4Byte, | |
| [kUpb_EncodedType_Bool] = kUpb_FieldRep_1Byte, | |
| [kUpb_EncodedType_String] = kUpb_FieldRep_StringView, | |
| [kUpb_EncodedType_Bytes] = kUpb_FieldRep_StringView, | |
| [kUpb_EncodedType_UInt32] = kUpb_FieldRep_4Byte, | |
| [kUpb_EncodedType_OpenEnum] = kUpb_FieldRep_4Byte, | |
| [kUpb_EncodedType_SFixed32] = kUpb_FieldRep_4Byte, | |
| [kUpb_EncodedType_SFixed64] = kUpb_FieldRep_8Byte, | |
| [kUpb_EncodedType_SInt32] = kUpb_FieldRep_4Byte, | |
| [kUpb_EncodedType_SInt64] = kUpb_FieldRep_8Byte, | |
| [kUpb_EncodedType_ClosedEnum] = kUpb_FieldRep_4Byte, | |
| }; | |
| char pointer_rep = d->platform == kUpb_MiniTablePlatform_32Bit | |
| ? kUpb_FieldRep_4Byte | |
| : kUpb_FieldRep_8Byte; | |
| int8_t type = _upb_FromBase92(ch); | |
| if (ch >= _upb_ToBase92(kUpb_EncodedType_RepeatedBase)) { | |
| type -= kUpb_EncodedType_RepeatedBase; | |
| field->UPB_PRIVATE(mode) = kUpb_FieldMode_Array; | |
| field->UPB_PRIVATE(mode) |= pointer_rep << kUpb_FieldRep_Shift; | |
| field->UPB_PRIVATE(offset) = kNoPresence; | |
| } else { | |
| field->UPB_PRIVATE(mode) = kUpb_FieldMode_Scalar; | |
| field->UPB_PRIVATE(offset) = kHasbitPresence; | |
| if (type == kUpb_EncodedType_Group || type == kUpb_EncodedType_Message) { | |
| field->UPB_PRIVATE(mode) |= pointer_rep << kUpb_FieldRep_Shift; | |
| } else if ((unsigned long)type >= sizeof(kUpb_EncodedToFieldRep)) { | |
| upb_MdDecoder_ErrorJmp(&d->base, "Invalid field type: %d", (int)type); | |
| } else { | |
| field->UPB_PRIVATE(mode) |= kUpb_EncodedToFieldRep[type] | |
| << kUpb_FieldRep_Shift; | |
| } | |
| } | |
| if ((unsigned long)type >= sizeof(kUpb_EncodedToType)) { | |
| upb_MdDecoder_ErrorJmp(&d->base, "Invalid field type: %d", (int)type); | |
| } | |
| upb_MiniTable_SetTypeAndSub(d, field, kUpb_EncodedToType[type], msg_modifiers, | |
| type == kUpb_EncodedType_OpenEnum); | |
| } | |
| static void upb_MtDecoder_ModifyField(upb_MtDecoder* d, | |
| uint32_t message_modifiers, | |
| uint32_t field_modifiers, | |
| upb_MiniTableField* field) { | |
| if (field_modifiers & kUpb_EncodedFieldModifier_FlipPacked) { | |
| if (!upb_MtDecoder_FieldIsPackable(field)) { | |
| upb_MdDecoder_ErrorJmp(&d->base, | |
| "Cannot flip packed on unpackable field %" PRIu32, | |
| upb_MiniTableField_Number(field)); | |
| } | |
| field->UPB_PRIVATE(mode) ^= kUpb_LabelFlags_IsPacked; | |
| } | |
| if (field_modifiers & kUpb_EncodedFieldModifier_FlipValidateUtf8) { | |
| if (field->UPB_PRIVATE(descriptortype) != kUpb_FieldType_Bytes || | |
| !(field->UPB_PRIVATE(mode) & kUpb_LabelFlags_IsAlternate)) { | |
| upb_MdDecoder_ErrorJmp(&d->base, | |
| "Cannot flip ValidateUtf8 on field %" PRIu32 | |
| ", type=%d, mode=%d", | |
| upb_MiniTableField_Number(field), | |
| (int)field->UPB_PRIVATE(descriptortype), | |
| (int)field->UPB_PRIVATE(mode)); | |
| } | |
| field->UPB_PRIVATE(descriptortype) = kUpb_FieldType_String; | |
| field->UPB_PRIVATE(mode) &= ~kUpb_LabelFlags_IsAlternate; | |
| } | |
| bool singular = field_modifiers & kUpb_EncodedFieldModifier_IsProto3Singular; | |
| bool required = field_modifiers & kUpb_EncodedFieldModifier_IsRequired; | |
| // Validate. | |
| if ((singular || required) && field->UPB_PRIVATE(offset) != kHasbitPresence) { | |
| upb_MdDecoder_ErrorJmp(&d->base, | |
| "Invalid modifier(s) for repeated field %" PRIu32, | |
| upb_MiniTableField_Number(field)); | |
| } | |
| if (singular && required) { | |
| upb_MdDecoder_ErrorJmp( | |
| &d->base, "Field %" PRIu32 " cannot be both singular and required", | |
| upb_MiniTableField_Number(field)); | |
| } | |
| if (singular && upb_MiniTableField_IsSubMessage(field)) { | |
| upb_MdDecoder_ErrorJmp(&d->base, | |
| "Field %" PRIu32 " cannot be a singular submessage", | |
| upb_MiniTableField_Number(field)); | |
| } | |
| if (singular) field->UPB_PRIVATE(offset) = kNoPresence; | |
| if (required) { | |
| field->UPB_PRIVATE(offset) = kRequiredPresence; | |
| } | |
| } | |
| static void upb_MtDecoder_PushOneof(upb_MtDecoder* d, | |
| upb_OneOfLayoutItem item) { | |
| if (item.field_index == kUpb_OneOfLayoutItem_IndexSentinel) { | |
| upb_MdDecoder_ErrorJmp(&d->base, "Empty oneof"); | |
| } | |
| if ((d->oneofs.size + 1) * sizeof(*d->oneofs.data) > | |
| d->oneofs.buf_capacity_bytes) { | |
| size_t new_cap = UPB_MAX(8, d->oneofs.size * 2) * sizeof(*d->oneofs.data); | |
| d->oneofs.data = | |
| upb_grealloc(d->oneofs.data, d->oneofs.buf_capacity_bytes, new_cap); | |
| upb_MdDecoder_CheckOutOfMemory(&d->base, d->oneofs.data); | |
| d->oneofs.buf_capacity_bytes = new_cap; | |
| } | |
| item.field_index -= kOneofBase; | |
| d->rep_counts_offsets[kUpb_OneOf_CaseFieldRep]++; | |
| d->rep_counts_offsets[item.rep]++; | |
| d->oneofs.data[d->oneofs.size++] = item; | |
| } | |
| static size_t upb_MtDecoder_SizeOfRep(upb_FieldRep rep, | |
| upb_MiniTablePlatform platform) { | |
| enum { string_view_size_32 = 8, string_view_size_64 = 16 }; | |
| UPB_STATIC_ASSERT(sizeof(upb_StringView) == | |
| UPB_SIZE(string_view_size_32, string_view_size_64), | |
| "StringView size mismatch"); | |
| static const uint8_t kRepToSize32[] = { | |
| [kUpb_FieldRep_1Byte] = 1, | |
| [kUpb_FieldRep_4Byte] = 4, | |
| [kUpb_FieldRep_StringView] = string_view_size_32, | |
| [kUpb_FieldRep_8Byte] = 8, | |
| }; | |
| static const uint8_t kRepToSize64[] = { | |
| [kUpb_FieldRep_1Byte] = 1, | |
| [kUpb_FieldRep_4Byte] = 4, | |
| [kUpb_FieldRep_StringView] = string_view_size_64, | |
| [kUpb_FieldRep_8Byte] = 8, | |
| }; | |
| return platform == kUpb_MiniTablePlatform_32Bit ? kRepToSize32[rep] | |
| : kRepToSize64[rep]; | |
| } | |
| static size_t upb_MtDecoder_AlignOfRep(upb_FieldRep rep, | |
| upb_MiniTablePlatform platform) { | |
| enum { string_view_align_32 = 4, string_view_align_64 = 8 }; | |
| UPB_STATIC_ASSERT(UPB_ALIGN_OF(upb_StringView) == | |
| UPB_SIZE(string_view_align_32, string_view_align_64), | |
| "StringView size mismatch"); | |
| static const uint8_t kRepToAlign32[] = { | |
| [kUpb_FieldRep_1Byte] = 1, | |
| [kUpb_FieldRep_4Byte] = 4, | |
| [kUpb_FieldRep_StringView] = string_view_align_32, | |
| [kUpb_FieldRep_8Byte] = 8, | |
| }; | |
| static const uint8_t kRepToAlign64[] = { | |
| [kUpb_FieldRep_1Byte] = 1, | |
| [kUpb_FieldRep_4Byte] = 4, | |
| [kUpb_FieldRep_StringView] = string_view_align_64, | |
| [kUpb_FieldRep_8Byte] = 8, | |
| }; | |
| return platform == kUpb_MiniTablePlatform_32Bit ? kRepToAlign32[rep] | |
| : kRepToAlign64[rep]; | |
| } | |
| static const char* upb_MtDecoder_DecodeOneofField(upb_MtDecoder* d, | |
| const char* ptr, | |
| char first_ch, | |
| upb_OneOfLayoutItem* item) { | |
| uint32_t field_num; | |
| ptr = upb_MdDecoder_DecodeBase92Varint( | |
| &d->base, ptr, first_ch, kUpb_EncodedValue_MinOneofField, | |
| kUpb_EncodedValue_MaxOneofField, &field_num); | |
| upb_MiniTableField* f = | |
| (void*)upb_MiniTable_FindFieldByNumber(&d->table, field_num); | |
| if (!f) { | |
| upb_MdDecoder_ErrorJmp(&d->base, | |
| "Couldn't add field number %" PRIu32 | |
| " to oneof, no such field number.", | |
| field_num); | |
| } | |
| if (f->UPB_PRIVATE(offset) != kHasbitPresence) { | |
| upb_MdDecoder_ErrorJmp( | |
| &d->base, | |
| "Cannot add repeated, required, or singular field %" PRIu32 | |
| " to oneof.", | |
| field_num); | |
| } | |
| // Oneof storage must be large enough to accommodate the largest member. | |
| int rep = f->UPB_PRIVATE(mode) >> kUpb_FieldRep_Shift; | |
| size_t new_size = upb_MtDecoder_SizeOfRep(rep, d->platform); | |
| size_t new_align = upb_MtDecoder_AlignOfRep(rep, d->platform); | |
| size_t current_size = upb_MtDecoder_SizeOfRep(item->rep, d->platform); | |
| size_t current_align = upb_MtDecoder_AlignOfRep(item->rep, d->platform); | |
| if (new_size > current_size || | |
| (new_size == current_size && new_align > current_align)) { | |
| UPB_ASSERT(new_align >= current_align); | |
| item->rep = rep; | |
| } else { | |
| UPB_ASSERT(current_align >= new_align); | |
| } | |
| // Prepend this field to the linked list. | |
| f->UPB_PRIVATE(offset) = item->field_index; | |
| item->field_index = (f - d->fields) + kOneofBase; | |
| return ptr; | |
| } | |
| static const char* upb_MtDecoder_DecodeOneofs(upb_MtDecoder* d, | |
| const char* ptr) { | |
| upb_OneOfLayoutItem item = { | |
| .rep = 0, .field_index = kUpb_OneOfLayoutItem_IndexSentinel}; | |
| while (ptr < d->base.end) { | |
| char ch = *ptr++; | |
| if (ch == kUpb_EncodedValue_FieldSeparator) { | |
| // Field separator, no action needed. | |
| } else if (ch == kUpb_EncodedValue_OneofSeparator) { | |
| // End of oneof. | |
| upb_MtDecoder_PushOneof(d, item); | |
| item.field_index = | |
| kUpb_OneOfLayoutItem_IndexSentinel; // Move to next oneof. | |
| } else { | |
| ptr = upb_MtDecoder_DecodeOneofField(d, ptr, ch, &item); | |
| } | |
| } | |
| // Push final oneof. | |
| upb_MtDecoder_PushOneof(d, item); | |
| return ptr; | |
| } | |
| static const char* upb_MtDecoder_ParseModifier(upb_MtDecoder* d, | |
| const char* ptr, char first_ch, | |
| upb_MiniTableField* last_field, | |
| uint64_t* msg_modifiers) { | |
| uint32_t mod; | |
| ptr = upb_MdDecoder_DecodeBase92Varint(&d->base, ptr, first_ch, | |
| kUpb_EncodedValue_MinModifier, | |
| kUpb_EncodedValue_MaxModifier, &mod); | |
| if (last_field) { | |
| upb_MtDecoder_ModifyField(d, *msg_modifiers, mod, last_field); | |
| } else { | |
| if (d->is_extension) { | |
| upb_MdDecoder_ErrorJmp(&d->base, | |
| "Extensions cannot have message modifiers"); | |
| } | |
| *msg_modifiers = mod; | |
| } | |
| return ptr; | |
| } | |
| size_t upb_MtDecoder_PtrSize(upb_MtDecoder* d) { | |
| return d->platform == kUpb_MiniTablePlatform_32Bit ? 4 : 8; | |
| } | |
| static void upb_MtDecoder_AllocateSubs(upb_MtDecoder* d, | |
| upb_MiniTableSubInternal* subs) { | |
| // The `ofs` variable tracks byte offset between the current field and the | |
| // current entry in the `subs` array. Whenever we move to the next entry in | |
| // the `fields` array, the offset decreases by the size of the field, but | |
| // whenever we move to the next entry in the `subs` array, the offset | |
| // *increases* by the size of the entry in the `subs` array. | |
| UPB_ASSERT((char*)subs >= (char*)d->fields); | |
| size_t ofs = (char*)subs - (char*)d->fields; | |
| uintptr_t ptr_size = upb_MtDecoder_PtrSize(d); | |
| for (int i = 0; i < d->table.UPB_PRIVATE(field_count); | |
| i++, ofs -= sizeof(upb_MiniTableField)) { | |
| upb_MiniTableField* f = &d->fields[i]; | |
| if (f->UPB_PRIVATE(submsg_ofs) == kUpb_NoSub) continue; | |
| size_t u32_ofs = ofs / kUpb_SubmsgOffsetBytes; | |
| UPB_ASSERT((ofs % 4) == 0); | |
| UPB_ASSERT((i * sizeof(upb_MiniTableField) + ofs) % ptr_size == 0); | |
| // u32_ofs must be strictly less than UINT16_MAX: UINT16_MAX is reserved as | |
| // kUpb_NoSub, the sentinel meaning "this field has no submessage". | |
| if (u32_ofs >= UINT16_MAX) { | |
| upb_MdDecoder_ErrorJmp(&d->base, "Submessage offset overflow"); | |
| } | |
| f->UPB_PRIVATE(submsg_ofs) = u32_ofs; | |
| ofs += ptr_size; | |
| } | |
| } | |
| static const char* upb_MtDecoder_Parse(upb_MtDecoder* d, const char* ptr, | |
| size_t len, void* fields, | |
| size_t field_size, | |
| uint16_t* field_count) { | |
| uint64_t msg_modifiers = 0; | |
| uint32_t last_field_number = 0; | |
| upb_MiniTableField* last_field = NULL; | |
| bool need_dense_below = !d->is_extension; | |
| d->base.end = UPB_PTRADD(ptr, len); | |
| while (ptr < d->base.end) { | |
| char ch = *ptr++; | |
| if (ch <= kUpb_EncodedValue_MaxField) { | |
| if (d->is_extension && last_field) { | |
| // For extensions, consume only a single field and then return. | |
| return --ptr; | |
| } | |
| upb_MiniTableField* field = fields; | |
| if (*field_count == UINT16_MAX) { | |
| upb_MdDecoder_ErrorJmp( | |
| &d->base, "Fields in message exceed the limit of %u", UINT16_MAX); | |
| } | |
| *field_count += 1; | |
| fields = (char*)fields + field_size; | |
| uint32_t number = ++last_field_number; | |
| if (number == 0 || (number > kUpb_MaxFieldNumber && !d->is_extension)) { | |
| upb_MdDecoder_ErrorJmp(&d->base, "Invalid field number: %" PRIu32, | |
| number); | |
| } | |
| field->UPB_PRIVATE(number) = number; | |
| last_field = field; | |
| upb_MiniTable_SetField(d, ch, field, msg_modifiers); | |
| } else if (kUpb_EncodedValue_MinModifier <= ch && | |
| ch <= kUpb_EncodedValue_MaxModifier) { | |
| ptr = upb_MtDecoder_ParseModifier(d, ptr, ch, last_field, &msg_modifiers); | |
| if (msg_modifiers & kUpb_MessageModifier_IsExtendable) { | |
| d->table.UPB_PRIVATE(ext) |= kUpb_ExtMode_Extendable; | |
| } | |
| } else if (ch == kUpb_EncodedValue_End) { | |
| if (d->is_extension) { | |
| upb_MdDecoder_ErrorJmp(&d->base, "Extensions cannot have oneofs."); | |
| } | |
| ptr = upb_MtDecoder_DecodeOneofs(d, ptr); | |
| } else if (kUpb_EncodedValue_MinSkip <= ch && | |
| ch <= kUpb_EncodedValue_MaxSkip) { | |
| if (need_dense_below) { | |
| d->table.UPB_PRIVATE(dense_below) = d->table.UPB_PRIVATE(field_count); | |
| need_dense_below = false; | |
| } | |
| uint32_t skip; | |
| ptr = upb_MdDecoder_DecodeBase92Varint(&d->base, ptr, ch, | |
| kUpb_EncodedValue_MinSkip, | |
| kUpb_EncodedValue_MaxSkip, &skip); | |
| if (skip == 0) { | |
| upb_MdDecoder_ErrorJmp(&d->base, "Invalid skip value: 0"); | |
| } | |
| if (skip > UINT32_MAX - last_field_number) { | |
| upb_MdDecoder_ErrorJmp(&d->base, "Field number overflow"); | |
| } | |
| last_field_number += skip; | |
| last_field_number--; // Next field seen will increment. | |
| } else { | |
| upb_MdDecoder_ErrorJmp(&d->base, "Invalid char: %c", ch); | |
| } | |
| } | |
| if (need_dense_below) { | |
| d->table.UPB_PRIVATE(dense_below) = d->table.UPB_PRIVATE(field_count); | |
| } | |
| return ptr; | |
| } | |
| static void upb_MtDecoder_ParseMessage(upb_MtDecoder* d, const char* data, | |
| size_t len) { | |
| const size_t bytes_per_field = | |
| sizeof(upb_MiniTableField) + sizeof(upb_MiniTableSubInternal); | |
| // Buffer length is an upper bound on the number of fields. We will return | |
| // what we don't use. | |
| size_t initial_bytes; | |
| if (upb_MulOverflow(bytes_per_field, len, &initial_bytes) || | |
| upb_AddOverflow(initial_bytes, (size_t)4, &initial_bytes)) { | |
| upb_MdDecoder_ErrorJmp(&d->base, "MiniDescriptor is too large"); | |
| } | |
| // Max size used per field is a upb_MiniTableField and a | |
| // upb_MiniTableSubInternal. There could also be up to 4 bytes of padding, | |
| // since sizeof(upb_MiniTableField) == 12 and | |
| // alignof(upb_MiniTableSubInternal) == 8. | |
| UPB_STATIC_ASSERT(UPB_ALIGN_OF(upb_MiniTableSubInternal) - | |
| UPB_ALIGN_OF(upb_MiniTableField) <= | |
| 4, | |
| "alignment difference is too large"); | |
| d->fields = upb_Arena_Malloc(d->arena, initial_bytes); | |
| upb_MdDecoder_CheckOutOfMemory(&d->base, d->fields); | |
| d->table.UPB_PRIVATE(field_count) = 0; | |
| d->table.UPB_PRIVATE(fields) = d->fields; | |
| upb_MtDecoder_Parse(d, data, len, d->fields, sizeof(*d->fields), | |
| &d->table.UPB_PRIVATE(field_count)); | |
| size_t field_bytes = | |
| UPB_ALIGN_UP(d->table.UPB_PRIVATE(field_count) * sizeof(*d->fields), | |
| upb_MtDecoder_PtrSize(d)); | |
| upb_MiniTableSubInternal* subs = | |
| UPB_PTR_AT(d->fields, field_bytes, upb_MiniTableSubInternal); | |
| memset(subs, 0, sizeof(upb_MiniTableSubInternal) * d->sub_count); | |
| // We now know how much space we actually used, so shrink the allocation to | |
| // that size. | |
| size_t final_bytes = | |
| field_bytes + sizeof(upb_MiniTableSubInternal) * d->sub_count; | |
| upb_Arena_ShrinkLast(d->arena, d->fields, initial_bytes, final_bytes); | |
| upb_MtDecoder_AllocateSubs(d, subs); | |
| } | |
| static void upb_MtDecoder_CalculateAlignments(upb_MtDecoder* d) { | |
| // Add alignment counts for non-oneof fields (oneofs were added already) | |
| int n = d->table.UPB_PRIVATE(field_count); | |
| for (int i = 0; i < n; i++) { | |
| upb_MiniTableField* f = &d->fields[i]; | |
| if (f->UPB_PRIVATE(offset) >= kOneofBase) continue; | |
| d->rep_counts_offsets[f->UPB_PRIVATE(mode) >> kUpb_FieldRep_Shift]++; | |
| } | |
| // Reserve properly aligned space for each type of field representation | |
| // present in this message. When we iterate over the fields, they will obtain | |
| // their offset from within the region matching their alignment requirements. | |
| size_t base = d->table.UPB_PRIVATE(size); | |
| // Start with the lowest alignment requirement, going up, because: | |
| // 1. If there are presence bits, we won't be aligned to start, but adding | |
| // some lower-alignment fields may get us closer without wasting space to | |
| // padding. | |
| // 2. The allocator enforces 8 byte alignment, so moving intermediate padding | |
| // to trailing padding doesn't save us anything. | |
| for (upb_FieldRep rep = kUpb_FieldRep_1Byte; rep <= kUpb_FieldRep_Max; | |
| rep++) { | |
| uint16_t count = d->rep_counts_offsets[rep]; | |
| if (count) { | |
| base = UPB_ALIGN_UP(base, upb_MtDecoder_AlignOfRep(rep, d->platform)); | |
| // This entry now tracks the base offset for this field representation | |
| // type, instead of the count | |
| d->rep_counts_offsets[rep] = base; | |
| base += upb_MtDecoder_SizeOfRep(rep, d->platform) * count; | |
| } | |
| } | |
| static const size_t max = UINT16_MAX; | |
| if (base > max) { | |
| upb_MdDecoder_ErrorJmp( | |
| &d->base, "Message size exceeded maximum size of %zu bytes", max); | |
| } | |
| d->table.UPB_PRIVATE(size) = (uint16_t)base; | |
| } | |
| static size_t upb_MiniTable_DivideRoundUp(size_t n, size_t d) { | |
| return (n + d - 1) / d; | |
| } | |
| static void upb_MtDecoder_AssignHasbits(upb_MtDecoder* d) { | |
| int n = d->table.UPB_PRIVATE(field_count); | |
| size_t last_hasbit = kUpb_Reserved_Hasbits - 1; | |
| // First assign required fields, which must have the lowest hasbits. | |
| for (int i = 0; i < n; i++) { | |
| upb_MiniTableField* field = | |
| (upb_MiniTableField*)&d->table.UPB_PRIVATE(fields)[i]; | |
| if (field->UPB_PRIVATE(offset) == kRequiredPresence) { | |
| field->presence = ++last_hasbit; | |
| } else if (field->UPB_PRIVATE(offset) == kNoPresence) { | |
| field->presence = 0; | |
| } | |
| } | |
| if (last_hasbit >= kUpb_Reserved_Hasbits + 63) { | |
| upb_MdDecoder_ErrorJmp(&d->base, "Too many required fields"); | |
| } | |
| d->table.UPB_PRIVATE(required_count) = | |
| last_hasbit - (kUpb_Reserved_Hasbits - 1); | |
| UPB_ASSERT(d->table.UPB_PRIVATE(required_count) < 64); | |
| // Next assign non-required hasbit fields. | |
| for (int i = 0; i < n; i++) { | |
| upb_MiniTableField* field = | |
| (upb_MiniTableField*)&d->table.UPB_PRIVATE(fields)[i]; | |
| if (field->UPB_PRIVATE(offset) == kHasbitPresence) { | |
| if (last_hasbit >= INT16_MAX) { | |
| upb_MdDecoder_ErrorJmp(&d->base, "Too many fields with presence"); | |
| } | |
| field->presence = ++last_hasbit; | |
| } | |
| } | |
| d->table.UPB_PRIVATE(size) = | |
| last_hasbit ? upb_MiniTable_DivideRoundUp(last_hasbit + 1, 8) : 0; | |
| } | |
| static size_t upb_MtDecoder_Place(upb_MtDecoder* d, upb_FieldRep rep) { | |
| size_t size = upb_MtDecoder_SizeOfRep(rep, d->platform); | |
| size_t offset = d->rep_counts_offsets[rep]; | |
| d->rep_counts_offsets[rep] += size; | |
| return offset; | |
| } | |
| static void upb_MtDecoder_AssignOffsets(upb_MtDecoder* d) { | |
| upb_MiniTableField* field_end = | |
| UPB_PTRADD(d->fields, d->table.UPB_PRIVATE(field_count)); | |
| for (upb_MiniTableField* field = d->fields; field < field_end; field++) { | |
| if (field->UPB_PRIVATE(offset) >= kOneofBase) continue; | |
| field->UPB_PRIVATE(offset) = | |
| upb_MtDecoder_Place(d, field->UPB_PRIVATE(mode) >> kUpb_FieldRep_Shift); | |
| } | |
| upb_OneOfLayoutItem* oneof_end = UPB_PTRADD(d->oneofs.data, d->oneofs.size); | |
| for (upb_OneOfLayoutItem* item = d->oneofs.data; item < oneof_end; item++) { | |
| upb_MiniTableField* f = &d->fields[item->field_index]; | |
| uint16_t case_offset = upb_MtDecoder_Place(d, kUpb_OneOf_CaseFieldRep); | |
| // The case offset is stored negated in the int16_t presence field, so it | |
| // must fit in the positive int16_t range or it would alias a hasbit index. | |
| if (case_offset > INT16_MAX) { | |
| upb_MdDecoder_ErrorJmp(&d->base, | |
| "Message size exceeded maximum size for oneofs"); | |
| } | |
| uint16_t data_offset = upb_MtDecoder_Place(d, item->rep); | |
| while (true) { | |
| f->presence = ~case_offset; | |
| uint16_t next_offset = f->UPB_PRIVATE(offset); | |
| f->UPB_PRIVATE(offset) = data_offset; | |
| if (next_offset == kUpb_OneOfLayoutItem_IndexSentinel) break; | |
| UPB_ASSERT(next_offset - kOneofBase < d->table.UPB_PRIVATE(field_count)); | |
| f = &d->fields[next_offset - kOneofBase]; | |
| } | |
| } | |
| // Since messages are always allocated on arenas, we can save repeatedly | |
| // realigning by doing alignment at minitable construction time. We don't want | |
| // to align to UPB_MALLOC_ALIGN because it can change with sanitizers, and if | |
| // we're generating code we don't want to calculate size differently depending | |
| // on the proto compiler's host or build configuration. | |
| d->table.UPB_PRIVATE(size) = | |
| UPB_ALIGN_UP(d->table.UPB_PRIVATE(size), kUpb_Message_Align); | |
| } | |
| static void upb_MtDecoder_ValidateEntryField(upb_MtDecoder* d, | |
| const upb_MiniTableField* f, | |
| uint32_t expected_num) { | |
| const char* name = expected_num == 1 ? "key" : "val"; | |
| const uint32_t f_number = upb_MiniTableField_Number(f); | |
| if (f_number != expected_num) { | |
| upb_MdDecoder_ErrorJmp(&d->base, | |
| "map %s did not have expected number (%d vs %d)", | |
| name, expected_num, f_number); | |
| } | |
| if (!upb_MiniTableField_IsScalar(f)) { | |
| upb_MdDecoder_ErrorJmp( | |
| &d->base, "map %s cannot be repeated or map, or be in oneof", name); | |
| } | |
| uint32_t not_ok_types; | |
| if (expected_num == 1) { | |
| not_ok_types = (1 << kUpb_FieldType_Float) | (1 << kUpb_FieldType_Double) | | |
| (1 << kUpb_FieldType_Message) | (1 << kUpb_FieldType_Group) | | |
| (1 << kUpb_FieldType_Bytes) | (1 << kUpb_FieldType_Enum); | |
| } else { | |
| not_ok_types = 1 << kUpb_FieldType_Group; | |
| } | |
| if ((1 << upb_MiniTableField_Type(f)) & not_ok_types) { | |
| upb_MdDecoder_ErrorJmp(&d->base, "map %s cannot have type %d", name, | |
| (int)f->UPB_PRIVATE(descriptortype)); | |
| } | |
| } | |
| static void upb_MtDecoder_ParseMap(upb_MtDecoder* d, const char* data, | |
| size_t len) { | |
| upb_MtDecoder_ParseMessage(d, data, len); | |
| upb_MtDecoder_AssignHasbits(d); | |
| if (UPB_UNLIKELY(d->table.UPB_PRIVATE(field_count) != 2)) { | |
| upb_MdDecoder_ErrorJmp(&d->base, "%hu fields in map", | |
| d->table.UPB_PRIVATE(field_count)); | |
| UPB_UNREACHABLE(); | |
| } | |
| if (d->oneofs.size != 0) { | |
| upb_MdDecoder_ErrorJmp(&d->base, "Map entry cannot have oneof"); | |
| } | |
| upb_MtDecoder_ValidateEntryField(d, &d->table.UPB_PRIVATE(fields)[0], 1); | |
| upb_MtDecoder_ValidateEntryField(d, &d->table.UPB_PRIVATE(fields)[1], 2); | |
| d->fields[0].UPB_PRIVATE(offset) = offsetof(upb_MapEntry, k); | |
| d->fields[1].UPB_PRIVATE(offset) = offsetof(upb_MapEntry, v); | |
| d->table.UPB_PRIVATE(size) = sizeof(upb_MapEntry); | |
| // Map entries have a special bit set to signal it's a map entry, used in | |
| // upb_MiniTable_SetSubMessage() below. | |
| d->table.UPB_PRIVATE(ext) |= kUpb_ExtMode_IsMapEntry; | |
| } | |
| static void upb_MtDecoder_ParseMessageSet(upb_MtDecoder* d, const char* data, | |
| size_t len) { | |
| if (len > 0) { | |
| upb_MdDecoder_ErrorJmp(&d->base, "Invalid message set encode length: %zu", | |
| len); | |
| } | |
| upb_MiniTable* ret = &d->table; | |
| ret->UPB_PRIVATE(size) = kUpb_Reserved_Hasbytes; | |
| ret->UPB_PRIVATE(field_count) = 0; | |
| ret->UPB_PRIVATE(ext) = kUpb_ExtMode_IsMessageSet; | |
| ret->UPB_PRIVATE(dense_below) = 0; | |
| ret->UPB_PRIVATE(table_mask) = -1; | |
| ret->UPB_PRIVATE(required_count) = 0; | |
| } | |
| static upb_MiniTable* upb_MtDecoder_DoBuildMiniTableWithBuf( | |
| upb_MtDecoder* decoder, const char* data, size_t len, void** buf, | |
| size_t* buf_size) { | |
| decoder->table.UPB_PRIVATE(size) = kUpb_Reserved_Hasbytes; | |
| decoder->table.UPB_PRIVATE(field_count) = 0; | |
| decoder->table.UPB_PRIVATE(ext) = kUpb_ExtMode_NonExtendable; | |
| decoder->table.UPB_PRIVATE(dense_below) = 0; | |
| decoder->table.UPB_PRIVATE(table_mask) = -1; | |
| decoder->table.UPB_PRIVATE(required_count) = 0; | |
| #ifdef UPB_TRACING_ENABLED | |
| // MiniTables built from MiniDescriptors will not be able to vend the message | |
| // name unless it is explicitly set with upb_MiniTable_SetFullName(). | |
| decoder->table.UPB_PRIVATE(full_name) = 0; | |
| #endif | |
| // Strip off and verify the version tag. | |
| if (!len--) goto done; | |
| const char vers = *data++; | |
| switch (vers) { | |
| case kUpb_EncodedVersion_MapV1: | |
| upb_MtDecoder_ParseMap(decoder, data, len); | |
| break; | |
| case kUpb_EncodedVersion_MessageV1: | |
| upb_MtDecoder_ParseMessage(decoder, data, len); | |
| upb_MtDecoder_AssignHasbits(decoder); | |
| upb_MtDecoder_CalculateAlignments(decoder); | |
| upb_MtDecoder_AssignOffsets(decoder); | |
| break; | |
| case kUpb_EncodedVersion_MessageSetV1: | |
| upb_MtDecoder_ParseMessageSet(decoder, data, len); | |
| break; | |
| default: | |
| upb_MdDecoder_ErrorJmp(&decoder->base, "Invalid message version: %c", | |
| vers); | |
| } | |
| done: | |
| *buf = decoder->oneofs.data; | |
| *buf_size = decoder->oneofs.buf_capacity_bytes; | |
| size_t mt_size = sizeof(upb_MiniTable); | |
| #if UPB_FASTTABLE | |
| upb_DecodeFast_TableEntry fasttable[32]; | |
| int fasttable_size = 0; | |
| if (decoder->platform == kUpb_MiniTablePlatform_64Bit) { | |
| fasttable_size = upb_DecodeFast_BuildTable(&decoder->table, fasttable); | |
| mt_size += fasttable_size * sizeof(fasttable[0]); | |
| } | |
| #endif | |
| upb_MiniTable* ret = upb_Arena_Malloc(decoder->arena, mt_size); | |
| upb_MdDecoder_CheckOutOfMemory(&decoder->base, ret); | |
| memcpy(ret, &decoder->table, sizeof(*ret)); | |
| #if UPB_FASTTABLE | |
| ret->UPB_PRIVATE(table_mask) = upb_DecodeFast_GetTableMask(fasttable_size); | |
| for (int i = 0; i < fasttable_size; i++) { | |
| ret->UPB_PRIVATE(fasttable)[i].field_data = fasttable[i].function_data; | |
| ret->UPB_PRIVATE(fasttable)[i].field_parser = | |
| upb_DecodeFast_GetFunctionPointer(fasttable[i].function_idx); | |
| } | |
| #endif | |
| UPB_PRIVATE(upb_MiniTable_CheckInvariants)(ret); | |
| #ifndef NDEBUG | |
| for (int i = 1; i < upb_MiniTable_FieldCount(ret); i++) { | |
| const upb_MiniTableField* f1 = upb_MiniTable_GetFieldByIndex(ret, i - 1); | |
| const upb_MiniTableField* f2 = upb_MiniTable_GetFieldByIndex(ret, i); | |
| UPB_ASSERT(upb_MiniTableField_Number(f2) > upb_MiniTableField_Number(f1)); | |
| } | |
| #endif | |
| return ret; | |
| } | |
| static upb_MiniTable* upb_MtDecoder_BuildMiniTableWithBuf( | |
| upb_MtDecoder* const decoder, const char* const data, const size_t len, | |
| void** const buf, size_t* const buf_size) { | |
| if (UPB_SETJMP(decoder->base.err) != 0) { | |
| *buf = decoder->oneofs.data; | |
| *buf_size = decoder->oneofs.buf_capacity_bytes; | |
| return NULL; | |
| } | |
| return upb_MtDecoder_DoBuildMiniTableWithBuf(decoder, data, len, buf, | |
| buf_size); | |
| } | |
| upb_MiniTable* upb_MiniTable_BuildWithBuf(const char* data, size_t len, | |
| upb_MiniTablePlatform platform, | |
| upb_Arena* arena, void** buf, | |
| size_t* buf_size, | |
| upb_Status* status) { | |
| upb_MtDecoder decoder = { | |
| .base = {.status = status}, | |
| .platform = platform, | |
| .sub_count = 0, | |
| .is_extension = false, | |
| .oneofs = | |
| { | |
| .data = *buf, | |
| .buf_capacity_bytes = *buf_size, | |
| .size = 0, | |
| }, | |
| .arena = arena, | |
| }; | |
| return upb_MtDecoder_BuildMiniTableWithBuf(&decoder, data, len, buf, | |
| buf_size); | |
| } | |
| static const char* upb_MtDecoder_DoBuildMiniTableExtension( | |
| upb_MtDecoder* decoder, const char* data, size_t len, | |
| upb_MiniTableExtension* ext, const upb_MiniTable* extendee, | |
| upb_MiniTableSub sub) { | |
| if (!(extendee->UPB_PRIVATE(ext) & | |
| (kUpb_ExtMode_Extendable | kUpb_ExtMode_IsMessageSet))) { | |
| upb_MdDecoder_ErrorJmp(&decoder->base, "Extendee is not extendable"); | |
| } | |
| // If the string is non-empty then it must begin with a version tag. | |
| if (len) { | |
| if (*data != kUpb_EncodedVersion_ExtensionV1) { | |
| upb_MdDecoder_ErrorJmp(&decoder->base, "Invalid ext version: %c", *data); | |
| } | |
| data++; | |
| len--; | |
| } | |
| uint16_t count = 0; | |
| const char* ret = | |
| upb_MtDecoder_Parse(decoder, data, len, ext, sizeof(*ext), &count); | |
| if (!ret || count != 1) return NULL; | |
| upb_MiniTableField* f = &ext->UPB_PRIVATE(field); | |
| uint32_t fieldnum = upb_MiniTableField_Number(f); | |
| const uint32_t kMaxFieldNumber = (1 << 29) - 1; | |
| if (fieldnum == 0 || | |
| (fieldnum > kMaxFieldNumber && !upb_MiniTable_IsMessageSet(extendee))) { | |
| upb_MdDecoder_ErrorJmp(&decoder->base, "Invalid extension field number"); | |
| } | |
| if (upb_MiniTable_FindFieldByNumber(extendee, fieldnum) != NULL) { | |
| upb_MdDecoder_ErrorJmp(&decoder->base, | |
| "Extension overlaps with a known field"); | |
| } | |
| f->UPB_PRIVATE(mode) |= kUpb_LabelFlags_IsExtension; | |
| f->UPB_PRIVATE(offset) = 0; | |
| f->presence = 0; | |
| if (UPB_PRIVATE(_upb_MiniTableField_HasSub)(f)) { | |
| // The sub is stored immediately after the upb_MiniTableExtension, whose | |
| // layout is `field` followed by the pointer-sized `extendee`. Compute the | |
| // offset for the target platform, since the generator emits it into | |
| // generated code for both 32-bit and 64-bit builds. | |
| size_t ptr_size = upb_MtDecoder_PtrSize(decoder); | |
| size_t sub_ofs = | |
| UPB_ALIGN_UP(sizeof(upb_MiniTableField), ptr_size) + ptr_size; | |
| f->UPB_PRIVATE(submsg_ofs) = sub_ofs / kUpb_SubmsgOffsetBytes; | |
| // Tables built for a non-native platform are only used to compute layouts | |
| // for code generation; their in-memory layout does not match the target, | |
| // so we must not write the sub at the target offset. | |
| if (ptr_size == sizeof(void*)) { | |
| UPB_ASSERT(sub_ofs == | |
| offsetof(upb_MiniTableExtensionWithSub, UPB_PRIVATE(sub))); | |
| *UPB_PRIVATE(_upb_MiniTableField_Sub)(f) = sub; | |
| } | |
| } else { | |
| f->UPB_PRIVATE(submsg_ofs) = kUpb_NoSub; | |
| } | |
| if (extendee->UPB_PRIVATE(ext) & kUpb_ExtMode_IsMessageSet) { | |
| // Extensions of MessageSet must be messages. | |
| if (!upb_MiniTableField_IsSubMessage(f)) return NULL; | |
| // Extensions of MessageSet must be non-repeating. | |
| if (upb_MiniTableField_IsArray(f)) return NULL; | |
| } | |
| ext->UPB_PRIVATE(extendee) = extendee; | |
| return ret; | |
| } | |
| static const char* upb_MtDecoder_BuildMiniTableExtension( | |
| upb_MtDecoder* const decoder, const char* const data, const size_t len, | |
| upb_MiniTableExtension* const ext, const upb_MiniTable* const extendee, | |
| const upb_MiniTableSub sub) { | |
| if (UPB_SETJMP(decoder->base.err) != 0) return NULL; | |
| return upb_MtDecoder_DoBuildMiniTableExtension(decoder, data, len, ext, | |
| extendee, sub); | |
| } | |
| const char* _upb_MiniTableExtension_Init(const char* data, size_t len, | |
| upb_MiniTableExtension* ext, | |
| const upb_MiniTable* extendee, | |
| upb_MiniTableSub sub, | |
| upb_MiniTablePlatform platform, | |
| upb_Status* status) { | |
| upb_MtDecoder decoder = { | |
| .base = {.status = status}, | |
| .arena = NULL, | |
| .platform = platform, | |
| .sub_count = 0, | |
| .is_extension = true, | |
| }; | |
| return upb_MtDecoder_BuildMiniTableExtension(&decoder, data, len, ext, | |
| extendee, sub); | |
| } | |
| upb_MiniTableExtension* _upb_MiniTableExtension_Build( | |
| const char* data, size_t len, const upb_MiniTable* extendee, | |
| upb_MiniTableSub sub, upb_MiniTablePlatform platform, upb_Arena* arena, | |
| upb_Status* status) { | |
| upb_MiniTableExtension* ext = | |
| upb_Arena_Malloc(arena, sizeof(upb_MiniTableExtensionWithSub)); | |
| if (UPB_UNLIKELY(!ext)) return NULL; | |
| const char* ptr = _upb_MiniTableExtension_Init(data, len, ext, extendee, sub, | |
| platform, status); | |
| if (UPB_UNLIKELY(!ptr)) return NULL; | |
| if (ext->UPB_PRIVATE(field).UPB_PRIVATE(submsg_ofs) == kUpb_NoSub) { | |
| upb_Arena_ShrinkLast(arena, ext, sizeof(upb_MiniTableExtensionWithSub), | |
| sizeof(upb_MiniTableExtension)); | |
| } | |
| return ext; | |
| } | |
| upb_MiniTable* _upb_MiniTable_Build(const char* data, size_t len, | |
| upb_MiniTablePlatform platform, | |
| upb_Arena* arena, upb_Status* status) { | |
| void* buf = NULL; | |
| size_t size = 0; | |
| upb_MiniTable* ret = upb_MiniTable_BuildWithBuf(data, len, platform, arena, | |
| &buf, &size, status); | |
| upb_gfree(buf); | |
| return ret; | |
| } | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Our awkward dance for including fasttable only when it is enabled. | |
| #if UPB_FASTTABLE | |
| #define UPB_INCLUDE_FAST_DECODE | |
| #endif | |
| #ifdef UPB_INCLUDE_FAST_DECODE | |
| #endif | |
| #undef UPB_INCLUDE_FAST_DECODE | |
| // Must be last. | |
| bool upb_MiniTable_SetSubMessage(upb_MiniTable* table, | |
| upb_MiniTableField* field, | |
| const upb_MiniTable* sub) { | |
| UPB_ASSERT((uintptr_t)table->UPB_PRIVATE(fields) <= (uintptr_t)field && | |
| (uintptr_t)field < (uintptr_t)(table->UPB_PRIVATE(fields) + | |
| table->UPB_PRIVATE(field_count))); | |
| UPB_ASSERT(sub); | |
| const bool sub_is_map = sub->UPB_PRIVATE(ext) & kUpb_ExtMode_IsMapEntry; | |
| const bool table_is_map = table->UPB_PRIVATE(ext) & kUpb_ExtMode_IsMapEntry; | |
| switch (field->UPB_PRIVATE(descriptortype)) { | |
| case kUpb_FieldType_Message: | |
| if (sub_is_map) { | |
| if (UPB_UNLIKELY(table_is_map)) return false; | |
| // A map field on the parent table must be repeated, and cannot be in a | |
| // oneof or an extension. | |
| UPB_ASSERT(!upb_MiniTableField_IsMap(field)); | |
| if (UPB_UNLIKELY(!upb_MiniTableField_IsArray(field) || | |
| upb_MiniTableField_IsInOneof(field) || | |
| upb_MiniTableField_IsExtension(field))) { | |
| return false; | |
| } | |
| field->UPB_PRIVATE(mode) = | |
| (field->UPB_PRIVATE(mode) & ~kUpb_FieldMode_Mask) | | |
| kUpb_FieldMode_Map; | |
| #if UPB_FASTTABLE | |
| // Update fasttable entry with specialized map decoder function pointer | |
| // and metadata. | |
| int size = table->UPB_PRIVATE(table_mask) == 0xff | |
| ? 0 | |
| : ((table->UPB_PRIVATE(table_mask) >> 3) + 1); | |
| for (int i = 0; i < size; i++) { | |
| _upb_FastTable_Entry* entry = &table->UPB_PRIVATE(fasttable)[i]; | |
| uint32_t field_number = | |
| upb_DecodeFastData_GetFieldNumber(entry->field_data); | |
| if (field_number == upb_MiniTableField_Number(field)) { | |
| uint16_t expected_tag = | |
| upb_DecodeFastData_GetExpectedTag(entry->field_data); | |
| uint64_t subofs = upb_DecodeFastData_GetSubofs(entry->field_data); | |
| upb_DecodeFast_TableEntry fast_entry; | |
| if (upb_DecodeFast_TryFillMapEntry(field, sub, expected_tag, subofs, | |
| &fast_entry)) { | |
| entry->field_parser = | |
| upb_DecodeFast_GetFunctionPointer(fast_entry.function_idx); | |
| entry->field_data = fast_entry.function_data; | |
| } else { | |
| entry->field_parser = &_upb_FastDecoder_DecodeGeneric; | |
| entry->field_data = 0; | |
| } | |
| } | |
| } | |
| #endif | |
| } else if (table_is_map) { | |
| // If table is a map entry, only field 2 (value) can be a submessage. | |
| if (UPB_UNLIKELY(upb_MiniTableField_Number(field) != 2)) { | |
| return false; | |
| } | |
| } | |
| break; | |
| case kUpb_FieldType_Group: | |
| if (UPB_UNLIKELY(sub_is_map || table_is_map)) return false; | |
| break; | |
| default: | |
| return false; | |
| } | |
| upb_MiniTableSubInternal* table_sub = | |
| UPB_PRIVATE(_upb_MiniTableField_Sub)(field); | |
| UPB_ASSERT(upb_MiniTable_GetSubMessageTable(field) == NULL); | |
| table_sub->UPB_PRIVATE(submsg) = sub; | |
| return true; | |
| } | |
| bool upb_MiniTable_SetSubEnum(upb_MiniTable* table, upb_MiniTableField* field, | |
| const upb_MiniTableEnum* sub) { | |
| UPB_ASSERT((uintptr_t)table->UPB_PRIVATE(fields) <= (uintptr_t)field && | |
| (uintptr_t)field < (uintptr_t)(table->UPB_PRIVATE(fields) + | |
| table->UPB_PRIVATE(field_count))); | |
| UPB_ASSERT(sub); | |
| if (field->UPB_PRIVATE(descriptortype) != kUpb_FieldType_Enum) { | |
| return false; | |
| } | |
| if (table->UPB_PRIVATE(ext) & kUpb_ExtMode_IsMapEntry) { | |
| if (UPB_UNLIKELY(upb_MiniTableField_Number(field) != 2)) { | |
| return false; | |
| } | |
| if (!upb_MiniTableEnum_CheckValue(sub, 0)) { | |
| // An enum used in a map must include 0 as a value. This matches a check | |
| // performed in protoc ("Enum value in map must define 0 as the first | |
| // value"). Protoc should ensure that we never get here. | |
| // | |
| // This ends up being important if we receive wire messages where a map | |
| // entry omits the value (and thus defaults to 0). | |
| return false; | |
| } | |
| } | |
| upb_MiniTableSubInternal* table_sub = | |
| UPB_PRIVATE(_upb_MiniTableField_Sub)(field); | |
| UPB_ASSERT(upb_MiniTable_GetSubEnumTable(field) == NULL); | |
| *table_sub = upb_MiniTableSub_FromEnum(sub); | |
| return true; | |
| } | |
| uint32_t upb_MiniTable_GetSubList(const upb_MiniTable* m, | |
| const upb_MiniTableField** subs) { | |
| uint32_t msg_count = 0; | |
| uint32_t enum_count = 0; | |
| for (int i = 0; i < upb_MiniTable_FieldCount(m); i++) { | |
| const upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, i); | |
| if (upb_MiniTableField_CType(f) == kUpb_CType_Message) { | |
| *subs = f; | |
| ++subs; | |
| msg_count++; | |
| } | |
| } | |
| for (int i = 0; i < upb_MiniTable_FieldCount(m); i++) { | |
| const upb_MiniTableField* f = upb_MiniTable_GetFieldByIndex(m, i); | |
| if (upb_MiniTableField_IsClosedEnum(f)) { | |
| *subs = f; | |
| ++subs; | |
| enum_count++; | |
| } | |
| } | |
| return (msg_count << 16) | enum_count; | |
| } | |
| // The list of sub_tables and sub_enums must exactly match the number and order | |
| // of sub-message fields and sub-enum fields given by upb_MiniTable_GetSubList() | |
| // above. | |
| bool upb_MiniTable_Link(upb_MiniTable* m, const upb_MiniTable** sub_tables, | |
| size_t sub_table_count, | |
| const upb_MiniTableEnum** sub_enums, | |
| size_t sub_enum_count) { | |
| uint32_t msg_count = 0; | |
| uint32_t enum_count = 0; | |
| for (int i = 0; i < upb_MiniTable_FieldCount(m); i++) { | |
| upb_MiniTableField* f = | |
| (upb_MiniTableField*)upb_MiniTable_GetFieldByIndex(m, i); | |
| if (upb_MiniTableField_CType(f) == kUpb_CType_Message) { | |
| if (msg_count >= sub_table_count) return false; | |
| const upb_MiniTable* sub = sub_tables[msg_count++]; | |
| if (sub && !upb_MiniTable_SetSubMessage(m, f, sub)) return false; | |
| } | |
| } | |
| for (int i = 0; i < upb_MiniTable_FieldCount(m); i++) { | |
| upb_MiniTableField* f = | |
| (upb_MiniTableField*)upb_MiniTable_GetFieldByIndex(m, i); | |
| if (upb_MiniTableField_IsClosedEnum(f)) { | |
| if (enum_count >= sub_enum_count) return false; | |
| const upb_MiniTableEnum* sub = sub_enums[enum_count++]; | |
| if (sub && !upb_MiniTable_SetSubEnum(m, f, sub)) return false; | |
| } | |
| } | |
| return (msg_count == sub_table_count) && (enum_count == sub_enum_count); | |
| } | |
| const char _kUpb_ToBase92[] = { | |
| ' ', '!', '#', '$', '%', '&', '(', ')', '*', '+', ',', '-', '.', '/', | |
| '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', | |
| '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', | |
| 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', | |
| 'Z', '[', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', | |
| 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', | |
| 'w', 'x', 'y', 'z', '{', '|', '}', '~', | |
| }; | |
| const int8_t _kUpb_FromBase92[] = { | |
| 0, 1, -1, 2, 3, 4, 5, -1, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, | |
| 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, | |
| 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, | |
| 55, 56, 57, -1, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, | |
| 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, | |
| }; | |
| #include <assert.h> | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| // Must be last. | |
| typedef struct { | |
| uint64_t present_values_mask; | |
| uint32_t last_written_value; | |
| } upb_MtDataEncoderInternal_EnumState; | |
| typedef struct { | |
| uint64_t msg_modifiers; | |
| uint32_t last_field_num; | |
| enum { | |
| kUpb_OneofState_NotStarted, | |
| kUpb_OneofState_StartedOneof, | |
| kUpb_OneofState_EmittedOneofField, | |
| } oneof_state; | |
| } upb_MtDataEncoderInternal_MsgState; | |
| typedef struct { | |
| char* buf_start; // Only for checking kUpb_MtDataEncoder_MinSize. | |
| union { | |
| upb_MtDataEncoderInternal_EnumState enum_state; | |
| upb_MtDataEncoderInternal_MsgState msg_state; | |
| } state; | |
| } upb_MtDataEncoderInternal; | |
| static upb_MtDataEncoderInternal* upb_MtDataEncoder_GetInternal( | |
| upb_MtDataEncoder* e, char* buf_start) { | |
| UPB_ASSERT(sizeof(upb_MtDataEncoderInternal) <= sizeof(e->internal)); | |
| upb_MtDataEncoderInternal* ret = (upb_MtDataEncoderInternal*)e->internal; | |
| ret->buf_start = buf_start; | |
| return ret; | |
| } | |
| static char* upb_MtDataEncoder_PutRaw(upb_MtDataEncoder* e, char* ptr, | |
| char ch) { | |
| upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; | |
| UPB_ASSERT(ptr - in->buf_start < kUpb_MtDataEncoder_MinSize); | |
| if (ptr == e->end) return NULL; | |
| *ptr++ = ch; | |
| return ptr; | |
| } | |
| static char* upb_MtDataEncoder_Put(upb_MtDataEncoder* e, char* ptr, char ch) { | |
| return upb_MtDataEncoder_PutRaw(e, ptr, _upb_ToBase92(ch)); | |
| } | |
| static char* upb_MtDataEncoder_PutBase92Varint(upb_MtDataEncoder* e, char* ptr, | |
| uint32_t val, int min, int max) { | |
| int shift = upb_Log2Ceiling(_upb_FromBase92(max) - _upb_FromBase92(min) + 1); | |
| UPB_ASSERT(shift <= 6); | |
| uint32_t mask = (1 << shift) - 1; | |
| do { | |
| uint32_t bits = val & mask; | |
| ptr = upb_MtDataEncoder_Put(e, ptr, bits + _upb_FromBase92(min)); | |
| if (!ptr) return NULL; | |
| val >>= shift; | |
| } while (val); | |
| return ptr; | |
| } | |
| char* upb_MtDataEncoder_PutModifier(upb_MtDataEncoder* e, char* ptr, | |
| uint64_t mod) { | |
| if (mod) { | |
| ptr = upb_MtDataEncoder_PutBase92Varint(e, ptr, mod, | |
| kUpb_EncodedValue_MinModifier, | |
| kUpb_EncodedValue_MaxModifier); | |
| } | |
| return ptr; | |
| } | |
| char* upb_MtDataEncoder_EncodeExtension(upb_MtDataEncoder* e, char* ptr, | |
| upb_FieldType type, uint32_t field_num, | |
| uint64_t field_mod) { | |
| upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); | |
| in->state.msg_state.msg_modifiers = 0; | |
| in->state.msg_state.last_field_num = 0; | |
| in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; | |
| ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_ExtensionV1); | |
| if (!ptr) return NULL; | |
| return upb_MtDataEncoder_PutField(e, ptr, type, field_num, field_mod); | |
| } | |
| char* upb_MtDataEncoder_EncodeMap(upb_MtDataEncoder* e, char* ptr, | |
| upb_FieldType key_type, | |
| upb_FieldType value_type, uint64_t key_mod, | |
| uint64_t value_mod) { | |
| upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); | |
| in->state.msg_state.msg_modifiers = 0; | |
| in->state.msg_state.last_field_num = 0; | |
| in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; | |
| ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MapV1); | |
| if (!ptr) return NULL; | |
| ptr = upb_MtDataEncoder_PutField(e, ptr, key_type, 1, key_mod); | |
| if (!ptr) return NULL; | |
| return upb_MtDataEncoder_PutField(e, ptr, value_type, 2, value_mod); | |
| } | |
| char* upb_MtDataEncoder_EncodeMessageSet(upb_MtDataEncoder* e, char* ptr) { | |
| (void)upb_MtDataEncoder_GetInternal(e, ptr); | |
| return upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MessageSetV1); | |
| } | |
| char* upb_MtDataEncoder_StartMessage(upb_MtDataEncoder* e, char* ptr, | |
| uint64_t msg_mod) { | |
| upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); | |
| in->state.msg_state.msg_modifiers = msg_mod; | |
| in->state.msg_state.last_field_num = 0; | |
| in->state.msg_state.oneof_state = kUpb_OneofState_NotStarted; | |
| ptr = upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_MessageV1); | |
| if (!ptr) return NULL; | |
| return upb_MtDataEncoder_PutModifier(e, ptr, msg_mod); | |
| } | |
| static char* _upb_MtDataEncoder_MaybePutFieldSkip(upb_MtDataEncoder* e, | |
| char* ptr, | |
| uint32_t field_num) { | |
| upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; | |
| if (field_num <= in->state.msg_state.last_field_num) return NULL; | |
| if (in->state.msg_state.last_field_num + 1 != field_num) { | |
| // Put skip. | |
| UPB_ASSERT(field_num > in->state.msg_state.last_field_num); | |
| uint32_t skip = field_num - in->state.msg_state.last_field_num; | |
| ptr = upb_MtDataEncoder_PutBase92Varint( | |
| e, ptr, skip, kUpb_EncodedValue_MinSkip, kUpb_EncodedValue_MaxSkip); | |
| if (!ptr) return NULL; | |
| } | |
| in->state.msg_state.last_field_num = field_num; | |
| return ptr; | |
| } | |
| static char* _upb_MtDataEncoder_PutFieldType(upb_MtDataEncoder* e, char* ptr, | |
| upb_FieldType type, | |
| uint64_t field_mod) { | |
| static const char kUpb_TypeToEncoded[] = { | |
| [kUpb_FieldType_Double] = kUpb_EncodedType_Double, | |
| [kUpb_FieldType_Float] = kUpb_EncodedType_Float, | |
| [kUpb_FieldType_Int64] = kUpb_EncodedType_Int64, | |
| [kUpb_FieldType_UInt64] = kUpb_EncodedType_UInt64, | |
| [kUpb_FieldType_Int32] = kUpb_EncodedType_Int32, | |
| [kUpb_FieldType_Fixed64] = kUpb_EncodedType_Fixed64, | |
| [kUpb_FieldType_Fixed32] = kUpb_EncodedType_Fixed32, | |
| [kUpb_FieldType_Bool] = kUpb_EncodedType_Bool, | |
| [kUpb_FieldType_String] = kUpb_EncodedType_String, | |
| [kUpb_FieldType_Group] = kUpb_EncodedType_Group, | |
| [kUpb_FieldType_Message] = kUpb_EncodedType_Message, | |
| [kUpb_FieldType_Bytes] = kUpb_EncodedType_Bytes, | |
| [kUpb_FieldType_UInt32] = kUpb_EncodedType_UInt32, | |
| [kUpb_FieldType_Enum] = kUpb_EncodedType_OpenEnum, | |
| [kUpb_FieldType_SFixed32] = kUpb_EncodedType_SFixed32, | |
| [kUpb_FieldType_SFixed64] = kUpb_EncodedType_SFixed64, | |
| [kUpb_FieldType_SInt32] = kUpb_EncodedType_SInt32, | |
| [kUpb_FieldType_SInt64] = kUpb_EncodedType_SInt64, | |
| }; | |
| int encoded_type = kUpb_TypeToEncoded[type]; | |
| if (field_mod & kUpb_FieldModifier_IsClosedEnum) { | |
| UPB_ASSERT(type == kUpb_FieldType_Enum); | |
| encoded_type = kUpb_EncodedType_ClosedEnum; | |
| } | |
| if (field_mod & kUpb_FieldModifier_IsRepeated) { | |
| // Repeated fields shift the type number up (unlike other modifiers which | |
| // are bit flags). | |
| encoded_type += kUpb_EncodedType_RepeatedBase; | |
| } | |
| return upb_MtDataEncoder_Put(e, ptr, encoded_type); | |
| } | |
| static char* _upb_MtDataEncoder_MaybePutModifiers(upb_MtDataEncoder* e, | |
| char* ptr, upb_FieldType type, | |
| uint64_t field_mod) { | |
| upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; | |
| uint32_t encoded_modifiers = 0; | |
| if ((field_mod & kUpb_FieldModifier_IsRepeated) && | |
| upb_FieldType_IsPackable(type)) { | |
| bool field_is_packed = field_mod & kUpb_FieldModifier_IsPacked; | |
| bool default_is_packed = in->state.msg_state.msg_modifiers & | |
| kUpb_MessageModifier_DefaultIsPacked; | |
| if (field_is_packed != default_is_packed) { | |
| encoded_modifiers |= kUpb_EncodedFieldModifier_FlipPacked; | |
| } | |
| } | |
| if (type == kUpb_FieldType_String) { | |
| bool field_validates_utf8 = field_mod & kUpb_FieldModifier_ValidateUtf8; | |
| bool message_validates_utf8 = | |
| in->state.msg_state.msg_modifiers & kUpb_MessageModifier_ValidateUtf8; | |
| if (field_validates_utf8 != message_validates_utf8) { | |
| // Old binaries do not recognize the field modifier. We need the failure | |
| // mode to be too lax rather than too strict. Our caller should have | |
| // handled this (see _upb_MessageDef_ValidateUtf8()). | |
| assert(!message_validates_utf8); | |
| encoded_modifiers |= kUpb_EncodedFieldModifier_FlipValidateUtf8; | |
| } | |
| } | |
| if (field_mod & kUpb_FieldModifier_IsProto3Singular) { | |
| encoded_modifiers |= kUpb_EncodedFieldModifier_IsProto3Singular; | |
| } | |
| if (field_mod & kUpb_FieldModifier_IsRequired) { | |
| encoded_modifiers |= kUpb_EncodedFieldModifier_IsRequired; | |
| } | |
| return upb_MtDataEncoder_PutModifier(e, ptr, encoded_modifiers); | |
| } | |
| char* upb_MtDataEncoder_PutField(upb_MtDataEncoder* e, char* ptr, | |
| upb_FieldType type, uint32_t field_num, | |
| uint64_t field_mod) { | |
| upb_MtDataEncoder_GetInternal(e, ptr); | |
| ptr = _upb_MtDataEncoder_MaybePutFieldSkip(e, ptr, field_num); | |
| if (!ptr) return NULL; | |
| ptr = _upb_MtDataEncoder_PutFieldType(e, ptr, type, field_mod); | |
| if (!ptr) return NULL; | |
| return _upb_MtDataEncoder_MaybePutModifiers(e, ptr, type, field_mod); | |
| } | |
| char* upb_MtDataEncoder_StartOneof(upb_MtDataEncoder* e, char* ptr) { | |
| upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); | |
| if (in->state.msg_state.oneof_state == kUpb_OneofState_NotStarted) { | |
| ptr = upb_MtDataEncoder_Put(e, ptr, _upb_FromBase92(kUpb_EncodedValue_End)); | |
| } else { | |
| ptr = upb_MtDataEncoder_Put( | |
| e, ptr, _upb_FromBase92(kUpb_EncodedValue_OneofSeparator)); | |
| } | |
| in->state.msg_state.oneof_state = kUpb_OneofState_StartedOneof; | |
| return ptr; | |
| } | |
| char* upb_MtDataEncoder_PutOneofField(upb_MtDataEncoder* e, char* ptr, | |
| uint32_t field_num) { | |
| upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); | |
| if (in->state.msg_state.oneof_state == kUpb_OneofState_EmittedOneofField) { | |
| ptr = upb_MtDataEncoder_Put( | |
| e, ptr, _upb_FromBase92(kUpb_EncodedValue_FieldSeparator)); | |
| if (!ptr) return NULL; | |
| } | |
| ptr = upb_MtDataEncoder_PutBase92Varint(e, ptr, field_num, _upb_ToBase92(0), | |
| _upb_ToBase92(63)); | |
| in->state.msg_state.oneof_state = kUpb_OneofState_EmittedOneofField; | |
| return ptr; | |
| } | |
| char* upb_MtDataEncoder_StartEnum(upb_MtDataEncoder* e, char* ptr) { | |
| upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); | |
| in->state.enum_state.present_values_mask = 0; | |
| in->state.enum_state.last_written_value = 0; | |
| return upb_MtDataEncoder_PutRaw(e, ptr, kUpb_EncodedVersion_EnumV1); | |
| } | |
| static char* upb_MtDataEncoder_FlushDenseEnumMask(upb_MtDataEncoder* e, | |
| char* ptr) { | |
| upb_MtDataEncoderInternal* in = (upb_MtDataEncoderInternal*)e->internal; | |
| ptr = upb_MtDataEncoder_Put(e, ptr, in->state.enum_state.present_values_mask); | |
| in->state.enum_state.present_values_mask = 0; | |
| in->state.enum_state.last_written_value += 5; | |
| return ptr; | |
| } | |
| char* upb_MtDataEncoder_PutEnumValue(upb_MtDataEncoder* e, char* ptr, | |
| uint32_t val) { | |
| // TODO: optimize this encoding. | |
| upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); | |
| UPB_ASSERT(val >= in->state.enum_state.last_written_value); | |
| uint32_t delta = val - in->state.enum_state.last_written_value; | |
| if (delta >= 5 && in->state.enum_state.present_values_mask) { | |
| ptr = upb_MtDataEncoder_FlushDenseEnumMask(e, ptr); | |
| if (!ptr) { | |
| return NULL; | |
| } | |
| delta -= 5; | |
| } | |
| if (delta >= 5) { | |
| ptr = upb_MtDataEncoder_PutBase92Varint( | |
| e, ptr, delta, kUpb_EncodedValue_MinSkip, kUpb_EncodedValue_MaxSkip); | |
| in->state.enum_state.last_written_value += delta; | |
| delta = 0; | |
| } | |
| UPB_ASSERT((in->state.enum_state.present_values_mask >> delta) == 0); | |
| in->state.enum_state.present_values_mask |= 1ULL << delta; | |
| return ptr; | |
| } | |
| char* upb_MtDataEncoder_EndEnum(upb_MtDataEncoder* e, char* ptr) { | |
| upb_MtDataEncoderInternal* in = upb_MtDataEncoder_GetInternal(e, ptr); | |
| if (!in->state.enum_state.present_values_mask) return ptr; | |
| return upb_MtDataEncoder_FlushDenseEnumMask(e, ptr); | |
| } | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| struct upb_ExtensionRegistry { | |
| upb_exttable exts; | |
| upb_Arena* arena; | |
| }; | |
| upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) { | |
| upb_ExtensionRegistry* r = upb_Arena_Malloc(arena, sizeof(*r)); | |
| if (!r) return NULL; | |
| r->arena = arena; | |
| if (!upb_exttable_init(&r->exts, 8, arena)) return NULL; | |
| return r; | |
| } | |
| UPB_API upb_ExtensionRegistryStatus upb_ExtensionRegistry_Add( | |
| upb_ExtensionRegistry* r, const upb_MiniTableExtension* e) { | |
| UPB_STATIC_ASSERT( | |
| offsetof(upb_MiniTableExtension, | |
| UPB_PRIVATE(field).UPB_PRIVATE(number)) == 0, | |
| "Extension must be first-member-of-struct convertable with uint32_t"); | |
| uint32_t fieldnum = upb_MiniTableExtension_Number(e); | |
| const upb_MiniTable* extendee = upb_MiniTableExtension_Extendee(e); | |
| if (upb_exttable_lookup(&r->exts, extendee, fieldnum) != NULL) { | |
| return kUpb_ExtensionRegistryStatus_DuplicateEntry; | |
| } | |
| if (!upb_exttable_insert(&r->exts, extendee, (const uint32_t*)e, r->arena)) { | |
| return kUpb_ExtensionRegistryStatus_OutOfMemory; | |
| } | |
| return kUpb_ExtensionRegistryStatus_Ok; | |
| } | |
| upb_ExtensionRegistryStatus upb_ExtensionRegistry_AddArray( | |
| upb_ExtensionRegistry* r, const upb_MiniTableExtension** e, size_t count) { | |
| const upb_MiniTableExtension** start = e; | |
| const upb_MiniTableExtension** end = UPB_PTRADD(e, count); | |
| upb_ExtensionRegistryStatus status = kUpb_ExtensionRegistryStatus_Ok; | |
| for (; e < end; e++) { | |
| status = upb_ExtensionRegistry_Add(r, *e); | |
| if (status != kUpb_ExtensionRegistryStatus_Ok) goto failure; | |
| } | |
| return kUpb_ExtensionRegistryStatus_Ok; | |
| failure: | |
| // Back out the entries previously added. | |
| for (end = e, e = start; e < end; e++) { | |
| const upb_MiniTableExtension* ext = *e; | |
| upb_exttable_remove(&r->exts, upb_MiniTableExtension_Extendee(ext), | |
| upb_MiniTableExtension_Number(ext)); | |
| } | |
| UPB_ASSERT(status != kUpb_ExtensionRegistryStatus_Ok); | |
| return status; | |
| } | |
| const upb_MiniTableExtension* upb_ExtensionRegistry_Lookup( | |
| const upb_ExtensionRegistry* r, const upb_MiniTable* t, uint32_t num) { | |
| const uint32_t* v = upb_exttable_lookup(&r->exts, t, num); | |
| return (const upb_MiniTableExtension*)v; | |
| } | |
| size_t upb_ExtensionRegistry_Size(const upb_ExtensionRegistry* r) { | |
| return upb_exttable_size(&r->exts); | |
| } | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| // Must be last. | |
| #if UPB_TSAN | |
| #include <sched.h> | |
| #endif // UPB_TSAN | |
| const UPB_PRIVATE(upb_GeneratedExtensionListEntry) * | |
| UPB_PRIVATE(upb_generated_extension_list) = NULL; | |
| typedef struct upb_GeneratedRegistry { | |
| UPB_ATOMIC(upb_GeneratedRegistryRef*) ref; | |
| UPB_ATOMIC(int32_t) ref_count; | |
| } upb_GeneratedRegistry; | |
| static upb_GeneratedRegistry* _upb_generated_registry(void) { | |
| static upb_GeneratedRegistry r = {NULL, 0}; | |
| return &r; | |
| } | |
| static bool _upb_GeneratedRegistry_AddAllLinkedExtensions( | |
| upb_ExtensionRegistry* r) { | |
| const UPB_PRIVATE(upb_GeneratedExtensionListEntry)* entry = | |
| UPB_PRIVATE(upb_generated_extension_list); | |
| while (entry != NULL) { | |
| const upb_MiniTableExtension** current = entry->start; | |
| for (current = entry->start; current != entry->stop; ++current) { | |
| const upb_MiniTableExtension* ext = *current; | |
| // Sentinels and padding introduced by the linker can result in zeroed | |
| // entries, so simply skip them. | |
| if (*current == NULL) { | |
| // MSVC introduces padding that might not be sized exactly the same as | |
| // the linker array element, but it should be properly aligned, so just | |
| // skipping empty elements should be safe. (If the size and align of | |
| // the array elements was different, we'd have to do something more | |
| // complicated). | |
| continue; | |
| } | |
| if (upb_ExtensionRegistry_Add(r, ext) != | |
| kUpb_ExtensionRegistryStatus_Ok) { | |
| return false; | |
| } | |
| } | |
| entry = entry->next; | |
| } | |
| return true; | |
| } | |
| // Constructs a new GeneratedRegistryRef, adding all linked extensions to the | |
| // registry or returning NULL on failure. | |
| static upb_GeneratedRegistryRef* _upb_GeneratedRegistry_New(void) { | |
| upb_Arena* arena = NULL; | |
| upb_ExtensionRegistry* extreg = NULL; | |
| upb_GeneratedRegistryRef* ref = upb_gmalloc(sizeof(upb_GeneratedRegistryRef)); | |
| if (ref == NULL) goto err; | |
| arena = upb_Arena_New(); | |
| if (arena == NULL) goto err; | |
| extreg = upb_ExtensionRegistry_New(arena); | |
| if (extreg == NULL) goto err; | |
| ref->UPB_PRIVATE(arena) = arena; | |
| ref->UPB_PRIVATE(registry) = extreg; | |
| if (!_upb_GeneratedRegistry_AddAllLinkedExtensions(extreg)) goto err; | |
| return ref; | |
| err: | |
| if (arena != NULL) upb_Arena_Free(arena); | |
| if (ref != NULL) upb_gfree(ref); | |
| return NULL; | |
| } | |
| const upb_GeneratedRegistryRef* upb_GeneratedRegistry_Load(void) { | |
| upb_GeneratedRegistry* registry = _upb_generated_registry(); | |
| // Loop until we successfully acquire a reference. This loop should only | |
| // kick in under extremely high contention, and it should be guaranteed to | |
| // succeed. | |
| while (true) { | |
| int32_t count = upb_Atomic_Load(®istry->ref_count, memory_order_acquire); | |
| // Try to increment the refcount, but only if it's not zero. | |
| while (count > 0) { | |
| if (upb_Atomic_CompareExchangeStrong(®istry->ref_count, &count, | |
| count + 1, memory_order_acquire, | |
| memory_order_relaxed)) { | |
| // Successfully incremented. We can now safely load and return the | |
| // pointer. | |
| const upb_GeneratedRegistryRef* ref = | |
| upb_Atomic_Load(®istry->ref, memory_order_acquire); | |
| UPB_ASSERT(ref != NULL); | |
| return ref; | |
| } | |
| // CAS failed, `count` was updated. Loop will retry. | |
| } | |
| // If we're here, the count was 0. Time for the slow path. | |
| // Double-check that the pointer is NULL before trying to create. | |
| upb_GeneratedRegistryRef* ref = | |
| upb_Atomic_Load(®istry->ref, memory_order_acquire); | |
| if (ref == NULL) { | |
| // Pointer is NULL, try to create and publish a new registry. | |
| upb_GeneratedRegistryRef* new_ref = _upb_GeneratedRegistry_New(); | |
| if (new_ref == NULL) return NULL; // OOM | |
| // Try to CAS the pointer from NULL to our new_ref. | |
| if (upb_Atomic_CompareExchangeStrong(®istry->ref, &ref, new_ref, | |
| memory_order_release, | |
| memory_order_acquire)) { | |
| // We won the race. Set the ref count to 1. | |
| upb_Atomic_Store(®istry->ref_count, 1, memory_order_release); | |
| return new_ref; | |
| } else { | |
| // We lost the race. `ref` now holds the pointer from the winning | |
| // thread. Clean up our unused one and loop to try again to get a | |
| // reference. | |
| upb_Arena_Free(new_ref->UPB_PRIVATE(arena)); | |
| upb_gfree(new_ref); | |
| } | |
| } | |
| // If we are here, either we lost the CAS race, or the pointer was already | |
| // non-NULL. In either case, we loop to the top and try to increment the | |
| // refcount of the existing object. | |
| #if UPB_TSAN | |
| // Yield to give other threads a chance to increment the refcount. This is | |
| // especially an issue for TSAN builds, which are prone to locking up from | |
| // the thread with the upb_Atomic_Store call above getting starved. | |
| sched_yield(); | |
| #endif // UPB_TSAN | |
| } | |
| } | |
| void upb_GeneratedRegistry_Release(const upb_GeneratedRegistryRef* r) { | |
| if (r == NULL) return; | |
| upb_GeneratedRegistry* registry = _upb_generated_registry(); | |
| int ref_count = upb_Atomic_Sub(®istry->ref_count, 1, memory_order_acq_rel); | |
| UPB_ASSERT(registry->ref_count >= 0); | |
| // A ref_count of 1 means that we decremented the refcount to 0. | |
| if (ref_count == 1) { | |
| upb_GeneratedRegistryRef* ref = | |
| upb_Atomic_Exchange(®istry->ref, NULL, memory_order_acq_rel); | |
| if (ref != NULL) { | |
| // This is the last reference and we won any potential race to store NULL, | |
| // so we need to clean up. | |
| upb_Arena_Free(ref->UPB_PRIVATE(arena)); | |
| upb_gfree(ref); | |
| } | |
| } | |
| } | |
| const upb_ExtensionRegistry* upb_GeneratedRegistry_Get( | |
| const upb_GeneratedRegistryRef* r) { | |
| if (r == NULL) return NULL; | |
| return r->UPB_PRIVATE(registry); | |
| } | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| // Must be last. | |
| const upb_MiniTableField* upb_MiniTable_GetOneof(const upb_MiniTable* m, | |
| const upb_MiniTableField* f) { | |
| if (UPB_UNLIKELY(!upb_MiniTableField_IsInOneof(f))) { | |
| return NULL; | |
| } | |
| const upb_MiniTableField* ptr = &m->UPB_PRIVATE(fields)[0]; | |
| const upb_MiniTableField* end = | |
| &m->UPB_PRIVATE(fields)[m->UPB_PRIVATE(field_count)]; | |
| for (; ptr < end; ptr++) { | |
| if (ptr->presence == (*f).presence) { | |
| return ptr; | |
| } | |
| } | |
| return NULL; | |
| } | |
| bool upb_MiniTable_NextOneofField(const upb_MiniTable* m, | |
| const upb_MiniTableField** f) { | |
| const upb_MiniTableField* ptr = *f; | |
| const upb_MiniTableField* end = | |
| &m->UPB_PRIVATE(fields)[m->UPB_PRIVATE(field_count)]; | |
| while (++ptr < end) { | |
| if (ptr->presence == (*f)->presence) { | |
| *f = ptr; | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| #include <stddef.h> | |
| // Must be last. | |
| // A MiniTable for a statically tree shaken message. Messages that use this | |
| // MiniTable are guaranteed to remain unlinked; unlike the empty message, this | |
| // MiniTable is never replaced, which greatly simplifies everything, because the | |
| // type of a sub-message is always known, without consulting a tagged bit. | |
| const struct upb_MiniTable UPB_PRIVATE(_kUpb_MiniTable_StaticallyTreeShaken) = { | |
| .UPB_PRIVATE(fields) = NULL, | |
| .UPB_PRIVATE(size) = sizeof(struct upb_Message), | |
| .UPB_PRIVATE(field_count) = 0, | |
| .UPB_PRIVATE(ext) = kUpb_ExtMode_NonExtendable, | |
| .UPB_PRIVATE(dense_below) = 0, | |
| .UPB_PRIVATE(table_mask) = -1, | |
| .UPB_PRIVATE(required_count) = 0, | |
| }; | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| // Must be last. | |
| UPB_NORETURN void _upb_UnreachableFailure(const char* file, int line, | |
| const char* function_name) { | |
| fprintf(stderr, "%s:%d: Reached unreachable statement in function `%s`.\n", | |
| file, line, function_name ? function_name : "(unknown)"); | |
| abort(); | |
| } | |
| #include <assert.h> | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <stdio.h> | |
| #include <string.h> | |
| // Must be last. | |
| struct upb_DefPool { | |
| upb_Arena* arena; | |
| upb_strtable syms; // full_name -> packed def ptr | |
| upb_strtable files; // file_name -> (upb_FileDef*) | |
| upb_inttable exts; // (upb_MiniTableExtension*) -> (upb_FieldDef*) | |
| upb_ExtensionRegistry* extreg; | |
| const upb_GeneratedRegistryRef* generated_extreg; | |
| const google_protobuf_FeatureSetDefaults* feature_set_defaults; | |
| upb_MiniTablePlatform platform; | |
| void* scratch_data; | |
| size_t scratch_size; | |
| size_t bytes_loaded; | |
| bool disable_closed_enum_checking; | |
| bool disable_implicit_field_presence; | |
| }; | |
| void upb_DefPool_Free(upb_DefPool* s) { | |
| upb_GeneratedRegistry_Release(s->generated_extreg); | |
| upb_Arena_Free(s->arena); | |
| upb_gfree(s->scratch_data); | |
| upb_gfree(s); | |
| } | |
| static const char serialized_defaults[] = UPB_INTERNAL_UPB_EDITION_DEFAULTS; | |
| upb_DefPool* upb_DefPool_New(void) { | |
| upb_DefPool* s = upb_gmalloc(sizeof(*s)); | |
| if (!s) return NULL; | |
| s->arena = upb_Arena_New(); | |
| s->bytes_loaded = 0; | |
| s->disable_closed_enum_checking = false; | |
| s->disable_implicit_field_presence = false; | |
| s->scratch_size = 240; | |
| s->scratch_data = upb_gmalloc(s->scratch_size); | |
| if (!s->scratch_data) goto err; | |
| if (!upb_strtable_init(&s->syms, 32, s->arena)) goto err; | |
| if (!upb_strtable_init(&s->files, 4, s->arena)) goto err; | |
| if (!upb_inttable_init(&s->exts, s->arena)) goto err; | |
| s->extreg = upb_ExtensionRegistry_New(s->arena); | |
| if (!s->extreg) goto err; | |
| s->generated_extreg = upb_GeneratedRegistry_Load(); | |
| if (!s->generated_extreg) goto err; | |
| s->platform = kUpb_MiniTablePlatform_Native; | |
| upb_Status status; | |
| if (!upb_DefPool_SetFeatureSetDefaults( | |
| s, serialized_defaults, sizeof(serialized_defaults) - 1, &status)) { | |
| goto err; | |
| } | |
| if (!s->feature_set_defaults) goto err; | |
| return s; | |
| err: | |
| upb_DefPool_Free(s); | |
| return NULL; | |
| } | |
| void upb_DefPool_DisableClosedEnumChecking(upb_DefPool* s) { | |
| UPB_ASSERT(upb_strtable_count(&s->files) == 0); | |
| s->disable_closed_enum_checking = true; | |
| } | |
| bool upb_DefPool_ClosedEnumCheckingDisabled(const upb_DefPool* s) { | |
| return s->disable_closed_enum_checking; | |
| } | |
| void upb_DefPool_DisableImplicitFieldPresence(upb_DefPool* s) { | |
| UPB_ASSERT(upb_strtable_count(&s->files) == 0); | |
| s->disable_implicit_field_presence = true; | |
| } | |
| bool upb_DefPool_ImplicitFieldPresenceDisabled(const upb_DefPool* s) { | |
| return s->disable_implicit_field_presence; | |
| } | |
| const google_protobuf_FeatureSetDefaults* upb_DefPool_FeatureSetDefaults( | |
| const upb_DefPool* s) { | |
| return s->feature_set_defaults; | |
| } | |
| bool upb_DefPool_SetFeatureSetDefaults(upb_DefPool* s, | |
| const char* serialized_defaults, | |
| size_t serialized_len, | |
| upb_Status* status) { | |
| const google_protobuf_FeatureSetDefaults* defaults = google_protobuf_FeatureSetDefaults_parse( | |
| serialized_defaults, serialized_len, s->arena); | |
| if (!defaults) { | |
| upb_Status_SetErrorFormat(status, "Failed to parse defaults"); | |
| return false; | |
| } | |
| if (upb_strtable_count(&s->files) > 0) { | |
| upb_Status_SetErrorFormat(status, | |
| "Feature set defaults can't be changed once the " | |
| "pool has started building"); | |
| return false; | |
| } | |
| int min_edition = google_protobuf_FeatureSetDefaults_minimum_edition(defaults); | |
| int max_edition = google_protobuf_FeatureSetDefaults_maximum_edition(defaults); | |
| if (min_edition > max_edition) { | |
| upb_Status_SetErrorFormat(status, "Invalid edition range %s to %s", | |
| upb_FileDef_EditionName(min_edition), | |
| upb_FileDef_EditionName(max_edition)); | |
| return false; | |
| } | |
| size_t size; | |
| const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* const* | |
| default_list = google_protobuf_FeatureSetDefaults_defaults(defaults, &size); | |
| int prev_edition = google_protobuf_EDITION_UNKNOWN; | |
| for (size_t i = 0; i < size; ++i) { | |
| int edition = google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_edition( | |
| default_list[i]); | |
| if (edition == google_protobuf_EDITION_UNKNOWN) { | |
| upb_Status_SetErrorFormat(status, "Invalid edition UNKNOWN specified"); | |
| return false; | |
| } | |
| if (edition <= prev_edition) { | |
| upb_Status_SetErrorFormat(status, | |
| "Feature set defaults are not strictly " | |
| "increasing, %s is greater than or equal to %s", | |
| upb_FileDef_EditionName(prev_edition), | |
| upb_FileDef_EditionName(edition)); | |
| return false; | |
| } | |
| prev_edition = edition; | |
| } | |
| // Copy the defaults into the pool. | |
| s->feature_set_defaults = defaults; | |
| return true; | |
| } | |
| bool _upb_DefPool_InsertExt(upb_DefPool* s, const upb_MiniTableExtension* ext, | |
| const upb_FieldDef* f) { | |
| return upb_inttable_insert(&s->exts, (uintptr_t)ext, upb_value_constptr(f), | |
| s->arena); | |
| } | |
| bool _upb_DefPool_InsertSym(upb_DefPool* s, upb_StringView sym, upb_value v, | |
| upb_Status* status) { | |
| // TODO: table should support an operation "tryinsert" to avoid the double | |
| // lookup. | |
| if (upb_strtable_lookup2(&s->syms, sym.data, sym.size, NULL)) { | |
| upb_Status_SetErrorFormat(status, "duplicate symbol '%s'", sym.data); | |
| return false; | |
| } | |
| if (!upb_strtable_insert(&s->syms, sym.data, sym.size, v, s->arena)) { | |
| upb_Status_SetErrorMessage(status, "out of memory"); | |
| return false; | |
| } | |
| return true; | |
| } | |
| static const void* _upb_DefPool_Unpack(const upb_DefPool* s, const char* sym, | |
| size_t size, upb_deftype_t type) { | |
| upb_value v; | |
| return upb_strtable_lookup2(&s->syms, sym, size, &v) | |
| ? _upb_DefType_Unpack(v, type) | |
| : NULL; | |
| } | |
| bool _upb_DefPool_LookupSym(const upb_DefPool* s, const char* sym, size_t size, | |
| upb_value* v) { | |
| return upb_strtable_lookup2(&s->syms, sym, size, v); | |
| } | |
| upb_ExtensionRegistry* _upb_DefPool_ExtReg(const upb_DefPool* s) { | |
| return s->extreg; | |
| } | |
| void** _upb_DefPool_ScratchData(const upb_DefPool* s) { | |
| return (void**)&s->scratch_data; | |
| } | |
| size_t* _upb_DefPool_ScratchSize(const upb_DefPool* s) { | |
| return (size_t*)&s->scratch_size; | |
| } | |
| void _upb_DefPool_SetPlatform(upb_DefPool* s, upb_MiniTablePlatform platform) { | |
| assert(upb_strtable_count(&s->files) == 0); | |
| s->platform = platform; | |
| } | |
| const upb_MessageDef* upb_DefPool_FindMessageByName(const upb_DefPool* s, | |
| const char* sym) { | |
| return upb_DefPool_FindMessageByNameWithSize(s, sym, strlen(sym)); | |
| } | |
| const upb_MessageDef* upb_DefPool_FindMessageByNameWithSize( | |
| const upb_DefPool* s, const char* sym, size_t len) { | |
| return _upb_DefPool_Unpack(s, sym, len, UPB_DEFTYPE_MSG); | |
| } | |
| const upb_EnumDef* upb_DefPool_FindEnumByName(const upb_DefPool* s, | |
| const char* sym) { | |
| return upb_DefPool_FindEnumByNameWithSize(s, sym, strlen(sym)); | |
| } | |
| const upb_EnumDef* upb_DefPool_FindEnumByNameWithSize(const upb_DefPool* s, | |
| const char* sym, | |
| size_t len) { | |
| return _upb_DefPool_Unpack(s, sym, len, UPB_DEFTYPE_ENUM); | |
| } | |
| const upb_EnumValueDef* upb_DefPool_FindEnumValueByName(const upb_DefPool* s, | |
| const char* sym) { | |
| return upb_DefPool_FindEnumValueByNameWithSize(s, sym, strlen(sym)); | |
| } | |
| const upb_EnumValueDef* upb_DefPool_FindEnumValueByNameWithSize( | |
| const upb_DefPool* s, const char* sym, size_t len) { | |
| return _upb_DefPool_Unpack(s, sym, len, UPB_DEFTYPE_ENUMVAL); | |
| } | |
| const upb_FileDef* upb_DefPool_FindFileByName(const upb_DefPool* s, | |
| const char* name) { | |
| upb_value v; | |
| return upb_strtable_lookup(&s->files, name, &v) ? upb_value_getconstptr(v) | |
| : NULL; | |
| } | |
| const upb_FileDef* upb_DefPool_FindFileByNameWithSize(const upb_DefPool* s, | |
| const char* name, | |
| size_t len) { | |
| upb_value v; | |
| return upb_strtable_lookup2(&s->files, name, len, &v) | |
| ? upb_value_getconstptr(v) | |
| : NULL; | |
| } | |
| const upb_FieldDef* upb_DefPool_FindExtensionByNameWithSize( | |
| const upb_DefPool* s, const char* name, size_t size) { | |
| upb_value v; | |
| if (!upb_strtable_lookup2(&s->syms, name, size, &v)) return NULL; | |
| switch (_upb_DefType_Type(v)) { | |
| case UPB_DEFTYPE_FIELD: | |
| return _upb_DefType_Unpack(v, UPB_DEFTYPE_FIELD); | |
| case UPB_DEFTYPE_MSG: { | |
| const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); | |
| if (_upb_MessageDef_InMessageSet(m)) { | |
| for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) { | |
| const upb_FieldDef* ext = upb_MessageDef_NestedExtension(m, i); | |
| if (upb_FieldDef_MessageSubDef(ext) == m) { | |
| return ext; | |
| } | |
| } | |
| } | |
| return NULL; | |
| } | |
| default: | |
| break; | |
| } | |
| return NULL; | |
| } | |
| const upb_FieldDef* upb_DefPool_FindExtensionByName(const upb_DefPool* s, | |
| const char* sym) { | |
| return upb_DefPool_FindExtensionByNameWithSize(s, sym, strlen(sym)); | |
| } | |
| const upb_ServiceDef* upb_DefPool_FindServiceByName(const upb_DefPool* s, | |
| const char* name) { | |
| return _upb_DefPool_Unpack(s, name, strlen(name), UPB_DEFTYPE_SERVICE); | |
| } | |
| const upb_ServiceDef* upb_DefPool_FindServiceByNameWithSize( | |
| const upb_DefPool* s, const char* name, size_t size) { | |
| return _upb_DefPool_Unpack(s, name, size, UPB_DEFTYPE_SERVICE); | |
| } | |
| const upb_FileDef* upb_DefPool_FindFileContainingSymbol(const upb_DefPool* s, | |
| const char* name) { | |
| upb_value v; | |
| // TODO: non-extension fields and oneofs. | |
| if (upb_strtable_lookup(&s->syms, name, &v)) { | |
| switch (_upb_DefType_Type(v)) { | |
| case UPB_DEFTYPE_EXT: { | |
| const upb_FieldDef* f = _upb_DefType_Unpack(v, UPB_DEFTYPE_EXT); | |
| return upb_FieldDef_File(f); | |
| } | |
| case UPB_DEFTYPE_MSG: { | |
| const upb_MessageDef* m = _upb_DefType_Unpack(v, UPB_DEFTYPE_MSG); | |
| return upb_MessageDef_File(m); | |
| } | |
| case UPB_DEFTYPE_ENUM: { | |
| const upb_EnumDef* e = _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUM); | |
| return upb_EnumDef_File(e); | |
| } | |
| case UPB_DEFTYPE_ENUMVAL: { | |
| const upb_EnumValueDef* ev = | |
| _upb_DefType_Unpack(v, UPB_DEFTYPE_ENUMVAL); | |
| return upb_EnumDef_File(upb_EnumValueDef_Enum(ev)); | |
| } | |
| case UPB_DEFTYPE_SERVICE: { | |
| const upb_ServiceDef* service = | |
| _upb_DefType_Unpack(v, UPB_DEFTYPE_SERVICE); | |
| return upb_ServiceDef_File(service); | |
| } | |
| default: | |
| UPB_UNREACHABLE(); | |
| } | |
| } | |
| const char* last_dot = strrchr(name, '.'); | |
| if (last_dot) { | |
| const upb_MessageDef* parent = | |
| upb_DefPool_FindMessageByNameWithSize(s, name, last_dot - name); | |
| if (parent) { | |
| const char* shortname = last_dot + 1; | |
| if (upb_MessageDef_FindByNameWithSize(parent, shortname, | |
| strlen(shortname), NULL, NULL)) { | |
| return upb_MessageDef_File(parent); | |
| } | |
| } | |
| } | |
| return NULL; | |
| } | |
| static void remove_filedef(upb_DefPool* s, upb_FileDef* file) { | |
| intptr_t ext_iter = UPB_INTTABLE_BEGIN; | |
| uintptr_t ext_key; | |
| upb_value ext_val; | |
| while (upb_inttable_next(&s->exts, &ext_key, &ext_val, &ext_iter)) { | |
| const upb_FieldDef* ext = upb_value_getconstptr(ext_val); | |
| if (upb_FieldDef_File(ext) == file) { | |
| upb_inttable_removeiter(&s->exts, &ext_iter); | |
| } | |
| } | |
| intptr_t iter = UPB_INTTABLE_BEGIN; | |
| upb_StringView key; | |
| upb_value val; | |
| while (upb_strtable_next2(&s->syms, &key, &val, &iter)) { | |
| const upb_FileDef* f; | |
| switch (_upb_DefType_Type(val)) { | |
| case UPB_DEFTYPE_EXT: | |
| f = upb_FieldDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_EXT)); | |
| break; | |
| case UPB_DEFTYPE_MSG: | |
| f = upb_MessageDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_MSG)); | |
| break; | |
| case UPB_DEFTYPE_ENUM: | |
| f = upb_EnumDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_ENUM)); | |
| break; | |
| case UPB_DEFTYPE_ENUMVAL: | |
| f = upb_EnumDef_File(upb_EnumValueDef_Enum( | |
| _upb_DefType_Unpack(val, UPB_DEFTYPE_ENUMVAL))); | |
| break; | |
| case UPB_DEFTYPE_SERVICE: | |
| f = upb_ServiceDef_File(_upb_DefType_Unpack(val, UPB_DEFTYPE_SERVICE)); | |
| break; | |
| default: | |
| UPB_UNREACHABLE(); | |
| } | |
| if (f == file) upb_strtable_removeiter(&s->syms, &iter); | |
| } | |
| } | |
| static const upb_FileDef* upb_DefBuilder_AddFileToPool( | |
| upb_DefBuilder* const builder, upb_DefPool* const s, | |
| const google_protobuf_FileDescriptorProto* const file_proto, | |
| const upb_StringView name, upb_Status* const status) { | |
| if (UPB_SETJMP(builder->err) != 0) { | |
| UPB_ASSERT(!upb_Status_IsOk(status)); | |
| if (builder->file) { | |
| remove_filedef(s, builder->file); | |
| builder->file = NULL; | |
| } | |
| } else if (!builder->arena || !builder->tmp_arena || | |
| !upb_strtable_init(&builder->feature_cache, 16, | |
| builder->tmp_arena) || | |
| !(builder->legacy_features = | |
| google_protobuf_FeatureSet_new(builder->tmp_arena))) { | |
| _upb_DefBuilder_OomErr(builder); | |
| } else { | |
| _upb_FileDef_Create(builder, file_proto); | |
| bool ok = | |
| upb_strtable_insert(&s->files, name.data, name.size, | |
| upb_value_constptr(builder->file), builder->arena); | |
| UPB_ASSERT(ok); | |
| UPB_ASSERT(upb_Status_IsOk(status)); | |
| ok = upb_Arena_Fuse(s->arena, builder->arena); | |
| UPB_ASSERT(ok); | |
| } | |
| if (builder->arena) upb_Arena_Free(builder->arena); | |
| if (builder->tmp_arena) upb_Arena_Free(builder->tmp_arena); | |
| return builder->file; | |
| } | |
| static const upb_FileDef* _upb_DefPool_AddFile( | |
| upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, | |
| const upb_MiniTableFile* layout, upb_Status* status) { | |
| const upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto); | |
| // Determine whether we already know about this file. | |
| { | |
| upb_value v; | |
| if (upb_strtable_lookup2(&s->files, name.data, name.size, &v)) { | |
| upb_Status_SetErrorFormat(status, | |
| "duplicate file name " UPB_STRINGVIEW_FORMAT, | |
| UPB_STRINGVIEW_ARGS(name)); | |
| return NULL; | |
| } | |
| } | |
| upb_DefBuilder ctx = { | |
| .symtab = s, | |
| .tmp_buf = NULL, | |
| .tmp_buf_size = 0, | |
| .layout = layout, | |
| .platform = s->platform, | |
| .msg_count = 0, | |
| .enum_count = 0, | |
| .ext_count = 0, | |
| .status = status, | |
| .file = NULL, | |
| .arena = upb_Arena_New(), | |
| .tmp_arena = upb_Arena_New(), | |
| }; | |
| return upb_DefBuilder_AddFileToPool(&ctx, s, file_proto, name, status); | |
| } | |
| const upb_FileDef* upb_DefPool_AddFile( | |
| upb_DefPool* s, const google_protobuf_FileDescriptorProto* file_proto, | |
| upb_Status* status) { | |
| return _upb_DefPool_AddFile(s, file_proto, NULL, status); | |
| } | |
| bool _upb_DefPool_LoadDefInitEx(upb_DefPool* s, const _upb_DefPool_Init* init, | |
| bool rebuild_minitable) { | |
| /* Since this function should never fail (it would indicate a bug in upb) we | |
| * print errors to stderr instead of returning error status to the user. */ | |
| _upb_DefPool_Init** deps = init->deps; | |
| google_protobuf_FileDescriptorProto* file; | |
| upb_Arena* arena; | |
| upb_Status status; | |
| upb_Status_Clear(&status); | |
| if (upb_DefPool_FindFileByName(s, init->filename)) { | |
| return true; | |
| } | |
| arena = upb_Arena_New(); | |
| for (; *deps; deps++) { | |
| if (!_upb_DefPool_LoadDefInitEx(s, *deps, rebuild_minitable)) goto err; | |
| } | |
| file = google_protobuf_FileDescriptorProto_parse_ex( | |
| init->descriptor.data, init->descriptor.size, NULL, | |
| kUpb_DecodeOption_AliasString, arena); | |
| s->bytes_loaded += init->descriptor.size; | |
| if (!file) { | |
| upb_Status_SetErrorFormat( | |
| &status, | |
| "Failed to parse compiled-in descriptor for file '%s'. This should " | |
| "never happen.", | |
| init->filename); | |
| goto err; | |
| } | |
| const upb_MiniTableFile* mt = rebuild_minitable ? NULL : init->layout; | |
| if (!_upb_DefPool_AddFile(s, file, mt, &status)) { | |
| goto err; | |
| } | |
| upb_Arena_Free(arena); | |
| return true; | |
| err: | |
| fprintf(stderr, | |
| "Error loading compiled-in descriptor for file '%s' (this should " | |
| "never happen): %s\n", | |
| init->filename, upb_Status_ErrorMessage(&status)); | |
| upb_Arena_Free(arena); | |
| return false; | |
| } | |
| size_t _upb_DefPool_BytesLoaded(const upb_DefPool* s) { | |
| return s->bytes_loaded; | |
| } | |
| upb_Arena* _upb_DefPool_Arena(const upb_DefPool* s) { return s->arena; } | |
| const upb_FieldDef* upb_DefPool_FindExtensionByMiniTable( | |
| const upb_DefPool* s, const upb_MiniTableExtension* ext) { | |
| upb_value v; | |
| bool ok = upb_inttable_lookup(&s->exts, (uintptr_t)ext, &v); | |
| UPB_ASSERT(ok); | |
| return upb_value_getconstptr(v); | |
| } | |
| const upb_FieldDef* upb_DefPool_FindExtensionByNumber(const upb_DefPool* s, | |
| const upb_MessageDef* m, | |
| int32_t fieldnum) { | |
| const upb_MiniTable* t = upb_MessageDef_MiniTable(m); | |
| const upb_MiniTableExtension* ext = | |
| upb_ExtensionRegistry_Lookup(s->extreg, t, fieldnum); | |
| return ext ? upb_DefPool_FindExtensionByMiniTable(s, ext) : NULL; | |
| } | |
| const upb_ExtensionRegistry* upb_DefPool_ExtensionRegistry( | |
| const upb_DefPool* s) { | |
| return s->extreg; | |
| } | |
| const upb_FieldDef** upb_DefPool_GetAllExtensions(const upb_DefPool* s, | |
| const upb_MessageDef* m, | |
| size_t* count) { | |
| size_t n = 0; | |
| intptr_t iter = UPB_INTTABLE_BEGIN; | |
| uintptr_t key; | |
| upb_value val; | |
| // This is O(all exts) instead of O(exts for m). If we need this to be | |
| // efficient we may need to make extreg into a two-level table, or have a | |
| // second per-message index. | |
| while (upb_inttable_next(&s->exts, &key, &val, &iter)) { | |
| const upb_FieldDef* f = upb_value_getconstptr(val); | |
| if (upb_FieldDef_ContainingType(f) == m) n++; | |
| } | |
| const upb_FieldDef** exts = upb_gmalloc(n * sizeof(*exts)); | |
| iter = UPB_INTTABLE_BEGIN; | |
| size_t i = 0; | |
| while (upb_inttable_next(&s->exts, &key, &val, &iter)) { | |
| const upb_FieldDef* f = upb_value_getconstptr(val); | |
| if (upb_FieldDef_ContainingType(f) == m) exts[i++] = f; | |
| } | |
| *count = n; | |
| return exts; | |
| } | |
| bool _upb_DefPool_LoadDefInit(upb_DefPool* s, const _upb_DefPool_Init* init) { | |
| return _upb_DefPool_LoadDefInitEx(s, init, false); | |
| } | |
| const upb_ExtensionRegistry* _upb_DefPool_GeneratedExtensionRegistry( | |
| const upb_DefPool* s) { | |
| return upb_GeneratedRegistry_Get(s->generated_extreg); | |
| } | |
| // Must be last. | |
| upb_deftype_t _upb_DefType_Type(upb_value v) { | |
| const uintptr_t num = (uintptr_t)upb_value_getconstptr(v); | |
| return num & UPB_DEFTYPE_MASK; | |
| } | |
| upb_value _upb_DefType_Pack(const void* ptr, upb_deftype_t type) { | |
| uintptr_t num = (uintptr_t)ptr; | |
| UPB_ASSERT((num & UPB_DEFTYPE_MASK) == 0); | |
| num |= type; | |
| return upb_value_constptr((const void*)num); | |
| } | |
| const void* _upb_DefType_Unpack(upb_value v, upb_deftype_t type) { | |
| uintptr_t num = (uintptr_t)upb_value_getconstptr(v); | |
| return (num & UPB_DEFTYPE_MASK) == type | |
| ? (const void*)(num & ~UPB_DEFTYPE_MASK) | |
| : NULL; | |
| } | |
| // Must be last. | |
| bool _upb_DescState_Grow(upb_DescState* d, upb_Arena* a) { | |
| const size_t oldbufsize = d->bufsize; | |
| const int used = d->ptr - d->buf; | |
| if (!d->buf) { | |
| d->buf = upb_Arena_Malloc(a, d->bufsize); | |
| if (!d->buf) return false; | |
| d->ptr = d->buf; | |
| d->e.end = d->buf + d->bufsize; | |
| } | |
| if (oldbufsize - used < kUpb_MtDataEncoder_MinSize) { | |
| d->bufsize *= 2; | |
| d->buf = upb_Arena_Realloc(a, d->buf, oldbufsize, d->bufsize); | |
| if (!d->buf) return false; | |
| d->ptr = d->buf + used; | |
| d->e.end = d->buf + d->bufsize; | |
| } | |
| return true; | |
| } | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| struct upb_EnumDef { | |
| UPB_ALIGN_AS(8) const google_protobuf_EnumOptions* opts; | |
| const google_protobuf_FeatureSet* resolved_features; | |
| const upb_MiniTableEnum* layout; // Only for proto2. | |
| const upb_FileDef* file; | |
| const upb_MessageDef* containing_type; // Could be merged with "file". | |
| const char* full_name; | |
| upb_strtable ntoi; | |
| upb_inttable iton; | |
| const upb_EnumValueDef* values; | |
| const upb_EnumReservedRange* res_ranges; | |
| const upb_StringView* res_names; | |
| int value_count; | |
| int res_range_count; | |
| int res_name_count; | |
| int32_t defaultval; | |
| google_protobuf_SymbolVisibility visibility; | |
| bool is_sorted; // Whether all of the values are defined in ascending order. | |
| }; | |
| // We store both regular proto enum names and custom JSON enum names in the | |
| // same strtable (ntoi). This is safe because protoc enforces that custom JSON | |
| // enum names never conflict with default enum names across different enum | |
| // values (or are identical, in which case we leave the entry untagged). Because | |
| // upb_EnumValueDef pointers are arena-aligned to at least 4 bytes (bit 0 is | |
| // always 0 for untagged pointers), we set bit 0 to tag custom JSON-only names | |
| // so that regular name lookups can ignore them. | |
| static const uintptr_t kUpb_EnumDef_JsonOnlyTag = 1ULL; | |
| static upb_value _upb_EnumDef_TagJsonOnly(upb_value v) { | |
| v.val |= kUpb_EnumDef_JsonOnlyTag; | |
| return v; | |
| } | |
| static bool _upb_EnumDef_IsJsonOnly(upb_value v) { | |
| return (v.val & kUpb_EnumDef_JsonOnlyTag) != 0; | |
| } | |
| static const upb_EnumValueDef* _upb_EnumDef_Untag(upb_value v) { | |
| return (const upb_EnumValueDef*)(v.val & ~kUpb_EnumDef_JsonOnlyTag); | |
| } | |
| upb_EnumDef* _upb_EnumDef_At(const upb_EnumDef* e, int i) { | |
| return (upb_EnumDef*)&e[i]; | |
| } | |
| const upb_MiniTableEnum* _upb_EnumDef_MiniTable(const upb_EnumDef* e) { | |
| return e->layout; | |
| } | |
| void _upb_EnumDef_Insert(upb_DefBuilder* ctx, upb_EnumDef* e, | |
| upb_EnumValueDef* v) { | |
| const char* name = upb_EnumValueDef_Name(v); | |
| const upb_value val = upb_value_constptr(v); | |
| bool ok = upb_strtable_insert(&e->ntoi, name, strlen(name), val, ctx->arena); | |
| if (!ok) _upb_DefBuilder_OomErr(ctx); | |
| // Aliased enum values can share the same custom JSON name, first one wins. | |
| const char* json_name = upb_EnumValueDef_JsonName(v); | |
| size_t json_len = strlen(json_name); | |
| if (strcmp(json_name, name) != 0) { | |
| upb_value existing_value; | |
| if (upb_strtable_lookup2(&e->ntoi, json_name, json_len, &existing_value)) { | |
| const upb_EnumValueDef* enumval = _upb_EnumDef_Untag(existing_value); | |
| if (upb_EnumValueDef_Number(enumval) != upb_EnumValueDef_Number(v)) { | |
| // If the custom JSON name exists, but points to a value with a | |
| // different number, then this is a parse/conflict error. | |
| _upb_DefBuilder_Errf(ctx, | |
| "duplicate custom json_name (%s) in enum (%s)", | |
| json_name, upb_EnumDef_FullName(e)); | |
| } | |
| } else { | |
| upb_value json_val = _upb_EnumDef_TagJsonOnly(val); | |
| if (!upb_strtable_insert(&e->ntoi, json_name, json_len, json_val, | |
| ctx->arena)) { | |
| _upb_DefBuilder_OomErr(ctx); | |
| } | |
| } | |
| } | |
| // Multiple enum values can have the same number, first one wins. | |
| const int number = upb_EnumValueDef_Number(v); | |
| if (!upb_inttable_lookup(&e->iton, number, NULL)) { | |
| if (!upb_inttable_insert(&e->iton, number, val, ctx->arena)) { | |
| _upb_DefBuilder_OomErr(ctx); | |
| } | |
| } | |
| } | |
| const google_protobuf_EnumOptions* upb_EnumDef_Options(const upb_EnumDef* e) { | |
| return e->opts; | |
| } | |
| bool upb_EnumDef_HasOptions(const upb_EnumDef* e) { | |
| return e->opts != (void*)kUpbDefOptDefault; | |
| } | |
| const google_protobuf_FeatureSet* upb_EnumDef_ResolvedFeatures(const upb_EnumDef* e) { | |
| return e->resolved_features; | |
| } | |
| google_protobuf_SymbolVisibility upb_EnumDef_Visibility(const upb_EnumDef* e) { | |
| return e->visibility; | |
| } | |
| const char* upb_EnumDef_FullName(const upb_EnumDef* e) { return e->full_name; } | |
| const char* upb_EnumDef_Name(const upb_EnumDef* e) { | |
| return _upb_DefBuilder_FullToShort(e->full_name); | |
| } | |
| const upb_FileDef* upb_EnumDef_File(const upb_EnumDef* e) { return e->file; } | |
| const upb_MessageDef* upb_EnumDef_ContainingType(const upb_EnumDef* e) { | |
| return e->containing_type; | |
| } | |
| int32_t upb_EnumDef_Default(const upb_EnumDef* e) { | |
| UPB_ASSERT(upb_EnumDef_FindValueByNumber(e, e->defaultval)); | |
| return e->defaultval; | |
| } | |
| int upb_EnumDef_ReservedRangeCount(const upb_EnumDef* e) { | |
| return e->res_range_count; | |
| } | |
| const upb_EnumReservedRange* upb_EnumDef_ReservedRange(const upb_EnumDef* e, | |
| int i) { | |
| UPB_ASSERT(0 <= i && i < e->res_range_count); | |
| return _upb_EnumReservedRange_At(e->res_ranges, i); | |
| } | |
| int upb_EnumDef_ReservedNameCount(const upb_EnumDef* e) { | |
| return e->res_name_count; | |
| } | |
| upb_StringView upb_EnumDef_ReservedName(const upb_EnumDef* e, int i) { | |
| UPB_ASSERT(0 <= i && i < e->res_name_count); | |
| return e->res_names[i]; | |
| } | |
| int upb_EnumDef_ValueCount(const upb_EnumDef* e) { return e->value_count; } | |
| const upb_EnumValueDef* upb_EnumDef_FindByJsonNameWithSize(const upb_EnumDef* e, | |
| const char* name, | |
| size_t size) { | |
| upb_value v; | |
| if (!upb_strtable_lookup2(&e->ntoi, name, size, &v)) { | |
| return NULL; | |
| } | |
| return _upb_EnumDef_Untag(v); | |
| } | |
| const upb_EnumValueDef* upb_EnumDef_FindValueByName(const upb_EnumDef* e, | |
| const char* name) { | |
| return upb_EnumDef_FindValueByNameWithSize(e, name, strlen(name)); | |
| } | |
| const upb_EnumValueDef* upb_EnumDef_FindValueByNameWithSize( | |
| const upb_EnumDef* e, const char* name, size_t size) { | |
| upb_value v; | |
| if (!upb_strtable_lookup2(&e->ntoi, name, size, &v)) { | |
| return NULL; | |
| } | |
| if (_upb_EnumDef_IsJsonOnly(v)) { | |
| return NULL; | |
| } | |
| return upb_value_getconstptr(v); | |
| } | |
| const upb_EnumValueDef* upb_EnumDef_FindValueByNumber(const upb_EnumDef* e, | |
| int32_t num) { | |
| upb_value v; | |
| return upb_inttable_lookup(&e->iton, num, &v) ? upb_value_getconstptr(v) | |
| : NULL; | |
| } | |
| bool upb_EnumDef_CheckNumber(const upb_EnumDef* e, int32_t num) { | |
| // We could use upb_EnumDef_FindValueByNumber(e, num) != NULL, but we expect | |
| // this to be faster (especially for small numbers). | |
| return upb_MiniTableEnum_CheckValue(e->layout, num); | |
| } | |
| const upb_EnumValueDef* upb_EnumDef_Value(const upb_EnumDef* e, int i) { | |
| UPB_ASSERT(0 <= i && i < e->value_count); | |
| return _upb_EnumValueDef_At(e->values, i); | |
| } | |
| static bool upb_EnumDef_IsSpecifiedAsClosed(const upb_EnumDef* e) { | |
| return google_protobuf_FeatureSet_enum_type(e->resolved_features) == | |
| google_protobuf_FeatureSet_CLOSED; | |
| } | |
| bool upb_EnumDef_IsClosed(const upb_EnumDef* e) { | |
| if (_upb_FileDef_ClosedEnumCheckingDisabled(e->file)) return false; | |
| return upb_EnumDef_IsSpecifiedAsClosed(e); | |
| } | |
| bool upb_EnumDef_MiniDescriptorEncode(const upb_EnumDef* e, upb_Arena* a, | |
| upb_StringView* out) { | |
| upb_DescState s; | |
| _upb_DescState_Init(&s); | |
| const upb_EnumValueDef** sorted = NULL; | |
| if (!e->is_sorted) { | |
| sorted = _upb_EnumValueDefs_Sorted(e->values, e->value_count, a); | |
| if (!sorted) return false; | |
| } | |
| if (!_upb_DescState_Grow(&s, a)) return false; | |
| s.ptr = upb_MtDataEncoder_StartEnum(&s.e, s.ptr); | |
| // Duplicate values are allowed but we only encode each value once. | |
| uint32_t previous = 0; | |
| for (int i = 0; i < e->value_count; i++) { | |
| const uint32_t current = | |
| upb_EnumValueDef_Number(sorted ? sorted[i] : upb_EnumDef_Value(e, i)); | |
| if (i != 0 && previous == current) continue; | |
| if (!_upb_DescState_Grow(&s, a)) return false; | |
| s.ptr = upb_MtDataEncoder_PutEnumValue(&s.e, s.ptr, current); | |
| previous = current; | |
| } | |
| if (!_upb_DescState_Grow(&s, a)) return false; | |
| s.ptr = upb_MtDataEncoder_EndEnum(&s.e, s.ptr); | |
| // There will always be room for this '\0' in the encoder buffer because | |
| // kUpb_MtDataEncoder_MinSize is overkill for upb_MtDataEncoder_EndEnum(). | |
| UPB_ASSERT(s.ptr < s.buf + s.bufsize); | |
| *s.ptr = '\0'; | |
| out->data = s.buf; | |
| out->size = s.ptr - s.buf; | |
| return true; | |
| } | |
| static upb_MiniTableEnum* create_enumlayout(upb_DefBuilder* ctx, | |
| const upb_EnumDef* e) { | |
| upb_StringView sv; | |
| bool ok = upb_EnumDef_MiniDescriptorEncode(e, ctx->tmp_arena, &sv); | |
| if (!ok) _upb_DefBuilder_Errf(ctx, "OOM while building enum MiniDescriptor"); | |
| upb_Status status; | |
| upb_MiniTableEnum* layout = | |
| upb_MiniTableEnum_Build(sv.data, sv.size, ctx->arena, &status); | |
| if (!layout) | |
| _upb_DefBuilder_Errf(ctx, "Error building enum MiniTable: %s", status.msg); | |
| return layout; | |
| } | |
| static upb_StringView* _upb_EnumReservedNames_New( | |
| upb_DefBuilder* ctx, int n, const upb_StringView* protos) { | |
| upb_StringView* sv = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_StringView, n); | |
| for (int i = 0; i < n; i++) { | |
| sv[i].data = | |
| upb_strdup2(protos[i].data, protos[i].size, _upb_DefBuilder_Arena(ctx)); | |
| sv[i].size = protos[i].size; | |
| } | |
| return sv; | |
| } | |
| static void create_enumdef(upb_DefBuilder* ctx, const char* prefix, | |
| const google_protobuf_EnumDescriptorProto* enum_proto, | |
| const google_protobuf_FeatureSet* parent_features, | |
| upb_EnumDef* e) { | |
| const google_protobuf_EnumValueDescriptorProto* const* values; | |
| const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* res_ranges; | |
| const upb_StringView* res_names; | |
| upb_StringView name; | |
| size_t n_value, n_res_range, n_res_name; | |
| UPB_DEF_SET_OPTIONS(e->opts, EnumDescriptorProto, EnumOptions, enum_proto); | |
| e->resolved_features = _upb_DefBuilder_ResolveFeatures( | |
| ctx, parent_features, google_protobuf_EnumOptions_features(e->opts)); | |
| // Must happen before _upb_DefBuilder_Add() | |
| e->file = _upb_DefBuilder_File(ctx); | |
| name = google_protobuf_EnumDescriptorProto_name(enum_proto); | |
| e->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); | |
| _upb_DefBuilder_Add(ctx, e->full_name, | |
| _upb_DefType_Pack(e, UPB_DEFTYPE_ENUM)); | |
| values = google_protobuf_EnumDescriptorProto_value(enum_proto, &n_value); | |
| if (n_value == 0) { | |
| _upb_DefBuilder_Errf(ctx, "enums must contain at least one value (%s)", | |
| e->full_name); | |
| } | |
| e->defaultval = google_protobuf_EnumValueDescriptorProto_number(values[0]); | |
| // When the special UPB_TREAT_CLOSED_ENUMS_LIKE_OPEN is enabled, we have to | |
| // exempt closed enums from this check, even when we are treating them as | |
| // open. | |
| // | |
| // We rely on the fact that the proto compiler will have already ensured that | |
| // implicit presence fields do not use closed enums, even if we are treating | |
| // them as open. | |
| if (!upb_EnumDef_IsSpecifiedAsClosed(e) && e->defaultval != 0) { | |
| _upb_DefBuilder_Errf(ctx, | |
| "for open enums, the first value must be zero (%s)", | |
| upb_EnumDef_FullName(e)); | |
| } | |
| bool ok = upb_strtable_init(&e->ntoi, n_value * 2, ctx->arena); | |
| if (!ok) _upb_DefBuilder_OomErr(ctx); | |
| ok = upb_inttable_init(&e->iton, ctx->arena); | |
| if (!ok) _upb_DefBuilder_OomErr(ctx); | |
| e->value_count = n_value; | |
| e->values = _upb_EnumValueDefs_New(ctx, prefix, n_value, values, | |
| e->resolved_features, e, &e->is_sorted); | |
| res_ranges = | |
| google_protobuf_EnumDescriptorProto_reserved_range(enum_proto, &n_res_range); | |
| e->res_range_count = n_res_range; | |
| e->res_ranges = _upb_EnumReservedRanges_New(ctx, n_res_range, res_ranges, e); | |
| res_names = google_protobuf_EnumDescriptorProto_reserved_name(enum_proto, &n_res_name); | |
| e->res_name_count = n_res_name; | |
| e->res_names = _upb_EnumReservedNames_New(ctx, n_res_name, res_names); | |
| e->visibility = google_protobuf_EnumDescriptorProto_visibility(enum_proto); | |
| if (upb_EnumDef_IsClosed(e)) { | |
| if (ctx->layout) { | |
| e->layout = upb_MiniTableFile_Enum(ctx->layout, ctx->enum_count++); | |
| } else { | |
| e->layout = create_enumlayout(ctx, e); | |
| } | |
| } else { | |
| e->layout = NULL; | |
| } | |
| } | |
| upb_EnumDef* _upb_EnumDefs_New(upb_DefBuilder* ctx, int n, | |
| const google_protobuf_EnumDescriptorProto* const* protos, | |
| const google_protobuf_FeatureSet* parent_features, | |
| const upb_MessageDef* containing_type) { | |
| _upb_DefType_CheckPadding(sizeof(upb_EnumDef)); | |
| // If a containing type is defined then get the full name from that. | |
| // Otherwise use the package name from the file def. | |
| const char* name = containing_type ? upb_MessageDef_FullName(containing_type) | |
| : _upb_FileDef_RawPackage(ctx->file); | |
| upb_EnumDef* e = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_EnumDef, n); | |
| for (int i = 0; i < n; i++) { | |
| create_enumdef(ctx, name, protos[i], parent_features, &e[i]); | |
| e[i].containing_type = containing_type; | |
| } | |
| return e; | |
| } | |
| #include <stdint.h> | |
| // Must be last. | |
| struct upb_EnumReservedRange { | |
| int32_t start; | |
| int32_t end; | |
| }; | |
| upb_EnumReservedRange* _upb_EnumReservedRange_At(const upb_EnumReservedRange* r, | |
| int i) { | |
| return (upb_EnumReservedRange*)&r[i]; | |
| } | |
| int32_t upb_EnumReservedRange_Start(const upb_EnumReservedRange* r) { | |
| return r->start; | |
| } | |
| int32_t upb_EnumReservedRange_End(const upb_EnumReservedRange* r) { | |
| return r->end; | |
| } | |
| upb_EnumReservedRange* _upb_EnumReservedRanges_New( | |
| upb_DefBuilder* ctx, int n, | |
| const google_protobuf_EnumDescriptorProto_EnumReservedRange* const* protos, | |
| const upb_EnumDef* e) { | |
| upb_EnumReservedRange* r = | |
| UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_EnumReservedRange, n); | |
| for (int i = 0; i < n; i++) { | |
| const int32_t start = | |
| google_protobuf_EnumDescriptorProto_EnumReservedRange_start(protos[i]); | |
| const int32_t end = | |
| google_protobuf_EnumDescriptorProto_EnumReservedRange_end(protos[i]); | |
| // A full validation would also check that each range is disjoint, and that | |
| // none of the fields overlap with the extension ranges, but we are just | |
| // sanity checking here. | |
| // Note: Not a typo! Unlike extension ranges and message reserved ranges, | |
| // the end value of an enum reserved range is *inclusive*! | |
| if (end < start) { | |
| _upb_DefBuilder_Errf(ctx, "Reserved range (%d, %d) is invalid, enum=%s\n", | |
| (int)start, (int)end, upb_EnumDef_FullName(e)); | |
| } | |
| r[i].start = start; | |
| r[i].end = end; | |
| } | |
| return r; | |
| } | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <stdlib.h> | |
| // Must be last. | |
| struct upb_EnumValueDef { | |
| UPB_ALIGN_AS(8) const google_protobuf_EnumValueOptions* opts; | |
| const google_protobuf_FeatureSet* resolved_features; | |
| const upb_EnumDef* parent; | |
| const char* full_name; | |
| const char* json_name; | |
| int32_t number; | |
| }; | |
| upb_EnumValueDef* _upb_EnumValueDef_At(const upb_EnumValueDef* v, int i) { | |
| return (upb_EnumValueDef*)&v[i]; | |
| } | |
| static int _upb_EnumValueDef_Compare(const void* p1, const void* p2) { | |
| const uint32_t v1 = (*(const upb_EnumValueDef**)p1)->number; | |
| const uint32_t v2 = (*(const upb_EnumValueDef**)p2)->number; | |
| return (v1 < v2) ? -1 : (v1 > v2); | |
| } | |
| const upb_EnumValueDef** _upb_EnumValueDefs_Sorted(const upb_EnumValueDef* v, | |
| size_t n, upb_Arena* a) { | |
| size_t bytes; | |
| if (upb_MulOverflow(n, sizeof(void*), &bytes)) return NULL; | |
| // TODO: Try to replace this arena alloc with a persistent scratch buffer. | |
| upb_EnumValueDef** out = (upb_EnumValueDef**)upb_Arena_Malloc(a, bytes); | |
| if (!out) return NULL; | |
| for (size_t i = 0; i < n; i++) { | |
| out[i] = (upb_EnumValueDef*)&v[i]; | |
| } | |
| qsort(out, n, sizeof(void*), _upb_EnumValueDef_Compare); | |
| return (const upb_EnumValueDef**)out; | |
| } | |
| const google_protobuf_EnumValueOptions* upb_EnumValueDef_Options( | |
| const upb_EnumValueDef* v) { | |
| return v->opts; | |
| } | |
| bool upb_EnumValueDef_HasOptions(const upb_EnumValueDef* v) { | |
| return v->opts != (void*)kUpbDefOptDefault; | |
| } | |
| const google_protobuf_FeatureSet* upb_EnumValueDef_ResolvedFeatures( | |
| const upb_EnumValueDef* e) { | |
| return e->resolved_features; | |
| } | |
| const upb_EnumDef* upb_EnumValueDef_Enum(const upb_EnumValueDef* v) { | |
| return v->parent; | |
| } | |
| const char* upb_EnumValueDef_FullName(const upb_EnumValueDef* v) { | |
| return v->full_name; | |
| } | |
| const char* upb_EnumValueDef_JsonName(const upb_EnumValueDef* v) { | |
| return v->json_name ? v->json_name : upb_EnumValueDef_Name(v); | |
| } | |
| const char* upb_EnumValueDef_Name(const upb_EnumValueDef* v) { | |
| return _upb_DefBuilder_FullToShort(v->full_name); | |
| } | |
| int32_t upb_EnumValueDef_Number(const upb_EnumValueDef* v) { return v->number; } | |
| uint32_t upb_EnumValueDef_Index(const upb_EnumValueDef* v) { | |
| // Compute index in our parent's array. | |
| return v - upb_EnumDef_Value(v->parent, 0); | |
| } | |
| static const char* _upb_EnumValueDef_ExtractJsonName( | |
| upb_DefBuilder* ctx, const upb_EnumValueDef* v) { | |
| if (!upb_EnumValueDef_HasOptions(v)) return NULL; | |
| const google_protobuf_EnumValueOptions* opts = (const google_protobuf_EnumValueOptions*)v->opts; | |
| if (!pb_enumvalue_has_json(opts)) return NULL; | |
| const pb_enumvalue_JsonEnumValueOptions* json_opts = pb_enumvalue_json(opts); | |
| if (!json_opts || !pb_enumvalue_JsonEnumValueOptions_has_string(json_opts)) { | |
| return NULL; | |
| } | |
| upb_StringView str = pb_enumvalue_JsonEnumValueOptions_string(json_opts); | |
| return upb_strdup2(str.data, str.size, ctx->arena); | |
| } | |
| static void create_enumvaldef(upb_DefBuilder* ctx, const char* prefix, | |
| const google_protobuf_EnumValueDescriptorProto* val_proto, | |
| const google_protobuf_FeatureSet* parent_features, | |
| upb_EnumDef* e, upb_EnumValueDef* v) { | |
| UPB_DEF_SET_OPTIONS(v->opts, EnumValueDescriptorProto, EnumValueOptions, | |
| val_proto); | |
| v->resolved_features = _upb_DefBuilder_ResolveFeatures( | |
| ctx, parent_features, google_protobuf_EnumValueOptions_features(v->opts)); | |
| upb_StringView name = google_protobuf_EnumValueDescriptorProto_name(val_proto); | |
| v->parent = e; // Must happen prior to _upb_DefBuilder_Add() | |
| v->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); | |
| v->number = google_protobuf_EnumValueDescriptorProto_number(val_proto); | |
| v->json_name = _upb_EnumValueDef_ExtractJsonName(ctx, v); | |
| _upb_DefBuilder_Add(ctx, v->full_name, | |
| _upb_DefType_Pack(v, UPB_DEFTYPE_ENUMVAL)); | |
| _upb_EnumDef_Insert(ctx, e, v); | |
| } | |
| // Allocate and initialize an array of |n| enum value defs owned by |e|. | |
| upb_EnumValueDef* _upb_EnumValueDefs_New( | |
| upb_DefBuilder* ctx, const char* prefix, int n, | |
| const google_protobuf_EnumValueDescriptorProto* const* protos, | |
| const google_protobuf_FeatureSet* parent_features, upb_EnumDef* e, bool* is_sorted) { | |
| _upb_DefType_CheckPadding(sizeof(upb_EnumValueDef)); | |
| upb_EnumValueDef* v = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_EnumValueDef, n); | |
| *is_sorted = true; | |
| uint32_t previous = 0; | |
| for (int i = 0; i < n; i++) { | |
| create_enumvaldef(ctx, prefix, protos[i], parent_features, e, &v[i]); | |
| const uint32_t current = v[i].number; | |
| if (previous > current) *is_sorted = false; | |
| previous = current; | |
| } | |
| return v; | |
| } | |
| #include <stdint.h> | |
| // Must be last. | |
| struct upb_ExtensionRange { | |
| const google_protobuf_ExtensionRangeOptions* opts; | |
| const google_protobuf_FeatureSet* resolved_features; | |
| int32_t start; | |
| int32_t end; | |
| }; | |
| upb_ExtensionRange* _upb_ExtensionRange_At(const upb_ExtensionRange* r, int i) { | |
| return (upb_ExtensionRange*)&r[i]; | |
| } | |
| const google_protobuf_ExtensionRangeOptions* upb_ExtensionRange_Options( | |
| const upb_ExtensionRange* r) { | |
| return r->opts; | |
| } | |
| bool upb_ExtensionRange_HasOptions(const upb_ExtensionRange* r) { | |
| return r->opts != (void*)kUpbDefOptDefault; | |
| } | |
| int32_t upb_ExtensionRange_Start(const upb_ExtensionRange* r) { | |
| return r->start; | |
| } | |
| int32_t upb_ExtensionRange_End(const upb_ExtensionRange* r) { return r->end; } | |
| upb_ExtensionRange* _upb_ExtensionRanges_New( | |
| upb_DefBuilder* ctx, int n, | |
| const google_protobuf_DescriptorProto_ExtensionRange* const* protos, | |
| const google_protobuf_FeatureSet* parent_features, const upb_MessageDef* m) { | |
| upb_ExtensionRange* r = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_ExtensionRange, n); | |
| for (int i = 0; i < n; i++) { | |
| UPB_DEF_SET_OPTIONS(r[i].opts, DescriptorProto_ExtensionRange, | |
| ExtensionRangeOptions, protos[i]); | |
| r[i].resolved_features = _upb_DefBuilder_ResolveFeatures( | |
| ctx, parent_features, google_protobuf_ExtensionRangeOptions_features(r[i].opts)); | |
| const int32_t start = | |
| google_protobuf_DescriptorProto_ExtensionRange_start(protos[i]); | |
| const int32_t end = google_protobuf_DescriptorProto_ExtensionRange_end(protos[i]); | |
| const int32_t max = | |
| google_protobuf_MessageOptions_message_set_wire_format(upb_MessageDef_Options(m)) | |
| ? INT32_MAX | |
| : kUpb_MaxFieldNumber + 1; | |
| // A full validation would also check that each range is disjoint, and that | |
| // none of the fields overlap with the extension ranges, but we are just | |
| // sanity checking here. | |
| if (start < 1 || end <= start || end > max) { | |
| _upb_DefBuilder_Errf(ctx, | |
| "Extension range (%d, %d) is invalid, message=%s\n", | |
| (int)start, (int)end, upb_MessageDef_FullName(m)); | |
| } | |
| r[i].start = start; | |
| r[i].end = end; | |
| } | |
| return r; | |
| } | |
| #include <ctype.h> | |
| #include <errno.h> | |
| #include <stdbool.h> | |
| #include <stdint.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| // Must be last. | |
| #define UPB_FIELD_TYPE_UNSPECIFIED 0 | |
| typedef struct { | |
| size_t len; | |
| char str[1]; // Null-terminated string data follows. | |
| } str_t; | |
| struct upb_FieldDef { | |
| UPB_ALIGN_AS(8) const google_protobuf_FieldOptions* opts; | |
| const google_protobuf_FeatureSet* resolved_features; | |
| const upb_FileDef* file; | |
| const upb_MessageDef* msgdef; | |
| const char* full_name; | |
| const char* json_name; | |
| union { | |
| int64_t sint; | |
| uint64_t uint; | |
| double dbl; | |
| float flt; | |
| bool boolean; | |
| str_t* str; | |
| void* msg; // Always NULL. | |
| } defaultval; | |
| union { | |
| const upb_OneofDef* oneof; | |
| const upb_MessageDef* extension_scope; | |
| } scope; | |
| union { | |
| const upb_MessageDef* msgdef; | |
| const upb_EnumDef* enumdef; | |
| const google_protobuf_FieldDescriptorProto* unresolved; | |
| } sub; | |
| uint32_t number_; | |
| uint16_t index_; | |
| uint16_t layout_index; // Index into msgdef->layout->fields or file->exts | |
| bool has_default; | |
| bool has_json_name; | |
| bool has_presence; | |
| bool is_extension; | |
| bool is_proto3_optional; | |
| upb_FieldType type_; | |
| upb_Label label_; | |
| }; | |
| upb_FieldDef* _upb_FieldDef_At(const upb_FieldDef* f, int i) { | |
| return (upb_FieldDef*)&f[i]; | |
| } | |
| const google_protobuf_FieldOptions* upb_FieldDef_Options(const upb_FieldDef* f) { | |
| return f->opts; | |
| } | |
| bool upb_FieldDef_HasOptions(const upb_FieldDef* f) { | |
| return f->opts != (void*)kUpbDefOptDefault; | |
| } | |
| const google_protobuf_FeatureSet* upb_FieldDef_ResolvedFeatures(const upb_FieldDef* f) { | |
| return f->resolved_features; | |
| } | |
| const char* upb_FieldDef_FullName(const upb_FieldDef* f) { | |
| return f->full_name; | |
| } | |
| upb_CType upb_FieldDef_CType(const upb_FieldDef* f) { | |
| return upb_FieldType_CType(f->type_); | |
| } | |
| upb_FieldType upb_FieldDef_Type(const upb_FieldDef* f) { return f->type_; } | |
| uint32_t upb_FieldDef_Index(const upb_FieldDef* f) { return f->index_; } | |
| uint32_t upb_FieldDef_LayoutIndex(const upb_FieldDef* f) { | |
| return f->layout_index; | |
| } | |
| upb_Label upb_FieldDef_Label(const upb_FieldDef* f) { return f->label_; } | |
| uint32_t upb_FieldDef_Number(const upb_FieldDef* f) { return f->number_; } | |
| bool upb_FieldDef_IsExtension(const upb_FieldDef* f) { return f->is_extension; } | |
| bool _upb_FieldDef_IsPackable(const upb_FieldDef* f) { | |
| return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsPrimitive(f); | |
| } | |
| bool upb_FieldDef_IsPacked(const upb_FieldDef* f) { | |
| return _upb_FieldDef_IsPackable(f) && | |
| google_protobuf_FeatureSet_repeated_field_encoding(f->resolved_features) == | |
| google_protobuf_FeatureSet_PACKED; | |
| } | |
| const char* upb_FieldDef_Name(const upb_FieldDef* f) { | |
| return _upb_DefBuilder_FullToShort(f->full_name); | |
| } | |
| const char* upb_FieldDef_JsonName(const upb_FieldDef* f) { | |
| return f->json_name; | |
| } | |
| bool upb_FieldDef_HasJsonName(const upb_FieldDef* f) { | |
| return f->has_json_name; | |
| } | |
| const upb_FileDef* upb_FieldDef_File(const upb_FieldDef* f) { return f->file; } | |
| const upb_MessageDef* upb_FieldDef_ContainingType(const upb_FieldDef* f) { | |
| return f->msgdef; | |
| } | |
| const upb_MessageDef* upb_FieldDef_ExtensionScope(const upb_FieldDef* f) { | |
| return f->is_extension ? f->scope.extension_scope : NULL; | |
| } | |
| const upb_OneofDef* upb_FieldDef_ContainingOneof(const upb_FieldDef* f) { | |
| return f->is_extension ? NULL : f->scope.oneof; | |
| } | |
| const upb_OneofDef* upb_FieldDef_RealContainingOneof(const upb_FieldDef* f) { | |
| const upb_OneofDef* oneof = upb_FieldDef_ContainingOneof(f); | |
| if (!oneof || upb_OneofDef_IsSynthetic(oneof)) return NULL; | |
| return oneof; | |
| } | |
| upb_MessageValue upb_FieldDef_Default(const upb_FieldDef* f) { | |
| upb_MessageValue ret; | |
| if (upb_FieldDef_IsRepeated(f) || upb_FieldDef_IsSubMessage(f)) { | |
| return (upb_MessageValue){.msg_val = NULL}; | |
| } | |
| switch (upb_FieldDef_CType(f)) { | |
| case kUpb_CType_Bool: | |
| return (upb_MessageValue){.bool_val = f->defaultval.boolean}; | |
| case kUpb_CType_Int64: | |
| return (upb_MessageValue){.int64_val = f->defaultval.sint}; | |
| case kUpb_CType_UInt64: | |
| return (upb_MessageValue){.uint64_val = f->defaultval.uint}; | |
| case kUpb_CType_Enum: | |
| case kUpb_CType_Int32: | |
| return (upb_MessageValue){.int32_val = (int32_t)f->defaultval.sint}; | |
| case kUpb_CType_UInt32: | |
| return (upb_MessageValue){.uint32_val = (uint32_t)f->defaultval.uint}; | |
| case kUpb_CType_Float: | |
| return (upb_MessageValue){.float_val = f->defaultval.flt}; | |
| case kUpb_CType_Double: | |
| return (upb_MessageValue){.double_val = f->defaultval.dbl}; | |
| case kUpb_CType_String: | |
| case kUpb_CType_Bytes: { | |
| str_t* str = f->defaultval.str; | |
| if (str) { | |
| return (upb_MessageValue){ | |
| .str_val = (upb_StringView){.data = str->str, .size = str->len}}; | |
| } else { | |
| return (upb_MessageValue){ | |
| .str_val = (upb_StringView){.data = NULL, .size = 0}}; | |
| } | |
| } | |
| default: | |
| UPB_UNREACHABLE(); | |
| } | |
| return ret; | |
| } | |
| const upb_MessageDef* upb_FieldDef_MessageSubDef(const upb_FieldDef* f) { | |
| return upb_FieldDef_IsSubMessage(f) ? f->sub.msgdef : NULL; | |
| } | |
| const upb_EnumDef* upb_FieldDef_EnumSubDef(const upb_FieldDef* f) { | |
| return upb_FieldDef_IsEnum(f) ? f->sub.enumdef : NULL; | |
| } | |
| const upb_MiniTableField* upb_FieldDef_MiniTable(const upb_FieldDef* f) { | |
| if (upb_FieldDef_IsExtension(f)) { | |
| const upb_FileDef* file = upb_FieldDef_File(f); | |
| return (upb_MiniTableField*)_upb_FileDef_ExtensionMiniTable( | |
| file, f->layout_index); | |
| } else { | |
| const upb_MiniTable* layout = upb_MessageDef_MiniTable(f->msgdef); | |
| return &layout->UPB_PRIVATE(fields)[f->layout_index]; | |
| } | |
| } | |
| const upb_MiniTableExtension* upb_FieldDef_MiniTableExtension( | |
| const upb_FieldDef* f) { | |
| UPB_ASSERT(upb_FieldDef_IsExtension(f)); | |
| const upb_FileDef* file = upb_FieldDef_File(f); | |
| return _upb_FileDef_ExtensionMiniTable(file, f->layout_index); | |
| } | |
| bool _upb_FieldDef_IsClosedEnum(const upb_FieldDef* f) { | |
| if (f->type_ != kUpb_FieldType_Enum) return false; | |
| return upb_EnumDef_IsClosed(f->sub.enumdef); | |
| } | |
| bool _upb_FieldDef_IsProto3Optional(const upb_FieldDef* f) { | |
| return f->is_proto3_optional; | |
| } | |
| int _upb_FieldDef_LayoutIndex(const upb_FieldDef* f) { return f->layout_index; } | |
| bool _upb_FieldDef_ValidateUtf8(const upb_FieldDef* f) { | |
| if (upb_FieldDef_Type(f) != kUpb_FieldType_String) return false; | |
| return google_protobuf_FeatureSet_utf8_validation(f->resolved_features) == | |
| google_protobuf_FeatureSet_VERIFY; | |
| } | |
| bool _upb_FieldDef_IsGroupLike(const upb_FieldDef* f) { | |
| // Groups are always tag-delimited. | |
| if (f->type_ != kUpb_FieldType_Group) { | |
| return false; | |
| } | |
| const upb_MessageDef* msg = upb_FieldDef_MessageSubDef(f); | |
| // Group fields always are always the lowercase type name. | |
| const char* mname = upb_MessageDef_Name(msg); | |
| const char* fname = upb_FieldDef_Name(f); | |
| size_t name_size = strlen(fname); | |
| if (name_size != strlen(mname)) return false; | |
| for (size_t i = 0; i < name_size; ++i) { | |
| if ((mname[i] | 0x20) != fname[i]) { | |
| // Case-insensitive ascii comparison. | |
| return false; | |
| } | |
| } | |
| if (upb_MessageDef_File(msg) != upb_FieldDef_File(f)) { | |
| return false; | |
| } | |
| // Group messages are always defined in the same scope as the field. File | |
| // level extensions will compare NULL == NULL here, which is why the file | |
| // comparison above is necessary to ensure both come from the same file. | |
| return upb_FieldDef_IsExtension(f) ? upb_FieldDef_ExtensionScope(f) == | |
| upb_MessageDef_ContainingType(msg) | |
| : upb_FieldDef_ContainingType(f) == | |
| upb_MessageDef_ContainingType(msg); | |
| } | |
| uint64_t _upb_FieldDef_Modifiers(const upb_FieldDef* f) { | |
| uint64_t out = upb_FieldDef_IsPacked(f) ? kUpb_FieldModifier_IsPacked : 0; | |
| if (upb_FieldDef_IsRepeated(f)) { | |
| out |= kUpb_FieldModifier_IsRepeated; | |
| } else if (upb_FieldDef_IsRequired(f)) { | |
| out |= kUpb_FieldModifier_IsRequired; | |
| } else if (!upb_FieldDef_HasPresence(f)) { | |
| out |= kUpb_FieldModifier_IsProto3Singular; | |
| } | |
| if (_upb_FieldDef_IsClosedEnum(f)) { | |
| out |= kUpb_FieldModifier_IsClosedEnum; | |
| } | |
| if (_upb_FieldDef_ValidateUtf8(f)) { | |
| out |= kUpb_FieldModifier_ValidateUtf8; | |
| } | |
| return out; | |
| } | |
| bool upb_FieldDef_HasDefault(const upb_FieldDef* f) { return f->has_default; } | |
| bool upb_FieldDef_HasPresence(const upb_FieldDef* f) { return f->has_presence; } | |
| bool upb_FieldDef_HasSubDef(const upb_FieldDef* f) { | |
| return upb_FieldDef_IsSubMessage(f) || upb_FieldDef_IsEnum(f); | |
| } | |
| bool upb_FieldDef_IsEnum(const upb_FieldDef* f) { | |
| return upb_FieldDef_CType(f) == kUpb_CType_Enum; | |
| } | |
| bool upb_FieldDef_IsMap(const upb_FieldDef* f) { | |
| return upb_FieldDef_IsRepeated(f) && upb_FieldDef_IsSubMessage(f) && | |
| upb_MessageDef_IsMapEntry(upb_FieldDef_MessageSubDef(f)); | |
| } | |
| bool upb_FieldDef_IsOptional(const upb_FieldDef* f) { | |
| return upb_FieldDef_Label(f) == kUpb_Label_Optional; | |
| } | |
| bool upb_FieldDef_IsPrimitive(const upb_FieldDef* f) { | |
| return !upb_FieldDef_IsString(f) && !upb_FieldDef_IsSubMessage(f); | |
| } | |
| bool upb_FieldDef_IsRepeated(const upb_FieldDef* f) { | |
| return upb_FieldDef_Label(f) == kUpb_Label_Repeated; | |
| } | |
| bool upb_FieldDef_IsRequired(const upb_FieldDef* f) { | |
| return google_protobuf_FeatureSet_field_presence(f->resolved_features) == | |
| google_protobuf_FeatureSet_LEGACY_REQUIRED; | |
| } | |
| bool upb_FieldDef_IsString(const upb_FieldDef* f) { | |
| return upb_FieldDef_CType(f) == kUpb_CType_String || | |
| upb_FieldDef_CType(f) == kUpb_CType_Bytes; | |
| } | |
| bool upb_FieldDef_IsSubMessage(const upb_FieldDef* f) { | |
| return upb_FieldDef_CType(f) == kUpb_CType_Message; | |
| } | |
| static bool between(int32_t x, int32_t low, int32_t high) { | |
| return x >= low && x <= high; | |
| } | |
| bool upb_FieldDef_checklabel(int32_t label) { return between(label, 1, 3); } | |
| bool upb_FieldDef_checktype(int32_t type) { return between(type, 1, 11); } | |
| bool upb_FieldDef_checkintfmt(int32_t fmt) { return between(fmt, 1, 3); } | |
| bool upb_FieldDef_checkdescriptortype(int32_t type) { | |
| return between(type, 1, 18); | |
| } | |
| static bool streql2(const char* a, size_t n, const char* b) { | |
| return n == strlen(b) && memcmp(a, b, n) == 0; | |
| } | |
| // Implement the transformation as described in the spec: | |
| // 1. upper case all letters after an underscore. | |
| // 2. remove all underscores. | |
| static char* make_json_name(const char* name, size_t size, upb_Arena* a) { | |
| char* out = upb_Arena_Malloc(a, size + 1); // +1 is to add a trailing '\0' | |
| if (out == NULL) return NULL; | |
| bool ucase_next = false; | |
| char* des = out; | |
| for (size_t i = 0; i < size; i++) { | |
| if (name[i] == '_') { | |
| ucase_next = true; | |
| } else { | |
| *des++ = ucase_next ? toupper(name[i]) : name[i]; | |
| ucase_next = false; | |
| } | |
| } | |
| *des++ = '\0'; | |
| return out; | |
| } | |
| static str_t* newstr(upb_DefBuilder* ctx, const char* data, size_t len) { | |
| str_t* ret = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); | |
| if (!ret) _upb_DefBuilder_OomErr(ctx); | |
| ret->len = len; | |
| if (len) memcpy(ret->str, data, len); | |
| ret->str[len] = '\0'; | |
| return ret; | |
| } | |
| static str_t* unescape(upb_DefBuilder* ctx, const upb_FieldDef* f, | |
| const char* data, size_t len) { | |
| // Size here is an upper bound; escape sequences could ultimately shrink it. | |
| str_t* ret = _upb_DefBuilder_Alloc(ctx, sizeof(*ret) + len); | |
| char* dst = &ret->str[0]; | |
| const char* src = data; | |
| const char* end = data + len; | |
| while (src < end) { | |
| if (*src == '\\') { | |
| src++; | |
| *dst++ = _upb_DefBuilder_ParseEscape(ctx, f, &src, end); | |
| } else { | |
| *dst++ = *src++; | |
| } | |
| } | |
| ret->len = dst - &ret->str[0]; | |
| return ret; | |
| } | |
| static void parse_default(upb_DefBuilder* ctx, const char* str, size_t len, | |
| upb_FieldDef* f) { | |
| char* end; | |
| char nullz[64]; | |
| errno = 0; | |
| switch (upb_FieldDef_CType(f)) { | |
| case kUpb_CType_Int32: | |
| case kUpb_CType_Int64: | |
| case kUpb_CType_UInt32: | |
| case kUpb_CType_UInt64: | |
| case kUpb_CType_Double: | |
| case kUpb_CType_Float: | |
| // Standard C number parsing functions expect null-terminated strings. | |
| if (len >= sizeof(nullz) - 1) { | |
| _upb_DefBuilder_Errf(ctx, "Default too long: %.*s", (int)len, str); | |
| } | |
| memcpy(nullz, str, len); | |
| nullz[len] = '\0'; | |
| str = nullz; | |
| break; | |
| default: | |
| break; | |
| } | |
| switch (upb_FieldDef_CType(f)) { | |
| case kUpb_CType_Int32: { | |
| long val = strtol(str, &end, 0); | |
| if (val > INT32_MAX || val < INT32_MIN || errno == ERANGE || *end) { | |
| goto invalid; | |
| } | |
| f->defaultval.sint = val; | |
| break; | |
| } | |
| case kUpb_CType_Enum: { | |
| const upb_EnumDef* e = f->sub.enumdef; | |
| const upb_EnumValueDef* ev = | |
| upb_EnumDef_FindValueByNameWithSize(e, str, len); | |
| if (!ev) { | |
| goto invalid; | |
| } | |
| f->defaultval.sint = upb_EnumValueDef_Number(ev); | |
| break; | |
| } | |
| case kUpb_CType_Int64: { | |
| long long val = strtoll(str, &end, 0); | |
| if (val > INT64_MAX || val < INT64_MIN || errno == ERANGE || *end) { | |
| goto invalid; | |
| } | |
| f->defaultval.sint = val; | |
| break; | |
| } | |
| case kUpb_CType_UInt32: { | |
| unsigned long val = strtoul(str, &end, 0); | |
| if (val > UINT32_MAX || errno == ERANGE || *end) { | |
| goto invalid; | |
| } | |
| f->defaultval.uint = val; | |
| break; | |
| } | |
| case kUpb_CType_UInt64: { | |
| unsigned long long val = strtoull(str, &end, 0); | |
| if (val > UINT64_MAX || errno == ERANGE || *end) { | |
| goto invalid; | |
| } | |
| f->defaultval.uint = val; | |
| break; | |
| } | |
| case kUpb_CType_Double: { | |
| double val = strtod(str, &end); | |
| if (errno == ERANGE || *end) { | |
| goto invalid; | |
| } | |
| f->defaultval.dbl = val; | |
| break; | |
| } | |
| case kUpb_CType_Float: { | |
| float val = strtof(str, &end); | |
| if (errno == ERANGE || *end) { | |
| goto invalid; | |
| } | |
| f->defaultval.flt = val; | |
| break; | |
| } | |
| case kUpb_CType_Bool: { | |
| if (streql2(str, len, "false")) { | |
| f->defaultval.boolean = false; | |
| } else if (streql2(str, len, "true")) { | |
| f->defaultval.boolean = true; | |
| } else { | |
| goto invalid; | |
| } | |
| break; | |
| } | |
| case kUpb_CType_String: | |
| f->defaultval.str = newstr(ctx, str, len); | |
| break; | |
| case kUpb_CType_Bytes: | |
| f->defaultval.str = unescape(ctx, f, str, len); | |
| break; | |
| case kUpb_CType_Message: | |
| /* Should not have a default value. */ | |
| _upb_DefBuilder_Errf(ctx, "Message should not have a default (%s)", | |
| upb_FieldDef_FullName(f)); | |
| } | |
| return; | |
| invalid: | |
| _upb_DefBuilder_Errf(ctx, "Invalid default '%.*s' for field %s of type %d", | |
| (int)len, str, upb_FieldDef_FullName(f), | |
| (int)upb_FieldDef_Type(f)); | |
| } | |
| static void set_default_default(upb_DefBuilder* ctx, upb_FieldDef* f, | |
| bool must_be_empty) { | |
| switch (upb_FieldDef_CType(f)) { | |
| case kUpb_CType_Int32: | |
| case kUpb_CType_Int64: | |
| f->defaultval.sint = 0; | |
| break; | |
| case kUpb_CType_UInt64: | |
| case kUpb_CType_UInt32: | |
| f->defaultval.uint = 0; | |
| break; | |
| case kUpb_CType_Double: | |
| case kUpb_CType_Float: | |
| f->defaultval.dbl = 0; | |
| break; | |
| case kUpb_CType_String: | |
| case kUpb_CType_Bytes: | |
| f->defaultval.str = newstr(ctx, NULL, 0); | |
| break; | |
| case kUpb_CType_Bool: | |
| f->defaultval.boolean = false; | |
| break; | |
| case kUpb_CType_Enum: { | |
| f->defaultval.sint = upb_EnumDef_Default(f->sub.enumdef); | |
| if (must_be_empty && f->defaultval.sint != 0) { | |
| _upb_DefBuilder_Errf(ctx, | |
| "Implicit presence field (%s) cannot use an enum " | |
| "type with a non-zero default (%s)", | |
| f->full_name, | |
| upb_EnumDef_FullName(f->sub.enumdef)); | |
| } | |
| break; | |
| } | |
| case kUpb_CType_Message: | |
| break; | |
| } | |
| } | |
| static bool _upb_FieldDef_InferLegacyFeatures( | |
| upb_DefBuilder* ctx, upb_FieldDef* f, | |
| const google_protobuf_FieldDescriptorProto* proto, | |
| const google_protobuf_FieldOptions* options, google_protobuf_Edition edition, | |
| google_protobuf_FeatureSet* features) { | |
| bool ret = false; | |
| if (google_protobuf_FieldDescriptorProto_label(proto) == kUpb_Label_Required) { | |
| if (edition == google_protobuf_EDITION_PROTO3) { | |
| _upb_DefBuilder_Errf(ctx, "proto3 fields cannot be required (%s)", | |
| f->full_name); | |
| } | |
| int val = google_protobuf_FeatureSet_LEGACY_REQUIRED; | |
| google_protobuf_FeatureSet_set_field_presence(features, val); | |
| ret = true; | |
| } | |
| if (google_protobuf_FieldDescriptorProto_type(proto) == kUpb_FieldType_Group) { | |
| int val = google_protobuf_FeatureSet_DELIMITED; | |
| google_protobuf_FeatureSet_set_message_encoding(features, val); | |
| ret = true; | |
| } | |
| if (google_protobuf_FieldOptions_has_packed(options)) { | |
| int val = google_protobuf_FieldOptions_packed(options) ? google_protobuf_FeatureSet_PACKED | |
| : google_protobuf_FeatureSet_EXPANDED; | |
| google_protobuf_FeatureSet_set_repeated_field_encoding(features, val); | |
| ret = true; | |
| } | |
| return ret; | |
| } | |
| static void _upb_FieldDef_Create(upb_DefBuilder* ctx, const char* prefix, | |
| const google_protobuf_FeatureSet* parent_features, | |
| const google_protobuf_FieldDescriptorProto* field_proto, | |
| upb_MessageDef* m, upb_FieldDef* f) { | |
| // Must happen before _upb_DefBuilder_Add() | |
| f->file = _upb_DefBuilder_File(ctx); | |
| const upb_StringView name = google_protobuf_FieldDescriptorProto_name(field_proto); | |
| f->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); | |
| f->number_ = google_protobuf_FieldDescriptorProto_number(field_proto); | |
| f->is_proto3_optional = | |
| google_protobuf_FieldDescriptorProto_proto3_optional(field_proto); | |
| f->msgdef = m; | |
| f->scope.oneof = NULL; | |
| UPB_DEF_SET_OPTIONS(f->opts, FieldDescriptorProto, FieldOptions, field_proto); | |
| google_protobuf_Edition edition = upb_FileDef_Edition(f->file); | |
| const google_protobuf_FeatureSet* unresolved_features = | |
| google_protobuf_FieldOptions_features(f->opts); | |
| bool implicit = false; | |
| if (_upb_DefBuilder_IsLegacyEdition(edition)) { | |
| upb_Message_Clear(UPB_UPCAST(ctx->legacy_features), | |
| UPB_DESC_MINITABLE(FeatureSet)); | |
| if (_upb_FieldDef_InferLegacyFeatures(ctx, f, field_proto, f->opts, edition, | |
| ctx->legacy_features)) { | |
| implicit = true; | |
| unresolved_features = ctx->legacy_features; | |
| } | |
| } | |
| if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { | |
| int oneof_index = google_protobuf_FieldDescriptorProto_oneof_index(field_proto); | |
| if (!m) { | |
| _upb_DefBuilder_Errf(ctx, "oneof field (%s) has no containing msg", | |
| f->full_name); | |
| } | |
| if (oneof_index < 0 || oneof_index >= upb_MessageDef_OneofCount(m)) { | |
| _upb_DefBuilder_Errf(ctx, "oneof_index out of range (%s)", f->full_name); | |
| } | |
| upb_OneofDef* oneof = (upb_OneofDef*)upb_MessageDef_Oneof(m, oneof_index); | |
| f->scope.oneof = oneof; | |
| parent_features = upb_OneofDef_ResolvedFeatures(oneof); | |
| _upb_OneofDef_Insert(ctx, oneof, f, name.data, name.size); | |
| } | |
| f->resolved_features = _upb_DefBuilder_DoResolveFeatures( | |
| ctx, parent_features, unresolved_features, implicit); | |
| f->label_ = (int)google_protobuf_FieldDescriptorProto_label(field_proto); | |
| if (f->label_ == kUpb_Label_Optional && | |
| // TODO: remove once we can deprecate kUpb_Label_Required. | |
| google_protobuf_FeatureSet_field_presence(f->resolved_features) == | |
| google_protobuf_FeatureSet_LEGACY_REQUIRED) { | |
| f->label_ = kUpb_Label_Required; | |
| } | |
| if (!google_protobuf_FieldDescriptorProto_has_name(field_proto)) { | |
| _upb_DefBuilder_Errf(ctx, "field has no name"); | |
| } | |
| f->has_json_name = google_protobuf_FieldDescriptorProto_has_json_name(field_proto); | |
| if (f->has_json_name) { | |
| const upb_StringView sv = | |
| google_protobuf_FieldDescriptorProto_json_name(field_proto); | |
| f->json_name = upb_strdup2(sv.data, sv.size, ctx->arena); | |
| } else { | |
| f->json_name = make_json_name(name.data, name.size, ctx->arena); | |
| } | |
| if (!f->json_name) _upb_DefBuilder_OomErr(ctx); | |
| const bool has_type = google_protobuf_FieldDescriptorProto_has_type(field_proto); | |
| const bool has_type_name = | |
| google_protobuf_FieldDescriptorProto_has_type_name(field_proto); | |
| f->type_ = (int)google_protobuf_FieldDescriptorProto_type(field_proto); | |
| if (has_type) { | |
| switch (f->type_) { | |
| case kUpb_FieldType_Message: | |
| case kUpb_FieldType_Group: | |
| case kUpb_FieldType_Enum: | |
| if (!has_type_name) { | |
| _upb_DefBuilder_Errf(ctx, "field of type %d requires type name (%s)", | |
| (int)f->type_, f->full_name); | |
| } | |
| break; | |
| default: | |
| if (has_type_name) { | |
| _upb_DefBuilder_Errf( | |
| ctx, "invalid type for field with type_name set (%s, %d)", | |
| f->full_name, (int)f->type_); | |
| } | |
| } | |
| } | |
| if ((!has_type && has_type_name) || f->type_ == kUpb_FieldType_Message) { | |
| f->type_ = | |
| UPB_FIELD_TYPE_UNSPECIFIED; // We'll assign this in resolve_subdef() | |
| } else { | |
| if (f->type_ < kUpb_FieldType_Double || f->type_ > kUpb_FieldType_SInt64) { | |
| _upb_DefBuilder_Errf(ctx, "invalid type for field %s (%d)", f->full_name, | |
| f->type_); | |
| } | |
| } | |
| if (f->label_ < kUpb_Label_Optional || f->label_ > kUpb_Label_Repeated) { | |
| _upb_DefBuilder_Errf(ctx, "invalid label for field %s (%d)", f->full_name, | |
| f->label_); | |
| } | |
| /* We can't resolve the subdef or (in the case of extensions) the containing | |
| * message yet, because it may not have been defined yet. We stash a pointer | |
| * to the field_proto until later when we can properly resolve it. */ | |
| f->sub.unresolved = field_proto; | |
| if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { | |
| if (upb_FieldDef_Label(f) != kUpb_Label_Optional) { | |
| _upb_DefBuilder_Errf(ctx, "fields in oneof must have OPTIONAL label (%s)", | |
| f->full_name); | |
| } | |
| } | |
| f->has_presence = | |
| (!upb_FieldDef_IsRepeated(f)) && | |
| (f->is_extension || _upb_FileDef_ImplicitFieldPresenceDisabled(f->file) || | |
| (f->type_ == kUpb_FieldType_Message || | |
| f->type_ == kUpb_FieldType_Group || upb_FieldDef_ContainingOneof(f) || | |
| google_protobuf_FeatureSet_field_presence(f->resolved_features) != | |
| google_protobuf_FeatureSet_IMPLICIT)); | |
| } | |
| static void _upb_FieldDef_CreateExt( | |
| upb_DefBuilder* ctx, const char* prefix, | |
| const google_protobuf_FeatureSet* parent_features, | |
| const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m, | |
| upb_FieldDef* f) { | |
| f->is_extension = true; | |
| _upb_FieldDef_Create(ctx, prefix, parent_features, field_proto, m, f); | |
| if (google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { | |
| _upb_DefBuilder_Errf(ctx, "oneof_index provided for extension field (%s)", | |
| f->full_name); | |
| } | |
| f->scope.extension_scope = m; | |
| _upb_DefBuilder_Add(ctx, f->full_name, _upb_DefType_Pack(f, UPB_DEFTYPE_EXT)); | |
| f->layout_index = ctx->ext_count++; | |
| if (ctx->layout) { | |
| UPB_ASSERT(upb_MiniTableExtension_Number( | |
| upb_FieldDef_MiniTableExtension(f)) == f->number_); | |
| } | |
| } | |
| static void _upb_FieldDef_CreateNotExt( | |
| upb_DefBuilder* ctx, const char* prefix, | |
| const google_protobuf_FeatureSet* parent_features, | |
| const google_protobuf_FieldDescriptorProto* field_proto, upb_MessageDef* m, | |
| upb_FieldDef* f) { | |
| f->is_extension = false; | |
| _upb_FieldDef_Create(ctx, prefix, parent_features, field_proto, m, f); | |
| if (!google_protobuf_FieldDescriptorProto_has_oneof_index(field_proto)) { | |
| if (f->is_proto3_optional) { | |
| _upb_DefBuilder_Errf( | |
| ctx, | |
| "non-extension field (%s) with proto3_optional was not in a oneof", | |
| f->full_name); | |
| } | |
| } | |
| _upb_MessageDef_InsertField(ctx, m, f); | |
| } | |
| upb_FieldDef* _upb_Extensions_New( | |
| upb_DefBuilder* ctx, int n, | |
| const google_protobuf_FieldDescriptorProto* const* protos, | |
| const google_protobuf_FeatureSet* parent_features, const char* prefix, | |
| upb_MessageDef* m) { | |
| _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); | |
| upb_FieldDef* defs = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_FieldDef, n); | |
| for (int i = 0; i < n; i++) { | |
| upb_FieldDef* f = &defs[i]; | |
| _upb_FieldDef_CreateExt(ctx, prefix, parent_features, protos[i], m, f); | |
| f->index_ = i; | |
| } | |
| return defs; | |
| } | |
| upb_FieldDef* _upb_FieldDefs_New( | |
| upb_DefBuilder* ctx, int n, | |
| const google_protobuf_FieldDescriptorProto* const* protos, | |
| const google_protobuf_FeatureSet* parent_features, const char* prefix, | |
| upb_MessageDef* m, bool* is_sorted) { | |
| _upb_DefType_CheckPadding(sizeof(upb_FieldDef)); | |
| upb_FieldDef* defs = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_FieldDef, n); | |
| uint32_t previous = 0; | |
| for (int i = 0; i < n; i++) { | |
| upb_FieldDef* f = &defs[i]; | |
| _upb_FieldDef_CreateNotExt(ctx, prefix, parent_features, protos[i], m, f); | |
| f->index_ = i; | |
| if (!ctx->layout) { | |
| // Speculate that the def fields are sorted. We will always sort the | |
| // MiniTable fields, so if defs are sorted then indices will match. | |
| // | |
| // If this is incorrect, we will overwrite later. | |
| f->layout_index = i; | |
| } | |
| const uint32_t current = f->number_; | |
| if (previous > current) *is_sorted = false; | |
| previous = current; | |
| } | |
| return defs; | |
| } | |
| static void resolve_subdef(upb_DefBuilder* ctx, const char* prefix, | |
| upb_FieldDef* f) { | |
| const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; | |
| upb_StringView name = google_protobuf_FieldDescriptorProto_type_name(field_proto); | |
| bool has_name = google_protobuf_FieldDescriptorProto_has_type_name(field_proto); | |
| switch ((int)f->type_) { | |
| case UPB_FIELD_TYPE_UNSPECIFIED: { | |
| // Type was not specified and must be inferred. | |
| UPB_ASSERT(has_name); | |
| upb_deftype_t type; | |
| const void* def = | |
| _upb_DefBuilder_ResolveAny(ctx, f->full_name, prefix, name, &type); | |
| switch (type) { | |
| case UPB_DEFTYPE_ENUM: | |
| f->sub.enumdef = def; | |
| f->type_ = kUpb_FieldType_Enum; | |
| break; | |
| case UPB_DEFTYPE_MSG: | |
| f->sub.msgdef = def; | |
| f->type_ = kUpb_FieldType_Message; | |
| // TODO: remove once we can deprecate | |
| // kUpb_FieldType_Group. | |
| if (google_protobuf_FeatureSet_message_encoding(f->resolved_features) == | |
| google_protobuf_FeatureSet_DELIMITED && | |
| !upb_MessageDef_IsMapEntry(def) && | |
| !(f->msgdef && upb_MessageDef_IsMapEntry(f->msgdef))) { | |
| f->type_ = kUpb_FieldType_Group; | |
| } | |
| f->has_presence = !upb_FieldDef_IsRepeated(f); | |
| break; | |
| default: | |
| _upb_DefBuilder_Errf(ctx, "Couldn't resolve type name for field %s", | |
| f->full_name); | |
| } | |
| break; | |
| } | |
| case kUpb_FieldType_Message: | |
| case kUpb_FieldType_Group: | |
| UPB_ASSERT(has_name); | |
| f->sub.msgdef = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, | |
| UPB_DEFTYPE_MSG); | |
| break; | |
| case kUpb_FieldType_Enum: | |
| UPB_ASSERT(has_name); | |
| f->sub.enumdef = _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, | |
| UPB_DEFTYPE_ENUM); | |
| break; | |
| default: | |
| // No resolution necessary. | |
| break; | |
| } | |
| } | |
| static int _upb_FieldDef_Compare(const void* p1, const void* p2) { | |
| const uint32_t v1 = (*(upb_FieldDef**)p1)->number_; | |
| const uint32_t v2 = (*(upb_FieldDef**)p2)->number_; | |
| return (v1 < v2) ? -1 : (v1 > v2); | |
| } | |
| // _upb_FieldDefs_Sorted() is mostly a pure function of its inputs, but has one | |
| // critical side effect that we depend on: it sets layout_index appropriately | |
| // for non-sorted lists of fields. | |
| const upb_FieldDef** _upb_FieldDefs_Sorted(const upb_FieldDef* f, int n, | |
| upb_Arena* a) { | |
| // TODO: Replace this arena alloc with a persistent scratch buffer. | |
| upb_FieldDef** out = (upb_FieldDef**)upb_Arena_Malloc(a, n * sizeof(void*)); | |
| if (!out) return NULL; | |
| for (int i = 0; i < n; i++) { | |
| out[i] = (upb_FieldDef*)&f[i]; | |
| } | |
| qsort(out, n, sizeof(void*), _upb_FieldDef_Compare); | |
| for (int i = 0; i < n; i++) { | |
| out[i]->layout_index = i; | |
| } | |
| return (const upb_FieldDef**)out; | |
| } | |
| bool upb_FieldDef_MiniDescriptorEncode(const upb_FieldDef* f, upb_Arena* a, | |
| upb_StringView* out) { | |
| UPB_ASSERT(f->is_extension); | |
| upb_DescState s; | |
| _upb_DescState_Init(&s); | |
| const int number = upb_FieldDef_Number(f); | |
| const uint64_t modifiers = _upb_FieldDef_Modifiers(f); | |
| if (!_upb_DescState_Grow(&s, a)) return false; | |
| s.ptr = upb_MtDataEncoder_EncodeExtension(&s.e, s.ptr, f->type_, number, | |
| modifiers); | |
| *s.ptr = '\0'; | |
| out->data = s.buf; | |
| out->size = s.ptr - s.buf; | |
| return true; | |
| } | |
| static void resolve_extension(upb_DefBuilder* ctx, const char* prefix, | |
| upb_FieldDef* f, | |
| const google_protobuf_FieldDescriptorProto* field_proto) { | |
| if (!google_protobuf_FieldDescriptorProto_has_extendee(field_proto)) { | |
| _upb_DefBuilder_Errf(ctx, "extension for field '%s' had no extendee", | |
| f->full_name); | |
| } | |
| upb_StringView name = google_protobuf_FieldDescriptorProto_extendee(field_proto); | |
| const upb_MessageDef* m = | |
| _upb_DefBuilder_Resolve(ctx, f->full_name, prefix, name, UPB_DEFTYPE_MSG); | |
| f->msgdef = m; | |
| if (!_upb_MessageDef_IsValidExtensionNumber(m, f->number_)) { | |
| _upb_DefBuilder_Errf( | |
| ctx, | |
| "field number %u in extension %s has no extension range in message %s", | |
| (unsigned)f->number_, f->full_name, upb_MessageDef_FullName(m)); | |
| } | |
| } | |
| void _upb_FieldDef_BuildMiniTableExtension(upb_DefBuilder* ctx, | |
| const upb_FieldDef* f) { | |
| const upb_MiniTableExtension* ext; | |
| if (ctx->layout) { | |
| ext = upb_FieldDef_MiniTableExtension(f); | |
| UPB_ASSERT(upb_FieldDef_Number(f) == upb_MiniTableExtension_Number(ext)); | |
| } else { | |
| upb_StringView desc; | |
| if (!upb_FieldDef_MiniDescriptorEncode(f, ctx->tmp_arena, &desc)) { | |
| _upb_DefBuilder_OomErr(ctx); | |
| } | |
| upb_MiniTableSub sub = {NULL}; | |
| if (upb_FieldDef_IsSubMessage(f)) { | |
| const upb_MiniTable* submsg = upb_MessageDef_MiniTable(f->sub.msgdef); | |
| sub = upb_MiniTableSub_FromMessage(submsg); | |
| } else if (_upb_FieldDef_IsClosedEnum(f)) { | |
| const upb_MiniTableEnum* subenum = _upb_EnumDef_MiniTable(f->sub.enumdef); | |
| sub = upb_MiniTableSub_FromEnum(subenum); | |
| } | |
| // _upb_MiniTableExtension_Build() sizes the allocation according to | |
| // whether the decoded extension needs trailing sub storage. | |
| ext = _upb_MiniTableExtension_Build( | |
| desc.data, desc.size, upb_MessageDef_MiniTable(f->msgdef), sub, | |
| ctx->platform, ctx->arena, ctx->status); | |
| if (!ext) _upb_DefBuilder_Errf(ctx, "Could not build extension mini table"); | |
| _upb_FileDef_SetExtensionMiniTable(ctx->file, f->layout_index, ext); | |
| } | |
| bool ok = _upb_DefPool_InsertExt(ctx->symtab, ext, f); | |
| if (!ok) _upb_DefBuilder_OomErr(ctx); | |
| } | |
| static void resolve_default(upb_DefBuilder* ctx, upb_FieldDef* f, | |
| const google_protobuf_FieldDescriptorProto* field_proto) { | |
| // Implicit presence fields should always have an effective default of 0. | |
| // This should naturally fall out of the validations that protoc performs: | |
| // - Implicit presence fields cannot specify a default value. | |
| // - Implicit presence fields for for enums can only use open enums, which | |
| // are required to have zero as their default. | |
| // - Even if we are treating all enums as open, the proto compiler will | |
| // still reject using a nominally closed enum with an implicit presence | |
| // field. | |
| bool must_be_empty = !f->has_presence && !upb_FieldDef_IsRepeated(f); | |
| // Have to delay resolving of the default value until now because of the enum | |
| // case, since enum defaults are specified with a label. | |
| if (google_protobuf_FieldDescriptorProto_has_default_value(field_proto)) { | |
| upb_StringView defaultval = | |
| google_protobuf_FieldDescriptorProto_default_value(field_proto); | |
| if (must_be_empty) { | |
| _upb_DefBuilder_Errf(ctx, | |
| "fields with implicit presence cannot have " | |
| "explicit defaults (%s)", | |
| f->full_name); | |
| } | |
| if (upb_FileDef_Edition(f->file) == google_protobuf_EDITION_PROTO3) { | |
| _upb_DefBuilder_Errf(ctx, | |
| "proto3 fields cannot have explicit defaults (%s)", | |
| f->full_name); | |
| } | |
| if (upb_FieldDef_IsSubMessage(f)) { | |
| _upb_DefBuilder_Errf(ctx, | |
| "message fields cannot have explicit defaults (%s)", | |
| f->full_name); | |
| } | |
| parse_default(ctx, defaultval.data, defaultval.size, f); | |
| f->has_default = true; | |
| } else { | |
| set_default_default(ctx, f, must_be_empty); | |
| f->has_default = false; | |
| } | |
| } | |
| void _upb_FieldDef_Resolve(upb_DefBuilder* ctx, const char* prefix, | |
| upb_FieldDef* f) { | |
| // We have to stash this away since resolve_subdef() may overwrite it. | |
| const google_protobuf_FieldDescriptorProto* field_proto = f->sub.unresolved; | |
| resolve_subdef(ctx, prefix, f); | |
| resolve_default(ctx, f, field_proto); | |
| if (f->is_extension) { | |
| resolve_extension(ctx, prefix, f, field_proto); | |
| } | |
| } | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| struct upb_FileDef { | |
| const google_protobuf_FileOptions* opts; | |
| const google_protobuf_FeatureSet* resolved_features; | |
| const char* name; | |
| const char* package; | |
| google_protobuf_Edition edition; | |
| const upb_FileDef** deps; | |
| const int32_t* public_deps; | |
| const int32_t* weak_deps; | |
| const char** option_deps; | |
| const upb_MessageDef* top_lvl_msgs; | |
| const upb_EnumDef* top_lvl_enums; | |
| const upb_FieldDef* top_lvl_exts; | |
| const upb_ServiceDef* services; | |
| const upb_MiniTableExtension** ext_layouts; | |
| const upb_DefPool* symtab; | |
| int dep_count; | |
| int public_dep_count; | |
| int weak_dep_count; | |
| int option_dep_count; | |
| int top_lvl_msg_count; | |
| int top_lvl_enum_count; | |
| int top_lvl_ext_count; | |
| int service_count; | |
| int ext_count; // All exts in the file. | |
| }; | |
| UPB_API const char* upb_FileDef_EditionName(int edition) { | |
| // TODO Synchronize this with descriptor.proto better. | |
| switch (edition) { | |
| case google_protobuf_EDITION_PROTO2: | |
| return "PROTO2"; | |
| case google_protobuf_EDITION_PROTO3: | |
| return "PROTO3"; | |
| case google_protobuf_EDITION_2023: | |
| return "2023"; | |
| default: | |
| return "UNKNOWN"; | |
| } | |
| } | |
| const google_protobuf_FileOptions* upb_FileDef_Options(const upb_FileDef* f) { | |
| return f->opts; | |
| } | |
| const google_protobuf_FeatureSet* upb_FileDef_ResolvedFeatures(const upb_FileDef* f) { | |
| return f->resolved_features; | |
| } | |
| bool upb_FileDef_HasOptions(const upb_FileDef* f) { | |
| return f->opts != (void*)kUpbDefOptDefault; | |
| } | |
| const char* upb_FileDef_Name(const upb_FileDef* f) { return f->name; } | |
| const char* upb_FileDef_Package(const upb_FileDef* f) { | |
| return f->package ? f->package : ""; | |
| } | |
| google_protobuf_Edition upb_FileDef_Edition(const upb_FileDef* f) { return f->edition; } | |
| const char* _upb_FileDef_RawPackage(const upb_FileDef* f) { return f->package; } | |
| int upb_FileDef_TopLevelMessageCount(const upb_FileDef* f) { | |
| return f->top_lvl_msg_count; | |
| } | |
| int upb_FileDef_DependencyCount(const upb_FileDef* f) { return f->dep_count; } | |
| int upb_FileDef_PublicDependencyCount(const upb_FileDef* f) { | |
| return f->public_dep_count; | |
| } | |
| int upb_FileDef_WeakDependencyCount(const upb_FileDef* f) { | |
| return f->weak_dep_count; | |
| } | |
| const char* upb_FileDef_OptionDependency(const upb_FileDef* f, int i) { | |
| UPB_ASSERT(0 <= i && i < f->option_dep_count); | |
| return f->option_deps[i]; | |
| } | |
| int upb_FileDef_OptionDependencyCount(const upb_FileDef* f) { | |
| return f->option_dep_count; | |
| } | |
| const int32_t* _upb_FileDef_PublicDependencyIndexes(const upb_FileDef* f) { | |
| return f->public_deps; | |
| } | |
| const int32_t* _upb_FileDef_WeakDependencyIndexes(const upb_FileDef* f) { | |
| return f->weak_deps; | |
| } | |
| bool _upb_FileDef_ClosedEnumCheckingDisabled(const upb_FileDef* f) { | |
| return upb_DefPool_ClosedEnumCheckingDisabled(f->symtab); | |
| } | |
| bool _upb_FileDef_ImplicitFieldPresenceDisabled(const upb_FileDef* f) { | |
| return upb_DefPool_ImplicitFieldPresenceDisabled(f->symtab); | |
| } | |
| int upb_FileDef_TopLevelEnumCount(const upb_FileDef* f) { | |
| return f->top_lvl_enum_count; | |
| } | |
| int upb_FileDef_TopLevelExtensionCount(const upb_FileDef* f) { | |
| return f->top_lvl_ext_count; | |
| } | |
| int upb_FileDef_ServiceCount(const upb_FileDef* f) { return f->service_count; } | |
| const upb_FileDef* upb_FileDef_Dependency(const upb_FileDef* f, int i) { | |
| UPB_ASSERT(0 <= i && i < f->dep_count); | |
| return f->deps[i]; | |
| } | |
| const upb_FileDef* upb_FileDef_PublicDependency(const upb_FileDef* f, int i) { | |
| UPB_ASSERT(0 <= i && i < f->public_dep_count); | |
| return f->deps[f->public_deps[i]]; | |
| } | |
| const upb_FileDef* upb_FileDef_WeakDependency(const upb_FileDef* f, int i) { | |
| UPB_ASSERT(0 <= i && i < f->weak_dep_count); | |
| return f->deps[f->weak_deps[i]]; | |
| } | |
| const upb_MessageDef* upb_FileDef_TopLevelMessage(const upb_FileDef* f, int i) { | |
| UPB_ASSERT(0 <= i && i < f->top_lvl_msg_count); | |
| return _upb_MessageDef_At(f->top_lvl_msgs, i); | |
| } | |
| const upb_EnumDef* upb_FileDef_TopLevelEnum(const upb_FileDef* f, int i) { | |
| UPB_ASSERT(0 <= i && i < f->top_lvl_enum_count); | |
| return _upb_EnumDef_At(f->top_lvl_enums, i); | |
| } | |
| const upb_FieldDef* upb_FileDef_TopLevelExtension(const upb_FileDef* f, int i) { | |
| UPB_ASSERT(0 <= i && i < f->top_lvl_ext_count); | |
| return _upb_FieldDef_At(f->top_lvl_exts, i); | |
| } | |
| const upb_ServiceDef* upb_FileDef_Service(const upb_FileDef* f, int i) { | |
| UPB_ASSERT(0 <= i && i < f->service_count); | |
| return _upb_ServiceDef_At(f->services, i); | |
| } | |
| const upb_DefPool* upb_FileDef_Pool(const upb_FileDef* f) { return f->symtab; } | |
| const upb_MiniTableExtension* _upb_FileDef_ExtensionMiniTable( | |
| const upb_FileDef* f, int i) { | |
| return f->ext_layouts[i]; | |
| } | |
| void _upb_FileDef_SetExtensionMiniTable(upb_FileDef* f, int i, | |
| const upb_MiniTableExtension* ext) { | |
| f->ext_layouts[i] = ext; | |
| } | |
| // Note: Import cycles are not allowed so this will terminate. | |
| bool upb_FileDef_Resolves(const upb_FileDef* f, const char* path) { | |
| if (!strcmp(f->name, path)) return true; | |
| for (int i = 0; i < upb_FileDef_PublicDependencyCount(f); i++) { | |
| const upb_FileDef* dep = upb_FileDef_PublicDependency(f, i); | |
| if (upb_FileDef_Resolves(dep, path)) return true; | |
| } | |
| return false; | |
| } | |
| static char* _strviewdup(upb_DefBuilder* ctx, upb_StringView view) { | |
| char* ret = upb_strdup2(view.data, view.size, _upb_DefBuilder_Arena(ctx)); | |
| if (!ret) _upb_DefBuilder_OomErr(ctx); | |
| return ret; | |
| } | |
| static bool streql_view(upb_StringView view, const char* b) { | |
| return view.size == strlen(b) && memcmp(view.data, b, view.size) == 0; | |
| } | |
| static int count_exts_in_msg(const google_protobuf_DescriptorProto* msg_proto) { | |
| size_t n; | |
| google_protobuf_DescriptorProto_extension(msg_proto, &n); | |
| int ext_count = n; | |
| const google_protobuf_DescriptorProto* const* nested_msgs = | |
| google_protobuf_DescriptorProto_nested_type(msg_proto, &n); | |
| for (size_t i = 0; i < n; i++) { | |
| ext_count += count_exts_in_msg(nested_msgs[i]); | |
| } | |
| return ext_count; | |
| } | |
| const google_protobuf_FeatureSet* _upb_FileDef_FindEdition(upb_DefBuilder* ctx, | |
| int edition) { | |
| const google_protobuf_FeatureSetDefaults* defaults = | |
| upb_DefPool_FeatureSetDefaults(ctx->symtab); | |
| int min = google_protobuf_FeatureSetDefaults_minimum_edition(defaults); | |
| int max = google_protobuf_FeatureSetDefaults_maximum_edition(defaults); | |
| if (edition < min) { | |
| _upb_DefBuilder_Errf(ctx, | |
| "Edition %s is earlier than the minimum edition %s " | |
| "given in the defaults", | |
| upb_FileDef_EditionName(edition), | |
| upb_FileDef_EditionName(min)); | |
| return NULL; | |
| } | |
| if (edition > max && edition != google_protobuf_EDITION_UNSTABLE) { | |
| _upb_DefBuilder_Errf(ctx, | |
| "Edition %s is later than the maximum edition %s " | |
| "given in the defaults", | |
| upb_FileDef_EditionName(edition), | |
| upb_FileDef_EditionName(max)); | |
| return NULL; | |
| } | |
| size_t n; | |
| const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* const* d = | |
| google_protobuf_FeatureSetDefaults_defaults(defaults, &n); | |
| const google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault* result = NULL; | |
| for (size_t i = 0; i < n; i++) { | |
| if (google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_edition(d[i]) > | |
| edition) { | |
| break; | |
| } | |
| result = d[i]; | |
| } | |
| if (result == NULL) { | |
| _upb_DefBuilder_Errf(ctx, "No valid default found for edition %s", | |
| upb_FileDef_EditionName(edition)); | |
| return NULL; | |
| } | |
| // Merge the fixed and overridable features to get the edition's default | |
| // feature set. | |
| const google_protobuf_FeatureSet* fixed = | |
| google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_fixed_features(result); | |
| const google_protobuf_FeatureSet* overridable = | |
| google_protobuf_FeatureSetDefaults_FeatureSetEditionDefault_overridable_features( | |
| result); | |
| if (!fixed && !overridable) { | |
| _upb_DefBuilder_Errf(ctx, "No valid default found for edition %s", | |
| upb_FileDef_EditionName(edition)); | |
| return NULL; | |
| } else if (!fixed) { | |
| return overridable; | |
| } | |
| return _upb_DefBuilder_DoResolveFeatures(ctx, fixed, overridable, | |
| /*is_implicit=*/true); | |
| } | |
| // Allocate and initialize one file def, and add it to the context object. | |
| void _upb_FileDef_Create(upb_DefBuilder* ctx, | |
| const google_protobuf_FileDescriptorProto* file_proto) { | |
| upb_FileDef* file = _upb_DefBuilder_Alloc(ctx, sizeof(upb_FileDef)); | |
| ctx->file = file; | |
| const google_protobuf_DescriptorProto* const* msgs; | |
| const google_protobuf_EnumDescriptorProto* const* enums; | |
| const google_protobuf_FieldDescriptorProto* const* exts; | |
| const google_protobuf_ServiceDescriptorProto* const* services; | |
| const upb_StringView* strs; | |
| const int32_t* public_deps; | |
| const int32_t* weak_deps; | |
| size_t n; | |
| file->symtab = ctx->symtab; | |
| // Count all extensions in the file, to build a flat array of layouts. | |
| google_protobuf_FileDescriptorProto_extension(file_proto, &n); | |
| int ext_count = n; | |
| msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); | |
| for (size_t i = 0; i < n; i++) { | |
| ext_count += count_exts_in_msg(msgs[i]); | |
| } | |
| file->ext_count = ext_count; | |
| if (ctx->layout) { | |
| // We are using the ext layouts that were passed in. | |
| file->ext_layouts = ctx->layout->UPB_PRIVATE(exts); | |
| const int mt_ext_count = upb_MiniTableFile_ExtensionCount(ctx->layout); | |
| if (mt_ext_count != file->ext_count) { | |
| _upb_DefBuilder_Errf(ctx, | |
| "Extension count did not match layout (%d vs %d)", | |
| mt_ext_count, file->ext_count); | |
| } | |
| } else { | |
| // We are building ext layouts from scratch. | |
| file->ext_layouts = _upb_DefBuilder_Alloc( | |
| ctx, sizeof(*file->ext_layouts) * file->ext_count); | |
| memset((void*)file->ext_layouts, 0, | |
| sizeof(*file->ext_layouts) * file->ext_count); | |
| } | |
| upb_StringView name = google_protobuf_FileDescriptorProto_name(file_proto); | |
| file->name = _strviewdup(ctx, name); | |
| if (strlen(file->name) != name.size) { | |
| _upb_DefBuilder_Errf(ctx, "File name contained embedded NULL"); | |
| } | |
| upb_StringView package = google_protobuf_FileDescriptorProto_package(file_proto); | |
| if (package.size) { | |
| _upb_DefBuilder_CheckIdentFull(ctx, package); | |
| file->package = _strviewdup(ctx, package); | |
| } else { | |
| file->package = NULL; | |
| } | |
| upb_StringView syntax = google_protobuf_FileDescriptorProto_syntax(file_proto); | |
| if (google_protobuf_FileDescriptorProto_has_edition(file_proto)) { | |
| if (!streql_view(syntax, "editions")) { | |
| _upb_DefBuilder_Errf(ctx, | |
| "Setting edition requires that syntax=\"editions\", " | |
| "but syntax is \"" UPB_STRINGVIEW_FORMAT "\"", | |
| UPB_STRINGVIEW_ARGS(syntax)); | |
| } | |
| file->edition = google_protobuf_FileDescriptorProto_edition(file_proto); | |
| } else if (google_protobuf_FileDescriptorProto_has_syntax(file_proto)) { | |
| if (streql_view(syntax, "proto2")) { | |
| file->edition = google_protobuf_EDITION_PROTO2; | |
| } else if (streql_view(syntax, "proto3")) { | |
| file->edition = google_protobuf_EDITION_PROTO3; | |
| } else if (streql_view(syntax, "editions")) { | |
| _upb_DefBuilder_Errf( | |
| ctx, "File has syntax=\"editions\", but no edition is specified"); | |
| } else { | |
| _upb_DefBuilder_Errf(ctx, "Invalid syntax '" UPB_STRINGVIEW_FORMAT "'", | |
| UPB_STRINGVIEW_ARGS(syntax)); | |
| } | |
| } else { | |
| // The legacy default when no edition or syntax is specified is proto2. | |
| file->edition = google_protobuf_EDITION_PROTO2; | |
| } | |
| // Read options. | |
| UPB_DEF_SET_OPTIONS(file->opts, FileDescriptorProto, FileOptions, file_proto); | |
| // Resolve features. | |
| const google_protobuf_FeatureSet* edition_defaults = | |
| _upb_FileDef_FindEdition(ctx, file->edition); | |
| const google_protobuf_FeatureSet* unresolved = google_protobuf_FileOptions_features(file->opts); | |
| file->resolved_features = | |
| _upb_DefBuilder_ResolveFeatures(ctx, edition_defaults, unresolved); | |
| // Verify dependencies. | |
| strs = google_protobuf_FileDescriptorProto_dependency(file_proto, &n); | |
| file->dep_count = n; | |
| file->deps = UPB_DEFBUILDER_ALLOCARRAY(ctx, const upb_FileDef*, n); | |
| for (size_t i = 0; i < n; i++) { | |
| upb_StringView str = strs[i]; | |
| file->deps[i] = | |
| upb_DefPool_FindFileByNameWithSize(ctx->symtab, str.data, str.size); | |
| if (!file->deps[i]) { | |
| _upb_DefBuilder_Errf(ctx, | |
| "Depends on file '" UPB_STRINGVIEW_FORMAT | |
| "', but it has not been loaded", | |
| UPB_STRINGVIEW_ARGS(str)); | |
| } | |
| } | |
| public_deps = google_protobuf_FileDescriptorProto_public_dependency(file_proto, &n); | |
| file->public_dep_count = n; | |
| file->public_deps = UPB_DEFBUILDER_ALLOCARRAY(ctx, int32_t, n); | |
| int32_t* mutable_public_deps = (int32_t*)file->public_deps; | |
| for (size_t i = 0; i < n; i++) { | |
| if (public_deps[i] < 0 || public_deps[i] >= file->dep_count) { | |
| _upb_DefBuilder_Errf(ctx, "public_dep %d is out of range", | |
| (int)public_deps[i]); | |
| } | |
| mutable_public_deps[i] = public_deps[i]; | |
| } | |
| weak_deps = google_protobuf_FileDescriptorProto_weak_dependency(file_proto, &n); | |
| file->weak_dep_count = n; | |
| file->weak_deps = UPB_DEFBUILDER_ALLOCARRAY(ctx, const int32_t, n); | |
| int32_t* mutable_weak_deps = (int32_t*)file->weak_deps; | |
| for (size_t i = 0; i < n; i++) { | |
| if (weak_deps[i] < 0 || weak_deps[i] >= file->dep_count) { | |
| _upb_DefBuilder_Errf(ctx, "weak_dep %d is out of range", | |
| (int)weak_deps[i]); | |
| } | |
| mutable_weak_deps[i] = weak_deps[i]; | |
| } | |
| const upb_StringView* option_deps; | |
| option_deps = google_protobuf_FileDescriptorProto_option_dependency(file_proto, &n); | |
| file->option_dep_count = n; | |
| file->option_deps = UPB_DEFBUILDER_ALLOCARRAY(ctx, const char*, n); | |
| for (size_t i = 0; i < n; i++) { | |
| file->option_deps[i] = _strviewdup(ctx, option_deps[i]); | |
| if (strlen(file->option_deps[i]) != option_deps[i].size) { | |
| _upb_DefBuilder_Errf(ctx, "option_dependency contained embedded NULL"); | |
| } | |
| } | |
| // Create enums. | |
| enums = google_protobuf_FileDescriptorProto_enum_type(file_proto, &n); | |
| file->top_lvl_enum_count = n; | |
| file->top_lvl_enums = | |
| _upb_EnumDefs_New(ctx, n, enums, file->resolved_features, NULL); | |
| // Create extensions. | |
| exts = google_protobuf_FileDescriptorProto_extension(file_proto, &n); | |
| file->top_lvl_ext_count = n; | |
| file->top_lvl_exts = _upb_Extensions_New( | |
| ctx, n, exts, file->resolved_features, file->package, NULL); | |
| // Create messages. | |
| msgs = google_protobuf_FileDescriptorProto_message_type(file_proto, &n); | |
| file->top_lvl_msg_count = n; | |
| file->top_lvl_msgs = | |
| _upb_MessageDefs_New(ctx, n, msgs, file->resolved_features, NULL); | |
| // Create services. | |
| services = google_protobuf_FileDescriptorProto_service(file_proto, &n); | |
| file->service_count = n; | |
| file->services = | |
| _upb_ServiceDefs_New(ctx, n, services, file->resolved_features); | |
| // Now that all names are in the table, build layouts and resolve refs. | |
| for (int i = 0; i < file->top_lvl_msg_count; i++) { | |
| upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); | |
| _upb_MessageDef_Resolve(ctx, m); | |
| } | |
| for (int i = 0; i < file->top_lvl_ext_count; i++) { | |
| upb_FieldDef* f = (upb_FieldDef*)upb_FileDef_TopLevelExtension(file, i); | |
| _upb_FieldDef_Resolve(ctx, file->package, f); | |
| } | |
| for (int i = 0; i < file->top_lvl_msg_count; i++) { | |
| upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); | |
| _upb_MessageDef_CreateMiniTable(ctx, (upb_MessageDef*)m); | |
| } | |
| for (int i = 0; i < file->top_lvl_ext_count; i++) { | |
| upb_FieldDef* f = (upb_FieldDef*)upb_FileDef_TopLevelExtension(file, i); | |
| _upb_FieldDef_BuildMiniTableExtension(ctx, f); | |
| } | |
| for (int i = 0; i < file->top_lvl_msg_count; i++) { | |
| upb_MessageDef* m = (upb_MessageDef*)upb_FileDef_TopLevelMessage(file, i); | |
| _upb_MessageDef_LinkMiniTable(ctx, m); | |
| } | |
| if (file->ext_count) { | |
| upb_ExtensionRegistryStatus status = upb_ExtensionRegistry_AddArray( | |
| _upb_DefPool_ExtReg(ctx->symtab), file->ext_layouts, file->ext_count); | |
| if (status != kUpb_ExtensionRegistryStatus_Ok) { | |
| if (status == kUpb_ExtensionRegistryStatus_OutOfMemory) { | |
| _upb_DefBuilder_OomErr(ctx); | |
| } | |
| UPB_ASSERT(status == kUpb_ExtensionRegistryStatus_DuplicateEntry); | |
| _upb_DefBuilder_Errf(ctx, "duplicate extension entry"); | |
| } | |
| } | |
| } | |
| #include <assert.h> | |
| #include <stdarg.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| /* The upb core does not generally have a concept of default instances. However | |
| * for descriptor options we make an exception since the max size is known and | |
| * modest (<200 bytes). All types can share a default instance since it is | |
| * initialized to zeroes. | |
| * | |
| * We have to allocate an extra pointer for upb's internal metadata. */ | |
| static UPB_ALIGN_AS(8) const | |
| char opt_default_buf[_UPB_MAXOPT_SIZE + sizeof(void*)] = {0}; | |
| const char* kUpbDefOptDefault = &opt_default_buf[sizeof(void*)]; | |
| const char* _upb_DefBuilder_FullToShort(const char* fullname) { | |
| const char* p; | |
| if (fullname == NULL) { | |
| return NULL; | |
| } else if ((p = strrchr(fullname, '.')) == NULL) { | |
| /* No '.' in the name, return the full string. */ | |
| return fullname; | |
| } else { | |
| /* Return one past the last '.'. */ | |
| return p + 1; | |
| } | |
| } | |
| void _upb_DefBuilder_FailJmp(upb_DefBuilder* ctx) { UPB_LONGJMP(ctx->err, 1); } | |
| void _upb_DefBuilder_Errf(upb_DefBuilder* ctx, const char* fmt, ...) { | |
| va_list argp; | |
| va_start(argp, fmt); | |
| upb_Status_VSetErrorFormat(ctx->status, fmt, argp); | |
| va_end(argp); | |
| _upb_DefBuilder_FailJmp(ctx); | |
| } | |
| void _upb_DefBuilder_OomErr(upb_DefBuilder* ctx) { | |
| upb_Status_SetErrorMessage(ctx->status, "out of memory"); | |
| _upb_DefBuilder_FailJmp(ctx); | |
| } | |
| // Verify a relative identifier string. The loop is branchless for speed. | |
| static void _upb_DefBuilder_CheckIdentNotFull(upb_DefBuilder* ctx, | |
| upb_StringView name) { | |
| bool good = name.size > 0; | |
| for (size_t i = 0; i < name.size; i++) { | |
| const char c = name.data[i]; | |
| const char d = c | 0x20; // force lowercase | |
| const bool is_alpha = (('a' <= d) & (d <= 'z')) | (c == '_'); | |
| const bool is_number = ('0' <= c) & (c <= '9'); | |
| good &= is_alpha | is_number; | |
| } | |
| if (!good) _upb_DefBuilder_CheckIdentSlow(ctx, name, false); | |
| } | |
| const char* _upb_DefBuilder_MakeFullName(upb_DefBuilder* ctx, | |
| const char* prefix, | |
| upb_StringView name) { | |
| _upb_DefBuilder_CheckIdentNotFull(ctx, name); | |
| if (prefix) { | |
| // ret = prefix + '.' + name; | |
| size_t n = strlen(prefix); | |
| char* ret = _upb_DefBuilder_Alloc(ctx, n + name.size + 2); | |
| strcpy(ret, prefix); | |
| ret[n] = '.'; | |
| memcpy(&ret[n + 1], name.data, name.size); | |
| ret[n + 1 + name.size] = '\0'; | |
| return ret; | |
| } else { | |
| char* ret = upb_strdup2(name.data, name.size, ctx->arena); | |
| if (!ret) _upb_DefBuilder_OomErr(ctx); | |
| return ret; | |
| } | |
| } | |
| static bool remove_component(char* base, size_t* len) { | |
| if (*len == 0) return false; | |
| for (size_t i = *len - 1; i > 0; i--) { | |
| if (base[i] == '.') { | |
| *len = i; | |
| return true; | |
| } | |
| } | |
| *len = 0; | |
| return true; | |
| } | |
| const void* _upb_DefBuilder_ResolveAny(upb_DefBuilder* ctx, | |
| const char* from_name_dbg, | |
| const char* base, upb_StringView sym, | |
| upb_deftype_t* type) { | |
| if (sym.size == 0) goto notfound; | |
| upb_value v; | |
| if (sym.data[0] == '.') { | |
| // Symbols starting with '.' are absolute, so we do a single lookup. | |
| // Slice to omit the leading '.' | |
| if (!_upb_DefPool_LookupSym(ctx->symtab, sym.data + 1, sym.size - 1, &v)) { | |
| goto notfound; | |
| } | |
| } else { | |
| // Remove components from base until we find an entry or run out. | |
| size_t baselen = base ? strlen(base) : 0; | |
| size_t alloc_size; | |
| if (upb_AddOverflow(sym.size, baselen + 1, &alloc_size)) { | |
| _upb_DefBuilder_OomErr(ctx); | |
| } | |
| char* tmp = upb_gmalloc(alloc_size); | |
| if (!tmp) _upb_DefBuilder_OomErr(ctx); | |
| while (1) { | |
| char* p = tmp; | |
| if (baselen) { | |
| memcpy(p, base, baselen); | |
| p[baselen] = '.'; | |
| p += baselen + 1; | |
| } | |
| memcpy(p, sym.data, sym.size); | |
| p += sym.size; | |
| if (_upb_DefPool_LookupSym(ctx->symtab, tmp, p - tmp, &v)) { | |
| break; | |
| } | |
| if (!remove_component(tmp, &baselen)) { | |
| upb_gfree(tmp); | |
| goto notfound; | |
| } | |
| } | |
| upb_gfree(tmp); | |
| } | |
| *type = _upb_DefType_Type(v); | |
| return _upb_DefType_Unpack(v, *type); | |
| notfound: | |
| _upb_DefBuilder_Errf(ctx, "couldn't resolve name '" UPB_STRINGVIEW_FORMAT "'", | |
| UPB_STRINGVIEW_ARGS(sym)); | |
| } | |
| const void* _upb_DefBuilder_Resolve(upb_DefBuilder* ctx, | |
| const char* from_name_dbg, const char* base, | |
| upb_StringView sym, upb_deftype_t type) { | |
| upb_deftype_t found_type; | |
| const void* ret = | |
| _upb_DefBuilder_ResolveAny(ctx, from_name_dbg, base, sym, &found_type); | |
| if (ret && found_type != type) { | |
| _upb_DefBuilder_Errf(ctx, | |
| "type mismatch when resolving %s: couldn't find " | |
| "name " UPB_STRINGVIEW_FORMAT " with type=%d", | |
| from_name_dbg, UPB_STRINGVIEW_ARGS(sym), (int)type); | |
| } | |
| return ret; | |
| } | |
| // Per ASCII this will lower-case a letter. If the result is a letter, the | |
| // input was definitely a letter. If the output is not a letter, this may | |
| // have transformed the character unpredictably. | |
| static char upb_ascii_lower(char ch) { return ch | 0x20; } | |
| // isalpha() etc. from <ctype.h> are locale-dependent, which we don't want. | |
| static bool upb_isbetween(uint8_t c, uint8_t low, uint8_t high) { | |
| return low <= c && c <= high; | |
| } | |
| static bool upb_isletter(char c) { | |
| char lower = upb_ascii_lower(c); | |
| return upb_isbetween(lower, 'a', 'z') || c == '_'; | |
| } | |
| static bool upb_isalphanum(char c) { | |
| return upb_isletter(c) || upb_isbetween(c, '0', '9'); | |
| } | |
| static bool TryGetChar(const char** src, const char* end, char* ch) { | |
| if (*src == end) return false; | |
| *ch = **src; | |
| *src += 1; | |
| return true; | |
| } | |
| static int TryGetHexDigit(const char** src, const char* end) { | |
| char ch; | |
| if (!TryGetChar(src, end, &ch)) return -1; | |
| if ('0' <= ch && ch <= '9') { | |
| return ch - '0'; | |
| } | |
| ch = upb_ascii_lower(ch); | |
| if ('a' <= ch && ch <= 'f') { | |
| return ch - 'a' + 0xa; | |
| } | |
| *src -= 1; // Char wasn't actually a hex digit. | |
| return -1; | |
| } | |
| static char upb_DefBuilder_ParseHexEscape(upb_DefBuilder* ctx, | |
| const upb_FieldDef* f, | |
| const char** src, const char* end) { | |
| int hex_digit = TryGetHexDigit(src, end); | |
| if (hex_digit < 0) { | |
| _upb_DefBuilder_Errf( | |
| ctx, "\\x must be followed by at least one hex digit (field='%s')", | |
| upb_FieldDef_FullName(f)); | |
| return 0; | |
| } | |
| unsigned int ret = hex_digit; | |
| while ((hex_digit = TryGetHexDigit(src, end)) >= 0) { | |
| ret = (ret << 4) | hex_digit; | |
| } | |
| if (ret > 0xff) { | |
| _upb_DefBuilder_Errf(ctx, "Value of hex escape in field %s exceeds 8 bits", | |
| upb_FieldDef_FullName(f)); | |
| return 0; | |
| } | |
| return ret; | |
| } | |
| static char TryGetOctalDigit(const char** src, const char* end) { | |
| char ch; | |
| if (!TryGetChar(src, end, &ch)) return -1; | |
| if ('0' <= ch && ch <= '7') { | |
| return ch - '0'; | |
| } | |
| *src -= 1; // Char wasn't actually an octal digit. | |
| return -1; | |
| } | |
| static char upb_DefBuilder_ParseOctalEscape(upb_DefBuilder* ctx, | |
| const upb_FieldDef* f, | |
| const char** src, const char* end) { | |
| char ch = 0; | |
| for (int i = 0; i < 3; i++) { | |
| char digit; | |
| if ((digit = TryGetOctalDigit(src, end)) >= 0) { | |
| ch = (ch << 3) | digit; | |
| } | |
| } | |
| return ch; | |
| } | |
| char _upb_DefBuilder_ParseEscape(upb_DefBuilder* ctx, const upb_FieldDef* f, | |
| const char** src, const char* end) { | |
| char ch; | |
| if (!TryGetChar(src, end, &ch)) { | |
| _upb_DefBuilder_Errf(ctx, "unterminated escape sequence in field %s", | |
| upb_FieldDef_FullName(f)); | |
| return 0; | |
| } | |
| switch (ch) { | |
| case 'a': | |
| return '\a'; | |
| case 'b': | |
| return '\b'; | |
| case 'f': | |
| return '\f'; | |
| case 'n': | |
| return '\n'; | |
| case 'r': | |
| return '\r'; | |
| case 't': | |
| return '\t'; | |
| case 'v': | |
| return '\v'; | |
| case '\\': | |
| return '\\'; | |
| case '\'': | |
| return '\''; | |
| case '\"': | |
| return '\"'; | |
| case '?': | |
| return '\?'; | |
| case 'x': | |
| case 'X': | |
| return upb_DefBuilder_ParseHexEscape(ctx, f, src, end); | |
| case '0': | |
| case '1': | |
| case '2': | |
| case '3': | |
| case '4': | |
| case '5': | |
| case '6': | |
| case '7': | |
| *src -= 1; | |
| return upb_DefBuilder_ParseOctalEscape(ctx, f, src, end); | |
| } | |
| _upb_DefBuilder_Errf(ctx, "Unknown escape sequence: \\%c", ch); | |
| } | |
| void _upb_DefBuilder_CheckIdentSlow(upb_DefBuilder* ctx, upb_StringView name, | |
| bool full) { | |
| const char* str = name.data; | |
| const size_t len = name.size; | |
| bool start = true; | |
| for (size_t i = 0; i < len; i++) { | |
| const char c = str[i]; | |
| if (c == '.') { | |
| if (start || !full) { | |
| _upb_DefBuilder_Errf( | |
| ctx, "invalid name: unexpected '.' (" UPB_STRINGVIEW_FORMAT ")", | |
| UPB_STRINGVIEW_ARGS(name)); | |
| } | |
| start = true; | |
| } else if (start) { | |
| if (!upb_isalphanum(c)) { | |
| _upb_DefBuilder_Errf(ctx, | |
| "invalid name: path components must start with a " | |
| "letter or digit (" UPB_STRINGVIEW_FORMAT ")", | |
| UPB_STRINGVIEW_ARGS(name)); | |
| } | |
| start = false; | |
| } else if (!upb_isalphanum(c)) { | |
| _upb_DefBuilder_Errf( | |
| ctx, | |
| "invalid name: non-alphanumeric character (" UPB_STRINGVIEW_FORMAT | |
| ")", | |
| UPB_STRINGVIEW_ARGS(name)); | |
| } | |
| } | |
| if (start) { | |
| _upb_DefBuilder_Errf(ctx, | |
| "invalid name: empty part (" UPB_STRINGVIEW_FORMAT ")", | |
| UPB_STRINGVIEW_ARGS(name)); | |
| } | |
| // We should never reach this point. | |
| UPB_ASSERT(false); | |
| } | |
| upb_StringView _upb_DefBuilder_MakeKey(upb_DefBuilder* ctx, | |
| const google_protobuf_FeatureSet* parent, | |
| upb_StringView key) { | |
| size_t need = key.size + sizeof(void*); | |
| if (ctx->tmp_buf_size < need) { | |
| ctx->tmp_buf_size = UPB_MAX(64, upb_RoundUpToPowerOfTwo(need)); | |
| ctx->tmp_buf = upb_Arena_Malloc(ctx->tmp_arena, ctx->tmp_buf_size); | |
| if (!ctx->tmp_buf) _upb_DefBuilder_OomErr(ctx); | |
| } | |
| memcpy(ctx->tmp_buf, &parent, sizeof(void*)); | |
| memcpy(ctx->tmp_buf + sizeof(void*), key.data, key.size); | |
| return upb_StringView_FromDataAndSize(ctx->tmp_buf, need); | |
| } | |
| bool _upb_DefBuilder_GetOrCreateFeatureSet(upb_DefBuilder* ctx, | |
| const google_protobuf_FeatureSet* parent, | |
| upb_StringView key, | |
| google_protobuf_FeatureSet** set) { | |
| upb_StringView k = _upb_DefBuilder_MakeKey(ctx, parent, key); | |
| upb_value v; | |
| if (upb_strtable_lookup2(&ctx->feature_cache, k.data, k.size, &v)) { | |
| *set = upb_value_getptr(v); | |
| return false; | |
| } | |
| *set = (google_protobuf_FeatureSet*)upb_Message_DeepClone( | |
| UPB_UPCAST(parent), UPB_DESC_MINITABLE(FeatureSet), ctx->arena); | |
| if (!*set) _upb_DefBuilder_OomErr(ctx); | |
| v = upb_value_ptr(*set); | |
| if (!upb_strtable_insert(&ctx->feature_cache, k.data, k.size, v, | |
| ctx->tmp_arena)) { | |
| _upb_DefBuilder_OomErr(ctx); | |
| } | |
| return true; | |
| } | |
| const google_protobuf_FeatureSet* _upb_DefBuilder_DoResolveFeatures( | |
| upb_DefBuilder* ctx, const google_protobuf_FeatureSet* parent, | |
| const google_protobuf_FeatureSet* child, bool is_implicit) { | |
| assert(parent); | |
| if (!child) return parent; | |
| if (!is_implicit && | |
| _upb_DefBuilder_IsLegacyEdition(upb_FileDef_Edition(ctx->file))) { | |
| _upb_DefBuilder_Errf(ctx, "Features can only be specified for editions"); | |
| } | |
| google_protobuf_FeatureSet* resolved; | |
| size_t child_size; | |
| const char* child_bytes = | |
| google_protobuf_FeatureSet_serialize(child, ctx->tmp_arena, &child_size); | |
| if (!child_bytes) _upb_DefBuilder_OomErr(ctx); | |
| upb_StringView key = upb_StringView_FromDataAndSize(child_bytes, child_size); | |
| if (!_upb_DefBuilder_GetOrCreateFeatureSet(ctx, parent, key, &resolved)) { | |
| return resolved; | |
| } | |
| upb_DecodeStatus dec_status = | |
| upb_Decode(child_bytes, child_size, UPB_UPCAST(resolved), | |
| UPB_DESC_MINITABLE(FeatureSet), NULL, 0, ctx->arena); | |
| if (dec_status != kUpb_DecodeStatus_Ok) _upb_DefBuilder_OomErr(ctx); | |
| return resolved; | |
| } | |
| #include <string.h> | |
| // Must be last. | |
| char* upb_strdup2(const char* s, size_t len, upb_Arena* a) { | |
| size_t n; | |
| char* p; | |
| if (upb_AddOverflow(len, (size_t)1, &n)) return NULL; | |
| // Always null-terminate, even if binary data; but don't rely on the input to | |
| // have a null-terminating byte since it may be a raw binary buffer. | |
| p = upb_Arena_Malloc(a, n); | |
| if (p) { | |
| if (len != 0) memcpy(p, s, len); | |
| p[len] = 0; | |
| } | |
| return p; | |
| } | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| bool upb_Message_HasFieldByDef(const upb_Message* msg, const upb_FieldDef* f) { | |
| const upb_MiniTableField* m_f = upb_FieldDef_MiniTable(f); | |
| UPB_ASSERT(upb_FieldDef_HasPresence(f)); | |
| if (upb_MiniTableField_IsExtension(m_f)) { | |
| return upb_Message_HasExtension(msg, (const upb_MiniTableExtension*)m_f); | |
| } else { | |
| return upb_Message_HasBaseField(msg, m_f); | |
| } | |
| } | |
| const upb_FieldDef* upb_Message_WhichOneofByDef(const upb_Message* msg, | |
| const upb_OneofDef* o) { | |
| const upb_FieldDef* f = upb_OneofDef_Field(o, 0); | |
| if (upb_OneofDef_IsSynthetic(o)) { | |
| UPB_ASSERT(upb_OneofDef_FieldCount(o) == 1); | |
| return upb_Message_HasFieldByDef(msg, f) ? f : NULL; | |
| } else { | |
| const upb_MiniTableField* field = upb_FieldDef_MiniTable(f); | |
| uint32_t oneof_case = upb_Message_WhichOneofFieldNumber(msg, field); | |
| f = oneof_case ? upb_OneofDef_LookupNumber(o, oneof_case) : NULL; | |
| UPB_ASSERT((f != NULL) == (oneof_case != 0)); | |
| return f; | |
| } | |
| } | |
| upb_MessageValue upb_Message_GetFieldByDef(const upb_Message* msg, | |
| const upb_FieldDef* f) { | |
| upb_MessageValue default_val = upb_FieldDef_Default(f); | |
| return upb_Message_GetField(msg, upb_FieldDef_MiniTable(f), default_val); | |
| } | |
| upb_MutableMessageValue upb_Message_Mutable(upb_Message* msg, | |
| const upb_FieldDef* f, | |
| upb_Arena* a) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| UPB_ASSERT(upb_FieldDef_IsSubMessage(f) || upb_FieldDef_IsRepeated(f)); | |
| if (upb_FieldDef_HasPresence(f) && !upb_Message_HasFieldByDef(msg, f)) { | |
| // We need to skip the upb_Message_GetFieldByDef() call in this case. | |
| goto make; | |
| } | |
| upb_MessageValue val = upb_Message_GetFieldByDef(msg, f); | |
| if (val.array_val) { | |
| return (upb_MutableMessageValue){.array = (upb_Array*)val.array_val}; | |
| } | |
| upb_MutableMessageValue ret; | |
| make: | |
| if (!a) return (upb_MutableMessageValue){.array = NULL}; | |
| if (upb_FieldDef_IsMap(f)) { | |
| const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f); | |
| const upb_FieldDef* key = | |
| upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_KeyFieldNumber); | |
| const upb_FieldDef* value = | |
| upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_ValueFieldNumber); | |
| ret.map = | |
| upb_Map_New(a, upb_FieldDef_CType(key), upb_FieldDef_CType(value)); | |
| } else if (upb_FieldDef_IsRepeated(f)) { | |
| ret.array = upb_Array_New(a, upb_FieldDef_CType(f)); | |
| } else { | |
| UPB_ASSERT(upb_FieldDef_IsSubMessage(f)); | |
| const upb_MessageDef* m = upb_FieldDef_MessageSubDef(f); | |
| ret.msg = upb_Message_New(upb_MessageDef_MiniTable(m), a); | |
| } | |
| val.array_val = ret.array; | |
| if (!upb_Message_SetFieldByDef(msg, f, val, a)) { | |
| ret.array = NULL; | |
| } | |
| return ret; | |
| } | |
| bool upb_Message_SetFieldByDef(upb_Message* msg, const upb_FieldDef* f, | |
| upb_MessageValue val, upb_Arena* a) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| const upb_MiniTableField* m_f = upb_FieldDef_MiniTable(f); | |
| if (upb_MiniTableField_IsExtension(m_f)) { | |
| return upb_Message_SetExtension(msg, (const upb_MiniTableExtension*)m_f, | |
| &val, a); | |
| } else { | |
| upb_Message_SetBaseField(msg, m_f, &val); | |
| return true; | |
| } | |
| } | |
| void upb_Message_ClearFieldByDef(upb_Message* msg, const upb_FieldDef* f) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| const upb_MiniTableField* m_f = upb_FieldDef_MiniTable(f); | |
| if (upb_MiniTableField_IsExtension(m_f)) { | |
| upb_Message_ClearExtension(msg, (const upb_MiniTableExtension*)m_f); | |
| } else { | |
| upb_Message_ClearBaseField(msg, m_f); | |
| } | |
| } | |
| void upb_Message_ClearByDef(upb_Message* msg, const upb_MessageDef* m) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| upb_Message_Clear(msg, upb_MessageDef_MiniTable(m)); | |
| } | |
| bool upb_Message_Next(const upb_Message* msg, const upb_MessageDef* m, | |
| const upb_DefPool* ext_pool, const upb_FieldDef** out_f, | |
| upb_MessageValue* out_val, size_t* iter) { | |
| const upb_MiniTable* mt = upb_MessageDef_MiniTable(m); | |
| size_t i = *iter; | |
| size_t n = upb_MiniTable_FieldCount(mt); | |
| upb_MessageValue zero = upb_MessageValue_Zero(); | |
| UPB_UNUSED(ext_pool); | |
| // Iterate over normal fields, returning the first one that is set. | |
| while (++i < n) { | |
| const upb_MiniTableField* field = upb_MiniTable_GetFieldByIndex(mt, i); | |
| upb_MessageValue val = upb_Message_GetField(msg, field, zero); | |
| // Skip field if unset or empty. | |
| if (upb_MiniTableField_HasPresence(field)) { | |
| if (!upb_Message_HasBaseField(msg, field)) continue; | |
| } else { | |
| switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(field)) { | |
| case kUpb_FieldMode_Map: | |
| if (!val.map_val || upb_Map_Size(val.map_val) == 0) continue; | |
| break; | |
| case kUpb_FieldMode_Array: | |
| if (!val.array_val || upb_Array_Size(val.array_val) == 0) continue; | |
| break; | |
| case kUpb_FieldMode_Scalar: | |
| if (UPB_PRIVATE(_upb_MiniTableField_DataIsZero)(field, &val)) | |
| continue; | |
| break; | |
| } | |
| } | |
| *out_val = val; | |
| *out_f = | |
| upb_MessageDef_FindFieldByNumber(m, upb_MiniTableField_Number(field)); | |
| *iter = i; | |
| return true; | |
| } | |
| if (ext_pool) { | |
| upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); | |
| if (!in) return false; | |
| for (; (i - n) < in->size; i++) { | |
| upb_TaggedAuxPtr tagged_ptr = in->aux_data[i - n]; | |
| if (upb_TaggedAuxPtr_IsCanonicalExtension(tagged_ptr)) { | |
| const upb_Extension* ext = | |
| upb_TaggedAuxPtr_CanonicalExtension(tagged_ptr); | |
| *out_val = upb_Extension_GetValue(ext); | |
| *out_f = upb_DefPool_FindExtensionByMiniTable( | |
| ext_pool, upb_Extension_MiniTableExtension(ext)); | |
| *iter = i; | |
| return true; | |
| } | |
| } | |
| } | |
| *iter = i; | |
| return false; | |
| } | |
| bool _upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, | |
| const upb_DefPool* ext_pool, int depth) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| size_t iter = kUpb_Message_Begin; | |
| const upb_FieldDef* f; | |
| upb_MessageValue val; | |
| bool ret = true; | |
| if (--depth == 0) return false; | |
| _upb_Message_DiscardUnknown_shallow(msg); | |
| while (upb_Message_Next(msg, m, ext_pool, &f, &val, &iter)) { | |
| const upb_MessageDef* subm = upb_FieldDef_MessageSubDef(f); | |
| if (!subm) continue; | |
| if (upb_FieldDef_IsMap(f)) { | |
| const upb_FieldDef* val_f = upb_MessageDef_FindFieldByNumber(subm, 2); | |
| const upb_MessageDef* val_m = upb_FieldDef_MessageSubDef(val_f); | |
| upb_Map* map = (upb_Map*)val.map_val; | |
| size_t iter = kUpb_Map_Begin; | |
| if (!val_m) continue; | |
| upb_MessageValue map_key, map_val; | |
| while (upb_Map_Next(map, &map_key, &map_val, &iter)) { | |
| if (!_upb_Message_DiscardUnknown((upb_Message*)map_val.msg_val, val_m, | |
| ext_pool, depth)) { | |
| ret = false; | |
| } | |
| } | |
| } else if (upb_FieldDef_IsRepeated(f)) { | |
| const upb_Array* arr = val.array_val; | |
| size_t i, n = upb_Array_Size(arr); | |
| for (i = 0; i < n; i++) { | |
| upb_MessageValue elem = upb_Array_Get(arr, i); | |
| if (!_upb_Message_DiscardUnknown((upb_Message*)elem.msg_val, subm, | |
| ext_pool, depth)) { | |
| ret = false; | |
| } | |
| } | |
| } else { | |
| if (!_upb_Message_DiscardUnknown((upb_Message*)val.msg_val, subm, | |
| ext_pool, depth)) { | |
| ret = false; | |
| } | |
| } | |
| } | |
| return ret; | |
| } | |
| bool upb_Message_DiscardUnknown(upb_Message* msg, const upb_MessageDef* m, | |
| const upb_DefPool* ext_pool, int maxdepth) { | |
| return _upb_Message_DiscardUnknown(msg, m, ext_pool, maxdepth); | |
| } | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| struct upb_MessageDef { | |
| UPB_ALIGN_AS(8) const google_protobuf_MessageOptions* opts; | |
| const google_protobuf_FeatureSet* resolved_features; | |
| const upb_MiniTable* layout; | |
| const upb_FileDef* file; | |
| const upb_MessageDef* containing_type; | |
| const char* full_name; | |
| // Tables for looking up fields by number and name. | |
| upb_inttable itof; | |
| upb_strtable ntof; | |
| // Looking up fields by json name. | |
| upb_strtable jtof; | |
| /* All nested defs. | |
| * MEM: We could save some space here by putting nested defs in a contiguous | |
| * region and calculating counts from offsets or vice-versa. */ | |
| const upb_FieldDef* fields; | |
| const upb_OneofDef* oneofs; | |
| const upb_ExtensionRange* ext_ranges; | |
| const upb_StringView* res_names; | |
| const upb_MessageDef* nested_msgs; | |
| const upb_MessageReservedRange* res_ranges; | |
| const upb_EnumDef* nested_enums; | |
| const upb_FieldDef* nested_exts; | |
| // TODO: These counters don't need anywhere near 32 bits. | |
| int field_count; | |
| int real_oneof_count; | |
| int oneof_count; | |
| int ext_range_count; | |
| int res_range_count; | |
| int res_name_count; | |
| int nested_msg_count; | |
| int nested_enum_count; | |
| int nested_ext_count; | |
| bool in_message_set; | |
| bool is_sorted; | |
| upb_WellKnown well_known_type; | |
| google_protobuf_SymbolVisibility visibility; | |
| }; | |
| static void assign_msg_wellknowntype(upb_MessageDef* m) { | |
| const char* name = m->full_name; | |
| if (name == NULL) { | |
| m->well_known_type = kUpb_WellKnown_Unspecified; | |
| return; | |
| } | |
| if (!strcmp(name, "google.protobuf.Any")) { | |
| m->well_known_type = kUpb_WellKnown_Any; | |
| } else if (!strcmp(name, "google.protobuf.FieldMask")) { | |
| m->well_known_type = kUpb_WellKnown_FieldMask; | |
| } else if (!strcmp(name, "google.protobuf.Duration")) { | |
| m->well_known_type = kUpb_WellKnown_Duration; | |
| } else if (!strcmp(name, "google.protobuf.Timestamp")) { | |
| m->well_known_type = kUpb_WellKnown_Timestamp; | |
| } else if (!strcmp(name, "google.protobuf.DoubleValue")) { | |
| m->well_known_type = kUpb_WellKnown_DoubleValue; | |
| } else if (!strcmp(name, "google.protobuf.FloatValue")) { | |
| m->well_known_type = kUpb_WellKnown_FloatValue; | |
| } else if (!strcmp(name, "google.protobuf.Int64Value")) { | |
| m->well_known_type = kUpb_WellKnown_Int64Value; | |
| } else if (!strcmp(name, "google.protobuf.UInt64Value")) { | |
| m->well_known_type = kUpb_WellKnown_UInt64Value; | |
| } else if (!strcmp(name, "google.protobuf.Int32Value")) { | |
| m->well_known_type = kUpb_WellKnown_Int32Value; | |
| } else if (!strcmp(name, "google.protobuf.UInt32Value")) { | |
| m->well_known_type = kUpb_WellKnown_UInt32Value; | |
| } else if (!strcmp(name, "google.protobuf.BoolValue")) { | |
| m->well_known_type = kUpb_WellKnown_BoolValue; | |
| } else if (!strcmp(name, "google.protobuf.StringValue")) { | |
| m->well_known_type = kUpb_WellKnown_StringValue; | |
| } else if (!strcmp(name, "google.protobuf.BytesValue")) { | |
| m->well_known_type = kUpb_WellKnown_BytesValue; | |
| } else if (!strcmp(name, "google.protobuf.Value")) { | |
| m->well_known_type = kUpb_WellKnown_Value; | |
| } else if (!strcmp(name, "google.protobuf.ListValue")) { | |
| m->well_known_type = kUpb_WellKnown_ListValue; | |
| } else if (!strcmp(name, "google.protobuf.Struct")) { | |
| m->well_known_type = kUpb_WellKnown_Struct; | |
| } else { | |
| m->well_known_type = kUpb_WellKnown_Unspecified; | |
| } | |
| } | |
| upb_MessageDef* _upb_MessageDef_At(const upb_MessageDef* m, int i) { | |
| return (upb_MessageDef*)&m[i]; | |
| } | |
| bool _upb_MessageDef_IsValidExtensionNumber(const upb_MessageDef* m, int n) { | |
| for (int i = 0; i < m->ext_range_count; i++) { | |
| const upb_ExtensionRange* r = upb_MessageDef_ExtensionRange(m, i); | |
| if (upb_ExtensionRange_Start(r) <= n && n < upb_ExtensionRange_End(r)) { | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| const google_protobuf_MessageOptions* upb_MessageDef_Options(const upb_MessageDef* m) { | |
| return m->opts; | |
| } | |
| bool upb_MessageDef_HasOptions(const upb_MessageDef* m) { | |
| return m->opts != (void*)kUpbDefOptDefault; | |
| } | |
| const google_protobuf_FeatureSet* upb_MessageDef_ResolvedFeatures( | |
| const upb_MessageDef* m) { | |
| return m->resolved_features; | |
| } | |
| const char* upb_MessageDef_FullName(const upb_MessageDef* m) { | |
| return m->full_name; | |
| } | |
| const upb_FileDef* upb_MessageDef_File(const upb_MessageDef* m) { | |
| return m->file; | |
| } | |
| const upb_MessageDef* upb_MessageDef_ContainingType(const upb_MessageDef* m) { | |
| return m->containing_type; | |
| } | |
| const char* upb_MessageDef_Name(const upb_MessageDef* m) { | |
| return _upb_DefBuilder_FullToShort(m->full_name); | |
| } | |
| const upb_FieldDef* upb_MessageDef_FindFieldByNumber(const upb_MessageDef* m, | |
| uint32_t i) { | |
| upb_value val; | |
| return upb_inttable_lookup(&m->itof, i, &val) ? upb_value_getconstptr(val) | |
| : NULL; | |
| } | |
| const upb_FieldDef* upb_MessageDef_FindFieldByNameWithSize( | |
| const upb_MessageDef* m, const char* name, size_t size) { | |
| upb_value val; | |
| if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { | |
| return NULL; | |
| } | |
| return _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); | |
| } | |
| const upb_OneofDef* upb_MessageDef_FindOneofByNameWithSize( | |
| const upb_MessageDef* m, const char* name, size_t size) { | |
| upb_value val; | |
| if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { | |
| return NULL; | |
| } | |
| return _upb_DefType_Unpack(val, UPB_DEFTYPE_ONEOF); | |
| } | |
| bool _upb_MessageDef_Insert(upb_MessageDef* m, const char* name, size_t len, | |
| upb_value v, upb_Arena* a) { | |
| return upb_strtable_insert(&m->ntof, name, len, v, a); | |
| } | |
| bool upb_MessageDef_FindByNameWithSize(const upb_MessageDef* m, | |
| const char* name, size_t len, | |
| const upb_FieldDef** out_f, | |
| const upb_OneofDef** out_o) { | |
| upb_value val; | |
| if (!upb_strtable_lookup2(&m->ntof, name, len, &val)) { | |
| return false; | |
| } | |
| const upb_FieldDef* f = _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); | |
| const upb_OneofDef* o = _upb_DefType_Unpack(val, UPB_DEFTYPE_ONEOF); | |
| if (out_f) *out_f = f; | |
| if (out_o) *out_o = o; | |
| return f || o; /* False if this was a JSON name. */ | |
| } | |
| const upb_FieldDef* upb_MessageDef_FindByJsonNameWithSize( | |
| const upb_MessageDef* m, const char* name, size_t size) { | |
| upb_value val; | |
| if (upb_strtable_lookup2(&m->jtof, name, size, &val)) { | |
| return upb_value_getconstptr(val); | |
| } | |
| if (!upb_strtable_lookup2(&m->ntof, name, size, &val)) { | |
| return NULL; | |
| } | |
| return _upb_DefType_Unpack(val, UPB_DEFTYPE_FIELD); | |
| } | |
| int upb_MessageDef_ExtensionRangeCount(const upb_MessageDef* m) { | |
| return m->ext_range_count; | |
| } | |
| int upb_MessageDef_ReservedRangeCount(const upb_MessageDef* m) { | |
| return m->res_range_count; | |
| } | |
| int upb_MessageDef_ReservedNameCount(const upb_MessageDef* m) { | |
| return m->res_name_count; | |
| } | |
| int upb_MessageDef_FieldCount(const upb_MessageDef* m) { | |
| return m->field_count; | |
| } | |
| int upb_MessageDef_OneofCount(const upb_MessageDef* m) { | |
| return m->oneof_count; | |
| } | |
| int upb_MessageDef_RealOneofCount(const upb_MessageDef* m) { | |
| return m->real_oneof_count; | |
| } | |
| int upb_MessageDef_NestedMessageCount(const upb_MessageDef* m) { | |
| return m->nested_msg_count; | |
| } | |
| int upb_MessageDef_NestedEnumCount(const upb_MessageDef* m) { | |
| return m->nested_enum_count; | |
| } | |
| int upb_MessageDef_NestedExtensionCount(const upb_MessageDef* m) { | |
| return m->nested_ext_count; | |
| } | |
| const upb_MiniTable* upb_MessageDef_MiniTable(const upb_MessageDef* m) { | |
| return m->layout; | |
| } | |
| const upb_ExtensionRange* upb_MessageDef_ExtensionRange(const upb_MessageDef* m, | |
| int i) { | |
| UPB_ASSERT(0 <= i && i < m->ext_range_count); | |
| return _upb_ExtensionRange_At(m->ext_ranges, i); | |
| } | |
| const upb_MessageReservedRange* upb_MessageDef_ReservedRange( | |
| const upb_MessageDef* m, int i) { | |
| UPB_ASSERT(0 <= i && i < m->res_range_count); | |
| return _upb_MessageReservedRange_At(m->res_ranges, i); | |
| } | |
| upb_StringView upb_MessageDef_ReservedName(const upb_MessageDef* m, int i) { | |
| UPB_ASSERT(0 <= i && i < m->res_name_count); | |
| return m->res_names[i]; | |
| } | |
| const upb_FieldDef* upb_MessageDef_Field(const upb_MessageDef* m, int i) { | |
| UPB_ASSERT(0 <= i && i < m->field_count); | |
| return _upb_FieldDef_At(m->fields, i); | |
| } | |
| const upb_OneofDef* upb_MessageDef_Oneof(const upb_MessageDef* m, int i) { | |
| UPB_ASSERT(0 <= i && i < m->oneof_count); | |
| return _upb_OneofDef_At(m->oneofs, i); | |
| } | |
| const upb_MessageDef* upb_MessageDef_NestedMessage(const upb_MessageDef* m, | |
| int i) { | |
| UPB_ASSERT(0 <= i && i < m->nested_msg_count); | |
| return &m->nested_msgs[i]; | |
| } | |
| const upb_EnumDef* upb_MessageDef_NestedEnum(const upb_MessageDef* m, int i) { | |
| UPB_ASSERT(0 <= i && i < m->nested_enum_count); | |
| return _upb_EnumDef_At(m->nested_enums, i); | |
| } | |
| const upb_FieldDef* upb_MessageDef_NestedExtension(const upb_MessageDef* m, | |
| int i) { | |
| UPB_ASSERT(0 <= i && i < m->nested_ext_count); | |
| return _upb_FieldDef_At(m->nested_exts, i); | |
| } | |
| upb_WellKnown upb_MessageDef_WellKnownType(const upb_MessageDef* m) { | |
| return m->well_known_type; | |
| } | |
| UPB_API google_protobuf_SymbolVisibility | |
| upb_MessageDef_Visibility(const upb_MessageDef* m) { | |
| return m->visibility; | |
| } | |
| bool _upb_MessageDef_InMessageSet(const upb_MessageDef* m) { | |
| return m->in_message_set; | |
| } | |
| const upb_FieldDef* upb_MessageDef_FindFieldByName(const upb_MessageDef* m, | |
| const char* name) { | |
| return upb_MessageDef_FindFieldByNameWithSize(m, name, strlen(name)); | |
| } | |
| const upb_OneofDef* upb_MessageDef_FindOneofByName(const upb_MessageDef* m, | |
| const char* name) { | |
| return upb_MessageDef_FindOneofByNameWithSize(m, name, strlen(name)); | |
| } | |
| bool upb_MessageDef_IsMapEntry(const upb_MessageDef* m) { | |
| return google_protobuf_MessageOptions_map_entry(m->opts); | |
| } | |
| bool upb_MessageDef_IsMessageSet(const upb_MessageDef* m) { | |
| return google_protobuf_MessageOptions_message_set_wire_format(m->opts); | |
| } | |
| static upb_MiniTable* _upb_MessageDef_MakeMiniTable(upb_DefBuilder* ctx, | |
| const upb_MessageDef* m) { | |
| upb_StringView desc; | |
| // Note: this will assign layout_index for fields, so upb_FieldDef_MiniTable() | |
| // is safe to call only after this call. | |
| bool ok = upb_MessageDef_MiniDescriptorEncode(m, ctx->tmp_arena, &desc); | |
| if (!ok) _upb_DefBuilder_OomErr(ctx); | |
| void** scratch_data = _upb_DefPool_ScratchData(ctx->symtab); | |
| size_t* scratch_size = _upb_DefPool_ScratchSize(ctx->symtab); | |
| upb_MiniTable* ret = upb_MiniTable_BuildWithBuf( | |
| desc.data, desc.size, ctx->platform, ctx->arena, scratch_data, | |
| scratch_size, ctx->status); | |
| if (!ret) _upb_DefBuilder_FailJmp(ctx); | |
| return ret; | |
| } | |
| void _upb_MessageDef_Resolve(upb_DefBuilder* ctx, upb_MessageDef* m) { | |
| for (int i = 0; i < m->field_count; i++) { | |
| upb_FieldDef* f = (upb_FieldDef*)upb_MessageDef_Field(m, i); | |
| _upb_FieldDef_Resolve(ctx, m->full_name, f); | |
| } | |
| m->in_message_set = false; | |
| for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) { | |
| upb_FieldDef* ext = (upb_FieldDef*)upb_MessageDef_NestedExtension(m, i); | |
| _upb_FieldDef_Resolve(ctx, m->full_name, ext); | |
| if (upb_FieldDef_Type(ext) == kUpb_FieldType_Message && | |
| upb_FieldDef_Label(ext) == kUpb_Label_Optional && | |
| upb_FieldDef_MessageSubDef(ext) == m && | |
| google_protobuf_MessageOptions_message_set_wire_format( | |
| upb_MessageDef_Options(upb_FieldDef_ContainingType(ext)))) { | |
| m->in_message_set = true; | |
| } | |
| } | |
| for (int i = 0; i < upb_MessageDef_NestedMessageCount(m); i++) { | |
| upb_MessageDef* n = (upb_MessageDef*)upb_MessageDef_NestedMessage(m, i); | |
| _upb_MessageDef_Resolve(ctx, n); | |
| } | |
| } | |
| void _upb_MessageDef_InsertField(upb_DefBuilder* ctx, upb_MessageDef* m, | |
| const upb_FieldDef* f) { | |
| const int32_t field_number = upb_FieldDef_Number(f); | |
| if (field_number <= 0 || field_number > kUpb_MaxFieldNumber) { | |
| _upb_DefBuilder_Errf(ctx, "invalid field number (%u)", field_number); | |
| } | |
| const char* json_name = upb_FieldDef_JsonName(f); | |
| const char* shortname = upb_FieldDef_Name(f); | |
| const size_t shortnamelen = strlen(shortname); | |
| if (upb_strtable_lookup(&m->ntof, shortname, NULL)) { | |
| _upb_DefBuilder_Errf(ctx, "duplicate field name (%s)", shortname); | |
| } | |
| const upb_value field_v = _upb_DefType_Pack(f, UPB_DEFTYPE_FIELD); | |
| bool ok = | |
| _upb_MessageDef_Insert(m, shortname, shortnamelen, field_v, ctx->arena); | |
| if (!ok) _upb_DefBuilder_OomErr(ctx); | |
| bool skip_json_conflicts = | |
| google_protobuf_MessageOptions_deprecated_legacy_json_field_conflicts( | |
| upb_MessageDef_Options(m)); | |
| if (!skip_json_conflicts && strcmp(shortname, json_name) != 0 && | |
| google_protobuf_FeatureSet_json_format(m->resolved_features) == | |
| google_protobuf_FeatureSet_ALLOW && | |
| upb_strtable_lookup(&m->ntof, json_name, NULL)) { | |
| _upb_DefBuilder_Errf( | |
| ctx, "duplicate json_name for (%s) with original field name (%s)", | |
| shortname, json_name); | |
| } | |
| if (upb_strtable_lookup(&m->jtof, json_name, NULL)) { | |
| if (!skip_json_conflicts) { | |
| _upb_DefBuilder_Errf(ctx, "duplicate json_name (%s)", json_name); | |
| } | |
| } else { | |
| const size_t json_size = strlen(json_name); | |
| ok = upb_strtable_insert(&m->jtof, json_name, json_size, | |
| upb_value_constptr(f), ctx->arena); | |
| if (!ok) _upb_DefBuilder_OomErr(ctx); | |
| } | |
| if (upb_inttable_lookup(&m->itof, field_number, NULL)) { | |
| _upb_DefBuilder_Errf(ctx, "duplicate field number (%u)", field_number); | |
| } | |
| ok = upb_inttable_insert(&m->itof, field_number, upb_value_constptr(f), | |
| ctx->arena); | |
| if (!ok) _upb_DefBuilder_OomErr(ctx); | |
| } | |
| void _upb_MessageDef_CreateMiniTable(upb_DefBuilder* ctx, upb_MessageDef* m) { | |
| if (ctx->layout == NULL) { | |
| m->layout = _upb_MessageDef_MakeMiniTable(ctx, m); | |
| } else { | |
| m->layout = upb_MiniTableFile_Message(ctx->layout, ctx->msg_count++); | |
| UPB_ASSERT(m->field_count == upb_MiniTable_FieldCount(m->layout)); | |
| // We don't need the result of this call, but it will assign layout_index | |
| // for all the fields in O(n lg n) time. | |
| _upb_FieldDefs_Sorted(m->fields, m->field_count, ctx->tmp_arena); | |
| } | |
| for (int i = 0; i < m->nested_msg_count; i++) { | |
| upb_MessageDef* nested = | |
| (upb_MessageDef*)upb_MessageDef_NestedMessage(m, i); | |
| _upb_MessageDef_CreateMiniTable(ctx, nested); | |
| } | |
| } | |
| void _upb_MessageDef_LinkMiniTable(upb_DefBuilder* ctx, | |
| const upb_MessageDef* m) { | |
| for (int i = 0; i < upb_MessageDef_NestedExtensionCount(m); i++) { | |
| const upb_FieldDef* ext = upb_MessageDef_NestedExtension(m, i); | |
| _upb_FieldDef_BuildMiniTableExtension(ctx, ext); | |
| } | |
| for (int i = 0; i < m->nested_msg_count; i++) { | |
| _upb_MessageDef_LinkMiniTable(ctx, upb_MessageDef_NestedMessage(m, i)); | |
| } | |
| if (ctx->layout || ctx->platform != kUpb_MiniTablePlatform_Native) return; | |
| for (int i = 0; i < m->field_count; i++) { | |
| const upb_FieldDef* f = upb_MessageDef_Field(m, i); | |
| const upb_MessageDef* sub_m = upb_FieldDef_MessageSubDef(f); | |
| const upb_EnumDef* sub_e = upb_FieldDef_EnumSubDef(f); | |
| const int layout_index = _upb_FieldDef_LayoutIndex(f); | |
| upb_MiniTable* mt = (upb_MiniTable*)upb_MessageDef_MiniTable(m); | |
| UPB_ASSERT(layout_index < m->field_count); | |
| upb_MiniTableField* mt_f = | |
| (upb_MiniTableField*)&m->layout->UPB_PRIVATE(fields)[layout_index]; | |
| if (sub_m) { | |
| UPB_ASSERT(mt_f); | |
| UPB_ASSERT(sub_m->layout); | |
| if (UPB_UNLIKELY(!upb_MiniTable_SetSubMessage(mt, mt_f, sub_m->layout))) { | |
| _upb_DefBuilder_Errf(ctx, "invalid submsg for (%s)", m->full_name); | |
| } | |
| } else if (_upb_FieldDef_IsClosedEnum(f)) { | |
| const upb_MiniTableEnum* mt_e = _upb_EnumDef_MiniTable(sub_e); | |
| if (UPB_UNLIKELY(!upb_MiniTable_SetSubEnum(mt, mt_f, mt_e))) { | |
| _upb_DefBuilder_Errf(ctx, "invalid subenum for (%s)", m->full_name); | |
| } | |
| } | |
| } | |
| #ifndef NDEBUG | |
| for (int i = 0; i < m->field_count; i++) { | |
| const upb_FieldDef* f = upb_MessageDef_Field(m, i); | |
| const int layout_index = _upb_FieldDef_LayoutIndex(f); | |
| UPB_ASSERT(layout_index < upb_MiniTable_FieldCount(m->layout)); | |
| const upb_MiniTableField* mt_f = | |
| &m->layout->UPB_PRIVATE(fields)[layout_index]; | |
| UPB_ASSERT(upb_FieldDef_Type(f) == upb_MiniTableField_Type(mt_f)); | |
| UPB_ASSERT(upb_FieldDef_CType(f) == upb_MiniTableField_CType(mt_f)); | |
| UPB_ASSERT(upb_FieldDef_HasPresence(f) == | |
| upb_MiniTableField_HasPresence(mt_f)); | |
| } | |
| #endif | |
| } | |
| // Returns whether packable repeated fields in the message should be considered | |
| // packed by default. This is used only for the purpose of encoding | |
| // MiniDescriptors, so we just return true if there are more packed fields than | |
| // unpacked. This optimizes for smaller MiniDescriptors. | |
| static bool _upb_MessageDef_DefaultIsPacked(const upb_MessageDef* m) { | |
| int packed = 0; | |
| int unpacked = 0; | |
| for (int i = 0; i < m->field_count; i++) { | |
| const upb_FieldDef* f = upb_MessageDef_Field(m, i); | |
| if (_upb_FieldDef_IsPackable(f)) { | |
| if (upb_FieldDef_IsPacked(f)) { | |
| ++packed; | |
| } else { | |
| ++unpacked; | |
| } | |
| } | |
| } | |
| return packed > unpacked; | |
| } | |
| static bool _upb_MessageDef_ValidateUtf8(const upb_MessageDef* m) { | |
| bool has_string = false; | |
| for (int i = 0; i < m->field_count; i++) { | |
| const upb_FieldDef* f = upb_MessageDef_Field(m, i); | |
| // Old binaries do not recognize the field-level "FlipValidateUtf8" wire | |
| // modifier, so we do not actually have field-level control for old | |
| // binaries. Given this, we judge that the better failure mode is to be | |
| // more lax than intended, rather than more strict. To achieve this, we | |
| // only mark the message with the ValidateUtf8 modifier if *all* fields | |
| // validate UTF-8. | |
| if (!_upb_FieldDef_ValidateUtf8(f)) return false; | |
| if (upb_FieldDef_Type(f) == kUpb_FieldType_String) has_string = true; | |
| } | |
| return has_string; | |
| } | |
| static uint64_t _upb_MessageDef_Modifiers(const upb_MessageDef* m) { | |
| uint64_t out = 0; | |
| if (_upb_MessageDef_DefaultIsPacked(m)) { | |
| out |= kUpb_MessageModifier_DefaultIsPacked; | |
| } | |
| if (_upb_MessageDef_ValidateUtf8(m)) { | |
| out |= kUpb_MessageModifier_ValidateUtf8; | |
| } | |
| if (m->ext_range_count) { | |
| out |= kUpb_MessageModifier_IsExtendable; | |
| } | |
| return out; | |
| } | |
| static bool _upb_MessageDef_EncodeMap(upb_DescState* s, const upb_MessageDef* m, | |
| upb_Arena* a) { | |
| if (m->field_count != 2) return false; | |
| const upb_FieldDef* key_field = upb_MessageDef_Field(m, 0); | |
| const upb_FieldDef* val_field = upb_MessageDef_Field(m, 1); | |
| if (key_field == NULL || val_field == NULL) return false; | |
| UPB_ASSERT(_upb_FieldDef_LayoutIndex(key_field) == 0); | |
| UPB_ASSERT(_upb_FieldDef_LayoutIndex(val_field) == 1); | |
| s->ptr = upb_MtDataEncoder_EncodeMap( | |
| &s->e, s->ptr, upb_FieldDef_Type(key_field), upb_FieldDef_Type(val_field), | |
| _upb_FieldDef_Modifiers(key_field), _upb_FieldDef_Modifiers(val_field)); | |
| return true; | |
| } | |
| static bool _upb_MessageDef_EncodeMessage(upb_DescState* s, | |
| const upb_MessageDef* m, | |
| upb_Arena* a) { | |
| const upb_FieldDef** sorted = NULL; | |
| if (!m->is_sorted) { | |
| sorted = _upb_FieldDefs_Sorted(m->fields, m->field_count, a); | |
| if (!sorted) return false; | |
| } | |
| s->ptr = upb_MtDataEncoder_StartMessage(&s->e, s->ptr, | |
| _upb_MessageDef_Modifiers(m)); | |
| for (int i = 0; i < m->field_count; i++) { | |
| const upb_FieldDef* f = sorted ? sorted[i] : upb_MessageDef_Field(m, i); | |
| const upb_FieldType type = upb_FieldDef_Type(f); | |
| const int number = upb_FieldDef_Number(f); | |
| const uint64_t modifiers = _upb_FieldDef_Modifiers(f); | |
| if (!_upb_DescState_Grow(s, a)) return false; | |
| s->ptr = upb_MtDataEncoder_PutField(&s->e, s->ptr, type, number, modifiers); | |
| } | |
| for (int i = 0; i < m->real_oneof_count; i++) { | |
| if (!_upb_DescState_Grow(s, a)) return false; | |
| s->ptr = upb_MtDataEncoder_StartOneof(&s->e, s->ptr); | |
| const upb_OneofDef* o = upb_MessageDef_Oneof(m, i); | |
| const int field_count = upb_OneofDef_FieldCount(o); | |
| for (int j = 0; j < field_count; j++) { | |
| const int number = upb_FieldDef_Number(upb_OneofDef_Field(o, j)); | |
| if (!_upb_DescState_Grow(s, a)) return false; | |
| s->ptr = upb_MtDataEncoder_PutOneofField(&s->e, s->ptr, number); | |
| } | |
| } | |
| return true; | |
| } | |
| static bool _upb_MessageDef_EncodeMessageSet(upb_DescState* s, | |
| const upb_MessageDef* m, | |
| upb_Arena* a) { | |
| s->ptr = upb_MtDataEncoder_EncodeMessageSet(&s->e, s->ptr); | |
| return true; | |
| } | |
| bool upb_MessageDef_MiniDescriptorEncode(const upb_MessageDef* m, upb_Arena* a, | |
| upb_StringView* out) { | |
| upb_DescState s; | |
| _upb_DescState_Init(&s); | |
| if (!_upb_DescState_Grow(&s, a)) return false; | |
| if (upb_MessageDef_IsMapEntry(m)) { | |
| if (!_upb_MessageDef_EncodeMap(&s, m, a)) return false; | |
| } else if (google_protobuf_MessageOptions_message_set_wire_format(m->opts)) { | |
| if (!_upb_MessageDef_EncodeMessageSet(&s, m, a)) return false; | |
| } else { | |
| if (!_upb_MessageDef_EncodeMessage(&s, m, a)) return false; | |
| } | |
| if (!_upb_DescState_Grow(&s, a)) return false; | |
| *s.ptr = '\0'; | |
| out->data = s.buf; | |
| out->size = s.ptr - s.buf; | |
| return true; | |
| } | |
| static upb_StringView* _upb_ReservedNames_New(upb_DefBuilder* ctx, int n, | |
| const upb_StringView* protos) { | |
| upb_StringView* sv = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_StringView, n); | |
| for (int i = 0; i < n; i++) { | |
| sv[i].data = | |
| upb_strdup2(protos[i].data, protos[i].size, _upb_DefBuilder_Arena(ctx)); | |
| sv[i].size = protos[i].size; | |
| } | |
| return sv; | |
| } | |
| static void create_msgdef(upb_DefBuilder* ctx, const char* prefix, | |
| const google_protobuf_DescriptorProto* msg_proto, | |
| const google_protobuf_FeatureSet* parent_features, | |
| const upb_MessageDef* containing_type, | |
| upb_MessageDef* m) { | |
| const google_protobuf_OneofDescriptorProto* const* oneofs; | |
| const google_protobuf_FieldDescriptorProto* const* fields; | |
| const google_protobuf_DescriptorProto_ExtensionRange* const* ext_ranges; | |
| const google_protobuf_DescriptorProto_ReservedRange* const* res_ranges; | |
| const upb_StringView* res_names; | |
| size_t n_oneof, n_field, n_enum, n_ext, n_msg; | |
| size_t n_ext_range, n_res_range, n_res_name; | |
| upb_StringView name; | |
| UPB_DEF_SET_OPTIONS(m->opts, DescriptorProto, MessageOptions, msg_proto); | |
| m->resolved_features = _upb_DefBuilder_ResolveFeatures( | |
| ctx, parent_features, google_protobuf_MessageOptions_features(m->opts)); | |
| // Must happen before _upb_DefBuilder_Add() | |
| m->file = _upb_DefBuilder_File(ctx); | |
| m->containing_type = containing_type; | |
| m->is_sorted = true; | |
| name = google_protobuf_DescriptorProto_name(msg_proto); | |
| m->full_name = _upb_DefBuilder_MakeFullName(ctx, prefix, name); | |
| _upb_DefBuilder_Add(ctx, m->full_name, _upb_DefType_Pack(m, UPB_DEFTYPE_MSG)); | |
| oneofs = google_protobuf_DescriptorProto_oneof_decl(msg_proto, &n_oneof); | |
| fields = google_protobuf_DescriptorProto_field(msg_proto, &n_field); | |
| ext_ranges = google_protobuf_DescriptorProto_extension_range(msg_proto, &n_ext_range); | |
| res_ranges = google_protobuf_DescriptorProto_reserved_range(msg_proto, &n_res_range); | |
| res_names = google_protobuf_DescriptorProto_reserved_name(msg_proto, &n_res_name); | |
| bool ok = upb_inttable_init(&m->itof, ctx->arena); | |
| if (!ok) _upb_DefBuilder_OomErr(ctx); | |
| ok = upb_strtable_init(&m->ntof, n_oneof + n_field, ctx->arena); | |
| if (!ok) _upb_DefBuilder_OomErr(ctx); | |
| ok = upb_strtable_init(&m->jtof, n_field, ctx->arena); | |
| if (!ok) _upb_DefBuilder_OomErr(ctx); | |
| m->oneof_count = n_oneof; | |
| m->oneofs = _upb_OneofDefs_New(ctx, n_oneof, oneofs, m->resolved_features, m); | |
| m->field_count = n_field; | |
| m->fields = _upb_FieldDefs_New(ctx, n_field, fields, m->resolved_features, | |
| m->full_name, m, &m->is_sorted); | |
| // Message Sets may not contain fields. | |
| if (UPB_UNLIKELY(google_protobuf_MessageOptions_message_set_wire_format(m->opts))) { | |
| if (UPB_UNLIKELY(n_field > 0)) { | |
| _upb_DefBuilder_Errf(ctx, "invalid message set (%s)", m->full_name); | |
| } | |
| } | |
| m->ext_range_count = n_ext_range; | |
| m->ext_ranges = _upb_ExtensionRanges_New(ctx, n_ext_range, ext_ranges, | |
| m->resolved_features, m); | |
| m->res_range_count = n_res_range; | |
| m->res_ranges = | |
| _upb_MessageReservedRanges_New(ctx, n_res_range, res_ranges, m); | |
| m->res_name_count = n_res_name; | |
| m->res_names = _upb_ReservedNames_New(ctx, n_res_name, res_names); | |
| const size_t synthetic_count = _upb_OneofDefs_Finalize(ctx, m); | |
| m->real_oneof_count = m->oneof_count - synthetic_count; | |
| assign_msg_wellknowntype(m); | |
| const google_protobuf_EnumDescriptorProto* const* enums = | |
| google_protobuf_DescriptorProto_enum_type(msg_proto, &n_enum); | |
| m->nested_enum_count = n_enum; | |
| m->nested_enums = | |
| _upb_EnumDefs_New(ctx, n_enum, enums, m->resolved_features, m); | |
| const google_protobuf_FieldDescriptorProto* const* exts = | |
| google_protobuf_DescriptorProto_extension(msg_proto, &n_ext); | |
| m->nested_ext_count = n_ext; | |
| m->nested_exts = _upb_Extensions_New(ctx, n_ext, exts, m->resolved_features, | |
| m->full_name, m); | |
| const google_protobuf_DescriptorProto* const* msgs = | |
| google_protobuf_DescriptorProto_nested_type(msg_proto, &n_msg); | |
| m->nested_msg_count = n_msg; | |
| m->nested_msgs = | |
| _upb_MessageDefs_New(ctx, n_msg, msgs, m->resolved_features, m); | |
| m->visibility = google_protobuf_DescriptorProto_visibility(msg_proto); | |
| } | |
| // Allocate and initialize an array of |n| message defs. | |
| upb_MessageDef* _upb_MessageDefs_New( | |
| upb_DefBuilder* ctx, int n, const google_protobuf_DescriptorProto* const* protos, | |
| const google_protobuf_FeatureSet* parent_features, | |
| const upb_MessageDef* containing_type) { | |
| _upb_DefType_CheckPadding(sizeof(upb_MessageDef)); | |
| const char* name = containing_type ? containing_type->full_name | |
| : _upb_FileDef_RawPackage(ctx->file); | |
| upb_MessageDef* m = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_MessageDef, n); | |
| for (int i = 0; i < n; i++) { | |
| create_msgdef(ctx, name, protos[i], parent_features, containing_type, | |
| &m[i]); | |
| } | |
| return m; | |
| } | |
| #include <stdint.h> | |
| // Must be last. | |
| struct upb_MessageReservedRange { | |
| int32_t start; | |
| int32_t end; | |
| }; | |
| upb_MessageReservedRange* _upb_MessageReservedRange_At( | |
| const upb_MessageReservedRange* r, int i) { | |
| return (upb_MessageReservedRange*)&r[i]; | |
| } | |
| int32_t upb_MessageReservedRange_Start(const upb_MessageReservedRange* r) { | |
| return r->start; | |
| } | |
| int32_t upb_MessageReservedRange_End(const upb_MessageReservedRange* r) { | |
| return r->end; | |
| } | |
| upb_MessageReservedRange* _upb_MessageReservedRanges_New( | |
| upb_DefBuilder* ctx, int n, | |
| const google_protobuf_DescriptorProto_ReservedRange* const* protos, | |
| const upb_MessageDef* m) { | |
| upb_MessageReservedRange* r = | |
| UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_MessageReservedRange, n); | |
| for (int i = 0; i < n; i++) { | |
| const int32_t start = google_protobuf_DescriptorProto_ReservedRange_start(protos[i]); | |
| const int32_t end = google_protobuf_DescriptorProto_ReservedRange_end(protos[i]); | |
| const int32_t max = kUpb_MaxFieldNumber + 1; | |
| // A full validation would also check that each range is disjoint, and that | |
| // none of the fields overlap with the extension ranges, but we are just | |
| // sanity checking here. | |
| if (start < 1 || end <= start || end > max) { | |
| _upb_DefBuilder_Errf(ctx, | |
| "Reserved range (%d, %d) is invalid, message=%s\n", | |
| (int)start, (int)end, upb_MessageDef_FullName(m)); | |
| } | |
| r[i].start = start; | |
| r[i].end = end; | |
| } | |
| return r; | |
| } | |
| // Must be last. | |
| struct upb_MethodDef { | |
| const google_protobuf_MethodOptions* opts; | |
| const google_protobuf_FeatureSet* resolved_features; | |
| upb_ServiceDef* service; | |
| const char* full_name; | |
| const upb_MessageDef* input_type; | |
| const upb_MessageDef* output_type; | |
| int index; | |
| bool client_streaming; | |
| bool server_streaming; | |
| }; | |
| upb_MethodDef* _upb_MethodDef_At(const upb_MethodDef* m, int i) { | |
| return (upb_MethodDef*)&m[i]; | |
| } | |
| const upb_ServiceDef* upb_MethodDef_Service(const upb_MethodDef* m) { | |
| return m->service; | |
| } | |
| const google_protobuf_MethodOptions* upb_MethodDef_Options(const upb_MethodDef* m) { | |
| return m->opts; | |
| } | |
| bool upb_MethodDef_HasOptions(const upb_MethodDef* m) { | |
| return m->opts != (void*)kUpbDefOptDefault; | |
| } | |
| const google_protobuf_FeatureSet* upb_MethodDef_ResolvedFeatures( | |
| const upb_MethodDef* m) { | |
| return m->resolved_features; | |
| } | |
| const char* upb_MethodDef_FullName(const upb_MethodDef* m) { | |
| return m->full_name; | |
| } | |
| const char* upb_MethodDef_Name(const upb_MethodDef* m) { | |
| return _upb_DefBuilder_FullToShort(m->full_name); | |
| } | |
| int upb_MethodDef_Index(const upb_MethodDef* m) { return m->index; } | |
| const upb_MessageDef* upb_MethodDef_InputType(const upb_MethodDef* m) { | |
| return m->input_type; | |
| } | |
| const upb_MessageDef* upb_MethodDef_OutputType(const upb_MethodDef* m) { | |
| return m->output_type; | |
| } | |
| bool upb_MethodDef_ClientStreaming(const upb_MethodDef* m) { | |
| return m->client_streaming; | |
| } | |
| bool upb_MethodDef_ServerStreaming(const upb_MethodDef* m) { | |
| return m->server_streaming; | |
| } | |
| static void create_method(upb_DefBuilder* ctx, | |
| const google_protobuf_MethodDescriptorProto* method_proto, | |
| const google_protobuf_FeatureSet* parent_features, | |
| upb_ServiceDef* s, upb_MethodDef* m) { | |
| UPB_DEF_SET_OPTIONS(m->opts, MethodDescriptorProto, MethodOptions, | |
| method_proto); | |
| m->resolved_features = _upb_DefBuilder_ResolveFeatures( | |
| ctx, parent_features, google_protobuf_MethodOptions_features(m->opts)); | |
| upb_StringView name = google_protobuf_MethodDescriptorProto_name(method_proto); | |
| m->service = s; | |
| m->full_name = | |
| _upb_DefBuilder_MakeFullName(ctx, upb_ServiceDef_FullName(s), name); | |
| m->client_streaming = | |
| google_protobuf_MethodDescriptorProto_client_streaming(method_proto); | |
| m->server_streaming = | |
| google_protobuf_MethodDescriptorProto_server_streaming(method_proto); | |
| m->input_type = _upb_DefBuilder_Resolve( | |
| ctx, m->full_name, m->full_name, | |
| google_protobuf_MethodDescriptorProto_input_type(method_proto), UPB_DEFTYPE_MSG); | |
| m->output_type = _upb_DefBuilder_Resolve( | |
| ctx, m->full_name, m->full_name, | |
| google_protobuf_MethodDescriptorProto_output_type(method_proto), UPB_DEFTYPE_MSG); | |
| _upb_ServiceDef_InsertMethod(ctx, s, m); | |
| } | |
| // Allocate and initialize an array of |n| method defs belonging to |s|. | |
| upb_MethodDef* _upb_MethodDefs_New( | |
| upb_DefBuilder* ctx, int n, | |
| const google_protobuf_MethodDescriptorProto* const* protos, | |
| const google_protobuf_FeatureSet* parent_features, upb_ServiceDef* s) { | |
| upb_MethodDef* m = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_MethodDef, n); | |
| for (int i = 0; i < n; i++) { | |
| create_method(ctx, protos[i], parent_features, s, &m[i]); | |
| m[i].index = i; | |
| } | |
| return m; | |
| } | |
| #include <stdint.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| // Must be last. | |
| struct upb_OneofDef { | |
| UPB_ALIGN_AS(8) const google_protobuf_OneofOptions* opts; | |
| const google_protobuf_FeatureSet* resolved_features; | |
| const upb_MessageDef* parent; | |
| const char* full_name; | |
| int field_count; | |
| bool synthetic; | |
| const upb_FieldDef** fields; | |
| upb_strtable ntof; // lookup a field by name | |
| upb_inttable itof; // lookup a field by number (index) | |
| }; | |
| upb_OneofDef* _upb_OneofDef_At(const upb_OneofDef* o, int i) { | |
| return (upb_OneofDef*)&o[i]; | |
| } | |
| const google_protobuf_OneofOptions* upb_OneofDef_Options(const upb_OneofDef* o) { | |
| return o->opts; | |
| } | |
| bool upb_OneofDef_HasOptions(const upb_OneofDef* o) { | |
| return o->opts != (void*)kUpbDefOptDefault; | |
| } | |
| const google_protobuf_FeatureSet* upb_OneofDef_ResolvedFeatures(const upb_OneofDef* o) { | |
| return o->resolved_features; | |
| } | |
| const char* upb_OneofDef_FullName(const upb_OneofDef* o) { | |
| return o->full_name; | |
| } | |
| const char* upb_OneofDef_Name(const upb_OneofDef* o) { | |
| return _upb_DefBuilder_FullToShort(o->full_name); | |
| } | |
| const upb_MessageDef* upb_OneofDef_ContainingType(const upb_OneofDef* o) { | |
| return o->parent; | |
| } | |
| int upb_OneofDef_FieldCount(const upb_OneofDef* o) { return o->field_count; } | |
| const upb_FieldDef* upb_OneofDef_Field(const upb_OneofDef* o, int i) { | |
| UPB_ASSERT(i < o->field_count); | |
| return o->fields[i]; | |
| } | |
| int upb_OneofDef_numfields(const upb_OneofDef* o) { return o->field_count; } | |
| uint32_t upb_OneofDef_Index(const upb_OneofDef* o) { | |
| // Compute index in our parent's array. | |
| return o - upb_MessageDef_Oneof(o->parent, 0); | |
| } | |
| bool upb_OneofDef_IsSynthetic(const upb_OneofDef* o) { return o->synthetic; } | |
| const upb_FieldDef* upb_OneofDef_LookupNameWithSize(const upb_OneofDef* o, | |
| const char* name, | |
| size_t size) { | |
| upb_value val; | |
| return upb_strtable_lookup2(&o->ntof, name, size, &val) | |
| ? upb_value_getptr(val) | |
| : NULL; | |
| } | |
| const upb_FieldDef* upb_OneofDef_LookupName(const upb_OneofDef* o, | |
| const char* name) { | |
| return upb_OneofDef_LookupNameWithSize(o, name, strlen(name)); | |
| } | |
| const upb_FieldDef* upb_OneofDef_LookupNumber(const upb_OneofDef* o, | |
| uint32_t num) { | |
| upb_value val; | |
| return upb_inttable_lookup(&o->itof, num, &val) ? upb_value_getptr(val) | |
| : NULL; | |
| } | |
| void _upb_OneofDef_Insert(upb_DefBuilder* ctx, upb_OneofDef* o, | |
| const upb_FieldDef* f, const char* name, | |
| size_t size) { | |
| o->field_count++; | |
| if (_upb_FieldDef_IsProto3Optional(f)) o->synthetic = true; | |
| const int number = upb_FieldDef_Number(f); | |
| const upb_value v = upb_value_constptr(f); | |
| // TODO: This lookup is unfortunate because we also perform it when | |
| // inserting into the message's table. Unfortunately that step occurs after | |
| // this one and moving things around could be tricky so let's leave it for | |
| // a future refactoring. | |
| const bool number_exists = upb_inttable_lookup(&o->itof, number, NULL); | |
| if (UPB_UNLIKELY(number_exists)) { | |
| _upb_DefBuilder_Errf(ctx, "oneof fields have the same number (%d)", number); | |
| } | |
| // TODO: More redundant work happening here. | |
| const bool name_exists = upb_strtable_lookup2(&o->ntof, name, size, NULL); | |
| if (UPB_UNLIKELY(name_exists)) { | |
| _upb_DefBuilder_Errf(ctx, "oneof fields have the same name (%.*s)", | |
| (int)size, name); | |
| } | |
| const bool ok = upb_inttable_insert(&o->itof, number, v, ctx->arena) && | |
| upb_strtable_insert(&o->ntof, name, size, v, ctx->arena); | |
| if (UPB_UNLIKELY(!ok)) { | |
| _upb_DefBuilder_OomErr(ctx); | |
| } | |
| } | |
| // Returns the synthetic count. | |
| size_t _upb_OneofDefs_Finalize(upb_DefBuilder* ctx, upb_MessageDef* m) { | |
| int synthetic_count = 0; | |
| for (int i = 0; i < upb_MessageDef_OneofCount(m); i++) { | |
| upb_OneofDef* o = (upb_OneofDef*)upb_MessageDef_Oneof(m, i); | |
| if (o->synthetic && o->field_count != 1) { | |
| _upb_DefBuilder_Errf(ctx, | |
| "Synthetic oneofs must have one field, not %d: %s", | |
| o->field_count, upb_OneofDef_Name(o)); | |
| } | |
| if (o->synthetic) { | |
| synthetic_count++; | |
| } else if (synthetic_count != 0) { | |
| _upb_DefBuilder_Errf( | |
| ctx, "Synthetic oneofs must be after all other oneofs: %s", | |
| upb_OneofDef_Name(o)); | |
| } | |
| o->fields = | |
| UPB_DEFBUILDER_ALLOCARRAY(ctx, const upb_FieldDef*, o->field_count); | |
| o->field_count = 0; | |
| } | |
| for (int i = 0; i < upb_MessageDef_FieldCount(m); i++) { | |
| const upb_FieldDef* f = upb_MessageDef_Field(m, i); | |
| upb_OneofDef* o = (upb_OneofDef*)upb_FieldDef_ContainingOneof(f); | |
| if (o) { | |
| o->fields[o->field_count++] = f; | |
| } | |
| } | |
| return synthetic_count; | |
| } | |
| static void create_oneofdef(upb_DefBuilder* ctx, upb_MessageDef* m, | |
| const google_protobuf_OneofDescriptorProto* oneof_proto, | |
| const google_protobuf_FeatureSet* parent_features, | |
| const upb_OneofDef* _o) { | |
| upb_OneofDef* o = (upb_OneofDef*)_o; | |
| UPB_DEF_SET_OPTIONS(o->opts, OneofDescriptorProto, OneofOptions, oneof_proto); | |
| o->resolved_features = _upb_DefBuilder_ResolveFeatures( | |
| ctx, parent_features, google_protobuf_OneofOptions_features(o->opts)); | |
| upb_StringView name = google_protobuf_OneofDescriptorProto_name(oneof_proto); | |
| o->parent = m; | |
| o->full_name = | |
| _upb_DefBuilder_MakeFullName(ctx, upb_MessageDef_FullName(m), name); | |
| o->field_count = 0; | |
| o->synthetic = false; | |
| if (upb_MessageDef_FindByNameWithSize(m, name.data, name.size, NULL, NULL)) { | |
| _upb_DefBuilder_Errf(ctx, "duplicate oneof name (%s)", o->full_name); | |
| } | |
| upb_value v = _upb_DefType_Pack(o, UPB_DEFTYPE_ONEOF); | |
| bool ok = _upb_MessageDef_Insert(m, name.data, name.size, v, ctx->arena); | |
| if (!ok) _upb_DefBuilder_OomErr(ctx); | |
| ok = upb_inttable_init(&o->itof, ctx->arena); | |
| if (!ok) _upb_DefBuilder_OomErr(ctx); | |
| ok = upb_strtable_init(&o->ntof, 4, ctx->arena); | |
| if (!ok) _upb_DefBuilder_OomErr(ctx); | |
| } | |
| // Allocate and initialize an array of |n| oneof defs. | |
| upb_OneofDef* _upb_OneofDefs_New( | |
| upb_DefBuilder* ctx, int n, | |
| const google_protobuf_OneofDescriptorProto* const* protos, | |
| const google_protobuf_FeatureSet* parent_features, upb_MessageDef* m) { | |
| _upb_DefType_CheckPadding(sizeof(upb_OneofDef)); | |
| upb_OneofDef* o = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_OneofDef, n); | |
| for (int i = 0; i < n; i++) { | |
| create_oneofdef(ctx, m, protos[i], parent_features, &o[i]); | |
| } | |
| return o; | |
| } | |
| #include <stddef.h> | |
| #include <string.h> | |
| // Must be last. | |
| struct upb_ServiceDef { | |
| UPB_ALIGN_AS(8) const google_protobuf_ServiceOptions* opts; | |
| const google_protobuf_FeatureSet* resolved_features; | |
| const upb_FileDef* file; | |
| const char* full_name; | |
| upb_MethodDef* methods; | |
| int method_count; | |
| int index; | |
| upb_strtable ntom; | |
| }; | |
| upb_ServiceDef* _upb_ServiceDef_At(const upb_ServiceDef* s, int index) { | |
| return (upb_ServiceDef*)&s[index]; | |
| } | |
| const google_protobuf_ServiceOptions* upb_ServiceDef_Options(const upb_ServiceDef* s) { | |
| return s->opts; | |
| } | |
| bool upb_ServiceDef_HasOptions(const upb_ServiceDef* s) { | |
| return s->opts != (void*)kUpbDefOptDefault; | |
| } | |
| const google_protobuf_FeatureSet* upb_ServiceDef_ResolvedFeatures( | |
| const upb_ServiceDef* s) { | |
| return s->resolved_features; | |
| } | |
| const char* upb_ServiceDef_FullName(const upb_ServiceDef* s) { | |
| return s->full_name; | |
| } | |
| const char* upb_ServiceDef_Name(const upb_ServiceDef* s) { | |
| return _upb_DefBuilder_FullToShort(s->full_name); | |
| } | |
| int upb_ServiceDef_Index(const upb_ServiceDef* s) { return s->index; } | |
| const upb_FileDef* upb_ServiceDef_File(const upb_ServiceDef* s) { | |
| return s->file; | |
| } | |
| int upb_ServiceDef_MethodCount(const upb_ServiceDef* s) { | |
| return s->method_count; | |
| } | |
| const upb_MethodDef* upb_ServiceDef_Method(const upb_ServiceDef* s, int i) { | |
| return (i < 0 || i >= s->method_count) ? NULL | |
| : _upb_MethodDef_At(s->methods, i); | |
| } | |
| const upb_MethodDef* upb_ServiceDef_FindMethodByName(const upb_ServiceDef* s, | |
| const char* name) { | |
| return upb_ServiceDef_FindMethodByNameWithSize(s, name, strlen(name)); | |
| } | |
| const upb_MethodDef* upb_ServiceDef_FindMethodByNameWithSize( | |
| const upb_ServiceDef* s, const char* name, size_t len) { | |
| upb_value val; | |
| if (!upb_strtable_lookup2(&s->ntom, name, len, &val)) { | |
| return NULL; | |
| } | |
| return _upb_DefType_Unpack(val, UPB_DEFTYPE_METHOD); | |
| } | |
| static void create_service(upb_DefBuilder* ctx, | |
| const google_protobuf_ServiceDescriptorProto* svc_proto, | |
| const google_protobuf_FeatureSet* parent_features, | |
| upb_ServiceDef* s) { | |
| UPB_DEF_SET_OPTIONS(s->opts, ServiceDescriptorProto, ServiceOptions, | |
| svc_proto); | |
| s->resolved_features = _upb_DefBuilder_ResolveFeatures( | |
| ctx, parent_features, google_protobuf_ServiceOptions_features(s->opts)); | |
| // Must happen before _upb_DefBuilder_Add() | |
| s->file = _upb_DefBuilder_File(ctx); | |
| upb_StringView name = google_protobuf_ServiceDescriptorProto_name(svc_proto); | |
| const char* package = _upb_FileDef_RawPackage(s->file); | |
| s->full_name = _upb_DefBuilder_MakeFullName(ctx, package, name); | |
| _upb_DefBuilder_Add(ctx, s->full_name, | |
| _upb_DefType_Pack(s, UPB_DEFTYPE_SERVICE)); | |
| size_t n; | |
| const google_protobuf_MethodDescriptorProto* const* methods = | |
| google_protobuf_ServiceDescriptorProto_method(svc_proto, &n); | |
| s->method_count = n; | |
| bool ok = upb_strtable_init(&s->ntom, n, ctx->arena); | |
| if (!ok) _upb_DefBuilder_OomErr(ctx); | |
| s->methods = _upb_MethodDefs_New(ctx, n, methods, s->resolved_features, s); | |
| } | |
| upb_ServiceDef* _upb_ServiceDefs_New( | |
| upb_DefBuilder* ctx, int n, | |
| const google_protobuf_ServiceDescriptorProto* const* protos, | |
| const google_protobuf_FeatureSet* parent_features) { | |
| _upb_DefType_CheckPadding(sizeof(upb_ServiceDef)); | |
| upb_ServiceDef* s = UPB_DEFBUILDER_ALLOCARRAY(ctx, upb_ServiceDef, n); | |
| for (int i = 0; i < n; i++) { | |
| create_service(ctx, protos[i], parent_features, &s[i]); | |
| s[i].index = i; | |
| } | |
| return s; | |
| } | |
| void _upb_ServiceDef_InsertMethod(upb_DefBuilder* ctx, upb_ServiceDef* s, | |
| const upb_MethodDef* m) { | |
| const char* shortname = upb_MethodDef_Name(m); | |
| const size_t shortnamelen = strlen(shortname); | |
| upb_value existing_v; | |
| if (upb_strtable_lookup(&s->ntom, shortname, &existing_v)) { | |
| _upb_DefBuilder_Errf(ctx, "duplicate method name (%s)", shortname); | |
| } | |
| const upb_value method_v = _upb_DefType_Pack(m, UPB_DEFTYPE_METHOD); | |
| bool ok = upb_strtable_insert(&s->ntom, shortname, shortnamelen, method_v, | |
| ctx->arena); | |
| if (!ok) _upb_DefBuilder_OomErr(ctx); | |
| } | |
| #include <inttypes.h> | |
| #include <math.h> | |
| #include <setjmp.h> | |
| #include <stdarg.h> | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| typedef struct { | |
| upb_Arena* arena; | |
| jmp_buf err; | |
| } upb_ToProto_Context; | |
| #define CHK_OOM(val) \ | |
| if (!(val)) UPB_LONGJMP(ctx->err, 1); | |
| // We want to copy the options verbatim into the destination options proto. | |
| // We use serialize+parse as our deep copy. | |
| #define SET_OPTIONS(proto, desc_type, options_type, src, extreg) \ | |
| { \ | |
| size_t size; \ | |
| /* MEM: could use a temporary arena here instead. */ \ | |
| char* pb = google_protobuf_##options_type##_serialize(src, ctx->arena, &size); \ | |
| CHK_OOM(pb); \ | |
| google_protobuf_##options_type* dst = \ | |
| google_protobuf_##options_type##_parse_ex(pb, size, extreg, 0, ctx->arena); \ | |
| CHK_OOM(dst); \ | |
| google_protobuf_##desc_type##_set_options(proto, dst); \ | |
| } | |
| static upb_StringView strviewdup2(upb_ToProto_Context* ctx, | |
| upb_StringView str) { | |
| char* p = upb_Arena_Malloc(ctx->arena, str.size); | |
| CHK_OOM(p); | |
| memcpy(p, str.data, str.size); | |
| return (upb_StringView){.data = p, .size = str.size}; | |
| } | |
| static upb_StringView strviewdup(upb_ToProto_Context* ctx, const char* s) { | |
| return strviewdup2(ctx, (upb_StringView){.data = s, .size = strlen(s)}); | |
| } | |
| static upb_StringView qual_dup(upb_ToProto_Context* ctx, const char* s) { | |
| size_t n = strlen(s); | |
| char* p = upb_Arena_Malloc(ctx->arena, n + 1); | |
| CHK_OOM(p); | |
| p[0] = '.'; | |
| memcpy(p + 1, s, n); | |
| return (upb_StringView){.data = p, .size = n + 1}; | |
| } | |
| UPB_PRINTF(2, 3) | |
| static upb_StringView printf_dup(upb_ToProto_Context* ctx, const char* fmt, | |
| ...) { | |
| const size_t max = 32; | |
| char* p = upb_Arena_Malloc(ctx->arena, max); | |
| CHK_OOM(p); | |
| va_list args; | |
| va_start(args, fmt); | |
| size_t n = _upb_vsnprintf(p, max, fmt, args); | |
| va_end(args); | |
| UPB_ASSERT(n < max); | |
| return (upb_StringView){.data = p, .size = n}; | |
| } | |
| static bool upb_isprint(char ch) { return ch >= 0x20 && ch <= 0x7f; } | |
| static int special_escape(char ch) { | |
| switch (ch) { | |
| // This is the same set of special escapes recognized by | |
| // absl::CEscape(). | |
| case '\n': | |
| return 'n'; | |
| case '\r': | |
| return 'r'; | |
| case '\t': | |
| return 't'; | |
| case '\\': | |
| return '\\'; | |
| case '\'': | |
| return '\''; | |
| case '"': | |
| return '"'; | |
| default: | |
| return -1; | |
| } | |
| } | |
| static upb_StringView default_bytes(upb_ToProto_Context* ctx, | |
| upb_StringView val) { | |
| size_t n = 0; | |
| for (size_t i = 0; i < val.size; i++) { | |
| char ch = val.data[i]; | |
| if (special_escape(ch) >= 0) | |
| n += 2; // '\C' | |
| else if (upb_isprint(ch)) | |
| n += 1; | |
| else | |
| n += 4; // '\123' | |
| } | |
| char* p = upb_Arena_Malloc(ctx->arena, n); | |
| CHK_OOM(p); | |
| char* dst = p; | |
| const char* src = val.data; | |
| const char* end = src + val.size; | |
| while (src < end) { | |
| unsigned char ch = *src++; | |
| if (special_escape(ch) >= 0) { | |
| *dst++ = '\\'; | |
| *dst++ = (char)special_escape(ch); | |
| } else if (upb_isprint(ch)) { | |
| *dst++ = ch; | |
| } else { | |
| *dst++ = '\\'; | |
| *dst++ = '0' + (ch >> 6); | |
| *dst++ = '0' + ((ch >> 3) & 0x7); | |
| *dst++ = '0' + (ch & 0x7); | |
| } | |
| } | |
| return (upb_StringView){.data = p, .size = n}; | |
| } | |
| static upb_StringView default_string(upb_ToProto_Context* ctx, | |
| const upb_FieldDef* f) { | |
| upb_MessageValue d = upb_FieldDef_Default(f); | |
| upb_CType type = upb_FieldDef_CType(f); | |
| if (type == kUpb_CType_Float || type == kUpb_CType_Double) { | |
| double val = type == kUpb_CType_Float ? d.float_val : d.double_val; | |
| if (val == INFINITY) { | |
| return strviewdup(ctx, "inf"); | |
| } else if (val == -INFINITY) { | |
| return strviewdup(ctx, "-inf"); | |
| } else if (val != val) { | |
| return strviewdup(ctx, "nan"); | |
| } | |
| } | |
| switch (upb_FieldDef_CType(f)) { | |
| case kUpb_CType_Bool: | |
| return strviewdup(ctx, d.bool_val ? "true" : "false"); | |
| case kUpb_CType_Enum: { | |
| const upb_EnumDef* e = upb_FieldDef_EnumSubDef(f); | |
| const upb_EnumValueDef* ev = | |
| upb_EnumDef_FindValueByNumber(e, d.int32_val); | |
| return strviewdup(ctx, upb_EnumValueDef_Name(ev)); | |
| } | |
| case kUpb_CType_Int64: | |
| return printf_dup(ctx, "%" PRId64, d.int64_val); | |
| case kUpb_CType_UInt64: | |
| return printf_dup(ctx, "%" PRIu64, d.uint64_val); | |
| case kUpb_CType_Int32: | |
| return printf_dup(ctx, "%" PRId32, d.int32_val); | |
| case kUpb_CType_UInt32: | |
| return printf_dup(ctx, "%" PRIu32, d.uint32_val); | |
| case kUpb_CType_Float: { | |
| char buf[kUpb_RoundTripBufferSize]; | |
| _upb_EncodeRoundTripFloat(d.float_val, buf, sizeof(buf)); | |
| return strviewdup(ctx, buf); | |
| } | |
| case kUpb_CType_Double: { | |
| char buf[kUpb_RoundTripBufferSize]; | |
| _upb_EncodeRoundTripDouble(d.double_val, buf, sizeof(buf)); | |
| return strviewdup(ctx, buf); | |
| } | |
| case kUpb_CType_String: | |
| return strviewdup2(ctx, d.str_val); | |
| case kUpb_CType_Bytes: | |
| return default_bytes(ctx, d.str_val); | |
| default: | |
| UPB_UNREACHABLE(); | |
| } | |
| } | |
| static google_protobuf_DescriptorProto_ReservedRange* resrange_toproto( | |
| upb_ToProto_Context* ctx, const upb_MessageReservedRange* r) { | |
| google_protobuf_DescriptorProto_ReservedRange* proto = | |
| google_protobuf_DescriptorProto_ReservedRange_new(ctx->arena); | |
| CHK_OOM(proto); | |
| google_protobuf_DescriptorProto_ReservedRange_set_start( | |
| proto, upb_MessageReservedRange_Start(r)); | |
| google_protobuf_DescriptorProto_ReservedRange_set_end(proto, | |
| upb_MessageReservedRange_End(r)); | |
| return proto; | |
| } | |
| static google_protobuf_EnumDescriptorProto_EnumReservedRange* enumresrange_toproto( | |
| upb_ToProto_Context* ctx, const upb_EnumReservedRange* r) { | |
| google_protobuf_EnumDescriptorProto_EnumReservedRange* proto = | |
| google_protobuf_EnumDescriptorProto_EnumReservedRange_new(ctx->arena); | |
| CHK_OOM(proto); | |
| google_protobuf_EnumDescriptorProto_EnumReservedRange_set_start( | |
| proto, upb_EnumReservedRange_Start(r)); | |
| google_protobuf_EnumDescriptorProto_EnumReservedRange_set_end( | |
| proto, upb_EnumReservedRange_End(r)); | |
| return proto; | |
| } | |
| static google_protobuf_FieldDescriptorProto* fielddef_toproto(upb_ToProto_Context* ctx, | |
| const upb_FieldDef* f) { | |
| google_protobuf_FieldDescriptorProto* proto = | |
| google_protobuf_FieldDescriptorProto_new(ctx->arena); | |
| CHK_OOM(proto); | |
| google_protobuf_FieldDescriptorProto_set_name(proto, | |
| strviewdup(ctx, upb_FieldDef_Name(f))); | |
| google_protobuf_FieldDescriptorProto_set_number(proto, upb_FieldDef_Number(f)); | |
| if (upb_FieldDef_IsRequired(f) && | |
| upb_FileDef_Edition(upb_FieldDef_File(f)) >= google_protobuf_EDITION_2023) { | |
| google_protobuf_FieldDescriptorProto_set_label( | |
| proto, google_protobuf_FieldDescriptorProto_LABEL_OPTIONAL); | |
| } else { | |
| google_protobuf_FieldDescriptorProto_set_label(proto, upb_FieldDef_Label(f)); | |
| } | |
| if (upb_FieldDef_Type(f) == kUpb_FieldType_Group && | |
| upb_FileDef_Edition(upb_FieldDef_File(f)) >= google_protobuf_EDITION_2023) { | |
| google_protobuf_FieldDescriptorProto_set_type(proto, kUpb_FieldType_Message); | |
| } else { | |
| google_protobuf_FieldDescriptorProto_set_type(proto, upb_FieldDef_Type(f)); | |
| } | |
| if (upb_FieldDef_HasJsonName(f)) { | |
| google_protobuf_FieldDescriptorProto_set_json_name( | |
| proto, strviewdup(ctx, upb_FieldDef_JsonName(f))); | |
| } | |
| if (upb_FieldDef_IsSubMessage(f)) { | |
| google_protobuf_FieldDescriptorProto_set_type_name( | |
| proto, | |
| qual_dup(ctx, upb_MessageDef_FullName(upb_FieldDef_MessageSubDef(f)))); | |
| } else if (upb_FieldDef_CType(f) == kUpb_CType_Enum) { | |
| google_protobuf_FieldDescriptorProto_set_type_name( | |
| proto, qual_dup(ctx, upb_EnumDef_FullName(upb_FieldDef_EnumSubDef(f)))); | |
| } | |
| if (upb_FieldDef_IsExtension(f)) { | |
| google_protobuf_FieldDescriptorProto_set_extendee( | |
| proto, | |
| qual_dup(ctx, upb_MessageDef_FullName(upb_FieldDef_ContainingType(f)))); | |
| } | |
| if (upb_FieldDef_HasDefault(f)) { | |
| google_protobuf_FieldDescriptorProto_set_default_value(proto, | |
| default_string(ctx, f)); | |
| } | |
| const upb_OneofDef* o = upb_FieldDef_ContainingOneof(f); | |
| if (o) { | |
| google_protobuf_FieldDescriptorProto_set_oneof_index(proto, upb_OneofDef_Index(o)); | |
| } | |
| if (_upb_FieldDef_IsProto3Optional(f)) { | |
| google_protobuf_FieldDescriptorProto_set_proto3_optional(proto, true); | |
| } | |
| if (upb_FieldDef_HasOptions(f)) { | |
| SET_OPTIONS(proto, FieldDescriptorProto, FieldOptions, | |
| upb_FieldDef_Options(f), | |
| _upb_DefPool_GeneratedExtensionRegistry( | |
| upb_FileDef_Pool(upb_FieldDef_File(f)))); | |
| } | |
| return proto; | |
| } | |
| static google_protobuf_OneofDescriptorProto* oneofdef_toproto(upb_ToProto_Context* ctx, | |
| const upb_OneofDef* o) { | |
| google_protobuf_OneofDescriptorProto* proto = | |
| google_protobuf_OneofDescriptorProto_new(ctx->arena); | |
| CHK_OOM(proto); | |
| google_protobuf_OneofDescriptorProto_set_name(proto, | |
| strviewdup(ctx, upb_OneofDef_Name(o))); | |
| if (upb_OneofDef_HasOptions(o)) { | |
| SET_OPTIONS(proto, OneofDescriptorProto, OneofOptions, | |
| upb_OneofDef_Options(o), | |
| _upb_DefPool_GeneratedExtensionRegistry(upb_FileDef_Pool( | |
| upb_MessageDef_File(upb_OneofDef_ContainingType(o))))); | |
| } | |
| return proto; | |
| } | |
| static google_protobuf_EnumValueDescriptorProto* enumvaldef_toproto( | |
| upb_ToProto_Context* ctx, const upb_EnumValueDef* e) { | |
| google_protobuf_EnumValueDescriptorProto* proto = | |
| google_protobuf_EnumValueDescriptorProto_new(ctx->arena); | |
| CHK_OOM(proto); | |
| google_protobuf_EnumValueDescriptorProto_set_name( | |
| proto, strviewdup(ctx, upb_EnumValueDef_Name(e))); | |
| google_protobuf_EnumValueDescriptorProto_set_number(proto, upb_EnumValueDef_Number(e)); | |
| if (upb_EnumValueDef_HasOptions(e)) { | |
| SET_OPTIONS(proto, EnumValueDescriptorProto, EnumValueOptions, | |
| upb_EnumValueDef_Options(e), | |
| _upb_DefPool_GeneratedExtensionRegistry(upb_FileDef_Pool( | |
| upb_EnumDef_File(upb_EnumValueDef_Enum(e))))); | |
| } | |
| return proto; | |
| } | |
| static google_protobuf_EnumDescriptorProto* enumdef_toproto(upb_ToProto_Context* ctx, | |
| const upb_EnumDef* e) { | |
| google_protobuf_EnumDescriptorProto* proto = | |
| google_protobuf_EnumDescriptorProto_new(ctx->arena); | |
| CHK_OOM(proto); | |
| google_protobuf_EnumDescriptorProto_set_name(proto, | |
| strviewdup(ctx, upb_EnumDef_Name(e))); | |
| int n = upb_EnumDef_ValueCount(e); | |
| google_protobuf_EnumValueDescriptorProto** vals = | |
| google_protobuf_EnumDescriptorProto_resize_value(proto, n, ctx->arena); | |
| CHK_OOM(vals); | |
| for (int i = 0; i < n; i++) { | |
| vals[i] = enumvaldef_toproto(ctx, upb_EnumDef_Value(e, i)); | |
| } | |
| n = upb_EnumDef_ReservedRangeCount(e); | |
| google_protobuf_EnumDescriptorProto_EnumReservedRange** res_ranges = | |
| google_protobuf_EnumDescriptorProto_resize_reserved_range(proto, n, ctx->arena); | |
| for (int i = 0; i < n; i++) { | |
| res_ranges[i] = enumresrange_toproto(ctx, upb_EnumDef_ReservedRange(e, i)); | |
| } | |
| n = upb_EnumDef_ReservedNameCount(e); | |
| upb_StringView* res_names = | |
| google_protobuf_EnumDescriptorProto_resize_reserved_name(proto, n, ctx->arena); | |
| for (int i = 0; i < n; i++) { | |
| res_names[i] = upb_EnumDef_ReservedName(e, i); | |
| } | |
| if (upb_EnumDef_HasOptions(e)) { | |
| SET_OPTIONS(proto, EnumDescriptorProto, EnumOptions, upb_EnumDef_Options(e), | |
| _upb_DefPool_GeneratedExtensionRegistry( | |
| upb_FileDef_Pool(upb_EnumDef_File(e)))); | |
| } | |
| google_protobuf_SymbolVisibility visibility = upb_EnumDef_Visibility(e); | |
| if (visibility != google_protobuf_VISIBILITY_UNSET) { | |
| google_protobuf_EnumDescriptorProto_set_visibility(proto, visibility); | |
| } | |
| return proto; | |
| } | |
| static google_protobuf_DescriptorProto_ExtensionRange* extrange_toproto( | |
| upb_ToProto_Context* ctx, const upb_MessageDef* m, | |
| const upb_ExtensionRange* e) { | |
| google_protobuf_DescriptorProto_ExtensionRange* proto = | |
| google_protobuf_DescriptorProto_ExtensionRange_new(ctx->arena); | |
| CHK_OOM(proto); | |
| google_protobuf_DescriptorProto_ExtensionRange_set_start(proto, | |
| upb_ExtensionRange_Start(e)); | |
| google_protobuf_DescriptorProto_ExtensionRange_set_end(proto, | |
| upb_ExtensionRange_End(e)); | |
| if (upb_ExtensionRange_HasOptions(e)) { | |
| SET_OPTIONS(proto, DescriptorProto_ExtensionRange, ExtensionRangeOptions, | |
| upb_ExtensionRange_Options(e), | |
| _upb_DefPool_GeneratedExtensionRegistry( | |
| upb_FileDef_Pool(upb_MessageDef_File(m)))); | |
| } | |
| return proto; | |
| } | |
| static google_protobuf_DescriptorProto* msgdef_toproto(upb_ToProto_Context* ctx, | |
| const upb_MessageDef* m) { | |
| google_protobuf_DescriptorProto* proto = google_protobuf_DescriptorProto_new(ctx->arena); | |
| CHK_OOM(proto); | |
| google_protobuf_DescriptorProto_set_name(proto, | |
| strviewdup(ctx, upb_MessageDef_Name(m))); | |
| int n; | |
| n = upb_MessageDef_FieldCount(m); | |
| google_protobuf_FieldDescriptorProto** fields = | |
| google_protobuf_DescriptorProto_resize_field(proto, n, ctx->arena); | |
| CHK_OOM(fields); | |
| for (int i = 0; i < n; i++) { | |
| fields[i] = fielddef_toproto(ctx, upb_MessageDef_Field(m, i)); | |
| } | |
| n = upb_MessageDef_OneofCount(m); | |
| google_protobuf_OneofDescriptorProto** oneofs = | |
| google_protobuf_DescriptorProto_resize_oneof_decl(proto, n, ctx->arena); | |
| for (int i = 0; i < n; i++) { | |
| oneofs[i] = oneofdef_toproto(ctx, upb_MessageDef_Oneof(m, i)); | |
| } | |
| n = upb_MessageDef_NestedMessageCount(m); | |
| google_protobuf_DescriptorProto** nested_msgs = | |
| google_protobuf_DescriptorProto_resize_nested_type(proto, n, ctx->arena); | |
| for (int i = 0; i < n; i++) { | |
| nested_msgs[i] = msgdef_toproto(ctx, upb_MessageDef_NestedMessage(m, i)); | |
| } | |
| n = upb_MessageDef_NestedEnumCount(m); | |
| google_protobuf_EnumDescriptorProto** nested_enums = | |
| google_protobuf_DescriptorProto_resize_enum_type(proto, n, ctx->arena); | |
| for (int i = 0; i < n; i++) { | |
| nested_enums[i] = enumdef_toproto(ctx, upb_MessageDef_NestedEnum(m, i)); | |
| } | |
| n = upb_MessageDef_NestedExtensionCount(m); | |
| google_protobuf_FieldDescriptorProto** nested_exts = | |
| google_protobuf_DescriptorProto_resize_extension(proto, n, ctx->arena); | |
| for (int i = 0; i < n; i++) { | |
| nested_exts[i] = | |
| fielddef_toproto(ctx, upb_MessageDef_NestedExtension(m, i)); | |
| } | |
| n = upb_MessageDef_ExtensionRangeCount(m); | |
| google_protobuf_DescriptorProto_ExtensionRange** ext_ranges = | |
| google_protobuf_DescriptorProto_resize_extension_range(proto, n, ctx->arena); | |
| for (int i = 0; i < n; i++) { | |
| ext_ranges[i] = | |
| extrange_toproto(ctx, m, upb_MessageDef_ExtensionRange(m, i)); | |
| } | |
| n = upb_MessageDef_ReservedRangeCount(m); | |
| google_protobuf_DescriptorProto_ReservedRange** res_ranges = | |
| google_protobuf_DescriptorProto_resize_reserved_range(proto, n, ctx->arena); | |
| for (int i = 0; i < n; i++) { | |
| res_ranges[i] = resrange_toproto(ctx, upb_MessageDef_ReservedRange(m, i)); | |
| } | |
| n = upb_MessageDef_ReservedNameCount(m); | |
| upb_StringView* res_names = | |
| google_protobuf_DescriptorProto_resize_reserved_name(proto, n, ctx->arena); | |
| for (int i = 0; i < n; i++) { | |
| res_names[i] = upb_MessageDef_ReservedName(m, i); | |
| } | |
| if (upb_MessageDef_HasOptions(m)) { | |
| SET_OPTIONS(proto, DescriptorProto, MessageOptions, | |
| upb_MessageDef_Options(m), | |
| _upb_DefPool_GeneratedExtensionRegistry( | |
| upb_FileDef_Pool(upb_MessageDef_File(m)))); | |
| } | |
| google_protobuf_SymbolVisibility visibility = upb_MessageDef_Visibility(m); | |
| if (visibility != google_protobuf_VISIBILITY_UNSET) { | |
| google_protobuf_DescriptorProto_set_visibility(proto, visibility); | |
| } | |
| return proto; | |
| } | |
| static google_protobuf_MethodDescriptorProto* methoddef_toproto(upb_ToProto_Context* ctx, | |
| const upb_MethodDef* m) { | |
| google_protobuf_MethodDescriptorProto* proto = | |
| google_protobuf_MethodDescriptorProto_new(ctx->arena); | |
| CHK_OOM(proto); | |
| google_protobuf_MethodDescriptorProto_set_name(proto, | |
| strviewdup(ctx, upb_MethodDef_Name(m))); | |
| google_protobuf_MethodDescriptorProto_set_input_type( | |
| proto, | |
| qual_dup(ctx, upb_MessageDef_FullName(upb_MethodDef_InputType(m)))); | |
| google_protobuf_MethodDescriptorProto_set_output_type( | |
| proto, | |
| qual_dup(ctx, upb_MessageDef_FullName(upb_MethodDef_OutputType(m)))); | |
| if (upb_MethodDef_ClientStreaming(m)) { | |
| google_protobuf_MethodDescriptorProto_set_client_streaming(proto, true); | |
| } | |
| if (upb_MethodDef_ServerStreaming(m)) { | |
| google_protobuf_MethodDescriptorProto_set_server_streaming(proto, true); | |
| } | |
| if (upb_MethodDef_HasOptions(m)) { | |
| SET_OPTIONS( | |
| proto, MethodDescriptorProto, MethodOptions, upb_MethodDef_Options(m), | |
| _upb_DefPool_GeneratedExtensionRegistry( | |
| upb_FileDef_Pool(upb_ServiceDef_File(upb_MethodDef_Service(m))))); | |
| } | |
| return proto; | |
| } | |
| static google_protobuf_ServiceDescriptorProto* servicedef_toproto( | |
| upb_ToProto_Context* ctx, const upb_ServiceDef* s) { | |
| google_protobuf_ServiceDescriptorProto* proto = | |
| google_protobuf_ServiceDescriptorProto_new(ctx->arena); | |
| CHK_OOM(proto); | |
| google_protobuf_ServiceDescriptorProto_set_name( | |
| proto, strviewdup(ctx, upb_ServiceDef_Name(s))); | |
| size_t n = upb_ServiceDef_MethodCount(s); | |
| google_protobuf_MethodDescriptorProto** methods = | |
| google_protobuf_ServiceDescriptorProto_resize_method(proto, n, ctx->arena); | |
| for (size_t i = 0; i < n; i++) { | |
| methods[i] = methoddef_toproto(ctx, upb_ServiceDef_Method(s, i)); | |
| } | |
| if (upb_ServiceDef_HasOptions(s)) { | |
| SET_OPTIONS(proto, ServiceDescriptorProto, ServiceOptions, | |
| upb_ServiceDef_Options(s), | |
| _upb_DefPool_GeneratedExtensionRegistry( | |
| upb_FileDef_Pool(upb_ServiceDef_File(s)))); | |
| } | |
| return proto; | |
| } | |
| static google_protobuf_FileDescriptorProto* filedef_toproto(upb_ToProto_Context* ctx, | |
| const upb_FileDef* f) { | |
| google_protobuf_FileDescriptorProto* proto = | |
| google_protobuf_FileDescriptorProto_new(ctx->arena); | |
| CHK_OOM(proto); | |
| google_protobuf_FileDescriptorProto_set_name(proto, | |
| strviewdup(ctx, upb_FileDef_Name(f))); | |
| const char* package = upb_FileDef_Package(f); | |
| if (package) { | |
| size_t n = strlen(package); | |
| if (n) { | |
| google_protobuf_FileDescriptorProto_set_package(proto, strviewdup(ctx, package)); | |
| } | |
| } | |
| google_protobuf_Edition edition = upb_FileDef_Edition(f); | |
| switch (edition) { | |
| case google_protobuf_EDITION_PROTO2: | |
| // We could set syntax to "proto2", but C++ omits it completely, which is | |
| // equivalent. | |
| break; | |
| case google_protobuf_EDITION_PROTO3: | |
| google_protobuf_FileDescriptorProto_set_syntax(proto, strviewdup(ctx, "proto3")); | |
| break; | |
| default: | |
| google_protobuf_FileDescriptorProto_set_syntax(proto, strviewdup(ctx, "editions")); | |
| google_protobuf_FileDescriptorProto_set_edition(proto, edition); | |
| break; | |
| } | |
| size_t n; | |
| n = upb_FileDef_DependencyCount(f); | |
| upb_StringView* deps = | |
| google_protobuf_FileDescriptorProto_resize_dependency(proto, n, ctx->arena); | |
| for (size_t i = 0; i < n; i++) { | |
| deps[i] = strviewdup(ctx, upb_FileDef_Name(upb_FileDef_Dependency(f, i))); | |
| } | |
| n = upb_FileDef_PublicDependencyCount(f); | |
| int32_t* public_deps = | |
| google_protobuf_FileDescriptorProto_resize_public_dependency(proto, n, ctx->arena); | |
| const int32_t* public_dep_nums = _upb_FileDef_PublicDependencyIndexes(f); | |
| if (n) memcpy(public_deps, public_dep_nums, n * sizeof(int32_t)); | |
| n = upb_FileDef_WeakDependencyCount(f); | |
| int32_t* weak_deps = | |
| google_protobuf_FileDescriptorProto_resize_weak_dependency(proto, n, ctx->arena); | |
| const int32_t* weak_dep_nums = _upb_FileDef_WeakDependencyIndexes(f); | |
| if (n) memcpy(weak_deps, weak_dep_nums, n * sizeof(int32_t)); | |
| n = upb_FileDef_OptionDependencyCount(f); | |
| upb_StringView* option_deps = | |
| google_protobuf_FileDescriptorProto_resize_option_dependency(proto, n, ctx->arena); | |
| for (size_t i = 0; i < n; i++) { | |
| option_deps[i] = strviewdup(ctx, upb_FileDef_OptionDependency(f, i)); | |
| } | |
| n = upb_FileDef_TopLevelMessageCount(f); | |
| google_protobuf_DescriptorProto** msgs = | |
| google_protobuf_FileDescriptorProto_resize_message_type(proto, n, ctx->arena); | |
| for (size_t i = 0; i < n; i++) { | |
| msgs[i] = msgdef_toproto(ctx, upb_FileDef_TopLevelMessage(f, i)); | |
| } | |
| n = upb_FileDef_TopLevelEnumCount(f); | |
| google_protobuf_EnumDescriptorProto** enums = | |
| google_protobuf_FileDescriptorProto_resize_enum_type(proto, n, ctx->arena); | |
| for (size_t i = 0; i < n; i++) { | |
| enums[i] = enumdef_toproto(ctx, upb_FileDef_TopLevelEnum(f, i)); | |
| } | |
| n = upb_FileDef_ServiceCount(f); | |
| google_protobuf_ServiceDescriptorProto** services = | |
| google_protobuf_FileDescriptorProto_resize_service(proto, n, ctx->arena); | |
| for (size_t i = 0; i < n; i++) { | |
| services[i] = servicedef_toproto(ctx, upb_FileDef_Service(f, i)); | |
| } | |
| n = upb_FileDef_TopLevelExtensionCount(f); | |
| google_protobuf_FieldDescriptorProto** exts = | |
| google_protobuf_FileDescriptorProto_resize_extension(proto, n, ctx->arena); | |
| for (size_t i = 0; i < n; i++) { | |
| exts[i] = fielddef_toproto(ctx, upb_FileDef_TopLevelExtension(f, i)); | |
| } | |
| if (upb_FileDef_HasOptions(f)) { | |
| SET_OPTIONS(proto, FileDescriptorProto, FileOptions, upb_FileDef_Options(f), | |
| _upb_DefPool_GeneratedExtensionRegistry(upb_FileDef_Pool(f))); | |
| } | |
| return proto; | |
| } | |
| static google_protobuf_DescriptorProto* upb_ToProto_ConvertMessageDef( | |
| upb_ToProto_Context* const ctx, const upb_MessageDef* const m) { | |
| if (UPB_SETJMP(ctx->err)) return NULL; | |
| return msgdef_toproto(ctx, m); | |
| } | |
| google_protobuf_DescriptorProto* upb_MessageDef_ToProto(const upb_MessageDef* m, | |
| upb_Arena* a) { | |
| upb_ToProto_Context ctx = {a}; | |
| return upb_ToProto_ConvertMessageDef(&ctx, m); | |
| } | |
| google_protobuf_EnumDescriptorProto* upb_ToProto_ConvertEnumDef( | |
| upb_ToProto_Context* const ctx, const upb_EnumDef* const e) { | |
| if (UPB_SETJMP(ctx->err)) return NULL; | |
| return enumdef_toproto(ctx, e); | |
| } | |
| google_protobuf_EnumDescriptorProto* upb_EnumDef_ToProto(const upb_EnumDef* e, | |
| upb_Arena* a) { | |
| upb_ToProto_Context ctx = {a}; | |
| return upb_ToProto_ConvertEnumDef(&ctx, e); | |
| } | |
| google_protobuf_EnumValueDescriptorProto* upb_ToProto_ConvertEnumValueDef( | |
| upb_ToProto_Context* const ctx, const upb_EnumValueDef* e) { | |
| if (UPB_SETJMP(ctx->err)) return NULL; | |
| return enumvaldef_toproto(ctx, e); | |
| } | |
| google_protobuf_EnumValueDescriptorProto* upb_EnumValueDef_ToProto( | |
| const upb_EnumValueDef* e, upb_Arena* a) { | |
| upb_ToProto_Context ctx = {a}; | |
| return upb_ToProto_ConvertEnumValueDef(&ctx, e); | |
| } | |
| google_protobuf_FieldDescriptorProto* upb_ToProto_ConvertFieldDef( | |
| upb_ToProto_Context* const ctx, const upb_FieldDef* f) { | |
| if (UPB_SETJMP(ctx->err)) return NULL; | |
| return fielddef_toproto(ctx, f); | |
| } | |
| google_protobuf_FieldDescriptorProto* upb_FieldDef_ToProto(const upb_FieldDef* f, | |
| upb_Arena* a) { | |
| upb_ToProto_Context ctx = {a}; | |
| return upb_ToProto_ConvertFieldDef(&ctx, f); | |
| } | |
| google_protobuf_OneofDescriptorProto* upb_ToProto_ConvertOneofDef( | |
| upb_ToProto_Context* const ctx, const upb_OneofDef* o) { | |
| if (UPB_SETJMP(ctx->err)) return NULL; | |
| return oneofdef_toproto(ctx, o); | |
| } | |
| google_protobuf_OneofDescriptorProto* upb_OneofDef_ToProto(const upb_OneofDef* o, | |
| upb_Arena* a) { | |
| upb_ToProto_Context ctx = {a}; | |
| return upb_ToProto_ConvertOneofDef(&ctx, o); | |
| } | |
| google_protobuf_FileDescriptorProto* upb_ToProto_ConvertFileDef( | |
| upb_ToProto_Context* const ctx, const upb_FileDef* const f) { | |
| if (UPB_SETJMP(ctx->err)) return NULL; | |
| return filedef_toproto(ctx, f); | |
| } | |
| google_protobuf_FileDescriptorProto* upb_FileDef_ToProto(const upb_FileDef* f, | |
| upb_Arena* a) { | |
| upb_ToProto_Context ctx = {a}; | |
| return upb_ToProto_ConvertFileDef(&ctx, f); | |
| } | |
| google_protobuf_MethodDescriptorProto* upb_ToProto_ConvertMethodDef( | |
| upb_ToProto_Context* const ctx, const upb_MethodDef* m) { | |
| if (UPB_SETJMP(ctx->err)) return NULL; | |
| return methoddef_toproto(ctx, m); | |
| } | |
| google_protobuf_MethodDescriptorProto* upb_MethodDef_ToProto( | |
| const upb_MethodDef* const m, upb_Arena* a) { | |
| upb_ToProto_Context ctx = {a}; | |
| return upb_ToProto_ConvertMethodDef(&ctx, m); | |
| } | |
| google_protobuf_ServiceDescriptorProto* upb_ToProto_ConvertServiceDef( | |
| upb_ToProto_Context* const ctx, const upb_ServiceDef* const s) { | |
| if (UPB_SETJMP(ctx->err)) return NULL; | |
| return servicedef_toproto(ctx, s); | |
| } | |
| google_protobuf_ServiceDescriptorProto* upb_ServiceDef_ToProto(const upb_ServiceDef* s, | |
| upb_Arena* a) { | |
| upb_ToProto_Context ctx = {a}; | |
| return upb_ToProto_ConvertServiceDef(&ctx, s); | |
| } | |
| #include <assert.h> | |
| #include <stdbool.h> | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Our awkward dance for including fasttable only when it is enabled. | |
| #if UPB_FASTTABLE | |
| #define UPB_INCLUDE_FAST_DECODE | |
| #endif | |
| #ifdef UPB_INCLUDE_FAST_DECODE | |
| #endif | |
| #undef UPB_INCLUDE_FAST_DECODE | |
| // Must be last. | |
| // A few fake field types for our tables. | |
| enum { | |
| kUpb_FakeFieldType_FieldNotFound = 0, | |
| kUpb_FakeFieldType_MessageSetItem = 19, | |
| }; | |
| // DecodeOp: an action to be performed for a wire-type/field-type combination. | |
| enum { | |
| // Special ops: we don't write data to regular fields for these. | |
| kUpb_DecodeOp_UnknownField = -1, | |
| kUpb_DecodeOp_MessageSetItem = -2, | |
| // Scalar-only ops. | |
| kUpb_DecodeOp_Scalar1Byte = 0, | |
| kUpb_DecodeOp_Scalar4Byte = 2, | |
| kUpb_DecodeOp_Scalar8Byte = 3, | |
| // Scalar/repeated ops. | |
| kUpb_DecodeOp_String = 4, | |
| kUpb_DecodeOp_Bytes = 5, | |
| kUpb_DecodeOp_SubMessage = 6, | |
| // Repeated-only ops (also see macros below). | |
| kUpb_DecodeOp_PackedEnum = 13, | |
| }; | |
| // For packed fields it is helpful to be able to recover the lg2 of the data | |
| // size from the op. | |
| #define OP_FIXPCK_LG2(n) (n + 5) /* n in [2, 3] => op in [7, 8] */ | |
| #define OP_VARPCK_LG2(n) (n + 9) /* n in [0, 2, 3] => op in [9, 11, 12] */ | |
| static bool _upb_Decoder_Reserve(upb_Decoder* d, upb_Array* arr, size_t elem) { | |
| bool need_realloc = | |
| arr->UPB_PRIVATE(capacity) - arr->UPB_PRIVATE(size) < elem; | |
| if (need_realloc && !UPB_PRIVATE(_upb_Array_Realloc)( | |
| arr, arr->UPB_PRIVATE(size) + elem, &d->arena)) { | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); | |
| } | |
| return need_realloc; | |
| } | |
| typedef struct { | |
| const char* ptr; | |
| uint64_t val; | |
| } _upb_DecodeLongVarintReturn; | |
| // This is identical to _upb_Decoder_DecodeTag() except that the maximum value | |
| // is INT32_MAX instead of UINT32_MAX. | |
| UPB_FORCEINLINE | |
| const char* upb_Decoder_DecodeSize(upb_Decoder* d, const char* ptr, | |
| uint32_t* size) { | |
| int sz; | |
| ptr = upb_WireReader_ReadSize(ptr, &sz, EPS(d)); | |
| *size = sz; | |
| return ptr; | |
| } | |
| UPB_FORCEINLINE upb_AddUnknownMode | |
| _upb_Decoder_GetAddUnknownMode(upb_Decoder* d, const char* data) { | |
| if (d->options & kUpb_DecodeOption_AliasString) { | |
| if (data != d->input.buffer_start) { | |
| // If the data is not from the beginning of the input buffer, then we can | |
| // safely attempt to coalesce this region with the previous one. | |
| return kUpb_AddUnknown_AliasAllowMerge; | |
| } else { | |
| return kUpb_AddUnknown_Alias; | |
| } | |
| } | |
| return kUpb_AddUnknown_Copy; | |
| } | |
| static void _upb_Decoder_MungeInt32(wireval* val) { | |
| if (!upb_IsLittleEndian()) { | |
| /* The next stage will memcpy(dst, &val, 4) */ | |
| val->uint32_val = val->uint64_val; | |
| } | |
| } | |
| static void _upb_Decoder_Munge(const upb_MiniTableField* field, wireval* val) { | |
| switch (field->UPB_PRIVATE(descriptortype)) { | |
| case kUpb_FieldType_Bool: | |
| val->bool_val = val->uint64_val != 0; | |
| break; | |
| case kUpb_FieldType_SInt32: | |
| val->uint32_val = _upb_Decoder_ZigZagDecode32(val->uint64_val); | |
| break; | |
| case kUpb_FieldType_SInt64: | |
| val->uint64_val = _upb_Decoder_ZigZagDecode64(val->uint64_val); | |
| break; | |
| case kUpb_FieldType_Int32: | |
| case kUpb_FieldType_UInt32: | |
| _upb_Decoder_MungeInt32(val); | |
| break; | |
| case kUpb_FieldType_Enum: | |
| UPB_UNREACHABLE(); | |
| } | |
| } | |
| static upb_Message* _upb_Decoder_NewSubMessage2(upb_Decoder* d, | |
| const upb_MiniTable* subl, | |
| const upb_MiniTableField* field, | |
| upb_Message** target) { | |
| UPB_ASSERT(subl); | |
| upb_Message* msg = _upb_Message_New(subl, &d->arena); | |
| if (!msg) upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); | |
| *target = msg; | |
| return msg; | |
| } | |
| static upb_Message* _upb_Decoder_NewSubMessage(upb_Decoder* d, | |
| const upb_MiniTableField* field, | |
| upb_Message** target) { | |
| const upb_MiniTable* subl = upb_MiniTable_GetSubMessageTable(field); | |
| return _upb_Decoder_NewSubMessage2(d, subl, field, target); | |
| } | |
| static const char* _upb_Decoder_ReadString2(upb_Decoder* d, const char* ptr, | |
| int size, upb_StringView* str, | |
| bool validate_utf8) { | |
| if (!_upb_Decoder_ReadString(d, &ptr, size, str, validate_utf8)) { | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); | |
| } | |
| return ptr; | |
| } | |
| UPB_FORCEINLINE | |
| const char* _upb_Decoder_RecurseSubMessage(upb_Decoder* d, const char* ptr, | |
| upb_Message* submsg, | |
| const upb_MiniTable* subl, | |
| uint32_t expected_end_group) { | |
| if (--d->depth < 0) { | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_MaxDepthExceeded); | |
| } | |
| ptr = _upb_Decoder_DecodeMessage(d, ptr, submsg, subl); | |
| d->depth++; | |
| if (d->end_group != expected_end_group) { | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_Malformed); | |
| } | |
| return ptr; | |
| } | |
| UPB_FORCEINLINE | |
| const char* _upb_Decoder_DecodeSubMessage(upb_Decoder* d, const char* ptr, | |
| upb_Message* submsg, | |
| const upb_MiniTableField* field, | |
| size_t size) { | |
| ptrdiff_t delta = upb_EpsCopyInputStream_PushLimit(&d->input, ptr, size); | |
| const upb_MiniTable* subl = upb_MiniTable_GetSubMessageTable(field); | |
| UPB_ASSERT(subl); | |
| ptr = _upb_Decoder_RecurseSubMessage(d, ptr, submsg, subl, DECODE_NOGROUP); | |
| upb_EpsCopyInputStream_PopLimit(&d->input, ptr, delta); | |
| return ptr; | |
| } | |
| UPB_FORCEINLINE | |
| const char* _upb_Decoder_DecodeGroup(upb_Decoder* d, const char* ptr, | |
| upb_Message* submsg, | |
| const upb_MiniTable* subl, | |
| uint32_t number) { | |
| if (upb_EpsCopyInputStream_IsDone(EPS(d), &ptr)) { | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_Malformed); | |
| } | |
| ptr = _upb_Decoder_RecurseSubMessage(d, ptr, submsg, subl, number); | |
| d->end_group = DECODE_NOGROUP; | |
| return ptr; | |
| } | |
| UPB_FORCEINLINE | |
| const char* _upb_Decoder_DecodeKnownGroup(upb_Decoder* d, const char* ptr, | |
| upb_Message* submsg, | |
| const upb_MiniTableField* field) { | |
| const upb_MiniTable* subl = upb_MiniTable_GetSubMessageTable(field); | |
| UPB_ASSERT(subl); | |
| return _upb_Decoder_DecodeGroup(d, ptr, submsg, subl, | |
| field->UPB_PRIVATE(number)); | |
| } | |
| UPB_FORCEINLINE | |
| const char* _upb_Decoder_DecodeFixedPacked(upb_Decoder* d, const char* ptr, | |
| upb_Array* arr, wireval* val, | |
| const upb_MiniTableField* field, | |
| int lg2) { | |
| upb_StringView sv; | |
| ptr = upb_EpsCopyInputStream_ReadStringEphemeral(&d->input, ptr, val->size, | |
| &sv); | |
| if (!ptr) upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_Malformed); | |
| int mask = (1 << lg2) - 1; | |
| if (UPB_UNLIKELY((val->size & mask) != 0 || ptr == NULL)) { | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_Malformed); | |
| } | |
| size_t count = val->size >> lg2; | |
| if (count == 0) return ptr; | |
| _upb_Decoder_Reserve(d, arr, count); | |
| void* mem = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), | |
| arr->UPB_PRIVATE(size) << lg2, void); | |
| arr->UPB_PRIVATE(size) += count; | |
| if (upb_IsLittleEndian()) { | |
| memcpy(mem, sv.data, sv.size); | |
| } else { | |
| const char* src = sv.data; | |
| const char* src_end = src + sv.size; | |
| char* dst = mem; | |
| if (lg2 == 2) { | |
| for (; src < src_end; src += 4, dst += 4) { | |
| uint32_t x; | |
| memcpy(&x, src, 4); | |
| x = upb_BigEndian32(x); | |
| memcpy(dst, &x, 4); | |
| } | |
| } else { | |
| UPB_ASSERT(lg2 == 3); | |
| for (; src < src_end; src += 8, dst += 8) { | |
| uint64_t x; | |
| memcpy(&x, src, 8); | |
| x = upb_BigEndian64(x); | |
| memcpy(dst, &x, 8); | |
| } | |
| } | |
| } | |
| return ptr; | |
| } | |
| UPB_FORCEINLINE | |
| const char* _upb_Decoder_DecodeVarintPacked(upb_Decoder* d, const char* ptr, | |
| upb_Array* arr, wireval* val, | |
| const upb_MiniTableField* field, | |
| int lg2) { | |
| int scale = 1 << lg2; | |
| ptrdiff_t delta = upb_EpsCopyInputStream_PushLimit(&d->input, ptr, val->size); | |
| char* out = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), | |
| arr->UPB_PRIVATE(size) << lg2, void); | |
| while (!upb_EpsCopyInputStream_IsDone(EPS(d), &ptr)) { | |
| wireval elem; | |
| ptr = upb_WireReader_ReadVarint(ptr, &elem.uint64_val, EPS(d)); | |
| _upb_Decoder_Munge(field, &elem); | |
| if (_upb_Decoder_Reserve(d, arr, 1)) { | |
| out = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), | |
| arr->UPB_PRIVATE(size) << lg2, void); | |
| } | |
| arr->UPB_PRIVATE(size)++; | |
| memcpy(out, &elem, scale); | |
| out += scale; | |
| } | |
| upb_EpsCopyInputStream_PopLimit(&d->input, ptr, delta); | |
| return ptr; | |
| } | |
| UPB_NOINLINE | |
| static const char* _upb_Decoder_DecodeEnumPacked( | |
| upb_Decoder* d, const char* ptr, upb_Message* msg, upb_Array* arr, | |
| const upb_MiniTableField* field, wireval* val) { | |
| const upb_MiniTableEnum* e = upb_MiniTable_GetSubEnumTable(field); | |
| ptrdiff_t delta = upb_EpsCopyInputStream_PushLimit(&d->input, ptr, val->size); | |
| char* out = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), | |
| arr->UPB_PRIVATE(size) * 4, void); | |
| while (!upb_EpsCopyInputStream_IsDone(EPS(d), &ptr)) { | |
| wireval elem; | |
| ptr = upb_WireReader_ReadVarint(ptr, &elem.uint64_val, EPS(d)); | |
| if (!upb_MiniTableEnum_CheckValue(e, elem.uint64_val)) { | |
| upb_Message* unknown_msg = | |
| field->UPB_PRIVATE(mode) & kUpb_LabelFlags_IsExtension | |
| ? d->original_msg | |
| : msg; | |
| if (!_upb_Encoder_AddEnumValueToUnknown(unknown_msg, | |
| field->UPB_PRIVATE(number), | |
| elem.uint64_val, &d->arena)) { | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); | |
| } | |
| continue; | |
| } | |
| _upb_Decoder_MungeInt32(&elem); | |
| if (_upb_Decoder_Reserve(d, arr, 1)) { | |
| out = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), | |
| arr->UPB_PRIVATE(size) * 4, void); | |
| } | |
| arr->UPB_PRIVATE(size)++; | |
| memcpy(out, &elem, 4); | |
| out += 4; | |
| } | |
| upb_EpsCopyInputStream_PopLimit(&d->input, ptr, delta); | |
| return ptr; | |
| } | |
| static upb_Array* _upb_Decoder_CreateArray(upb_Decoder* d, | |
| const upb_MiniTableField* field) { | |
| const upb_FieldType field_type = field->UPB_PRIVATE(descriptortype); | |
| const size_t lg2 = UPB_PRIVATE(_upb_FieldType_SizeLg2)(field_type); | |
| upb_Array* ret = UPB_PRIVATE(_upb_Array_New)( | |
| &d->arena, _UPB_ARRAY_DEFAULT_INITIAL_SIZE, lg2); | |
| if (!ret) upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); | |
| return ret; | |
| } | |
| #if UPB_FASTTABLE | |
| UPB_PRESERVE_NONE | |
| #endif | |
| static const char* _upb_Decoder_DecodeToArray(upb_Decoder* d, const char* ptr, | |
| upb_Message* msg, | |
| const upb_MiniTableField* field, | |
| wireval* val, int op) { | |
| upb_Array** arrp = UPB_PTR_AT(msg, field->UPB_PRIVATE(offset), void); | |
| upb_Array* arr = *arrp; | |
| void* mem; | |
| if (arr) { | |
| _upb_Decoder_Reserve(d, arr, 1); | |
| } else { | |
| arr = _upb_Decoder_CreateArray(d, field); | |
| *arrp = arr; | |
| } | |
| switch (op) { | |
| case kUpb_DecodeOp_Scalar1Byte: | |
| case kUpb_DecodeOp_Scalar4Byte: | |
| case kUpb_DecodeOp_Scalar8Byte: | |
| /* Append scalar value. */ | |
| mem = UPB_PTR_AT(upb_Array_MutableDataPtr(arr), | |
| arr->UPB_PRIVATE(size) << op, void); | |
| arr->UPB_PRIVATE(size)++; | |
| memcpy(mem, val, 1 << op); | |
| return ptr; | |
| case kUpb_DecodeOp_String: { | |
| /* Append string. */ | |
| upb_StringView* str = (upb_StringView*)upb_Array_MutableDataPtr(arr) + | |
| arr->UPB_PRIVATE(size); | |
| ptr = _upb_Decoder_ReadString2(d, ptr, val->size, str, | |
| /*validate_utf8=*/true); | |
| arr->UPB_PRIVATE(size)++; | |
| return ptr; | |
| } | |
| case kUpb_DecodeOp_Bytes: { | |
| /* Append bytes. */ | |
| upb_StringView* str = (upb_StringView*)upb_Array_MutableDataPtr(arr) + | |
| arr->UPB_PRIVATE(size); | |
| ptr = _upb_Decoder_ReadString2(d, ptr, val->size, str, | |
| /*validate_utf8=*/false); | |
| arr->UPB_PRIVATE(size)++; | |
| return ptr; | |
| } | |
| case kUpb_DecodeOp_SubMessage: { | |
| /* Append submessage / group. */ | |
| upb_Message** target = | |
| UPB_PTR_AT(upb_Array_MutableDataPtr(arr), | |
| arr->UPB_PRIVATE(size) * sizeof(void*), upb_Message*); | |
| upb_Message* submsg = _upb_Decoder_NewSubMessage(d, field, target); | |
| arr->UPB_PRIVATE(size)++; | |
| if (UPB_UNLIKELY(field->UPB_PRIVATE(descriptortype) == | |
| kUpb_FieldType_Group)) { | |
| return _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, field); | |
| } else { | |
| return _upb_Decoder_DecodeSubMessage(d, ptr, submsg, field, val->size); | |
| } | |
| } | |
| case OP_FIXPCK_LG2(2): | |
| case OP_FIXPCK_LG2(3): | |
| return _upb_Decoder_DecodeFixedPacked(d, ptr, arr, val, field, | |
| op - OP_FIXPCK_LG2(0)); | |
| case OP_VARPCK_LG2(0): | |
| case OP_VARPCK_LG2(2): | |
| case OP_VARPCK_LG2(3): | |
| return _upb_Decoder_DecodeVarintPacked(d, ptr, arr, val, field, | |
| op - OP_VARPCK_LG2(0)); | |
| case kUpb_DecodeOp_PackedEnum: | |
| return _upb_Decoder_DecodeEnumPacked(d, ptr, msg, arr, field, val); | |
| default: | |
| UPB_UNREACHABLE(); | |
| } | |
| } | |
| upb_Map* _upb_Decoder_CreateMap(upb_Decoder* d, const upb_MiniTable* entry) { | |
| // Maps descriptor type -> upb map size | |
| static const uint8_t kSizeInMap[] = { | |
| [0] = -1, // invalid descriptor type | |
| [kUpb_FieldType_Double] = 8, | |
| [kUpb_FieldType_Float] = 4, | |
| [kUpb_FieldType_Int64] = 8, | |
| [kUpb_FieldType_UInt64] = 8, | |
| [kUpb_FieldType_Int32] = 4, | |
| [kUpb_FieldType_Fixed64] = 8, | |
| [kUpb_FieldType_Fixed32] = 4, | |
| [kUpb_FieldType_Bool] = 1, | |
| [kUpb_FieldType_String] = UPB_MAPTYPE_STRING, | |
| [kUpb_FieldType_Group] = sizeof(void*), | |
| [kUpb_FieldType_Message] = sizeof(void*), | |
| [kUpb_FieldType_Bytes] = UPB_MAPTYPE_STRING, | |
| [kUpb_FieldType_UInt32] = 4, | |
| [kUpb_FieldType_Enum] = 4, | |
| [kUpb_FieldType_SFixed32] = 4, | |
| [kUpb_FieldType_SFixed64] = 8, | |
| [kUpb_FieldType_SInt32] = 4, | |
| [kUpb_FieldType_SInt64] = 8, | |
| }; | |
| const upb_MiniTableField* key_field = &entry->UPB_PRIVATE(fields)[0]; | |
| const upb_MiniTableField* val_field = &entry->UPB_PRIVATE(fields)[1]; | |
| char key_size = kSizeInMap[key_field->UPB_PRIVATE(descriptortype)]; | |
| char val_size = kSizeInMap[val_field->UPB_PRIVATE(descriptortype)]; | |
| UPB_ASSERT(key_field->UPB_PRIVATE(offset) == offsetof(upb_MapEntry, k)); | |
| UPB_ASSERT(val_field->UPB_PRIVATE(offset) == offsetof(upb_MapEntry, v)); | |
| upb_Map* ret = _upb_Map_New(&d->arena, key_size, val_size); | |
| if (!ret) upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); | |
| return ret; | |
| } | |
| #if UPB_FASTTABLE | |
| UPB_PRESERVE_NONE | |
| #endif | |
| static const char* _upb_Decoder_DecodeToMap(upb_Decoder* d, const char* ptr, | |
| upb_Message* msg, | |
| const upb_MiniTableField* field, | |
| wireval* val) { | |
| upb_Map** map_p = UPB_PTR_AT(msg, field->UPB_PRIVATE(offset), upb_Map*); | |
| upb_Map* map = *map_p; | |
| upb_MapEntry ent; | |
| UPB_ASSERT(upb_MiniTableField_Type(field) == kUpb_FieldType_Message); | |
| const upb_MiniTable* entry = upb_MiniTable_GetSubMessageTable(field); | |
| UPB_ASSERT(entry); | |
| UPB_ASSERT(entry->UPB_PRIVATE(field_count) == 2); | |
| UPB_ASSERT(upb_MiniTableField_IsScalar(&entry->UPB_PRIVATE(fields)[0])); | |
| UPB_ASSERT(upb_MiniTableField_IsScalar(&entry->UPB_PRIVATE(fields)[1])); | |
| if (!map) { | |
| map = _upb_Decoder_CreateMap(d, entry); | |
| *map_p = map; | |
| } | |
| // Parse map entry. | |
| memset(&ent, 0, sizeof(ent)); | |
| bool value_is_message = | |
| entry->UPB_PRIVATE(fields)[1].UPB_PRIVATE(descriptortype) == | |
| kUpb_FieldType_Message || | |
| entry->UPB_PRIVATE(fields)[1].UPB_PRIVATE(descriptortype) == | |
| kUpb_FieldType_Group; | |
| const upb_MiniTable* sub_table = | |
| value_is_message | |
| ? upb_MiniTable_GetSubMessageTable(&entry->UPB_PRIVATE(fields)[1]) | |
| : NULL; | |
| upb_Message* sub_msg = NULL; | |
| if (sub_table) { | |
| // Create proactively to handle the case where it doesn't appear. | |
| _upb_Decoder_NewSubMessage(d, &entry->UPB_PRIVATE(fields)[1], &sub_msg); | |
| ent.v.val = upb_value_ptr(sub_msg); | |
| } | |
| ptr = _upb_Decoder_DecodeSubMessage(d, ptr, &ent.message, field, val->size); | |
| if (sub_msg && sub_table->UPB_PRIVATE(required_count)) { | |
| // If the map entry did not contain a value on the wire, `sub_msg` is an | |
| // empty message; we must check if it is missing any required fields. If the | |
| // value was present, this check is redundant but harmless. | |
| _upb_Decoder_CheckRequired(d, ptr, sub_msg, sub_table); | |
| } | |
| if (upb_Message_HasUnknown(&ent.message)) { | |
| if (!_upb_Encoder_AddMapEntryUnknown(msg, field, &ent.message, entry, | |
| &d->arena)) { | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); | |
| } | |
| } else { | |
| if (_upb_Map_Insert(map, &ent.k, map->key_size, &ent.v, map->val_size, | |
| &d->arena) == kUpb_MapInsertStatus_OutOfMemory) { | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); | |
| } | |
| } | |
| return ptr; | |
| } | |
| #if UPB_FASTTABLE | |
| UPB_PRESERVE_NONE | |
| #endif | |
| static const char* _upb_Decoder_DecodeToSubMessage( | |
| upb_Decoder* d, const char* ptr, upb_Message* msg, | |
| const upb_MiniTableField* field, wireval* val, int op) { | |
| void* mem = UPB_PTR_AT(msg, field->UPB_PRIVATE(offset), void); | |
| int type = field->UPB_PRIVATE(descriptortype); | |
| // Set presence if necessary. | |
| if (UPB_PRIVATE(_upb_MiniTableField_HasHasbit)(field)) { | |
| UPB_PRIVATE(_upb_Message_SetHasbit)(msg, field); | |
| } else if (upb_MiniTableField_IsInOneof(field)) { | |
| // Oneof case | |
| uint32_t* oneof_case = UPB_PRIVATE(_upb_Message_OneofCasePtr)(msg, field); | |
| if (op == kUpb_DecodeOp_String || op == kUpb_DecodeOp_Bytes) { | |
| // Read the string before setting the oneof case, so that if the read | |
| // fails the case still points to the previous member, which is intact. | |
| ptr = _upb_Decoder_ReadString2(d, ptr, val->size, mem, | |
| op == kUpb_DecodeOp_String); | |
| *oneof_case = field->UPB_PRIVATE(number); | |
| return ptr; | |
| } | |
| if (op == kUpb_DecodeOp_SubMessage && | |
| *oneof_case != field->UPB_PRIVATE(number)) { | |
| memset(mem, 0, sizeof(void*)); | |
| } | |
| *oneof_case = field->UPB_PRIVATE(number); | |
| } | |
| // Store into message. | |
| switch (op) { | |
| case kUpb_DecodeOp_SubMessage: { | |
| upb_Message** submsgp = mem; | |
| upb_Message* submsg = *submsgp; | |
| if (!submsg) submsg = _upb_Decoder_NewSubMessage(d, field, submsgp); | |
| if (UPB_UNLIKELY(type == kUpb_FieldType_Group)) { | |
| ptr = _upb_Decoder_DecodeKnownGroup(d, ptr, submsg, field); | |
| } else { | |
| ptr = _upb_Decoder_DecodeSubMessage(d, ptr, submsg, field, val->size); | |
| } | |
| break; | |
| } | |
| case kUpb_DecodeOp_String: | |
| return _upb_Decoder_ReadString2(d, ptr, val->size, mem, | |
| /*validate_utf8=*/true); | |
| case kUpb_DecodeOp_Bytes: | |
| return _upb_Decoder_ReadString2(d, ptr, val->size, mem, | |
| /*validate_utf8=*/false); | |
| case kUpb_DecodeOp_Scalar8Byte: | |
| memcpy(mem, val, 8); | |
| break; | |
| case kUpb_DecodeOp_Scalar4Byte: | |
| memcpy(mem, val, 4); | |
| break; | |
| case kUpb_DecodeOp_Scalar1Byte: | |
| memcpy(mem, val, 1); | |
| break; | |
| default: | |
| UPB_UNREACHABLE(); | |
| } | |
| return ptr; | |
| } | |
| enum { | |
| kStartItemTag = ((kUpb_MsgSet_Item << 3) | kUpb_WireType_StartGroup), | |
| kEndItemTag = ((kUpb_MsgSet_Item << 3) | kUpb_WireType_EndGroup), | |
| kTypeIdTag = ((kUpb_MsgSet_TypeId << 3) | kUpb_WireType_Varint), | |
| kMessageTag = ((kUpb_MsgSet_Message << 3) | kUpb_WireType_Delimited), | |
| }; | |
| static void upb_Decoder_AddKnownMessageSetItem( | |
| upb_Decoder* d, upb_Message* msg, const upb_MiniTableExtension* item_mt, | |
| const char* data, uint32_t size) { | |
| upb_Extension* ext = | |
| UPB_PRIVATE(_upb_Message_GetOrCreateExtension)(msg, item_mt, &d->arena); | |
| if (UPB_UNLIKELY(!ext)) { | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); | |
| } | |
| upb_Message* submsg = upb_Extension_GetMutableMessage(ext); | |
| submsg = _upb_Decoder_NewSubMessage2( | |
| d, upb_MiniTableExtension_GetSubMessage(item_mt), | |
| &item_mt->UPB_PRIVATE(field), &submsg); | |
| upb_Extension_SetMessage(ext, submsg); | |
| // upb_Decode_LimitDepth() takes uint32_t, d->depth - 1 can not be negative. | |
| if (d->depth <= 1) { | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_MaxDepthExceeded); | |
| } | |
| upb_DecodeStatus status = upb_Decode( | |
| data, size, submsg, upb_MiniTableExtension_GetSubMessage(item_mt), | |
| d->extreg, upb_Decode_LimitDepth(d->options, d->depth - 1), &d->arena); | |
| if (status != kUpb_DecodeStatus_Ok) { | |
| upb_ErrorHandler_ThrowError(d->err, status); | |
| } | |
| } | |
| static void upb_Decoder_AddUnknownMessageSetItem(upb_Decoder* d, | |
| upb_Message* msg, | |
| uint32_t type_id, | |
| const char* message_data, | |
| uint32_t message_size) { | |
| char buf[6 * kUpb_Encoder_EncodeVarint32MaxSize]; | |
| char* ptr = buf; | |
| ptr = upb_Encoder_EncodeVarint32(kStartItemTag, ptr); | |
| ptr = upb_Encoder_EncodeVarint32(kTypeIdTag, ptr); | |
| ptr = upb_Encoder_EncodeVarint32(type_id, ptr); | |
| ptr = upb_Encoder_EncodeVarint32(kMessageTag, ptr); | |
| ptr = upb_Encoder_EncodeVarint32(message_size, ptr); | |
| char* split = ptr; | |
| ptr = upb_Encoder_EncodeVarint32(kEndItemTag, ptr); | |
| char* end = ptr; | |
| upb_StringView unknown[] = { | |
| {buf, split - buf}, | |
| {message_data, message_size}, | |
| {split, end - split}, | |
| }; | |
| if (!UPB_PRIVATE(_upb_Message_AddUnknownV)(msg, &d->arena, unknown, 3)) { | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); | |
| } | |
| } | |
| static void upb_Decoder_AddMessageSetItem(upb_Decoder* d, upb_Message* msg, | |
| const upb_MiniTable* t, | |
| uint32_t type_id, const char* data, | |
| uint32_t size) { | |
| const upb_MiniTableExtension* item_mt = | |
| upb_ExtensionRegistry_Lookup(d->extreg, t, type_id); | |
| if (item_mt) { | |
| upb_Decoder_AddKnownMessageSetItem(d, msg, item_mt, data, size); | |
| } else { | |
| upb_Decoder_AddUnknownMessageSetItem(d, msg, type_id, data, size); | |
| } | |
| } | |
| static const char* upb_Decoder_DecodeMessageSetItem( | |
| upb_Decoder* d, const char* ptr, upb_Message* msg, | |
| const upb_MiniTable* layout) { | |
| uint32_t type_id = 0; | |
| upb_StringView preserved = {NULL, 0}; | |
| typedef enum { | |
| kUpb_HaveId = 1 << 0, | |
| kUpb_HavePayload = 1 << 1, | |
| } StateMask; | |
| StateMask state_mask = 0; | |
| while (!upb_EpsCopyInputStream_IsDone(EPS(d), &ptr)) { | |
| uint32_t tag; | |
| ptr = upb_WireReader_ReadTag(ptr, &tag, EPS(d)); | |
| switch (tag) { | |
| case kEndItemTag: | |
| return ptr; | |
| case kTypeIdTag: { | |
| uint64_t tmp; | |
| ptr = upb_WireReader_ReadVarint(ptr, &tmp, EPS(d)); | |
| if (state_mask & kUpb_HaveId) break; // Ignore dup. | |
| state_mask |= kUpb_HaveId; | |
| type_id = tmp; | |
| if (state_mask & kUpb_HavePayload) { | |
| upb_Decoder_AddMessageSetItem(d, msg, layout, type_id, preserved.data, | |
| preserved.size); | |
| } | |
| break; | |
| } | |
| case kMessageTag: { | |
| uint32_t size; | |
| upb_StringView sv; | |
| ptr = upb_Decoder_DecodeSize(d, ptr, &size); | |
| ptr = upb_EpsCopyInputStream_ReadStringAlwaysAlias(&d->input, ptr, size, | |
| &sv); | |
| if (!ptr) { | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_Malformed); | |
| } | |
| if (state_mask & kUpb_HavePayload) break; // Ignore dup. | |
| state_mask |= kUpb_HavePayload; | |
| if (state_mask & kUpb_HaveId) { | |
| upb_Decoder_AddMessageSetItem(d, msg, layout, type_id, sv.data, | |
| sv.size); | |
| } else { | |
| // Out of order, we must preserve the payload. | |
| preserved = sv; | |
| } | |
| break; | |
| } | |
| default: | |
| // We do not preserve unexpected fields inside a message set item. | |
| ptr = _upb_WireReader_SkipValue(ptr, tag, d->depth, &d->input); | |
| break; | |
| } | |
| } | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_Malformed); | |
| } | |
| static upb_MiniTableField upb_Decoder_FieldNotFoundField = { | |
| 0, 0, 0, 0, kUpb_FakeFieldType_FieldNotFound, 0}; | |
| UPB_NOINLINE const upb_MiniTableField* _upb_Decoder_FindExtensionField( | |
| upb_Decoder* d, const upb_MiniTable* t, uint32_t field_number, int ext_mode, | |
| uint32_t wire_type) { | |
| // Treat a message set as an extendable message if it is a delimited field. | |
| // This provides compatibility with encoders that are unaware of message | |
| // sets and serialize them as normal extensions. | |
| if (ext_mode == kUpb_ExtMode_Extendable || | |
| (ext_mode == kUpb_ExtMode_IsMessageSet && | |
| wire_type == kUpb_WireType_Delimited)) { | |
| const upb_MiniTableExtension* ext = | |
| upb_ExtensionRegistry_Lookup(d->extreg, t, field_number); | |
| if (ext) return &ext->UPB_PRIVATE(field); | |
| } else if (ext_mode == kUpb_ExtMode_IsMessageSet) { | |
| if (field_number == kUpb_MsgSet_Item) { | |
| static upb_MiniTableField item = { | |
| 0, 0, 0, 0, kUpb_FakeFieldType_MessageSetItem, 0}; | |
| return &item; | |
| } | |
| } | |
| return &upb_Decoder_FieldNotFoundField; | |
| } | |
| static const upb_MiniTableField* _upb_Decoder_FindField(upb_Decoder* d, | |
| const upb_MiniTable* t, | |
| uint32_t field_number, | |
| uint32_t wire_type) { | |
| UPB_ASSERT(t); | |
| const upb_MiniTableField* field = | |
| upb_MiniTable_FindFieldByNumber(t, field_number); | |
| if (field) return field; | |
| if (d->extreg && UPB_PRIVATE(_upb_MiniTable_ExtModeBase)(t)) { | |
| return _upb_Decoder_FindExtensionField( | |
| d, t, field_number, UPB_PRIVATE(_upb_MiniTable_ExtModeBase)(t), | |
| wire_type); | |
| } | |
| return &upb_Decoder_FieldNotFoundField; // Unknown field. | |
| } | |
| static int _upb_Decoder_GetVarintOp(const upb_MiniTableField* field) { | |
| static const int8_t kVarintOps[] = { | |
| [kUpb_FakeFieldType_FieldNotFound] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_Double] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_Float] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_Int64] = kUpb_DecodeOp_Scalar8Byte, | |
| [kUpb_FieldType_UInt64] = kUpb_DecodeOp_Scalar8Byte, | |
| [kUpb_FieldType_Int32] = kUpb_DecodeOp_Scalar4Byte, | |
| [kUpb_FieldType_Fixed64] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_Fixed32] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_Bool] = kUpb_DecodeOp_Scalar1Byte, | |
| [kUpb_FieldType_String] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_Message] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_Bytes] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_UInt32] = kUpb_DecodeOp_Scalar4Byte, | |
| [kUpb_FieldType_Enum] = kUpb_DecodeOp_Scalar4Byte, | |
| [kUpb_FieldType_SFixed32] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_SFixed64] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_SInt32] = kUpb_DecodeOp_Scalar4Byte, | |
| [kUpb_FieldType_SInt64] = kUpb_DecodeOp_Scalar8Byte, | |
| [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_UnknownField, | |
| }; | |
| return kVarintOps[field->UPB_PRIVATE(descriptortype)]; | |
| } | |
| UPB_FORCEINLINE | |
| void _upb_Decoder_CheckUnlinked(upb_Decoder* d, const upb_MiniTable* mt, | |
| const upb_MiniTableField* field, int* op) { | |
| // If sub-message is not linked, treat as unknown. | |
| if (field->UPB_PRIVATE(mode) & kUpb_LabelFlags_IsExtension) return; | |
| const upb_MiniTable* mt_sub = upb_MiniTable_GetSubMessageTable(field); | |
| if (mt_sub != NULL) return; // Normal case, sub-message is linked. | |
| _upb_Decoder_VerifyOneofUnlinked(mt, field); | |
| *op = kUpb_DecodeOp_UnknownField; | |
| } | |
| UPB_FORCEINLINE | |
| void _upb_Decoder_MaybeVerifyUtf8(upb_Decoder* d, | |
| const upb_MiniTableField* field, int* op) { | |
| UPB_ASSUME(field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Bytes); | |
| if (_upb_Decoder_FieldRequiresUtf8Validation(d, field)) { | |
| *op = kUpb_DecodeOp_String; | |
| } | |
| } | |
| static int _upb_Decoder_GetDelimitedOp(upb_Decoder* d, const upb_MiniTable* mt, | |
| const upb_MiniTableField* field) { | |
| enum { kRepeatedBase = 19 }; | |
| static const int8_t kDelimitedOps[] = { | |
| // For non-repeated field type. | |
| [kUpb_FakeFieldType_FieldNotFound] = | |
| kUpb_DecodeOp_UnknownField, // Field not found. | |
| [kUpb_FieldType_Double] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_Float] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_Int64] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_UInt64] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_Int32] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_Fixed64] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_Fixed32] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_Bool] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_String] = kUpb_DecodeOp_String, | |
| [kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_Message] = kUpb_DecodeOp_SubMessage, | |
| [kUpb_FieldType_Bytes] = kUpb_DecodeOp_Bytes, | |
| [kUpb_FieldType_UInt32] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_Enum] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_SFixed32] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_SFixed64] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_SInt32] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FieldType_SInt64] = kUpb_DecodeOp_UnknownField, | |
| [kUpb_FakeFieldType_MessageSetItem] = kUpb_DecodeOp_SubMessage, | |
| // For repeated field type. | |
| [kRepeatedBase + kUpb_FieldType_Double] = OP_FIXPCK_LG2(3), | |
| [kRepeatedBase + kUpb_FieldType_Float] = OP_FIXPCK_LG2(2), | |
| [kRepeatedBase + kUpb_FieldType_Int64] = OP_VARPCK_LG2(3), | |
| [kRepeatedBase + kUpb_FieldType_UInt64] = OP_VARPCK_LG2(3), | |
| [kRepeatedBase + kUpb_FieldType_Int32] = OP_VARPCK_LG2(2), | |
| [kRepeatedBase + kUpb_FieldType_Fixed64] = OP_FIXPCK_LG2(3), | |
| [kRepeatedBase + kUpb_FieldType_Fixed32] = OP_FIXPCK_LG2(2), | |
| [kRepeatedBase + kUpb_FieldType_Bool] = OP_VARPCK_LG2(0), | |
| [kRepeatedBase + kUpb_FieldType_String] = kUpb_DecodeOp_String, | |
| [kRepeatedBase + kUpb_FieldType_Group] = kUpb_DecodeOp_UnknownField, | |
| [kRepeatedBase + kUpb_FieldType_Message] = kUpb_DecodeOp_SubMessage, | |
| [kRepeatedBase + kUpb_FieldType_Bytes] = kUpb_DecodeOp_Bytes, | |
| [kRepeatedBase + kUpb_FieldType_UInt32] = OP_VARPCK_LG2(2), | |
| [kRepeatedBase + kUpb_FieldType_Enum] = kUpb_DecodeOp_PackedEnum, | |
| [kRepeatedBase + kUpb_FieldType_SFixed32] = OP_FIXPCK_LG2(2), | |
| [kRepeatedBase + kUpb_FieldType_SFixed64] = OP_FIXPCK_LG2(3), | |
| [kRepeatedBase + kUpb_FieldType_SInt32] = OP_VARPCK_LG2(2), | |
| [kRepeatedBase + kUpb_FieldType_SInt64] = OP_VARPCK_LG2(3), | |
| // Omitting kUpb_FakeFieldType_MessageSetItem, because we never emit a | |
| // repeated msgset type | |
| }; | |
| int ndx = field->UPB_PRIVATE(descriptortype); | |
| if (upb_MiniTableField_IsArray(field)) ndx += kRepeatedBase; | |
| int op = kDelimitedOps[ndx]; | |
| if (op == kUpb_DecodeOp_SubMessage) { | |
| _upb_Decoder_CheckUnlinked(d, mt, field, &op); | |
| } else if (op == kUpb_DecodeOp_Bytes) { | |
| _upb_Decoder_MaybeVerifyUtf8(d, field, &op); | |
| } | |
| return op; | |
| } | |
| UPB_FORCEINLINE | |
| const char* _upb_Decoder_DecodeWireValue(upb_Decoder* d, const char* ptr, | |
| const upb_MiniTable* mt, | |
| const upb_MiniTableField* field, | |
| uint32_t wire_type, wireval* val, | |
| int* op) { | |
| static const unsigned kFixed32OkMask = (1 << kUpb_FieldType_Float) | | |
| (1 << kUpb_FieldType_Fixed32) | | |
| (1 << kUpb_FieldType_SFixed32); | |
| static const unsigned kFixed64OkMask = (1 << kUpb_FieldType_Double) | | |
| (1 << kUpb_FieldType_Fixed64) | | |
| (1 << kUpb_FieldType_SFixed64); | |
| switch (wire_type) { | |
| case kUpb_WireType_Varint: | |
| ptr = upb_WireReader_ReadVarint(ptr, &val->uint64_val, EPS(d)); | |
| if (upb_MiniTableField_IsClosedEnum(field)) { | |
| const upb_MiniTableEnum* e = upb_MiniTable_GetSubEnumTable(field); | |
| if (!upb_MiniTableEnum_CheckValue(e, val->uint64_val)) { | |
| *op = kUpb_DecodeOp_UnknownField; | |
| return ptr; | |
| } | |
| _upb_Decoder_MungeInt32(val); | |
| } else { | |
| _upb_Decoder_Munge(field, val); | |
| } | |
| *op = _upb_Decoder_GetVarintOp(field); | |
| return ptr; | |
| case kUpb_WireType_32Bit: | |
| *op = kUpb_DecodeOp_Scalar4Byte; | |
| if (((1 << field->UPB_PRIVATE(descriptortype)) & kFixed32OkMask) == 0) { | |
| *op = kUpb_DecodeOp_UnknownField; | |
| } | |
| return upb_WireReader_ReadFixed32(ptr, &val->uint32_val, &d->input); | |
| case kUpb_WireType_64Bit: | |
| *op = kUpb_DecodeOp_Scalar8Byte; | |
| if (((1 << field->UPB_PRIVATE(descriptortype)) & kFixed64OkMask) == 0) { | |
| *op = kUpb_DecodeOp_UnknownField; | |
| } | |
| return upb_WireReader_ReadFixed64(ptr, &val->uint64_val, &d->input); | |
| case kUpb_WireType_Delimited: | |
| ptr = upb_Decoder_DecodeSize(d, ptr, &val->size); | |
| *op = _upb_Decoder_GetDelimitedOp(d, mt, field); | |
| return ptr; | |
| case kUpb_WireType_StartGroup: | |
| val->uint32_val = field->UPB_PRIVATE(number); | |
| if (field->UPB_PRIVATE(descriptortype) == kUpb_FieldType_Group) { | |
| *op = kUpb_DecodeOp_SubMessage; | |
| _upb_Decoder_CheckUnlinked(d, mt, field, op); | |
| } else if (field->UPB_PRIVATE(descriptortype) == | |
| kUpb_FakeFieldType_MessageSetItem) { | |
| *op = kUpb_DecodeOp_MessageSetItem; | |
| } else { | |
| *op = kUpb_DecodeOp_UnknownField; | |
| } | |
| return ptr; | |
| default: | |
| break; | |
| } | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_Malformed); | |
| } | |
| UPB_FORCEINLINE | |
| const char* _upb_Decoder_DecodeKnownField(upb_Decoder* d, const char* ptr, | |
| upb_Message* msg, | |
| const upb_MiniTableField* field, | |
| int op, wireval* val) { | |
| uint8_t mode = field->UPB_PRIVATE(mode); | |
| if (UPB_UNLIKELY(mode & kUpb_LabelFlags_IsExtension)) { | |
| const upb_MiniTableExtension* ext_layout = | |
| (const upb_MiniTableExtension*)field; | |
| upb_Extension* ext = UPB_PRIVATE(_upb_Message_GetOrCreateExtension)( | |
| msg, ext_layout, &d->arena); | |
| if (UPB_UNLIKELY(!ext)) { | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); | |
| } | |
| d->original_msg = msg; | |
| msg = UPB_PTR_AT(ext, UPB_ONLYBITS(kUpb_Extension_DataOffset), upb_Message); | |
| } | |
| switch (mode & kUpb_FieldMode_Mask) { | |
| case kUpb_FieldMode_Array: | |
| return _upb_Decoder_DecodeToArray(d, ptr, msg, field, val, op); | |
| case kUpb_FieldMode_Map: | |
| return _upb_Decoder_DecodeToMap(d, ptr, msg, field, val); | |
| case kUpb_FieldMode_Scalar: | |
| return _upb_Decoder_DecodeToSubMessage(d, ptr, msg, field, val, op); | |
| default: | |
| UPB_UNREACHABLE(); | |
| } | |
| } | |
| UPB_FORCEINLINE | |
| bool _upb_Decoder_CanSkipUnknownField(upb_Decoder* d, uint32_t next_field_num, | |
| uint32_t next_wire_type, | |
| const upb_MiniTable* mt, uint32_t* gap_lo, | |
| uint32_t* gap_hi, bool is_extendable) { | |
| if (next_wire_type == kUpb_WireType_EndGroup) { | |
| return false; | |
| } | |
| if (UPB_UNLIKELY(upb_MiniTable_IsMessageSet(mt))) { | |
| if (next_field_num == kUpb_MsgSet_Item) { | |
| return false; | |
| } | |
| } | |
| if (next_field_num <= *gap_lo || next_field_num >= *gap_hi) { | |
| if (UPB_LIKELY(next_field_num == *gap_hi)) { | |
| // Common case of fields in ascending order encountering a known | |
| // field | |
| return false; | |
| } | |
| if (UPB_UNLIKELY(next_field_num == 0)) { | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_Malformed); | |
| } | |
| if (next_field_num == *gap_lo) { | |
| return false; | |
| } | |
| if (!UPB_PRIVATE(_upb_MiniTable_FindUnknownGap)(mt, next_field_num, gap_lo, | |
| gap_hi)) { | |
| return false; | |
| } | |
| } | |
| if (is_extendable) { | |
| if (upb_ExtensionRegistry_Lookup(d->extreg, mt, next_field_num)) { | |
| return false; | |
| } | |
| } | |
| return true; | |
| } | |
| UPB_NOINLINE | |
| static const char* _upb_Decoder_DecodeUnknowns( | |
| upb_Decoder* d, const char* ptr, upb_Message* msg, const upb_MiniTable* mt, | |
| uint32_t field_number, uint32_t wire_type, wireval val, const char* start) { | |
| if (field_number == 0) { | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_Malformed); | |
| } | |
| upb_EpsCopyCapture capture; | |
| upb_EpsCopyCapture_Start(&capture, &d->input, start); | |
| // We have already parsed the tag and "value" (or size) of the first unknown | |
| // field. ptr is currently: | |
| // - after value for Varint, 32Bit, 64Bit. | |
| // - after size for Delimited. | |
| // - after tag for StartGroup. | |
| // We need to finish skipping the first field. | |
| if (wire_type == kUpb_WireType_Delimited) { | |
| upb_StringView sv; | |
| ptr = upb_EpsCopyInputStream_ReadStringEphemeral(&d->input, ptr, val.size, | |
| &sv); | |
| } else if (wire_type == kUpb_WireType_StartGroup) { | |
| ptr = UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, field_number << 3, | |
| d->depth, &d->input); | |
| } | |
| // Fast check if next fields are also unknown, based on the gap between known | |
| // fields our first unknown falls between. | |
| uint32_t gap_lo = 0; | |
| uint32_t gap_hi = 0; | |
| bool has_gap = UPB_PRIVATE(_upb_MiniTable_FindUnknownGap)(mt, field_number, | |
| &gap_lo, &gap_hi); | |
| if (has_gap) { | |
| bool is_extendable = | |
| (UPB_UNLIKELY(UPB_PRIVATE(_upb_MiniTable_IsExtendable)(mt)) || | |
| UPB_UNLIKELY(upb_MiniTable_IsMessageSet(mt))) && | |
| d->extreg; | |
| while (!upb_EpsCopyInputStream_IsDone(EPS(d), &ptr)) { | |
| const char* start_ptr = ptr; | |
| uint32_t tag; | |
| ptr = upb_WireReader_ReadTag(ptr, &tag, EPS(d)); | |
| uint32_t next_field_num = tag >> 3; | |
| uint32_t next_wire_type = tag & 7; | |
| if (_upb_Decoder_CanSkipUnknownField(d, next_field_num, next_wire_type, | |
| mt, &gap_lo, &gap_hi, | |
| is_extendable)) { | |
| ptr = _upb_WireReader_SkipValueForceInline(ptr, tag, d->depth, EPS(d)); | |
| } else { | |
| ptr = start_ptr; | |
| break; | |
| } | |
| } | |
| } | |
| upb_StringView sv; | |
| upb_EpsCopyCapture_End(&capture, &d->input, ptr, &sv); | |
| if (UPB_LIKELY(sv.size > 0)) { | |
| if (!UPB_PRIVATE(_upb_Message_AddUnknown)( | |
| msg, sv.data, sv.size, &d->arena, | |
| _upb_Decoder_GetAddUnknownMode(d, sv.data))) { | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); | |
| } | |
| } | |
| return ptr; | |
| } | |
| UPB_FORCEINLINE | |
| const char* _upb_Decoder_DecodeFieldTag(upb_Decoder* d, const char* ptr, | |
| uint32_t* field_number, | |
| uint32_t* wire_type) { | |
| uint32_t tag; | |
| UPB_ASSERT(ptr < d->input.limit_ptr); | |
| ptr = upb_WireReader_ReadTag(ptr, &tag, EPS(d)); | |
| *field_number = tag >> 3; | |
| *wire_type = tag & 7; | |
| return ptr; | |
| } | |
| UPB_FORCEINLINE | |
| const char* _upb_Decoder_DecodeFieldData( | |
| upb_Decoder* d, const char* ptr, upb_Message* msg, const upb_MiniTable* mt, | |
| uint32_t field_number, uint32_t wire_type, const char* start) { | |
| int op; | |
| wireval val; | |
| const upb_MiniTableField* field = | |
| _upb_Decoder_FindField(d, mt, field_number, wire_type); | |
| ptr = _upb_Decoder_DecodeWireValue(d, ptr, mt, field, wire_type, &val, &op); | |
| if (op >= 0) { | |
| return _upb_Decoder_DecodeKnownField(d, ptr, msg, field, op, &val); | |
| } else { | |
| switch (op) { | |
| case kUpb_DecodeOp_UnknownField: | |
| return _upb_Decoder_DecodeUnknowns(d, ptr, msg, mt, field_number, | |
| wire_type, val, start); | |
| case kUpb_DecodeOp_MessageSetItem: | |
| return upb_Decoder_DecodeMessageSetItem(d, ptr, msg, mt); | |
| default: | |
| UPB_UNREACHABLE(); | |
| } | |
| } | |
| } | |
| static const char* _upb_Decoder_EndMessage(upb_Decoder* d, const char* ptr) { | |
| d->message_is_done = true; | |
| return ptr; | |
| } | |
| UPB_FORCEINLINE | |
| const char* _upb_Decoder_DecodeFieldNoFast(upb_Decoder* d, const char* ptr, | |
| upb_Message* msg, | |
| const upb_MiniTable* mt) { | |
| uint32_t field_number; | |
| uint32_t wire_type; | |
| const char* start = ptr; | |
| ptr = _upb_Decoder_DecodeFieldTag(d, ptr, &field_number, &wire_type); | |
| if (wire_type == kUpb_WireType_EndGroup) { | |
| d->end_group = field_number; | |
| return _upb_Decoder_EndMessage(d, ptr); | |
| } | |
| ptr = _upb_Decoder_DecodeFieldData(d, ptr, msg, mt, field_number, wire_type, | |
| start); | |
| _upb_Decoder_Trace(d, 'M'); | |
| return ptr; | |
| } | |
| UPB_FORCEINLINE | |
| bool _upb_Decoder_TryDecodeMessageFast(upb_Decoder* d, const char** ptr, | |
| upb_Message* msg, | |
| const upb_MiniTable* mt, | |
| uint64_t last_field_index, | |
| uint64_t data) { | |
| #if UPB_FASTTABLE | |
| if (mt->UPB_PRIVATE(table_mask) == (unsigned char)-1 || | |
| (d->options & kUpb_DecodeOption_DisableFastTable)) { | |
| // Fast table is unavailable or disabled. | |
| return false; | |
| } | |
| uint64_t data2 = upb_DecodeFastData2_PackMask(mt->UPB_PRIVATE(table_mask)); | |
| const char* start = | |
| UPB_PRIVATE(upb_EpsCopyInputStream_GetInputPtr)(&d->input, *ptr); | |
| char* trace_next = _upb_Decoder_TraceNext(d); | |
| upb_FastDecoder_Return ret = | |
| upb_DecodeFast_Dispatch(d, *ptr, msg, mt, 0, 0, data2); | |
| *ptr = ret.ptr; | |
| if (d->message_is_done) { | |
| // The entire message was successfully parsed fast. | |
| return true; | |
| } | |
| // *ptr now points to the beginning of a field that could not be parsed fast. | |
| // It's possible that some fields were parsed fast, in which case *ptr will | |
| // have been updated. However, it's also possible that the very first field | |
| // encountered could not be parsed fast, in which case *ptr will be unchanged. | |
| // | |
| // If the fast decoder consumed any data, it must have emitted at least | |
| // one 'F' event into the trace buffer (in addition to the 'D' event | |
| // that is always emitted). | |
| const char* end = | |
| UPB_PRIVATE(upb_EpsCopyInputStream_GetInputPtr)(&d->input, *ptr); | |
| char* trace_end = _upb_Decoder_TracePtr(d); | |
| UPB_ASSERT(trace_end == NULL || trace_end != trace_next || end == start); | |
| _upb_Decoder_Trace(d, '<'); | |
| #endif | |
| return false; | |
| } | |
| UPB_FORCEINLINE | |
| const char* _upb_Decoder_DecodeField(upb_Decoder* d, const char* ptr, | |
| upb_Message* msg, const upb_MiniTable* mt, | |
| uint64_t last_field_index, uint64_t data) { | |
| if (_upb_Decoder_TryDecodeMessageFast(d, &ptr, msg, mt, last_field_index, | |
| data)) { | |
| return ptr; | |
| } else if (upb_EpsCopyInputStream_IsDone(EPS(d), &ptr)) { | |
| return _upb_Decoder_EndMessage(d, ptr); | |
| } | |
| return _upb_Decoder_DecodeFieldNoFast(d, ptr, msg, mt); | |
| } | |
| UPB_NOINLINE | |
| static const char* _upb_Decoder_DecodeEmptyMessage(upb_Decoder* d, | |
| const char* ptr, | |
| upb_Message* msg) { | |
| if (upb_EpsCopyInputStream_IsDone(EPS(d), &ptr)) { | |
| return ptr; | |
| } | |
| const char* start = ptr; | |
| const char* capture_end = ptr; | |
| upb_EpsCopyCapture capture; | |
| upb_EpsCopyCapture_Start(&capture, &d->input, start); | |
| while (!upb_EpsCopyInputStream_IsDone(EPS(d), &ptr)) { | |
| uint32_t tag; | |
| capture_end = ptr; | |
| ptr = upb_WireReader_ReadTag(ptr, &tag, EPS(d)); | |
| if ((tag & 7) == kUpb_WireType_EndGroup) { | |
| d->end_group = tag >> 3; | |
| break; | |
| } | |
| ptr = _upb_WireReader_SkipValueForceInline(ptr, tag, d->depth, EPS(d)); | |
| capture_end = ptr; | |
| } | |
| upb_StringView sv; | |
| upb_EpsCopyCapture_End(&capture, EPS(d), capture_end, &sv); | |
| if (sv.size > 0) { | |
| if (!UPB_PRIVATE(_upb_Message_AddUnknown)( | |
| msg, sv.data, sv.size, &d->arena, | |
| _upb_Decoder_GetAddUnknownMode(d, sv.data))) { | |
| upb_ErrorHandler_ThrowError(d->err, kUpb_DecodeStatus_OutOfMemory); | |
| } | |
| } | |
| return ptr; | |
| } | |
| // When fasttable is enabled, _upb_Decoder_DecodeMessage possibly calls a | |
| // preserve_none function, which forces a spill of all callee-save registers | |
| // registers to the stack in its prologue and restoration in its epilogue, due | |
| // to mismatched calling conventions - the fast decoder (preserve_none) calls | |
| // _upb_Decoder_DecodeMessage (normal) which calls the fast decoder | |
| // (preserve_none). Arm has a lot of callee-save registers in its normal calling | |
| // convention, including a bunch of simd&fp registers that our preserve_none | |
| // caller is probably not actually using. To avoid this cost, all functions in | |
| // the call stack (excluding force-inlined) between the fast decoder's decode | |
| // message function and a recursive call to the fast decoder should use the fast | |
| // decoder's calling convention. | |
| #if UPB_FASTTABLE | |
| UPB_PRESERVE_NONE | |
| #endif | |
| UPB_NOINLINE | |
| const char* _upb_Decoder_DecodeMessage(upb_Decoder* d, const char* ptr, | |
| upb_Message* msg, | |
| const upb_MiniTable* mt) { | |
| UPB_ASSERT(mt); | |
| UPB_ASSERT(d->message_is_done == false); | |
| if (UPB_UNLIKELY(upb_MiniTable_FieldCount(mt) == 0 && | |
| UPB_PRIVATE(_upb_MiniTable_ExtModeBase)(mt) == | |
| kUpb_ExtMode_NonExtendable)) { | |
| return _upb_Decoder_DecodeEmptyMessage(d, ptr, msg); | |
| } | |
| do { | |
| ptr = _upb_Decoder_DecodeField(d, ptr, msg, mt, 0, 0); | |
| } while (!d->message_is_done); | |
| d->message_is_done = false; | |
| return UPB_UNLIKELY(mt && mt->UPB_PRIVATE(required_count)) | |
| ? _upb_Decoder_CheckRequired(d, ptr, msg, mt) | |
| : ptr; | |
| } | |
| static upb_DecodeStatus _upb_Decoder_DecodeTop(struct upb_Decoder* d, | |
| const char* buf, | |
| upb_Message* msg, | |
| const upb_MiniTable* m) { | |
| _upb_Decoder_DecodeMessage(d, buf, msg, m); | |
| if (d->end_group != DECODE_NOGROUP) return kUpb_DecodeStatus_Malformed; | |
| if (d->missing_required) return kUpb_DecodeStatus_MissingRequired; | |
| return kUpb_DecodeStatus_Ok; | |
| } | |
| static upb_DecodeStatus upb_Decoder_Decode(upb_Decoder* const decoder, | |
| const char* const buf, | |
| upb_Message* const msg, | |
| const upb_MiniTable* const m, | |
| upb_Arena* const arena) { | |
| if (UPB_SETJMP(decoder->err->buf) == 0) { | |
| decoder->err->code = _upb_Decoder_DecodeTop(decoder, buf, msg, m); | |
| } else { | |
| UPB_ASSERT(decoder->err->code != kUpb_DecodeStatus_Ok); | |
| } | |
| return upb_Decoder_Destroy(decoder, arena); | |
| } | |
| static uint16_t upb_DecodeOptions_GetMaxDepth(uint32_t options) { | |
| return options >> 16; | |
| } | |
| uint16_t upb_DecodeOptions_GetEffectiveMaxDepth(uint32_t options) { | |
| uint16_t max_depth = upb_DecodeOptions_GetMaxDepth(options); | |
| return max_depth ? max_depth : kUpb_WireFormat_DefaultDepthLimit; | |
| } | |
| upb_DecodeStatus upb_Decode(const char* buf, size_t size, upb_Message* msg, | |
| const upb_MiniTable* mt, | |
| const upb_ExtensionRegistry* extreg, int options, | |
| upb_Arena* arena) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| upb_Decoder decoder; | |
| upb_ErrorHandler err; | |
| upb_ErrorHandler_Init(&err); | |
| buf = upb_Decoder_Init(&decoder, buf, size, extreg, options, arena, &err, | |
| NULL, 0); | |
| return upb_Decoder_Decode(&decoder, buf, msg, mt, arena); | |
| } | |
| upb_DecodeStatus upb_DecodeWithTrace(const char* buf, size_t size, | |
| upb_Message* msg, const upb_MiniTable* mt, | |
| const upb_ExtensionRegistry* extreg, | |
| int options, upb_Arena* arena, | |
| char* trace_buf, size_t trace_size) { | |
| UPB_ASSERT(!upb_Message_IsFrozen(msg)); | |
| upb_Decoder decoder; | |
| upb_ErrorHandler err; | |
| upb_ErrorHandler_Init(&err); | |
| buf = upb_Decoder_Init(&decoder, buf, size, extreg, options, arena, &err, | |
| trace_buf, trace_size); | |
| return upb_Decoder_Decode(&decoder, buf, msg, mt, arena); | |
| } | |
| upb_DecodeStatus upb_DecodeLengthPrefixed(const char* buf, size_t size, | |
| upb_Message* msg, | |
| size_t* num_bytes_read, | |
| const upb_MiniTable* mt, | |
| const upb_ExtensionRegistry* extreg, | |
| int options, upb_Arena* arena) { | |
| // To avoid needing to make a Decoder just to decode the initial length, | |
| // hand-decode the leading varint for the message length here. | |
| uint64_t msg_len = 0; | |
| for (size_t i = 0;; ++i) { | |
| if (i >= size || i > 9) { | |
| return kUpb_DecodeStatus_Malformed; | |
| } | |
| uint64_t b = *buf; | |
| buf++; | |
| msg_len += (b & 0x7f) << (i * 7); | |
| if ((b & 0x80) == 0) { | |
| *num_bytes_read = i + 1 + msg_len; | |
| break; | |
| } | |
| } | |
| // If the total number of bytes we would read (= the bytes from the varint | |
| // plus however many bytes that varint says we should read) is larger then the | |
| // input buffer then error as malformed. | |
| if (*num_bytes_read > size) { | |
| return kUpb_DecodeStatus_Malformed; | |
| } | |
| if (msg_len > INT32_MAX) { | |
| return kUpb_DecodeStatus_Malformed; | |
| } | |
| return upb_Decode(buf, msg_len, msg, mt, extreg, options, arena); | |
| } | |
| const char* upb_DecodeStatus_String(upb_DecodeStatus status) { | |
| switch (status) { | |
| case kUpb_DecodeStatus_Ok: | |
| return "Ok"; | |
| case kUpb_DecodeStatus_Malformed: | |
| return "Wire format was corrupt"; | |
| case kUpb_DecodeStatus_OutOfMemory: | |
| return "Arena alloc failed"; | |
| case kUpb_DecodeStatus_BadUtf8: | |
| return "String field had bad UTF-8"; | |
| case kUpb_DecodeStatus_MaxDepthExceeded: | |
| return "Exceeded upb_DecodeOptions_MaxDepth"; | |
| case kUpb_DecodeStatus_MissingRequired: | |
| return "Missing required field"; | |
| default: | |
| return "Unknown decode status"; | |
| } | |
| } | |
| #undef OP_FIXPCK_LG2 | |
| #undef OP_VARPCK_LG2 | |
| // We encode backwards, to avoid pre-computing lengths (one-pass encode). | |
| #include <stdbool.h> | |
| #include <stdint.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| // Must be last. | |
| upb_EncodeStatus upb_Encode(const upb_Message* msg, const upb_MiniTable* l, | |
| int options, upb_Arena* arena, char** buf, | |
| size_t* size) { | |
| return _upb_Encode(msg, l, options, arena, buf, size, false); | |
| } | |
| upb_EncodeStatus upb_EncodeLengthPrefixed(const upb_Message* msg, | |
| const upb_MiniTable* l, int options, | |
| upb_Arena* arena, char** buf, | |
| size_t* size) { | |
| return _upb_Encode(msg, l, options, arena, buf, size, true); | |
| } | |
| const char* upb_EncodeStatus_String(upb_EncodeStatus status) { | |
| switch (status) { | |
| case kUpb_EncodeStatus_Ok: | |
| return "Ok"; | |
| case kUpb_EncodeStatus_MissingRequired: | |
| return "Missing required field"; | |
| case kUpb_EncodeStatus_MaxDepthExceeded: | |
| return "Max depth exceeded"; | |
| case kUpb_EncodeStatus_OutOfMemory: | |
| return "Arena alloc failed"; | |
| default: | |
| return "Unknown encode status"; | |
| } | |
| } | |
| #include <setjmp.h> | |
| #include <stddef.h> | |
| // Must be last. | |
| static upb_EncodeStatus upb_DoEncodeExtension(upb_encstate* encoder, char* ptr, | |
| const struct upb_Extension* ext, | |
| bool is_message_set, | |
| upb_StringView* view, | |
| int encode_options) { | |
| if (UPB_SETJMP(*encoder->err) == 0) { | |
| char* buf = ptr; | |
| size_t size = 0; | |
| UPB_PRIVATE(_upb_Encode_Extension)( | |
| encoder, upb_Extension_MiniTableExtension(ext), | |
| upb_Extension_GetValue(ext), is_message_set, &buf, &size, | |
| encode_options); | |
| view->data = buf; | |
| view->size = size; | |
| } else { | |
| UPB_ASSERT(encoder->status != kUpb_EncodeStatus_Ok); | |
| upb_BackAlloc_Abort(&encoder->alloc); | |
| view->data = NULL; | |
| view->size = 0; | |
| } | |
| UPB_PRIVATE(_upb_encstate_destroy)(encoder); | |
| return encoder->status; | |
| } | |
| upb_EncodeStatus upb_EncodeExtension(const struct upb_Extension* ext, | |
| struct upb_Arena* arena, | |
| upb_StringView* view, int encode_options) { | |
| const upb_MiniTable* extendee = | |
| upb_MiniTableExtension_Extendee(upb_Extension_MiniTableExtension(ext)); | |
| bool is_message_set = | |
| extendee != NULL && upb_MiniTable_IsMessageSet(extendee); | |
| upb_encstate e; | |
| jmp_buf err; | |
| char* ptr = UPB_PRIVATE(_upb_encstate_init)(&e, &err, arena); | |
| return upb_DoEncodeExtension(&e, ptr, ext, is_message_set, view, | |
| encode_options); | |
| } | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| char upb_BackAlloc_sentinel; | |
| static size_t upb_BackAlloc_CalcBlockSize(upb_BackAlloc* a, size_t required, | |
| bool* one_off) { | |
| #if UPB_HWASAN | |
| required = UPB_ALIGN_UP(required, UPB_MALLOC_ALIGN); | |
| #endif | |
| size_t organic_block_size = | |
| UPB_PRIVATE(_upb_Arena_NextBlockSize)(a->arena, required, one_off); | |
| // We want to offer amortized linear time, which means we must grow block | |
| // sizes exponentially. However, merely allocating a power of 2 is | |
| // pathological for allocators that use a header with mmap for large | |
| // contiguous allocations. Instead, we want to allocate based on a power of | |
| // 2, but request slightly less to leave room for backing allocator | |
| // metadata. If we had universal size feedback this would not be necessary. | |
| size_t scaled_block_size = upb_RoundUpToPowerOfTwo(required); | |
| // Estimated value such that 128 bytes of possible overhead is not | |
| // significant. 128 bytes should be enough for whatever metadata is needed. | |
| if (scaled_block_size >= 4096 * 4) { | |
| scaled_block_size = upb_RoundUpToPowerOfTwo(required + 128) - 128; | |
| } | |
| // Scaled block size calculations could overflow, but that's OK as it's | |
| // unsigned and won't be used if it's less than the organic block size | |
| if (scaled_block_size > organic_block_size) { | |
| return UPB_PRIVATE(_upb_Arena_NextBlockSize)(a->arena, scaled_block_size, | |
| one_off); | |
| } | |
| return organic_block_size; | |
| } | |
| static char* upb_BackAlloc_Realloc(upb_BackAlloc* a, char* ptr, size_t n) { | |
| size_t copy = a->limit - ptr; | |
| size_t required_block_size; | |
| if (upb_AddOverflow(copy, n, &required_block_size)) { | |
| return NULL; | |
| } | |
| bool one_off = false; | |
| size_t size = upb_BackAlloc_CalcBlockSize(a, required_block_size, &one_off); | |
| char* block = UPB_PRIVATE(_upb_Arena_AllocBlock)(a->arena, &size); | |
| if (!block) { | |
| return NULL; | |
| } | |
| UPB_PRIVATE(_upb_Arena_UpdateGrowthState)(a->arena, required_block_size, size, | |
| one_off); | |
| char* dst = block + size - copy; | |
| memcpy(dst, ptr, copy); | |
| if (a->limit != a->buf) { | |
| // Dispose of the old block. | |
| if (a->standalone) { | |
| // Note: while it would technically be possible to give this block to the | |
| // arena to use for allocations, this could lead to a lot of garbage | |
| // blocks that never get used. | |
| UPB_PRIVATE(_upb_Arena_FreeBlock)(a->arena, a->buf); | |
| } else { | |
| UPB_PRIVATE(_upb_Arena_UseBlock)(a->arena, a->buf, a->limit - a->buf); | |
| } | |
| } | |
| a->buf = block; | |
| a->limit = block + size; | |
| a->standalone = true; | |
| return dst - n; | |
| } | |
| char* upb_BackAlloc_Grow(upb_BackAlloc* a, char* ptr, size_t n) { | |
| if (!upb_AllocationCount_IncrementAndCheck()) { | |
| return NULL; | |
| } | |
| if (a->limit == a->buf) { | |
| // First allocation: try to steal a block. | |
| size_t size = n; | |
| char* block = UPB_PRIVATE(_upb_Arena_Steal)(a->arena, &size); | |
| if (block) { | |
| UPB_ASSERT(size >= n); | |
| UPB_ASSERT(a->standalone == false); | |
| a->buf = block; | |
| a->limit = block + size; | |
| return a->limit - n; | |
| } | |
| } | |
| return upb_BackAlloc_Realloc(a, ptr, n); | |
| } | |
| // Must be last. | |
| UPB_NOINLINE | |
| const char* _upb_Decoder_CheckRequired(upb_Decoder* d, const char* ptr, | |
| const upb_Message* msg, | |
| const upb_MiniTable* m) { | |
| UPB_ASSERT(m->UPB_PRIVATE(required_count)); | |
| if (UPB_UNLIKELY(d->options & kUpb_DecodeOption_CheckRequired)) { | |
| d->missing_required = | |
| d->missing_required || | |
| !UPB_PRIVATE(_upb_Message_IsInitializedShallow)(msg, m); | |
| } | |
| return ptr; | |
| } | |
| // We encode backwards, to avoid pre-computing lengths (one-pass encode). | |
| #include <setjmp.h> | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| UPB_NOINLINE bool _upb_Encoder_AddMapEntryUnknown( | |
| upb_Message* msg, const upb_MiniTableField* field, upb_Message* ent_msg, | |
| const upb_MiniTable* entry, upb_Arena* arena) { | |
| char* buf; | |
| size_t size; | |
| upb_EncodeStatus status = | |
| _upb_Encode(ent_msg, entry, 0, arena, &buf, &size, false); | |
| if (status != kUpb_EncodeStatus_Ok) { | |
| return false; | |
| } | |
| char delim_buf[2 * kUpb_Encoder_EncodeVarint32MaxSize]; | |
| char* delim_end = delim_buf; | |
| uint32_t tag = | |
| ((uint32_t)field->UPB_PRIVATE(number) << 3) | kUpb_WireType_Delimited; | |
| delim_end = upb_Encoder_EncodeVarint32(tag, delim_end); | |
| delim_end = upb_Encoder_EncodeVarint32(size, delim_end); | |
| upb_StringView unknown[] = { | |
| {delim_buf, delim_end - delim_buf}, | |
| {buf, size}, | |
| }; | |
| return UPB_PRIVATE(_upb_Message_AddUnknownV)(msg, arena, unknown, 2); | |
| } | |
| static uint32_t encode_zz32(int32_t n) { | |
| return ((uint32_t)n << 1) ^ (n >> 31); | |
| } | |
| static uint64_t encode_zz64(int64_t n) { | |
| return ((uint64_t)n << 1) ^ (n >> 63); | |
| } | |
| UPB_NORETURN static void encode_err(upb_encstate* e, upb_EncodeStatus s) { | |
| UPB_ASSERT(s != kUpb_EncodeStatus_Ok); | |
| e->status = s; | |
| UPB_LONGJMP(*e->err, 1); | |
| } | |
| UPB_NOINLINE static char* encode_growbuffer(char* ptr, upb_encstate* e, | |
| size_t bytes) { | |
| ptr = upb_BackAlloc_Grow(&e->alloc, ptr, bytes); | |
| if (ptr == NULL) { | |
| encode_err(e, kUpb_EncodeStatus_OutOfMemory); | |
| } | |
| return ptr; | |
| } | |
| // Call to ensure that at least `bytes` bytes are available for writing at | |
| // ptr. | |
| UPB_FORCEINLINE | |
| char* encode_reserve(char* ptr, upb_encstate* e, size_t bytes) { | |
| if (upb_BackAlloc_HasBytes(&e->alloc, ptr, bytes)) { | |
| return ptr - bytes; | |
| } | |
| return encode_growbuffer(ptr, e, bytes); | |
| } | |
| static char* encode_bytes_unchecked(char* ptr, upb_encstate* e, | |
| const void* data, size_t len) { | |
| if (len == 0) return ptr; /* memcpy() with zero size is UB */ | |
| ptr -= len; | |
| memcpy(ptr, data, len); | |
| return ptr; | |
| } | |
| /* Writes the given bytes to the buffer, handling reserve/advance. */ | |
| static char* encode_bytes(char* ptr, upb_encstate* e, const void* data, | |
| size_t len) { | |
| if (len == 0) return ptr; /* memcpy() with zero size is UB */ | |
| ptr = encode_reserve(ptr, e, len); | |
| memcpy(ptr, data, len); | |
| return ptr; | |
| } | |
| static char* encode_fixed64_unchecked(char* ptr, upb_encstate* e, | |
| uint64_t val) { | |
| val = upb_BigEndian64(val); | |
| return encode_bytes_unchecked(ptr, e, &val, sizeof(uint64_t)); | |
| } | |
| static char* encode_fixed32_unchecked(char* ptr, upb_encstate* e, | |
| uint32_t val) { | |
| val = upb_BigEndian32(val); | |
| return encode_bytes_unchecked(ptr, e, &val, sizeof(uint32_t)); | |
| } | |
| #define UPB_PB_VARINT_MAX_LEN 10 | |
| #define UPB_PB_VARINT32_MAX_LEN 5 | |
| #if UPB_ARM64_ASM | |
| // Each arm64 instruction encodes to 4 bytes, and it takes two intructions | |
| // to process each byte of output, so we branch ahead by (4 + 4) * skip to | |
| // avoid the remaining bytes. When BTI is on, we need to use specific | |
| // "landing pad" instructions, so we pad those with nop to make it a power | |
| // of 2, skipping 16 bytes at each stage instead of 8. This carries some | |
| // overhead especially on in-order cores so they're not included unless | |
| // building with branch protection. | |
| #if UPB_ARM64_BTI_DEFAULT | |
| // BTI is used with jc targets here because we don't control which register will | |
| // be used for addr; if it's x16 or x17 a `br` is treated like a call. | |
| #define UPB_BTI_JC "bti jc\n" | |
| #define UPB_BTI_NOP "nop\n" | |
| #define UPB_BTI_SHIFT_IMM "4\n" | |
| #else | |
| #define UPB_BTI_JC | |
| #define UPB_BTI_NOP | |
| #define UPB_BTI_SHIFT_IMM "3\n" | |
| #endif | |
| UPB_NOINLINE static char* encode_longvarint(char* ptr, upb_encstate* e, | |
| uint64_t val) { | |
| ptr = encode_reserve(ptr, e, UPB_PB_VARINT_MAX_LEN); | |
| uint64_t clz; | |
| __asm__("clz %[cnt], %[val]\n" : [cnt] "=r"(clz) : [val] "r"(val)); | |
| uint32_t skip = | |
| UPB_PRIVATE(upb_WireWriter_VarintUnusedSizeFromLeadingZeros64)(clz); | |
| ptr += skip; | |
| uint64_t addr, mask; | |
| __asm__ volatile( | |
| // Formatter keeps merging short lines | |
| // clang-format off | |
| "adr %[addr], 0f\n" | |
| "add %[addr], %[addr], %[cnt], lsl #" UPB_BTI_SHIFT_IMM | |
| "mov %w[mask], #0x80\n" | |
| "br %[addr]\n" | |
| // Work around llvm/llvm-project#47432, where alignment directives inside | |
| // functions crash the compiler when generating SEH info on windows. | |
| #ifndef __SEH__ | |
| ".p2align " UPB_BTI_SHIFT_IMM | |
| #endif | |
| "0:\n" | |
| // We don't need addr any more, but we've got the register for our whole | |
| // assembly block so we'll use it as scratch to store the shift+masked | |
| // values before storing them. | |
| // The following stores are unsigned offset stores: | |
| // strb Wt, [Xn, #imm] | |
| UPB_BTI_JC | |
| "orr %[addr], %[mask], %[val], lsr #56\n" | |
| "strb %w[addr], [%[ptr], #8]\n" | |
| UPB_BTI_NOP | |
| UPB_BTI_JC | |
| "orr %[addr], %[mask], %[val], lsr #49\n" | |
| "strb %w[addr], [%[ptr], #7]\n" | |
| UPB_BTI_NOP | |
| UPB_BTI_JC | |
| "orr %[addr], %[mask], %[val], lsr #42\n" | |
| "strb %w[addr], [%[ptr], #6]\n" | |
| UPB_BTI_NOP | |
| UPB_BTI_JC | |
| "orr %[addr], %[mask], %[val], lsr #35\n" | |
| "strb %w[addr], [%[ptr], #5]\n" | |
| UPB_BTI_NOP | |
| UPB_BTI_JC | |
| "orr %[addr], %[mask], %[val], lsr #28\n" | |
| "strb %w[addr], [%[ptr], #4]\n" | |
| UPB_BTI_NOP | |
| UPB_BTI_JC | |
| "orr %w[addr], %w[mask], %w[val], lsr #21\n" | |
| "strb %w[addr], [%[ptr], #3]\n" | |
| UPB_BTI_NOP | |
| UPB_BTI_JC | |
| "orr %w[addr], %w[mask], %w[val], lsr #14\n" | |
| "strb %w[addr], [%[ptr], #2]\n" | |
| UPB_BTI_NOP | |
| UPB_BTI_JC | |
| "orr %w[addr], %w[mask], %w[val], lsr #7\n" | |
| "strb %w[addr], [%[ptr], #1]\n" | |
| UPB_BTI_NOP | |
| UPB_BTI_JC | |
| "orr %w[addr], %w[val], #0x80\n" | |
| "strb %w[addr], [%[ptr]]\n" | |
| UPB_BTI_NOP | |
| UPB_BTI_JC | |
| // clang-format on | |
| : [addr] "=&r"(addr), [mask] "=&r"(mask) | |
| : [val] "r"(val), [ptr] "r"(ptr), [cnt] "r"((uint64_t)skip) | |
| : "memory"); | |
| uint32_t continuations = UPB_PB_VARINT_MAX_LEN - 1 - skip; | |
| // msan can't instrument stores in inline assembly | |
| UPB_PRIVATE(upb_Xsan_MarkInitialized)(ptr, continuations); | |
| // Encode the final byte after the continuation bytes. | |
| ptr[continuations] = val >> (7 * continuations); | |
| return ptr; | |
| } | |
| #undef UPB_BTI_JC | |
| #undef UPB_BTI_NOP | |
| #undef UPB_BTI_SHIFT_IMM | |
| #else | |
| UPB_NOINLINE | |
| static char* encode_longvarint(char* ptr, upb_encstate* e, uint64_t val) { | |
| ptr = encode_reserve(ptr, e, UPB_PB_VARINT_MAX_LEN); | |
| size_t len = 0; | |
| do { | |
| uint8_t byte = val & 0x7fU; | |
| val >>= 7; | |
| if (val) byte |= 0x80U; | |
| ptr[len++] = byte; | |
| } while (val); | |
| char* start = ptr + UPB_PB_VARINT_MAX_LEN - len; | |
| memmove(start, ptr, len); | |
| return start; | |
| } | |
| #endif | |
| UPB_FORCEINLINE | |
| char* encode_varint_unchecked(char* ptr, upb_encstate* e, uint64_t val) { | |
| if (val < 128) { | |
| --ptr; | |
| *ptr = val; | |
| return ptr; | |
| } else { | |
| return encode_longvarint(ptr, e, val); | |
| } | |
| } | |
| UPB_FORCEINLINE | |
| char* encode_varint(char* ptr, upb_encstate* e, uint64_t val) { | |
| if (val < 128 && upb_BackAlloc_HasBytes(&e->alloc, ptr, 1)) { | |
| --ptr; | |
| *ptr = val; | |
| return ptr; | |
| } else { | |
| return encode_longvarint(ptr, e, val); | |
| } | |
| } | |
| UPB_NOINLINE | |
| char* encode_longlength(char* ptr, upb_encstate* e, uint64_t val) { | |
| if (val > INT32_MAX) { | |
| encode_err(e, kUpb_EncodeStatus_MaxSizeExceeded); | |
| } | |
| return encode_longvarint(ptr, e, val); | |
| } | |
| UPB_FORCEINLINE | |
| char* encode_length(char* ptr, upb_encstate* e, uint64_t val) { | |
| if (val < 128 && upb_BackAlloc_HasBytes(&e->alloc, ptr, 1)) { | |
| --ptr; | |
| *ptr = val; | |
| return ptr; | |
| } else { | |
| return encode_longlength(ptr, e, val); | |
| } | |
| } | |
| UPB_FORCEINLINE | |
| char* encode_length_unchecked(char* ptr, upb_encstate* e, uint64_t val) { | |
| if (val < 128) { | |
| --ptr; | |
| *ptr = val; | |
| return ptr; | |
| } else { | |
| return encode_longlength(ptr, e, val); | |
| } | |
| } | |
| static char* encode_double_unchecked(char* ptr, upb_encstate* e, double d) { | |
| uint64_t u64; | |
| UPB_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t), "bad double size"); | |
| memcpy(&u64, &d, sizeof(uint64_t)); | |
| return encode_fixed64_unchecked(ptr, e, u64); | |
| } | |
| static char* encode_float_unchecked(char* ptr, upb_encstate* e, float d) { | |
| uint32_t u32; | |
| UPB_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), "bad float size"); | |
| memcpy(&u32, &d, sizeof(uint32_t)); | |
| return encode_fixed32_unchecked(ptr, e, u32); | |
| } | |
| static char* encode_tag_unchecked(char* ptr, upb_encstate* e, | |
| uint32_t field_number, uint8_t wire_type) { | |
| return encode_varint_unchecked(ptr, e, (field_number << 3) | wire_type); | |
| } | |
| static char* encode_tag(char* ptr, upb_encstate* e, uint32_t field_number, | |
| uint8_t wire_type) { | |
| return encode_varint(ptr, e, (field_number << 3) | wire_type); | |
| } | |
| static char* encode_fixedarray(char* ptr, upb_encstate* e, const upb_Array* arr, | |
| size_t elem_size, uint32_t tag) { | |
| size_t bytes = upb_Array_Size(arr) * elem_size; | |
| const char* data = upb_Array_DataPtr(arr); | |
| const char* arr_ptr = data + bytes - elem_size; | |
| if (tag || !upb_IsLittleEndian()) { | |
| while (true) { | |
| if (elem_size == 4) { | |
| uint32_t val; | |
| memcpy(&val, arr_ptr, sizeof(val)); | |
| val = upb_BigEndian32(val); | |
| ptr = encode_bytes(ptr, e, &val, elem_size); | |
| } else { | |
| UPB_ASSERT(elem_size == 8); | |
| uint64_t val; | |
| memcpy(&val, arr_ptr, sizeof(val)); | |
| val = upb_BigEndian64(val); | |
| ptr = encode_bytes(ptr, e, &val, elem_size); | |
| } | |
| if (tag) { | |
| ptr = encode_varint(ptr, e, tag); | |
| } | |
| if (arr_ptr == data) break; | |
| arr_ptr -= elem_size; | |
| } | |
| return ptr; | |
| } else { | |
| return encode_bytes(ptr, e, data, bytes); | |
| } | |
| } | |
| static char* encode_scalar(char* ptr, upb_encstate* e, const void* field_mem, | |
| const upb_MiniTableField* f) { | |
| // Max size is tag + 10 bytes for max varint or 8 for largest fixed size | |
| #define CASE(ctype, type, wtype, encodeval) \ | |
| { \ | |
| const size_t bytes = UPB_PB_VARINT32_MAX_LEN + UPB_PB_VARINT_MAX_LEN; \ | |
| ptr = encode_reserve(ptr, e, bytes); \ | |
| ptr += bytes; \ | |
| const ctype val = *(const ctype*)field_mem; \ | |
| ptr = encode_##type##_unchecked(ptr, e, encodeval); \ | |
| return encode_tag_unchecked(ptr, e, upb_MiniTableField_Number(f), wtype); \ | |
| } | |
| switch (f->UPB_PRIVATE(descriptortype)) { | |
| case kUpb_FieldType_Double: | |
| CASE(double, double, kUpb_WireType_64Bit, val); | |
| case kUpb_FieldType_Float: | |
| CASE(float, float, kUpb_WireType_32Bit, val); | |
| case kUpb_FieldType_Int64: | |
| case kUpb_FieldType_UInt64: | |
| CASE(uint64_t, varint, kUpb_WireType_Varint, val); | |
| case kUpb_FieldType_UInt32: | |
| CASE(uint32_t, varint, kUpb_WireType_Varint, val); | |
| case kUpb_FieldType_Int32: | |
| case kUpb_FieldType_Enum: | |
| CASE(int32_t, varint, kUpb_WireType_Varint, (int64_t)val); | |
| case kUpb_FieldType_SFixed64: | |
| case kUpb_FieldType_Fixed64: | |
| CASE(uint64_t, fixed64, kUpb_WireType_64Bit, val); | |
| case kUpb_FieldType_Fixed32: | |
| case kUpb_FieldType_SFixed32: | |
| CASE(uint32_t, fixed32, kUpb_WireType_32Bit, val); | |
| case kUpb_FieldType_Bool: | |
| CASE(bool, varint, kUpb_WireType_Varint, val); | |
| case kUpb_FieldType_SInt32: | |
| CASE(int32_t, varint, kUpb_WireType_Varint, encode_zz32(val)); | |
| case kUpb_FieldType_SInt64: | |
| CASE(int64_t, varint, kUpb_WireType_Varint, encode_zz64(val)); | |
| case kUpb_FieldType_String: | |
| case kUpb_FieldType_Bytes: { | |
| upb_StringView view = *(upb_StringView*)field_mem; | |
| const size_t max_size = | |
| UPB_PB_VARINT32_MAX_LEN + UPB_PB_VARINT32_MAX_LEN + view.size; | |
| ptr = encode_reserve(ptr, e, max_size); | |
| ptr += max_size; | |
| ptr = encode_bytes_unchecked(ptr, e, view.data, view.size); | |
| ptr = encode_length_unchecked(ptr, e, view.size); | |
| return encode_tag_unchecked(ptr, e, upb_MiniTableField_Number(f), | |
| kUpb_WireType_Delimited); | |
| } | |
| case kUpb_FieldType_Group: { | |
| size_t size; | |
| upb_Message* submsg = *(upb_Message**)field_mem; | |
| const upb_MiniTable* subm = upb_MiniTable_GetSubMessageTable(f); | |
| if (submsg == 0) { | |
| return ptr; | |
| } | |
| if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); | |
| ptr = encode_tag(ptr, e, upb_MiniTableField_Number(f), | |
| kUpb_WireType_EndGroup); | |
| ptr = encode_message(ptr, e, submsg, subm, &size); | |
| e->depth++; | |
| return encode_tag(ptr, e, upb_MiniTableField_Number(f), | |
| kUpb_WireType_StartGroup); | |
| } | |
| case kUpb_FieldType_Message: { | |
| size_t size; | |
| upb_Message* submsg = *(upb_Message**)field_mem; | |
| const upb_MiniTable* subm = upb_MiniTable_GetSubMessageTable(f); | |
| if (submsg == 0) { | |
| return ptr; | |
| } | |
| if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); | |
| ptr = encode_message(ptr, e, submsg, subm, &size); | |
| e->depth++; | |
| size_t max_size = UPB_PB_VARINT32_MAX_LEN + UPB_PB_VARINT32_MAX_LEN; | |
| ptr = encode_reserve(ptr, e, max_size); | |
| ptr += max_size; | |
| ptr = encode_length_unchecked(ptr, e, size); | |
| return encode_tag_unchecked(ptr, e, upb_MiniTableField_Number(f), | |
| kUpb_WireType_Delimited); | |
| } | |
| default: | |
| UPB_UNREACHABLE(); | |
| } | |
| #undef CASE | |
| } | |
| static char* encode_array(char* ptr, upb_encstate* e, const upb_Message* msg, | |
| const upb_MiniTableField* f) { | |
| const upb_Array* arr = *UPB_PTR_AT(msg, f->UPB_PRIVATE(offset), upb_Array*); | |
| bool packed = upb_MiniTableField_IsPacked(f); | |
| size_t pre_len = upb_BackAlloc_Size(&e->alloc, ptr); | |
| if (arr == NULL || upb_Array_Size(arr) == 0) { | |
| return ptr; | |
| } | |
| #define VARINT_CASE(ctype, encode) \ | |
| { \ | |
| const ctype* start = upb_Array_DataPtr(arr); \ | |
| const ctype* arr_ptr = start + upb_Array_Size(arr); \ | |
| if (packed) { \ | |
| do { \ | |
| arr_ptr--; \ | |
| ptr = encode_varint(ptr, e, encode); \ | |
| } while (arr_ptr != start); \ | |
| } else { \ | |
| uint32_t number = upb_MiniTableField_Number(f); \ | |
| do { \ | |
| arr_ptr--; \ | |
| ptr = encode_varint(ptr, e, encode); \ | |
| ptr = encode_tag(ptr, e, number, kUpb_WireType_Varint); \ | |
| } while (arr_ptr != start); \ | |
| } \ | |
| } \ | |
| break; | |
| #define TAG(wire_type) (packed ? 0 : (f->UPB_PRIVATE(number) << 3 | wire_type)) | |
| switch (f->UPB_PRIVATE(descriptortype)) { | |
| case kUpb_FieldType_Double: | |
| ptr = encode_fixedarray(ptr, e, arr, sizeof(double), | |
| TAG(kUpb_WireType_64Bit)); | |
| break; | |
| case kUpb_FieldType_Float: | |
| ptr = encode_fixedarray(ptr, e, arr, sizeof(float), | |
| TAG(kUpb_WireType_32Bit)); | |
| break; | |
| case kUpb_FieldType_SFixed64: | |
| case kUpb_FieldType_Fixed64: | |
| ptr = encode_fixedarray(ptr, e, arr, sizeof(uint64_t), | |
| TAG(kUpb_WireType_64Bit)); | |
| break; | |
| case kUpb_FieldType_Fixed32: | |
| case kUpb_FieldType_SFixed32: | |
| ptr = encode_fixedarray(ptr, e, arr, sizeof(uint32_t), | |
| TAG(kUpb_WireType_32Bit)); | |
| break; | |
| case kUpb_FieldType_Int64: | |
| case kUpb_FieldType_UInt64: | |
| VARINT_CASE(uint64_t, *arr_ptr); | |
| case kUpb_FieldType_UInt32: | |
| VARINT_CASE(uint32_t, *arr_ptr); | |
| case kUpb_FieldType_Int32: | |
| case kUpb_FieldType_Enum: | |
| VARINT_CASE(int32_t, (int64_t)*arr_ptr); | |
| case kUpb_FieldType_Bool: | |
| VARINT_CASE(bool, *arr_ptr); | |
| case kUpb_FieldType_SInt32: | |
| VARINT_CASE(int32_t, encode_zz32(*arr_ptr)); | |
| case kUpb_FieldType_SInt64: | |
| VARINT_CASE(int64_t, encode_zz64(*arr_ptr)); | |
| case kUpb_FieldType_String: | |
| case kUpb_FieldType_Bytes: { | |
| const upb_StringView* start = upb_Array_DataPtr(arr); | |
| const upb_StringView* str_ptr = start + upb_Array_Size(arr); | |
| do { | |
| str_ptr--; | |
| ptr = encode_bytes(ptr, e, str_ptr->data, str_ptr->size); | |
| ptr = encode_length(ptr, e, str_ptr->size); | |
| ptr = encode_tag(ptr, e, upb_MiniTableField_Number(f), | |
| kUpb_WireType_Delimited); | |
| } while (str_ptr != start); | |
| return ptr; | |
| } | |
| case kUpb_FieldType_Group: { | |
| const upb_Message* const* start = upb_Array_DataPtr(arr); | |
| const upb_Message* const* arr_ptr = start + upb_Array_Size(arr); | |
| const upb_MiniTable* subm = upb_MiniTable_GetSubMessageTable(f); | |
| if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); | |
| do { | |
| size_t size; | |
| arr_ptr--; | |
| ptr = encode_tag(ptr, e, upb_MiniTableField_Number(f), | |
| kUpb_WireType_EndGroup); | |
| ptr = encode_message(ptr, e, *arr_ptr, subm, &size); | |
| ptr = encode_tag(ptr, e, upb_MiniTableField_Number(f), | |
| kUpb_WireType_StartGroup); | |
| } while (arr_ptr != start); | |
| e->depth++; | |
| return ptr; | |
| } | |
| case kUpb_FieldType_Message: { | |
| const upb_Message* const* start = upb_Array_DataPtr(arr); | |
| const upb_Message* const* arr_ptr = start + upb_Array_Size(arr); | |
| const upb_MiniTable* subm = upb_MiniTable_GetSubMessageTable(f); | |
| if (--e->depth == 0) encode_err(e, kUpb_EncodeStatus_MaxDepthExceeded); | |
| do { | |
| size_t size; | |
| arr_ptr--; | |
| ptr = encode_message(ptr, e, *arr_ptr, subm, &size); | |
| ptr = encode_length(ptr, e, size); | |
| ptr = encode_tag(ptr, e, upb_MiniTableField_Number(f), | |
| kUpb_WireType_Delimited); | |
| } while (arr_ptr != start); | |
| e->depth++; | |
| return ptr; | |
| } | |
| } | |
| #undef VARINT_CASE | |
| if (packed) { | |
| ptr = encode_length(ptr, e, upb_BackAlloc_Size(&e->alloc, ptr) - pre_len); | |
| ptr = encode_tag(ptr, e, upb_MiniTableField_Number(f), | |
| kUpb_WireType_Delimited); | |
| } | |
| return ptr; | |
| } | |
| UPB_FORCEINLINE | |
| char* encode_mapentry(char* ptr, upb_encstate* e, uint32_t number, | |
| const upb_MiniTableField* key_field, | |
| const upb_MiniTableField* val_field, | |
| const upb_MapEntry* ent) { | |
| size_t pre_len = upb_BackAlloc_Size(&e->alloc, ptr); | |
| UPB_ASSUME(upb_MiniTableField_Number(val_field) == 2); | |
| ptr = encode_scalar(ptr, e, &ent->v, val_field); | |
| UPB_ASSUME(upb_MiniTableField_Number(key_field) == 1); | |
| ptr = encode_scalar(ptr, e, &ent->k, key_field); | |
| size_t size = upb_BackAlloc_Size(&e->alloc, ptr) - pre_len; | |
| ptr = encode_length(ptr, e, size); | |
| ptr = encode_tag(ptr, e, number, kUpb_WireType_Delimited); | |
| return ptr; | |
| } | |
| UPB_NOINLINE | |
| static char* encode_map(char* ptr, upb_encstate* e, const upb_Message* msg, | |
| const upb_MiniTableField* f) { | |
| const upb_Map* map = *UPB_PTR_AT(msg, f->UPB_PRIVATE(offset), const upb_Map*); | |
| const upb_MiniTable* layout = upb_MiniTable_MapEntrySubMessage(f); | |
| UPB_ASSERT(upb_MiniTable_FieldCount(layout) == 2); | |
| if (!map || !upb_Map_Size(map)) return ptr; | |
| uint32_t number = upb_MiniTableField_Number(f); | |
| uint32_t key_size = map->key_size; | |
| uint32_t val_size = map->val_size; | |
| const upb_MiniTableField* key_field = upb_MiniTable_MapKey(layout); | |
| const upb_MiniTableField* val_field = upb_MiniTable_MapValue(layout); | |
| if (e->options & kUpb_EncodeOption_Deterministic) { | |
| _upb_sortedmap sorted; | |
| if (!_upb_mapsorter_pushmap( | |
| &e->sorter, key_field->UPB_PRIVATE(descriptortype), map, &sorted)) { | |
| encode_err(e, kUpb_EncodeStatus_OutOfMemory); | |
| } | |
| upb_MapEntry ent; | |
| while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) { | |
| ptr = encode_mapentry(ptr, e, number, key_field, val_field, &ent); | |
| } | |
| _upb_mapsorter_popmap(&e->sorter, &sorted); | |
| } else { | |
| upb_value val; | |
| if (map->UPB_PRIVATE(is_strtable)) { | |
| intptr_t iter = UPB_STRTABLE_BEGIN; | |
| upb_StringView strkey; | |
| while (upb_strtable_next2(&map->t.strtable, &strkey, &val, &iter)) { | |
| upb_MapEntry ent; | |
| _upb_map_fromkey(strkey, &ent.k, key_size); | |
| _upb_map_fromvalue(val, &ent.v, val_size); | |
| ptr = encode_mapentry(ptr, e, number, key_field, val_field, &ent); | |
| } | |
| } else { | |
| intptr_t iter = UPB_INTTABLE_BEGIN; | |
| uintptr_t intkey = 0; | |
| while (upb_inttable_next(&map->t.inttable, &intkey, &val, &iter)) { | |
| upb_MapEntry ent; | |
| UPB_ASSUME(key_size != UPB_MAPTYPE_STRING); | |
| memcpy(&ent.k, &intkey, key_size); | |
| _upb_map_fromvalue(val, &ent.v, val_size); | |
| ptr = encode_mapentry(ptr, e, number, key_field, val_field, &ent); | |
| } | |
| } | |
| } | |
| return ptr; | |
| } | |
| static bool encode_shouldencode(const upb_Message* msg, | |
| const upb_MiniTableField* f) { | |
| return UPB_PRIVATE(_upb_Message_FieldIsSet)(msg, f); | |
| } | |
| static char* encode_field(char* ptr, upb_encstate* e, const upb_Message* msg, | |
| const upb_MiniTableField* field) { | |
| switch (UPB_PRIVATE(_upb_MiniTableField_Mode)(field)) { | |
| case kUpb_FieldMode_Scalar: | |
| return encode_scalar( | |
| ptr, e, UPB_PTR_AT(msg, field->UPB_PRIVATE(offset), void), field); | |
| case kUpb_FieldMode_Array: | |
| return encode_array(ptr, e, msg, field); | |
| case kUpb_FieldMode_Map: | |
| return encode_map(ptr, e, msg, field); | |
| default: | |
| UPB_UNREACHABLE(); | |
| } | |
| } | |
| static char* encode_msgset_item(char* ptr, upb_encstate* e, | |
| const upb_MiniTableExtension* ext, | |
| const upb_MessageValue ext_val) { | |
| // MessageSet items are always singular submessages. This holds for canonical | |
| // extensions of a MessageSet, but must also hold for any non-canonical | |
| // extension that is encoded as a MessageSet item. | |
| UPB_ASSERT(upb_MiniTableField_IsScalar(upb_MiniTableExtension_ToField(ext))); | |
| UPB_ASSERT(upb_MiniTableExtension_CType(ext) == kUpb_CType_Message); | |
| size_t size; | |
| ptr = encode_tag(ptr, e, kUpb_MsgSet_Item, kUpb_WireType_EndGroup); | |
| ptr = encode_message(ptr, e, ext_val.msg_val, | |
| upb_MiniTableExtension_GetSubMessage(ext), &size); | |
| ptr = encode_varint(ptr, e, size); | |
| ptr = encode_tag(ptr, e, kUpb_MsgSet_Message, kUpb_WireType_Delimited); | |
| ptr = encode_varint(ptr, e, upb_MiniTableExtension_Number(ext)); | |
| ptr = encode_tag(ptr, e, kUpb_MsgSet_TypeId, kUpb_WireType_Varint); | |
| ptr = encode_tag(ptr, e, kUpb_MsgSet_Item, kUpb_WireType_StartGroup); | |
| return ptr; | |
| } | |
| static char* encode_ext(char* ptr, upb_encstate* e, | |
| const upb_MiniTableExtension* ext, | |
| upb_MessageValue ext_val, bool is_message_set) { | |
| if (UPB_UNLIKELY(is_message_set)) { | |
| ptr = encode_msgset_item(ptr, e, ext, ext_val); | |
| } else { | |
| ptr = encode_field(ptr, e, &ext_val.UPB_PRIVATE(ext_msg_val), | |
| &ext->UPB_PRIVATE(field)); | |
| } | |
| return ptr; | |
| } | |
| static char* encode_exts(char* ptr, upb_encstate* e, const upb_MiniTable* m, | |
| const upb_Message* msg) { | |
| if (UPB_PRIVATE(_upb_MiniTable_ExtModeBase)(m) == kUpb_ExtMode_NonExtendable) | |
| return ptr; | |
| upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); | |
| if (!in) return ptr; | |
| /* Encode all canonical extensions together. Unlike C++, we do not attempt to | |
| * keep these in field number order relative to normal fields or even to each | |
| * other. */ | |
| uintptr_t iter = kUpb_Message_ExtensionBegin; | |
| const upb_MiniTableExtension* ext; | |
| upb_MessageValue ext_val; | |
| if (!UPB_PRIVATE(_upb_Message_NextExtensionReverse)(msg, &ext, &ext_val, | |
| &iter)) { | |
| // Message has no extensions. | |
| return ptr; | |
| } | |
| if (e->options & kUpb_EncodeOption_Deterministic) { | |
| _upb_sortedmap sorted; | |
| if (!_upb_mapsorter_pushexts(&e->sorter, in, &sorted)) { | |
| encode_err(e, kUpb_EncodeStatus_OutOfMemory); | |
| } | |
| const upb_Extension* ext; | |
| while (_upb_sortedmap_nextext(&e->sorter, &sorted, &ext)) { | |
| ptr = encode_ext(ptr, e, upb_Extension_MiniTableExtension(ext), | |
| upb_Extension_GetValue(ext), | |
| UPB_PRIVATE(_upb_MiniTable_ExtModeBase)(m) == | |
| kUpb_ExtMode_IsMessageSet); | |
| } | |
| _upb_mapsorter_popmap(&e->sorter, &sorted); | |
| } else { | |
| do { | |
| ptr = encode_ext(ptr, e, ext, ext_val, | |
| m->UPB_PRIVATE(ext) == kUpb_ExtMode_IsMessageSet); | |
| } while (UPB_PRIVATE(_upb_Message_NextExtensionReverse)(msg, &ext, &ext_val, | |
| &iter)); | |
| } | |
| return ptr; | |
| } | |
| char* encode_message(char* ptr, upb_encstate* e, const upb_Message* msg, | |
| const upb_MiniTable* m, size_t* size) { | |
| size_t pre_len = upb_BackAlloc_Size(&e->alloc, ptr); | |
| if (e->options & kUpb_EncodeOption_CheckRequired) { | |
| if (m->UPB_PRIVATE(required_count)) { | |
| if (!UPB_PRIVATE(_upb_Message_IsInitializedShallow)(msg, m)) { | |
| encode_err(e, kUpb_EncodeStatus_MissingRequired); | |
| } | |
| } | |
| } | |
| bool skip_unknown = (e->options & kUpb_EncodeOption_SkipUnknown) != 0; | |
| const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); | |
| if (!skip_unknown && in) { | |
| // Iterate backwards because the encoder builds the buffer in reverse | |
| // (from end to start). This ensures that unknown fields and non-canonical | |
| // extensions are emitted in their original forward order. | |
| size_t i = in->size; | |
| while (i > 0) { | |
| i--; | |
| upb_TaggedAuxPtr tagged_ptr = in->aux_data[i]; | |
| if (upb_TaggedAuxPtr_IsUnknownStringView(tagged_ptr)) { | |
| const upb_StringView* unknown = | |
| upb_TaggedPtrAux_StringViewRepr(tagged_ptr); | |
| ptr = encode_bytes(ptr, e, unknown->data, unknown->size); | |
| } else if (upb_TaggedAuxPtr_IsNonCanonicalExtension(tagged_ptr)) { | |
| const upb_Extension* ext = | |
| upb_TaggedAuxPtr_NonCanonicalExtension(tagged_ptr); | |
| ptr = encode_ext(ptr, e, upb_Extension_MiniTableExtension(ext), | |
| upb_Extension_GetValue(ext), | |
| UPB_PRIVATE(_upb_MiniTable_ExtModeBase)(m) == | |
| kUpb_ExtMode_IsMessageSet); | |
| } | |
| } | |
| } | |
| ptr = encode_exts(ptr, e, m, msg); | |
| if (upb_MiniTable_FieldCount(m)) { | |
| const upb_MiniTableField* f = | |
| &m->UPB_PRIVATE(fields)[m->UPB_PRIVATE(field_count)]; | |
| const upb_MiniTableField* first = &m->UPB_PRIVATE(fields)[0]; | |
| while (f != first) { | |
| f--; | |
| if (encode_shouldencode(msg, f)) { | |
| ptr = encode_field(ptr, e, msg, f); | |
| } | |
| } | |
| } | |
| *size = upb_BackAlloc_Size(&e->alloc, ptr) - pre_len; | |
| return ptr; | |
| } | |
| static upb_EncodeStatus upb_Encoder_Encode(char* ptr, | |
| upb_encstate* const encoder, | |
| const upb_Message* const msg, | |
| const upb_MiniTable* const l, | |
| char** const buf, size_t* const size, | |
| bool prepend_len) { | |
| // Unfortunately we must continue to perform hackery here because there are | |
| // code paths which blindly copy the returned pointer without bothering to | |
| // check for errors until much later (b/235839510). So we still set *buf to | |
| // NULL on error and we still set it to non-NULL on a successful empty result. | |
| if (UPB_SETJMP(*encoder->err) == 0) { | |
| size_t encoded_msg_size; | |
| ptr = encode_message(ptr, encoder, msg, l, &encoded_msg_size); | |
| if (prepend_len) { | |
| ptr = encode_length(ptr, encoder, encoded_msg_size); | |
| } | |
| *size = upb_BackAlloc_Finish(&encoder->alloc, ptr); | |
| *buf = ptr; | |
| } else { | |
| UPB_ASSERT(encoder->status != kUpb_EncodeStatus_Ok); | |
| upb_BackAlloc_Abort(&encoder->alloc); | |
| *buf = NULL; | |
| *size = 0; | |
| } | |
| UPB_PRIVATE(_upb_encstate_destroy)(encoder); | |
| return encoder->status; | |
| } | |
| upb_EncodeStatus _upb_Encode(const upb_Message* msg, const upb_MiniTable* l, | |
| int options, upb_Arena* arena, char** buf, | |
| size_t* size, bool prepend_len) { | |
| upb_encstate e; | |
| jmp_buf err; | |
| e.status = kUpb_EncodeStatus_Ok; | |
| e.err = &err; | |
| char* ptr = upb_BackAlloc_Init(&e.alloc, arena); | |
| e.depth = upb_EncodeOptions_GetEffectiveMaxDepth(options); | |
| e.options = options; | |
| _upb_mapsorter_init(&e.sorter); | |
| return upb_Encoder_Encode(ptr, &e, msg, l, buf, size, prepend_len); | |
| } | |
| char* UPB_PRIVATE(_upb_Encode_FieldToBuffer)(char* ptr, upb_encstate* e, | |
| const upb_Message* msg, | |
| const upb_MiniTableField* field) { | |
| return encode_field(ptr, e, msg, field); | |
| } | |
| upb_EncodeStatus UPB_PRIVATE(_upb_Encode_Field)(upb_encstate* e, | |
| const upb_Message* msg, | |
| const upb_MiniTableField* field, | |
| char** buf, size_t* size, | |
| int options) { | |
| e->options = options; | |
| e->depth = upb_EncodeOptions_GetEffectiveMaxDepth(options); | |
| char* ptr = *buf; | |
| if (encode_shouldencode(msg, field)) { | |
| ptr = encode_field(ptr, e, msg, field); | |
| } | |
| *size = upb_BackAlloc_Finish(&e->alloc, ptr); | |
| *buf = ptr; | |
| return e->status; | |
| } | |
| upb_EncodeStatus UPB_PRIVATE(_upb_Encode_Extension)( | |
| upb_encstate* e, const upb_MiniTableExtension* ext, | |
| upb_MessageValue ext_val, bool is_message_set, char** buf, size_t* size, | |
| int options) { | |
| e->options = options; | |
| e->depth = upb_EncodeOptions_GetEffectiveMaxDepth(options); | |
| char* ptr = *buf; | |
| ptr = encode_ext(ptr, e, ext, ext_val, is_message_set); | |
| *size = upb_BackAlloc_Finish(&e->alloc, ptr); | |
| *buf = ptr; | |
| return e->status; | |
| } | |
| #include <stdint.h> | |
| #include <string.h> | |
| // Must be last. | |
| UPB_NORETURN UPB_NOINLINE void UPB_PRIVATE( | |
| upb_EpsCopyInputStream_ThrowMalformed)(upb_EpsCopyInputStream* e) { | |
| e->error = true; | |
| upb_ErrorHandler_ThrowError(e->err, kUpb_ErrorCode_Malformed); | |
| } | |
| const char* UPB_PRIVATE(upb_EpsCopyInputStream_IsDoneFallback)( | |
| struct upb_EpsCopyInputStream* e, const char* ptr, int overrun) { | |
| if (overrun < e->limit) { | |
| // Need to copy remaining data into patch buffer. | |
| UPB_ASSERT(overrun < kUpb_EpsCopyInputStream_SlopBytes); | |
| const char* old_end = ptr; | |
| const char* new_start = &e->patch[overrun]; | |
| memset(&e->patch[kUpb_EpsCopyInputStream_SlopBytes], 0, | |
| kUpb_EpsCopyInputStream_SlopBytes); | |
| memcpy(e->patch, e->end, kUpb_EpsCopyInputStream_SlopBytes); | |
| ptr = new_start; | |
| e->end = &e->patch[kUpb_EpsCopyInputStream_SlopBytes]; | |
| e->limit -= kUpb_EpsCopyInputStream_SlopBytes; | |
| e->limit_ptr = e->end + e->limit; | |
| UPB_ASSERT(ptr < e->limit_ptr); | |
| e->input_delta = (uintptr_t)old_end - (uintptr_t)new_start; | |
| UPB_PRIVATE(upb_EpsCopyInputStream_BoundsChecked)( | |
| e, kUpb_EpsCopyInputStream_SlopBytes); | |
| return new_start; | |
| } else { | |
| UPB_ASSERT(overrun > e->limit); | |
| return UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(e); | |
| } | |
| } | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| // Must be last. | |
| UPB_NOINLINE UPB_PRIVATE(_upb_WireReader_LongVarint) | |
| UPB_PRIVATE(_upb_WireReader_ReadLongVarint)( | |
| const char* ptr, uint64_t val, upb_EpsCopyInputStream* stream) { | |
| for (int i = 1; i < 10; i++) { | |
| uint64_t byte = (uint8_t)ptr[i]; | |
| val += (byte - 1) << (i * 7); | |
| if (!(byte & 0x80)) { | |
| return (UPB_PRIVATE(_upb_WireReader_LongVarint)){ptr + i + 1, val}; | |
| } | |
| } | |
| return (UPB_PRIVATE(_upb_WireReader_LongVarint)){ | |
| UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(stream), 0}; | |
| } | |
| UPB_NOINLINE UPB_PRIVATE(_upb_WireReader_LongVarint) | |
| UPB_PRIVATE(_upb_WireReader_ReadLongTag)(const char* ptr, uint64_t val, | |
| upb_EpsCopyInputStream* stream) { | |
| for (int i = 1; i < 5; i++) { | |
| uint64_t byte = (uint8_t)ptr[i]; | |
| val += (byte - 1) << (i * 7); | |
| if (!(byte & 0x80)) { | |
| if (val > UINT32_MAX) break; | |
| return (UPB_PRIVATE(_upb_WireReader_LongVarint)){ptr + i + 1, val}; | |
| } | |
| } | |
| return (UPB_PRIVATE(_upb_WireReader_LongVarint)){ | |
| UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(stream), 0}; | |
| } | |
| UPB_NOINLINE UPB_PRIVATE(_upb_WireReader_LongVarint) | |
| UPB_PRIVATE(_upb_WireReader_ReadLongSize)(const char* ptr, uint64_t val, | |
| upb_EpsCopyInputStream* stream) { | |
| for (int i = 1; i < 5; i++) { | |
| uint64_t byte = (uint8_t)ptr[i]; | |
| val += (byte - 1) << (i * 7); | |
| if (!(byte & 0x80)) { | |
| if (val > INT32_MAX) break; | |
| return (UPB_PRIVATE(_upb_WireReader_LongVarint)){ptr + i + 1, val}; | |
| } | |
| } | |
| return (UPB_PRIVATE(_upb_WireReader_LongVarint)){ | |
| UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(stream), 0}; | |
| } | |
| const char* UPB_PRIVATE(_upb_WireReader_SkipGroup)( | |
| const char* ptr, uint32_t tag, int depth_limit, | |
| upb_EpsCopyInputStream* stream) { | |
| if (depth_limit <= 0) { | |
| return UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(stream); | |
| } | |
| depth_limit--; | |
| uint32_t end_group_tag = (tag & ~7ULL) | kUpb_WireType_EndGroup; | |
| while (!upb_EpsCopyInputStream_IsDone(stream, &ptr)) { | |
| uint32_t tag; | |
| ptr = upb_WireReader_ReadTag(ptr, &tag, stream); | |
| if (!ptr) break; | |
| if (tag == end_group_tag) return ptr; | |
| ptr = _upb_WireReader_SkipValue(ptr, tag, depth_limit, stream); | |
| if (!ptr) break; | |
| } | |
| // Encountered limit end before end group tag. | |
| return UPB_PRIVATE(upb_EpsCopyInputStream_ReturnError)(stream); | |
| } | |
| // This should #undef all macros #defined in def.inc | |
| #undef UPB_SIZE | |
| #undef UPB_PTR_AT | |
| #undef UPB_SIZEOF_FLEX | |
| #undef UPB_FLEX_CAPACITY | |
| #undef UPB_SIZEOF_FLEX_WOULD_OVERFLOW | |
| #undef UPB_MAPTYPE_STRING | |
| #undef UPB_EXPORT | |
| #undef UPB_INLINE | |
| #undef UPB_API | |
| #undef UPBC_API | |
| #undef UPB_API_INLINE | |
| #undef UPB_API_INLINE_IF_NOT_GCC | |
| #undef UPB_ALIGN_UP | |
| #undef UPB_ALIGN_DOWN | |
| #undef UPB_ALIGN_MALLOC | |
| #undef UPB_ALIGN_OF | |
| #undef UPB_ALIGN_AS | |
| #undef UPB_STATIC_ASSERT | |
| #undef UPB_STATIC_ASSERT_CONCAT | |
| #undef UPB_STATIC_ASSERT_CONCAT_IMPL | |
| #undef UPB_LIKELY | |
| #undef UPB_UNLIKELY | |
| #undef UPB_UNPREDICTABLE | |
| #undef UPB_FORCEINLINE | |
| #undef UPB_NOINLINE | |
| #undef UPB_NORETURN | |
| #undef UPB_PRINTF | |
| #undef UPB_NODEREF | |
| #undef UPB_NODISCARD | |
| #undef UPB_MAX | |
| #undef UPB_MIN | |
| #undef UPB_UNUSED | |
| #undef UPB_ASSUME | |
| #undef UPB_ASSERT | |
| #undef UPB_UNREACHABLE | |
| #undef UPB_UNREACHABLE_FAILURE | |
| #undef UPB_PRETTY_FUNCTION | |
| #undef UPB_DEFAULT_MAX_BLOCK_SIZE | |
| #undef UPB_SETJMP | |
| #undef UPB_LONGJMP | |
| #undef UPB_PTRADD | |
| #undef UPB_MUSTTAIL | |
| #undef UPB_PRESERVE_MOST | |
| #undef UPB_PRESERVE_NONE | |
| #undef UPB_FASTTABLE_SUPPORTED | |
| #undef UPB_FASTTABLE_MASK | |
| #undef UPB_FASTTABLE | |
| #undef UPB_FASTTABLE_INIT | |
| #undef UPB_POISON_MEMORY_REGION | |
| #undef UPB_UNPOISON_MEMORY_REGION | |
| #undef UPB_ASAN | |
| #undef UPB_HWASAN | |
| #undef UPB_HWASAN_POISON_TAG | |
| #undef UPB_MSAN | |
| #undef UPB_MALLOC_ALIGN | |
| #undef UPB_TSAN | |
| #undef UPB_DEPRECATED | |
| #undef UPB_IGNORE_DEPRECATION_START | |
| #undef UPB_IGNORE_DEPRECATION_STOP | |
| #undef UPB_GNUC_MIN | |
| #undef UPB_CLANG_MIN | |
| #undef UPB_DESCRIPTOR_UPB_H_FILENAME | |
| #undef UPB_DESC_MINITABLE | |
| #undef UPB_IS_GOOGLE3 | |
| #undef UPB_ATOMIC | |
| #undef UPB_USE_C11_ATOMICS | |
| #undef UPB_USE_MSC_ATOMICS | |
| #undef UPB_PRIVATE | |
| #undef UPB_ONLYBITS | |
| #undef UPB_LINKARR_DECLARE | |
| #undef UPB_LINKARR_APPEND | |
| #undef UPB_LINKARR_START | |
| #undef UPB_LINKARR_STOP | |
| #undef UPB_HAS_ATTRIBUTE | |
| #undef UPB_HAS_CPP_ATTRIBUTE | |
| #undef UPB_HAS_BUILTIN | |
| #undef UPB_MEMCPY_INLINE | |
| #undef UPB_HAS_EXTENSION | |
| #undef UPB_HAS_FEATURE | |
| #undef UPB_XSAN_MEMBER | |
| #undef UPB_XSAN | |
| #undef UPB_XSAN_STRUCT_SIZE | |
| #undef UPB_ENABLE_REF_CYCLE_CHECKS | |
| #undef UPB_ARM64_ASM | |
| #undef UPB_ARM64_BTI_DEFAULT | |
| #undef UPB_DEPRECATE_AND_INLINE | |
| #undef UPB_MAYBE_ASSUME | |
| #undef UPB_ATTR_CONST | |
| #undef _UPB_STRINGIFY | |
| #undef _UPB_STRINGIFY2 | |
| #undef UPB_CONSTRUCTOR | |
| #undef UPB_RETAIN | |
| #undef UPB_HIDDEN |