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