// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package xml

import (
	
	
	
	
	
	
	
	
)

// BUG(rsc): Mapping between XML elements and data structures is inherently flawed:
// an XML element is an order-dependent collection of anonymous
// values, while a data structure is an order-independent collection
// of named values.
// See [encoding/json] for a textual representation more suitable
// to data structures.

// Unmarshal parses the XML-encoded data and stores the result in
// the value pointed to by v, which must be an arbitrary struct,
// slice, or string. Well-formed data that does not fit into v is
// discarded.
//
// Because Unmarshal uses the reflect package, it can only assign
// to exported (upper case) fields. Unmarshal uses a case-sensitive
// comparison to match XML element names to tag values and struct
// field names.
//
// Unmarshal maps an XML element to a struct using the following rules.
// In the rules, the tag of a field refers to the value associated with the
// key 'xml' in the struct field's tag (see the example above).
//
//   - If the struct has a field of type []byte or string with tag
//     ",innerxml", Unmarshal accumulates the raw XML nested inside the
//     element in that field. The rest of the rules still apply.
//
//   - If the struct has a field named XMLName of type Name,
//     Unmarshal records the element name in that field.
//
//   - If the XMLName field has an associated tag of the form
//     "name" or "namespace-URL name", the XML element must have
//     the given name (and, optionally, name space) or else Unmarshal
//     returns an error.
//
//   - If the XML element has an attribute whose name matches a
//     struct field name with an associated tag containing ",attr" or
//     the explicit name in a struct field tag of the form "name,attr",
//     Unmarshal records the attribute value in that field.
//
//   - If the XML element has an attribute not handled by the previous
//     rule and the struct has a field with an associated tag containing
//     ",any,attr", Unmarshal records the attribute value in the first
//     such field.
//
//   - If the XML element contains character data, that data is
//     accumulated in the first struct field that has tag ",chardata".
//     The struct field may have type []byte or string.
//     If there is no such field, the character data is discarded.
//
//   - If the XML element contains comments, they are accumulated in
//     the first struct field that has tag ",comment".  The struct
//     field may have type []byte or string. If there is no such
//     field, the comments are discarded.
//
//   - If the XML element contains a sub-element whose name matches
//     the prefix of a tag formatted as "a" or "a>b>c", unmarshal
//     will descend into the XML structure looking for elements with the
//     given names, and will map the innermost elements to that struct
//     field. A tag starting with ">" is equivalent to one starting
//     with the field name followed by ">".
//
//   - If the XML element contains a sub-element whose name matches
//     a struct field's XMLName tag and the struct field has no
//     explicit name tag as per the previous rule, unmarshal maps
//     the sub-element to that struct field.
//
//   - If the XML element contains a sub-element whose name matches a
//     field without any mode flags (",attr", ",chardata", etc), Unmarshal
//     maps the sub-element to that struct field.
//
//   - If the XML element contains a sub-element that hasn't matched any
//     of the above rules and the struct has a field with tag ",any",
//     unmarshal maps the sub-element to that struct field.
//
//   - An anonymous struct field is handled as if the fields of its
//     value were part of the outer struct.
//
//   - A struct field with tag "-" is never unmarshaled into.
//
// If Unmarshal encounters a field type that implements the Unmarshaler
// interface, Unmarshal calls its UnmarshalXML method to produce the value from
// the XML element.  Otherwise, if the value implements
// [encoding.TextUnmarshaler], Unmarshal calls that value's UnmarshalText method.
//
// Unmarshal maps an XML element to a string or []byte by saving the
// concatenation of that element's character data in the string or
// []byte. The saved []byte is never nil.
//
// Unmarshal maps an attribute value to a string or []byte by saving
// the value in the string or slice.
//
// Unmarshal maps an attribute value to an [Attr] by saving the attribute,
// including its name, in the Attr.
//
// Unmarshal maps an XML element or attribute value to a slice by
// extending the length of the slice and mapping the element or attribute
// to the newly created value.
//
// Unmarshal maps an XML element or attribute value to a bool by
// setting it to the boolean value represented by the string. Whitespace
// is trimmed and ignored.
//
// Unmarshal maps an XML element or attribute value to an integer or
// floating-point field by setting the field to the result of
// interpreting the string value in decimal. There is no check for
// overflow. Whitespace is trimmed and ignored.
//
// Unmarshal maps an XML element to a Name by recording the element
// name.
//
// Unmarshal maps an XML element to a pointer by setting the pointer
// to a freshly allocated value and then mapping the element to that value.
//
// A missing element or empty attribute value will be unmarshaled as a zero value.
// If the field is a slice, a zero value will be appended to the field. Otherwise, the
// field will be set to its zero value.
func ( []byte,  any) error {
	return NewDecoder(bytes.NewReader()).Decode()
}

