koffi 2.1.0-beta.1 → 2.1.0-beta.2
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/CMakeLists.txt +1 -1
- package/ChangeLog.md +17 -0
- package/build/qemu/2.1.0-beta.2/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.2/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.2/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.2/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.2/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.2/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.2/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.2/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.2/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.2/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.2/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.2/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.2/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.2/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.2/koffi_win32_x64.tar.gz +0 -0
- package/doc/functions.md +67 -1
- package/doc/templates/badges.html +1 -2
- package/doc/types.md +100 -147
- package/package.json +1 -1
- package/src/abi_arm32.cc +166 -2
- package/src/abi_arm64.cc +195 -2
- package/src/abi_riscv64.cc +106 -2
- package/src/abi_x64_sysv.cc +113 -3
- package/src/abi_x64_win.cc +112 -2
- package/src/abi_x86.cc +155 -4
- package/src/call.cc +199 -0
- package/src/ffi.cc +50 -18
- package/src/ffi.hh +12 -0
- package/build/qemu/2.1.0-beta.1/koffi_darwin_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_linux_arm32hf.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_linux_riscv64hf64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_openbsd_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_openbsd_x64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_win32_arm64.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/2.1.0-beta.1/koffi_win32_x64.tar.gz +0 -0
- package/doc/dist/html/.buildinfo +0 -4
- package/doc/dist/html/_sources/benchmarks.md.txt +0 -137
- package/doc/dist/html/_sources/changes.md.txt +0 -161
- package/doc/dist/html/_sources/contribute.md.txt +0 -127
- package/doc/dist/html/_sources/functions.md.txt +0 -355
- package/doc/dist/html/_sources/index.rst.txt +0 -39
- package/doc/dist/html/_sources/memory.md.txt +0 -32
- package/doc/dist/html/_sources/platforms.md.txt +0 -31
- package/doc/dist/html/_sources/start.md.txt +0 -100
- package/doc/dist/html/_sources/types.md.txt +0 -588
- package/doc/dist/html/_static/_sphinx_javascript_frameworks_compat.js +0 -134
- package/doc/dist/html/_static/basic.css +0 -932
- package/doc/dist/html/_static/bench_linux.png +0 -0
- package/doc/dist/html/_static/bench_windows.png +0 -0
- package/doc/dist/html/_static/custom.css +0 -22
- package/doc/dist/html/_static/debug.css +0 -69
- package/doc/dist/html/_static/doctools.js +0 -264
- package/doc/dist/html/_static/documentation_options.js +0 -14
- package/doc/dist/html/_static/file.png +0 -0
- package/doc/dist/html/_static/jquery-3.6.0.js +0 -10881
- package/doc/dist/html/_static/jquery.js +0 -2
- package/doc/dist/html/_static/language_data.js +0 -199
- package/doc/dist/html/_static/minus.png +0 -0
- package/doc/dist/html/_static/perf_linux_20220623.png +0 -0
- package/doc/dist/html/_static/perf_linux_20220623_2.png +0 -0
- package/doc/dist/html/_static/perf_windows_20220623.png +0 -0
- package/doc/dist/html/_static/perf_windows_20220623_2.png +0 -0
- package/doc/dist/html/_static/plus.png +0 -0
- package/doc/dist/html/_static/pygments.css +0 -252
- package/doc/dist/html/_static/scripts/furo-extensions.js +0 -0
- package/doc/dist/html/_static/scripts/furo.js +0 -3
- package/doc/dist/html/_static/scripts/furo.js.LICENSE.txt +0 -7
- package/doc/dist/html/_static/scripts/furo.js.map +0 -1
- package/doc/dist/html/_static/searchtools.js +0 -531
- package/doc/dist/html/_static/skeleton.css +0 -296
- package/doc/dist/html/_static/styles/furo-extensions.css +0 -2
- package/doc/dist/html/_static/styles/furo-extensions.css.map +0 -1
- package/doc/dist/html/_static/styles/furo.css +0 -2
- package/doc/dist/html/_static/styles/furo.css.map +0 -1
- package/doc/dist/html/_static/underscore-1.13.1.js +0 -2042
- package/doc/dist/html/_static/underscore.js +0 -6
- package/doc/dist/html/benchmarks.html +0 -572
- package/doc/dist/html/changes.html +0 -668
- package/doc/dist/html/contribute.html +0 -404
- package/doc/dist/html/functions.html +0 -657
- package/doc/dist/html/genindex.html +0 -254
- package/doc/dist/html/index.html +0 -360
- package/doc/dist/html/memory.html +0 -347
- package/doc/dist/html/objects.inv +0 -0
- package/doc/dist/html/platforms.html +0 -372
- package/doc/dist/html/search.html +0 -262
- package/doc/dist/html/searchindex.js +0 -1
- package/doc/dist/html/start.html +0 -385
- package/doc/dist/html/types.html +0 -1097
package/CMakeLists.txt
CHANGED
|
@@ -31,7 +31,7 @@ if(MSVC)
|
|
|
31
31
|
enable_language(ASM_MASM)
|
|
32
32
|
endif()
|
|
33
33
|
else()
|
|
34
|
-
add_compile_options(-Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter)
|
|
34
|
+
add_compile_options(-Wall -Wextra -Wno-missing-field-initializers -Wno-unused-parameter -Wswitch -Werror=switch)
|
|
35
35
|
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
|
36
36
|
add_compile_options(-Wno-unknown-warning-option)
|
|
37
37
|
endif()
|
package/ChangeLog.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
## History
|
|
4
4
|
|
|
5
|
+
### Koffi 2.1.0 (in beta)
|
|
6
|
+
|
|
7
|
+
**Main changes:**
|
|
8
|
+
|
|
9
|
+
- Add [koffi.as()](functions.md#polymorphic-parameters) to support polymorphic APIs based on `void *` parameters
|
|
10
|
+
- Add [endian-sensitive integer types](types.md#endian-sensitive-types): `intX_le_t`, `intX_be_t`
|
|
11
|
+
- Accept typed arrays for `void *` parameters
|
|
12
|
+
- Introduce `koffi.opaque()` to replace `koffi.handle()` (which remains supported until Koffi 3.0)
|
|
13
|
+
|
|
14
|
+
**Other changes:**
|
|
15
|
+
|
|
16
|
+
- Improve global performance with inlining and unity builds
|
|
17
|
+
- Add `size_t` primitive type
|
|
18
|
+
- Support member-specific alignement value in structs
|
|
19
|
+
- Detect impossible parameters and return types (such as non-pointer opaque types)
|
|
20
|
+
- Various documentation fixes and improvements
|
|
21
|
+
|
|
5
22
|
### Koffi 2.0.1
|
|
6
23
|
|
|
7
24
|
**Main changes:**
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/doc/functions.md
CHANGED
|
@@ -105,7 +105,7 @@ printf('Integer %d, double %g, str %s', 'int', 6, 'double', 8.5, 'str', 'THE END
|
|
|
105
105
|
|
|
106
106
|
On x86 platforms, only the Cdecl convention can be used for variadic functions.
|
|
107
107
|
|
|
108
|
-
##
|
|
108
|
+
## Special considerations
|
|
109
109
|
|
|
110
110
|
### Output parameters
|
|
111
111
|
|
|
@@ -177,8 +177,72 @@ let db = out[0];
|
|
|
177
177
|
sqlite3_close_v2(db);
|
|
178
178
|
```
|
|
179
179
|
|
|
180
|
+
### Polymorphic parameters
|
|
181
|
+
|
|
182
|
+
*New in Koffi 2.1*
|
|
183
|
+
|
|
184
|
+
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.
|
|
185
|
+
|
|
186
|
+
Koffi provides two features to deal with this:
|
|
187
|
+
|
|
188
|
+
- Typed JS arrays can be used as values in place everywhere `void *` is expected. See [dynamic arrays](types.md#array-pointers-dynamic-arrays) for more information, for input or output.
|
|
189
|
+
- You can use `koffi.as(value, type)` to tell Koffi what kind of type is actually expected.
|
|
190
|
+
|
|
191
|
+
The example below shows the use of `koffi.as()` to read the header of a PNG file with `fread()`.
|
|
192
|
+
|
|
193
|
+
```js
|
|
194
|
+
const koffi = require('koffi');
|
|
195
|
+
const lib = koffi.load('libc.so.6');
|
|
196
|
+
|
|
197
|
+
const FILE = koffi.opaque('FILE');
|
|
198
|
+
|
|
199
|
+
const PngHeader = koffi.pack('PngHeader', {
|
|
200
|
+
signature: koffi.array('uint8_t', 8),
|
|
201
|
+
ihdr: koffi.pack({
|
|
202
|
+
length: 'uint32_be_t',
|
|
203
|
+
chunk: koffi.array('char', 4),
|
|
204
|
+
width: 'uint32_be_t',
|
|
205
|
+
height: 'uint32_be_t',
|
|
206
|
+
depth: 'uint8_t',
|
|
207
|
+
color: 'uint8_t',
|
|
208
|
+
compression: 'uint8_t',
|
|
209
|
+
filter: 'uint8_t',
|
|
210
|
+
interlace: 'uint8_t',
|
|
211
|
+
crc: 'uint32_be_t'
|
|
212
|
+
})
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const fopen = lib.func('FILE *fopen(const char *path, const char *mode)');
|
|
216
|
+
const fclose = lib.func('int fclose(FILE *fp)');
|
|
217
|
+
const fread = lib.func('size_t fread(_Out_ void *ptr, size_t size, size_t nmemb, FILE *fp)');
|
|
218
|
+
|
|
219
|
+
let filename = process.argv[2];
|
|
220
|
+
if (filename == null)
|
|
221
|
+
throw new Error('Usage: node png.js <image.png>');
|
|
222
|
+
|
|
223
|
+
let hdr = {};
|
|
224
|
+
{
|
|
225
|
+
|
|
226
|
+
let fp = fopen(filename, 'rb');
|
|
227
|
+
if (!fp)
|
|
228
|
+
throw new Error(`Failed to open '${filename}'`);
|
|
229
|
+
|
|
230
|
+
try {
|
|
231
|
+
let len = fread(koffi.as(hdr, 'PngHeader *'), 1, koffi.sizeof(PngHeader), fp);
|
|
232
|
+
if (len < koffi.sizeof(PngHeader))
|
|
233
|
+
throw new Error('Failed to read PNG header');
|
|
234
|
+
} finally {
|
|
235
|
+
fclose(fp);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
console.log('PNG header:', hdr);
|
|
240
|
+
```
|
|
241
|
+
|
|
180
242
|
### Heap-allocated values
|
|
181
243
|
|
|
244
|
+
*New in Koffi 2.0*
|
|
245
|
+
|
|
182
246
|
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.
|
|
183
247
|
|
|
184
248
|
For opaque types, such as FILE, this does not matter because you will explicitly call `fclose()` on them. But some values (such as strings) get implicitly converted by Koffi, and you lose access to the original pointer. This creates a leak if the string is heap-allocated.
|
|
@@ -299,6 +363,8 @@ console.log(ret);
|
|
|
299
363
|
|
|
300
364
|
### Registered callbacks
|
|
301
365
|
|
|
366
|
+
*New in Koffi 2.0*
|
|
367
|
+
|
|
302
368
|
Use registered callbacks when the function needs to be called at a later time (e.g. log handler, event handler, `fopencookie/funopen`). Call `koffi.register(func, type)` to register a callback function, with two arguments: the JS function, and the callback type.
|
|
303
369
|
|
|
304
370
|
When you are done, call `koffi.unregister()` (with the value returned by `koffi.register()`) to release the slot. A maximum of 16 registered callbacks can exist at the same time. Failure to do so will leak the slot, and subsequent registrations may fail (with an exception) once all slots are used.
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
<div style="text-align: center; margin-top: 2em;">
|
|
2
|
-
<a href="https://www.npmjs.com/package/koffi"><img src="https://img.shields.io/badge/NPM-
|
|
2
|
+
<a href="https://www.npmjs.com/package/koffi"><img src="https://img.shields.io/badge/NPM-Koffi-brightgreen" alt="NPM"/></a>
|
|
3
3
|
<a href="https://github.com/Koromix/luigi/tree/master/koffi"><img src="https://img.shields.io/badge/GitHub-Koffi-ff6600" alt="GitHub"/></a>
|
|
4
4
|
</div>
|
|
5
|
-
|
package/doc/types.md
CHANGED
|
@@ -2,45 +2,34 @@
|
|
|
2
2
|
|
|
3
3
|
## Primitive types
|
|
4
4
|
|
|
5
|
+
### Standard types
|
|
6
|
+
|
|
5
7
|
While the C standard allows for variation in the size of most integer types, Koffi enforces the same definition for most primitive types, listed below:
|
|
6
8
|
|
|
7
|
-
JS type
|
|
8
|
-
|
|
9
|
-
Undefined
|
|
10
|
-
Number (integer)
|
|
11
|
-
Number (integer)
|
|
12
|
-
Number (integer)
|
|
13
|
-
Number (integer)
|
|
14
|
-
Number (integer)
|
|
15
|
-
Number (integer)
|
|
16
|
-
Number (integer)
|
|
17
|
-
Number (integer)
|
|
18
|
-
Number (integer)
|
|
19
|
-
Number (integer)
|
|
20
|
-
Number (integer)
|
|
21
|
-
Number (integer)
|
|
22
|
-
Number (integer)
|
|
23
|
-
Number (integer)
|
|
24
|
-
Number (integer)
|
|
25
|
-
Number (integer)
|
|
26
|
-
Number (integer)
|
|
27
|
-
Number (
|
|
28
|
-
Number (
|
|
29
|
-
Number (
|
|
30
|
-
Number (
|
|
31
|
-
Number (integer) | unsigned int | 4 | Unsigned |
|
|
32
|
-
Number (integer) | int64 | 8 | Signed |
|
|
33
|
-
Number (integer) | int64_t | 8 | Signed |
|
|
34
|
-
Number (integer) | uint64 | 8 | Unsigned |
|
|
35
|
-
Number (integer) | uint64_t | 8 | Unsigned |
|
|
36
|
-
Number (integer) | longlong | 8 | Signed |
|
|
37
|
-
Number (integer) | long long | 8 | Signed |
|
|
38
|
-
Number (integer) | ulonglong | 8 | Unsigned |
|
|
39
|
-
Number (integer) | unsigned long long | 8 | Unsigned |
|
|
40
|
-
Number (float) | float32 | 4 | |
|
|
41
|
-
Number (float) | float64 | 8 | |
|
|
42
|
-
Number (float) | float | 4 | |
|
|
43
|
-
Number (float) | double | 8 | |
|
|
9
|
+
JS type | C type | Bytes | Signedness | Note
|
|
10
|
+
---------------- | ----------------------------- | ----- | ---------- | ---------------------------
|
|
11
|
+
Undefined | void | 0 | | Only valid as a return type
|
|
12
|
+
Number (integer) | int8, int8_t | 1 | Signed |
|
|
13
|
+
Number (integer) | uint8, uint8_t | 1 | Unsigned |
|
|
14
|
+
Number (integer) | char | 1 | Signed |
|
|
15
|
+
Number (integer) | uchar, unsigned char | 1 | Unsigned |
|
|
16
|
+
Number (integer) | char16, char16_t | 2 | Signed |
|
|
17
|
+
Number (integer) | int16, int16_t | 2 | Signed |
|
|
18
|
+
Number (integer) | uint16, uint16_t | 2 | Unsigned |
|
|
19
|
+
Number (integer) | short | 2 | Signed |
|
|
20
|
+
Number (integer) | ushort, unsigned short | 2 | Unsigned |
|
|
21
|
+
Number (integer) | int32, int32_t | 4 | Signed |
|
|
22
|
+
Number (integer) | uint32, uint32_t | 4 | Unsigned |
|
|
23
|
+
Number (integer) | int | 4 | Signed |
|
|
24
|
+
Number (integer) | uint, unsigned int | 4 | Unsigned |
|
|
25
|
+
Number (integer) | int64, int64_t | 8 | Signed |
|
|
26
|
+
Number (integer) | uint64, uint64_t | 8 | Unsigned |
|
|
27
|
+
Number (integer) | longlong, long long | 8 | Signed |
|
|
28
|
+
Number (integer) | ulonglong, unsigned long long | 8 | Unsigned |
|
|
29
|
+
Number (float) | float32 | 4 | |
|
|
30
|
+
Number (float) | float64 | 8 | |
|
|
31
|
+
Number (float) | float | 4 | |
|
|
32
|
+
Number (float) | double | 8 | |
|
|
44
33
|
|
|
45
34
|
Koffi also accepts BigInt values when converting from JS to C integers. If the value exceeds the range of the C type, Koffi will convert the number to an undefined value. In the reverse direction, BigInt values are automatically used when needed for big 64-bit integers.
|
|
46
35
|
|
|
@@ -56,8 +45,8 @@ Number (integer) | intptr | Signed | 4 or 8 bytes depending on reg
|
|
|
56
45
|
Number (integer) | intptr_t | Signed | 4 or 8 bytes depending on register width
|
|
57
46
|
Number (integer) | uintptr | Unsigned | 4 or 8 bytes depending on register width
|
|
58
47
|
Number (integer) | uintptr_t | Unsigned | 4 or 8 bytes depending on register width
|
|
59
|
-
String | str
|
|
60
|
-
String | str16
|
|
48
|
+
String | str, string | | JS strings are converted to and from UTF-8
|
|
49
|
+
String | str16, string16 | | JS strings are converted to and from UTF-16 (LE)
|
|
61
50
|
|
|
62
51
|
Primitive types can be specified by name (in a string) or through `koffi.types`:
|
|
63
52
|
|
|
@@ -67,6 +56,25 @@ let struct1 = koffi.struct({ dummy: 'long' });
|
|
|
67
56
|
let struct2 = koffi.struct({ dummy: koffi.types.long });
|
|
68
57
|
```
|
|
69
58
|
|
|
59
|
+
### Endian-sensitive types
|
|
60
|
+
|
|
61
|
+
Koffi defines a bunch of endian-sensitive types, which can be used when dealing with binary data (network payloads, binary file formats, etc.).
|
|
62
|
+
|
|
63
|
+
JS type | C type | Bytes | Signedness | Endianness
|
|
64
|
+
---------------- | ---------------------- | ----- | ---------- | -------------
|
|
65
|
+
Number (integer) | int16_le, int16_le_t | 2 | Signed | Little Endian
|
|
66
|
+
Number (integer) | int16_be, int16_be_t | 2 | Signed | Big Endian
|
|
67
|
+
Number (integer) | uint16_le, uint16_le_t | 2 | Unsigned | Little Endian
|
|
68
|
+
Number (integer) | uint16_be, uint16_be_t | 2 | Unsigned | Big Endian
|
|
69
|
+
Number (integer) | int32_le, int32_le_t | 4 | Signed | Little Endian
|
|
70
|
+
Number (integer) | int32_be, int32_be_t | 4 | Signed | Big Endian
|
|
71
|
+
Number (integer) | uint32_le, uint32_le_t | 4 | Unsigned | Little Endian
|
|
72
|
+
Number (integer) | uint32_be, uint32_be_t | 4 | Unsigned | Big Endian
|
|
73
|
+
Number (integer) | int64_le, int64_le_t | 8 | Signed | Little Endian
|
|
74
|
+
Number (integer) | int64_be, int64_be_t | 8 | Signed | Big Endian
|
|
75
|
+
Number (integer) | uint64_le, uint64_le_t | 8 | Unsigned | Little Endian
|
|
76
|
+
Number (integer) | uint64_be, uint64_be_t | 8 | Unsigned | Big Endian
|
|
77
|
+
|
|
70
78
|
## Struct types
|
|
71
79
|
|
|
72
80
|
### Struct definition
|
|
@@ -328,8 +336,8 @@ In C, pointer arguments are used for differenty purposes. It is important to dis
|
|
|
328
336
|
|
|
329
337
|
- **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).
|
|
330
338
|
- **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.
|
|
331
|
-
- **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.
|
|
332
339
|
- **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.
|
|
340
|
+
- **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.
|
|
333
341
|
|
|
334
342
|
### Struct pointers
|
|
335
343
|
|
|
@@ -357,6 +365,8 @@ console.log(pos);
|
|
|
357
365
|
|
|
358
366
|
### Named pointer types
|
|
359
367
|
|
|
368
|
+
*New in Koffi 2.0*
|
|
369
|
+
|
|
360
370
|
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:
|
|
361
371
|
|
|
362
372
|
```js
|
|
@@ -367,111 +377,6 @@ const GetHandleInformation = lib.func('bool __stdcall GetHandleInformation(HANDL
|
|
|
367
377
|
const CloseHandle = lib.func('bool __stdcall CloseHandle(HANDLE h)');
|
|
368
378
|
```
|
|
369
379
|
|
|
370
|
-
### Array pointers
|
|
371
|
-
|
|
372
|
-
In C, dynamically-sized arrays are usually passed around as pointers. The length is either passed as an additional argument, or inferred from the array content itself, for example with a terminating sentinel value (such as a NULL pointers in the case of an array of strings).
|
|
373
|
-
|
|
374
|
-
Koffi can translate JS arrays and TypedArrays to pointer arguments. However, because C does not have a proper notion of dynamically-sized arrays (fat pointers), you need to provide the length or the sentinel value yourself depending on the API.
|
|
375
|
-
|
|
376
|
-
Here is a simple example of a C function taking a NULL-terminated list of strings as input, to calculate the total length of all strings.
|
|
377
|
-
|
|
378
|
-
```c
|
|
379
|
-
// Build with: clang -fPIC -o length.so -shared length.c -Wall -O2
|
|
380
|
-
|
|
381
|
-
#include <stdlib.h>
|
|
382
|
-
#include <stdint.h>
|
|
383
|
-
#include <string.h>
|
|
384
|
-
|
|
385
|
-
int64_t ComputeTotalLength(const char **strings)
|
|
386
|
-
{
|
|
387
|
-
int64_t total = 0;
|
|
388
|
-
|
|
389
|
-
for (const char **ptr = strings; *ptr; ptr++) {
|
|
390
|
-
const char *str = *ptr;
|
|
391
|
-
total += strlen(str);
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
return total;
|
|
395
|
-
}
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
```js
|
|
399
|
-
const koffi = require('koffi');
|
|
400
|
-
const lib = koffi.load('./length.so');
|
|
401
|
-
|
|
402
|
-
const ComputeTotalLength = lib.func('int64_t ComputeTotalLength(const char **strings)');
|
|
403
|
-
|
|
404
|
-
let strings = ['Get', 'Total', 'Length', null];
|
|
405
|
-
let total = ComputeTotalLength(strings);
|
|
406
|
-
|
|
407
|
-
console.log(total); // Prints 14
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
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](functions.md#output-parameters).
|
|
411
|
-
|
|
412
|
-
Here is an example based on the Win32 API, listing files in the current directory with `FindFirstFileW()` and `FindNextFileW()`:
|
|
413
|
-
|
|
414
|
-
```js
|
|
415
|
-
const koffi = require('koffi');
|
|
416
|
-
const lib = koffi.load('kernel32.dll');
|
|
417
|
-
|
|
418
|
-
const HANDLE = koffi.pointer('HANDLE', koffi.opaque());
|
|
419
|
-
const FILETIME = koffi.struct('FILETIME', {
|
|
420
|
-
dwLowDateTime: 'uint',
|
|
421
|
-
dwHighDateTime: 'uint'
|
|
422
|
-
});
|
|
423
|
-
const WIN32_FIND_DATA = koffi.struct('WIN32_FIND_DATA', {
|
|
424
|
-
dwFileAttributes: 'uint',
|
|
425
|
-
ftCreationTime: FILETIME,
|
|
426
|
-
ftLastAccessTime: FILETIME,
|
|
427
|
-
ftLastWriteTime: FILETIME,
|
|
428
|
-
nFileSizeHigh: 'uint',
|
|
429
|
-
nFileSizeLow: 'uint',
|
|
430
|
-
dwReserved0: 'uint',
|
|
431
|
-
dwReserved1: 'uint',
|
|
432
|
-
cFileName: koffi.array('char16', 260),
|
|
433
|
-
cAlternateFileName: koffi.array('char16', 14),
|
|
434
|
-
dwFileType: 'uint', // Obsolete. Do not use.
|
|
435
|
-
dwCreatorType: 'uint', // Obsolete. Do not use
|
|
436
|
-
wFinderFlags: 'ushort' // Obsolete. Do not use
|
|
437
|
-
});
|
|
438
|
-
|
|
439
|
-
const FindFirstFile = lib.func('HANDLE __stdcall FindFirstFileW(str16 path, _Out_ WIN32_FIND_DATA *data)');
|
|
440
|
-
const FindNextFile = lib.func('bool __stdcall FindNextFileW(HANDLE h, _Out_ WIN32_FIND_DATA *data)');
|
|
441
|
-
const FindClose = lib.func('bool __stdcall FindClose(HANDLE h)');
|
|
442
|
-
const GetLastError = lib.func('uint GetLastError()');
|
|
443
|
-
|
|
444
|
-
function list(dirname) {
|
|
445
|
-
let filenames = [];
|
|
446
|
-
|
|
447
|
-
let data = {};
|
|
448
|
-
let h = FindFirstFile(dirname + '\\*', data);
|
|
449
|
-
|
|
450
|
-
if (!h) {
|
|
451
|
-
if (GetLastError() == 2) // ERROR_FILE_NOT_FOUND
|
|
452
|
-
return filenames;
|
|
453
|
-
throw new Error('FindFirstFile() failed');
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
try {
|
|
457
|
-
do {
|
|
458
|
-
if (data.cFileName != '.' && data.cFileName != '..')
|
|
459
|
-
filenames.push(data.cFileName);
|
|
460
|
-
} while (FindNextFile(h, data));
|
|
461
|
-
|
|
462
|
-
if (GetLastError() != 18) // ERROR_NO_MORE_FILES
|
|
463
|
-
throw new Error('FindNextFile() failed');
|
|
464
|
-
} finally {
|
|
465
|
-
FindClose(h);
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
return filenames;
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
let filenames = list('.');
|
|
472
|
-
console.log(filenames);
|
|
473
|
-
```
|
|
474
|
-
|
|
475
380
|
### Pointers to primitive types
|
|
476
381
|
|
|
477
382
|
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.
|
|
@@ -509,7 +414,9 @@ AddInt(sum, 6);
|
|
|
509
414
|
console.log(sum[0]); // Prints 42
|
|
510
415
|
```
|
|
511
416
|
|
|
512
|
-
##
|
|
417
|
+
## Array types
|
|
418
|
+
|
|
419
|
+
### Fixed-size C arrays
|
|
513
420
|
|
|
514
421
|
Fixed-size arrays are declared with `koffi.array(type, length)`. Just like in C, they cannot be passed as functions parameters (they degenerate to pointers), or returned by value. You can however embed them in struct types.
|
|
515
422
|
|
|
@@ -541,7 +448,7 @@ console.log(ReturnFoo1({ i: 5, a16: [6, 8] })) // Prints { i: 5, a16: Int16Array
|
|
|
541
448
|
console.log(ReturnFoo2({ i: 5, a16: [6, 8] })) // Prints { i: 5, a16: [6, 8] }
|
|
542
449
|
```
|
|
543
450
|
|
|
544
|
-
###
|
|
451
|
+
### Fixed-size string buffers
|
|
545
452
|
|
|
546
453
|
Koffi can also convert JS strings to fixed-sized arrays in the following cases:
|
|
547
454
|
|
|
@@ -550,6 +457,48 @@ Koffi can also convert JS strings to fixed-sized arrays in the following cases:
|
|
|
550
457
|
|
|
551
458
|
The reverse case is also true, Koffi can convert a C fixed-size buffer to a JS string. This happens by default for char, char16 and char16_t arrays, but you can also explicitly ask for this with the `string` array hint (e.g. `koffi.array('char', 8, 'string')`).
|
|
552
459
|
|
|
460
|
+
### Array pointers (dynamic arrays)
|
|
461
|
+
|
|
462
|
+
In C, dynamically-sized arrays are usually passed around as pointers. The length is either passed as an additional argument, or inferred from the array content itself, for example with a terminating sentinel value (such as a NULL pointers in the case of an array of strings).
|
|
463
|
+
|
|
464
|
+
Koffi can translate JS arrays and TypedArrays to pointer arguments. However, because C does not have a proper notion of dynamically-sized arrays (fat pointers), you need to provide the length or the sentinel value yourself depending on the API.
|
|
465
|
+
|
|
466
|
+
Here is a simple example of a C function taking a NULL-terminated list of strings as input, to calculate the total length of all strings.
|
|
467
|
+
|
|
468
|
+
```c
|
|
469
|
+
// Build with: clang -fPIC -o length.so -shared length.c -Wall -O2
|
|
470
|
+
|
|
471
|
+
#include <stdlib.h>
|
|
472
|
+
#include <stdint.h>
|
|
473
|
+
#include <string.h>
|
|
474
|
+
|
|
475
|
+
int64_t ComputeTotalLength(const char **strings)
|
|
476
|
+
{
|
|
477
|
+
int64_t total = 0;
|
|
478
|
+
|
|
479
|
+
for (const char **ptr = strings; *ptr; ptr++) {
|
|
480
|
+
const char *str = *ptr;
|
|
481
|
+
total += strlen(str);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
return total;
|
|
485
|
+
}
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
```js
|
|
489
|
+
const koffi = require('koffi');
|
|
490
|
+
const lib = koffi.load('./length.so');
|
|
491
|
+
|
|
492
|
+
const ComputeTotalLength = lib.func('int64_t ComputeTotalLength(const char **strings)');
|
|
493
|
+
|
|
494
|
+
let strings = ['Get', 'Total', 'Length', null];
|
|
495
|
+
let total = ComputeTotalLength(strings);
|
|
496
|
+
|
|
497
|
+
console.log(total); // Prints 14
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
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](functions.md#output-parameters).
|
|
501
|
+
|
|
553
502
|
## Disposable types
|
|
554
503
|
|
|
555
504
|
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.
|
|
@@ -560,6 +509,8 @@ Read the documentation for [disposable types](functions.md#heap-allocated-values
|
|
|
560
509
|
|
|
561
510
|
### Type introspection
|
|
562
511
|
|
|
512
|
+
*New in Koffi 2.0: `koffi.resolve()`*
|
|
513
|
+
|
|
563
514
|
Koffi exposes three functions to explore type information:
|
|
564
515
|
|
|
565
516
|
- `koffi.sizeof(type)` to get the size of a type
|
|
@@ -585,4 +536,6 @@ console.log(koffi.sizeof(koffi.types.long));
|
|
|
585
536
|
|
|
586
537
|
### Type aliases
|
|
587
538
|
|
|
539
|
+
*New in Koffi 2.0*
|
|
540
|
+
|
|
588
541
|
You can alias a type with `koffi.alias(name, type)`. Aliased types are completely equivalent.
|