marshal.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. package plist
  2. import (
  3. "encoding"
  4. "reflect"
  5. "time"
  6. )
  7. func isEmptyValue(v reflect.Value) bool {
  8. switch v.Kind() {
  9. case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
  10. return v.Len() == 0
  11. case reflect.Bool:
  12. return !v.Bool()
  13. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  14. return v.Int() == 0
  15. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  16. return v.Uint() == 0
  17. case reflect.Float32, reflect.Float64:
  18. return v.Float() == 0
  19. case reflect.Interface, reflect.Ptr:
  20. return v.IsNil()
  21. }
  22. return false
  23. }
  24. var (
  25. plistMarshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem()
  26. textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem()
  27. timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
  28. )
  29. func implementsInterface(val reflect.Value, interfaceType reflect.Type) (interface{}, bool) {
  30. if val.CanInterface() && val.Type().Implements(interfaceType) {
  31. return val.Interface(), true
  32. }
  33. if val.CanAddr() {
  34. pv := val.Addr()
  35. if pv.CanInterface() && pv.Type().Implements(interfaceType) {
  36. return pv.Interface(), true
  37. }
  38. }
  39. return nil, false
  40. }
  41. func (p *Encoder) marshalPlistInterface(marshalable Marshaler) cfValue {
  42. value, err := marshalable.MarshalPlist()
  43. if err != nil {
  44. panic(err)
  45. }
  46. return p.marshal(reflect.ValueOf(value))
  47. }
  48. // marshalTextInterface marshals a TextMarshaler to a plist string.
  49. func (p *Encoder) marshalTextInterface(marshalable encoding.TextMarshaler) cfValue {
  50. s, err := marshalable.MarshalText()
  51. if err != nil {
  52. panic(err)
  53. }
  54. return cfString(s)
  55. }
  56. // marshalStruct marshals a reflected struct value to a plist dictionary
  57. func (p *Encoder) marshalStruct(typ reflect.Type, val reflect.Value) cfValue {
  58. tinfo, _ := getTypeInfo(typ)
  59. dict := &cfDictionary{
  60. keys: make([]string, 0, len(tinfo.fields)),
  61. values: make([]cfValue, 0, len(tinfo.fields)),
  62. }
  63. for _, finfo := range tinfo.fields {
  64. value := finfo.value(val)
  65. if !value.IsValid() || finfo.omitEmpty && isEmptyValue(value) {
  66. continue
  67. }
  68. dict.keys = append(dict.keys, finfo.name)
  69. dict.values = append(dict.values, p.marshal(value))
  70. }
  71. return dict
  72. }
  73. func (p *Encoder) marshalTime(val reflect.Value) cfValue {
  74. time := val.Interface().(time.Time)
  75. return cfDate(time)
  76. }
  77. func (p *Encoder) marshal(val reflect.Value) cfValue {
  78. if !val.IsValid() {
  79. return nil
  80. }
  81. if receiver, can := implementsInterface(val, plistMarshalerType); can {
  82. return p.marshalPlistInterface(receiver.(Marshaler))
  83. }
  84. // time.Time implements TextMarshaler, but we need to store it in RFC3339
  85. if val.Type() == timeType {
  86. return p.marshalTime(val)
  87. }
  88. if val.Kind() == reflect.Ptr || (val.Kind() == reflect.Interface && val.NumMethod() == 0) {
  89. ival := val.Elem()
  90. if ival.IsValid() && ival.Type() == timeType {
  91. return p.marshalTime(ival)
  92. }
  93. }
  94. // Check for text marshaler.
  95. if receiver, can := implementsInterface(val, textMarshalerType); can {
  96. return p.marshalTextInterface(receiver.(encoding.TextMarshaler))
  97. }
  98. // Descend into pointers or interfaces
  99. if val.Kind() == reflect.Ptr || (val.Kind() == reflect.Interface && val.NumMethod() == 0) {
  100. val = val.Elem()
  101. }
  102. // We got this far and still may have an invalid anything or nil ptr/interface
  103. if !val.IsValid() || ((val.Kind() == reflect.Ptr || val.Kind() == reflect.Interface) && val.IsNil()) {
  104. return nil
  105. }
  106. typ := val.Type()
  107. if typ == uidType {
  108. return cfUID(val.Uint())
  109. }
  110. if val.Kind() == reflect.Struct {
  111. return p.marshalStruct(typ, val)
  112. }
  113. switch val.Kind() {
  114. case reflect.String:
  115. return cfString(val.String())
  116. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  117. return &cfNumber{signed: true, value: uint64(val.Int())}
  118. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  119. return &cfNumber{signed: false, value: val.Uint()}
  120. case reflect.Float32:
  121. return &cfReal{wide: false, value: val.Float()}
  122. case reflect.Float64:
  123. return &cfReal{wide: true, value: val.Float()}
  124. case reflect.Bool:
  125. return cfBoolean(val.Bool())
  126. case reflect.Slice, reflect.Array:
  127. if typ.Elem().Kind() == reflect.Uint8 {
  128. bytes := []byte(nil)
  129. if val.CanAddr() {
  130. bytes = val.Bytes()
  131. } else {
  132. bytes = make([]byte, val.Len())
  133. reflect.Copy(reflect.ValueOf(bytes), val)
  134. }
  135. return cfData(bytes)
  136. }
  137. values := make([]cfValue, val.Len())
  138. for i, length := 0, val.Len(); i < length; i++ {
  139. if subpval := p.marshal(val.Index(i)); subpval != nil {
  140. values[i] = subpval
  141. }
  142. }
  143. return &cfArray{values}
  144. case reflect.Map:
  145. if typ.Key().Kind() != reflect.String {
  146. panic(&unknownTypeError{typ})
  147. }
  148. l := val.Len()
  149. dict := &cfDictionary{
  150. keys: make([]string, 0, l),
  151. values: make([]cfValue, 0, l),
  152. }
  153. for _, keyv := range val.MapKeys() {
  154. if subpval := p.marshal(val.MapIndex(keyv)); subpval != nil {
  155. dict.keys = append(dict.keys, keyv.String())
  156. dict.values = append(dict.values, subpval)
  157. }
  158. }
  159. return dict
  160. default:
  161. panic(&unknownTypeError{typ})
  162. }
  163. }