| // Protocol Buffers - Google's data interchange format | |
| // Copyright 2023 Google LLC. 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 | |
| #include "upb/message/message.h" | |
| #include <stdarg.h> | |
| #include <stddef.h> | |
| #include <stdint.h> | |
| #include <string.h> | |
| #include "upb/base/string_view.h" | |
| #include "upb/mem/arena.h" | |
| #include "upb/message/accessors.h" | |
| #include "upb/message/array.h" | |
| #include "upb/message/internal/accessors.h" | |
| #include "upb/message/internal/extension.h" | |
| #include "upb/message/internal/message.h" | |
| #include "upb/message/internal/types.h" | |
| #include "upb/message/map.h" | |
| #include "upb/message/value.h" | |
| #include "upb/mini_table/extension.h" | |
| #include "upb/mini_table/field.h" | |
| #include "upb/mini_table/internal/field.h" | |
| #include "upb/mini_table/message.h" | |
| #include "upb/port/overflow.h" | |
| // Must be last. | |
| #include "upb/port/def.inc" | |
| 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(); // Maps cannot be extensions. | |
| 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; | |
| } |