• 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/internal/encode.h"
9 
10 #include <inttypes.h>
11 #include <stddef.h>
12 #include <stdint.h>
13 
14 #include "upb/base/descriptor_constants.h"
15 #include "upb/base/string_view.h"
16 #include "upb/lex/round_trip.h"
17 #include "upb/message/array.h"
18 #include "upb/wire/eps_copy_input_stream.h"
19 #include "upb/wire/reader.h"
20 #include "upb/wire/types.h"
21 
22 // Must be last.
23 #include "upb/port/def.inc"
24 
25 #define CHK(x)      \
26   do {              \
27     if (!(x)) {     \
28       return false; \
29     }               \
30   } while (0)
31 
32 /*
33  * Unknown fields are printed by number.
34  *
35  * 1001: 123
36  * 1002: "hello"
37  * 1006: 0xdeadbeef
38  * 1003: {
39  *   1: 111
40  * }
41  */
UPB_PRIVATE(_upb_TextEncode_Unknown)42 const char* UPB_PRIVATE(_upb_TextEncode_Unknown)(txtenc* e, const char* ptr,
43                                                  upb_EpsCopyInputStream* stream,
44                                                  int groupnum) {
45   // We are guaranteed that the unknown data is valid wire format, and will not
46   // contain tag zero.
47   uint32_t end_group = groupnum > 0
48                            ? ((groupnum << kUpb_WireReader_WireTypeBits) |
49                               kUpb_WireType_EndGroup)
50                            : 0;
51 
52   while (!upb_EpsCopyInputStream_IsDone(stream, &ptr)) {
53     uint32_t tag;
54     CHK(ptr = upb_WireReader_ReadTag(ptr, &tag));
55     if (tag == end_group) return ptr;
56 
57     UPB_PRIVATE(_upb_TextEncode_Indent)(e);
58     UPB_PRIVATE(_upb_TextEncode_Printf)
59     (e, "%d: ", (int)upb_WireReader_GetFieldNumber(tag));
60 
61     switch (upb_WireReader_GetWireType(tag)) {
62       case kUpb_WireType_Varint: {
63         uint64_t val;
64         CHK(ptr = upb_WireReader_ReadVarint(ptr, &val));
65         UPB_PRIVATE(_upb_TextEncode_Printf)(e, "%" PRIu64, val);
66         break;
67       }
68       case kUpb_WireType_32Bit: {
69         uint32_t val;
70         ptr = upb_WireReader_ReadFixed32(ptr, &val);
71         UPB_PRIVATE(_upb_TextEncode_Printf)(e, "0x%08" PRIu32, val);
72         break;
73       }
74       case kUpb_WireType_64Bit: {
75         uint64_t val;
76         ptr = upb_WireReader_ReadFixed64(ptr, &val);
77         UPB_PRIVATE(_upb_TextEncode_Printf)(e, "0x%016" PRIu64, val);
78         break;
79       }
80       case kUpb_WireType_Delimited: {
81         int size;
82         char* start = e->ptr;
83         size_t start_overflow = e->overflow;
84         CHK(ptr = upb_WireReader_ReadSize(ptr, &size));
85         CHK(upb_EpsCopyInputStream_CheckDataSizeAvailable(stream, ptr, size));
86 
87         // Speculatively try to parse as message.
88         UPB_PRIVATE(_upb_TextEncode_PutStr)(e, "{");
89         UPB_PRIVATE(_upb_TextEncode_EndField)(e);
90 
91         // EpsCopyInputStream can't back up, so create a sub-stream for the
92         // speculative parse.
93         upb_EpsCopyInputStream sub_stream;
94         const char* sub_ptr = upb_EpsCopyInputStream_GetAliasedPtr(stream, ptr);
95         upb_EpsCopyInputStream_Init(&sub_stream, &sub_ptr, size, true);
96 
97         e->indent_depth++;
98         if (UPB_PRIVATE(_upb_TextEncode_Unknown)(e, sub_ptr, &sub_stream, -1)) {
99           ptr = upb_EpsCopyInputStream_Skip(stream, ptr, size);
100           e->indent_depth--;
101           UPB_PRIVATE(_upb_TextEncode_Indent)(e);
102           UPB_PRIVATE(_upb_TextEncode_PutStr)(e, "}");
103         } else {
104           // Didn't work out, print as raw bytes.
105           e->indent_depth--;
106           e->ptr = start;
107           e->overflow = start_overflow;
108           const char* str = ptr;
109           ptr = upb_EpsCopyInputStream_ReadString(stream, &str, size, NULL);
110           UPB_ASSERT(ptr);
111           UPB_PRIVATE(_upb_TextEncode_Bytes)
112           (e, (upb_StringView){.data = str, .size = size});
113         }
114         break;
115       }
116       case kUpb_WireType_StartGroup:
117         UPB_PRIVATE(_upb_TextEncode_PutStr)(e, "{");
118         UPB_PRIVATE(_upb_TextEncode_EndField)(e);
119         e->indent_depth++;
120         CHK(ptr = UPB_PRIVATE(_upb_TextEncode_Unknown)(
121                 e, ptr, stream, upb_WireReader_GetFieldNumber(tag)));
122         e->indent_depth--;
123         UPB_PRIVATE(_upb_TextEncode_Indent)(e);
124         UPB_PRIVATE(_upb_TextEncode_PutStr)(e, "}");
125         break;
126       default:
127         return NULL;
128     }
129     UPB_PRIVATE(_upb_TextEncode_EndField)(e);
130   }
131 
132   return end_group == 0 && !upb_EpsCopyInputStream_IsError(stream) ? ptr : NULL;
133 }
134 
135 #undef CHK
136 
UPB_PRIVATE(_upb_TextEncode_Scalar)137 void UPB_PRIVATE(_upb_TextEncode_Scalar)(txtenc* e, upb_MessageValue val,
138                                          upb_CType ctype) {
139   switch (ctype) {
140     case kUpb_CType_Bool:
141       UPB_PRIVATE(_upb_TextEncode_PutStr)(e, val.bool_val ? "true" : "false");
142       break;
143     case kUpb_CType_Float: {
144       char buf[32];
145       _upb_EncodeRoundTripFloat(val.float_val, buf, sizeof(buf));
146       UPB_PRIVATE(_upb_TextEncode_PutStr)(e, buf);
147       break;
148     }
149     case kUpb_CType_Double: {
150       char buf[32];
151       _upb_EncodeRoundTripDouble(val.double_val, buf, sizeof(buf));
152       UPB_PRIVATE(_upb_TextEncode_PutStr)(e, buf);
153       break;
154     }
155     case kUpb_CType_Int32:
156       UPB_PRIVATE(_upb_TextEncode_Printf)(e, "%" PRId32, val.int32_val);
157       break;
158     case kUpb_CType_UInt32:
159       UPB_PRIVATE(_upb_TextEncode_Printf)(e, "%" PRIu32, val.uint32_val);
160       break;
161     case kUpb_CType_Int64:
162       UPB_PRIVATE(_upb_TextEncode_Printf)(e, "%" PRId64, val.int64_val);
163       break;
164     case kUpb_CType_UInt64:
165       UPB_PRIVATE(_upb_TextEncode_Printf)(e, "%" PRIu64, val.uint64_val);
166       break;
167     case kUpb_CType_String:
168       UPB_PRIVATE(_upb_HardenedPrintString)
169       (e, val.str_val.data, val.str_val.size);
170       break;
171     case kUpb_CType_Bytes:
172       UPB_PRIVATE(_upb_TextEncode_Bytes)(e, val.str_val);
173       break;
174     case kUpb_CType_Enum:
175       UPB_ASSERT(false);  // handled separately in each encoder
176       break;
177     default:
178       UPB_UNREACHABLE();
179   }
180 }