/
formats.go
200 lines (179 loc) · 4.95 KB
/
formats.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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
package mpv
// #include "utils.h"
// #include <stdlib.h>
import "C"
import (
"encoding/binary"
"unsafe"
)
func convert2Pointer(data interface{}, format Format) unsafe.Pointer {
switch format {
case FormatNone:
break
case FormatString, FormatOsdString:
if data == nil {
var result *C.char
return unsafe.Pointer(&result)
}
return unsafe.Pointer(C.CString(data.(string)))
case FormatFlag:
if data == nil {
var result C.int
return unsafe.Pointer(&result)
}
result := C.int(0)
if data.(bool) {
result = 1
}
return unsafe.Pointer(&result)
case FormatInt64:
if data == nil {
var result C.int64_t
return unsafe.Pointer(&result)
}
result := C.int64_t(data.(int64))
return unsafe.Pointer(&result)
case FormatDouble:
if data == nil {
var result C.long
return unsafe.Pointer(&result)
}
result := C.long(data.(float64))
return unsafe.Pointer(&result)
case FormatNode:
if data == nil {
var result C.mpv_node
return unsafe.Pointer(&result)
}
// TODO
case FormatNodeArray:
if data == nil {
var result C.mpv_node_list
return unsafe.Pointer(&result)
}
result := C.mpv_node_list{}
arr := data.(NodeList)
result.num = C.int(len(arr))
result.values = C.makeNodeList(result.num)
result.keys = nil
for i, v := range arr {
if v.Data != nil {
C.setNodeListElement(result.values, C.int(i), *v.CNode())
}
}
return unsafe.Pointer(&result)
case FormatNodeMap:
if data == nil {
var result C.mpv_node_list
return unsafe.Pointer(&result)
}
result := C.mpv_node_list{}
arr := data.(NodeMap)
result.num = C.int(len(arr))
result.values = C.makeNodeList(result.num)
result.keys = C.makeStringArray(result.num)
index := 0
for k, v := range arr {
C.setString(result.keys, C.int(index), C.CString(k))
if v.Data != nil {
C.setNodeListElement(result.values, C.int(index), *v.CNode())
}
index += 1
}
return unsafe.Pointer(&result)
case FormatByteArray:
if data == nil {
var result C.mpv_byte_array
return unsafe.Pointer(&result)
}
}
return nil
}
func convert2Data(data interface{}, format Format) interface{} {
switch format {
case FormatNone:
return nil
case FormatString:
if val, ok := data.(*C.char); ok {
return C.GoString(val)
} else
if val, ok := data.(unsafe.Pointer); ok {
return C.GoString((*C.char)(val))
}
val := binary.LittleEndian.Uint64(data.([]byte))
return C.GoString((*C.char)(unsafe.Pointer(uintptr(val))))
case FormatFlag:
if val, ok := data.(C.int); ok {
return val == 1
} else
if val, ok := data.(unsafe.Pointer); ok {
return *(*C.int)(val) == 1
}
return data.(C.int) == 1
case FormatInt64:
if val, ok := data.(C.int64_t); ok {
return int64(val)
} else
if val, ok := data.(unsafe.Pointer); ok { // Idk if this could even be unsafe.Pointer in real usage.
return int64(*(*C.long)(val))
}
return int64(binary.LittleEndian.Uint64(data.([]byte)))
case FormatDouble:
if val, ok := data.(C.double); ok {
return float64(val)
} else
if val, ok := data.(unsafe.Pointer); ok {
return float64(*(*C.double)(val))
}
return nil
case FormatNode:
if val, ok := data.(C.mpv_node); ok {
content := convert2Data(val.u[:], Format(val.format))
return &Node{Data: content, Format: Format(val.format)}
} else if val, ok := data.(*C.mpv_node); ok {
content := convert2Data(val.u[:], Format(val.format))
return &Node{Data: content, Format: Format(val.format)}
} else if val, ok := data.(unsafe.Pointer); ok {
cnode := *(*C.mpv_node)(val)
content := convert2Data(cnode.u[:], Format(cnode.format))
return &Node{Data: content, Format: Format(cnode.format)}
}
return nil
case FormatNodeArray:
ptr := binary.LittleEndian.Uint64(data.([]byte))
arr := *(*C.mpv_node_list)(unsafe.Pointer(uintptr(ptr)))
var cvalues *C.mpv_node = arr.values
values := unsafe.Slice(cvalues, int(arr.num))
result := make(NodeList, arr.num)
for i, v := range values {
val := convert2Data(v.u[:], Format(v.format))
node := Node{Data: val, Format: Format(v.format)}
result[i] = node
}
return result
case FormatNodeMap:
ptr := binary.LittleEndian.Uint64(data.([]byte))
nodeMap := *(*C.mpv_node_list)(unsafe.Pointer(uintptr(ptr)))
var ckeys **C.char = nodeMap.keys
var cvalues *C.mpv_node = nodeMap.values
keys := unsafe.Slice(ckeys, int(nodeMap.num))
values := unsafe.Slice(cvalues, int(nodeMap.num))
result := make(NodeMap, nodeMap.num)
for i, v := range values {
val := convert2Data(v.u[:], Format(v.format))
node := Node{Data: val, Format: Format(v.format)}
key := C.GoString((*C.char)(keys[C.int(i)]))
result[key] = node
}
return result
case FormatByteArray:
// This is always address to value
val := binary.LittleEndian.Uint64(data.([]byte))
ptr := unsafe.Pointer(uintptr(val))
tmp := *(*C.mpv_byte_array)(ptr)
// In libmpv 'size' is int64, but C.GoBytes accept only int
// Could be a problem in the future
return C.GoBytes(tmp.data, C.int(tmp.size))
}
return nil
}