koffi 3.0.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -3
- package/cnoke.cjs +2 -2
- package/doc/benchmarks.md +1 -1
- package/doc/callbacks.md +7 -26
- package/doc/{input.md → composites.md} +161 -147
- package/doc/contribute.md +3 -2
- package/doc/index.md +0 -14
- package/doc/{functions.md → load.md} +54 -113
- package/doc/migration.md +4 -7
- package/doc/misc.md +0 -103
- package/doc/output.md +5 -11
- package/doc/pointers.md +76 -17
- package/doc/primitives.md +151 -0
- package/doc/start.md +3 -13
- package/doc/types.md +88 -0
- package/doc/unions.md +0 -186
- package/doc/values.md +134 -0
- package/index.d.ts +375 -308
- package/lib/native/base/base.cc +66 -24
- package/lib/native/base/base.hh +55 -153
- package/package.json +16 -16
- package/src/koffi/CMakeLists.txt +20 -17
- package/src/koffi/index.cjs +30 -111
- package/src/koffi/index.js +22 -96
- package/src/koffi/indirect.cjs +30 -111
- package/src/koffi/indirect.js +24 -24
- package/src/koffi/src/abi/arm64.cc +48 -62
- package/src/koffi/src/abi/riscv64.cc +39 -57
- package/src/koffi/src/abi/x64sysv.cc +39 -57
- package/src/koffi/src/abi/x64win.cc +48 -65
- package/src/koffi/src/abi/x86.cc +47 -59
- package/src/koffi/src/call.cc +426 -209
- package/src/koffi/src/call.hh +7 -11
- package/src/koffi/src/ffi.cc +534 -303
- package/src/koffi/src/ffi.hh +71 -15
- package/src/koffi/src/parser.cc +5 -3
- package/src/koffi/src/parser.hh +2 -2
- package/src/koffi/src/static.cjs +122 -0
- package/src/koffi/src/static.js +125 -0
- package/src/koffi/src/type.cc +725 -0
- package/src/koffi/src/type.hh +71 -0
- package/src/koffi/src/util.cc +117 -1202
- package/src/koffi/src/util.hh +158 -156
- package/src/koffi/src/uv.cc +17 -11
- package/src/koffi/src/uv.hh +2 -1
- package/vendor/node-addon-api/README.md +1 -1
- package/vendor/node-addon-api/napi-inl.h +213 -35
- package/vendor/node-addon-api/napi.h +118 -7
- package/doc/variables.md +0 -102
- package/indirect.d.ts +0 -322
|
@@ -11,14 +11,7 @@ const lib = koffi.load('/path/to/shared/library'); // File extension depends on
|
|
|
11
11
|
|
|
12
12
|
This library will be automatically unloaded once all references to it are gone (including all the functions that use it, as described below).
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
> [!NOTE]
|
|
17
|
-
> On some platforms (such as with the [musl C library on Linux](https://wiki.musl-libc.org/functional-differences-from-glibc.html#Unloading-libraries)), shared libraries cannot be unloaded, so the library will remain loaded and memory mapped after the call to `lib.unload()`.
|
|
18
|
-
|
|
19
|
-
# Loading options
|
|
20
|
-
|
|
21
|
-
*New in Koffi 2.6, changed in Koffi 2.8.2 and Koffi 2.8.6*
|
|
14
|
+
## Load options
|
|
22
15
|
|
|
23
16
|
The `load` function can take an optional object argument, with the following options:
|
|
24
17
|
|
|
@@ -34,7 +27,14 @@ const lib = koffi.load('/path/to/shared/library.so', options);
|
|
|
34
27
|
|
|
35
28
|
More options may be added if needed.
|
|
36
29
|
|
|
37
|
-
|
|
30
|
+
## Unloading
|
|
31
|
+
|
|
32
|
+
Use `lib.unload()` to can explicitly unload a library. Any attempt to find or call a function from this library after unloading it will crash.
|
|
33
|
+
|
|
34
|
+
> [!NOTE]
|
|
35
|
+
> On some platforms (such as with the [musl C library on Linux](https://wiki.musl-libc.org/functional-differences-from-glibc.html#Unloading-libraries)), shared libraries cannot be unloaded, so the library will remain loaded and memory mapped after the call to `lib.unload()`.
|
|
36
|
+
|
|
37
|
+
# Functions
|
|
38
38
|
|
|
39
39
|
## Definition syntax
|
|
40
40
|
|
|
@@ -48,10 +48,16 @@ Use the object returned by `koffi.load()` to load C functions from the library.
|
|
|
48
48
|
To declare a function, you need to specify its non-mangled name, its return type, and its parameters. Use an ellipsis as the last parameter for variadic functions.
|
|
49
49
|
|
|
50
50
|
```js
|
|
51
|
-
const printf = lib.func('printf', 'int', ['str', '...']);
|
|
52
51
|
const atoi = lib.func('atoi', 'int', ['str']);
|
|
53
52
|
```
|
|
54
53
|
|
|
54
|
+
Once a native function has been declared, you can simply call it as you would any other JS function:
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
let value = atoi('1257'); // Returns 1257 as number
|
|
58
|
+
console.log(typeof value); // Print number
|
|
59
|
+
```
|
|
60
|
+
|
|
55
61
|
Koffi automatically tries mangled names for non-standard x86 calling conventions. See the section on [calling conventions](#calling-conventions) for more information on this subject.
|
|
56
62
|
|
|
57
63
|
### C-like prototypes
|
|
@@ -59,8 +65,15 @@ Koffi automatically tries mangled names for non-standard x86 calling conventions
|
|
|
59
65
|
If you prefer, you can declare functions using simple C-like prototype strings, as shown below:
|
|
60
66
|
|
|
61
67
|
```js
|
|
62
|
-
|
|
63
|
-
const atoi = lib.func('int atoi(
|
|
68
|
+
// The parameter name (nptn below) is not used by Koffi, and optional, but can be nice for documentation
|
|
69
|
+
const atoi = lib.func('int atoi(const char *nptr)');
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Once a native function has been declared, you can simply call it as you would any other JS function:
|
|
73
|
+
|
|
74
|
+
```js
|
|
75
|
+
let value = atoi('1257'); // Returns 1257 as number
|
|
76
|
+
console.log(typeof value); // Print number
|
|
64
77
|
```
|
|
65
78
|
|
|
66
79
|
You can use `()` or `(void)` for functions that take no argument.
|
|
@@ -72,20 +85,19 @@ Variadic functions are declared with an ellipsis as the last argument.
|
|
|
72
85
|
In order to call a variadic function, you must provide two Javascript arguments for each additional C parameter, the first one is the expected type and the second one is the value.
|
|
73
86
|
|
|
74
87
|
```js
|
|
75
|
-
|
|
88
|
+
// These two declarations are identical
|
|
89
|
+
const printf1 = lib.func('printf', 'int', ['str', '...']);
|
|
90
|
+
const printf2 = lib.func('int printf(str fmt, ...)');
|
|
76
91
|
|
|
77
92
|
// The variadic arguments are: 6 (int), 8.5 (double), 'THE END' (const char *)
|
|
78
|
-
|
|
93
|
+
printf1('Integer %d, double %g, str %s', 'int', 6, 'double', 8.5, 'str', 'THE END');
|
|
94
|
+
printf2('Integer %d, double %g, str %s', 'int', 6, 'double', 8.5, 'str', 'THE END');
|
|
79
95
|
```
|
|
80
96
|
|
|
81
97
|
On x86 platforms, only the Cdecl convention can be used for variadic functions.
|
|
82
98
|
|
|
83
99
|
## Calling conventions
|
|
84
100
|
|
|
85
|
-
*Changed in Koffi 2.7*
|
|
86
|
-
|
|
87
|
-
By default, calling a C function happens synchronously.
|
|
88
|
-
|
|
89
101
|
Most architectures only support one procedure call standard per process. The 32-bit x86 platform is an exception to this, and Koffi supports several x86 conventions:
|
|
90
102
|
|
|
91
103
|
Convention | Classic form | Prototype form | Description
|
|
@@ -97,11 +109,6 @@ Most architectures only support one procedure call standard per process. The 32-
|
|
|
97
109
|
|
|
98
110
|
You can safely use these on non-x86 platforms, they are simply ignored.
|
|
99
111
|
|
|
100
|
-
> [!NOTE]
|
|
101
|
-
> Support for specifying the convention as the first argument of the classic form was introduced in Koffi 2.7.
|
|
102
|
-
>
|
|
103
|
-
> In earlier versions, you had to use `koffi.stdcall()` and similar functions. These functions are still supported but deprecated, and will be removed in Koffi 3.0.
|
|
104
|
-
|
|
105
112
|
Below you can find a small example showing how to use a non-default calling convention, with the two syntaxes:
|
|
106
113
|
|
|
107
114
|
```js
|
|
@@ -111,30 +118,8 @@ import koffi from 'koffi';
|
|
|
111
118
|
const lib = koffi.load('user32.dll');
|
|
112
119
|
|
|
113
120
|
// The following two declarations are equivalent, and use stdcall on x86 (and the default ABI on other platforms)
|
|
114
|
-
const
|
|
115
|
-
const
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
# Call types
|
|
119
|
-
|
|
120
|
-
## Synchronous calls
|
|
121
|
-
|
|
122
|
-
Once a native function has been declared, you can simply call it as you would any other JS function.
|
|
123
|
-
|
|
124
|
-
```js
|
|
125
|
-
const atoi = lib.func('int atoi(const char *str)');
|
|
126
|
-
|
|
127
|
-
let value = atoi('1257');
|
|
128
|
-
console.log(value);
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
For [variadic functions](functions#variadic-functions), you msut specificy the type and the value for each additional argument.
|
|
132
|
-
|
|
133
|
-
```js
|
|
134
|
-
const printf = lib.func('printf', 'int', ['str', '...']);
|
|
135
|
-
|
|
136
|
-
// The variadic arguments are: 6 (int), 8.5 (double), 'THE END' (const char *)
|
|
137
|
-
printf('Integer %d, double %g, str %s', 'int', 6, 'double', 8.5, 'str', 'THE END');
|
|
121
|
+
const MessageBoxA1 = lib.func('__stdcall', 'MessageBoxA', 'int', ['void *', 'str', 'str', 'uint']);
|
|
122
|
+
const MessageBoxA2 = lib.func('int __stdcall MessageBoxA(void *hwnd, str text, str caption, uint type)');
|
|
138
123
|
```
|
|
139
124
|
|
|
140
125
|
## Asynchronous calls
|
|
@@ -167,84 +152,40 @@ Variadic functions cannot be called asynchronously.
|
|
|
167
152
|
|
|
168
153
|
> [!WARNING]
|
|
169
154
|
> Asynchronous functions run on worker threads. You need to deal with thread safety issues if you share data between threads.
|
|
170
|
-
>
|
|
171
|
-
> Callbacks must be called from the main thread, or more precisely from the same thread as the V8 intepreter. Calling a callback from another thread is undefined behavior, and will likely lead to a crash or a big mess. You've been warned!
|
|
172
|
-
|
|
173
|
-
# Function pointers
|
|
174
|
-
|
|
175
|
-
*New in Koffi 2.4*
|
|
176
|
-
|
|
177
|
-
You can call a function pointer in two ways:
|
|
178
155
|
|
|
179
|
-
|
|
180
|
-
- Decode the function pointer to an actual function with `koffi.decode(ptr, type)`
|
|
156
|
+
## Conversion of parameters
|
|
181
157
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
```c
|
|
185
|
-
typedef int BinaryIntFunc(int a, int b);
|
|
186
|
-
|
|
187
|
-
static int AddInt(int a, int b) { return a + b; }
|
|
188
|
-
static int SubstractInt(int a, int b) { return a - b; }
|
|
189
|
-
|
|
190
|
-
BinaryIntFunc *GetBinaryIntFunction(const char *type)
|
|
191
|
-
{
|
|
192
|
-
if (!strcmp(type, "add")) {
|
|
193
|
-
return AddInt;
|
|
194
|
-
} else if (!strcmp(type, "substract")) {
|
|
195
|
-
return SubstractInt;
|
|
196
|
-
} else {
|
|
197
|
-
return NULL;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
## Call pointer directly
|
|
158
|
+
By default, Koffi will only forward and translate arguments from Javascript to C. However, many C functions use pointer arguments for output values, or input/output values.
|
|
203
159
|
|
|
204
|
-
|
|
160
|
+
Among other thing, in the the following pages you will learn more about:
|
|
205
161
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
162
|
+
- The [primitives types](primitives) supported by Koffi
|
|
163
|
+
- How to define [composite types](composites): structs, arrays and unions
|
|
164
|
+
- How you can [define and use pointers](pointers)
|
|
165
|
+
- How to deal with [output parameters](output)
|
|
209
166
|
|
|
210
|
-
|
|
167
|
+
# Variables
|
|
211
168
|
|
|
212
|
-
|
|
213
|
-
const substract_ptr = GetBinaryIntFunction('substract');
|
|
169
|
+
*Changed in Koffi 3.1.0*
|
|
214
170
|
|
|
215
|
-
|
|
216
|
-
let delta = koffi.call(substract_ptr, BinaryIntFunc, 100, 58);
|
|
171
|
+
To find an exported variable symbol, use `lib.symbol(name)`. You need to specify its name and its type.
|
|
217
172
|
|
|
218
|
-
|
|
173
|
+
```c
|
|
174
|
+
int my_int = 42;
|
|
175
|
+
const char *my_string = NULL;
|
|
219
176
|
```
|
|
220
177
|
|
|
221
|
-
## Decode pointer to function
|
|
222
|
-
|
|
223
|
-
Use `koffi.decode(ptr, type)` to get back a JS function, which you can then use like any other Koffi function.
|
|
224
|
-
|
|
225
|
-
This method also allows you to perform an [asynchronous call](#asynchronous-calls) with the async member of the decoded function.
|
|
226
|
-
|
|
227
178
|
```js
|
|
228
|
-
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
const GetBinaryIntFunction = lib.func('BinaryIntFunc *GetBinaryIntFunction(const char *name)');
|
|
232
|
-
|
|
233
|
-
const add = koffi.decode(GetBinaryIntFunction('add'), BinaryIntFunc);
|
|
234
|
-
const substract = koffi.decode(GetBinaryIntFunction('substract'), BinaryIntFunc);
|
|
235
|
-
|
|
236
|
-
let sum = add(4, 5);
|
|
237
|
-
let delta = substract(100, 58);
|
|
238
|
-
|
|
239
|
-
console.log(sum, delta); // Prints 9 and 42
|
|
179
|
+
const my_int = lib.symbol('my_int');
|
|
180
|
+
const my_string = lib.symbol('my_string');
|
|
240
181
|
```
|
|
241
182
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
By default, Koffi will only forward and translate arguments from Javascript to C. However, many C functions use pointer arguments for output values, or input/output values.
|
|
183
|
+
This function returns a pointer (a BigInt value in Koffi 3). To read or change the value of the variable, you can use:
|
|
245
184
|
|
|
246
|
-
|
|
185
|
+
- [koffi.decode()](values#decode-to-js-values) to read the value
|
|
186
|
+
- [koffi.encode()](values#encode-to-c-memory) to change the value
|
|
247
187
|
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
188
|
+
> [!NOTE]
|
|
189
|
+
> Until Koffi 3.1.0, the `symbol()` function required you to give a type, even though it did nothing with this information. This was a leftover from Koffi 2.
|
|
190
|
+
>
|
|
191
|
+
> For compatibility, you can still call `lib.symbol(name, type)`, but this is deprecated.
|
package/doc/migration.md
CHANGED
|
@@ -6,7 +6,7 @@ However, some changes could impact your code:
|
|
|
6
6
|
|
|
7
7
|
- Koffi is now distributed in [split packages](#split-packages) to reduce install size/bloat.
|
|
8
8
|
- Pointers are now [BigInt values](#bigint-pointers) instead of opaque V8 external values.
|
|
9
|
-
- Types created by koffi are now [type objects](#type-objects)
|
|
9
|
+
- Types created by koffi are now [type objects](#type-objects) instead of opaque V8 external values.
|
|
10
10
|
- Using `koffi.register()` with a [receiver value](#registered-callback-binding) is deprecated.
|
|
11
11
|
- Several old [deprecated functions](#removed-functions) have been removed.
|
|
12
12
|
|
|
@@ -36,7 +36,7 @@ You can resolve type strings to type objects with `koffi.type()`. This function
|
|
|
36
36
|
> [!NOTE]
|
|
37
37
|
> For compatibility reasons, both `koffi.resolve()` and `koffi.introspect()` still exist, as aliases for `koffi.type()`. Using them will emit a deprecation warning.
|
|
38
38
|
|
|
39
|
-
Read the documentation about [type specifiers](
|
|
39
|
+
Read the documentation about [type specifiers](types#type-specifiers) for more information.
|
|
40
40
|
|
|
41
41
|
The two versions below illustrate the API difference between Koffi 2.x and Koffi 3.x:
|
|
42
42
|
|
|
@@ -108,7 +108,7 @@ You may need to change your code if you use:
|
|
|
108
108
|
- Opaque types
|
|
109
109
|
- `koffi.introspect()`
|
|
110
110
|
|
|
111
|
-
## Callback
|
|
111
|
+
## Callback types
|
|
112
112
|
|
|
113
113
|
In Koffi 1.x, callbacks were defined in a way that made them usable directly as parameter and return types, obscuring the underlying pointer. Now, you must use them through a pointer: `void CallIt(CallbackType func)` in Koffi 1.x becomes `void CallIt(CallbackType *func)` in version 2.0 and newer.
|
|
114
114
|
|
|
@@ -161,10 +161,7 @@ console.log(ret);
|
|
|
161
161
|
|
|
162
162
|
Koffi 1.x only supported [transient callbacks](callbacks#javascript-callbacks), you must use Koffi 2.x for registered callbacks.
|
|
163
163
|
|
|
164
|
-
|
|
165
|
-
> The function `koffi.proto()` was introduced in Koffi 2.4, it was called `koffi.callback()` in earlier versions.
|
|
166
|
-
|
|
167
|
-
## Opaque type changes
|
|
164
|
+
## Opaque types
|
|
168
165
|
|
|
169
166
|
In Koffi 1.x, opaque handles were defined in a way that made them usable directly as parameter and return types, obscuring the underlying pointer. Now, in Koffi 2.0, you must use them through a pointer, and use an array for output parameters.
|
|
170
167
|
|
package/doc/misc.md
CHANGED
|
@@ -1,98 +1,3 @@
|
|
|
1
|
-
# Types
|
|
2
|
-
|
|
3
|
-
## Type specifiers
|
|
4
|
-
|
|
5
|
-
*Changed in Koffi 3.0*
|
|
6
|
-
|
|
7
|
-
> [!NOTE]
|
|
8
|
-
> In Koffi 2.0, types were External values, you had to use `koffi.introspect()` to get type information. In Koffi 3.0, this information is directly available in type objects, and this function is deprecated.
|
|
9
|
-
>
|
|
10
|
-
> Consult the [migration guide](migration) for more information.
|
|
11
|
-
|
|
12
|
-
You can use strings or type objects to give type information to Koffi (when declaring functions, structs, and so on). Use `koffi.type(spec)` to resolve all accepted type values (strings and type objects) to type objects.
|
|
13
|
-
|
|
14
|
-
You can inspect the type object for information: name, primitive, size, alignment, members (record types), reference type (array, pointer), length (array), arguments and return type (prototypes).
|
|
15
|
-
|
|
16
|
-
```js
|
|
17
|
-
const FoobarType = koffi.struct('FoobarType', {
|
|
18
|
-
a: 'int',
|
|
19
|
-
b: 'char *',
|
|
20
|
-
c: 'double'
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
console.log(FoobarType);
|
|
24
|
-
|
|
25
|
-
// Expected result on 64-bit machines:
|
|
26
|
-
// {
|
|
27
|
-
// name: 'FoobarType',
|
|
28
|
-
// primitive: 'Record',
|
|
29
|
-
// size: 24,
|
|
30
|
-
// alignment: 8,
|
|
31
|
-
// disposable: false,
|
|
32
|
-
// members: {
|
|
33
|
-
// a: { name: 'a', type: [Type], offset: 0 },
|
|
34
|
-
// b: { name: 'b', type: [Type], offset: 8 },
|
|
35
|
-
// c: { name: 'c', type: [Type], offset: 16 }
|
|
36
|
-
// }
|
|
37
|
-
// }
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Koffi also exposes a few more utility functions to get a subset of this information:
|
|
41
|
-
|
|
42
|
-
- `koffi.sizeof(type)` to get the size of a type
|
|
43
|
-
- `koffi.alignof(type)` to get the alignment of a type
|
|
44
|
-
- `koffi.offsetof(type, member_name)` to get the offset of a record member
|
|
45
|
-
- `koffi.type(type)` to get the resolved type object from a type string
|
|
46
|
-
|
|
47
|
-
Just like before, you can refer to primitive types by their name or through `koffi.types`:
|
|
48
|
-
|
|
49
|
-
```js
|
|
50
|
-
// These two lines do the same:
|
|
51
|
-
console.log(koffi.sizeof('long'));
|
|
52
|
-
console.log(koffi.sizeof(koffi.types.long));
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
## Aliases
|
|
56
|
-
|
|
57
|
-
*New in Koffi 2.0*
|
|
58
|
-
|
|
59
|
-
You can alias a type with `koffi.alias(name, type)`. Aliased types are completely equivalent.
|
|
60
|
-
|
|
61
|
-
## Circular references
|
|
62
|
-
|
|
63
|
-
*New in Koffi 2.10.0*
|
|
64
|
-
|
|
65
|
-
In some cases, composite types can point to each other and thus depend on each other. This can also happen when a function takes a pointer to a struct that also contains a function pointer.
|
|
66
|
-
|
|
67
|
-
To deal with this, you can create an opaque type and redefine it later to a concrete struct or union type, as shown below.
|
|
68
|
-
|
|
69
|
-
```js
|
|
70
|
-
const Type1 = koffi.opaque('Type1');
|
|
71
|
-
|
|
72
|
-
const Type2 = koffi.struct('Type2', {
|
|
73
|
-
ptr: 'Type1 *',
|
|
74
|
-
i: 'int'
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// Redefine Type1 to a concrete type
|
|
78
|
-
koffi.struct(Type1, {
|
|
79
|
-
ptr: 'Type2 *',
|
|
80
|
-
f: 'float'
|
|
81
|
-
});
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
> [!NOTE]
|
|
85
|
-
> You must use a proper type object when you redefine the type. If you only have the name, use `koffi.resolve()` to get a type object from a type string.
|
|
86
|
-
>
|
|
87
|
-
> ```js
|
|
88
|
-
> const MyType = koffi.opaque('MyType');
|
|
89
|
-
>
|
|
90
|
-
> // This does not work, you must use the MyType object and not a type string
|
|
91
|
-
> koffi.struct('MyType', {
|
|
92
|
-
> ptr: 'Type2 *',
|
|
93
|
-
> f: 'float'
|
|
94
|
-
> });
|
|
95
|
-
|
|
96
1
|
# Settings
|
|
97
2
|
|
|
98
3
|
## Memory usage
|
|
@@ -122,8 +27,6 @@ Async calls run on worker threads, the number of which depends on the number of
|
|
|
122
27
|
|
|
123
28
|
## Default settings
|
|
124
29
|
|
|
125
|
-
*Changed in Koffi 2.15*
|
|
126
|
-
|
|
127
30
|
Setting | Default | Maximum | Description
|
|
128
31
|
-------------------- | ------- | ------- | ----------------------------------------------------
|
|
129
32
|
sync_stack_size | 1 MiB | 16 MiB | Stack size for synchronous calls
|
|
@@ -136,14 +39,10 @@ max_type_size | 64 MiB | 512 MiB | Maximum size of Koffi types (for arra
|
|
|
136
39
|
|
|
137
40
|
# Usage statistics
|
|
138
41
|
|
|
139
|
-
*New in Koffi 2.3.2*
|
|
140
|
-
|
|
141
42
|
You can use `koffi.stats()` to get a few statistics related to Koffi.
|
|
142
43
|
|
|
143
44
|
# POSIX error codes
|
|
144
45
|
|
|
145
|
-
*New in Koffi 2.3.14*
|
|
146
|
-
|
|
147
46
|
You can use `koffi.errno()` to get the current errno value, and `koffi.errno(value)` to change it.
|
|
148
47
|
|
|
149
48
|
The standard POSIX error codes are available in `koffi.os.errno`, as shown below:
|
|
@@ -166,8 +65,6 @@ console.log('close() with invalid FD is POSIX compliant!');
|
|
|
166
65
|
|
|
167
66
|
# Reset internal state
|
|
168
67
|
|
|
169
|
-
*New in Koffi 2.5.19*
|
|
170
|
-
|
|
171
68
|
You can use `koffi.reset()` to clear some Koffi internal state such as:
|
|
172
69
|
|
|
173
70
|
- Parser type names
|
package/doc/output.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
For simplicity, and because Javascript only has value semantics for primitive types, Koffi can marshal out (or in/out) multiple types of parameters:
|
|
4
4
|
|
|
5
|
-
- [Structs](
|
|
6
|
-
- [Unions](unions)
|
|
7
|
-
- [Opaque types](
|
|
5
|
+
- [Structs](composites#structs) (to/from JS objects)
|
|
6
|
+
- [Unions](composites#unions)
|
|
7
|
+
- [Opaque types](composites#opaque-types)
|
|
8
8
|
- String buffers
|
|
9
9
|
|
|
10
10
|
In order to change an argument from input-only to output or input/output, use the following functions:
|
|
@@ -161,8 +161,6 @@ sqlite3_close_v2(db);
|
|
|
161
161
|
|
|
162
162
|
## String buffer example
|
|
163
163
|
|
|
164
|
-
*New in Koffi 2.2*
|
|
165
|
-
|
|
166
164
|
This example calls a C function to concatenate two strings to a pre-allocated string buffer. Since JS strings are immutable, you must pass an array with a single string instead.
|
|
167
165
|
|
|
168
166
|
```c
|
|
@@ -208,8 +206,6 @@ In most cases, you can use buffers and typed arrays to provide output buffers. T
|
|
|
208
206
|
|
|
209
207
|
## Transient pointers
|
|
210
208
|
|
|
211
|
-
*New in Koffi 2.3*
|
|
212
|
-
|
|
213
209
|
You can use buffers and typed arrays for output (and input/output) pointer parameters. Simply pass the buffer as an argument and the native function will receive a pointer to its contents.
|
|
214
210
|
|
|
215
211
|
Once the native function returns, you can decode the content with `koffi.decode(value, type)` as in the following example:
|
|
@@ -248,17 +244,15 @@ console.log(vec1); // { x: 3, y: 2, z: 1 }
|
|
|
248
244
|
console.log(vec2); // { x: 1, y: 2, z: 3 }
|
|
249
245
|
```
|
|
250
246
|
|
|
251
|
-
See [decoding variables](
|
|
247
|
+
See [decoding variables](values#decode-to-js-values) for more information about the decode function.
|
|
252
248
|
|
|
253
249
|
## Stable pointers
|
|
254
250
|
|
|
255
|
-
*New in Koffi 2.8*
|
|
256
|
-
|
|
257
251
|
In some cases, the native code may need to change the output buffer at a later time, maybe during a later call or from another thread.
|
|
258
252
|
|
|
259
253
|
In this case, it is **not safe to use buffers or typed arrays**!
|
|
260
254
|
|
|
261
|
-
However, you can use `koffi.alloc(type, len)` to allocate memory and get a pointer that won't move, and can be safely used at any time by the native code. Use [koffi.decode()](
|
|
255
|
+
However, you can use `koffi.alloc(type, len)` to allocate memory and get a pointer that won't move, and can be safely used at any time by the native code. Use [koffi.decode()](values#decode-to-js-values) to read data from the pointer when needed.
|
|
262
256
|
|
|
263
257
|
The example below sets up some memory to be used as an output buffer where a concatenation function appends a string on each call.
|
|
264
258
|
|
package/doc/pointers.md
CHANGED
|
@@ -5,13 +5,15 @@ In C, pointer arguments are used for differenty purposes. It is important to dis
|
|
|
5
5
|
- **Struct pointers**: Use of struct pointers by C libraries fall in two cases: avoid (potentially) expensive copies, and to let the function change struct contents (output or input/output arguments).
|
|
6
6
|
- **Opaque pointers**: the library does not expose the contents of the structs, and only provides you with a pointer to it (e.g. `FILE *`). Only the functions provided by the library can do something with this pointer, in Koffi we call this an opaque type. This is usually done for ABI-stability reason, and to prevent library users from messing directly with library internals.
|
|
7
7
|
- **Pointers to primitive types**: This is more rare, and generally used for output or input/output arguments. The Win32 API has a lot of these.
|
|
8
|
-
- **Arrays**: in C,
|
|
8
|
+
- **Arrays**: in C, dynamically-sized arrays are usually passed to functions with pointers, either NULL-terminated (or any other sentinel value) or with an additional length argument.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Koffi uses BigInt numbers to represent pointers.
|
|
11
|
+
|
|
12
|
+
# Data pointers
|
|
11
13
|
|
|
12
14
|
## Struct pointers
|
|
13
15
|
|
|
14
|
-
The following Win32 example uses `GetCursorPos()` (with an output parameter) to retrieve and show the current cursor position.
|
|
16
|
+
The following Win32 example uses `GetCursorPos()` (with an [output parameter](output)) to retrieve and show the current cursor position.
|
|
15
17
|
|
|
16
18
|
```js
|
|
17
19
|
import koffi from 'koffi';
|
|
@@ -37,8 +39,6 @@ console.log(pos);
|
|
|
37
39
|
|
|
38
40
|
## Opaque pointers
|
|
39
41
|
|
|
40
|
-
*New in Koffi 2.0*
|
|
41
|
-
|
|
42
42
|
Some C libraries use handles, which behave as pointers to opaque structs. An example of this is the HANDLE type in the Win32 API. If you want to reproduce this behavior, you can define a **named pointer type** to an opaque type, like so:
|
|
43
43
|
|
|
44
44
|
```js
|
|
@@ -49,11 +49,9 @@ const GetHandleInformation = lib.func('bool __stdcall GetHandleInformation(HANDL
|
|
|
49
49
|
const CloseHandle = lib.func('bool __stdcall CloseHandle(HANDLE h)');
|
|
50
50
|
```
|
|
51
51
|
|
|
52
|
-
Koffi uses BigInt numbers to represent opaque pointers.
|
|
53
|
-
|
|
54
52
|
## Pointer to primitive types
|
|
55
53
|
|
|
56
|
-
In
|
|
54
|
+
In Javascript, it is not possible to pass a primitive value by reference to another function. This means that you cannot call a function and expect it to modify the value of one of its number or string parameter.
|
|
57
55
|
|
|
58
56
|
However, arrays and objects (among others) are reference type values. Assigning an array or an object from one variable to another does not invole any copy. Instead, as the following example illustrates, the new variable references the same array as the first:
|
|
59
57
|
|
|
@@ -68,7 +66,7 @@ console.log(list1); // Prints [1, 42]
|
|
|
68
66
|
|
|
69
67
|
All of this means that C functions that are expected to modify their primitive output values (such as an `int *` parameter) cannot be used directly. However, thanks to Koffi's transparent array support, you can use Javascript arrays to approximate reference semantics with single-element arrays.
|
|
70
68
|
|
|
71
|
-
Below, you can find an example of an addition function where the result is stored in an `int *` input/output parameter and how to use this function from Koffi.
|
|
69
|
+
Below, you can find an example of an addition function where the result is stored in an `int *` [input/output parameter](output) and how to use this function from Koffi.
|
|
72
70
|
|
|
73
71
|
```c
|
|
74
72
|
void AddInt(int *dest, int add)
|
|
@@ -132,9 +130,74 @@ console.log(total); // Prints 14
|
|
|
132
130
|
|
|
133
131
|
By default, just like for objects, array arguments are copied from JS to C but not vice-versa. You can however change the direction as documented in the section on [output parameters](output).
|
|
134
132
|
|
|
135
|
-
#
|
|
133
|
+
# Function pointers
|
|
134
|
+
|
|
135
|
+
You can call a function pointer in two ways:
|
|
136
|
+
|
|
137
|
+
- Directly call the function pointer with `koffi.call(ptr, type, ...)`
|
|
138
|
+
- Decode the function pointer to an actual function with `koffi.decode(ptr, type)`
|
|
139
|
+
|
|
140
|
+
The example below shows how to call an `int (*)(int, int)` C function pointer both ways, based on the following native C library:
|
|
141
|
+
|
|
142
|
+
```c
|
|
143
|
+
typedef int BinaryIntFunc(int a, int b);
|
|
144
|
+
|
|
145
|
+
static int AddInt(int a, int b) { return a + b; }
|
|
146
|
+
static int SubstractInt(int a, int b) { return a - b; }
|
|
147
|
+
|
|
148
|
+
BinaryIntFunc *GetBinaryIntFunction(const char *type)
|
|
149
|
+
{
|
|
150
|
+
if (!strcmp(type, "add")) {
|
|
151
|
+
return AddInt;
|
|
152
|
+
} else if (!strcmp(type, "substract")) {
|
|
153
|
+
return SubstractInt;
|
|
154
|
+
} else {
|
|
155
|
+
return NULL;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Call pointer directly
|
|
161
|
+
|
|
162
|
+
Use `koffi.call(ptr, type, ...)` to call a function pointer. The first two arguments are the pointer itself and the type of the function you are trying to call (declared with `koffi.proto()` as shown below), and the remaining arguments are used for the call.
|
|
163
|
+
|
|
164
|
+
```js
|
|
165
|
+
// Declare function type
|
|
166
|
+
const BinaryIntFunc = koffi.proto('int BinaryIntFunc(int a, int b)');
|
|
136
167
|
|
|
137
|
-
|
|
168
|
+
const GetBinaryIntFunction = lib.func('BinaryIntFunc *GetBinaryIntFunction(const char *name)');
|
|
169
|
+
|
|
170
|
+
const add_ptr = GetBinaryIntFunction('add');
|
|
171
|
+
const substract_ptr = GetBinaryIntFunction('substract');
|
|
172
|
+
|
|
173
|
+
let sum = koffi.call(add_ptr, BinaryIntFunc, 4, 5);
|
|
174
|
+
let delta = koffi.call(substract_ptr, BinaryIntFunc, 100, 58);
|
|
175
|
+
|
|
176
|
+
console.log(sum, delta); // Prints 9 and 42
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Decode pointer to function
|
|
180
|
+
|
|
181
|
+
Use `koffi.decode(ptr, type)` to get back a JS function, which you can then use like any other Koffi function.
|
|
182
|
+
|
|
183
|
+
```js
|
|
184
|
+
// Declare function type
|
|
185
|
+
const BinaryIntFunc = koffi.proto('int BinaryIntFunc(int a, int b)');
|
|
186
|
+
|
|
187
|
+
const GetBinaryIntFunction = lib.func('BinaryIntFunc *GetBinaryIntFunction(const char *name)');
|
|
188
|
+
|
|
189
|
+
const add = koffi.decode(GetBinaryIntFunction('add'), BinaryIntFunc);
|
|
190
|
+
const substract = koffi.decode(GetBinaryIntFunction('substract'), BinaryIntFunc);
|
|
191
|
+
|
|
192
|
+
let sum = add(4, 5);
|
|
193
|
+
let delta = substract(100, 58);
|
|
194
|
+
|
|
195
|
+
console.log(sum, delta); // Prints 9 and 42
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
This method also allows you to perform an [asynchronous call](load#asynchronous-calls) with the async member of the decoded function.
|
|
199
|
+
|
|
200
|
+
# Handling void pointers
|
|
138
201
|
|
|
139
202
|
Many C functions use `void *` parameters in order to pass polymorphic objects and arrays, meaning that the data format changes can change depending on one other argument, or on some kind of struct tag member.
|
|
140
203
|
|
|
@@ -143,7 +206,7 @@ Koffi provides two features to deal with this:
|
|
|
143
206
|
- You can use `koffi.as(value, type)` to tell Koffi what kind of type is actually expected, as shown in the example below.
|
|
144
207
|
- Buffers and typed JS arrays can be used as values in place everywhere a pointer is expected. See [dynamic arrays](#dynamic-arrays) for more information, for input or output.
|
|
145
208
|
|
|
146
|
-
The example below shows the use of `koffi.as()` to read the header of a PNG file with `fread()` directly to a JS object.
|
|
209
|
+
The example below shows the use of `koffi.as()` to read the header of a PNG file with `fread()` directly to a JS object. It also uses [endian-sensitive integers](primitives#endian-sensitive-integers) to decode PNG header values:
|
|
147
210
|
|
|
148
211
|
```js
|
|
149
212
|
import koffi from 'koffi';
|
|
@@ -197,8 +260,6 @@ console.log('PNG header:', hdr);
|
|
|
197
260
|
|
|
198
261
|
# Disposable types
|
|
199
262
|
|
|
200
|
-
*New in Koffi 2.0*
|
|
201
|
-
|
|
202
263
|
Disposable types allow you to register a function that will automatically called after each C to JS conversion performed by Koffi. This can be used to avoid leaking heap-allocated strings, for example.
|
|
203
264
|
|
|
204
265
|
Some C functions return heap-allocated values directly or through output parameters. While Koffi automatically converts values from C to JS (to a string or an object), it does not know when something needs to be freed, or how.
|
|
@@ -230,7 +291,7 @@ let copy = strdup('Hello!');
|
|
|
230
291
|
console.log(copy); // Prints Hello!
|
|
231
292
|
```
|
|
232
293
|
|
|
233
|
-
When you declare functions with the [prototype-like syntax](
|
|
294
|
+
When you declare functions with the [prototype-like syntax](load#definition-syntax), you can either use named disposable types or use the '!' shortcut qualifier with compatibles types, as shown in the example below. This qualifier creates an anonymous disposable type that calls `koffi.free(ptr)`.
|
|
234
295
|
|
|
235
296
|
```js
|
|
236
297
|
import koffi from 'koffi';
|
|
@@ -252,8 +313,6 @@ Disposable types can only be created from pointer or string types.
|
|
|
252
313
|
|
|
253
314
|
# External buffers (views)
|
|
254
315
|
|
|
255
|
-
*New in Koffi 2.11.0*
|
|
256
|
-
|
|
257
316
|
You can access unmanaged memory with `koffi.view(ptr, len)`. This function takes a pointer and a length, and creates an ArrayBuffer through which you can access the underlying memory without copy.
|
|
258
317
|
|
|
259
318
|
> [!NOTE]
|