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