unmarshal.go 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. package plist
  2. import (
  3. "encoding"
  4. "fmt"
  5. "reflect"
  6. "runtime"
  7. "time"
  8. )
  9. type incompatibleDecodeTypeError struct {
  10. dest reflect.Type
  11. src string // type name (from cfValue)
  12. }
  13. func (u *incompatibleDecodeTypeError) Error() string {
  14. return fmt.Sprintf("plist: type mismatch: tried to decode plist type `%v' into value of type `%v'", u.src, u.dest)
  15. }
  16. var (
  17. plistUnmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem()
  18. textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()
  19. uidType = reflect.TypeOf(UID(0))
  20. )
  21. func isEmptyInterface(v reflect.Value) bool {
  22. return v.Kind() == reflect.Interface && v.NumMethod() == 0
  23. }
  24. func (p *Decoder) unmarshalPlistInterface(pval cfValue, unmarshalable Unmarshaler) {
  25. err := unmarshalable.UnmarshalPlist(func(i interface{}) (err error) {
  26. defer func() {
  27. if r := recover(); r != nil {
  28. if _, ok := r.(runtime.Error); ok {
  29. panic(r)
  30. }
  31. err = r.(error)
  32. }
  33. }()
  34. p.unmarshal(pval, reflect.ValueOf(i))
  35. return
  36. })
  37. if err != nil {
  38. panic(err)
  39. }
  40. }
  41. func (p *Decoder) unmarshalTextInterface(pval cfString, unmarshalable encoding.TextUnmarshaler) {
  42. err := unmarshalable.UnmarshalText([]byte(pval))
  43. if err != nil {
  44. panic(err)
  45. }
  46. }
  47. func (p *Decoder) unmarshalTime(pval cfDate, val reflect.Value) {
  48. val.Set(reflect.ValueOf(time.Time(pval)))
  49. }
  50. func (p *Decoder) unmarshalLaxString(s string, val reflect.Value) {
  51. switch val.Kind() {
  52. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  53. i := mustParseInt(s, 10, 64)
  54. val.SetInt(i)
  55. return
  56. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  57. i := mustParseUint(s, 10, 64)
  58. val.SetUint(i)
  59. return
  60. case reflect.Float32, reflect.Float64:
  61. f := mustParseFloat(s, 64)
  62. val.SetFloat(f)
  63. return
  64. case reflect.Bool:
  65. b := mustParseBool(s)
  66. val.SetBool(b)
  67. return
  68. case reflect.Struct:
  69. if val.Type() == timeType {
  70. t, err := time.Parse(textPlistTimeLayout, s)
  71. if err != nil {
  72. panic(err)
  73. }
  74. val.Set(reflect.ValueOf(t.In(time.UTC)))
  75. return
  76. }
  77. fallthrough
  78. default:
  79. panic(&incompatibleDecodeTypeError{val.Type(), "string"})
  80. }
  81. }
  82. func (p *Decoder) unmarshal(pval cfValue, val reflect.Value) {
  83. if pval == nil {
  84. return
  85. }
  86. if val.Kind() == reflect.Ptr {
  87. if val.IsNil() {
  88. val.Set(reflect.New(val.Type().Elem()))
  89. }
  90. val = val.Elem()
  91. }
  92. if isEmptyInterface(val) {
  93. v := p.valueInterface(pval)
  94. val.Set(reflect.ValueOf(v))
  95. return
  96. }
  97. incompatibleTypeError := &incompatibleDecodeTypeError{val.Type(), pval.typeName()}
  98. // time.Time implements TextMarshaler, but we need to parse it as RFC3339
  99. if date, ok := pval.(cfDate); ok {
  100. if val.Type() == timeType {
  101. p.unmarshalTime(date, val)
  102. return
  103. }
  104. panic(incompatibleTypeError)
  105. }
  106. if receiver, can := implementsInterface(val, plistUnmarshalerType); can {
  107. p.unmarshalPlistInterface(pval, receiver.(Unmarshaler))
  108. return
  109. }
  110. if val.Type() != timeType {
  111. if receiver, can := implementsInterface(val, textUnmarshalerType); can {
  112. if str, ok := pval.(cfString); ok {
  113. p.unmarshalTextInterface(str, receiver.(encoding.TextUnmarshaler))
  114. } else {
  115. panic(incompatibleTypeError)
  116. }
  117. return
  118. }
  119. }
  120. typ := val.Type()
  121. switch pval := pval.(type) {
  122. case cfString:
  123. if val.Kind() == reflect.String {
  124. val.SetString(string(pval))
  125. return
  126. }
  127. if p.lax {
  128. p.unmarshalLaxString(string(pval), val)
  129. return
  130. }
  131. panic(incompatibleTypeError)
  132. case *cfNumber:
  133. switch val.Kind() {
  134. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  135. val.SetInt(int64(pval.value))
  136. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  137. val.SetUint(pval.value)
  138. default:
  139. panic(incompatibleTypeError)
  140. }
  141. case *cfReal:
  142. if val.Kind() == reflect.Float32 || val.Kind() == reflect.Float64 {
  143. // TODO: Consider warning on a downcast (storing a 64-bit value in a 32-bit reflect)
  144. val.SetFloat(pval.value)
  145. } else {
  146. panic(incompatibleTypeError)
  147. }
  148. case cfBoolean:
  149. if val.Kind() == reflect.Bool {
  150. val.SetBool(bool(pval))
  151. } else {
  152. panic(incompatibleTypeError)
  153. }
  154. case cfData:
  155. if val.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Uint8 {
  156. val.SetBytes([]byte(pval))
  157. } else {
  158. panic(incompatibleTypeError)
  159. }
  160. case cfUID:
  161. if val.Type() == uidType {
  162. val.SetUint(uint64(pval))
  163. } else {
  164. switch val.Kind() {
  165. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  166. val.SetInt(int64(pval))
  167. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  168. val.SetUint(uint64(pval))
  169. default:
  170. panic(incompatibleTypeError)
  171. }
  172. }
  173. case *cfArray:
  174. p.unmarshalArray(pval, val)
  175. case *cfDictionary:
  176. p.unmarshalDictionary(pval, val)
  177. }
  178. }
  179. func (p *Decoder) unmarshalArray(a *cfArray, val reflect.Value) {
  180. var n int
  181. if val.Kind() == reflect.Slice {
  182. // Slice of element values.
  183. // Grow slice.
  184. cnt := len(a.values) + val.Len()
  185. if cnt >= val.Cap() {
  186. ncap := 2 * cnt
  187. if ncap < 4 {
  188. ncap = 4
  189. }
  190. new := reflect.MakeSlice(val.Type(), val.Len(), ncap)
  191. reflect.Copy(new, val)
  192. val.Set(new)
  193. }
  194. n = val.Len()
  195. val.SetLen(cnt)
  196. } else if val.Kind() == reflect.Array {
  197. if len(a.values) > val.Cap() {
  198. panic(fmt.Errorf("plist: attempted to unmarshal %d values into an array of size %d", len(a.values), val.Cap()))
  199. }
  200. } else {
  201. panic(&incompatibleDecodeTypeError{val.Type(), a.typeName()})
  202. }
  203. // Recur to read element into slice.
  204. for _, sval := range a.values {
  205. p.unmarshal(sval, val.Index(n))
  206. n++
  207. }
  208. }
  209. func (p *Decoder) unmarshalDictionary(dict *cfDictionary, val reflect.Value) {
  210. typ := val.Type()
  211. switch val.Kind() {
  212. case reflect.Struct:
  213. tinfo, err := getTypeInfo(typ)
  214. if err != nil {
  215. panic(err)
  216. }
  217. entries := make(map[string]cfValue, len(dict.keys))
  218. for i, k := range dict.keys {
  219. sval := dict.values[i]
  220. entries[k] = sval
  221. }
  222. for _, finfo := range tinfo.fields {
  223. p.unmarshal(entries[finfo.name], finfo.value(val))
  224. }
  225. case reflect.Map:
  226. if val.IsNil() {
  227. val.Set(reflect.MakeMap(typ))
  228. }
  229. for i, k := range dict.keys {
  230. sval := dict.values[i]
  231. keyv := reflect.ValueOf(k).Convert(typ.Key())
  232. mapElem := reflect.New(typ.Elem()).Elem()
  233. p.unmarshal(sval, mapElem)
  234. val.SetMapIndex(keyv, mapElem)
  235. }
  236. default:
  237. panic(&incompatibleDecodeTypeError{typ, dict.typeName()})
  238. }
  239. }
  240. /* *Interface is modelled after encoding/json */
  241. func (p *Decoder) valueInterface(pval cfValue) interface{} {
  242. switch pval := pval.(type) {
  243. case cfString:
  244. return string(pval)
  245. case *cfNumber:
  246. if pval.signed {
  247. return int64(pval.value)
  248. }
  249. return pval.value
  250. case *cfReal:
  251. if pval.wide {
  252. return pval.value
  253. }
  254. return float32(pval.value)
  255. case cfBoolean:
  256. return bool(pval)
  257. case *cfArray:
  258. return p.arrayInterface(pval)
  259. case *cfDictionary:
  260. return p.dictionaryInterface(pval)
  261. case cfData:
  262. return []byte(pval)
  263. case cfDate:
  264. return time.Time(pval)
  265. case cfUID:
  266. return UID(pval)
  267. }
  268. return nil
  269. }
  270. func (p *Decoder) arrayInterface(a *cfArray) []interface{} {
  271. out := make([]interface{}, len(a.values))
  272. for i, subv := range a.values {
  273. out[i] = p.valueInterface(subv)
  274. }
  275. return out
  276. }
  277. func (p *Decoder) dictionaryInterface(dict *cfDictionary) map[string]interface{} {
  278. out := make(map[string]interface{})
  279. for i, k := range dict.keys {
  280. subv := dict.values[i]
  281. out[k] = p.valueInterface(subv)
  282. }
  283. return out
  284. }