• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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