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