blob: 7f3b549f9f413de57da4cbfe6e2fb92008ff79b5 [file]
// Protocol Buffers - Google's data interchange format
// Copyright 2026 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/unknown_fields.h"
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "upb/base/string_view.h"
#include "upb/mem/arena.h"
#include "upb/mem/internal/arena.h"
#include "upb/message/internal/message.h"
#include "upb/message/internal/types.h"
// Must be last.
#include "upb/port/def.inc"
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;
}