mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-11-03 17:42:25 -06:00 
			
		
		
		
	
		
			
	
	
		
			816 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			816 lines
		
	
	
	
		
			20 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| 
								 | 
							
								package yaml
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								import (
							 | 
						||
| 
								 | 
							
									"encoding"
							 | 
						||
| 
								 | 
							
									"encoding/base64"
							 | 
						||
| 
								 | 
							
									"fmt"
							 | 
						||
| 
								 | 
							
									"io"
							 | 
						||
| 
								 | 
							
									"math"
							 | 
						||
| 
								 | 
							
									"reflect"
							 | 
						||
| 
								 | 
							
									"strconv"
							 | 
						||
| 
								 | 
							
									"time"
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const (
							 | 
						||
| 
								 | 
							
									documentNode = 1 << iota
							 | 
						||
| 
								 | 
							
									mappingNode
							 | 
						||
| 
								 | 
							
									sequenceNode
							 | 
						||
| 
								 | 
							
									scalarNode
							 | 
						||
| 
								 | 
							
									aliasNode
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type node struct {
							 | 
						||
| 
								 | 
							
									kind         int
							 | 
						||
| 
								 | 
							
									line, column int
							 | 
						||
| 
								 | 
							
									tag          string
							 | 
						||
| 
								 | 
							
									// For an alias node, alias holds the resolved alias.
							 | 
						||
| 
								 | 
							
									alias    *node
							 | 
						||
| 
								 | 
							
									value    string
							 | 
						||
| 
								 | 
							
									implicit bool
							 | 
						||
| 
								 | 
							
									children []*node
							 | 
						||
| 
								 | 
							
									anchors  map[string]*node
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// ----------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								// Parser, produces a node tree out of a libyaml event stream.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type parser struct {
							 | 
						||
| 
								 | 
							
									parser   yaml_parser_t
							 | 
						||
| 
								 | 
							
									event    yaml_event_t
							 | 
						||
| 
								 | 
							
									doc      *node
							 | 
						||
| 
								 | 
							
									doneInit bool
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func newParser(b []byte) *parser {
							 | 
						||
| 
								 | 
							
									p := parser{}
							 | 
						||
| 
								 | 
							
									if !yaml_parser_initialize(&p.parser) {
							 | 
						||
| 
								 | 
							
										panic("failed to initialize YAML emitter")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if len(b) == 0 {
							 | 
						||
| 
								 | 
							
										b = []byte{'\n'}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									yaml_parser_set_input_string(&p.parser, b)
							 | 
						||
| 
								 | 
							
									return &p
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func newParserFromReader(r io.Reader) *parser {
							 | 
						||
| 
								 | 
							
									p := parser{}
							 | 
						||
| 
								 | 
							
									if !yaml_parser_initialize(&p.parser) {
							 | 
						||
| 
								 | 
							
										panic("failed to initialize YAML emitter")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									yaml_parser_set_input_reader(&p.parser, r)
							 | 
						||
| 
								 | 
							
									return &p
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p *parser) init() {
							 | 
						||
| 
								 | 
							
									if p.doneInit {
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									p.expect(yaml_STREAM_START_EVENT)
							 | 
						||
| 
								 | 
							
									p.doneInit = true
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p *parser) destroy() {
							 | 
						||
| 
								 | 
							
									if p.event.typ != yaml_NO_EVENT {
							 | 
						||
| 
								 | 
							
										yaml_event_delete(&p.event)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									yaml_parser_delete(&p.parser)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// expect consumes an event from the event stream and
							 | 
						||
| 
								 | 
							
								// checks that it's of the expected type.
							 | 
						||
| 
								 | 
							
								func (p *parser) expect(e yaml_event_type_t) {
							 | 
						||
| 
								 | 
							
									if p.event.typ == yaml_NO_EVENT {
							 | 
						||
| 
								 | 
							
										if !yaml_parser_parse(&p.parser, &p.event) {
							 | 
						||
| 
								 | 
							
											p.fail()
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if p.event.typ == yaml_STREAM_END_EVENT {
							 | 
						||
| 
								 | 
							
										failf("attempted to go past the end of stream; corrupted value?")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if p.event.typ != e {
							 | 
						||
| 
								 | 
							
										p.parser.problem = fmt.Sprintf("expected %s event but got %s", e, p.event.typ)
							 | 
						||
| 
								 | 
							
										p.fail()
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									yaml_event_delete(&p.event)
							 | 
						||
| 
								 | 
							
									p.event.typ = yaml_NO_EVENT
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// peek peeks at the next event in the event stream,
							 | 
						||
| 
								 | 
							
								// puts the results into p.event and returns the event type.
							 | 
						||
| 
								 | 
							
								func (p *parser) peek() yaml_event_type_t {
							 | 
						||
| 
								 | 
							
									if p.event.typ != yaml_NO_EVENT {
							 | 
						||
| 
								 | 
							
										return p.event.typ
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if !yaml_parser_parse(&p.parser, &p.event) {
							 | 
						||
| 
								 | 
							
										p.fail()
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return p.event.typ
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p *parser) fail() {
							 | 
						||
| 
								 | 
							
									var where string
							 | 
						||
| 
								 | 
							
									var line int
							 | 
						||
| 
								 | 
							
									if p.parser.problem_mark.line != 0 {
							 | 
						||
| 
								 | 
							
										line = p.parser.problem_mark.line
							 | 
						||
| 
								 | 
							
										// Scanner errors don't iterate line before returning error
							 | 
						||
| 
								 | 
							
										if p.parser.error == yaml_SCANNER_ERROR {
							 | 
						||
| 
								 | 
							
											line++
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									} else if p.parser.context_mark.line != 0 {
							 | 
						||
| 
								 | 
							
										line = p.parser.context_mark.line
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if line != 0 {
							 | 
						||
| 
								 | 
							
										where = "line " + strconv.Itoa(line) + ": "
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									var msg string
							 | 
						||
| 
								 | 
							
									if len(p.parser.problem) > 0 {
							 | 
						||
| 
								 | 
							
										msg = p.parser.problem
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										msg = "unknown problem parsing YAML content"
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									failf("%s%s", where, msg)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p *parser) anchor(n *node, anchor []byte) {
							 | 
						||
| 
								 | 
							
									if anchor != nil {
							 | 
						||
| 
								 | 
							
										p.doc.anchors[string(anchor)] = n
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p *parser) parse() *node {
							 | 
						||
| 
								 | 
							
									p.init()
							 | 
						||
| 
								 | 
							
									switch p.peek() {
							 | 
						||
| 
								 | 
							
									case yaml_SCALAR_EVENT:
							 | 
						||
| 
								 | 
							
										return p.scalar()
							 | 
						||
| 
								 | 
							
									case yaml_ALIAS_EVENT:
							 | 
						||
| 
								 | 
							
										return p.alias()
							 | 
						||
| 
								 | 
							
									case yaml_MAPPING_START_EVENT:
							 | 
						||
| 
								 | 
							
										return p.mapping()
							 | 
						||
| 
								 | 
							
									case yaml_SEQUENCE_START_EVENT:
							 | 
						||
| 
								 | 
							
										return p.sequence()
							 | 
						||
| 
								 | 
							
									case yaml_DOCUMENT_START_EVENT:
							 | 
						||
| 
								 | 
							
										return p.document()
							 | 
						||
| 
								 | 
							
									case yaml_STREAM_END_EVENT:
							 | 
						||
| 
								 | 
							
										// Happens when attempting to decode an empty buffer.
							 | 
						||
| 
								 | 
							
										return nil
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										panic("attempted to parse unknown event: " + p.event.typ.String())
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p *parser) node(kind int) *node {
							 | 
						||
| 
								 | 
							
									return &node{
							 | 
						||
| 
								 | 
							
										kind:   kind,
							 | 
						||
| 
								 | 
							
										line:   p.event.start_mark.line,
							 | 
						||
| 
								 | 
							
										column: p.event.start_mark.column,
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p *parser) document() *node {
							 | 
						||
| 
								 | 
							
									n := p.node(documentNode)
							 | 
						||
| 
								 | 
							
									n.anchors = make(map[string]*node)
							 | 
						||
| 
								 | 
							
									p.doc = n
							 | 
						||
| 
								 | 
							
									p.expect(yaml_DOCUMENT_START_EVENT)
							 | 
						||
| 
								 | 
							
									n.children = append(n.children, p.parse())
							 | 
						||
| 
								 | 
							
									p.expect(yaml_DOCUMENT_END_EVENT)
							 | 
						||
| 
								 | 
							
									return n
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p *parser) alias() *node {
							 | 
						||
| 
								 | 
							
									n := p.node(aliasNode)
							 | 
						||
| 
								 | 
							
									n.value = string(p.event.anchor)
							 | 
						||
| 
								 | 
							
									n.alias = p.doc.anchors[n.value]
							 | 
						||
| 
								 | 
							
									if n.alias == nil {
							 | 
						||
| 
								 | 
							
										failf("unknown anchor '%s' referenced", n.value)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									p.expect(yaml_ALIAS_EVENT)
							 | 
						||
| 
								 | 
							
									return n
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p *parser) scalar() *node {
							 | 
						||
| 
								 | 
							
									n := p.node(scalarNode)
							 | 
						||
| 
								 | 
							
									n.value = string(p.event.value)
							 | 
						||
| 
								 | 
							
									n.tag = string(p.event.tag)
							 | 
						||
| 
								 | 
							
									n.implicit = p.event.implicit
							 | 
						||
| 
								 | 
							
									p.anchor(n, p.event.anchor)
							 | 
						||
| 
								 | 
							
									p.expect(yaml_SCALAR_EVENT)
							 | 
						||
| 
								 | 
							
									return n
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p *parser) sequence() *node {
							 | 
						||
| 
								 | 
							
									n := p.node(sequenceNode)
							 | 
						||
| 
								 | 
							
									p.anchor(n, p.event.anchor)
							 | 
						||
| 
								 | 
							
									p.expect(yaml_SEQUENCE_START_EVENT)
							 | 
						||
| 
								 | 
							
									for p.peek() != yaml_SEQUENCE_END_EVENT {
							 | 
						||
| 
								 | 
							
										n.children = append(n.children, p.parse())
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									p.expect(yaml_SEQUENCE_END_EVENT)
							 | 
						||
| 
								 | 
							
									return n
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (p *parser) mapping() *node {
							 | 
						||
| 
								 | 
							
									n := p.node(mappingNode)
							 | 
						||
| 
								 | 
							
									p.anchor(n, p.event.anchor)
							 | 
						||
| 
								 | 
							
									p.expect(yaml_MAPPING_START_EVENT)
							 | 
						||
| 
								 | 
							
									for p.peek() != yaml_MAPPING_END_EVENT {
							 | 
						||
| 
								 | 
							
										n.children = append(n.children, p.parse(), p.parse())
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									p.expect(yaml_MAPPING_END_EVENT)
							 | 
						||
| 
								 | 
							
									return n
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// ----------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								// Decoder, unmarshals a node into a provided value.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								type decoder struct {
							 | 
						||
| 
								 | 
							
									doc     *node
							 | 
						||
| 
								 | 
							
									aliases map[*node]bool
							 | 
						||
| 
								 | 
							
									mapType reflect.Type
							 | 
						||
| 
								 | 
							
									terrors []string
							 | 
						||
| 
								 | 
							
									strict  bool
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									decodeCount int
							 | 
						||
| 
								 | 
							
									aliasCount  int
							 | 
						||
| 
								 | 
							
									aliasDepth  int
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var (
							 | 
						||
| 
								 | 
							
									mapItemType    = reflect.TypeOf(MapItem{})
							 | 
						||
| 
								 | 
							
									durationType   = reflect.TypeOf(time.Duration(0))
							 | 
						||
| 
								 | 
							
									defaultMapType = reflect.TypeOf(map[interface{}]interface{}{})
							 | 
						||
| 
								 | 
							
									ifaceType      = defaultMapType.Elem()
							 | 
						||
| 
								 | 
							
									timeType       = reflect.TypeOf(time.Time{})
							 | 
						||
| 
								 | 
							
									ptrTimeType    = reflect.TypeOf(&time.Time{})
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func newDecoder(strict bool) *decoder {
							 | 
						||
| 
								 | 
							
									d := &decoder{mapType: defaultMapType, strict: strict}
							 | 
						||
| 
								 | 
							
									d.aliases = make(map[*node]bool)
							 | 
						||
| 
								 | 
							
									return d
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (d *decoder) terror(n *node, tag string, out reflect.Value) {
							 | 
						||
| 
								 | 
							
									if n.tag != "" {
							 | 
						||
| 
								 | 
							
										tag = n.tag
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									value := n.value
							 | 
						||
| 
								 | 
							
									if tag != yaml_SEQ_TAG && tag != yaml_MAP_TAG {
							 | 
						||
| 
								 | 
							
										if len(value) > 10 {
							 | 
						||
| 
								 | 
							
											value = " `" + value[:7] + "...`"
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											value = " `" + value + "`"
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									d.terrors = append(d.terrors, fmt.Sprintf("line %d: cannot unmarshal %s%s into %s", n.line+1, shortTag(tag), value, out.Type()))
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (d *decoder) callUnmarshaler(n *node, u Unmarshaler) (good bool) {
							 | 
						||
| 
								 | 
							
									terrlen := len(d.terrors)
							 | 
						||
| 
								 | 
							
									err := u.UnmarshalYAML(func(v interface{}) (err error) {
							 | 
						||
| 
								 | 
							
										defer handleErr(&err)
							 | 
						||
| 
								 | 
							
										d.unmarshal(n, reflect.ValueOf(v))
							 | 
						||
| 
								 | 
							
										if len(d.terrors) > terrlen {
							 | 
						||
| 
								 | 
							
											issues := d.terrors[terrlen:]
							 | 
						||
| 
								 | 
							
											d.terrors = d.terrors[:terrlen]
							 | 
						||
| 
								 | 
							
											return &TypeError{issues}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										return nil
							 | 
						||
| 
								 | 
							
									})
							 | 
						||
| 
								 | 
							
									if e, ok := err.(*TypeError); ok {
							 | 
						||
| 
								 | 
							
										d.terrors = append(d.terrors, e.Errors...)
							 | 
						||
| 
								 | 
							
										return false
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										fail(err)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return true
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// d.prepare initializes and dereferences pointers and calls UnmarshalYAML
							 | 
						||
| 
								 | 
							
								// if a value is found to implement it.
							 | 
						||
| 
								 | 
							
								// It returns the initialized and dereferenced out value, whether
							 | 
						||
| 
								 | 
							
								// unmarshalling was already done by UnmarshalYAML, and if so whether
							 | 
						||
| 
								 | 
							
								// its types unmarshalled appropriately.
							 | 
						||
| 
								 | 
							
								//
							 | 
						||
| 
								 | 
							
								// If n holds a null value, prepare returns before doing anything.
							 | 
						||
| 
								 | 
							
								func (d *decoder) prepare(n *node, out reflect.Value) (newout reflect.Value, unmarshaled, good bool) {
							 | 
						||
| 
								 | 
							
									if n.tag == yaml_NULL_TAG || n.kind == scalarNode && n.tag == "" && (n.value == "null" || n.value == "~" || n.value == "" && n.implicit) {
							 | 
						||
| 
								 | 
							
										return out, false, false
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									again := true
							 | 
						||
| 
								 | 
							
									for again {
							 | 
						||
| 
								 | 
							
										again = false
							 | 
						||
| 
								 | 
							
										if out.Kind() == reflect.Ptr {
							 | 
						||
| 
								 | 
							
											if out.IsNil() {
							 | 
						||
| 
								 | 
							
												out.Set(reflect.New(out.Type().Elem()))
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											out = out.Elem()
							 | 
						||
| 
								 | 
							
											again = true
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if out.CanAddr() {
							 | 
						||
| 
								 | 
							
											if u, ok := out.Addr().Interface().(Unmarshaler); ok {
							 | 
						||
| 
								 | 
							
												good = d.callUnmarshaler(n, u)
							 | 
						||
| 
								 | 
							
												return out, true, good
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return out, false, false
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const (
							 | 
						||
| 
								 | 
							
									// 400,000 decode operations is ~500kb of dense object declarations, or
							 | 
						||
| 
								 | 
							
									// ~5kb of dense object declarations with 10000% alias expansion
							 | 
						||
| 
								 | 
							
									alias_ratio_range_low = 400000
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// 4,000,000 decode operations is ~5MB of dense object declarations, or
							 | 
						||
| 
								 | 
							
									// ~4.5MB of dense object declarations with 10% alias expansion
							 | 
						||
| 
								 | 
							
									alias_ratio_range_high = 4000000
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// alias_ratio_range is the range over which we scale allowed alias ratios
							 | 
						||
| 
								 | 
							
									alias_ratio_range = float64(alias_ratio_range_high - alias_ratio_range_low)
							 | 
						||
| 
								 | 
							
								)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func allowedAliasRatio(decodeCount int) float64 {
							 | 
						||
| 
								 | 
							
									switch {
							 | 
						||
| 
								 | 
							
									case decodeCount <= alias_ratio_range_low:
							 | 
						||
| 
								 | 
							
										// allow 99% to come from alias expansion for small-to-medium documents
							 | 
						||
| 
								 | 
							
										return 0.99
							 | 
						||
| 
								 | 
							
									case decodeCount >= alias_ratio_range_high:
							 | 
						||
| 
								 | 
							
										// allow 10% to come from alias expansion for very large documents
							 | 
						||
| 
								 | 
							
										return 0.10
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										// scale smoothly from 99% down to 10% over the range.
							 | 
						||
| 
								 | 
							
										// this maps to 396,000 - 400,000 allowed alias-driven decodes over the range.
							 | 
						||
| 
								 | 
							
										// 400,000 decode operations is ~100MB of allocations in worst-case scenarios (single-item maps).
							 | 
						||
| 
								 | 
							
										return 0.99 - 0.89*(float64(decodeCount-alias_ratio_range_low)/alias_ratio_range)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (d *decoder) unmarshal(n *node, out reflect.Value) (good bool) {
							 | 
						||
| 
								 | 
							
									d.decodeCount++
							 | 
						||
| 
								 | 
							
									if d.aliasDepth > 0 {
							 | 
						||
| 
								 | 
							
										d.aliasCount++
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if d.aliasCount > 100 && d.decodeCount > 1000 && float64(d.aliasCount)/float64(d.decodeCount) > allowedAliasRatio(d.decodeCount) {
							 | 
						||
| 
								 | 
							
										failf("document contains excessive aliasing")
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									switch n.kind {
							 | 
						||
| 
								 | 
							
									case documentNode:
							 | 
						||
| 
								 | 
							
										return d.document(n, out)
							 | 
						||
| 
								 | 
							
									case aliasNode:
							 | 
						||
| 
								 | 
							
										return d.alias(n, out)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									out, unmarshaled, good := d.prepare(n, out)
							 | 
						||
| 
								 | 
							
									if unmarshaled {
							 | 
						||
| 
								 | 
							
										return good
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									switch n.kind {
							 | 
						||
| 
								 | 
							
									case scalarNode:
							 | 
						||
| 
								 | 
							
										good = d.scalar(n, out)
							 | 
						||
| 
								 | 
							
									case mappingNode:
							 | 
						||
| 
								 | 
							
										good = d.mapping(n, out)
							 | 
						||
| 
								 | 
							
									case sequenceNode:
							 | 
						||
| 
								 | 
							
										good = d.sequence(n, out)
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										panic("internal error: unknown node kind: " + strconv.Itoa(n.kind))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return good
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (d *decoder) document(n *node, out reflect.Value) (good bool) {
							 | 
						||
| 
								 | 
							
									if len(n.children) == 1 {
							 | 
						||
| 
								 | 
							
										d.doc = n
							 | 
						||
| 
								 | 
							
										d.unmarshal(n.children[0], out)
							 | 
						||
| 
								 | 
							
										return true
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return false
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (d *decoder) alias(n *node, out reflect.Value) (good bool) {
							 | 
						||
| 
								 | 
							
									if d.aliases[n] {
							 | 
						||
| 
								 | 
							
										// TODO this could actually be allowed in some circumstances.
							 | 
						||
| 
								 | 
							
										failf("anchor '%s' value contains itself", n.value)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									d.aliases[n] = true
							 | 
						||
| 
								 | 
							
									d.aliasDepth++
							 | 
						||
| 
								 | 
							
									good = d.unmarshal(n.alias, out)
							 | 
						||
| 
								 | 
							
									d.aliasDepth--
							 | 
						||
| 
								 | 
							
									delete(d.aliases, n)
							 | 
						||
| 
								 | 
							
									return good
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var zeroValue reflect.Value
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func resetMap(out reflect.Value) {
							 | 
						||
| 
								 | 
							
									for _, k := range out.MapKeys() {
							 | 
						||
| 
								 | 
							
										out.SetMapIndex(k, zeroValue)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (d *decoder) scalar(n *node, out reflect.Value) bool {
							 | 
						||
| 
								 | 
							
									var tag string
							 | 
						||
| 
								 | 
							
									var resolved interface{}
							 | 
						||
| 
								 | 
							
									if n.tag == "" && !n.implicit {
							 | 
						||
| 
								 | 
							
										tag = yaml_STR_TAG
							 | 
						||
| 
								 | 
							
										resolved = n.value
							 | 
						||
| 
								 | 
							
									} else {
							 | 
						||
| 
								 | 
							
										tag, resolved = resolve(n.tag, n.value)
							 | 
						||
| 
								 | 
							
										if tag == yaml_BINARY_TAG {
							 | 
						||
| 
								 | 
							
											data, err := base64.StdEncoding.DecodeString(resolved.(string))
							 | 
						||
| 
								 | 
							
											if err != nil {
							 | 
						||
| 
								 | 
							
												failf("!!binary value contains invalid base64 data")
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											resolved = string(data)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if resolved == nil {
							 | 
						||
| 
								 | 
							
										if out.Kind() == reflect.Map && !out.CanAddr() {
							 | 
						||
| 
								 | 
							
											resetMap(out)
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											out.Set(reflect.Zero(out.Type()))
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										return true
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
							 | 
						||
| 
								 | 
							
										// We've resolved to exactly the type we want, so use that.
							 | 
						||
| 
								 | 
							
										out.Set(resolvedv)
							 | 
						||
| 
								 | 
							
										return true
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									// Perhaps we can use the value as a TextUnmarshaler to
							 | 
						||
| 
								 | 
							
									// set its value.
							 | 
						||
| 
								 | 
							
									if out.CanAddr() {
							 | 
						||
| 
								 | 
							
										u, ok := out.Addr().Interface().(encoding.TextUnmarshaler)
							 | 
						||
| 
								 | 
							
										if ok {
							 | 
						||
| 
								 | 
							
											var text []byte
							 | 
						||
| 
								 | 
							
											if tag == yaml_BINARY_TAG {
							 | 
						||
| 
								 | 
							
												text = []byte(resolved.(string))
							 | 
						||
| 
								 | 
							
											} else {
							 | 
						||
| 
								 | 
							
												// We let any value be unmarshaled into TextUnmarshaler.
							 | 
						||
| 
								 | 
							
												// That might be more lax than we'd like, but the
							 | 
						||
| 
								 | 
							
												// TextUnmarshaler itself should bowl out any dubious values.
							 | 
						||
| 
								 | 
							
												text = []byte(n.value)
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											err := u.UnmarshalText(text)
							 | 
						||
| 
								 | 
							
											if err != nil {
							 | 
						||
| 
								 | 
							
												fail(err)
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											return true
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									switch out.Kind() {
							 | 
						||
| 
								 | 
							
									case reflect.String:
							 | 
						||
| 
								 | 
							
										if tag == yaml_BINARY_TAG {
							 | 
						||
| 
								 | 
							
											out.SetString(resolved.(string))
							 | 
						||
| 
								 | 
							
											return true
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if resolved != nil {
							 | 
						||
| 
								 | 
							
											out.SetString(n.value)
							 | 
						||
| 
								 | 
							
											return true
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									case reflect.Interface:
							 | 
						||
| 
								 | 
							
										if resolved == nil {
							 | 
						||
| 
								 | 
							
											out.Set(reflect.Zero(out.Type()))
							 | 
						||
| 
								 | 
							
										} else if tag == yaml_TIMESTAMP_TAG {
							 | 
						||
| 
								 | 
							
											// It looks like a timestamp but for backward compatibility
							 | 
						||
| 
								 | 
							
											// reasons we set it as a string, so that code that unmarshals
							 | 
						||
| 
								 | 
							
											// timestamp-like values into interface{} will continue to
							 | 
						||
| 
								 | 
							
											// see a string and not a time.Time.
							 | 
						||
| 
								 | 
							
											// TODO(v3) Drop this.
							 | 
						||
| 
								 | 
							
											out.Set(reflect.ValueOf(n.value))
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											out.Set(reflect.ValueOf(resolved))
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										return true
							 | 
						||
| 
								 | 
							
									case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
							 | 
						||
| 
								 | 
							
										switch resolved := resolved.(type) {
							 | 
						||
| 
								 | 
							
										case int:
							 | 
						||
| 
								 | 
							
											if !out.OverflowInt(int64(resolved)) {
							 | 
						||
| 
								 | 
							
												out.SetInt(int64(resolved))
							 | 
						||
| 
								 | 
							
												return true
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										case int64:
							 | 
						||
| 
								 | 
							
											if !out.OverflowInt(resolved) {
							 | 
						||
| 
								 | 
							
												out.SetInt(resolved)
							 | 
						||
| 
								 | 
							
												return true
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										case uint64:
							 | 
						||
| 
								 | 
							
											if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
							 | 
						||
| 
								 | 
							
												out.SetInt(int64(resolved))
							 | 
						||
| 
								 | 
							
												return true
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										case float64:
							 | 
						||
| 
								 | 
							
											if resolved <= math.MaxInt64 && !out.OverflowInt(int64(resolved)) {
							 | 
						||
| 
								 | 
							
												out.SetInt(int64(resolved))
							 | 
						||
| 
								 | 
							
												return true
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										case string:
							 | 
						||
| 
								 | 
							
											if out.Type() == durationType {
							 | 
						||
| 
								 | 
							
												d, err := time.ParseDuration(resolved)
							 | 
						||
| 
								 | 
							
												if err == nil {
							 | 
						||
| 
								 | 
							
													out.SetInt(int64(d))
							 | 
						||
| 
								 | 
							
													return true
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
							 | 
						||
| 
								 | 
							
										switch resolved := resolved.(type) {
							 | 
						||
| 
								 | 
							
										case int:
							 | 
						||
| 
								 | 
							
											if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
							 | 
						||
| 
								 | 
							
												out.SetUint(uint64(resolved))
							 | 
						||
| 
								 | 
							
												return true
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										case int64:
							 | 
						||
| 
								 | 
							
											if resolved >= 0 && !out.OverflowUint(uint64(resolved)) {
							 | 
						||
| 
								 | 
							
												out.SetUint(uint64(resolved))
							 | 
						||
| 
								 | 
							
												return true
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										case uint64:
							 | 
						||
| 
								 | 
							
											if !out.OverflowUint(uint64(resolved)) {
							 | 
						||
| 
								 | 
							
												out.SetUint(uint64(resolved))
							 | 
						||
| 
								 | 
							
												return true
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										case float64:
							 | 
						||
| 
								 | 
							
											if resolved <= math.MaxUint64 && !out.OverflowUint(uint64(resolved)) {
							 | 
						||
| 
								 | 
							
												out.SetUint(uint64(resolved))
							 | 
						||
| 
								 | 
							
												return true
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									case reflect.Bool:
							 | 
						||
| 
								 | 
							
										switch resolved := resolved.(type) {
							 | 
						||
| 
								 | 
							
										case bool:
							 | 
						||
| 
								 | 
							
											out.SetBool(resolved)
							 | 
						||
| 
								 | 
							
											return true
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									case reflect.Float32, reflect.Float64:
							 | 
						||
| 
								 | 
							
										switch resolved := resolved.(type) {
							 | 
						||
| 
								 | 
							
										case int:
							 | 
						||
| 
								 | 
							
											out.SetFloat(float64(resolved))
							 | 
						||
| 
								 | 
							
											return true
							 | 
						||
| 
								 | 
							
										case int64:
							 | 
						||
| 
								 | 
							
											out.SetFloat(float64(resolved))
							 | 
						||
| 
								 | 
							
											return true
							 | 
						||
| 
								 | 
							
										case uint64:
							 | 
						||
| 
								 | 
							
											out.SetFloat(float64(resolved))
							 | 
						||
| 
								 | 
							
											return true
							 | 
						||
| 
								 | 
							
										case float64:
							 | 
						||
| 
								 | 
							
											out.SetFloat(resolved)
							 | 
						||
| 
								 | 
							
											return true
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									case reflect.Struct:
							 | 
						||
| 
								 | 
							
										if resolvedv := reflect.ValueOf(resolved); out.Type() == resolvedv.Type() {
							 | 
						||
| 
								 | 
							
											out.Set(resolvedv)
							 | 
						||
| 
								 | 
							
											return true
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									case reflect.Ptr:
							 | 
						||
| 
								 | 
							
										if out.Type().Elem() == reflect.TypeOf(resolved) {
							 | 
						||
| 
								 | 
							
											// TODO DOes this make sense? When is out a Ptr except when decoding a nil value?
							 | 
						||
| 
								 | 
							
											elem := reflect.New(out.Type().Elem())
							 | 
						||
| 
								 | 
							
											elem.Elem().Set(reflect.ValueOf(resolved))
							 | 
						||
| 
								 | 
							
											out.Set(elem)
							 | 
						||
| 
								 | 
							
											return true
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									d.terror(n, tag, out)
							 | 
						||
| 
								 | 
							
									return false
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func settableValueOf(i interface{}) reflect.Value {
							 | 
						||
| 
								 | 
							
									v := reflect.ValueOf(i)
							 | 
						||
| 
								 | 
							
									sv := reflect.New(v.Type()).Elem()
							 | 
						||
| 
								 | 
							
									sv.Set(v)
							 | 
						||
| 
								 | 
							
									return sv
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (d *decoder) sequence(n *node, out reflect.Value) (good bool) {
							 | 
						||
| 
								 | 
							
									l := len(n.children)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var iface reflect.Value
							 | 
						||
| 
								 | 
							
									switch out.Kind() {
							 | 
						||
| 
								 | 
							
									case reflect.Slice:
							 | 
						||
| 
								 | 
							
										out.Set(reflect.MakeSlice(out.Type(), l, l))
							 | 
						||
| 
								 | 
							
									case reflect.Array:
							 | 
						||
| 
								 | 
							
										if l != out.Len() {
							 | 
						||
| 
								 | 
							
											failf("invalid array: want %d elements but got %d", out.Len(), l)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									case reflect.Interface:
							 | 
						||
| 
								 | 
							
										// No type hints. Will have to use a generic sequence.
							 | 
						||
| 
								 | 
							
										iface = out
							 | 
						||
| 
								 | 
							
										out = settableValueOf(make([]interface{}, l))
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										d.terror(n, yaml_SEQ_TAG, out)
							 | 
						||
| 
								 | 
							
										return false
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									et := out.Type().Elem()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									j := 0
							 | 
						||
| 
								 | 
							
									for i := 0; i < l; i++ {
							 | 
						||
| 
								 | 
							
										e := reflect.New(et).Elem()
							 | 
						||
| 
								 | 
							
										if ok := d.unmarshal(n.children[i], e); ok {
							 | 
						||
| 
								 | 
							
											out.Index(j).Set(e)
							 | 
						||
| 
								 | 
							
											j++
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if out.Kind() != reflect.Array {
							 | 
						||
| 
								 | 
							
										out.Set(out.Slice(0, j))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if iface.IsValid() {
							 | 
						||
| 
								 | 
							
										iface.Set(out)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return true
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (d *decoder) mapping(n *node, out reflect.Value) (good bool) {
							 | 
						||
| 
								 | 
							
									switch out.Kind() {
							 | 
						||
| 
								 | 
							
									case reflect.Struct:
							 | 
						||
| 
								 | 
							
										return d.mappingStruct(n, out)
							 | 
						||
| 
								 | 
							
									case reflect.Slice:
							 | 
						||
| 
								 | 
							
										return d.mappingSlice(n, out)
							 | 
						||
| 
								 | 
							
									case reflect.Map:
							 | 
						||
| 
								 | 
							
										// okay
							 | 
						||
| 
								 | 
							
									case reflect.Interface:
							 | 
						||
| 
								 | 
							
										if d.mapType.Kind() == reflect.Map {
							 | 
						||
| 
								 | 
							
											iface := out
							 | 
						||
| 
								 | 
							
											out = reflect.MakeMap(d.mapType)
							 | 
						||
| 
								 | 
							
											iface.Set(out)
							 | 
						||
| 
								 | 
							
										} else {
							 | 
						||
| 
								 | 
							
											slicev := reflect.New(d.mapType).Elem()
							 | 
						||
| 
								 | 
							
											if !d.mappingSlice(n, slicev) {
							 | 
						||
| 
								 | 
							
												return false
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											out.Set(slicev)
							 | 
						||
| 
								 | 
							
											return true
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										d.terror(n, yaml_MAP_TAG, out)
							 | 
						||
| 
								 | 
							
										return false
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									outt := out.Type()
							 | 
						||
| 
								 | 
							
									kt := outt.Key()
							 | 
						||
| 
								 | 
							
									et := outt.Elem()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									mapType := d.mapType
							 | 
						||
| 
								 | 
							
									if outt.Key() == ifaceType && outt.Elem() == ifaceType {
							 | 
						||
| 
								 | 
							
										d.mapType = outt
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if out.IsNil() {
							 | 
						||
| 
								 | 
							
										out.Set(reflect.MakeMap(outt))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									l := len(n.children)
							 | 
						||
| 
								 | 
							
									for i := 0; i < l; i += 2 {
							 | 
						||
| 
								 | 
							
										if isMerge(n.children[i]) {
							 | 
						||
| 
								 | 
							
											d.merge(n.children[i+1], out)
							 | 
						||
| 
								 | 
							
											continue
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										k := reflect.New(kt).Elem()
							 | 
						||
| 
								 | 
							
										if d.unmarshal(n.children[i], k) {
							 | 
						||
| 
								 | 
							
											kkind := k.Kind()
							 | 
						||
| 
								 | 
							
											if kkind == reflect.Interface {
							 | 
						||
| 
								 | 
							
												kkind = k.Elem().Kind()
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											if kkind == reflect.Map || kkind == reflect.Slice {
							 | 
						||
| 
								 | 
							
												failf("invalid map key: %#v", k.Interface())
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											e := reflect.New(et).Elem()
							 | 
						||
| 
								 | 
							
											if d.unmarshal(n.children[i+1], e) {
							 | 
						||
| 
								 | 
							
												d.setMapIndex(n.children[i+1], out, k, e)
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									d.mapType = mapType
							 | 
						||
| 
								 | 
							
									return true
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (d *decoder) setMapIndex(n *node, out, k, v reflect.Value) {
							 | 
						||
| 
								 | 
							
									if d.strict && out.MapIndex(k) != zeroValue {
							 | 
						||
| 
								 | 
							
										d.terrors = append(d.terrors, fmt.Sprintf("line %d: key %#v already set in map", n.line+1, k.Interface()))
							 | 
						||
| 
								 | 
							
										return
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									out.SetMapIndex(k, v)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (d *decoder) mappingSlice(n *node, out reflect.Value) (good bool) {
							 | 
						||
| 
								 | 
							
									outt := out.Type()
							 | 
						||
| 
								 | 
							
									if outt.Elem() != mapItemType {
							 | 
						||
| 
								 | 
							
										d.terror(n, yaml_MAP_TAG, out)
							 | 
						||
| 
								 | 
							
										return false
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									mapType := d.mapType
							 | 
						||
| 
								 | 
							
									d.mapType = outt
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var slice []MapItem
							 | 
						||
| 
								 | 
							
									var l = len(n.children)
							 | 
						||
| 
								 | 
							
									for i := 0; i < l; i += 2 {
							 | 
						||
| 
								 | 
							
										if isMerge(n.children[i]) {
							 | 
						||
| 
								 | 
							
											d.merge(n.children[i+1], out)
							 | 
						||
| 
								 | 
							
											continue
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										item := MapItem{}
							 | 
						||
| 
								 | 
							
										k := reflect.ValueOf(&item.Key).Elem()
							 | 
						||
| 
								 | 
							
										if d.unmarshal(n.children[i], k) {
							 | 
						||
| 
								 | 
							
											v := reflect.ValueOf(&item.Value).Elem()
							 | 
						||
| 
								 | 
							
											if d.unmarshal(n.children[i+1], v) {
							 | 
						||
| 
								 | 
							
												slice = append(slice, item)
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									out.Set(reflect.ValueOf(slice))
							 | 
						||
| 
								 | 
							
									d.mapType = mapType
							 | 
						||
| 
								 | 
							
									return true
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (d *decoder) mappingStruct(n *node, out reflect.Value) (good bool) {
							 | 
						||
| 
								 | 
							
									sinfo, err := getStructInfo(out.Type())
							 | 
						||
| 
								 | 
							
									if err != nil {
							 | 
						||
| 
								 | 
							
										panic(err)
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									name := settableValueOf("")
							 | 
						||
| 
								 | 
							
									l := len(n.children)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var inlineMap reflect.Value
							 | 
						||
| 
								 | 
							
									var elemType reflect.Type
							 | 
						||
| 
								 | 
							
									if sinfo.InlineMap != -1 {
							 | 
						||
| 
								 | 
							
										inlineMap = out.Field(sinfo.InlineMap)
							 | 
						||
| 
								 | 
							
										inlineMap.Set(reflect.New(inlineMap.Type()).Elem())
							 | 
						||
| 
								 | 
							
										elemType = inlineMap.Type().Elem()
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									var doneFields []bool
							 | 
						||
| 
								 | 
							
									if d.strict {
							 | 
						||
| 
								 | 
							
										doneFields = make([]bool, len(sinfo.FieldsList))
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									for i := 0; i < l; i += 2 {
							 | 
						||
| 
								 | 
							
										ni := n.children[i]
							 | 
						||
| 
								 | 
							
										if isMerge(ni) {
							 | 
						||
| 
								 | 
							
											d.merge(n.children[i+1], out)
							 | 
						||
| 
								 | 
							
											continue
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if !d.unmarshal(ni, name) {
							 | 
						||
| 
								 | 
							
											continue
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if info, ok := sinfo.FieldsMap[name.String()]; ok {
							 | 
						||
| 
								 | 
							
											if d.strict {
							 | 
						||
| 
								 | 
							
												if doneFields[info.Id] {
							 | 
						||
| 
								 | 
							
													d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s already set in type %s", ni.line+1, name.String(), out.Type()))
							 | 
						||
| 
								 | 
							
													continue
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												doneFields[info.Id] = true
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											var field reflect.Value
							 | 
						||
| 
								 | 
							
											if info.Inline == nil {
							 | 
						||
| 
								 | 
							
												field = out.Field(info.Num)
							 | 
						||
| 
								 | 
							
											} else {
							 | 
						||
| 
								 | 
							
												field = out.FieldByIndex(info.Inline)
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											d.unmarshal(n.children[i+1], field)
							 | 
						||
| 
								 | 
							
										} else if sinfo.InlineMap != -1 {
							 | 
						||
| 
								 | 
							
											if inlineMap.IsNil() {
							 | 
						||
| 
								 | 
							
												inlineMap.Set(reflect.MakeMap(inlineMap.Type()))
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											value := reflect.New(elemType).Elem()
							 | 
						||
| 
								 | 
							
											d.unmarshal(n.children[i+1], value)
							 | 
						||
| 
								 | 
							
											d.setMapIndex(n.children[i+1], inlineMap, name, value)
							 | 
						||
| 
								 | 
							
										} else if d.strict {
							 | 
						||
| 
								 | 
							
											d.terrors = append(d.terrors, fmt.Sprintf("line %d: field %s not found in type %s", ni.line+1, name.String(), out.Type()))
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return true
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func failWantMap() {
							 | 
						||
| 
								 | 
							
									failf("map merge requires map or sequence of maps as the value")
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func (d *decoder) merge(n *node, out reflect.Value) {
							 | 
						||
| 
								 | 
							
									switch n.kind {
							 | 
						||
| 
								 | 
							
									case mappingNode:
							 | 
						||
| 
								 | 
							
										d.unmarshal(n, out)
							 | 
						||
| 
								 | 
							
									case aliasNode:
							 | 
						||
| 
								 | 
							
										if n.alias != nil && n.alias.kind != mappingNode {
							 | 
						||
| 
								 | 
							
											failWantMap()
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										d.unmarshal(n, out)
							 | 
						||
| 
								 | 
							
									case sequenceNode:
							 | 
						||
| 
								 | 
							
										// Step backwards as earlier nodes take precedence.
							 | 
						||
| 
								 | 
							
										for i := len(n.children) - 1; i >= 0; i-- {
							 | 
						||
| 
								 | 
							
											ni := n.children[i]
							 | 
						||
| 
								 | 
							
											if ni.kind == aliasNode {
							 | 
						||
| 
								 | 
							
												if ni.alias != nil && ni.alias.kind != mappingNode {
							 | 
						||
| 
								 | 
							
													failWantMap()
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											} else if ni.kind != mappingNode {
							 | 
						||
| 
								 | 
							
												failWantMap()
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											d.unmarshal(ni, out)
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									default:
							 | 
						||
| 
								 | 
							
										failWantMap()
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								func isMerge(n *node) bool {
							 | 
						||
| 
								 | 
							
									return n.kind == scalarNode && n.value == "<<" && (n.implicit == true || n.tag == yaml_MERGE_TAG)
							 | 
						||
| 
								 | 
							
								}
							 |