1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2024 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/text/debug_string.h"
9
10 #include <inttypes.h>
11 #include <stdarg.h>
12 #include <stddef.h>
13 #include <stdio.h>
14 #include <string.h>
15
16 #include "upb/base/descriptor_constants.h"
17 #include "upb/message/array.h"
18 #include "upb/message/internal/iterator.h"
19 #include "upb/message/internal/map_entry.h"
20 #include "upb/message/internal/map_sorter.h"
21 #include "upb/message/map.h"
22 #include "upb/message/message.h"
23 #include "upb/message/value.h"
24 #include "upb/mini_table/extension.h"
25 #include "upb/mini_table/field.h"
26 #include "upb/mini_table/internal/field.h"
27 #include "upb/mini_table/internal/message.h"
28 #include "upb/mini_table/message.h"
29 #include "upb/text/internal/encode.h"
30 #include "upb/wire/eps_copy_input_stream.h"
31
32 // Must be last.
33 #include "upb/port/def.inc"
34
35 static void _upb_MessageDebugString(txtenc* e, const upb_Message* msg,
36 const upb_MiniTable* mt);
37
_upb_FieldDebugString(txtenc * e,upb_MessageValue val,const upb_MiniTableField * f,const upb_MiniTable * mt,const char * label,const upb_MiniTableExtension * ext)38 static void _upb_FieldDebugString(txtenc* e, upb_MessageValue val,
39 const upb_MiniTableField* f,
40 const upb_MiniTable* mt, const char* label,
41 const upb_MiniTableExtension* ext) {
42 UPB_PRIVATE(_upb_TextEncode_Indent)(e);
43 const upb_CType ctype = upb_MiniTableField_CType(f);
44 const bool is_ext = upb_MiniTableField_IsExtension(f);
45 char number[10]; // A 32-bit integer can hold up to 10 digits.
46 snprintf(number, sizeof(number), "%" PRIu32, upb_MiniTableField_Number(f));
47 // label is to pass down whether we're dealing with a "key" of a map or
48 // a "value" of a map.
49 if (!label) label = number;
50
51 if (is_ext) {
52 UPB_PRIVATE(_upb_TextEncode_Printf)(e, "[%s]", label);
53 } else {
54 UPB_PRIVATE(_upb_TextEncode_Printf)(e, "%s", label);
55 }
56
57 if (ctype == kUpb_CType_Message) {
58 UPB_PRIVATE(_upb_TextEncode_Printf)(e, " {");
59 UPB_PRIVATE(_upb_TextEncode_EndField)(e);
60 e->indent_depth++;
61 const upb_MiniTable* subm = ext ? upb_MiniTableExtension_GetSubMessage(ext)
62 : upb_MiniTable_SubMessage(mt, f);
63 _upb_MessageDebugString(e, val.msg_val, subm);
64 e->indent_depth--;
65 UPB_PRIVATE(_upb_TextEncode_Indent)(e);
66 UPB_PRIVATE(_upb_TextEncode_PutStr)(e, "}");
67 UPB_PRIVATE(_upb_TextEncode_EndField)(e);
68 return;
69 }
70
71 UPB_PRIVATE(_upb_TextEncode_Printf)(e, ": ");
72
73 if (ctype ==
74 kUpb_CType_Enum) { // Enum has to be processed separately because of
75 // divergent behavior between encoders
76 UPB_PRIVATE(_upb_TextEncode_Printf)(e, "%" PRId32, val.int32_val);
77 } else {
78 UPB_PRIVATE(_upb_TextEncode_Scalar)(e, val, ctype);
79 }
80
81 UPB_PRIVATE(_upb_TextEncode_EndField)(e);
82 }
83
84 /*
85 * Arrays print as simple repeated elements, eg.
86 *
87 * 5: 1
88 * 5: 2
89 * 5: 3
90 */
_upb_ArrayDebugString(txtenc * e,const upb_Array * arr,const upb_MiniTableField * f,const upb_MiniTable * mt,const upb_MiniTableExtension * ext)91 static void _upb_ArrayDebugString(txtenc* e, const upb_Array* arr,
92 const upb_MiniTableField* f,
93 const upb_MiniTable* mt,
94 const upb_MiniTableExtension* ext) {
95 for (size_t i = 0, n = upb_Array_Size(arr); i < n; i++) {
96 _upb_FieldDebugString(e, upb_Array_Get(arr, i), f, mt, NULL, ext);
97 }
98 }
99
_upb_MapEntryDebugString(txtenc * e,upb_MessageValue key,upb_MessageValue val,const upb_MiniTableField * f,const upb_MiniTable * mt)100 static void _upb_MapEntryDebugString(txtenc* e, upb_MessageValue key,
101 upb_MessageValue val,
102 const upb_MiniTableField* f,
103 const upb_MiniTable* mt) {
104 const upb_MiniTable* entry = upb_MiniTable_SubMessage(mt, f);
105 const upb_MiniTableField* key_f = upb_MiniTable_MapKey(entry);
106 const upb_MiniTableField* val_f = upb_MiniTable_MapValue(entry);
107
108 UPB_PRIVATE(_upb_TextEncode_Indent)(e);
109 UPB_PRIVATE(_upb_TextEncode_Printf)(e, "%u {", upb_MiniTableField_Number(f));
110 UPB_PRIVATE(_upb_TextEncode_EndField)(e);
111 e->indent_depth++;
112
113 _upb_FieldDebugString(e, key, key_f, entry, "key", NULL);
114 _upb_FieldDebugString(e, val, val_f, entry, "value", NULL);
115
116 e->indent_depth--;
117 UPB_PRIVATE(_upb_TextEncode_Indent)(e);
118 UPB_PRIVATE(_upb_TextEncode_PutStr)(e, "}");
119 UPB_PRIVATE(_upb_TextEncode_EndField)(e);
120 }
121
122 /*
123 * Maps print as messages of key/value, etc.
124 *
125 * 1 {
126 * key: "abc"
127 * value: 123
128 * }
129 * 2 {
130 * key: "def"
131 * value: 456
132 * }
133 */
_upb_MapDebugString(txtenc * e,const upb_Map * map,const upb_MiniTableField * f,const upb_MiniTable * mt)134 static void _upb_MapDebugString(txtenc* e, const upb_Map* map,
135 const upb_MiniTableField* f,
136 const upb_MiniTable* mt) {
137 if (e->options & UPB_TXTENC_NOSORT) {
138 size_t iter = kUpb_Map_Begin;
139 upb_MessageValue key, val;
140 while (upb_Map_Next(map, &key, &val, &iter)) {
141 _upb_MapEntryDebugString(e, key, val, f, mt);
142 }
143 } else {
144 if (upb_Map_Size(map) == 0) return;
145
146 const upb_MiniTable* entry = upb_MiniTable_SubMessage(mt, f);
147 const upb_MiniTableField* key_f = upb_MiniTable_GetFieldByIndex(entry, 0);
148 _upb_sortedmap sorted;
149 upb_MapEntry ent;
150
151 _upb_mapsorter_pushmap(&e->sorter, upb_MiniTableField_Type(key_f), map,
152 &sorted);
153 while (_upb_sortedmap_next(&e->sorter, map, &sorted, &ent)) {
154 upb_MessageValue key, val;
155 memcpy(&key, &ent.k, sizeof(key));
156 memcpy(&val, &ent.v, sizeof(val));
157 _upb_MapEntryDebugString(e, key, val, f, mt);
158 }
159 _upb_mapsorter_popmap(&e->sorter, &sorted);
160 }
161 }
162
_upb_MessageDebugString(txtenc * e,const upb_Message * msg,const upb_MiniTable * mt)163 static void _upb_MessageDebugString(txtenc* e, const upb_Message* msg,
164 const upb_MiniTable* mt) {
165 size_t iter = kUpb_BaseField_Begin;
166 const upb_MiniTableField* f;
167 upb_MessageValue val;
168
169 // Base fields will be printed out first, followed by extension fields, and
170 // finally unknown fields.
171
172 while (UPB_PRIVATE(_upb_Message_NextBaseField)(msg, mt, &f, &val, &iter)) {
173 if (upb_MiniTableField_IsMap(f)) {
174 _upb_MapDebugString(e, val.map_val, f, mt);
175 } else if (upb_MiniTableField_IsArray(f)) {
176 // ext set to NULL as we're not dealing with extensions yet
177 _upb_ArrayDebugString(e, val.array_val, f, mt, NULL);
178 } else {
179 // ext set to NULL as we're not dealing with extensions yet
180 // label set to NULL as we're not currently working with a MapEntry
181 _upb_FieldDebugString(e, val, f, mt, NULL, NULL);
182 }
183 }
184
185 const upb_MiniTableExtension* ext;
186 upb_MessageValue val_ext;
187 iter = kUpb_Extension_Begin;
188 while (
189 UPB_PRIVATE(_upb_Message_NextExtension)(msg, mt, &ext, &val_ext, &iter)) {
190 const upb_MiniTableField* f = &ext->UPB_PRIVATE(field);
191 // It is not sufficient to only pass |f| as we lose valuable information
192 // about sub-messages. It is required that we pass |ext|.
193 if (upb_MiniTableField_IsMap(f)) {
194 UPB_UNREACHABLE(); // Maps cannot be extensions.
195 break;
196 } else if (upb_MiniTableField_IsArray(f)) {
197 _upb_ArrayDebugString(e, val_ext.array_val, f, mt, ext);
198 } else {
199 // label set to NULL as we're not currently working with a MapEntry
200 _upb_FieldDebugString(e, val_ext, f, mt, NULL, ext);
201 }
202 }
203
204 if ((e->options & UPB_TXTENC_SKIPUNKNOWN) == 0) {
205 size_t size;
206 const char* ptr = upb_Message_GetUnknown(msg, &size);
207 if (size != 0) {
208 char* start = e->ptr;
209 upb_EpsCopyInputStream stream;
210 upb_EpsCopyInputStream_Init(&stream, &ptr, size, true);
211 if (!UPB_PRIVATE(_upb_TextEncode_Unknown)(e, ptr, &stream, -1)) {
212 /* Unknown failed to parse, back up and don't print it at all. */
213 e->ptr = start;
214 }
215 }
216 }
217 }
218
upb_DebugString(const upb_Message * msg,const upb_MiniTable * mt,int options,char * buf,size_t size)219 size_t upb_DebugString(const upb_Message* msg, const upb_MiniTable* mt,
220 int options, char* buf, size_t size) {
221 txtenc e;
222
223 e.buf = buf;
224 e.ptr = buf;
225 e.end = UPB_PTRADD(buf, size);
226 e.overflow = 0;
227 e.indent_depth = 0;
228 e.options = options;
229 e.ext_pool = NULL;
230 _upb_mapsorter_init(&e.sorter);
231
232 _upb_MessageDebugString(&e, msg, mt);
233 _upb_mapsorter_destroy(&e.sorter);
234 return UPB_PRIVATE(_upb_TextEncode_Nullz)(&e, size);
235 }
236