mirror of
https://github.com/protocolbuffers/protobuf
synced 2026-08-26 02:23:14 -04:00
202 lines
7.6 KiB
C
202 lines
7.6 KiB
C
// 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/extension.h"
|
|
#include "upb/message/internal/message.h"
|
|
#include "upb/message/internal/types.h"
|
|
#include "upb/mini_table/extension.h"
|
|
#include "upb/wire/encode.h"
|
|
#include "upb/wire/encode_extension.h"
|
|
#include "upb/wire/eps_copy_input_stream.h"
|
|
#include "upb/wire/reader.h"
|
|
|
|
// Must be last.
|
|
#include "upb/port/def.inc"
|
|
|
|
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_MiniTableExtension_Number(ret.unknown.value.extension->ext);
|
|
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;
|
|
}
|