blob: be63169b719458291f3d6badf0eac39985a80074 [file] [log] [blame]
mpagenkoaf801632020-07-03 10:00:42 +00001//
2// Copyright (c) 2011-2019 Canonical Ltd
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16package yaml
17
18import (
19 "encoding"
20 "encoding/base64"
21 "fmt"
22 "io"
23 "math"
24 "reflect"
25 "strconv"
26 "time"
27)
28
29// ----------------------------------------------------------------------------
30// Parser, produces a node tree out of a libyaml event stream.
31
32type parser struct {
33 parser yaml_parser_t
34 event yaml_event_t
35 doc *Node
36 anchors map[string]*Node
37 doneInit bool
38}
39
40func newParser(b []byte) *parser {
41 p := parser{}
42 if !yaml_parser_initialize(&p.parser) {
43 panic("failed to initialize YAML emitter")
44 }
45 if len(b) == 0 {
46 b = []byte{'\n'}
47 }
48 yaml_parser_set_input_string(&p.parser, b)
49 return &p
50}
51
52func newParserFromReader(r io.Reader) *parser {
53 p := parser{}
54 if !yaml_parser_initialize(&p.parser) {
55 panic("failed to initialize YAML emitter")
56 }
57 yaml_parser_set_input_reader(&p.parser, r)
58 return &p
59}
60
61func (p *parser) init() {
62 if p.doneInit {
63 return
64 }
65 p.anchors = make(map[string]*Node)
66 p.expect(yaml_STREAM_START_EVENT)
67 p.doneInit = true
68}
69
70func (p *parser) destroy() {
71 if p.event.typ != yaml_NO_EVENT {
72 yaml_event_delete(&p.event)
73 }
74 yaml_parser_delete(&p.parser)
75}
76
77// expect consumes an event from the event stream and
78// checks that it's of the expected type.
79func (p *parser) expect(e yaml_event_type_t) {
80 if p.event.typ == yaml_NO_EVENT {
81 if !yaml_parser_parse(&p.parser, &p.event) {
82 p.fail()
83 }
84 }
85 if p.event.typ == yaml_STREAM_END_EVENT {
86 failf("attempted to go past the end of stream; corrupted value?")
87 }
88 if p.event.typ != e {
89 p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ)
90 p.fail()
91 }
92 yaml_event_delete(&p.event)
93 p.event.typ = yaml_NO_EVENT
94}
95
96// peek peeks at the next event in the event stream,
97// puts the results into p.event and returns the event type.
98func (p *parser) peek() yaml_event_type_t {
99 if p.event.typ != yaml_NO_EVENT {
100 return p.event.typ
101 }
102 if !yaml_parser_parse(&p.parser, &p.event) {
103 p.fail()
104 }
105 return p.event.typ
106}
107
108func (p *parser) fail() {
109 var where string
110 var line int
111 if p.parser.problem_mark.line != 0 {
112 line = p.parser.problem_mark.line
113 // Scanner errors don't iterate line before returning error
114 if p.parser.error == yaml_SCANNER_ERROR {
115 line++
116 }
117 } else if p.parser.context_mark.line != 0 {
118 line = p.parser.context_mark.line
119 }
120 if line != 0 {
121 where = "line " + strconv.Itoa(line) + ": "
122 }
123 var msg string
124 if len(p.parser.problem) > 0 {
125 msg = p.parser.problem
126 } else {
127 msg = "unknown problem parsing YAML content"
128 }
129 failf("%s%s", where, msg)
130}
131
132func (p *parser) anchor(n *Node, anchor []byte) {
133 if anchor != nil {
134 n.Anchor = string(anchor)
135 p.anchors[n.Anchor] = n
136 }
137}
138
139func (p *parser) parse() *Node {
140 p.init()
141 switch p.peek() {
142 case yaml_SCALAR_EVENT:
143 return p.scalar()
144 case yaml_ALIAS_EVENT:
145 return p.alias()
146 case yaml_MAPPING_START_EVENT:
147 return p.mapping()
148 case yaml_SEQUENCE_START_EVENT:
149 return p.sequence()
150 case yaml_DOCUMENT_START_EVENT:
151 return p.document()
152 case yaml_STREAM_END_EVENT:
153 // Happens when attempting to decode an empty buffer.
154 return nil
155 case yaml_TAIL_COMMENT_EVENT:
156 panic("internal error: unexpected tail comment event (please report)")
157 default:
158 panic("internal error: attempted to parse unknown event (please report): " + p.event.typ.String())
159 }
160}
161
162func (p *parser) node(kind Kind, defaultTag, tag, value string) *Node {
163 var style Style
164 if tag != "" && tag != "!" {
165 tag = shortTag(tag)
166 style = TaggedStyle
167 } else if defaultTag != "" {
168 tag = defaultTag
169 } else if kind == ScalarNode {
170 tag, _ = resolve("", value)
171 }
172 return &Node{
173 Kind: kind,
174 Tag: tag,
175 Value: value,
176 Style: style,
177 Line: p.event.start_mark.line + 1,
178 Column: p.event.start_mark.column + 1,
179 HeadComment: string(p.event.head_comment),
180 LineComment: string(p.event.line_comment),
181 FootComment: string(p.event.foot_comment),
182 }
183}
184
185func (p *parser) parseChild(parent *Node) *Node {
186 child := p.parse()
187 parent.Content = append(parent.Content, child)
188 return child
189}
190
191func (p *parser) document() *Node {
192 n := p.node(DocumentNode, "", "", "")
193 p.doc = n
194 p.expect(yaml_DOCUMENT_START_EVENT)
195 p.parseChild(n)
196 if p.peek() == yaml_DOCUMENT_END_EVENT {
197 n.FootComment = string(p.event.foot_comment)
198 }
199 p.expect(yaml_DOCUMENT_END_EVENT)
200 return n
201}
202
203func (p *parser) alias() *Node {
204 n := p.node(AliasNode, "", "", string(p.event.anchor))
205 n.Alias = p.anchors[n.Value]
206 if n.Alias == nil {
207 failf("unknown anchor '%s' referenced", n.Value)
208 }
209 p.expect(yaml_ALIAS_EVENT)
210 return n
211}
212
213func (p *parser) scalar() *Node {
214 var parsedStyle = p.event.scalar_style()
215 var nodeStyle Style
216 switch {
217 case parsedStyle&yaml_DOUBLE_QUOTED_SCALAR_STYLE != 0:
218 nodeStyle = DoubleQuotedStyle
219 case parsedStyle&yaml_SINGLE_QUOTED_SCALAR_STYLE != 0:
220 nodeStyle = SingleQuotedStyle
221 case parsedStyle&yaml_LITERAL_SCALAR_STYLE != 0:
222 nodeStyle = LiteralStyle
223 case parsedStyle&yaml_FOLDED_SCALAR_STYLE != 0:
224 nodeStyle = FoldedStyle
225 }
226 var nodeValue = string(p.event.value)
227 var nodeTag = string(p.event.tag)
228 var defaultTag string
229 if nodeStyle == 0 {
230 if nodeValue == "<<" {
231 defaultTag = mergeTag
232 }
233 } else {
234 defaultTag = strTag
235 }
236 n := p.node(ScalarNode, defaultTag, nodeTag, nodeValue)
237 n.Style |= nodeStyle
238 p.anchor(n, p.event.anchor)
239 p.expect(yaml_SCALAR_EVENT)
240 return n
241}
242
243func (p *parser) sequence() *Node {
244 n := p.node(SequenceNode, seqTag, string(p.event.tag), "")
245 if p.event.sequence_style()&yaml_FLOW_SEQUENCE_STYLE != 0 {
246 n.Style |= FlowStyle
247 }
248 p.anchor(n, p.event.anchor)
249 p.expect(yaml_SEQUENCE_START_EVENT)
250 for p.peek() != yaml_SEQUENCE_END_EVENT {
251 p.parseChild(n)
252 }
253 n.LineComment = string(p.event.line_comment)
254 n.FootComment = string(p.event.foot_comment)
255 p.expect(yaml_SEQUENCE_END_EVENT)
256 return n
257}
258
259func (p *parser) mapping() *Node {
260 n := p.node(MappingNode, mapTag, string(p.event.tag), "")
261 block := true
262 if p.event.mapping_style()&yaml_FLOW_MAPPING_STYLE != 0 {
263 block = false
264 n.Style |= FlowStyle
265 }
266 p.anchor(n, p.event.anchor)
267 p.expect(yaml_MAPPING_START_EVENT)
268 for p.peek() != yaml_MAPPING_END_EVENT {
269 k := p.parseChild(n)
270 if block && k.FootComment != "" {
271 // Must be a foot comment for the prior value when being dedented.
272 if len(n.Content) > 2 {
273 n.Content[len(n.Content)-3].FootComment = k.FootComment
274 k.FootComment = ""
275 }
276 }
277 v := p.parseChild(n)
278 if k.FootComment == "" && v.FootComment != "" {
279 k.FootComment = v.FootComment
280 v.FootComment = ""
281 }
282 if p.peek() == yaml_TAIL_COMMENT_EVENT {
283 if k.FootComment == "" {
284 k.FootComment = string(p.event.foot_comment)
285 }
286 p.expect(yaml_TAIL_COMMENT_EVENT)
287 }
288 }
289 n.LineComment = string(p.event.line_comment)
290 n.FootComment = string(p.event.foot_comment)
291 if n.Style&FlowStyle == 0 && n.FootComment != "" && len(n.Content) > 1 {
292 n.Content[len(n.Content)-2].FootComment = n.FootComment
293 n.FootComment = ""
294 }
295 p.expect(yaml_MAPPING_END_EVENT)
296 return n
297}
298
299// ----------------------------------------------------------------------------
300// Decoder, unmarshals a node into a provided value.
301
302type decoder struct {
303 doc *Node
304 aliases map[*Node]bool
305 terrors []string
306
307 stringMapType reflect.Type
308 generalMapType reflect.Type
309
310 knownFields bool
311 uniqueKeys bool
312 decodeCount int
313 aliasCount int
314 aliasDepth int
315}
316
317var (
318 nodeType = reflect.TypeOf(Node{})
319 durationType = reflect.TypeOf(time.Duration(0))
320 stringMapType = reflect.TypeOf(map[string]interface{}{})
321 generalMapType = reflect.TypeOf(map[interface{}]interface{}{})
322 ifaceType = generalMapType.Elem()
323 timeType = reflect.TypeOf(time.Time{})
324 ptrTimeType = reflect.TypeOf(&time.Time{})
325)
326
327func newDecoder() *decoder {
328 d := &decoder{
329 stringMapType: stringMapType,
330 generalMapType: generalMapType,
331 uniqueKeys: true,
332 }
333 d.aliases = make(map[*Node]bool)
334 return d
335}
336
337func (d *decoder) terror(n *Node, tag string, out reflect.Value) {
338 if n.Tag != "" {
339 tag = n.Tag
340 }
341 value := n.Value
342 if tag != seqTag && tag != mapTag {
343 if len(value) > 10 {
344 value = " `" + value[:7] + "...`"
345 } else {
346 value = " `" + value + "`"
347 }
348 }
349 d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.Line, shortTag(tag), value, out.Type()))
350}
351
352func (d *decoder) callUnmarshaler(n *Node, u Unmarshaler) (good bool) {
353 err := u.UnmarshalYAML(n)
354 if e, ok := err.(*TypeError); ok {
355 d.terrors = append(d.terrors, e.Errors...)
356 return false
357 }
358 if err != nil {
359 fail(err)
360 }
361 return true
362}
363
364func (d *decoder) callObsoleteUnmarshaler(n *Node, u obsoleteUnmarshaler) (good bool) {
365 terrlen := len(d.terrors)
366 err := u.UnmarshalYAML(func(v interface{}) (err error) {
367 defer handleErr(&err)
368 d.unmarshal(n, reflect.ValueOf(v))
369 if len(d.terrors) > terrlen {
370 issues := d.terrors[terrlen:]
371 d.terrors = d.terrors[:terrlen]
372 return &TypeError{issues}
373 }
374 return nil
375 })
376 if e, ok := err.(*TypeError); ok {
377 d.terrors = append(d.terrors, e.Errors...)
378 return false
379 }
380 if err != nil {
381 fail(err)
382 }
383 return true
384}
385
386// d.prepare initializes and dereferences pointers and calls UnmarshalYAML
387// if a value is found to implement it.
388// It returns the initialized and dereferenced out value, whether
389// unmarshalling was already done by UnmarshalYAML, and if so whether
390// its types unmarshalled appropriately.
391//
392// If n holds a null value, prepare returns before doing anything.
393func (d *decoder) prepare(n *Node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
394 if n.ShortTag() == nullTag {
395 return out, false, false
396 }
397 again := true
398 for again {
399 again = false
400 if out.Kind() == reflect.Ptr {
401 if out.IsNil() {
402 out.Set(reflect.New(out.Type().Elem()))
403 }
404 out = out.Elem()
405 again = true
406 }
407 if out.CanAddr() {
408 outi := out.Addr().Interface()
409 if u, ok := outi.(Unmarshaler); ok {
410 good = d.callUnmarshaler(n, u)
411 return out, true, good
412 }
413 if u, ok := outi.(obsoleteUnmarshaler); ok {
414 good = d.callObsoleteUnmarshaler(n, u)
415 return out, true, good
416 }
417 }
418 }
419 return out, false, false
420}
421
422func (d *decoder) fieldByIndex(n *Node, v reflect.Value, index []int) (field reflect.Value) {
423 if n.ShortTag() == nullTag {
424 return reflect.Value{}
425 }
426 for _, num := range index {
427 for {
428 if v.Kind() == reflect.Ptr {
429 if v.IsNil() {
430 v.Set(reflect.New(v.Type().Elem()))
431 }
432 v = v.Elem()
433 continue
434 }
435 break
436 }
437 v = v.Field(num)
438 }
439 return v
440}
441
442const (
443 // 400,000 decode operations is ~500kb of dense object declarations, or
444 // ~5kb of dense object declarations with 10000% alias expansion
445 alias_ratio_range_low = 400000
446
447 // 4,000,000 decode operations is ~5MB of dense object declarations, or
448 // ~4.5MB of dense object declarations with 10% alias expansion
449 alias_ratio_range_high = 4000000
450
451 // alias_ratio_range is the range over which we scale allowed alias ratios
452 alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low)
453)
454
455func allowedAliasRatio(decodeCount int) float64 {
456 switch {
457 case decodeCount <= alias_ratio_range_low:
458 // allow 99% to come from alias expansion for small-to-medium documents
459 return 0.99
460 case decodeCount >= alias_ratio_range_high:
461 // allow 10% to come from alias expansion for very large documents
462 return 0.10
463 default:
464 // scale smoothly from 99% down to 10% over the range.
465 // this maps to 396,000 - 400,000 allowed alias-driven decodes over the range.
466 // 400,000 decode operations is ~100MB of allocations in worst-case scenarios (single-item maps).
467 return 0.99 - 0.89*(float64(decodeCount-alias_ratio_range_low)/alias_ratio_range)
468 }
469}
470
471func (d *decoder) unmarshal(n *Node, out reflect.Value) (good bool) {
472 d.decodeCount++
473 if d.aliasDepth > 0 {
474 d.aliasCount++
475 }
476 if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) {
477 failf("document contains excessive aliasing")
478 }
479 if out.Type() == nodeType {
480 out.Set(reflect.ValueOf(n).Elem())
481 return true
482 }
483 switch n.Kind {
484 case DocumentNode:
485 return d.document(n, out)
486 case AliasNode:
487 return d.alias(n, out)
488 }
489 out, unmarshaled, good := d.prepare(n, out)
490 if unmarshaled {
491 return good
492 }
493 switch n.Kind {
494 case ScalarNode:
495 good = d.scalar(n, out)
496 case MappingNode:
497 good = d.mapping(n, out)
498 case SequenceNode:
499 good = d.sequence(n, out)
500 default:
501 panic("internal error: unknown node kind: " + strconv.Itoa(int(n.Kind)))
502 }
503 return good
504}
505
506func (d *decoder) document(n *Node, out reflect.Value) (good bool) {
507 if len(n.Content) == 1 {
508 d.doc = n
509 d.unmarshal(n.Content[0], out)
510 return true
511 }
512 return false
513}
514
515func (d *decoder) alias(n *Node, out reflect.Value) (good bool) {
516 if d.aliases[n] {
517 // TODO this could actually be allowed in some circumstances.
518 failf("anchor '%s' value contains itself", n.Value)
519 }
520 d.aliases[n] = true
521 d.aliasDepth++
522 good = d.unmarshal(n.Alias, out)
523 d.aliasDepth--
524 delete(d.aliases, n)
525 return good
526}
527
528var zeroValue reflect.Value
529
530func resetMap(out reflect.Value) {
531 for _, k := range out.MapKeys() {
532 out.SetMapIndex(k, zeroValue)
533 }
534}
535
536func (d *decoder) scalar(n *Node, out reflect.Value) bool {
537 var tag string
538 var resolved interface{}
539 if n.indicatedString() {
540 tag = strTag
541 resolved = n.Value
542 } else {
543 tag, resolved = resolve(n.Tag, n.Value)
544 if tag == binaryTag {
545 data, err := base64.StdEncoding.DecodeString(resolved.(string))
546 if err != nil {
547 failf("!!binary value contains invalid base64 data")
548 }
549 resolved = string(data)
550 }
551 }
552 if resolved == nil {
553 if out.CanAddr() {
554 switch out.Kind() {
555 case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice:
556 out.Set(reflect.Zero(out.Type()))
557 return true
558 }
559 }
560 return false
561 }
562 if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
563 // We've resolved to exactly the type we want, so use that.
564 out.Set(resolvedv)
565 return true
566 }
567 // Perhaps we can use the value as a TextUnmarshaler to
568 // set its value.
569 if out.CanAddr() {
570 u, ok := out.Addr().Interface().(encoding.TextUnmarshaler)
571 if ok {
572 var text []byte
573 if tag == binaryTag {
574 text = []byte(resolved.(string))
575 } else {
576 // We let any value be unmarshaled into TextUnmarshaler.
577 // That might be more lax than we'd like, but the
578 // TextUnmarshaler itself should bowl out any dubious values.
579 text = []byte(n.Value)
580 }
581 err := u.UnmarshalText(text)
582 if err != nil {
583 fail(err)
584 }
585 return true
586 }
587 }
588 switch out.Kind() {
589 case reflect.String:
590 if tag == binaryTag {
591 out.SetString(resolved.(string))
592 return true
593 }
594 out.SetString(n.Value)
595 return true
596 case reflect.Interface:
597 out.Set(reflect.ValueOf(resolved))
598 return true
599 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
600 // This used to work in v2, but it's very unfriendly.
601 isDuration := out.Type() == durationType
602
603 switch resolved := resolved.(type) {
604 case int:
605 if !isDuration && !out.OverflowInt(int64(resolved)) {
606 out.SetInt(int64(resolved))
607 return true
608 }
609 case int64:
610 if !isDuration && !out.OverflowInt(resolved) {
611 out.SetInt(resolved)
612 return true
613 }
614 case uint64:
615 if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
616 out.SetInt(int64(resolved))
617 return true
618 }
619 case float64:
620 if !isDuration && resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
621 out.SetInt(int64(resolved))
622 return true
623 }
624 case string:
625 if out.Type() == durationType {
626 d, err := time.ParseDuration(resolved)
627 if err == nil {
628 out.SetInt(int64(d))
629 return true
630 }
631 }
632 }
633 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
634 switch resolved := resolved.(type) {
635 case int:
636 if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
637 out.SetUint(uint64(resolved))
638 return true
639 }
640 case int64:
641 if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
642 out.SetUint(uint64(resolved))
643 return true
644 }
645 case uint64:
646 if !out.OverflowUint(uint64(resolved)) {
647 out.SetUint(uint64(resolved))
648 return true
649 }
650 case float64:
651 if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {
652 out.SetUint(uint64(resolved))
653 return true
654 }
655 }
656 case reflect.Bool:
657 switch resolved := resolved.(type) {
658 case bool:
659 out.SetBool(resolved)
660 return true
661 case string:
662 // This offers some compatibility with the 1.1 spec (https://yaml.org/type/bool.html).
663 // It only works if explicitly attempting to unmarshal into a typed bool value.
664 switch resolved {
665 case "y", "Y", "yes", "Yes", "YES", "on", "On", "ON":
666 out.SetBool(true)
667 return true
668 case "n", "N", "no", "No", "NO", "off", "Off", "OFF":
669 out.SetBool(false)
670 return true
671 }
672 }
673 case reflect.Float32, reflect.Float64:
674 switch resolved := resolved.(type) {
675 case int:
676 out.SetFloat(float64(resolved))
677 return true
678 case int64:
679 out.SetFloat(float64(resolved))
680 return true
681 case uint64:
682 out.SetFloat(float64(resolved))
683 return true
684 case float64:
685 out.SetFloat(resolved)
686 return true
687 }
688 case reflect.Struct:
689 if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
690 out.Set(resolvedv)
691 return true
692 }
693 case reflect.Ptr:
694 panic("yaml internal error: please report the issue")
695 }
696 d.terror(n, tag, out)
697 return false
698}
699
700func settableValueOf(i interface{}) reflect.Value {
701 v := reflect.ValueOf(i)
702 sv := reflect.New(v.Type()).Elem()
703 sv.Set(v)
704 return sv
705}
706
707func (d *decoder) sequence(n *Node, out reflect.Value) (good bool) {
708 l := len(n.Content)
709
710 var iface reflect.Value
711 switch out.Kind() {
712 case reflect.Slice:
713 out.Set(reflect.MakeSlice(out.Type(), l, l))
714 case reflect.Array:
715 if l != out.Len() {
716 failf("invalid array: want %d elements but got %d", out.Len(), l)
717 }
718 case reflect.Interface:
719 // No type hints. Will have to use a generic sequence.
720 iface = out
721 out = settableValueOf(make([]interface{}, l))
722 default:
723 d.terror(n, seqTag, out)
724 return false
725 }
726 et := out.Type().Elem()
727
728 j := 0
729 for i := 0; i < l; i++ {
730 e := reflect.New(et).Elem()
731 if ok := d.unmarshal(n.Content[i], e); ok {
732 out.Index(j).Set(e)
733 j++
734 }
735 }
736 if out.Kind() != reflect.Array {
737 out.Set(out.Slice(0, j))
738 }
739 if iface.IsValid() {
740 iface.Set(out)
741 }
742 return true
743}
744
745func (d *decoder) mapping(n *Node, out reflect.Value) (good bool) {
746 l := len(n.Content)
747 if d.uniqueKeys {
748 nerrs := len(d.terrors)
749 for i := 0; i < l; i += 2 {
750 ni := n.Content[i]
751 for j := i + 2; j < l; j += 2 {
752 nj := n.Content[j]
753 if ni.Kind == nj.Kind && ni.Value == nj.Value {
754 d.terrors = append(d.terrors, fmt.Sprintf("line %d: mapping key %#v already defined at line %d", nj.Line, nj.Value, ni.Line))
755 }
756 }
757 }
758 if len(d.terrors) > nerrs {
759 return false
760 }
761 }
762 switch out.Kind() {
763 case reflect.Struct:
764 return d.mappingStruct(n, out)
765 case reflect.Map:
766 // okay
767 case reflect.Interface:
768 iface := out
769 if isStringMap(n) {
770 out = reflect.MakeMap(d.stringMapType)
771 } else {
772 out = reflect.MakeMap(d.generalMapType)
773 }
774 iface.Set(out)
775 default:
776 d.terror(n, mapTag, out)
777 return false
778 }
779
780 outt := out.Type()
781 kt := outt.Key()
782 et := outt.Elem()
783
784 stringMapType := d.stringMapType
785 generalMapType := d.generalMapType
786 if outt.Elem() == ifaceType {
787 if outt.Key().Kind() == reflect.String {
788 d.stringMapType = outt
789 } else if outt.Key() == ifaceType {
790 d.generalMapType = outt
791 }
792 }
793
794 if out.IsNil() {
795 out.Set(reflect.MakeMap(outt))
796 }
797 for i := 0; i < l; i += 2 {
798 if isMerge(n.Content[i]) {
799 d.merge(n.Content[i+1], out)
800 continue
801 }
802 k := reflect.New(kt).Elem()
803 if d.unmarshal(n.Content[i], k) {
804 kkind := k.Kind()
805 if kkind == reflect.Interface {
806 kkind = k.Elem().Kind()
807 }
808 if kkind == reflect.Map || kkind == reflect.Slice {
809 failf("invalid map key: %#v", k.Interface())
810 }
811 e := reflect.New(et).Elem()
812 if d.unmarshal(n.Content[i+1], e) {
813 out.SetMapIndex(k, e)
814 }
815 }
816 }
817 d.stringMapType = stringMapType
818 d.generalMapType = generalMapType
819 return true
820}
821
822func isStringMap(n *Node) bool {
823 if n.Kind != MappingNode {
824 return false
825 }
826 l := len(n.Content)
827 for i := 0; i < l; i += 2 {
828 if n.Content[i].ShortTag() != strTag {
829 return false
830 }
831 }
832 return true
833}
834
835func (d *decoder) mappingStruct(n *Node, out reflect.Value) (good bool) {
836 sinfo, err := getStructInfo(out.Type())
837 if err != nil {
838 panic(err)
839 }
840
841 var inlineMap reflect.Value
842 var elemType reflect.Type
843 if sinfo.InlineMap != -1 {
844 inlineMap = out.Field(sinfo.InlineMap)
845 inlineMap.Set(reflect.New(inlineMap.Type()).Elem())
846 elemType = inlineMap.Type().Elem()
847 }
848
849 for _, index := range sinfo.InlineUnmarshalers {
850 field := d.fieldByIndex(n, out, index)
851 d.prepare(n, field)
852 }
853
854 var doneFields []bool
855 if d.uniqueKeys {
856 doneFields = make([]bool, len(sinfo.FieldsList))
857 }
858 name := settableValueOf("")
859 l := len(n.Content)
860 for i := 0; i < l; i += 2 {
861 ni := n.Content[i]
862 if isMerge(ni) {
863 d.merge(n.Content[i+1], out)
864 continue
865 }
866 if !d.unmarshal(ni, name) {
867 continue
868 }
869 if info, ok := sinfo.FieldsMap[name.String()]; ok {
870 if d.uniqueKeys {
871 if doneFields[info.Id] {
872 d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.Line, name.String(), out.Type()))
873 continue
874 }
875 doneFields[info.Id] = true
876 }
877 var field reflect.Value
878 if info.Inline == nil {
879 field = out.Field(info.Num)
880 } else {
881 field = d.fieldByIndex(n, out, info.Inline)
882 }
883 d.unmarshal(n.Content[i+1], field)
884 } else if sinfo.InlineMap != -1 {
885 if inlineMap.IsNil() {
886 inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
887 }
888 value := reflect.New(elemType).Elem()
889 d.unmarshal(n.Content[i+1], value)
890 inlineMap.SetMapIndex(name, value)
891 } else if d.knownFields {
892 d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.Line, name.String(), out.Type()))
893 }
894 }
895 return true
896}
897
898func failWantMap() {
899 failf("map merge requires map or sequence of maps as the value")
900}
901
902func (d *decoder) merge(n *Node, out reflect.Value) {
903 switch n.Kind {
904 case MappingNode:
905 d.unmarshal(n, out)
906 case AliasNode:
907 if n.Alias != nil && n.Alias.Kind != MappingNode {
908 failWantMap()
909 }
910 d.unmarshal(n, out)
911 case SequenceNode:
912 // Step backwards as earlier nodes take precedence.
913 for i := len(n.Content) - 1; i >= 0; i-- {
914 ni := n.Content[i]
915 if ni.Kind == AliasNode {
916 if ni.Alias != nil && ni.Alias.Kind != MappingNode {
917 failWantMap()
918 }
919 } else if ni.Kind != MappingNode {
920 failWantMap()
921 }
922 d.unmarshal(ni, out)
923 }
924 default:
925 failWantMap()
926 }
927}
928
929func isMerge(n *Node) bool {
930 return n.Kind == ScalarNode && n.Value == "<<" && (n.Tag == "" || n.Tag == "!" || shortTag(n.Tag) == mergeTag)
931}