From 28812a8faeb3b03d496d039f9caefc6d0752c0c9 Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Fri, 15 Nov 2024 23:40:53 +0000 Subject: [PATCH] Auto-generate files after cl/697017028 --- .../Reflection/FeatureSetDescriptor.g.cs | 17 + php/ext/google/protobuf/php-upb.c | 613 ++++++++++-------- php/ext/google/protobuf/php-upb.h | 463 +++++++------ ruby/ext/google/protobuf_c/ruby-upb.c | 613 ++++++++++-------- ruby/ext/google/protobuf_c/ruby-upb.h | 463 +++++++------ 5 files changed, 1139 insertions(+), 1030 deletions(-) create mode 100644 csharp/src/Google.Protobuf/Reflection/FeatureSetDescriptor.g.cs diff --git a/csharp/src/Google.Protobuf/Reflection/FeatureSetDescriptor.g.cs b/csharp/src/Google.Protobuf/Reflection/FeatureSetDescriptor.g.cs new file mode 100644 index 0000000000..208ce1fcb6 --- /dev/null +++ b/csharp/src/Google.Protobuf/Reflection/FeatureSetDescriptor.g.cs @@ -0,0 +1,17 @@ +#region Copyright notice and license +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file or at +// https://developers.google.com/open-source/licenses/bsd +#endregion + +namespace Google.Protobuf.Reflection; + +internal sealed partial class FeatureSetDescriptor +{ + // Canonical serialized form of the edition defaults, generated by embed_edition_defaults. + private const string DefaultsBase64 = + "ChMYhAciACoMCAEQAhgCIAMoATACChMY5wciACoMCAIQARgBIAIoATABChMY6AciDAgBEAEYASACKAEwASoAIOYHKOgH"; +} diff --git a/php/ext/google/protobuf/php-upb.c b/php/ext/google/protobuf/php-upb.c index bbe14088ee..ca2718562a 100644 --- a/php/ext/google/protobuf/php-upb.c +++ b/php/ext/google/protobuf/php-upb.c @@ -4096,6 +4096,7 @@ void upb_Message_Freeze(upb_Message* msg, const upb_MiniTable* m) { #include +#include // Must be last. @@ -4255,14 +4256,336 @@ bool upb_Message_IsEqual(const upb_Message* msg1, const upb_Message* msg2, if (!(options & kUpb_CompareOption_IncludeUnknownFields)) return true; - // Check the unknown fields. - size_t usize1, usize2; - const char* uf1 = upb_Message_GetUnknown(msg1, &usize1); - const char* uf2 = upb_Message_GetUnknown(msg2, &usize2); - // The wire encoder enforces a maximum depth of 100 so we match that here. - return UPB_PRIVATE(_upb_Message_UnknownFieldsAreEqual)( - uf1, usize1, uf2, usize2, 100) == kUpb_UnknownCompareResult_Equal; + return UPB_PRIVATE(_upb_Message_UnknownFieldsAreEqual)(msg1, msg2, 100) == + kUpb_UnknownCompareResult_Equal; +} + + +#include +#include + + +// 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_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 = UPB_MAX(4, old * 2); + + *base = upb_Arena_Realloc(ctx->arena, *base, old * sizeof(**base), + new * sizeof(**base)); + 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, ptr1, (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) { + const int oldsize = ctx->tmp_size * sizeof(*ctx->tmp); + ctx->tmp_size = UPB_MAX(8, ctx->tmp_size); + while (ctx->tmp_size < fields->size) ctx->tmp_size *= 2; + const int newsize = ctx->tmp_size * sizeof(*ctx->tmp); + ctx->tmp = upb_grealloc(ctx->tmp, oldsize, newsize); + } + 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; + while (!upb_EpsCopyInputStream_IsDone(&ctx->stream, &ptr)) { + uint32_t tag; + ptr = upb_WireReader_ReadTag(ptr, &tag); + 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); + break; + case kUpb_WireType_64Bit: + ptr = upb_WireReader_ReadFixed64(ptr, &field->data.uint64); + break; + case kUpb_WireType_32Bit: + ptr = upb_WireReader_ReadFixed32(ptr, &field->data.uint32); + break; + case kUpb_WireType_Delimited: { + int size; + ptr = upb_WireReader_ReadSize(ptr, &size); + const char* s_ptr = ptr; + ptr = upb_EpsCopyInputStream_ReadStringAliased(&ctx->stream, &s_ptr, + size); + field->data.delimited.data = s_ptr; + field->data.delimited.size = 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_StringView view; + while (upb_Message_NextUnknown(msg, &view, &iter)) { + upb_EpsCopyInputStream_Init(&ctx->stream, &view.data, view.size, true); + upb_CombineUnknownFields(ctx, &builder, &view.data); + UPB_ASSERT(upb_EpsCopyInputStream_IsDone(&ctx->stream, &view.data) && + !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 { + ret = ctx->status; + UPB_ASSERT(ret != kUpb_UnknownCompareResult_Equal); + } + + upb_Arena_Free(ctx->arena); + upb_gfree(ctx->tmp); + return ret; +} + +upb_UnknownCompareResult UPB_PRIVATE(_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; + + return upb_UnknownField_Compare(&ctx, msg1, msg2); } @@ -12032,282 +12355,6 @@ int upb_Unicode_ToUTF8(uint32_t cp, char* out) { } -#include - - -// 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_Arena* arena; - upb_UnknownField* tmp; - size_t tmp_size; - int depth; - upb_UnknownCompareResult status; - jmp_buf err; -} upb_UnknownField_Context; - -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 = UPB_MAX(4, old * 2); - - *base = upb_Arena_Realloc(ctx->arena, *base, old * sizeof(**base), - new * sizeof(**base)); - 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, ptr1, (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) { - const int oldsize = ctx->tmp_size * sizeof(*ctx->tmp); - ctx->tmp_size = UPB_MAX(8, ctx->tmp_size); - while (ctx->tmp_size < fields->size) ctx->tmp_size *= 2; - const int newsize = ctx->tmp_size * sizeof(*ctx->tmp); - ctx->tmp = upb_grealloc(ctx->tmp, oldsize, newsize); - } - upb_UnknownFields_SortRecursive(fields->fields, 0, fields->size, ctx->tmp); -} - -static upb_UnknownFields* upb_UnknownFields_DoBuild( - upb_UnknownField_Context* ctx, const char** buf) { - upb_UnknownField* arr_base = NULL; - upb_UnknownField* arr_ptr = NULL; - upb_UnknownField* arr_end = NULL; - const char* ptr = *buf; - uint32_t last_tag = 0; - bool sorted = true; - while (!upb_EpsCopyInputStream_IsDone(&ctx->stream, &ptr)) { - uint32_t tag; - ptr = upb_WireReader_ReadTag(ptr, &tag); - 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); - break; - case kUpb_WireType_64Bit: - ptr = upb_WireReader_ReadFixed64(ptr, &field->data.uint64); - break; - case kUpb_WireType_32Bit: - ptr = upb_WireReader_ReadFixed32(ptr, &field->data.uint32); - break; - case kUpb_WireType_Delimited: { - int size; - ptr = upb_WireReader_ReadSize(ptr, &size); - const char* s_ptr = ptr; - ptr = upb_EpsCopyInputStream_ReadStringAliased(&ctx->stream, &s_ptr, - size); - field->data.delimited.data = s_ptr; - field->data.delimited.size = 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_DoBuild(ctx, &ptr); - ctx->depth++; - break; - default: - UPB_UNREACHABLE(); - } - } - - *buf = ptr; - upb_UnknownFields* ret = upb_Arena_Malloc(ctx->arena, sizeof(*ret)); - if (!ret) upb_UnknownFields_OutOfMemory(ctx); - ret->fields = arr_base; - ret->size = arr_ptr - arr_base; - ret->capacity = arr_end - arr_base; - if (!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_Build(upb_UnknownField_Context* ctx, - const char* ptr, - size_t size) { - upb_EpsCopyInputStream_Init(&ctx->stream, &ptr, size, true); - upb_UnknownFields* fields = upb_UnknownFields_DoBuild(ctx, &ptr); - UPB_ASSERT(upb_EpsCopyInputStream_IsDone(&ctx->stream, &ptr) && - !upb_EpsCopyInputStream_IsError(&ctx->stream)); - 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 char* buf1, size_t size1, - const char* buf2, size_t size2) { - 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, buf1, size1); - upb_UnknownFields* uf2 = upb_UnknownFields_Build(ctx, buf2, size2); - - // 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 char* const buf1, - const size_t size1, const char* const buf2, const size_t size2) { - upb_UnknownCompareResult ret; - if (UPB_SETJMP(ctx->err) == 0) { - ret = upb_UnknownField_DoCompare(ctx, buf1, size1, buf2, size2); - } else { - ret = ctx->status; - UPB_ASSERT(ret != kUpb_UnknownCompareResult_Equal); - } - - upb_Arena_Free(ctx->arena); - upb_gfree(ctx->tmp); - return ret; -} - -upb_UnknownCompareResult UPB_PRIVATE(_upb_Message_UnknownFieldsAreEqual)( - const char* buf1, size_t size1, const char* buf2, size_t size2, - int max_depth) { - if (size1 == 0 && size2 == 0) return kUpb_UnknownCompareResult_Equal; - if (size1 == 0 || size2 == 0) return kUpb_UnknownCompareResult_NotEqual; - if (memcmp(buf1, buf2, size1) == 0) return kUpb_UnknownCompareResult_Equal; - - 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; - - return upb_UnknownField_Compare(&ctx, buf1, size1, buf2, size2); -} - - #include diff --git a/php/ext/google/protobuf/php-upb.h b/php/ext/google/protobuf/php-upb.h index 5882d6e698..dada045adf 100644 --- a/php/ext/google/protobuf/php-upb.h +++ b/php/ext/google/protobuf/php-upb.h @@ -13847,8 +13847,7 @@ typedef enum { } upb_UnknownCompareResult; upb_UnknownCompareResult UPB_PRIVATE(_upb_Message_UnknownFieldsAreEqual)( - const char* buf1, size_t size1, const char* buf2, size_t size2, - int max_depth); + const upb_Message* msg1, const upb_Message* msg2, int max_depth); #ifdef __cplusplus } /* extern "C" */ @@ -13880,6 +13879,236 @@ bool UPB_PRIVATE(_upb_Message_NextExtension)( size_t* iter); #endif // THIRD_PARTY_UPB_UPB_MESSAGE_INTERNAL_ITERATOR_H_ +#ifndef UPB_WIRE_READER_H_ +#define UPB_WIRE_READER_H_ + + +#ifndef UPB_WIRE_INTERNAL_READER_H_ +#define UPB_WIRE_INTERNAL_READER_H_ + +// Must be last. + +#define kUpb_WireReader_WireTypeBits 3 +#define kUpb_WireReader_WireTypeMask 7 + +typedef struct { + const char* ptr; + uint64_t val; +} UPB_PRIVATE(_upb_WireReader_LongVarint); + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_PRIVATE(_upb_WireReader_LongVarint) +UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(const char* ptr, uint64_t val); + +UPB_FORCEINLINE const char* UPB_PRIVATE(_upb_WireReader_ReadVarint)( + const char* ptr, uint64_t* val, int maxlen, uint64_t maxval) { + uint64_t byte = (uint8_t)*ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = (uint32_t)byte; + return ptr + 1; + } + const char* start = ptr; + UPB_PRIVATE(_upb_WireReader_LongVarint) + res = UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(ptr, byte); + if (!res.ptr || (maxlen < 10 && res.ptr - start > maxlen) || + res.val > maxval) { + return NULL; // Malformed. + } + *val = res.val; + return res.ptr; +} + +UPB_API_INLINE uint32_t upb_WireReader_GetFieldNumber(uint32_t tag) { + return tag >> kUpb_WireReader_WireTypeBits; +} + +UPB_API_INLINE uint8_t upb_WireReader_GetWireType(uint32_t tag) { + return tag & kUpb_WireReader_WireTypeMask; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_WIRE_INTERNAL_READER_H_ + +#ifndef UPB_WIRE_TYPES_H_ +#define UPB_WIRE_TYPES_H_ + +// A list of types as they are encoded on the wire. +typedef enum { + kUpb_WireType_Varint = 0, + kUpb_WireType_64Bit = 1, + kUpb_WireType_Delimited = 2, + kUpb_WireType_StartGroup = 3, + kUpb_WireType_EndGroup = 4, + kUpb_WireType_32Bit = 5 +} upb_WireType; + +#endif /* UPB_WIRE_TYPES_H_ */ + +// Must be last. + +// The upb_WireReader interface is suitable for general-purpose parsing of +// protobuf binary wire format. It is designed to be used along with +// upb_EpsCopyInputStream for buffering, and all parsing routines in this file +// assume that at least kUpb_EpsCopyInputStream_SlopBytes worth of data is +// available to read without any bounds checks. + +#ifdef __cplusplus +extern "C" { +#endif + +// Parses a tag into `tag`, and returns a pointer past the end of the tag, or +// NULL if there was an error in the tag data. +// +// REQUIRES: there must be at least 10 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_FORCEINLINE const char* upb_WireReader_ReadTag(const char* ptr, + uint32_t* tag) { + uint64_t val; + ptr = UPB_PRIVATE(_upb_WireReader_ReadVarint)(ptr, &val, 5, UINT32_MAX); + if (!ptr) return NULL; + *tag = val; + return ptr; +} + +// Given a tag, returns the field number. +UPB_API_INLINE uint32_t upb_WireReader_GetFieldNumber(uint32_t tag); + +// Given a tag, returns the wire type. +UPB_API_INLINE uint8_t upb_WireReader_GetWireType(uint32_t tag); + +UPB_INLINE const char* upb_WireReader_ReadVarint(const char* ptr, + uint64_t* val) { + return UPB_PRIVATE(_upb_WireReader_ReadVarint)(ptr, val, 10, UINT64_MAX); +} + +// Skips data for a varint, returning a pointer past the end of the varint, or +// NULL if there was an error in the varint data. +// +// REQUIRES: there must be at least 10 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_INLINE const char* upb_WireReader_SkipVarint(const char* ptr) { + uint64_t val; + return upb_WireReader_ReadVarint(ptr, &val); +} + +// Reads a varint indicating the size of a delimited field into `size`, or +// NULL if there was an error in the varint data. +// +// REQUIRES: there must be at least 10 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_INLINE const char* upb_WireReader_ReadSize(const char* ptr, int* size) { + uint64_t size64; + ptr = upb_WireReader_ReadVarint(ptr, &size64); + if (!ptr || size64 >= INT32_MAX) return NULL; + *size = size64; + return ptr; +} + +// Reads a fixed32 field, performing byte swapping if necessary. +// +// REQUIRES: there must be at least 4 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_INLINE const char* upb_WireReader_ReadFixed32(const char* ptr, void* val) { + uint32_t uval; + memcpy(&uval, ptr, 4); + uval = upb_BigEndian32(uval); + memcpy(val, &uval, 4); + return ptr + 4; +} + +// Reads a fixed64 field, performing byte swapping if necessary. +// +// REQUIRES: there must be at least 4 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_INLINE const char* upb_WireReader_ReadFixed64(const char* ptr, void* val) { + uint64_t uval; + memcpy(&uval, ptr, 8); + uval = upb_BigEndian64(uval); + memcpy(val, &uval, 8); + return ptr + 8; +} + +const char* UPB_PRIVATE(_upb_WireReader_SkipGroup)( + const char* ptr, uint32_t tag, int depth_limit, + upb_EpsCopyInputStream* stream); + +// Skips data for a group, returning a pointer past the end of the group, or +// NULL if there was an error parsing the group. The `tag` argument should be +// the start group tag that begins the group. The `depth_limit` argument +// indicates how many levels of recursion the group is allowed to have before +// reporting a parse error (this limit exists to protect against stack +// overflow). +// +// TODO: evaluate how the depth_limit should be specified. Do users need +// control over this? +UPB_INLINE const char* upb_WireReader_SkipGroup( + const char* ptr, uint32_t tag, upb_EpsCopyInputStream* stream) { + return UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, tag, 100, stream); +} + +UPB_INLINE const char* _upb_WireReader_SkipValue( + const char* ptr, uint32_t tag, int depth_limit, + upb_EpsCopyInputStream* stream) { + switch (upb_WireReader_GetWireType(tag)) { + case kUpb_WireType_Varint: + return upb_WireReader_SkipVarint(ptr); + case kUpb_WireType_32Bit: + return ptr + 4; + case kUpb_WireType_64Bit: + return ptr + 8; + case kUpb_WireType_Delimited: { + int size; + ptr = upb_WireReader_ReadSize(ptr, &size); + if (!ptr) return NULL; + ptr += size; + return ptr; + } + case kUpb_WireType_StartGroup: + return UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, tag, depth_limit, + stream); + case kUpb_WireType_EndGroup: + return NULL; // Should be handled before now. + default: + return NULL; // Unknown wire type. + } +} + +// Skips data for a wire value of any type, returning a pointer past the end of +// the data, or NULL if there was an error parsing the group. The `tag` argument +// should be the tag that was just parsed. The `depth_limit` argument indicates +// how many levels of recursion a group is allowed to have before reporting a +// parse error (this limit exists to protect against stack overflow). +// +// REQUIRES: there must be at least 10 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +// +// TODO: evaluate how the depth_limit should be specified. Do users need +// control over this? +UPB_INLINE const char* upb_WireReader_SkipValue( + const char* ptr, uint32_t tag, upb_EpsCopyInputStream* stream) { + return _upb_WireReader_SkipValue(ptr, tag, 100, stream); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_WIRE_READER_H_ + #ifndef UPB_MESSAGE_COPY_H_ #define UPB_MESSAGE_COPY_H_ @@ -14364,236 +14593,6 @@ UPB_INLINE uint32_t _upb_FastDecoder_LoadTag(const char* ptr) { #endif /* UPB_WIRE_INTERNAL_DECODER_H_ */ - -#ifndef UPB_WIRE_READER_H_ -#define UPB_WIRE_READER_H_ - - -#ifndef UPB_WIRE_INTERNAL_READER_H_ -#define UPB_WIRE_INTERNAL_READER_H_ - -// Must be last. - -#define kUpb_WireReader_WireTypeBits 3 -#define kUpb_WireReader_WireTypeMask 7 - -typedef struct { - const char* ptr; - uint64_t val; -} UPB_PRIVATE(_upb_WireReader_LongVarint); - -#ifdef __cplusplus -extern "C" { -#endif - -UPB_PRIVATE(_upb_WireReader_LongVarint) -UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(const char* ptr, uint64_t val); - -UPB_FORCEINLINE const char* UPB_PRIVATE(_upb_WireReader_ReadVarint)( - const char* ptr, uint64_t* val, int maxlen, uint64_t maxval) { - uint64_t byte = (uint8_t)*ptr; - if (UPB_LIKELY((byte & 0x80) == 0)) { - *val = (uint32_t)byte; - return ptr + 1; - } - const char* start = ptr; - UPB_PRIVATE(_upb_WireReader_LongVarint) - res = UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(ptr, byte); - if (!res.ptr || (maxlen < 10 && res.ptr - start > maxlen) || - res.val > maxval) { - return NULL; // Malformed. - } - *val = res.val; - return res.ptr; -} - -UPB_API_INLINE uint32_t upb_WireReader_GetFieldNumber(uint32_t tag) { - return tag >> kUpb_WireReader_WireTypeBits; -} - -UPB_API_INLINE uint8_t upb_WireReader_GetWireType(uint32_t tag) { - return tag & kUpb_WireReader_WireTypeMask; -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif // UPB_WIRE_INTERNAL_READER_H_ - -#ifndef UPB_WIRE_TYPES_H_ -#define UPB_WIRE_TYPES_H_ - -// A list of types as they are encoded on the wire. -typedef enum { - kUpb_WireType_Varint = 0, - kUpb_WireType_64Bit = 1, - kUpb_WireType_Delimited = 2, - kUpb_WireType_StartGroup = 3, - kUpb_WireType_EndGroup = 4, - kUpb_WireType_32Bit = 5 -} upb_WireType; - -#endif /* UPB_WIRE_TYPES_H_ */ - -// Must be last. - -// The upb_WireReader interface is suitable for general-purpose parsing of -// protobuf binary wire format. It is designed to be used along with -// upb_EpsCopyInputStream for buffering, and all parsing routines in this file -// assume that at least kUpb_EpsCopyInputStream_SlopBytes worth of data is -// available to read without any bounds checks. - -#ifdef __cplusplus -extern "C" { -#endif - -// Parses a tag into `tag`, and returns a pointer past the end of the tag, or -// NULL if there was an error in the tag data. -// -// REQUIRES: there must be at least 10 bytes of data available at `ptr`. -// Bounds checks must be performed before calling this function, preferably -// by calling upb_EpsCopyInputStream_IsDone(). -UPB_FORCEINLINE const char* upb_WireReader_ReadTag(const char* ptr, - uint32_t* tag) { - uint64_t val; - ptr = UPB_PRIVATE(_upb_WireReader_ReadVarint)(ptr, &val, 5, UINT32_MAX); - if (!ptr) return NULL; - *tag = val; - return ptr; -} - -// Given a tag, returns the field number. -UPB_API_INLINE uint32_t upb_WireReader_GetFieldNumber(uint32_t tag); - -// Given a tag, returns the wire type. -UPB_API_INLINE uint8_t upb_WireReader_GetWireType(uint32_t tag); - -UPB_INLINE const char* upb_WireReader_ReadVarint(const char* ptr, - uint64_t* val) { - return UPB_PRIVATE(_upb_WireReader_ReadVarint)(ptr, val, 10, UINT64_MAX); -} - -// Skips data for a varint, returning a pointer past the end of the varint, or -// NULL if there was an error in the varint data. -// -// REQUIRES: there must be at least 10 bytes of data available at `ptr`. -// Bounds checks must be performed before calling this function, preferably -// by calling upb_EpsCopyInputStream_IsDone(). -UPB_INLINE const char* upb_WireReader_SkipVarint(const char* ptr) { - uint64_t val; - return upb_WireReader_ReadVarint(ptr, &val); -} - -// Reads a varint indicating the size of a delimited field into `size`, or -// NULL if there was an error in the varint data. -// -// REQUIRES: there must be at least 10 bytes of data available at `ptr`. -// Bounds checks must be performed before calling this function, preferably -// by calling upb_EpsCopyInputStream_IsDone(). -UPB_INLINE const char* upb_WireReader_ReadSize(const char* ptr, int* size) { - uint64_t size64; - ptr = upb_WireReader_ReadVarint(ptr, &size64); - if (!ptr || size64 >= INT32_MAX) return NULL; - *size = size64; - return ptr; -} - -// Reads a fixed32 field, performing byte swapping if necessary. -// -// REQUIRES: there must be at least 4 bytes of data available at `ptr`. -// Bounds checks must be performed before calling this function, preferably -// by calling upb_EpsCopyInputStream_IsDone(). -UPB_INLINE const char* upb_WireReader_ReadFixed32(const char* ptr, void* val) { - uint32_t uval; - memcpy(&uval, ptr, 4); - uval = upb_BigEndian32(uval); - memcpy(val, &uval, 4); - return ptr + 4; -} - -// Reads a fixed64 field, performing byte swapping if necessary. -// -// REQUIRES: there must be at least 4 bytes of data available at `ptr`. -// Bounds checks must be performed before calling this function, preferably -// by calling upb_EpsCopyInputStream_IsDone(). -UPB_INLINE const char* upb_WireReader_ReadFixed64(const char* ptr, void* val) { - uint64_t uval; - memcpy(&uval, ptr, 8); - uval = upb_BigEndian64(uval); - memcpy(val, &uval, 8); - return ptr + 8; -} - -const char* UPB_PRIVATE(_upb_WireReader_SkipGroup)( - const char* ptr, uint32_t tag, int depth_limit, - upb_EpsCopyInputStream* stream); - -// Skips data for a group, returning a pointer past the end of the group, or -// NULL if there was an error parsing the group. The `tag` argument should be -// the start group tag that begins the group. The `depth_limit` argument -// indicates how many levels of recursion the group is allowed to have before -// reporting a parse error (this limit exists to protect against stack -// overflow). -// -// TODO: evaluate how the depth_limit should be specified. Do users need -// control over this? -UPB_INLINE const char* upb_WireReader_SkipGroup( - const char* ptr, uint32_t tag, upb_EpsCopyInputStream* stream) { - return UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, tag, 100, stream); -} - -UPB_INLINE const char* _upb_WireReader_SkipValue( - const char* ptr, uint32_t tag, int depth_limit, - upb_EpsCopyInputStream* stream) { - switch (upb_WireReader_GetWireType(tag)) { - case kUpb_WireType_Varint: - return upb_WireReader_SkipVarint(ptr); - case kUpb_WireType_32Bit: - return ptr + 4; - case kUpb_WireType_64Bit: - return ptr + 8; - case kUpb_WireType_Delimited: { - int size; - ptr = upb_WireReader_ReadSize(ptr, &size); - if (!ptr) return NULL; - ptr += size; - return ptr; - } - case kUpb_WireType_StartGroup: - return UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, tag, depth_limit, - stream); - case kUpb_WireType_EndGroup: - return NULL; // Should be handled before now. - default: - return NULL; // Unknown wire type. - } -} - -// Skips data for a wire value of any type, returning a pointer past the end of -// the data, or NULL if there was an error parsing the group. The `tag` argument -// should be the tag that was just parsed. The `depth_limit` argument indicates -// how many levels of recursion a group is allowed to have before reporting a -// parse error (this limit exists to protect against stack overflow). -// -// REQUIRES: there must be at least 10 bytes of data available at `ptr`. -// Bounds checks must be performed before calling this function, preferably -// by calling upb_EpsCopyInputStream_IsDone(). -// -// TODO: evaluate how the depth_limit should be specified. Do users need -// control over this? -UPB_INLINE const char* upb_WireReader_SkipValue( - const char* ptr, uint32_t tag, upb_EpsCopyInputStream* stream) { - return _upb_WireReader_SkipValue(ptr, tag, 100, stream); -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif // UPB_WIRE_READER_H_ /* This file was generated by upb_generator from the input file: * * google/protobuf/descriptor.proto diff --git a/ruby/ext/google/protobuf_c/ruby-upb.c b/ruby/ext/google/protobuf_c/ruby-upb.c index 188598f8f1..0cb8b441da 100644 --- a/ruby/ext/google/protobuf_c/ruby-upb.c +++ b/ruby/ext/google/protobuf_c/ruby-upb.c @@ -4096,6 +4096,7 @@ void upb_Message_Freeze(upb_Message* msg, const upb_MiniTable* m) { #include +#include // Must be last. @@ -4255,14 +4256,336 @@ bool upb_Message_IsEqual(const upb_Message* msg1, const upb_Message* msg2, if (!(options & kUpb_CompareOption_IncludeUnknownFields)) return true; - // Check the unknown fields. - size_t usize1, usize2; - const char* uf1 = upb_Message_GetUnknown(msg1, &usize1); - const char* uf2 = upb_Message_GetUnknown(msg2, &usize2); - // The wire encoder enforces a maximum depth of 100 so we match that here. - return UPB_PRIVATE(_upb_Message_UnknownFieldsAreEqual)( - uf1, usize1, uf2, usize2, 100) == kUpb_UnknownCompareResult_Equal; + return UPB_PRIVATE(_upb_Message_UnknownFieldsAreEqual)(msg1, msg2, 100) == + kUpb_UnknownCompareResult_Equal; +} + + +#include +#include + + +// 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_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 = UPB_MAX(4, old * 2); + + *base = upb_Arena_Realloc(ctx->arena, *base, old * sizeof(**base), + new * sizeof(**base)); + 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, ptr1, (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) { + const int oldsize = ctx->tmp_size * sizeof(*ctx->tmp); + ctx->tmp_size = UPB_MAX(8, ctx->tmp_size); + while (ctx->tmp_size < fields->size) ctx->tmp_size *= 2; + const int newsize = ctx->tmp_size * sizeof(*ctx->tmp); + ctx->tmp = upb_grealloc(ctx->tmp, oldsize, newsize); + } + 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; + while (!upb_EpsCopyInputStream_IsDone(&ctx->stream, &ptr)) { + uint32_t tag; + ptr = upb_WireReader_ReadTag(ptr, &tag); + 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); + break; + case kUpb_WireType_64Bit: + ptr = upb_WireReader_ReadFixed64(ptr, &field->data.uint64); + break; + case kUpb_WireType_32Bit: + ptr = upb_WireReader_ReadFixed32(ptr, &field->data.uint32); + break; + case kUpb_WireType_Delimited: { + int size; + ptr = upb_WireReader_ReadSize(ptr, &size); + const char* s_ptr = ptr; + ptr = upb_EpsCopyInputStream_ReadStringAliased(&ctx->stream, &s_ptr, + size); + field->data.delimited.data = s_ptr; + field->data.delimited.size = 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_StringView view; + while (upb_Message_NextUnknown(msg, &view, &iter)) { + upb_EpsCopyInputStream_Init(&ctx->stream, &view.data, view.size, true); + upb_CombineUnknownFields(ctx, &builder, &view.data); + UPB_ASSERT(upb_EpsCopyInputStream_IsDone(&ctx->stream, &view.data) && + !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 { + ret = ctx->status; + UPB_ASSERT(ret != kUpb_UnknownCompareResult_Equal); + } + + upb_Arena_Free(ctx->arena); + upb_gfree(ctx->tmp); + return ret; +} + +upb_UnknownCompareResult UPB_PRIVATE(_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; + + return upb_UnknownField_Compare(&ctx, msg1, msg2); } @@ -11519,282 +11842,6 @@ int upb_Unicode_ToUTF8(uint32_t cp, char* out) { } -#include - - -// 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_Arena* arena; - upb_UnknownField* tmp; - size_t tmp_size; - int depth; - upb_UnknownCompareResult status; - jmp_buf err; -} upb_UnknownField_Context; - -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 = UPB_MAX(4, old * 2); - - *base = upb_Arena_Realloc(ctx->arena, *base, old * sizeof(**base), - new * sizeof(**base)); - 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, ptr1, (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) { - const int oldsize = ctx->tmp_size * sizeof(*ctx->tmp); - ctx->tmp_size = UPB_MAX(8, ctx->tmp_size); - while (ctx->tmp_size < fields->size) ctx->tmp_size *= 2; - const int newsize = ctx->tmp_size * sizeof(*ctx->tmp); - ctx->tmp = upb_grealloc(ctx->tmp, oldsize, newsize); - } - upb_UnknownFields_SortRecursive(fields->fields, 0, fields->size, ctx->tmp); -} - -static upb_UnknownFields* upb_UnknownFields_DoBuild( - upb_UnknownField_Context* ctx, const char** buf) { - upb_UnknownField* arr_base = NULL; - upb_UnknownField* arr_ptr = NULL; - upb_UnknownField* arr_end = NULL; - const char* ptr = *buf; - uint32_t last_tag = 0; - bool sorted = true; - while (!upb_EpsCopyInputStream_IsDone(&ctx->stream, &ptr)) { - uint32_t tag; - ptr = upb_WireReader_ReadTag(ptr, &tag); - 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); - break; - case kUpb_WireType_64Bit: - ptr = upb_WireReader_ReadFixed64(ptr, &field->data.uint64); - break; - case kUpb_WireType_32Bit: - ptr = upb_WireReader_ReadFixed32(ptr, &field->data.uint32); - break; - case kUpb_WireType_Delimited: { - int size; - ptr = upb_WireReader_ReadSize(ptr, &size); - const char* s_ptr = ptr; - ptr = upb_EpsCopyInputStream_ReadStringAliased(&ctx->stream, &s_ptr, - size); - field->data.delimited.data = s_ptr; - field->data.delimited.size = 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_DoBuild(ctx, &ptr); - ctx->depth++; - break; - default: - UPB_UNREACHABLE(); - } - } - - *buf = ptr; - upb_UnknownFields* ret = upb_Arena_Malloc(ctx->arena, sizeof(*ret)); - if (!ret) upb_UnknownFields_OutOfMemory(ctx); - ret->fields = arr_base; - ret->size = arr_ptr - arr_base; - ret->capacity = arr_end - arr_base; - if (!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_Build(upb_UnknownField_Context* ctx, - const char* ptr, - size_t size) { - upb_EpsCopyInputStream_Init(&ctx->stream, &ptr, size, true); - upb_UnknownFields* fields = upb_UnknownFields_DoBuild(ctx, &ptr); - UPB_ASSERT(upb_EpsCopyInputStream_IsDone(&ctx->stream, &ptr) && - !upb_EpsCopyInputStream_IsError(&ctx->stream)); - 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 char* buf1, size_t size1, - const char* buf2, size_t size2) { - 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, buf1, size1); - upb_UnknownFields* uf2 = upb_UnknownFields_Build(ctx, buf2, size2); - - // 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 char* const buf1, - const size_t size1, const char* const buf2, const size_t size2) { - upb_UnknownCompareResult ret; - if (UPB_SETJMP(ctx->err) == 0) { - ret = upb_UnknownField_DoCompare(ctx, buf1, size1, buf2, size2); - } else { - ret = ctx->status; - UPB_ASSERT(ret != kUpb_UnknownCompareResult_Equal); - } - - upb_Arena_Free(ctx->arena); - upb_gfree(ctx->tmp); - return ret; -} - -upb_UnknownCompareResult UPB_PRIVATE(_upb_Message_UnknownFieldsAreEqual)( - const char* buf1, size_t size1, const char* buf2, size_t size2, - int max_depth) { - if (size1 == 0 && size2 == 0) return kUpb_UnknownCompareResult_Equal; - if (size1 == 0 || size2 == 0) return kUpb_UnknownCompareResult_NotEqual; - if (memcmp(buf1, buf2, size1) == 0) return kUpb_UnknownCompareResult_Equal; - - 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; - - return upb_UnknownField_Compare(&ctx, buf1, size1, buf2, size2); -} - - #include diff --git a/ruby/ext/google/protobuf_c/ruby-upb.h b/ruby/ext/google/protobuf_c/ruby-upb.h index c8605816b6..af8d4e30e5 100755 --- a/ruby/ext/google/protobuf_c/ruby-upb.h +++ b/ruby/ext/google/protobuf_c/ruby-upb.h @@ -13849,8 +13849,7 @@ typedef enum { } upb_UnknownCompareResult; upb_UnknownCompareResult UPB_PRIVATE(_upb_Message_UnknownFieldsAreEqual)( - const char* buf1, size_t size1, const char* buf2, size_t size2, - int max_depth); + const upb_Message* msg1, const upb_Message* msg2, int max_depth); #ifdef __cplusplus } /* extern "C" */ @@ -13882,6 +13881,236 @@ bool UPB_PRIVATE(_upb_Message_NextExtension)( size_t* iter); #endif // THIRD_PARTY_UPB_UPB_MESSAGE_INTERNAL_ITERATOR_H_ +#ifndef UPB_WIRE_READER_H_ +#define UPB_WIRE_READER_H_ + + +#ifndef UPB_WIRE_INTERNAL_READER_H_ +#define UPB_WIRE_INTERNAL_READER_H_ + +// Must be last. + +#define kUpb_WireReader_WireTypeBits 3 +#define kUpb_WireReader_WireTypeMask 7 + +typedef struct { + const char* ptr; + uint64_t val; +} UPB_PRIVATE(_upb_WireReader_LongVarint); + +#ifdef __cplusplus +extern "C" { +#endif + +UPB_PRIVATE(_upb_WireReader_LongVarint) +UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(const char* ptr, uint64_t val); + +UPB_FORCEINLINE const char* UPB_PRIVATE(_upb_WireReader_ReadVarint)( + const char* ptr, uint64_t* val, int maxlen, uint64_t maxval) { + uint64_t byte = (uint8_t)*ptr; + if (UPB_LIKELY((byte & 0x80) == 0)) { + *val = (uint32_t)byte; + return ptr + 1; + } + const char* start = ptr; + UPB_PRIVATE(_upb_WireReader_LongVarint) + res = UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(ptr, byte); + if (!res.ptr || (maxlen < 10 && res.ptr - start > maxlen) || + res.val > maxval) { + return NULL; // Malformed. + } + *val = res.val; + return res.ptr; +} + +UPB_API_INLINE uint32_t upb_WireReader_GetFieldNumber(uint32_t tag) { + return tag >> kUpb_WireReader_WireTypeBits; +} + +UPB_API_INLINE uint8_t upb_WireReader_GetWireType(uint32_t tag) { + return tag & kUpb_WireReader_WireTypeMask; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_WIRE_INTERNAL_READER_H_ + +#ifndef UPB_WIRE_TYPES_H_ +#define UPB_WIRE_TYPES_H_ + +// A list of types as they are encoded on the wire. +typedef enum { + kUpb_WireType_Varint = 0, + kUpb_WireType_64Bit = 1, + kUpb_WireType_Delimited = 2, + kUpb_WireType_StartGroup = 3, + kUpb_WireType_EndGroup = 4, + kUpb_WireType_32Bit = 5 +} upb_WireType; + +#endif /* UPB_WIRE_TYPES_H_ */ + +// Must be last. + +// The upb_WireReader interface is suitable for general-purpose parsing of +// protobuf binary wire format. It is designed to be used along with +// upb_EpsCopyInputStream for buffering, and all parsing routines in this file +// assume that at least kUpb_EpsCopyInputStream_SlopBytes worth of data is +// available to read without any bounds checks. + +#ifdef __cplusplus +extern "C" { +#endif + +// Parses a tag into `tag`, and returns a pointer past the end of the tag, or +// NULL if there was an error in the tag data. +// +// REQUIRES: there must be at least 10 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_FORCEINLINE const char* upb_WireReader_ReadTag(const char* ptr, + uint32_t* tag) { + uint64_t val; + ptr = UPB_PRIVATE(_upb_WireReader_ReadVarint)(ptr, &val, 5, UINT32_MAX); + if (!ptr) return NULL; + *tag = val; + return ptr; +} + +// Given a tag, returns the field number. +UPB_API_INLINE uint32_t upb_WireReader_GetFieldNumber(uint32_t tag); + +// Given a tag, returns the wire type. +UPB_API_INLINE uint8_t upb_WireReader_GetWireType(uint32_t tag); + +UPB_INLINE const char* upb_WireReader_ReadVarint(const char* ptr, + uint64_t* val) { + return UPB_PRIVATE(_upb_WireReader_ReadVarint)(ptr, val, 10, UINT64_MAX); +} + +// Skips data for a varint, returning a pointer past the end of the varint, or +// NULL if there was an error in the varint data. +// +// REQUIRES: there must be at least 10 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_INLINE const char* upb_WireReader_SkipVarint(const char* ptr) { + uint64_t val; + return upb_WireReader_ReadVarint(ptr, &val); +} + +// Reads a varint indicating the size of a delimited field into `size`, or +// NULL if there was an error in the varint data. +// +// REQUIRES: there must be at least 10 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_INLINE const char* upb_WireReader_ReadSize(const char* ptr, int* size) { + uint64_t size64; + ptr = upb_WireReader_ReadVarint(ptr, &size64); + if (!ptr || size64 >= INT32_MAX) return NULL; + *size = size64; + return ptr; +} + +// Reads a fixed32 field, performing byte swapping if necessary. +// +// REQUIRES: there must be at least 4 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_INLINE const char* upb_WireReader_ReadFixed32(const char* ptr, void* val) { + uint32_t uval; + memcpy(&uval, ptr, 4); + uval = upb_BigEndian32(uval); + memcpy(val, &uval, 4); + return ptr + 4; +} + +// Reads a fixed64 field, performing byte swapping if necessary. +// +// REQUIRES: there must be at least 4 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +UPB_INLINE const char* upb_WireReader_ReadFixed64(const char* ptr, void* val) { + uint64_t uval; + memcpy(&uval, ptr, 8); + uval = upb_BigEndian64(uval); + memcpy(val, &uval, 8); + return ptr + 8; +} + +const char* UPB_PRIVATE(_upb_WireReader_SkipGroup)( + const char* ptr, uint32_t tag, int depth_limit, + upb_EpsCopyInputStream* stream); + +// Skips data for a group, returning a pointer past the end of the group, or +// NULL if there was an error parsing the group. The `tag` argument should be +// the start group tag that begins the group. The `depth_limit` argument +// indicates how many levels of recursion the group is allowed to have before +// reporting a parse error (this limit exists to protect against stack +// overflow). +// +// TODO: evaluate how the depth_limit should be specified. Do users need +// control over this? +UPB_INLINE const char* upb_WireReader_SkipGroup( + const char* ptr, uint32_t tag, upb_EpsCopyInputStream* stream) { + return UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, tag, 100, stream); +} + +UPB_INLINE const char* _upb_WireReader_SkipValue( + const char* ptr, uint32_t tag, int depth_limit, + upb_EpsCopyInputStream* stream) { + switch (upb_WireReader_GetWireType(tag)) { + case kUpb_WireType_Varint: + return upb_WireReader_SkipVarint(ptr); + case kUpb_WireType_32Bit: + return ptr + 4; + case kUpb_WireType_64Bit: + return ptr + 8; + case kUpb_WireType_Delimited: { + int size; + ptr = upb_WireReader_ReadSize(ptr, &size); + if (!ptr) return NULL; + ptr += size; + return ptr; + } + case kUpb_WireType_StartGroup: + return UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, tag, depth_limit, + stream); + case kUpb_WireType_EndGroup: + return NULL; // Should be handled before now. + default: + return NULL; // Unknown wire type. + } +} + +// Skips data for a wire value of any type, returning a pointer past the end of +// the data, or NULL if there was an error parsing the group. The `tag` argument +// should be the tag that was just parsed. The `depth_limit` argument indicates +// how many levels of recursion a group is allowed to have before reporting a +// parse error (this limit exists to protect against stack overflow). +// +// REQUIRES: there must be at least 10 bytes of data available at `ptr`. +// Bounds checks must be performed before calling this function, preferably +// by calling upb_EpsCopyInputStream_IsDone(). +// +// TODO: evaluate how the depth_limit should be specified. Do users need +// control over this? +UPB_INLINE const char* upb_WireReader_SkipValue( + const char* ptr, uint32_t tag, upb_EpsCopyInputStream* stream) { + return _upb_WireReader_SkipValue(ptr, tag, 100, stream); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif // UPB_WIRE_READER_H_ + #ifndef UPB_MESSAGE_COPY_H_ #define UPB_MESSAGE_COPY_H_ @@ -14367,236 +14596,6 @@ UPB_INLINE uint32_t _upb_FastDecoder_LoadTag(const char* ptr) { #endif /* UPB_WIRE_INTERNAL_DECODER_H_ */ -#ifndef UPB_WIRE_READER_H_ -#define UPB_WIRE_READER_H_ - - -#ifndef UPB_WIRE_INTERNAL_READER_H_ -#define UPB_WIRE_INTERNAL_READER_H_ - -// Must be last. - -#define kUpb_WireReader_WireTypeBits 3 -#define kUpb_WireReader_WireTypeMask 7 - -typedef struct { - const char* ptr; - uint64_t val; -} UPB_PRIVATE(_upb_WireReader_LongVarint); - -#ifdef __cplusplus -extern "C" { -#endif - -UPB_PRIVATE(_upb_WireReader_LongVarint) -UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(const char* ptr, uint64_t val); - -UPB_FORCEINLINE const char* UPB_PRIVATE(_upb_WireReader_ReadVarint)( - const char* ptr, uint64_t* val, int maxlen, uint64_t maxval) { - uint64_t byte = (uint8_t)*ptr; - if (UPB_LIKELY((byte & 0x80) == 0)) { - *val = (uint32_t)byte; - return ptr + 1; - } - const char* start = ptr; - UPB_PRIVATE(_upb_WireReader_LongVarint) - res = UPB_PRIVATE(_upb_WireReader_ReadLongVarint)(ptr, byte); - if (!res.ptr || (maxlen < 10 && res.ptr - start > maxlen) || - res.val > maxval) { - return NULL; // Malformed. - } - *val = res.val; - return res.ptr; -} - -UPB_API_INLINE uint32_t upb_WireReader_GetFieldNumber(uint32_t tag) { - return tag >> kUpb_WireReader_WireTypeBits; -} - -UPB_API_INLINE uint8_t upb_WireReader_GetWireType(uint32_t tag) { - return tag & kUpb_WireReader_WireTypeMask; -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif // UPB_WIRE_INTERNAL_READER_H_ - -#ifndef UPB_WIRE_TYPES_H_ -#define UPB_WIRE_TYPES_H_ - -// A list of types as they are encoded on the wire. -typedef enum { - kUpb_WireType_Varint = 0, - kUpb_WireType_64Bit = 1, - kUpb_WireType_Delimited = 2, - kUpb_WireType_StartGroup = 3, - kUpb_WireType_EndGroup = 4, - kUpb_WireType_32Bit = 5 -} upb_WireType; - -#endif /* UPB_WIRE_TYPES_H_ */ - -// Must be last. - -// The upb_WireReader interface is suitable for general-purpose parsing of -// protobuf binary wire format. It is designed to be used along with -// upb_EpsCopyInputStream for buffering, and all parsing routines in this file -// assume that at least kUpb_EpsCopyInputStream_SlopBytes worth of data is -// available to read without any bounds checks. - -#ifdef __cplusplus -extern "C" { -#endif - -// Parses a tag into `tag`, and returns a pointer past the end of the tag, or -// NULL if there was an error in the tag data. -// -// REQUIRES: there must be at least 10 bytes of data available at `ptr`. -// Bounds checks must be performed before calling this function, preferably -// by calling upb_EpsCopyInputStream_IsDone(). -UPB_FORCEINLINE const char* upb_WireReader_ReadTag(const char* ptr, - uint32_t* tag) { - uint64_t val; - ptr = UPB_PRIVATE(_upb_WireReader_ReadVarint)(ptr, &val, 5, UINT32_MAX); - if (!ptr) return NULL; - *tag = val; - return ptr; -} - -// Given a tag, returns the field number. -UPB_API_INLINE uint32_t upb_WireReader_GetFieldNumber(uint32_t tag); - -// Given a tag, returns the wire type. -UPB_API_INLINE uint8_t upb_WireReader_GetWireType(uint32_t tag); - -UPB_INLINE const char* upb_WireReader_ReadVarint(const char* ptr, - uint64_t* val) { - return UPB_PRIVATE(_upb_WireReader_ReadVarint)(ptr, val, 10, UINT64_MAX); -} - -// Skips data for a varint, returning a pointer past the end of the varint, or -// NULL if there was an error in the varint data. -// -// REQUIRES: there must be at least 10 bytes of data available at `ptr`. -// Bounds checks must be performed before calling this function, preferably -// by calling upb_EpsCopyInputStream_IsDone(). -UPB_INLINE const char* upb_WireReader_SkipVarint(const char* ptr) { - uint64_t val; - return upb_WireReader_ReadVarint(ptr, &val); -} - -// Reads a varint indicating the size of a delimited field into `size`, or -// NULL if there was an error in the varint data. -// -// REQUIRES: there must be at least 10 bytes of data available at `ptr`. -// Bounds checks must be performed before calling this function, preferably -// by calling upb_EpsCopyInputStream_IsDone(). -UPB_INLINE const char* upb_WireReader_ReadSize(const char* ptr, int* size) { - uint64_t size64; - ptr = upb_WireReader_ReadVarint(ptr, &size64); - if (!ptr || size64 >= INT32_MAX) return NULL; - *size = size64; - return ptr; -} - -// Reads a fixed32 field, performing byte swapping if necessary. -// -// REQUIRES: there must be at least 4 bytes of data available at `ptr`. -// Bounds checks must be performed before calling this function, preferably -// by calling upb_EpsCopyInputStream_IsDone(). -UPB_INLINE const char* upb_WireReader_ReadFixed32(const char* ptr, void* val) { - uint32_t uval; - memcpy(&uval, ptr, 4); - uval = upb_BigEndian32(uval); - memcpy(val, &uval, 4); - return ptr + 4; -} - -// Reads a fixed64 field, performing byte swapping if necessary. -// -// REQUIRES: there must be at least 4 bytes of data available at `ptr`. -// Bounds checks must be performed before calling this function, preferably -// by calling upb_EpsCopyInputStream_IsDone(). -UPB_INLINE const char* upb_WireReader_ReadFixed64(const char* ptr, void* val) { - uint64_t uval; - memcpy(&uval, ptr, 8); - uval = upb_BigEndian64(uval); - memcpy(val, &uval, 8); - return ptr + 8; -} - -const char* UPB_PRIVATE(_upb_WireReader_SkipGroup)( - const char* ptr, uint32_t tag, int depth_limit, - upb_EpsCopyInputStream* stream); - -// Skips data for a group, returning a pointer past the end of the group, or -// NULL if there was an error parsing the group. The `tag` argument should be -// the start group tag that begins the group. The `depth_limit` argument -// indicates how many levels of recursion the group is allowed to have before -// reporting a parse error (this limit exists to protect against stack -// overflow). -// -// TODO: evaluate how the depth_limit should be specified. Do users need -// control over this? -UPB_INLINE const char* upb_WireReader_SkipGroup( - const char* ptr, uint32_t tag, upb_EpsCopyInputStream* stream) { - return UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, tag, 100, stream); -} - -UPB_INLINE const char* _upb_WireReader_SkipValue( - const char* ptr, uint32_t tag, int depth_limit, - upb_EpsCopyInputStream* stream) { - switch (upb_WireReader_GetWireType(tag)) { - case kUpb_WireType_Varint: - return upb_WireReader_SkipVarint(ptr); - case kUpb_WireType_32Bit: - return ptr + 4; - case kUpb_WireType_64Bit: - return ptr + 8; - case kUpb_WireType_Delimited: { - int size; - ptr = upb_WireReader_ReadSize(ptr, &size); - if (!ptr) return NULL; - ptr += size; - return ptr; - } - case kUpb_WireType_StartGroup: - return UPB_PRIVATE(_upb_WireReader_SkipGroup)(ptr, tag, depth_limit, - stream); - case kUpb_WireType_EndGroup: - return NULL; // Should be handled before now. - default: - return NULL; // Unknown wire type. - } -} - -// Skips data for a wire value of any type, returning a pointer past the end of -// the data, or NULL if there was an error parsing the group. The `tag` argument -// should be the tag that was just parsed. The `depth_limit` argument indicates -// how many levels of recursion a group is allowed to have before reporting a -// parse error (this limit exists to protect against stack overflow). -// -// REQUIRES: there must be at least 10 bytes of data available at `ptr`. -// Bounds checks must be performed before calling this function, preferably -// by calling upb_EpsCopyInputStream_IsDone(). -// -// TODO: evaluate how the depth_limit should be specified. Do users need -// control over this? -UPB_INLINE const char* upb_WireReader_SkipValue( - const char* ptr, uint32_t tag, upb_EpsCopyInputStream* stream) { - return _upb_WireReader_SkipValue(ptr, tag, 100, stream); -} - -#ifdef __cplusplus -} /* extern "C" */ -#endif - - -#endif // UPB_WIRE_READER_H_ - #ifndef UPB_LEX_STRTOD_H_ #define UPB_LEX_STRTOD_H_