1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2023 Google LLC. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7
8 #include "upb/mini_table/extension_registry.h"
9
10 #include <stddef.h>
11 #include <stdint.h>
12 #include <string.h>
13
14 #include "upb/hash/str_table.h"
15 #include "upb/mem/arena.h"
16 #include "upb/mini_table/extension.h"
17 #include "upb/mini_table/message.h"
18
19 // Must be last.
20 #include "upb/port/def.inc"
21
22 #define EXTREG_KEY_SIZE (sizeof(upb_MiniTable*) + sizeof(uint32_t))
23
24 struct upb_ExtensionRegistry {
25 upb_Arena* arena;
26 upb_strtable exts; // Key is upb_MiniTable* concatenated with fieldnum.
27 };
28
extreg_key(char * buf,const upb_MiniTable * l,uint32_t fieldnum)29 static void extreg_key(char* buf, const upb_MiniTable* l, uint32_t fieldnum) {
30 memcpy(buf, &l, sizeof(l));
31 memcpy(buf + sizeof(l), &fieldnum, sizeof(fieldnum));
32 }
33
upb_ExtensionRegistry_New(upb_Arena * arena)34 upb_ExtensionRegistry* upb_ExtensionRegistry_New(upb_Arena* arena) {
35 upb_ExtensionRegistry* r = upb_Arena_Malloc(arena, sizeof(*r));
36 if (!r) return NULL;
37 r->arena = arena;
38 if (!upb_strtable_init(&r->exts, 8, arena)) return NULL;
39 return r;
40 }
41
upb_ExtensionRegistry_Add(upb_ExtensionRegistry * r,const upb_MiniTableExtension * e)42 UPB_API bool upb_ExtensionRegistry_Add(upb_ExtensionRegistry* r,
43 const upb_MiniTableExtension* e) {
44 char buf[EXTREG_KEY_SIZE];
45 extreg_key(buf, e->UPB_PRIVATE(extendee), upb_MiniTableExtension_Number(e));
46 if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, NULL)) return false;
47 return upb_strtable_insert(&r->exts, buf, EXTREG_KEY_SIZE,
48 upb_value_constptr(e), r->arena);
49 }
50
upb_ExtensionRegistry_AddArray(upb_ExtensionRegistry * r,const upb_MiniTableExtension ** e,size_t count)51 bool upb_ExtensionRegistry_AddArray(upb_ExtensionRegistry* r,
52 const upb_MiniTableExtension** e,
53 size_t count) {
54 const upb_MiniTableExtension** start = e;
55 const upb_MiniTableExtension** end = UPB_PTRADD(e, count);
56 for (; e < end; e++) {
57 if (!upb_ExtensionRegistry_Add(r, *e)) goto failure;
58 }
59 return true;
60
61 failure:
62 // Back out the entries previously added.
63 for (end = e, e = start; e < end; e++) {
64 const upb_MiniTableExtension* ext = *e;
65 char buf[EXTREG_KEY_SIZE];
66 extreg_key(buf, ext->UPB_PRIVATE(extendee),
67 upb_MiniTableExtension_Number(ext));
68 upb_strtable_remove2(&r->exts, buf, EXTREG_KEY_SIZE, NULL);
69 }
70 return false;
71 }
72
73 #ifdef UPB_LINKARR_DECLARE
74
75 UPB_LINKARR_DECLARE(upb_AllExts, upb_MiniTableExtension);
76
upb_ExtensionRegistry_AddAllLinkedExtensions(upb_ExtensionRegistry * r)77 bool upb_ExtensionRegistry_AddAllLinkedExtensions(upb_ExtensionRegistry* r) {
78 const upb_MiniTableExtension* start = UPB_LINKARR_START(upb_AllExts);
79 const upb_MiniTableExtension* stop = UPB_LINKARR_STOP(upb_AllExts);
80 for (const upb_MiniTableExtension* p = start; p < stop; p++) {
81 // Windows can introduce zero padding, so we have to skip zeroes.
82 if (upb_MiniTableExtension_Number(p) != 0) {
83 if (!upb_ExtensionRegistry_Add(r, p)) return false;
84 }
85 }
86 return true;
87 }
88
89 #endif // UPB_LINKARR_DECLARE
90
upb_ExtensionRegistry_Lookup(const upb_ExtensionRegistry * r,const upb_MiniTable * t,uint32_t num)91 const upb_MiniTableExtension* upb_ExtensionRegistry_Lookup(
92 const upb_ExtensionRegistry* r, const upb_MiniTable* t, uint32_t num) {
93 char buf[EXTREG_KEY_SIZE];
94 upb_value v;
95 extreg_key(buf, t, num);
96 if (upb_strtable_lookup2(&r->exts, buf, EXTREG_KEY_SIZE, &v)) {
97 return upb_value_getconstptr(v);
98 } else {
99 return NULL;
100 }
101 }
102