1
2
3
4
5 package prototext
6
7 import (
8 "fmt"
9 "strconv"
10 "unicode/utf8"
11
12 "google.golang.org/protobuf/encoding/protowire"
13 "google.golang.org/protobuf/internal/encoding/messageset"
14 "google.golang.org/protobuf/internal/encoding/text"
15 "google.golang.org/protobuf/internal/errors"
16 "google.golang.org/protobuf/internal/flags"
17 "google.golang.org/protobuf/internal/genid"
18 "google.golang.org/protobuf/internal/order"
19 "google.golang.org/protobuf/internal/pragma"
20 "google.golang.org/protobuf/internal/strs"
21 "google.golang.org/protobuf/proto"
22 "google.golang.org/protobuf/reflect/protoreflect"
23 "google.golang.org/protobuf/reflect/protoregistry"
24 )
25
26 const defaultIndent = " "
27
28
29
30
31
32 func Format(m proto.Message) string {
33 return MarshalOptions{Multiline: true}.Format(m)
34 }
35
36
37
38
39 func Marshal(m proto.Message) ([]byte, error) {
40 return MarshalOptions{}.Marshal(m)
41 }
42
43
44 type MarshalOptions struct {
45 pragma.NoUnkeyedLiterals
46
47
48
49
50 Multiline bool
51
52
53
54
55
56 Indent string
57
58
59
60 EmitASCII bool
61
62
63
64
65 allowInvalidUTF8 bool
66
67
68
69
70 AllowPartial bool
71
72
73
74
75 EmitUnknown bool
76
77
78
79 Resolver interface {
80 protoregistry.ExtensionTypeResolver
81 protoregistry.MessageTypeResolver
82 }
83 }
84
85
86
87
88
89 func (o MarshalOptions) Format(m proto.Message) string {
90 if m == nil || !m.ProtoReflect().IsValid() {
91 return "<nil>"
92 }
93 o.allowInvalidUTF8 = true
94 o.AllowPartial = true
95 o.EmitUnknown = true
96 b, _ := o.Marshal(m)
97 return string(b)
98 }
99
100
101
102
103 func (o MarshalOptions) Marshal(m proto.Message) ([]byte, error) {
104 return o.marshal(nil, m)
105 }
106
107
108
109 func (o MarshalOptions) MarshalAppend(b []byte, m proto.Message) ([]byte, error) {
110 return o.marshal(b, m)
111 }
112
113
114
115
116 func (o MarshalOptions) marshal(b []byte, m proto.Message) ([]byte, error) {
117 var delims = [2]byte{'{', '}'}
118
119 if o.Multiline && o.Indent == "" {
120 o.Indent = defaultIndent
121 }
122 if o.Resolver == nil {
123 o.Resolver = protoregistry.GlobalTypes
124 }
125
126 internalEnc, err := text.NewEncoder(b, o.Indent, delims, o.EmitASCII)
127 if err != nil {
128 return nil, err
129 }
130
131
132
133 if m == nil {
134 return b, nil
135 }
136
137 enc := encoder{internalEnc, o}
138 err = enc.marshalMessage(m.ProtoReflect(), false)
139 if err != nil {
140 return nil, err
141 }
142 out := enc.Bytes()
143 if len(o.Indent) > 0 && len(out) > 0 {
144 out = append(out, '\n')
145 }
146 if o.AllowPartial {
147 return out, nil
148 }
149 return out, proto.CheckInitialized(m)
150 }
151
152 type encoder struct {
153 *text.Encoder
154 opts MarshalOptions
155 }
156
157
158 func (e encoder) marshalMessage(m protoreflect.Message, inclDelims bool) error {
159 messageDesc := m.Descriptor()
160 if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) {
161 return errors.New("no support for proto1 MessageSets")
162 }
163
164 if inclDelims {
165 e.StartMessage()
166 defer e.EndMessage()
167 }
168
169
170 if messageDesc.FullName() == genid.Any_message_fullname {
171 if e.marshalAny(m) {
172 return nil
173 }
174
175 }
176
177
178 var err error
179 order.RangeFields(m, order.IndexNameFieldOrder, func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
180 if err = e.marshalField(fd.TextName(), v, fd); err != nil {
181 return false
182 }
183 return true
184 })
185 if err != nil {
186 return err
187 }
188
189
190 if e.opts.EmitUnknown {
191 e.marshalUnknown(m.GetUnknown())
192 }
193
194 return nil
195 }
196
197
198 func (e encoder) marshalField(name string, val protoreflect.Value, fd protoreflect.FieldDescriptor) error {
199 switch {
200 case fd.IsList():
201 return e.marshalList(name, val.List(), fd)
202 case fd.IsMap():
203 return e.marshalMap(name, val.Map(), fd)
204 default:
205 e.WriteName(name)
206 return e.marshalSingular(val, fd)
207 }
208 }
209
210
211
212 func (e encoder) marshalSingular(val protoreflect.Value, fd protoreflect.FieldDescriptor) error {
213 kind := fd.Kind()
214 switch kind {
215 case protoreflect.BoolKind:
216 e.WriteBool(val.Bool())
217
218 case protoreflect.StringKind:
219 s := val.String()
220 if !e.opts.allowInvalidUTF8 && strs.EnforceUTF8(fd) && !utf8.ValidString(s) {
221 return errors.InvalidUTF8(string(fd.FullName()))
222 }
223 e.WriteString(s)
224
225 case protoreflect.Int32Kind, protoreflect.Int64Kind,
226 protoreflect.Sint32Kind, protoreflect.Sint64Kind,
227 protoreflect.Sfixed32Kind, protoreflect.Sfixed64Kind:
228 e.WriteInt(val.Int())
229
230 case protoreflect.Uint32Kind, protoreflect.Uint64Kind,
231 protoreflect.Fixed32Kind, protoreflect.Fixed64Kind:
232 e.WriteUint(val.Uint())
233
234 case protoreflect.FloatKind:
235
236 e.WriteFloat(val.Float(), 32)
237
238 case protoreflect.DoubleKind:
239
240 e.WriteFloat(val.Float(), 64)
241
242 case protoreflect.BytesKind:
243 e.WriteString(string(val.Bytes()))
244
245 case protoreflect.EnumKind:
246 num := val.Enum()
247 if desc := fd.Enum().Values().ByNumber(num); desc != nil {
248 e.WriteLiteral(string(desc.Name()))
249 } else {
250
251 e.WriteInt(int64(num))
252 }
253
254 case protoreflect.MessageKind, protoreflect.GroupKind:
255 return e.marshalMessage(val.Message(), true)
256
257 default:
258 panic(fmt.Sprintf("%v has unknown kind: %v", fd.FullName(), kind))
259 }
260 return nil
261 }
262
263
264 func (e encoder) marshalList(name string, list protoreflect.List, fd protoreflect.FieldDescriptor) error {
265 size := list.Len()
266 for i := 0; i < size; i++ {
267 e.WriteName(name)
268 if err := e.marshalSingular(list.Get(i), fd); err != nil {
269 return err
270 }
271 }
272 return nil
273 }
274
275
276 func (e encoder) marshalMap(name string, mmap protoreflect.Map, fd protoreflect.FieldDescriptor) error {
277 var err error
278 order.RangeEntries(mmap, order.GenericKeyOrder, func(key protoreflect.MapKey, val protoreflect.Value) bool {
279 e.WriteName(name)
280 e.StartMessage()
281 defer e.EndMessage()
282
283 e.WriteName(string(genid.MapEntry_Key_field_name))
284 err = e.marshalSingular(key.Value(), fd.MapKey())
285 if err != nil {
286 return false
287 }
288
289 e.WriteName(string(genid.MapEntry_Value_field_name))
290 err = e.marshalSingular(val, fd.MapValue())
291 if err != nil {
292 return false
293 }
294 return true
295 })
296 return err
297 }
298
299
300
301 func (e encoder) marshalUnknown(b []byte) {
302 const dec = 10
303 const hex = 16
304 for len(b) > 0 {
305 num, wtype, n := protowire.ConsumeTag(b)
306 b = b[n:]
307 e.WriteName(strconv.FormatInt(int64(num), dec))
308
309 switch wtype {
310 case protowire.VarintType:
311 var v uint64
312 v, n = protowire.ConsumeVarint(b)
313 e.WriteUint(v)
314 case protowire.Fixed32Type:
315 var v uint32
316 v, n = protowire.ConsumeFixed32(b)
317 e.WriteLiteral("0x" + strconv.FormatUint(uint64(v), hex))
318 case protowire.Fixed64Type:
319 var v uint64
320 v, n = protowire.ConsumeFixed64(b)
321 e.WriteLiteral("0x" + strconv.FormatUint(v, hex))
322 case protowire.BytesType:
323 var v []byte
324 v, n = protowire.ConsumeBytes(b)
325 e.WriteString(string(v))
326 case protowire.StartGroupType:
327 e.StartMessage()
328 var v []byte
329 v, n = protowire.ConsumeGroup(num, b)
330 e.marshalUnknown(v)
331 e.EndMessage()
332 default:
333 panic(fmt.Sprintf("prototext: error parsing unknown field wire type: %v", wtype))
334 }
335
336 b = b[n:]
337 }
338 }
339
340
341
342 func (e encoder) marshalAny(any protoreflect.Message) bool {
343
344 fds := any.Descriptor().Fields()
345 fdType := fds.ByNumber(genid.Any_TypeUrl_field_number)
346 typeURL := any.Get(fdType).String()
347 mt, err := e.opts.Resolver.FindMessageByURL(typeURL)
348 if err != nil {
349 return false
350 }
351 m := mt.New().Interface()
352
353
354 fdValue := fds.ByNumber(genid.Any_Value_field_number)
355 value := any.Get(fdValue)
356 err = proto.UnmarshalOptions{
357 AllowPartial: true,
358 Resolver: e.opts.Resolver,
359 }.Unmarshal(value.Bytes(), m)
360 if err != nil {
361 return false
362 }
363
364
365
366 pos := e.Snapshot()
367
368
369 e.WriteName("[" + typeURL + "]")
370 err = e.marshalMessage(m.ProtoReflect(), true)
371 if err != nil {
372 e.Reset(pos)
373 return false
374 }
375 return true
376 }
377
View as plain text