Blame vendor/github.com/kolo/xmlrpc/encoder.go

Packit 63bb0d
package xmlrpc
Packit 63bb0d
Packit 63bb0d
import (
Packit 63bb0d
	"bytes"
Packit 63bb0d
	"encoding/xml"
Packit 63bb0d
	"fmt"
Packit 63bb0d
	"reflect"
Packit 63bb0d
	"sort"
Packit 63bb0d
	"strconv"
Packit 63bb0d
	"time"
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
// Base64 represents value in base64 encoding
Packit 63bb0d
type Base64 string
Packit 63bb0d
Packit 63bb0d
type encodeFunc func(reflect.Value) ([]byte, error)
Packit 63bb0d
Packit 63bb0d
func marshal(v interface{}) ([]byte, error) {
Packit 63bb0d
	if v == nil {
Packit 63bb0d
		return []byte{}, nil
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	val := reflect.ValueOf(v)
Packit 63bb0d
	return encodeValue(val)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func encodeValue(val reflect.Value) ([]byte, error) {
Packit 63bb0d
	var b []byte
Packit 63bb0d
	var err error
Packit 63bb0d
Packit 63bb0d
	if val.Kind() == reflect.Ptr || val.Kind() == reflect.Interface {
Packit 63bb0d
		if val.IsNil() {
Packit 63bb0d
			return []byte("<value/>"), nil
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		val = val.Elem()
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	switch val.Kind() {
Packit 63bb0d
	case reflect.Struct:
Packit 63bb0d
		switch val.Interface().(type) {
Packit 63bb0d
		case time.Time:
Packit 63bb0d
			t := val.Interface().(time.Time)
Packit 63bb0d
			b = []byte(fmt.Sprintf("<dateTime.iso8601>%s</dateTime.iso8601>", t.Format(iso8601)))
Packit 63bb0d
		default:
Packit 63bb0d
			b, err = encodeStruct(val)
Packit 63bb0d
		}
Packit 63bb0d
	case reflect.Map:
Packit 63bb0d
		b, err = encodeMap(val)
Packit 63bb0d
	case reflect.Slice:
Packit 63bb0d
		b, err = encodeSlice(val)
Packit 63bb0d
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
Packit 63bb0d
		b = []byte(fmt.Sprintf("<int>%s</int>", strconv.FormatInt(val.Int(), 10)))
Packit 63bb0d
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
Packit 63bb0d
		b = []byte(fmt.Sprintf("<i4>%s</i4>", strconv.FormatUint(val.Uint(), 10)))
Packit 63bb0d
	case reflect.Float32, reflect.Float64:
Packit 63bb0d
		b = []byte(fmt.Sprintf("<double>%s</double>",
Packit 63bb0d
			strconv.FormatFloat(val.Float(), 'f', -1, val.Type().Bits())))
Packit 63bb0d
	case reflect.Bool:
Packit 63bb0d
		if val.Bool() {
Packit 63bb0d
			b = []byte("<boolean>1</boolean>")
Packit 63bb0d
		} else {
Packit 63bb0d
			b = []byte("<boolean>0</boolean>")
Packit 63bb0d
		}
Packit 63bb0d
	case reflect.String:
Packit 63bb0d
		var buf bytes.Buffer
Packit 63bb0d
Packit 63bb0d
		xml.Escape(&buf, []byte(val.String()))
Packit 63bb0d
Packit 63bb0d
		if _, ok := val.Interface().(Base64); ok {
Packit 63bb0d
			b = []byte(fmt.Sprintf("<base64>%s</base64>", buf.String()))
Packit 63bb0d
		} else {
Packit 63bb0d
			b = []byte(fmt.Sprintf("<string>%s</string>", buf.String()))
Packit 63bb0d
		}
Packit 63bb0d
	default:
Packit 63bb0d
		return nil, fmt.Errorf("xmlrpc encode error: unsupported type")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return nil, err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return []byte(fmt.Sprintf("<value>%s</value>", string(b))), nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func encodeStruct(val reflect.Value) ([]byte, error) {
Packit 63bb0d
	var b bytes.Buffer
Packit 63bb0d
Packit 63bb0d
	b.WriteString("<struct>")
Packit 63bb0d
Packit 63bb0d
	t := val.Type()
Packit 63bb0d
	for i := 0; i < t.NumField(); i++ {
Packit 63bb0d
		b.WriteString("<member>")
Packit 63bb0d
		f := t.Field(i)
Packit 63bb0d
Packit 63bb0d
		name := f.Tag.Get("xmlrpc")
Packit 63bb0d
		if name == "" {
Packit 63bb0d
			name = f.Name
Packit 63bb0d
		}
Packit 63bb0d
		b.WriteString(fmt.Sprintf("<name>%s</name>", name))
Packit 63bb0d
Packit 63bb0d
		p, err := encodeValue(val.FieldByName(f.Name))
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			return nil, err
Packit 63bb0d
		}
Packit 63bb0d
		b.Write(p)
Packit 63bb0d
Packit 63bb0d
		b.WriteString("</member>")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	b.WriteString("</struct>")
Packit 63bb0d
Packit 63bb0d
	return b.Bytes(), nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
var sortMapKeys bool
Packit 63bb0d
Packit 63bb0d
func encodeMap(val reflect.Value) ([]byte, error) {
Packit 63bb0d
	var t = val.Type()
Packit 63bb0d
Packit 63bb0d
	if t.Key().Kind() != reflect.String {
Packit 63bb0d
		return nil, fmt.Errorf("xmlrpc encode error: only maps with string keys are supported")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	var b bytes.Buffer
Packit 63bb0d
Packit 63bb0d
	b.WriteString("<struct>")
Packit 63bb0d
Packit 63bb0d
	keys := val.MapKeys()
Packit 63bb0d
Packit 63bb0d
	if sortMapKeys {
Packit 63bb0d
		sort.Slice(keys, func(i, j int) bool { return keys[i].String() < keys[j].String() })
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	for i := 0; i < val.Len(); i++ {
Packit 63bb0d
		key := keys[i]
Packit 63bb0d
		kval := val.MapIndex(key)
Packit 63bb0d
Packit 63bb0d
		b.WriteString("<member>")
Packit 63bb0d
		b.WriteString(fmt.Sprintf("<name>%s</name>", key.String()))
Packit 63bb0d
Packit 63bb0d
		p, err := encodeValue(kval)
Packit 63bb0d
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			return nil, err
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		b.Write(p)
Packit 63bb0d
		b.WriteString("</member>")
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	b.WriteString("</struct>")
Packit 63bb0d
Packit 63bb0d
	return b.Bytes(), nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
func encodeSlice(val reflect.Value) ([]byte, error) {
Packit 63bb0d
	var b bytes.Buffer
Packit 63bb0d
Packit 63bb0d
	b.WriteString("<array><data>")
Packit 63bb0d
Packit 63bb0d
	for i := 0; i < val.Len(); i++ {
Packit 63bb0d
		p, err := encodeValue(val.Index(i))
Packit 63bb0d
		if err != nil {
Packit 63bb0d
			return nil, err
Packit 63bb0d
		}
Packit 63bb0d
Packit 63bb0d
		b.Write(p)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	b.WriteString("</data></array>")
Packit 63bb0d
Packit 63bb0d
	return b.Bytes(), nil
Packit 63bb0d
}