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