// Decode works like [Unmarshal], except it reads the decoder
// stream to find the start element.
func ( *Decoder) ( any) error {
	return .DecodeElement(, nil)
}

// DecodeElement works like [Unmarshal] except that it takes
// a pointer to the start XML element to decode into v.
// It is useful when a client reads some raw XML tokens itself
// but also wants to defer to [Unmarshal] for some elements.
func ( *Decoder) ( any,  *StartElement) error {
	 := reflect.ValueOf()
	if .Kind() != reflect.Pointer {
		return errors.New("non-pointer passed to Unmarshal")
	}

	if .IsNil() {
		return errors.New("nil pointer passed to Unmarshal")
	}
	return .unmarshal(.Elem(), , 0)
}

// An UnmarshalError represents an error in the unmarshaling process.
type UnmarshalError string

func ( UnmarshalError) () string { return string() }

// Unmarshaler is the interface implemented by objects that can unmarshal
// an XML element description of themselves.
//
// UnmarshalXML decodes a single XML element
// beginning with the given start element.
// If it returns an error, the outer call to Unmarshal stops and
// returns that error.
// UnmarshalXML must consume exactly one XML element.
// One common implementation strategy is to unmarshal into
// a separate value with a layout matching the expected XML
// using d.DecodeElement, and then to copy the data from
// that value into the receiver.
// Another common strategy is to use d.Token to process the
// XML object one token at a time.
// UnmarshalXML may not use d.RawToken.
type Unmarshaler interface {
	UnmarshalXML(d *Decoder, start StartElement) error
}

// UnmarshalerAttr is the interface implemented by objects that can unmarshal
// an XML attribute description of themselves.
//
// UnmarshalXMLAttr decodes a single XML attribute.
// If it returns an error, the outer call to [Unmarshal] stops and
// returns that error.
// UnmarshalXMLAttr is used only for struct fields with the
// "attr" option in the field tag.
type UnmarshalerAttr interface {
	UnmarshalXMLAttr(attr Attr) error
}

// receiverType returns the receiver type to use in an expression like "%s.MethodName".
func receiverType( any) string {
	 := reflect.TypeOf()
	if .Name() != "" {
		return .String()
	}
	return "(" + .String() + ")"
}

// unmarshalInterface unmarshals a single XML element into val.
// start is the opening tag of the element.
func ( *Decoder) ( Unmarshaler,  *StartElement) error {
	// Record that decoder must stop at end tag corresponding to start.
	.pushEOF()

	.unmarshalDepth++
	 := .UnmarshalXML(, *)
	.unmarshalDepth--
	if  != nil {
		.popEOF()
		return 
	}

	if !.popEOF() {
		return fmt.Errorf("xml: %s.UnmarshalXML did not consume entire <%s> element", receiverType(), .Name.Local)
	}

	return nil
}

// unmarshalTextInterface unmarshals a single XML element into val.
// The chardata contained in the element (but not its children)
// is passed to the text unmarshaler.
func ( *Decoder) ( encoding.TextUnmarshaler) error {
	var  []byte
	 := 1
	for  > 0 {
		,  := .Token()
		if  != nil {
			return 
		}
		switch t := .(type) {
		case CharData:
			if  == 1 {
				 = append(, ...)
			}
		case StartElement:
			++
		case EndElement:
			--
		}
	}
	return .UnmarshalText()
}

