123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- package ini
- import (
- "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 error
- type INIDecoderError struct {
- msg string
- err error
- f *field
- }
- // Error returns an formatted string of the INIDecoderError
- func (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 error
- type INIEncoderError struct {
- msg string
- err error
- f *field
- }
- // Error returns an formatted string of the INIEncoderError
- func (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 methods
- type decodeFn func([]byte) error
- type 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 t
- func (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 field
- func (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 function
- func (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")
- }
|