-
Notifications
You must be signed in to change notification settings - Fork 4
/
jna.clj
223 lines (156 loc) · 5.41 KB
/
jna.clj
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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
(ns tech.jna
(:require [tech.jna.base :as base]
[tech.resource :as resource])
(:import [com.sun.jna Native NativeLibrary Pointer Function Platform Structure]
[com.sun.jna.ptr PointerByReference LongByReference IntByReference]))
(set! *warn-on-reflection* true)
(set! *unchecked-math* :warn-on-boxed)
(defprotocol PToPtr
(is-jna-ptr-convertible? [item])
(->ptr-backing-store [item]
"Conversion to a jna pointer type that points to the data of the object."))
(defn ptr-convertible?
[item]
(when (and item (satisfies? PToPtr item))
(is-jna-ptr-convertible? item)))
(defn as-ptr
[item]
(when (ptr-convertible? item)
(->ptr-backing-store item)))
(extend-protocol PToPtr
Pointer
(is-jna-ptr-convertible? [item] true)
(->ptr-backing-store [item] item)
PointerByReference
(is-jna-ptr-convertible? [item] true)
(->ptr-backing-store [item] (.getValue ^PointerByReference item))
Structure
(is-jna-ptr-convertible? [item] true)
(->ptr-backing-store [item] (.getPointer item)))
(defn add-library-path
"Add a search path. The multimethod (base/find-library pathtype path) is called to
expand the pathtype, path into one or more actual paths to attempt. Valid existing
pathtypes are
:system - no changes, looks in system paths.
:java-library-path - Appends library to all paths in java-library-paths
:resource - Uses jna Native/extractFromResourcePath"
[libname pathtype path]
(base/add-library-path libname pathtype path))
(defn clear-library-paths
"Clear the library search paths for a specific library.
Use with care; the default if non found is:
[[:system libname]
[:java-library-path libname]]."
[libname]
(base/clear-library-paths libname))
(defn library-paths
"Get the current library search paths for a library."
[libname]
(base/library-paths libname))
(defn map-shared-library-name
"Map a stem to a shared library name in platform specific manner"
[libname]
(base/map-shared-library-name libname))
(defn set-loaded-library!
"Override the search mechanism and set the native library to X."
[libname native-library]
(base/set-loaded-library! libname native-library))
(defn load-library
^NativeLibrary [libname]
(base/load-library libname))
(defn find-function
^Function [fn-name libname]
(base/find-function fn-name libname))
(defn malloc-untracked
"Malloc pointer of Y bytes. Up to call to call Native/free on result at some point"
^Pointer [^long num-bytes]
(Pointer. (Native/malloc num-bytes)))
(defn malloc
"Malloc a pointer of Y bytes. Track using both resource context
and gc system."
^Pointer [^long num-bytes]
(let [retval (malloc-untracked num-bytes)
native-value (Pointer/nativeValue retval)]
(resource/track retval
#(Native/free native-value)
[:gc :stack])))
(defn unsafe-read-byte
[^Pointer byte-ary ^long idx]
(base/unsafe-read-byte byte-ary idx))
(defn variable-byte-ptr->string
"Convert a c-string into a string"
^String [^Pointer ptr-addr]
(.getString ptr-addr 0 "ASCII"))
(defn char-ptr-ptr->string-vec
"Decode a char** ptr."
[^long num-strings ^Pointer char-ptr-ptr]
(base/char-ptr-ptr->string-vec num-strings char-ptr-ptr))
(defn string->ptr
^Pointer [^String data]
(let [^Pointer retval (malloc (+ 1 (count data)))]
(.setString retval 0 data "ASCII")
retval))
(defn string->wide-ptr
^Pointer [^String data]
(let [^Pointer retval (malloc (-> (+ 1 (count data))
(* Native/WCHAR_SIZE)))]
(.setWideString retval 0 data)
retval))
(defn wide-ptr->string
^String [^Pointer wide-ptr]
(.getWideString wide-ptr 0))
(defn create-ptr-ptr
"Create a pointer to a pointer."
[^Pointer ptr]
(let [ptr-map {:ptr ptr}
retval (PointerByReference. ptr)]
;;Ensure the original ptr is referenced else you could get hurt.
(resource/track retval #(get ptr-map :ptr) [:gc])))
(defn checknil
^Pointer [value]
(let [value (->ptr-backing-store value)]
(if (= 0 (long (Pointer/nativeValue value)))
(throw (ex-info "Pointer value is nil"
{}))
value)))
(defn ensure-type
[item-cls item]
(base/ensure-type item-cls item))
(defn ensure-ptr-ptr
^PointerByReference [item]
(base/ensure-ptr-ptr item))
(defn ensure-ptr
^Pointer [item]
(base/ensure-ptr (->ptr-backing-store
item)))
(defn size-t
[& [item]]
(case Native/SIZE_T_SIZE
4 (int (or item 0))
8 (long (or item 0))))
(def size-t-type (type (size-t)))
(def size-t-ref-type (if (= Long size-t-type)
LongByReference
IntByReference))
(defn size-t-ref
[& [init-value]]
(if (= LongByReference size-t-ref-type)
(LongByReference. (long (or init-value 0)))
(IntByReference. (int (or init-value 0)))))
(defn size-t-ref-value
[ref-obj]
(if (instance? LongByReference ref-obj)
(.getValue ^LongByReference ref-obj)
(.getValue ^IntByReference ref-obj)))
(defmacro def-jna-fn
"Define a dynamically bound fn. Upon first call, it will attempt to find
the function pointer from libname.
Argpair is of type [symbol type-coersion], symbol cannot match type-coersion."
[libname fn-name docstring rettype & argpairs]
`(base/def-jna-fn ~libname ~fn-name ~docstring ~rettype ~@argpairs))
(defn c-library-name
^String []
(base/c-library-name))
(defn math-library-name
^String []
(base/math-library-name))