// unmarshalAttr unmarshals a single XML attribute into val.
func ( *Decoder) ( reflect.Value,  Attr) error {
	if .Kind() == reflect.Pointer {
		if .IsNil() {
			.Set(reflect.New(.Type().Elem()))
		}
		 = .Elem()
	}
	if .CanInterface() && .Type().Implements(unmarshalerAttrType) {
		// This is an unmarshaler with a non-pointer receiver,
		// so it's likely to be incorrect, but we do what we're told.
		return .Interface().(UnmarshalerAttr).UnmarshalXMLAttr()
	}
	if .CanAddr() {
		 := .Addr()
		if .CanInterface() && .Type().Implements(unmarshalerAttrType) {
			return .Interface().(UnmarshalerAttr).UnmarshalXMLAttr()
		}
	}

	// Not an UnmarshalerAttr; try encoding.TextUnmarshaler.
	if .CanInterface() && .Type().Implements(textUnmarshalerType) {
		// This is an unmarshaler with a non-pointer receiver,
		// so it's likely to be incorrect, but we do what we're told.
		return .Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(.Value))
	}
	if .CanAddr() {
		 := .Addr()
		if .CanInterface() && .Type().Implements(textUnmarshalerType) {
			return .Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(.Value))
		}
	}

	if .Type().Kind() == reflect.Slice && .Type().Elem().Kind() != reflect.Uint8 {
		// Slice of element values.
		// Grow slice.
		 := .Len()
		.Grow(1)
		.SetLen( + 1)

		// Recur to read element into slice.
		if  := .(.Index(), );  != nil {
			.SetLen()
			return 
		}
		return nil
	}

	if .Type() == attrType {
		.Set(reflect.ValueOf())
		return nil
	}

	return copyValue(, []byte(.Value))
}

var (
	attrType            = reflect.TypeFor[Attr]()
	unmarshalerType     = reflect.TypeFor[Unmarshaler]()
	unmarshalerAttrType = reflect.TypeFor[UnmarshalerAttr]()
	textUnmarshalerType = reflect.TypeFor[encoding.TextUnmarshaler]()
)

const (
	maxUnmarshalDepth     = 10000
	maxUnmarshalDepthWasm = 5000 // go.dev/issue/56498
)

var errUnmarshalDepth = errors.New("exceeded max depth")

