blob: b53805056a9a8176ed61b915ae79603894ca67fc [file] [log] [blame]
khenaidoo7d3c5582021-08-11 18:09:44 -04001// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package prototext
6
7import (
8 "fmt"
9 "unicode/utf8"
10
11 "google.golang.org/protobuf/internal/encoding/messageset"
12 "google.golang.org/protobuf/internal/encoding/text"
13 "google.golang.org/protobuf/internal/errors"
14 "google.golang.org/protobuf/internal/flags"
15 "google.golang.org/protobuf/internal/genid"
16 "google.golang.org/protobuf/internal/pragma"
17 "google.golang.org/protobuf/internal/set"
18 "google.golang.org/protobuf/internal/strs"
19 "google.golang.org/protobuf/proto"
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +053020 "google.golang.org/protobuf/reflect/protoreflect"
khenaidoo7d3c5582021-08-11 18:09:44 -040021 "google.golang.org/protobuf/reflect/protoregistry"
22)
23
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +053024// Unmarshal reads the given []byte into the given [proto.Message].
khenaidoo7d3c5582021-08-11 18:09:44 -040025// The provided message must be mutable (e.g., a non-nil pointer to a message).
26func Unmarshal(b []byte, m proto.Message) error {
27 return UnmarshalOptions{}.Unmarshal(b, m)
28}
29
30// UnmarshalOptions is a configurable textproto format unmarshaler.
31type UnmarshalOptions struct {
32 pragma.NoUnkeyedLiterals
33
34 // AllowPartial accepts input for messages that will result in missing
35 // required fields. If AllowPartial is false (the default), Unmarshal will
36 // return error if there are any missing required fields.
37 AllowPartial bool
38
39 // DiscardUnknown specifies whether to ignore unknown fields when parsing.
40 // An unknown field is any field whose field name or field number does not
41 // resolve to any known or extension field in the message.
42 // By default, unmarshal rejects unknown fields as an error.
43 DiscardUnknown bool
44
45 // Resolver is used for looking up types when unmarshaling
46 // google.protobuf.Any messages or extension fields.
47 // If nil, this defaults to using protoregistry.GlobalTypes.
48 Resolver interface {
49 protoregistry.MessageTypeResolver
50 protoregistry.ExtensionTypeResolver
51 }
52}
53
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +053054// Unmarshal reads the given []byte and populates the given [proto.Message]
khenaidoo7d3c5582021-08-11 18:09:44 -040055// using options in the UnmarshalOptions object.
56// The provided message must be mutable (e.g., a non-nil pointer to a message).
57func (o UnmarshalOptions) Unmarshal(b []byte, m proto.Message) error {
58 return o.unmarshal(b, m)
59}
60
61// unmarshal is a centralized function that all unmarshal operations go through.
62// For profiling purposes, avoid changing the name of this function or
63// introducing other code paths for unmarshal that do not go through this.
64func (o UnmarshalOptions) unmarshal(b []byte, m proto.Message) error {
65 proto.Reset(m)
66
67 if o.Resolver == nil {
68 o.Resolver = protoregistry.GlobalTypes
69 }
70
71 dec := decoder{text.NewDecoder(b), o}
72 if err := dec.unmarshalMessage(m.ProtoReflect(), false); err != nil {
73 return err
74 }
75 if o.AllowPartial {
76 return nil
77 }
78 return proto.CheckInitialized(m)
79}
80
81type decoder struct {
82 *text.Decoder
83 opts UnmarshalOptions
84}
85
86// newError returns an error object with position info.
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +053087func (d decoder) newError(pos int, f string, x ...any) error {
khenaidoo7d3c5582021-08-11 18:09:44 -040088 line, column := d.Position(pos)
89 head := fmt.Sprintf("(line %d:%d): ", line, column)
90 return errors.New(head+f, x...)
91}
92
93// unexpectedTokenError returns a syntax error for the given unexpected token.
94func (d decoder) unexpectedTokenError(tok text.Token) error {
95 return d.syntaxError(tok.Pos(), "unexpected token: %s", tok.RawString())
96}
97
98// syntaxError returns a syntax error for given position.
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +053099func (d decoder) syntaxError(pos int, f string, x ...any) error {
khenaidoo7d3c5582021-08-11 18:09:44 -0400100 line, column := d.Position(pos)
101 head := fmt.Sprintf("syntax error (line %d:%d): ", line, column)
102 return errors.New(head+f, x...)
103}
104
105// unmarshalMessage unmarshals into the given protoreflect.Message.
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530106func (d decoder) unmarshalMessage(m protoreflect.Message, checkDelims bool) error {
khenaidoo7d3c5582021-08-11 18:09:44 -0400107 messageDesc := m.Descriptor()
108 if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) {
109 return errors.New("no support for proto1 MessageSets")
110 }
111
112 if messageDesc.FullName() == genid.Any_message_fullname {
113 return d.unmarshalAny(m, checkDelims)
114 }
115
116 if checkDelims {
117 tok, err := d.Read()
118 if err != nil {
119 return err
120 }
121
122 if tok.Kind() != text.MessageOpen {
123 return d.unexpectedTokenError(tok)
124 }
125 }
126
127 var seenNums set.Ints
128 var seenOneofs set.Ints
129 fieldDescs := messageDesc.Fields()
130
131 for {
132 // Read field name.
133 tok, err := d.Read()
134 if err != nil {
135 return err
136 }
137 switch typ := tok.Kind(); typ {
138 case text.Name:
139 // Continue below.
140 case text.EOF:
141 if checkDelims {
142 return text.ErrUnexpectedEOF
143 }
144 return nil
145 default:
146 if checkDelims && typ == text.MessageClose {
147 return nil
148 }
149 return d.unexpectedTokenError(tok)
150 }
151
152 // Resolve the field descriptor.
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530153 var name protoreflect.Name
154 var fd protoreflect.FieldDescriptor
155 var xt protoreflect.ExtensionType
khenaidoo7d3c5582021-08-11 18:09:44 -0400156 var xtErr error
157 var isFieldNumberName bool
158
159 switch tok.NameKind() {
160 case text.IdentName:
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530161 name = protoreflect.Name(tok.IdentName())
khenaidoo7d3c5582021-08-11 18:09:44 -0400162 fd = fieldDescs.ByTextName(string(name))
163
164 case text.TypeName:
165 // Handle extensions only. This code path is not for Any.
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530166 xt, xtErr = d.opts.Resolver.FindExtensionByName(protoreflect.FullName(tok.TypeName()))
khenaidoo7d3c5582021-08-11 18:09:44 -0400167
168 case text.FieldNumber:
169 isFieldNumberName = true
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530170 num := protoreflect.FieldNumber(tok.FieldNumber())
khenaidoo7d3c5582021-08-11 18:09:44 -0400171 if !num.IsValid() {
172 return d.newError(tok.Pos(), "invalid field number: %d", num)
173 }
174 fd = fieldDescs.ByNumber(num)
175 if fd == nil {
176 xt, xtErr = d.opts.Resolver.FindExtensionByNumber(messageDesc.FullName(), num)
177 }
178 }
179
180 if xt != nil {
181 fd = xt.TypeDescriptor()
182 if !messageDesc.ExtensionRanges().Has(fd.Number()) || fd.ContainingMessage().FullName() != messageDesc.FullName() {
183 return d.newError(tok.Pos(), "message %v cannot be extended by %v", messageDesc.FullName(), fd.FullName())
184 }
185 } else if xtErr != nil && xtErr != protoregistry.NotFound {
186 return d.newError(tok.Pos(), "unable to resolve [%s]: %v", tok.RawString(), xtErr)
187 }
khenaidoo7d3c5582021-08-11 18:09:44 -0400188
189 // Handle unknown fields.
190 if fd == nil {
191 if d.opts.DiscardUnknown || messageDesc.ReservedNames().Has(name) {
192 d.skipValue()
193 continue
194 }
195 return d.newError(tok.Pos(), "unknown field: %v", tok.RawString())
196 }
197
198 // Handle fields identified by field number.
199 if isFieldNumberName {
200 // TODO: Add an option to permit parsing field numbers.
201 //
202 // This requires careful thought as the MarshalOptions.EmitUnknown
203 // option allows formatting unknown fields as the field number and the
204 // best-effort textual representation of the field value. In that case,
205 // it may not be possible to unmarshal the value from a parser that does
206 // have information about the unknown field.
207 return d.newError(tok.Pos(), "cannot specify field by number: %v", tok.RawString())
208 }
209
210 switch {
211 case fd.IsList():
212 kind := fd.Kind()
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530213 if kind != protoreflect.MessageKind && kind != protoreflect.GroupKind && !tok.HasSeparator() {
khenaidoo7d3c5582021-08-11 18:09:44 -0400214 return d.syntaxError(tok.Pos(), "missing field separator :")
215 }
216
217 list := m.Mutable(fd).List()
218 if err := d.unmarshalList(fd, list); err != nil {
219 return err
220 }
221
222 case fd.IsMap():
223 mmap := m.Mutable(fd).Map()
224 if err := d.unmarshalMap(fd, mmap); err != nil {
225 return err
226 }
227
228 default:
229 kind := fd.Kind()
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530230 if kind != protoreflect.MessageKind && kind != protoreflect.GroupKind && !tok.HasSeparator() {
khenaidoo7d3c5582021-08-11 18:09:44 -0400231 return d.syntaxError(tok.Pos(), "missing field separator :")
232 }
233
234 // If field is a oneof, check if it has already been set.
235 if od := fd.ContainingOneof(); od != nil {
236 idx := uint64(od.Index())
237 if seenOneofs.Has(idx) {
238 return d.newError(tok.Pos(), "error parsing %q, oneof %v is already set", tok.RawString(), od.FullName())
239 }
240 seenOneofs.Set(idx)
241 }
242
243 num := uint64(fd.Number())
244 if seenNums.Has(num) {
245 return d.newError(tok.Pos(), "non-repeated field %q is repeated", tok.RawString())
246 }
247
248 if err := d.unmarshalSingular(fd, m); err != nil {
249 return err
250 }
251 seenNums.Set(num)
252 }
253 }
254
255 return nil
256}
257
258// unmarshalSingular unmarshals a non-repeated field value specified by the
259// given FieldDescriptor.
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530260func (d decoder) unmarshalSingular(fd protoreflect.FieldDescriptor, m protoreflect.Message) error {
261 var val protoreflect.Value
khenaidoo7d3c5582021-08-11 18:09:44 -0400262 var err error
263 switch fd.Kind() {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530264 case protoreflect.MessageKind, protoreflect.GroupKind:
khenaidoo7d3c5582021-08-11 18:09:44 -0400265 val = m.NewField(fd)
266 err = d.unmarshalMessage(val.Message(), true)
267 default:
268 val, err = d.unmarshalScalar(fd)
269 }
270 if err == nil {
271 m.Set(fd, val)
272 }
273 return err
274}
275
276// unmarshalScalar unmarshals a scalar/enum protoreflect.Value specified by the
277// given FieldDescriptor.
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530278func (d decoder) unmarshalScalar(fd protoreflect.FieldDescriptor) (protoreflect.Value, error) {
khenaidoo7d3c5582021-08-11 18:09:44 -0400279 tok, err := d.Read()
280 if err != nil {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530281 return protoreflect.Value{}, err
khenaidoo7d3c5582021-08-11 18:09:44 -0400282 }
283
284 if tok.Kind() != text.Scalar {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530285 return protoreflect.Value{}, d.unexpectedTokenError(tok)
khenaidoo7d3c5582021-08-11 18:09:44 -0400286 }
287
288 kind := fd.Kind()
289 switch kind {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530290 case protoreflect.BoolKind:
khenaidoo7d3c5582021-08-11 18:09:44 -0400291 if b, ok := tok.Bool(); ok {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530292 return protoreflect.ValueOfBool(b), nil
khenaidoo7d3c5582021-08-11 18:09:44 -0400293 }
294
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530295 case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
khenaidoo7d3c5582021-08-11 18:09:44 -0400296 if n, ok := tok.Int32(); ok {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530297 return protoreflect.ValueOfInt32(n), nil
khenaidoo7d3c5582021-08-11 18:09:44 -0400298 }
299
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530300 case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
khenaidoo7d3c5582021-08-11 18:09:44 -0400301 if n, ok := tok.Int64(); ok {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530302 return protoreflect.ValueOfInt64(n), nil
khenaidoo7d3c5582021-08-11 18:09:44 -0400303 }
304
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530305 case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
khenaidoo7d3c5582021-08-11 18:09:44 -0400306 if n, ok := tok.Uint32(); ok {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530307 return protoreflect.ValueOfUint32(n), nil
khenaidoo7d3c5582021-08-11 18:09:44 -0400308 }
309
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530310 case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
khenaidoo7d3c5582021-08-11 18:09:44 -0400311 if n, ok := tok.Uint64(); ok {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530312 return protoreflect.ValueOfUint64(n), nil
khenaidoo7d3c5582021-08-11 18:09:44 -0400313 }
314
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530315 case protoreflect.FloatKind:
khenaidoo7d3c5582021-08-11 18:09:44 -0400316 if n, ok := tok.Float32(); ok {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530317 return protoreflect.ValueOfFloat32(n), nil
khenaidoo7d3c5582021-08-11 18:09:44 -0400318 }
319
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530320 case protoreflect.DoubleKind:
khenaidoo7d3c5582021-08-11 18:09:44 -0400321 if n, ok := tok.Float64(); ok {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530322 return protoreflect.ValueOfFloat64(n), nil
khenaidoo7d3c5582021-08-11 18:09:44 -0400323 }
324
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530325 case protoreflect.StringKind:
khenaidoo7d3c5582021-08-11 18:09:44 -0400326 if s, ok := tok.String(); ok {
327 if strs.EnforceUTF8(fd) && !utf8.ValidString(s) {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530328 return protoreflect.Value{}, d.newError(tok.Pos(), "contains invalid UTF-8")
khenaidoo7d3c5582021-08-11 18:09:44 -0400329 }
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530330 return protoreflect.ValueOfString(s), nil
khenaidoo7d3c5582021-08-11 18:09:44 -0400331 }
332
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530333 case protoreflect.BytesKind:
khenaidoo7d3c5582021-08-11 18:09:44 -0400334 if b, ok := tok.String(); ok {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530335 return protoreflect.ValueOfBytes([]byte(b)), nil
khenaidoo7d3c5582021-08-11 18:09:44 -0400336 }
337
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530338 case protoreflect.EnumKind:
khenaidoo7d3c5582021-08-11 18:09:44 -0400339 if lit, ok := tok.Enum(); ok {
340 // Lookup EnumNumber based on name.
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530341 if enumVal := fd.Enum().Values().ByName(protoreflect.Name(lit)); enumVal != nil {
342 return protoreflect.ValueOfEnum(enumVal.Number()), nil
khenaidoo7d3c5582021-08-11 18:09:44 -0400343 }
344 }
345 if num, ok := tok.Int32(); ok {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530346 return protoreflect.ValueOfEnum(protoreflect.EnumNumber(num)), nil
khenaidoo7d3c5582021-08-11 18:09:44 -0400347 }
348
349 default:
350 panic(fmt.Sprintf("invalid scalar kind %v", kind))
351 }
352
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530353 return protoreflect.Value{}, d.newError(tok.Pos(), "invalid value for %v type: %v", kind, tok.RawString())
khenaidoo7d3c5582021-08-11 18:09:44 -0400354}
355
356// unmarshalList unmarshals into given protoreflect.List. A list value can
357// either be in [] syntax or simply just a single scalar/message value.
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530358func (d decoder) unmarshalList(fd protoreflect.FieldDescriptor, list protoreflect.List) error {
khenaidoo7d3c5582021-08-11 18:09:44 -0400359 tok, err := d.Peek()
360 if err != nil {
361 return err
362 }
363
364 switch fd.Kind() {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530365 case protoreflect.MessageKind, protoreflect.GroupKind:
khenaidoo7d3c5582021-08-11 18:09:44 -0400366 switch tok.Kind() {
367 case text.ListOpen:
368 d.Read()
369 for {
370 tok, err := d.Peek()
371 if err != nil {
372 return err
373 }
374
375 switch tok.Kind() {
376 case text.ListClose:
377 d.Read()
378 return nil
379 case text.MessageOpen:
380 pval := list.NewElement()
381 if err := d.unmarshalMessage(pval.Message(), true); err != nil {
382 return err
383 }
384 list.Append(pval)
385 default:
386 return d.unexpectedTokenError(tok)
387 }
388 }
389
390 case text.MessageOpen:
391 pval := list.NewElement()
392 if err := d.unmarshalMessage(pval.Message(), true); err != nil {
393 return err
394 }
395 list.Append(pval)
396 return nil
397 }
398
399 default:
400 switch tok.Kind() {
401 case text.ListOpen:
402 d.Read()
403 for {
404 tok, err := d.Peek()
405 if err != nil {
406 return err
407 }
408
409 switch tok.Kind() {
410 case text.ListClose:
411 d.Read()
412 return nil
413 case text.Scalar:
414 pval, err := d.unmarshalScalar(fd)
415 if err != nil {
416 return err
417 }
418 list.Append(pval)
419 default:
420 return d.unexpectedTokenError(tok)
421 }
422 }
423
424 case text.Scalar:
425 pval, err := d.unmarshalScalar(fd)
426 if err != nil {
427 return err
428 }
429 list.Append(pval)
430 return nil
431 }
432 }
433
434 return d.unexpectedTokenError(tok)
435}
436
437// unmarshalMap unmarshals into given protoreflect.Map. A map value is a
438// textproto message containing {key: <kvalue>, value: <mvalue>}.
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530439func (d decoder) unmarshalMap(fd protoreflect.FieldDescriptor, mmap protoreflect.Map) error {
khenaidoo7d3c5582021-08-11 18:09:44 -0400440 // Determine ahead whether map entry is a scalar type or a message type in
441 // order to call the appropriate unmarshalMapValue func inside
442 // unmarshalMapEntry.
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530443 var unmarshalMapValue func() (protoreflect.Value, error)
khenaidoo7d3c5582021-08-11 18:09:44 -0400444 switch fd.MapValue().Kind() {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530445 case protoreflect.MessageKind, protoreflect.GroupKind:
446 unmarshalMapValue = func() (protoreflect.Value, error) {
khenaidoo7d3c5582021-08-11 18:09:44 -0400447 pval := mmap.NewValue()
448 if err := d.unmarshalMessage(pval.Message(), true); err != nil {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530449 return protoreflect.Value{}, err
khenaidoo7d3c5582021-08-11 18:09:44 -0400450 }
451 return pval, nil
452 }
453 default:
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530454 unmarshalMapValue = func() (protoreflect.Value, error) {
khenaidoo7d3c5582021-08-11 18:09:44 -0400455 return d.unmarshalScalar(fd.MapValue())
456 }
457 }
458
459 tok, err := d.Read()
460 if err != nil {
461 return err
462 }
463 switch tok.Kind() {
464 case text.MessageOpen:
465 return d.unmarshalMapEntry(fd, mmap, unmarshalMapValue)
466
467 case text.ListOpen:
468 for {
469 tok, err := d.Read()
470 if err != nil {
471 return err
472 }
473 switch tok.Kind() {
474 case text.ListClose:
475 return nil
476 case text.MessageOpen:
477 if err := d.unmarshalMapEntry(fd, mmap, unmarshalMapValue); err != nil {
478 return err
479 }
480 default:
481 return d.unexpectedTokenError(tok)
482 }
483 }
484
485 default:
486 return d.unexpectedTokenError(tok)
487 }
488}
489
490// unmarshalMap unmarshals into given protoreflect.Map. A map value is a
491// textproto message containing {key: <kvalue>, value: <mvalue>}.
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530492func (d decoder) unmarshalMapEntry(fd protoreflect.FieldDescriptor, mmap protoreflect.Map, unmarshalMapValue func() (protoreflect.Value, error)) error {
493 var key protoreflect.MapKey
494 var pval protoreflect.Value
khenaidoo7d3c5582021-08-11 18:09:44 -0400495Loop:
496 for {
497 // Read field name.
498 tok, err := d.Read()
499 if err != nil {
500 return err
501 }
502 switch tok.Kind() {
503 case text.Name:
504 if tok.NameKind() != text.IdentName {
505 if !d.opts.DiscardUnknown {
506 return d.newError(tok.Pos(), "unknown map entry field %q", tok.RawString())
507 }
508 d.skipValue()
509 continue Loop
510 }
511 // Continue below.
512 case text.MessageClose:
513 break Loop
514 default:
515 return d.unexpectedTokenError(tok)
516 }
517
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530518 switch name := protoreflect.Name(tok.IdentName()); name {
khenaidoo7d3c5582021-08-11 18:09:44 -0400519 case genid.MapEntry_Key_field_name:
520 if !tok.HasSeparator() {
521 return d.syntaxError(tok.Pos(), "missing field separator :")
522 }
523 if key.IsValid() {
524 return d.newError(tok.Pos(), "map entry %q cannot be repeated", name)
525 }
526 val, err := d.unmarshalScalar(fd.MapKey())
527 if err != nil {
528 return err
529 }
530 key = val.MapKey()
531
532 case genid.MapEntry_Value_field_name:
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530533 if kind := fd.MapValue().Kind(); (kind != protoreflect.MessageKind) && (kind != protoreflect.GroupKind) {
khenaidoo7d3c5582021-08-11 18:09:44 -0400534 if !tok.HasSeparator() {
535 return d.syntaxError(tok.Pos(), "missing field separator :")
536 }
537 }
538 if pval.IsValid() {
539 return d.newError(tok.Pos(), "map entry %q cannot be repeated", name)
540 }
541 pval, err = unmarshalMapValue()
542 if err != nil {
543 return err
544 }
545
546 default:
547 if !d.opts.DiscardUnknown {
548 return d.newError(tok.Pos(), "unknown map entry field %q", name)
549 }
550 d.skipValue()
551 }
552 }
553
554 if !key.IsValid() {
555 key = fd.MapKey().Default().MapKey()
556 }
557 if !pval.IsValid() {
558 switch fd.MapValue().Kind() {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530559 case protoreflect.MessageKind, protoreflect.GroupKind:
khenaidoo7d3c5582021-08-11 18:09:44 -0400560 // If value field is not set for message/group types, construct an
561 // empty one as default.
562 pval = mmap.NewValue()
563 default:
564 pval = fd.MapValue().Default()
565 }
566 }
567 mmap.Set(key, pval)
568 return nil
569}
570
571// unmarshalAny unmarshals an Any textproto. It can either be in expanded form
572// or non-expanded form.
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530573func (d decoder) unmarshalAny(m protoreflect.Message, checkDelims bool) error {
khenaidoo7d3c5582021-08-11 18:09:44 -0400574 var typeURL string
575 var bValue []byte
576 var seenTypeUrl bool
577 var seenValue bool
578 var isExpanded bool
579
580 if checkDelims {
581 tok, err := d.Read()
582 if err != nil {
583 return err
584 }
585
586 if tok.Kind() != text.MessageOpen {
587 return d.unexpectedTokenError(tok)
588 }
589 }
590
591Loop:
592 for {
593 // Read field name. Can only have 3 possible field names, i.e. type_url,
594 // value and type URL name inside [].
595 tok, err := d.Read()
596 if err != nil {
597 return err
598 }
599 if typ := tok.Kind(); typ != text.Name {
600 if checkDelims {
601 if typ == text.MessageClose {
602 break Loop
603 }
604 } else if typ == text.EOF {
605 break Loop
606 }
607 return d.unexpectedTokenError(tok)
608 }
609
610 switch tok.NameKind() {
611 case text.IdentName:
612 // Both type_url and value fields require field separator :.
613 if !tok.HasSeparator() {
614 return d.syntaxError(tok.Pos(), "missing field separator :")
615 }
616
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530617 switch name := protoreflect.Name(tok.IdentName()); name {
khenaidoo7d3c5582021-08-11 18:09:44 -0400618 case genid.Any_TypeUrl_field_name:
619 if seenTypeUrl {
620 return d.newError(tok.Pos(), "duplicate %v field", genid.Any_TypeUrl_field_fullname)
621 }
622 if isExpanded {
623 return d.newError(tok.Pos(), "conflict with [%s] field", typeURL)
624 }
625 tok, err := d.Read()
626 if err != nil {
627 return err
628 }
629 var ok bool
630 typeURL, ok = tok.String()
631 if !ok {
632 return d.newError(tok.Pos(), "invalid %v field value: %v", genid.Any_TypeUrl_field_fullname, tok.RawString())
633 }
634 seenTypeUrl = true
635
636 case genid.Any_Value_field_name:
637 if seenValue {
638 return d.newError(tok.Pos(), "duplicate %v field", genid.Any_Value_field_fullname)
639 }
640 if isExpanded {
641 return d.newError(tok.Pos(), "conflict with [%s] field", typeURL)
642 }
643 tok, err := d.Read()
644 if err != nil {
645 return err
646 }
647 s, ok := tok.String()
648 if !ok {
649 return d.newError(tok.Pos(), "invalid %v field value: %v", genid.Any_Value_field_fullname, tok.RawString())
650 }
651 bValue = []byte(s)
652 seenValue = true
653
654 default:
655 if !d.opts.DiscardUnknown {
656 return d.newError(tok.Pos(), "invalid field name %q in %v message", tok.RawString(), genid.Any_message_fullname)
657 }
658 }
659
660 case text.TypeName:
661 if isExpanded {
662 return d.newError(tok.Pos(), "cannot have more than one type")
663 }
664 if seenTypeUrl {
665 return d.newError(tok.Pos(), "conflict with type_url field")
666 }
667 typeURL = tok.TypeName()
668 var err error
669 bValue, err = d.unmarshalExpandedAny(typeURL, tok.Pos())
670 if err != nil {
671 return err
672 }
673 isExpanded = true
674
675 default:
676 if !d.opts.DiscardUnknown {
677 return d.newError(tok.Pos(), "invalid field name %q in %v message", tok.RawString(), genid.Any_message_fullname)
678 }
679 }
680 }
681
682 fds := m.Descriptor().Fields()
683 if len(typeURL) > 0 {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530684 m.Set(fds.ByNumber(genid.Any_TypeUrl_field_number), protoreflect.ValueOfString(typeURL))
khenaidoo7d3c5582021-08-11 18:09:44 -0400685 }
686 if len(bValue) > 0 {
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530687 m.Set(fds.ByNumber(genid.Any_Value_field_number), protoreflect.ValueOfBytes(bValue))
khenaidoo7d3c5582021-08-11 18:09:44 -0400688 }
689 return nil
690}
691
692func (d decoder) unmarshalExpandedAny(typeURL string, pos int) ([]byte, error) {
693 mt, err := d.opts.Resolver.FindMessageByURL(typeURL)
694 if err != nil {
695 return nil, d.newError(pos, "unable to resolve message [%v]: %v", typeURL, err)
696 }
697 // Create new message for the embedded message type and unmarshal the value
698 // field into it.
699 m := mt.New()
700 if err := d.unmarshalMessage(m, true); err != nil {
701 return nil, err
702 }
703 // Serialize the embedded message and return the resulting bytes.
704 b, err := proto.MarshalOptions{
705 AllowPartial: true, // Never check required fields inside an Any.
706 Deterministic: true,
707 }.Marshal(m.Interface())
708 if err != nil {
709 return nil, d.newError(pos, "error in marshaling message into Any.value: %v", err)
710 }
711 return b, nil
712}
713
714// skipValue makes the decoder parse a field value in order to advance the read
715// to the next field. It relies on Read returning an error if the types are not
716// in valid sequence.
717func (d decoder) skipValue() error {
718 tok, err := d.Read()
719 if err != nil {
720 return err
721 }
722 // Only need to continue reading for messages and lists.
723 switch tok.Kind() {
724 case text.MessageOpen:
725 return d.skipMessageValue()
726
727 case text.ListOpen:
728 for {
729 tok, err := d.Read()
730 if err != nil {
731 return err
732 }
733 switch tok.Kind() {
734 case text.ListClose:
735 return nil
736 case text.MessageOpen:
Akash Reddy Kankanala92dfdf82025-03-23 22:07:09 +0530737 if err := d.skipMessageValue(); err != nil {
738 return err
739 }
khenaidoo7d3c5582021-08-11 18:09:44 -0400740 default:
741 // Skip items. This will not validate whether skipped values are
742 // of the same type or not, same behavior as C++
743 // TextFormat::Parser::AllowUnknownField(true) version 3.8.0.
744 }
745 }
746 }
747 return nil
748}
749
750// skipMessageValue makes the decoder parse and skip over all fields in a
751// message. It assumes that the previous read type is MessageOpen.
752func (d decoder) skipMessageValue() error {
753 for {
754 tok, err := d.Read()
755 if err != nil {
756 return err
757 }
758 switch tok.Kind() {
759 case text.MessageClose:
760 return nil
761 case text.Name:
762 if err := d.skipValue(); err != nil {
763 return err
764 }
765 }
766 }
767}