blob: c2f8f28f2cb0223db7d462352780a49dfa4b7377 [file] [log] [blame]
Matteo Scandoloa4285862020-12-01 18:10:10 -08001// 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 "strings"
10 "unicode/utf8"
11
12 "google.golang.org/protobuf/internal/encoding/messageset"
13 "google.golang.org/protobuf/internal/encoding/text"
14 "google.golang.org/protobuf/internal/errors"
15 "google.golang.org/protobuf/internal/fieldnum"
16 "google.golang.org/protobuf/internal/flags"
17 "google.golang.org/protobuf/internal/pragma"
18 "google.golang.org/protobuf/internal/set"
19 "google.golang.org/protobuf/internal/strs"
20 "google.golang.org/protobuf/proto"
21 pref "google.golang.org/protobuf/reflect/protoreflect"
22 "google.golang.org/protobuf/reflect/protoregistry"
23)
24
25// Unmarshal reads the given []byte into the given proto.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
54// Unmarshal reads the given []byte and populates the given proto.Message using options in
55// UnmarshalOptions object.
56func (o UnmarshalOptions) Unmarshal(b []byte, m proto.Message) error {
57 return o.unmarshal(b, m)
58}
59
60// unmarshal is a centralized function that all unmarshal operations go through.
61// For profiling purposes, avoid changing the name of this function or
62// introducing other code paths for unmarshal that do not go through this.
63func (o UnmarshalOptions) unmarshal(b []byte, m proto.Message) error {
64 proto.Reset(m)
65
66 if o.Resolver == nil {
67 o.Resolver = protoregistry.GlobalTypes
68 }
69
70 dec := decoder{text.NewDecoder(b), o}
71 if err := dec.unmarshalMessage(m.ProtoReflect(), false); err != nil {
72 return err
73 }
74 if o.AllowPartial {
75 return nil
76 }
77 return proto.CheckInitialized(m)
78}
79
80type decoder struct {
81 *text.Decoder
82 opts UnmarshalOptions
83}
84
85// newError returns an error object with position info.
86func (d decoder) newError(pos int, f string, x ...interface{}) error {
87 line, column := d.Position(pos)
88 head := fmt.Sprintf("(line %d:%d): ", line, column)
89 return errors.New(head+f, x...)
90}
91
92// unexpectedTokenError returns a syntax error for the given unexpected token.
93func (d decoder) unexpectedTokenError(tok text.Token) error {
94 return d.syntaxError(tok.Pos(), "unexpected token: %s", tok.RawString())
95}
96
97// syntaxError returns a syntax error for given position.
98func (d decoder) syntaxError(pos int, f string, x ...interface{}) error {
99 line, column := d.Position(pos)
100 head := fmt.Sprintf("syntax error (line %d:%d): ", line, column)
101 return errors.New(head+f, x...)
102}
103
104// unmarshalMessage unmarshals into the given protoreflect.Message.
105func (d decoder) unmarshalMessage(m pref.Message, checkDelims bool) error {
106 messageDesc := m.Descriptor()
107 if !flags.ProtoLegacy && messageset.IsMessageSet(messageDesc) {
108 return errors.New("no support for proto1 MessageSets")
109 }
110
111 if messageDesc.FullName() == "google.protobuf.Any" {
112 return d.unmarshalAny(m, checkDelims)
113 }
114
115 if checkDelims {
116 tok, err := d.Read()
117 if err != nil {
118 return err
119 }
120
121 if tok.Kind() != text.MessageOpen {
122 return d.unexpectedTokenError(tok)
123 }
124 }
125
126 var seenNums set.Ints
127 var seenOneofs set.Ints
128 fieldDescs := messageDesc.Fields()
129
130 for {
131 // Read field name.
132 tok, err := d.Read()
133 if err != nil {
134 return err
135 }
136 switch typ := tok.Kind(); typ {
137 case text.Name:
138 // Continue below.
139 case text.EOF:
140 if checkDelims {
141 return text.ErrUnexpectedEOF
142 }
143 return nil
144 default:
145 if checkDelims && typ == text.MessageClose {
146 return nil
147 }
148 return d.unexpectedTokenError(tok)
149 }
150
151 // Resolve the field descriptor.
152 var name pref.Name
153 var fd pref.FieldDescriptor
154 var xt pref.ExtensionType
155 var xtErr error
156 var isFieldNumberName bool
157
158 switch tok.NameKind() {
159 case text.IdentName:
160 name = pref.Name(tok.IdentName())
161 fd = fieldDescs.ByName(name)
162 if fd == nil {
163 // The proto name of a group field is in all lowercase,
164 // while the textproto field name is the group message name.
165 gd := fieldDescs.ByName(pref.Name(strings.ToLower(string(name))))
166 if gd != nil && gd.Kind() == pref.GroupKind && gd.Message().Name() == name {
167 fd = gd
168 }
169 } else if fd.Kind() == pref.GroupKind && fd.Message().Name() != name {
170 fd = nil // reset since field name is actually the message name
171 }
172
173 case text.TypeName:
174 // Handle extensions only. This code path is not for Any.
175 xt, xtErr = d.findExtension(pref.FullName(tok.TypeName()))
176
177 case text.FieldNumber:
178 isFieldNumberName = true
179 num := pref.FieldNumber(tok.FieldNumber())
180 if !num.IsValid() {
181 return d.newError(tok.Pos(), "invalid field number: %d", num)
182 }
183 fd = fieldDescs.ByNumber(num)
184 if fd == nil {
185 xt, xtErr = d.opts.Resolver.FindExtensionByNumber(messageDesc.FullName(), num)
186 }
187 }
188
189 if xt != nil {
190 fd = xt.TypeDescriptor()
191 if !messageDesc.ExtensionRanges().Has(fd.Number()) || fd.ContainingMessage().FullName() != messageDesc.FullName() {
192 return d.newError(tok.Pos(), "message %v cannot be extended by %v", messageDesc.FullName(), fd.FullName())
193 }
194 } else if xtErr != nil && xtErr != protoregistry.NotFound {
195 return d.newError(tok.Pos(), "unable to resolve [%s]: %v", tok.RawString(), xtErr)
196 }
197 if flags.ProtoLegacy {
198 if fd != nil && fd.IsWeak() && fd.Message().IsPlaceholder() {
199 fd = nil // reset since the weak reference is not linked in
200 }
201 }
202
203 // Handle unknown fields.
204 if fd == nil {
205 if d.opts.DiscardUnknown || messageDesc.ReservedNames().Has(name) {
206 d.skipValue()
207 continue
208 }
209 return d.newError(tok.Pos(), "unknown field: %v", tok.RawString())
210 }
211
212 // Handle fields identified by field number.
213 if isFieldNumberName {
214 // TODO: Add an option to permit parsing field numbers.
215 //
216 // This requires careful thought as the MarshalOptions.EmitUnknown
217 // option allows formatting unknown fields as the field number and the
218 // best-effort textual representation of the field value. In that case,
219 // it may not be possible to unmarshal the value from a parser that does
220 // have information about the unknown field.
221 return d.newError(tok.Pos(), "cannot specify field by number: %v", tok.RawString())
222 }
223
224 switch {
225 case fd.IsList():
226 kind := fd.Kind()
227 if kind != pref.MessageKind && kind != pref.GroupKind && !tok.HasSeparator() {
228 return d.syntaxError(tok.Pos(), "missing field separator :")
229 }
230
231 list := m.Mutable(fd).List()
232 if err := d.unmarshalList(fd, list); err != nil {
233 return err
234 }
235
236 case fd.IsMap():
237 mmap := m.Mutable(fd).Map()
238 if err := d.unmarshalMap(fd, mmap); err != nil {
239 return err
240 }
241
242 default:
243 kind := fd.Kind()
244 if kind != pref.MessageKind && kind != pref.GroupKind && !tok.HasSeparator() {
245 return d.syntaxError(tok.Pos(), "missing field separator :")
246 }
247
248 // If field is a oneof, check if it has already been set.
249 if od := fd.ContainingOneof(); od != nil {
250 idx := uint64(od.Index())
251 if seenOneofs.Has(idx) {
252 return d.newError(tok.Pos(), "error parsing %q, oneof %v is already set", tok.RawString(), od.FullName())
253 }
254 seenOneofs.Set(idx)
255 }
256
257 num := uint64(fd.Number())
258 if seenNums.Has(num) {
259 return d.newError(tok.Pos(), "non-repeated field %q is repeated", tok.RawString())
260 }
261
262 if err := d.unmarshalSingular(fd, m); err != nil {
263 return err
264 }
265 seenNums.Set(num)
266 }
267 }
268
269 return nil
270}
271
272// findExtension returns protoreflect.ExtensionType from the Resolver if found.
273func (d decoder) findExtension(xtName pref.FullName) (pref.ExtensionType, error) {
274 xt, err := d.opts.Resolver.FindExtensionByName(xtName)
275 if err == nil {
276 return xt, nil
277 }
278 return messageset.FindMessageSetExtension(d.opts.Resolver, xtName)
279}
280
281// unmarshalSingular unmarshals a non-repeated field value specified by the
282// given FieldDescriptor.
283func (d decoder) unmarshalSingular(fd pref.FieldDescriptor, m pref.Message) error {
284 var val pref.Value
285 var err error
286 switch fd.Kind() {
287 case pref.MessageKind, pref.GroupKind:
288 val = m.NewField(fd)
289 err = d.unmarshalMessage(val.Message(), true)
290 default:
291 val, err = d.unmarshalScalar(fd)
292 }
293 if err == nil {
294 m.Set(fd, val)
295 }
296 return err
297}
298
299// unmarshalScalar unmarshals a scalar/enum protoreflect.Value specified by the
300// given FieldDescriptor.
301func (d decoder) unmarshalScalar(fd pref.FieldDescriptor) (pref.Value, error) {
302 tok, err := d.Read()
303 if err != nil {
304 return pref.Value{}, err
305 }
306
307 if tok.Kind() != text.Scalar {
308 return pref.Value{}, d.unexpectedTokenError(tok)
309 }
310
311 kind := fd.Kind()
312 switch kind {
313 case pref.BoolKind:
314 if b, ok := tok.Bool(); ok {
315 return pref.ValueOfBool(b), nil
316 }
317
318 case pref.Int32Kind, pref.Sint32Kind, pref.Sfixed32Kind:
319 if n, ok := tok.Int32(); ok {
320 return pref.ValueOfInt32(n), nil
321 }
322
323 case pref.Int64Kind, pref.Sint64Kind, pref.Sfixed64Kind:
324 if n, ok := tok.Int64(); ok {
325 return pref.ValueOfInt64(n), nil
326 }
327
328 case pref.Uint32Kind, pref.Fixed32Kind:
329 if n, ok := tok.Uint32(); ok {
330 return pref.ValueOfUint32(n), nil
331 }
332
333 case pref.Uint64Kind, pref.Fixed64Kind:
334 if n, ok := tok.Uint64(); ok {
335 return pref.ValueOfUint64(n), nil
336 }
337
338 case pref.FloatKind:
339 if n, ok := tok.Float32(); ok {
340 return pref.ValueOfFloat32(n), nil
341 }
342
343 case pref.DoubleKind:
344 if n, ok := tok.Float64(); ok {
345 return pref.ValueOfFloat64(n), nil
346 }
347
348 case pref.StringKind:
349 if s, ok := tok.String(); ok {
350 if strs.EnforceUTF8(fd) && !utf8.ValidString(s) {
351 return pref.Value{}, d.newError(tok.Pos(), "contains invalid UTF-8")
352 }
353 return pref.ValueOfString(s), nil
354 }
355
356 case pref.BytesKind:
357 if b, ok := tok.String(); ok {
358 return pref.ValueOfBytes([]byte(b)), nil
359 }
360
361 case pref.EnumKind:
362 if lit, ok := tok.Enum(); ok {
363 // Lookup EnumNumber based on name.
364 if enumVal := fd.Enum().Values().ByName(pref.Name(lit)); enumVal != nil {
365 return pref.ValueOfEnum(enumVal.Number()), nil
366 }
367 }
368 if num, ok := tok.Int32(); ok {
369 return pref.ValueOfEnum(pref.EnumNumber(num)), nil
370 }
371
372 default:
373 panic(fmt.Sprintf("invalid scalar kind %v", kind))
374 }
375
376 return pref.Value{}, d.newError(tok.Pos(), "invalid value for %v type: %v", kind, tok.RawString())
377}
378
379// unmarshalList unmarshals into given protoreflect.List. A list value can
380// either be in [] syntax or simply just a single scalar/message value.
381func (d decoder) unmarshalList(fd pref.FieldDescriptor, list pref.List) error {
382 tok, err := d.Peek()
383 if err != nil {
384 return err
385 }
386
387 switch fd.Kind() {
388 case pref.MessageKind, pref.GroupKind:
389 switch tok.Kind() {
390 case text.ListOpen:
391 d.Read()
392 for {
393 tok, err := d.Peek()
394 if err != nil {
395 return err
396 }
397
398 switch tok.Kind() {
399 case text.ListClose:
400 d.Read()
401 return nil
402 case text.MessageOpen:
403 pval := list.NewElement()
404 if err := d.unmarshalMessage(pval.Message(), true); err != nil {
405 return err
406 }
407 list.Append(pval)
408 default:
409 return d.unexpectedTokenError(tok)
410 }
411 }
412
413 case text.MessageOpen:
414 pval := list.NewElement()
415 if err := d.unmarshalMessage(pval.Message(), true); err != nil {
416 return err
417 }
418 list.Append(pval)
419 return nil
420 }
421
422 default:
423 switch tok.Kind() {
424 case text.ListOpen:
425 d.Read()
426 for {
427 tok, err := d.Peek()
428 if err != nil {
429 return err
430 }
431
432 switch tok.Kind() {
433 case text.ListClose:
434 d.Read()
435 return nil
436 case text.Scalar:
437 pval, err := d.unmarshalScalar(fd)
438 if err != nil {
439 return err
440 }
441 list.Append(pval)
442 default:
443 return d.unexpectedTokenError(tok)
444 }
445 }
446
447 case text.Scalar:
448 pval, err := d.unmarshalScalar(fd)
449 if err != nil {
450 return err
451 }
452 list.Append(pval)
453 return nil
454 }
455 }
456
457 return d.unexpectedTokenError(tok)
458}
459
460// unmarshalMap unmarshals into given protoreflect.Map. A map value is a
461// textproto message containing {key: <kvalue>, value: <mvalue>}.
462func (d decoder) unmarshalMap(fd pref.FieldDescriptor, mmap pref.Map) error {
463 // Determine ahead whether map entry is a scalar type or a message type in
464 // order to call the appropriate unmarshalMapValue func inside
465 // unmarshalMapEntry.
466 var unmarshalMapValue func() (pref.Value, error)
467 switch fd.MapValue().Kind() {
468 case pref.MessageKind, pref.GroupKind:
469 unmarshalMapValue = func() (pref.Value, error) {
470 pval := mmap.NewValue()
471 if err := d.unmarshalMessage(pval.Message(), true); err != nil {
472 return pref.Value{}, err
473 }
474 return pval, nil
475 }
476 default:
477 unmarshalMapValue = func() (pref.Value, error) {
478 return d.unmarshalScalar(fd.MapValue())
479 }
480 }
481
482 tok, err := d.Read()
483 if err != nil {
484 return err
485 }
486 switch tok.Kind() {
487 case text.MessageOpen:
488 return d.unmarshalMapEntry(fd, mmap, unmarshalMapValue)
489
490 case text.ListOpen:
491 for {
492 tok, err := d.Read()
493 if err != nil {
494 return err
495 }
496 switch tok.Kind() {
497 case text.ListClose:
498 return nil
499 case text.MessageOpen:
500 if err := d.unmarshalMapEntry(fd, mmap, unmarshalMapValue); err != nil {
501 return err
502 }
503 default:
504 return d.unexpectedTokenError(tok)
505 }
506 }
507
508 default:
509 return d.unexpectedTokenError(tok)
510 }
511}
512
513// unmarshalMap unmarshals into given protoreflect.Map. A map value is a
514// textproto message containing {key: <kvalue>, value: <mvalue>}.
515func (d decoder) unmarshalMapEntry(fd pref.FieldDescriptor, mmap pref.Map, unmarshalMapValue func() (pref.Value, error)) error {
516 var key pref.MapKey
517 var pval pref.Value
518Loop:
519 for {
520 // Read field name.
521 tok, err := d.Read()
522 if err != nil {
523 return err
524 }
525 switch tok.Kind() {
526 case text.Name:
527 if tok.NameKind() != text.IdentName {
528 if !d.opts.DiscardUnknown {
529 return d.newError(tok.Pos(), "unknown map entry field %q", tok.RawString())
530 }
531 d.skipValue()
532 continue Loop
533 }
534 // Continue below.
535 case text.MessageClose:
536 break Loop
537 default:
538 return d.unexpectedTokenError(tok)
539 }
540
541 name := tok.IdentName()
542 switch name {
543 case "key":
544 if !tok.HasSeparator() {
545 return d.syntaxError(tok.Pos(), "missing field separator :")
546 }
547 if key.IsValid() {
548 return d.newError(tok.Pos(), `map entry "key" cannot be repeated`)
549 }
550 val, err := d.unmarshalScalar(fd.MapKey())
551 if err != nil {
552 return err
553 }
554 key = val.MapKey()
555
556 case "value":
557 if kind := fd.MapValue().Kind(); (kind != pref.MessageKind) && (kind != pref.GroupKind) {
558 if !tok.HasSeparator() {
559 return d.syntaxError(tok.Pos(), "missing field separator :")
560 }
561 }
562 if pval.IsValid() {
563 return d.newError(tok.Pos(), `map entry "value" cannot be repeated`)
564 }
565 pval, err = unmarshalMapValue()
566 if err != nil {
567 return err
568 }
569
570 default:
571 if !d.opts.DiscardUnknown {
572 return d.newError(tok.Pos(), "unknown map entry field %q", name)
573 }
574 d.skipValue()
575 }
576 }
577
578 if !key.IsValid() {
579 key = fd.MapKey().Default().MapKey()
580 }
581 if !pval.IsValid() {
582 switch fd.MapValue().Kind() {
583 case pref.MessageKind, pref.GroupKind:
584 // If value field is not set for message/group types, construct an
585 // empty one as default.
586 pval = mmap.NewValue()
587 default:
588 pval = fd.MapValue().Default()
589 }
590 }
591 mmap.Set(key, pval)
592 return nil
593}
594
595// unmarshalAny unmarshals an Any textproto. It can either be in expanded form
596// or non-expanded form.
597func (d decoder) unmarshalAny(m pref.Message, checkDelims bool) error {
598 var typeURL string
599 var bValue []byte
600
601 // hasFields tracks which valid fields have been seen in the loop below in
602 // order to flag an error if there are duplicates or conflicts. It may
603 // contain the strings "type_url", "value" and "expanded". The literal
604 // "expanded" is used to indicate that the expanded form has been
605 // encountered already.
606 hasFields := map[string]bool{}
607
608 if checkDelims {
609 tok, err := d.Read()
610 if err != nil {
611 return err
612 }
613
614 if tok.Kind() != text.MessageOpen {
615 return d.unexpectedTokenError(tok)
616 }
617 }
618
619Loop:
620 for {
621 // Read field name. Can only have 3 possible field names, i.e. type_url,
622 // value and type URL name inside [].
623 tok, err := d.Read()
624 if err != nil {
625 return err
626 }
627 if typ := tok.Kind(); typ != text.Name {
628 if checkDelims {
629 if typ == text.MessageClose {
630 break Loop
631 }
632 } else if typ == text.EOF {
633 break Loop
634 }
635 return d.unexpectedTokenError(tok)
636 }
637
638 switch tok.NameKind() {
639 case text.IdentName:
640 // Both type_url and value fields require field separator :.
641 if !tok.HasSeparator() {
642 return d.syntaxError(tok.Pos(), "missing field separator :")
643 }
644
645 switch tok.IdentName() {
646 case "type_url":
647 if hasFields["type_url"] {
648 return d.newError(tok.Pos(), "duplicate Any type_url field")
649 }
650 if hasFields["expanded"] {
651 return d.newError(tok.Pos(), "conflict with [%s] field", typeURL)
652 }
653 tok, err := d.Read()
654 if err != nil {
655 return err
656 }
657 var ok bool
658 typeURL, ok = tok.String()
659 if !ok {
660 return d.newError(tok.Pos(), "invalid Any type_url: %v", tok.RawString())
661 }
662 hasFields["type_url"] = true
663
664 case "value":
665 if hasFields["value"] {
666 return d.newError(tok.Pos(), "duplicate Any value field")
667 }
668 if hasFields["expanded"] {
669 return d.newError(tok.Pos(), "conflict with [%s] field", typeURL)
670 }
671 tok, err := d.Read()
672 if err != nil {
673 return err
674 }
675 s, ok := tok.String()
676 if !ok {
677 return d.newError(tok.Pos(), "invalid Any value: %v", tok.RawString())
678 }
679 bValue = []byte(s)
680 hasFields["value"] = true
681
682 default:
683 if !d.opts.DiscardUnknown {
684 return d.newError(tok.Pos(), "invalid field name %q in google.protobuf.Any message", tok.RawString())
685 }
686 }
687
688 case text.TypeName:
689 if hasFields["expanded"] {
690 return d.newError(tok.Pos(), "cannot have more than one type")
691 }
692 if hasFields["type_url"] {
693 return d.newError(tok.Pos(), "conflict with type_url field")
694 }
695 typeURL = tok.TypeName()
696 var err error
697 bValue, err = d.unmarshalExpandedAny(typeURL, tok.Pos())
698 if err != nil {
699 return err
700 }
701 hasFields["expanded"] = true
702
703 default:
704 if !d.opts.DiscardUnknown {
705 return d.newError(tok.Pos(), "invalid field name %q in google.protobuf.Any message", tok.RawString())
706 }
707 }
708 }
709
710 fds := m.Descriptor().Fields()
711 if len(typeURL) > 0 {
712 m.Set(fds.ByNumber(fieldnum.Any_TypeUrl), pref.ValueOfString(typeURL))
713 }
714 if len(bValue) > 0 {
715 m.Set(fds.ByNumber(fieldnum.Any_Value), pref.ValueOfBytes(bValue))
716 }
717 return nil
718}
719
720func (d decoder) unmarshalExpandedAny(typeURL string, pos int) ([]byte, error) {
721 mt, err := d.opts.Resolver.FindMessageByURL(typeURL)
722 if err != nil {
723 return nil, d.newError(pos, "unable to resolve message [%v]: %v", typeURL, err)
724 }
725 // Create new message for the embedded message type and unmarshal the value
726 // field into it.
727 m := mt.New()
728 if err := d.unmarshalMessage(m, true); err != nil {
729 return nil, err
730 }
731 // Serialize the embedded message and return the resulting bytes.
732 b, err := proto.MarshalOptions{
733 AllowPartial: true, // Never check required fields inside an Any.
734 Deterministic: true,
735 }.Marshal(m.Interface())
736 if err != nil {
737 return nil, d.newError(pos, "error in marshaling message into Any.value: %v", err)
738 }
739 return b, nil
740}
741
742// skipValue makes the decoder parse a field value in order to advance the read
743// to the next field. It relies on Read returning an error if the types are not
744// in valid sequence.
745func (d decoder) skipValue() error {
746 tok, err := d.Read()
747 if err != nil {
748 return err
749 }
750 // Only need to continue reading for messages and lists.
751 switch tok.Kind() {
752 case text.MessageOpen:
753 return d.skipMessageValue()
754
755 case text.ListOpen:
756 for {
757 tok, err := d.Read()
758 if err != nil {
759 return err
760 }
761 switch tok.Kind() {
762 case text.ListClose:
763 return nil
764 case text.MessageOpen:
765 return d.skipMessageValue()
766 default:
767 // Skip items. This will not validate whether skipped values are
768 // of the same type or not, same behavior as C++
769 // TextFormat::Parser::AllowUnknownField(true) version 3.8.0.
770 if err := d.skipValue(); err != nil {
771 return err
772 }
773 }
774 }
775 }
776 return nil
777}
778
779// skipMessageValue makes the decoder parse and skip over all fields in a
780// message. It assumes that the previous read type is MessageOpen.
781func (d decoder) skipMessageValue() error {
782 for {
783 tok, err := d.Read()
784 if err != nil {
785 return err
786 }
787 switch tok.Kind() {
788 case text.MessageClose:
789 return nil
790 case text.Name:
791 if err := d.skipValue(); err != nil {
792 return err
793 }
794 }
795 }
796}