// Unmarshal a single XML element into val.
func ( *Decoder) ( reflect.Value,  *StartElement,  int) error {
	if  >= maxUnmarshalDepth || runtime.GOARCH == "wasm" &&  >= maxUnmarshalDepthWasm {
		return errUnmarshalDepth
	}
	// Find start element if we need it.
	if  == nil {
		for {
			,  := .Token()
			if  != nil {
				return 
			}
			if ,  := .(StartElement);  {
				 = &
				break
			}
		}
	}

	// Load value from interface, but only if the result will be
	// usefully addressable.
	if .Kind() == reflect.Interface && !.IsNil() {
		 := .Elem()
		if .Kind() == reflect.Pointer && !.IsNil() {
			 = 
		}
	}

	if .Kind() == reflect.Pointer {
		if .IsNil() {
			.Set(reflect.New(.Type().Elem()))
		}
		 = .Elem()
	}

	if .CanInterface() && .Type().Implements(unmarshalerType) {
		// This is an unmarshaler with a non-pointer receiver,
		// so it's likely to be incorrect, but we do what we're told.
		return .unmarshalInterface(.Interface().(Unmarshaler), )
	}

	if .CanAddr() {
		 := .Addr()
		if .CanInterface() && .Type().Implements(unmarshalerType) {
			return .unmarshalInterface(.Interface().(Unmarshaler), )
		}
	}

	if .CanInterface() && .Type().Implements(textUnmarshalerType) {
		return .unmarshalTextInterface(.Interface().(encoding.TextUnmarshaler))
	}

	if .CanAddr() {
		 := .Addr()
		if .CanInterface() && .Type().Implements(textUnmarshalerType) {
			return .unmarshalTextInterface(.Interface().(encoding.TextUnmarshaler))
		}
	}

	var (
		         []byte
		     reflect.Value
		      []byte
		  reflect.Value
		      reflect.Value
		 int
		  []byte
		      reflect.Value
		           reflect.Value
		        *typeInfo
		          error
	)

	switch  := ; .Kind() {
	default:
		return errors.New("unknown type " + .Type().String())

	case reflect.Interface:
		// TODO: For now, simply ignore the field. In the near
		//       future we may choose to unmarshal the start
		//       element on it, if not nil.
		return .Skip()

	case reflect.Slice:
		 := .Type()
		if .Elem().Kind() == reflect.Uint8 {
			// []byte
			 = 
			break
		}

		// Slice of element values.
		// Grow slice.
		 := .Len()
		.Grow(1)
		.SetLen( + 1)

		// Recur to read element into slice.
		if  := .(.Index(), , +1);  != nil {
			.SetLen()
			return 
		}
		return nil

	case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.String:
		 = 

	case reflect.Struct:
		 := .Type()
		if  == nameType {
			.Set(reflect.ValueOf(.Name))
			break
		}

		 = 
		,  = getTypeInfo()
		if  != nil {
			return 
		}

		// Validate and assign element name.
		if .xmlname != nil {
			 := .xmlname
			if .name != "" && .name != .Name.Local {
				return UnmarshalError("expected element type <" + .name + "> but have <" + .Name.Local + ">")
			}
			if .xmlns != "" && .xmlns != .Name.Space {
				 := "expected element <" + .name + "> in name space " + .xmlns + " but have "
				if .Name.Space == "" {
					 += "no name space"
				} else {
					 += .Name.Space
				}
				return UnmarshalError()
			}
			 := .value(, initNilPointers)
			if ,  := .Interface().(Name);  {
				.Set(reflect.ValueOf(.Name))
			}
		}

		// Assign attributes.
		for ,  := range .Attr {
			 := false
			 := -1
			for  := range .fields {
				 := &.fields[]
				switch .flags & fMode {
				case fAttr:
					 := .value(, initNilPointers)
					if .Name.Local == .name && (.xmlns == "" || .xmlns == .Name.Space) {
						if  := .unmarshalAttr(, );  != nil {
							return 
						}
						 = true
					}

				case fAny | fAttr:
					if  == -1 {
						 = 
					}
				}
			}
			if ! &&  >= 0 {
				 := &.fields[]
				 := .value(, initNilPointers)
				if  := .unmarshalAttr(, );  != nil {
					return 
				}
			}
		}

		// Determine whether we need to save character data or comments.
		for  := range .fields {
			 := &.fields[]
			switch .flags & fMode {
			case fCDATA, fCharData:
				if !.IsValid() {
					 = .value(, initNilPointers)
				}

			case fComment:
				if !.IsValid() {
					 = .value(, initNilPointers)
				}

			case fAny, fAny | fElement:
				if !.IsValid() {
					 = .value(, initNilPointers)
				}

			case fInnerXML:
				if !.IsValid() {
					 = .value(, initNilPointers)
					if .saved == nil {
						 = 0
						.saved = new(bytes.Buffer)
					} else {
						 = .savedOffset()
					}
				}
			}
		}
	}

	// Find end element.
	// Process sub-elements along the way.
:
	for {
		var  int
		if .IsValid() {
			 = .savedOffset()
		}
		,  := .Token()
		if  != nil {
			return 
		}
		switch t := .(type) {
		case StartElement:
			 := false
			if .IsValid() {
				// unmarshalPath can call unmarshal, so we need to pass the depth through so that
				// we can continue to enforce the maximum recursion limit.
				,  = .unmarshalPath(, , nil, &, )
				if  != nil {
					return 
				}
				if ! && .IsValid() {
					 = true
					if  := .(, &, +1);  != nil {
						return 
					}
				}
			}
			if ! {
				if  := .Skip();  != nil {
					return 
				}
			}

		case EndElement:
			if .IsValid() {
				 = .saved.Bytes()[:]
				if  == 0 {
					.saved = nil
				}
			}
			break 

		case CharData:
			if .IsValid() {
				 = append(, ...)
			}

		case Comment:
			if .IsValid() {
				 = append(, ...)
			}
		}
	}

	if .IsValid() && .CanInterface() && .Type().Implements(textUnmarshalerType) {
		if  := .Interface().(encoding.TextUnmarshaler).UnmarshalText();  != nil {
			return 
		}
		 = reflect.Value{}
	}

	if .IsValid() && .CanAddr() {
		 := .Addr()
		if .CanInterface() && .Type().Implements(textUnmarshalerType) {
			if  := .Interface().(encoding.TextUnmarshaler).UnmarshalText();  != nil {
				return 
			}
			 = reflect.Value{}
		}
	}

	if  := copyValue(, );  != nil {
		return 
	}

	switch  := ; .Kind() {
	case reflect.String:
		.SetString(string())
	case reflect.Slice:
		.Set(reflect.ValueOf())
	}

	switch  := ; .Kind() {
	case reflect.String:
		.SetString(string())
	case reflect.Slice:
		if .Type().Elem().Kind() == reflect.Uint8 {
			.Set(reflect.ValueOf())
		}
	}

	return nil
}

