|
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 |
}
|