mirror of
https://github.com/FiloSottile/mkcert.git
synced 2025-10-14 00:41:40 +08:00
Import howett.net/plist by its correct name
Also bumping the version to one with a go.mod.
This commit is contained in:
317
vendor/howett.net/plist/unmarshal.go
generated
vendored
Normal file
317
vendor/howett.net/plist/unmarshal.go
generated
vendored
Normal file
@@ -0,0 +1,317 @@
|
||||
package plist
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"time"
|
||||
)
|
||||
|
||||
type incompatibleDecodeTypeError struct {
|
||||
dest reflect.Type
|
||||
src string // type name (from cfValue)
|
||||
}
|
||||
|
||||
func (u *incompatibleDecodeTypeError) Error() string {
|
||||
return fmt.Sprintf("plist: type mismatch: tried to decode plist type `%v' into value of type `%v'", u.src, u.dest)
|
||||
}
|
||||
|
||||
var (
|
||||
plistUnmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
|
||||
textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
|
||||
uidType = reflect.TypeOf(UID(0))
|
||||
)
|
||||
|
||||
func isEmptyInterface(v reflect.Value) bool {
|
||||
return v.Kind() == reflect.Interface && v.NumMethod() == 0
|
||||
}
|
||||
|
||||
func (p *Decoder) unmarshalPlistInterface(pval cfValue, unmarshalable Unmarshaler) {
|
||||
err := unmarshalable.UnmarshalPlist(func(i interface{}) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
if _, ok := r.(runtime.Error); ok {
|
||||
panic(r)
|
||||
}
|
||||
err = r.(error)
|
||||
}
|
||||
}()
|
||||
p.unmarshal(pval, reflect.ValueOf(i))
|
||||
return
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Decoder) unmarshalTextInterface(pval cfString, unmarshalable encoding.TextUnmarshaler) {
|
||||
err := unmarshalable.UnmarshalText([]byte(pval))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Decoder) unmarshalTime(pval cfDate, val reflect.Value) {
|
||||
val.Set(reflect.ValueOf(time.Time(pval)))
|
||||
}
|
||||
|
||||
func (p *Decoder) unmarshalLaxString(s string, val reflect.Value) {
|
||||
switch val.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
i := mustParseInt(s, 10, 64)
|
||||
val.SetInt(i)
|
||||
return
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
i := mustParseUint(s, 10, 64)
|
||||
val.SetUint(i)
|
||||
return
|
||||
case reflect.Float32, reflect.Float64:
|
||||
f := mustParseFloat(s, 64)
|
||||
val.SetFloat(f)
|
||||
return
|
||||
case reflect.Bool:
|
||||
b := mustParseBool(s)
|
||||
val.SetBool(b)
|
||||
return
|
||||
case reflect.Struct:
|
||||
if val.Type() == timeType {
|
||||
t, err := time.Parse(textPlistTimeLayout, s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
val.Set(reflect.ValueOf(t.In(time.UTC)))
|
||||
return
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
panic(&incompatibleDecodeTypeError{val.Type(), "string"})
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Decoder) unmarshal(pval cfValue, val reflect.Value) {
|
||||
if pval == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if val.Kind() == reflect.Ptr {
|
||||
if val.IsNil() {
|
||||
val.Set(reflect.New(val.Type().Elem()))
|
||||
}
|
||||
val = val.Elem()
|
||||
}
|
||||
|
||||
if isEmptyInterface(val) {
|
||||
v := p.valueInterface(pval)
|
||||
val.Set(reflect.ValueOf(v))
|
||||
return
|
||||
}
|
||||
|
||||
incompatibleTypeError := &incompatibleDecodeTypeError{val.Type(), pval.typeName()}
|
||||
|
||||
// time.Time implements TextMarshaler, but we need to parse it as RFC3339
|
||||
if date, ok := pval.(cfDate); ok {
|
||||
if val.Type() == timeType {
|
||||
p.unmarshalTime(date, val)
|
||||
return
|
||||
}
|
||||
panic(incompatibleTypeError)
|
||||
}
|
||||
|
||||
if receiver, can := implementsInterface(val, plistUnmarshalerType); can {
|
||||
p.unmarshalPlistInterface(pval, receiver.(Unmarshaler))
|
||||
return
|
||||
}
|
||||
|
||||
if val.Type() != timeType {
|
||||
if receiver, can := implementsInterface(val, textUnmarshalerType); can {
|
||||
if str, ok := pval.(cfString); ok {
|
||||
p.unmarshalTextInterface(str, receiver.(encoding.TextUnmarshaler))
|
||||
} else {
|
||||
panic(incompatibleTypeError)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
typ := val.Type()
|
||||
|
||||
switch pval := pval.(type) {
|
||||
case cfString:
|
||||
if val.Kind() == reflect.String {
|
||||
val.SetString(string(pval))
|
||||
return
|
||||
}
|
||||
if p.lax {
|
||||
p.unmarshalLaxString(string(pval), val)
|
||||
return
|
||||
}
|
||||
|
||||
panic(incompatibleTypeError)
|
||||
case *cfNumber:
|
||||
switch val.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
val.SetInt(int64(pval.value))
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
val.SetUint(pval.value)
|
||||
default:
|
||||
panic(incompatibleTypeError)
|
||||
}
|
||||
case *cfReal:
|
||||
if val.Kind() == reflect.Float32 || val.Kind() == reflect.Float64 {
|
||||
// TODO: Consider warning on a downcast (storing a 64-bit value in a 32-bit reflect)
|
||||
val.SetFloat(pval.value)
|
||||
} else {
|
||||
panic(incompatibleTypeError)
|
||||
}
|
||||
case cfBoolean:
|
||||
if val.Kind() == reflect.Bool {
|
||||
val.SetBool(bool(pval))
|
||||
} else {
|
||||
panic(incompatibleTypeError)
|
||||
}
|
||||
case cfData:
|
||||
if val.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 {
|
||||
val.SetBytes([]byte(pval))
|
||||
} else {
|
||||
panic(incompatibleTypeError)
|
||||
}
|
||||
case cfUID:
|
||||
if val.Type() == uidType {
|
||||
val.SetUint(uint64(pval))
|
||||
} else {
|
||||
switch val.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
val.SetInt(int64(pval))
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
val.SetUint(uint64(pval))
|
||||
default:
|
||||
panic(incompatibleTypeError)
|
||||
}
|
||||
}
|
||||
case *cfArray:
|
||||
p.unmarshalArray(pval, val)
|
||||
case *cfDictionary:
|
||||
p.unmarshalDictionary(pval, val)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Decoder) unmarshalArray(a *cfArray, val reflect.Value) {
|
||||
var n int
|
||||
if val.Kind() == reflect.Slice {
|
||||
// Slice of element values.
|
||||
// Grow slice.
|
||||
cnt := len(a.values) + val.Len()
|
||||
if cnt >= val.Cap() {
|
||||
ncap := 2 * cnt
|
||||
if ncap < 4 {
|
||||
ncap = 4
|
||||
}
|
||||
new := reflect.MakeSlice(val.Type(), val.Len(), ncap)
|
||||
reflect.Copy(new, val)
|
||||
val.Set(new)
|
||||
}
|
||||
n = val.Len()
|
||||
val.SetLen(cnt)
|
||||
} else if val.Kind() == reflect.Array {
|
||||
if len(a.values) > val.Cap() {
|
||||
panic(fmt.Errorf("plist: attempted to unmarshal %d values into an array of size %d", len(a.values), val.Cap()))
|
||||
}
|
||||
} else {
|
||||
panic(&incompatibleDecodeTypeError{val.Type(), a.typeName()})
|
||||
}
|
||||
|
||||
// Recur to read element into slice.
|
||||
for _, sval := range a.values {
|
||||
p.unmarshal(sval, val.Index(n))
|
||||
n++
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Decoder) unmarshalDictionary(dict *cfDictionary, val reflect.Value) {
|
||||
typ := val.Type()
|
||||
switch val.Kind() {
|
||||
case reflect.Struct:
|
||||
tinfo, err := getTypeInfo(typ)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
entries := make(map[string]cfValue, len(dict.keys))
|
||||
for i, k := range dict.keys {
|
||||
sval := dict.values[i]
|
||||
entries[k] = sval
|
||||
}
|
||||
|
||||
for _, finfo := range tinfo.fields {
|
||||
p.unmarshal(entries[finfo.name], finfo.value(val))
|
||||
}
|
||||
case reflect.Map:
|
||||
if val.IsNil() {
|
||||
val.Set(reflect.MakeMap(typ))
|
||||
}
|
||||
|
||||
for i, k := range dict.keys {
|
||||
sval := dict.values[i]
|
||||
|
||||
keyv := reflect.ValueOf(k).Convert(typ.Key())
|
||||
mapElem := reflect.New(typ.Elem()).Elem()
|
||||
|
||||
p.unmarshal(sval, mapElem)
|
||||
val.SetMapIndex(keyv, mapElem)
|
||||
}
|
||||
default:
|
||||
panic(&incompatibleDecodeTypeError{typ, dict.typeName()})
|
||||
}
|
||||
}
|
||||
|
||||
/* *Interface is modelled after encoding/json */
|
||||
func (p *Decoder) valueInterface(pval cfValue) interface{} {
|
||||
switch pval := pval.(type) {
|
||||
case cfString:
|
||||
return string(pval)
|
||||
case *cfNumber:
|
||||
if pval.signed {
|
||||
return int64(pval.value)
|
||||
}
|
||||
return pval.value
|
||||
case *cfReal:
|
||||
if pval.wide {
|
||||
return pval.value
|
||||
} else {
|
||||
return float32(pval.value)
|
||||
}
|
||||
case cfBoolean:
|
||||
return bool(pval)
|
||||
case *cfArray:
|
||||
return p.arrayInterface(pval)
|
||||
case *cfDictionary:
|
||||
return p.dictionaryInterface(pval)
|
||||
case cfData:
|
||||
return []byte(pval)
|
||||
case cfDate:
|
||||
return time.Time(pval)
|
||||
case cfUID:
|
||||
return UID(pval)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Decoder) arrayInterface(a *cfArray) []interface{} {
|
||||
out := make([]interface{}, len(a.values))
|
||||
for i, subv := range a.values {
|
||||
out[i] = p.valueInterface(subv)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (p *Decoder) dictionaryInterface(dict *cfDictionary) map[string]interface{} {
|
||||
out := make(map[string]interface{})
|
||||
for i, k := range dict.keys {
|
||||
subv := dict.values[i]
|
||||
out[k] = p.valueInterface(subv)
|
||||
}
|
||||
return out
|
||||
}
|
Reference in New Issue
Block a user