func copyValue( reflect.Value,  []byte) ( error) {
	 := 

	if .Kind() == reflect.Pointer {
		if .IsNil() {
			.Set(reflect.New(.Type().Elem()))
		}
		 = .Elem()
	}

	// Save accumulated data.
	switch .Kind() {
	case reflect.Invalid:
		// Probably a comment.
	default:
		return errors.New("cannot unmarshal into " + .Type().String())
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		if len() == 0 {
			.SetInt(0)
			return nil
		}
		,  := strconv.ParseInt(strings.TrimSpace(string()), 10, .Type().Bits())
		if  != nil {
			return 
		}
		.SetInt()
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
		if len() == 0 {
			.SetUint(0)
			return nil
		}
		,  := strconv.ParseUint(strings.TrimSpace(string()), 10, .Type().Bits())
		if  != nil {
			return 
		}
		.SetUint()
	case reflect.Float32, reflect.Float64:
		if len() == 0 {
			.SetFloat(0)
			return nil
		}
		,  := strconv.ParseFloat(strings.TrimSpace(string()), .Type().Bits())
		if  != nil {
			return 
		}
		.SetFloat()
	case reflect.Bool:
		if len() == 0 {
			.SetBool(false)
			return nil
		}
		,  := strconv.ParseBool(strings.TrimSpace(string()))
		if  != nil {
			return 
		}
		.SetBool()
	case reflect.String:
		.SetString(string())
	case reflect.Slice:
		if len() == 0 {
			// non-nil to flag presence
			 = []byte{}
		}
		.SetBytes()
	}
	return nil
}

// unmarshalPath walks down an XML structure looking for wanted
// paths, and calls unmarshal on them.
// The consumed result tells whether XML elements have been consumed
// from the Decoder until start's matching end element, or if it's
// still untouched because start is uninteresting for sv's fields.
func ( *Decoder) ( *typeInfo,  reflect.Value,  []string,  *StartElement,  int) ( bool,  error) {
	 := false
:
	for  := range .fields {
		 := &.fields[]
		if .flags&fElement == 0 || len(.parents) < len() || .xmlns != "" && .xmlns != .Name.Space {
			continue
		}
		for  := range  {
			if [] != .parents[] {
				continue 
			}
		}
		if len(.parents) == len() && .name == .Name.Local {
			// It's a perfect match, unmarshal the field.
			return true, .unmarshal(.value(, initNilPointers), , +1)
		}
		if len(.parents) > len() && .parents[len()] == .Name.Local {
			// It's a prefix for the field. Break and recurse
			// since it's not ok for one field path to be itself
			// the prefix for another field path.
			 = true

			// We can reuse the same slice as long as we
			// don't try to append to it.
			 = .parents[:len()+1]
			break
		}
	}
	if ! {
		// We have no business with this element.
		return false, nil
	}
	// The element is not a perfect match for any field, but one
	// or more fields have the path to this element as a parent
	// prefix. Recurse and attempt to match these.
	for {
		var  Token
		,  = .Token()
		if  != nil {
			return true, 
		}
		switch t := .(type) {
		case StartElement:
			// the recursion depth of unmarshalPath is limited to the path length specified
			// by the struct field tag, so we don't increment the depth here.
			,  := .(, , , &, )
			if  != nil {
				return true, 
			}
			if ! {
				if  := .Skip();  != nil {
					return true, 
				}
			}
		case EndElement:
			return true, nil
		}
	}
}

// Skip reads tokens until it has consumed the end element
// matching the most recent start element already consumed,
// skipping nested structures.
// It returns nil if it finds an end element matching the start
// element; otherwise it returns an error describing the problem.
func ( *Decoder) () error {
	var  int64
	for {
		,  := .Token()
		if  != nil {
			return 
		}
		switch .(type) {
		case StartElement:
			++
		case EndElement:
			if  == 0 {
				return nil
			}
			--
		}
	}
}