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.
Files changed (50) hide show
  1. package/CHANGELOG.md +32 -3
  2. package/cnoke.cjs +2 -2
  3. package/doc/benchmarks.md +1 -1
  4. package/doc/callbacks.md +7 -26
  5. package/doc/{input.md → composites.md} +161 -147
  6. package/doc/contribute.md +3 -2
  7. package/doc/index.md +0 -14
  8. package/doc/{functions.md → load.md} +54 -113
  9. package/doc/migration.md +4 -7
  10. package/doc/misc.md +0 -103
  11. package/doc/output.md +5 -11
  12. package/doc/pointers.md +76 -17
  13. package/doc/primitives.md +151 -0
  14. package/doc/start.md +3 -13
  15. package/doc/types.md +88 -0
  16. package/doc/unions.md +0 -186
  17. package/doc/values.md +134 -0
  18. package/index.d.ts +375 -308
  19. package/lib/native/base/base.cc +66 -24
  20. package/lib/native/base/base.hh +55 -153
  21. package/package.json +16 -16
  22. package/src/koffi/CMakeLists.txt +20 -17
  23. package/src/koffi/index.cjs +30 -111
  24. package/src/koffi/index.js +22 -96
  25. package/src/koffi/indirect.cjs +30 -111
  26. package/src/koffi/indirect.js +24 -24
  27. package/src/koffi/src/abi/arm64.cc +48 -62
  28. package/src/koffi/src/abi/riscv64.cc +39 -57
  29. package/src/koffi/src/abi/x64sysv.cc +39 -57
  30. package/src/koffi/src/abi/x64win.cc +48 -65
  31. package/src/koffi/src/abi/x86.cc +47 -59
  32. package/src/koffi/src/call.cc +426 -209
  33. package/src/koffi/src/call.hh +7 -11
  34. package/src/koffi/src/ffi.cc +534 -303
  35. package/src/koffi/src/ffi.hh +71 -15
  36. package/src/koffi/src/parser.cc +5 -3
  37. package/src/koffi/src/parser.hh +2 -2
  38. package/src/koffi/src/static.cjs +122 -0
  39. package/src/koffi/src/static.js +125 -0
  40. package/src/koffi/src/type.cc +725 -0
  41. package/src/koffi/src/type.hh +71 -0
  42. package/src/koffi/src/util.cc +117 -1202
  43. package/src/koffi/src/util.hh +158 -156
  44. package/src/koffi/src/uv.cc +17 -11
  45. package/src/koffi/src/uv.hh +2 -1
  46. package/vendor/node-addon-api/README.md +1 -1
  47. package/vendor/node-addon-api/napi-inl.h +213 -35
  48. package/vendor/node-addon-api/napi.h +118 -7
  49. package/doc/variables.md +0 -102
  50. 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
- Starting with *Koffi 2.3.20*, you can explicitly unload a library by calling `lib.unload()`. Any attempt to find or call a function from this library after unloading it will crash.
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
- # Function definitions
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
- const printf = lib.func('int printf(const char *fmt, ...)');
63
- const atoi = lib.func('int atoi(str)'); // The parameter name is not used by Koffi, and optional
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
- const printf = lib.func('printf', 'int', ['str', '...']);
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
- printf('Integer %d, double %g, str %s', 'int', 6, 'double', 8.5, 'str', 'THE END');
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 MessageBoxA_1 = lib.func('__stdcall', 'MessageBoxA', 'int', ['void *', 'str', 'str', 'uint']);
115
- const MessageBoxA_2 = lib.func('int __stdcall MessageBoxA(void *hwnd, str text, str caption, uint type)');
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
- - Directly call the function pointer with `koffi.call(ptr, type, ...)`
180
- - Decode the function pointer to an actual function with `koffi.decode(ptr, type)`
156
+ ## Conversion of parameters
181
157
 
182
- The example below shows how to call an `int (*)(int, int)` C function pointer both ways, based on the following native C library:
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
- 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.
160
+ Among other thing, in the the following pages you will learn more about:
205
161
 
206
- ```js
207
- // Declare function type
208
- const BinaryIntFunc = koffi.proto('int BinaryIntFunc(int a, int b)');
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
- const GetBinaryIntFunction = lib.func('BinaryIntFunc *GetBinaryIntFunction(const char *name)');
167
+ # Variables
211
168
 
212
- const add_ptr = GetBinaryIntFunction('add');
213
- const substract_ptr = GetBinaryIntFunction('substract');
169
+ *Changed in Koffi 3.1.0*
214
170
 
215
- let sum = koffi.call(add_ptr, BinaryIntFunc, 4, 5);
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
- console.log(sum, delta); // Prints 9 and 42
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
- // Declare function type
229
- const BinaryIntFunc = koffi.proto('int BinaryIntFunc(int a, int b)');
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
- # Conversion of parameters
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
- Among other thing, in the the following pages you will learn more about:
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
- - How Koffi translates [input parameters](input) to C
249
- - How you can [define and use pointers](pointers)
250
- - How to deal with [output parameters](output)
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) insted of opaque V8 external values.
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](migration#type-specifiers) for more information.
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 type changes
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
- > [!NOTE]
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](input#struct-types) (to/from JS objects)
6
- - [Unions](unions)
7
- - [Opaque types](input#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](variables#decode-to-js-values) for more information about the decode function.
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()](variables#decode-to-js-values) to read data from the pointer when needed.
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, you dynamically-sized arrays are usually passed to functions with pointers, either NULL-terminated (or any other sentinel value) or with an additional length argument.
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
- # Pointer types
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 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.
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
- # Handling void pointers
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
- *New in Koffi 2.1*
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](functions#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)`.
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]