-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathplist.go
83 lines (76 loc) · 2.57 KB
/
plist.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// Package plist implements serializing and deserializing of property list
// objects using CoreFoundation.
//
// Property list objects are any object of type:
// - string
// - []byte
// - time.Time
// - bool
// - numeric type (except for 64-bit uint types)
// - a slice of any property list object
// - a map from a string to any property list object
//
// Note, a []byte (or []uint8) slice is always converted to a CFDataRef,
// but a slice of any other type is converted to a CFArrayRef
package plist
// #cgo LDFLAGS: -framework CoreFoundation
// #include <CoreFoundation/CoreFoundation.h>
import "C"
import "errors"
// TODO: CFPropertyListWrite() for stream-based writing
// TODO: CFPropertyListCreateWithStream() for stream-based reading
func cfPropertyListCreateWithData(data []byte) (cfObj cfTypeRef, format Format, err error) {
cfData := convertBytesToCFData(data)
defer C.CFRelease(C.CFTypeRef(cfData))
var cfFormat C.CFPropertyListFormat
var cfError C.CFErrorRef
cfPlist := C.CFPropertyListCreateWithData(nil, cfData, 0, &cfFormat, &cfError)
if cfPlist == nil {
// an error occurred
if cfError != nil {
defer cfRelease(cfTypeRef(cfError))
return nil, Format{cfFormat}, NewCFError(cfError)
}
return nil, Format{}, errors.New("plist: unknown error in CFPropertyListCreateWithData")
}
return cfTypeRef(cfPlist), Format{cfFormat}, nil
}
func cfPropertyListCreateData(plist cfTypeRef, format Format) ([]byte, error) {
var cfError C.CFErrorRef
cfData := C.CFPropertyListCreateData(nil, C.CFPropertyListRef(plist), format.cfFormat, 0, &cfError)
if cfData == nil {
// an error occurred
if cfError != nil {
defer cfRelease(cfTypeRef(cfError))
return nil, NewCFError(cfError)
}
return nil, errors.New("plist: unknown error in CFPropertyListCreateData")
}
defer cfRelease(cfTypeRef(cfData))
return convertCFDataToBytes(cfData), nil
}
type CFError struct {
Domain string
Code int
UserInfo map[string]interface{}
Description string // comes from CFErrorCopyDescription()
}
func NewCFError(c C.CFErrorRef) *CFError {
e := &CFError{
Domain: convertCFStringToString(C.CFStringRef(C.CFErrorGetDomain(c))),
Code: int(C.CFErrorGetCode(c)),
}
cfDict := C.CFErrorCopyUserInfo(c)
defer C.CFRelease(C.CFTypeRef(cfDict))
if userInfo, err := convertCFDictionaryToMap(cfDict); err == nil {
// on error, skip user info
e.UserInfo = userInfo
}
cfStr := C.CFErrorCopyDescription(c)
defer C.CFRelease(C.CFTypeRef(cfStr))
e.Description = convertCFStringToString(cfStr)
return e
}
func (e *CFError) Error() string {
return "plist: " + e.Description
}