// 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 #ifndef UPB_MESSAGE_UNKNOWN_FIELDS_H_ #define UPB_MESSAGE_UNKNOWN_FIELDS_H_ #include #include #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" #ifdef __cplusplus extern "C" { #endif // Support iteration over unknown (upb_MessageUnknown*), including unknown // upb_StringView and non-canonical extensions (upb_Extension*). UPB_INLINE bool upb_Message_NextUnknown2(const struct upb_Message* msg, struct upb_MessageUnknown* data, uintptr_t* iter) { const upb_Message_Internal* in = UPB_PRIVATE(_upb_Message_GetInternal)(msg); size_t i = *iter; if (in) { while (i < in->size) { upb_TaggedAuxPtr tagged_ptr = in->aux_data[i++]; if (upb_TaggedAuxPtr_IsUnknownStringView(tagged_ptr)) { data->type = kUpb_MessageUnknownType_StringView; data->value.bytes = *upb_TaggedPtrAux_StringViewRepr(tagged_ptr); *iter = i; return true; } else if (upb_TaggedAuxPtr_IsNonCanonicalExtension(tagged_ptr)) { data->type = kUpb_MessageUnknownType_NonCanonicalExtension; data->value.extension = upb_TaggedAuxPtr_NonCanonicalExtension(tagged_ptr); *iter = i; return true; } } } data->type = kUpb_MessageUnknownType_StringView; data->value.bytes.size = 0; data->value.bytes.data = NULL; *iter = i; return false; } typedef enum { kUpb_FindUnknown_Ok, kUpb_FindUnknown_NotPresent, kUpb_FindUnknown_ParseError, } upb_FindUnknown_Status; typedef struct { upb_FindUnknown_Status status; struct upb_MessageUnknown unknown; uintptr_t iter; } upb_FindUnknownRet2; // Finds first occurrence of unknown data (upb_MessageUnknown) by tag id in // message, including unknown upb_StringView and non-canonical extensions // (upb_Extension*). // // If multiple matching entries exist for the same field number (e.g. both a // raw unknown upb_StringView and a non-canonical extension), this function // returns the one encountered first in internal iteration order (which follows // the order they were added or parsed). // // A depth_limit of zero means to just use the upb default depth limit. upb_FindUnknownRet2 upb_Message_FindUnknown2(const struct upb_Message* msg, uint32_t field_number, int depth_limit); // Removes a segment of unknown data from the message, advancing to the next // segment. Returns false if the removed segment was at the end of the last // chunk. // // This must be done while iterating: // // uintptr_t iter = kUpb_Message_UnknownBegin; // upb_MessageUnknown data; // // Iterate chunks // while (upb_Message_NextUnknown2(msg, &data, &iter)) { // // Iterate within a chunk, deleting ranges // while (ShouldDeleteSubSegment(&data)) { // // Data now points to the region to be deleted // switch (upb_Message_DeleteUnknown2(msg, &data, &iter)) { // case kUpb_Message_DeleteUnknown_DeletedLast: return ok; // case kUpb_Message_DeleteUnknown_IterUpdated: break; // // If DeleteUnknown returned kUpb_Message_DeleteUnknown_IterUpdated, // // then data now points to the remaining unknown fields after the // // region that was just deleted. // case kUpb_Message_DeleteUnknown_AllocFail: return err; // } // } // } // // The range given in `data` must be contained inside the most recently // returned region. // // Support deletion of unknown (upb_MessageUnknown*), including unknown // upb_StringView and non-canonical extensions (upb_Extension*). UPB_NODISCARD upb_Message_DeleteUnknownStatus upb_Message_DeleteUnknown2( struct upb_Message* msg, struct upb_MessageUnknown* data, uintptr_t* iter, struct upb_Arena* arena); #ifdef __cplusplus } /* extern "C" */ #endif #include "upb/port/undef.inc" #endif /* UPB_MESSAGE_UNKNOWN_FIELDS_H_ */