| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 | package iniimport (	"encoding"	"fmt"	"reflect"	"strconv"	"strings")// Types to look for ("Marshaler"/"Unmarshaler" interface)var (	marshalerType       = reflect.TypeOf(new(Marshaler)).Elem()	unmarshalerType     = reflect.TypeOf(new(Unmarshaler)).Elem()	textMarshalerType   = reflect.TypeOf(new(encoding.TextMarshaler)).Elem()	textUnmarshalerType = reflect.TypeOf(new(encoding.TextUnmarshaler)).Elem())// INIDecoderError is returned on decoding errortype INIDecoderError struct {	msg string	err error	f   *field}// Error returns an formatted string of the INIDecoderErrorfunc (i *INIDecoderError) Error() string {	return fmt.Sprintf(		"INI Decoder Error: %s. %s. Field %s, namespace: %s",		i.msg, i.err.Error(), i.f.t.Name(), i.f.ns,	)}// INIEncoderError is returned on encoding errortype INIEncoderError struct {	msg string	err error	f   *field}// Error returns an formatted string of the INIEncoderErrorfunc (i *INIEncoderError) Error() string {	return fmt.Sprintf(		"INI Encoder Error: %s. Field: %s, namespace: %s",		i.msg, i.err.Error(), i.f.t.Name(), i.f.ns,	)}// decoder and encoder methodstype decodeFn func([]byte) errortype encodeFn func() ([]byte, error)type field struct {	ns string	t reflect.Type	v reflect.Value	p interface{}	// decoder or encoder method (will be changed when a cache for "elements" is implemented)	fn interface{} // Use setFn to set this!}func newField(v reflect.Value, p interface{}, i int) *field {	f := &field{		t: v.Type(),		v: v,		p: nil,	}	if p != nil {		switch p.(type) {		case reflect.Type:			f.p = p.(reflect.Type).Field(i)		case reflect.Value:			f.p = p.(reflect.Value).Type().Field(i)		}	}	return f}// implements checks if the field implements the type t, or a pointer method to type tfunc (f *field) implements(t reflect.Type) bool {	return (f.t.Implements(t) || (f.t.Kind() != reflect.Ptr && reflect.PtrTo(f.t).Implements(t)))}// setNS determines the namespace for the fieldfunc (f *field) setNS(ns string) string {	if f.p == nil {		f.ns = ns + "." + f.t.Name()		return f.ns	}	if tag := f.p.(reflect.StructField).Tag.Get("ini"); len(tag) != 0 {		f.ns = ns + "." + tag		return f.ns	}	f.ns = ns + "." + f.p.(reflect.StructField).Name	return f.ns}// setFN sets the functionfunc (f *field) setFn(fn interface{}) {	f.fn = fn}// decode returns the decoder-method (do not call f.fn, for future changes!)func (f *field) decode(b []byte) error {	return f.fn.(decodeFn)(b)}// encode returns the decoder-method (do not call f.fn directly, for future changes!)func (f *field) encode() ([]byte, error) {	return f.fn.(encodeFn)()}/** DECODER METHODS**/func (f *field) valid() error {	if f.v.CanAddr() {		return nil	}	return fmt.Errorf("Field '%s' not addressable", f.ns)}func (f *field) uintDecoder(b []byte) error {	if err := f.valid(); err != nil {		return &INIDecoderError{			msg: "Unsigned integer decoder",			err: err,			f:   f,		}	}	i, err := strconv.ParseUint(string(b), 10, 64)	if err != nil {		return &INIDecoderError{			msg: "Unsigned integer decoder",			err: err,			f:   f,		}	}	f.v.SetUint(i)	return nil}func (f *field) intDecoder(b []byte) error {	if err := f.valid(); err != nil {		return &INIDecoderError{			msg: "Integer decoder",			err: err,			f:   f,		}	}	i, err := strconv.ParseInt(string(b), 10, 64)	if err != nil {		return &INIDecoderError{			msg: "Integer decoder",			err: err,			f:   f,		}	}	f.v.SetInt(i)	return nil}func (f *field) float32Decoder(b []byte) error {	if err := f.valid(); err != nil {		return &INIDecoderError{			msg: "Float (32) decoder",			err: err,			f:   f,		}	}	i, err := strconv.ParseFloat(string(b), 32)	if err != nil {		return &INIDecoderError{			msg: "Float (32) decoder",			err: err,			f:   f,		}	}	f.v.SetFloat(i)	return nil}func (f *field) float64Decoder(b []byte) error {	if err := f.valid(); err != nil {		return &INIDecoderError{			msg: "Float (64) decoder",			err: err,			f:   f,		}	}	i, err := strconv.ParseFloat(string(b), 64)	if err != nil {		return &INIDecoderError{			msg: "Float (64) decoder",			err: err,			f:   f,		}	}	f.v.SetFloat(i)	return nil}func (f *field) strDecoder(b []byte) error {	if err := f.valid(); err != nil {		return &INIDecoderError{			msg: "String decoder",			err: err,			f:   f,		}	}	f.v.SetString(string(b))	return nil}func (f *field) boolDecoder(b []byte) error {	if err := f.valid(); err != nil {		return &INIDecoderError{			msg: "Boolean decoder",			err: err,			f:   f,		}	}	f.v.SetBool(true)	return nil}func (f *field) unmarshalerDecoder(b []byte) error {	if err := f.valid(); err != nil {		return &INIDecoderError{			msg: "Unmarshaler decoder",			err: err,			f:   f,		}	}	v := f.v	if v.Kind() != reflect.Ptr && v.Type().Name() != "" {		v = v.Addr()	}	if v.IsNil() {		v.Set(reflect.New(v.Type().Elem()))	}	if i, ok := v.Interface().(Unmarshaler); ok {		if err := i.UnmarshalINI(b); err != nil {			return &INIDecoderError{				msg: "UnmarshalINI decoder",				err: err,				f:   f,			}		}		return nil	}	if i, ok := v.Interface().(encoding.TextUnmarshaler); ok {		if err := i.UnmarshalText(b); err != nil {			return &INIDecoderError{				msg: "UnmarshalText decoder",				err: err,				f:   f,			}		}		return nil	}	return fmt.Errorf("Cannot load Unmarshaler")}/** ENCODER METHODS**/func (f *field) nskey() string {	return f.ns[strings.LastIndexByte(f.ns, '.')+1:]}func (f *field) uintEncoder() ([]byte, error) {	i := strconv.FormatUint(f.v.Uint(), 10)	return []byte(f.nskey() + " = " + i), nil}func (f *field) intEncoder() ([]byte, error) {	i := strconv.FormatInt(f.v.Int(), 10)	return []byte(f.nskey() + " = " + i), nil}func (f *field) float32Encoder() ([]byte, error) {	i := strconv.FormatFloat(f.v.Float(), 'G', -1, 32)	return []byte(f.nskey() + " = " + i), nil}func (f *field) float64Encoder() ([]byte, error) {	i := strconv.FormatFloat(f.v.Float(), 'G', -1, 64)	return []byte(f.nskey() + " = " + i), nil}func (f *field) strEncoder() ([]byte, error) {	str := strings.Replace(f.v.String(), "\n", "\\\n", -1)	return []byte(f.nskey() + " = " + str), nil}func (f *field) boolEncoder() ([]byte, error) {	if f.v.Bool() {		return []byte(f.nskey()), nil	}	return nil, nil}func (f *field) structEncoder() ([]byte, error) {	split := strings.SplitN(f.ns, ".", 3)	if len(split) == 2 {		return nil, nil	}	if len(split) != 3 {		return nil, &INIEncoderError{			msg: "Struct encoder",			err: fmt.Errorf("Invalid namespace"),			f:   f,		}	}	return []byte("\n[" + split[2] + "]"), nil}func (f *field) marshalerDecoder() ([]byte, error) {	if err := f.valid(); err != nil {		return nil, &INIEncoderError{			msg: "Unmarshaler decoder",			err: err,			f:   f,		}	}	v := f.v	if v.Kind() != reflect.Ptr && v.Type().Name() != "" {		v = v.Addr()	}	if v.IsNil() {		v.Set(reflect.New(v.Type().Elem()))	}	if i, ok := v.Interface().(Marshaler); ok {		b, err := i.MarshalINI()		if err != nil {			return nil, err		}		if b == nil {			return nil, nil		}		return append([]byte(f.nskey()+" = "), b...), nil	}	if i, ok := v.Interface().(encoding.TextMarshaler); ok {		b, err := i.MarshalText()		if err != nil {			return nil, err		}		if b == nil {			return nil, nil		}		return append([]byte(f.nskey()+" = "), b...), nil	}	return nil, fmt.Errorf("Cannot load Marshaler")}
 |