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
@@ -0,0 +1,151 @@
1
+ # Number types
2
+
3
+ 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:
4
+
5
+ C type | JS type | Bytes | Signedness | Note
6
+ ----------------------------- | ---------------- | ----- | ---------- | ---------------------------
7
+ void | Undefined | 0 | | Only valid as a return type
8
+ int8, int8_t | Number (integer) | 1 | Signed |
9
+ uint8, uint8_t | Number (integer) | 1 | Unsigned |
10
+ char | Number (integer) | 1 | Signed |
11
+ uchar, unsigned char | Number (integer) | 1 | Unsigned |
12
+ char16, char16_t | Number (integer) | 2 | Signed |
13
+ int16, int16_t | Number (integer) | 2 | Signed |
14
+ uint16, uint16_t | Number (integer) | 2 | Unsigned |
15
+ short | Number (integer) | 2 | Signed |
16
+ ushort, unsigned short | Number (integer) | 2 | Unsigned |
17
+ char32, char32_t | Number (integer) | 4 | Signed |
18
+ int32, int32_t | Number (integer) | 4 | Signed |
19
+ uint32, uint32_t | Number (integer) | 4 | Unsigned |
20
+ int | Number (integer) | 4 | Signed |
21
+ uint, unsigned int | Number (integer) | 4 | Unsigned |
22
+ int64, int64_t | Number (integer) | 8 | Signed |
23
+ uint64, uint64_t | Number (integer) | 8 | Unsigned |
24
+ longlong, long long | Number (integer) | 8 | Signed |
25
+ ulonglong, unsigned long long | Number (integer) | 8 | Unsigned |
26
+ float32 | Number (float) | 4 | |
27
+ float64 | Number (float) | 8 | |
28
+ float | Number (float) | 4 | |
29
+ double | Number (float) | 8 | |
30
+
31
+ 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.
32
+
33
+ Koffi defines a few more types that can change size depending on the OS and the architecture:
34
+
35
+ C type | JS type | Signedness | Note
36
+ ---------------- | ---------------- | ----------- | ------------------------------------------------
37
+ bool | Boolean | | Usually one byte
38
+ long | Number (integer) | Signed | 4 or 8 bytes depending on platform (LP64, LLP64)
39
+ ulong | Number (integer) | Unsigned | 4 or 8 bytes depending on platform (LP64, LLP64)
40
+ unsigned long | Number (integer) | Unsigned | 4 or 8 bytes depending on platform (LP64, LLP64)
41
+ intptr | Number (integer) | Signed | 4 or 8 bytes depending on register width
42
+ intptr_t | Number (integer) | Signed | 4 or 8 bytes depending on register width
43
+ uintptr | Number (integer) | Unsigned | 4 or 8 bytes depending on register width
44
+ uintptr_t | Number (integer) | Unsigned | 4 or 8 bytes depending on register width
45
+ wchar_t | Number (integer) | | 2 bytes on Windows, 4 bytes Linux, macOS and BSD
46
+
47
+ Primitive types can be specified by name (in a string) or through `koffi.types`:
48
+
49
+ ```js
50
+ // These two lines do the same:
51
+ let struct1 = koffi.struct({ dummy: 'long' });
52
+ let struct2 = koffi.struct({ dummy: koffi.types.long });
53
+ ```
54
+
55
+ # String types
56
+
57
+ Koffi can convert JS strings to and from UTF-8, UTF-16 or UTF-32.
58
+
59
+ Type name | Aliases | JS type | Conversion / encoding
60
+ ------------------------------ | --------------- | ------- | ---------------------
61
+ const char \*, char \* | str, string | String | UTF-8
62
+ const char16_t \*, char16_t \* | str16, string16 | String | UTF-16
63
+ const char32_t \*, char32_t \* | str32, string32 | String | UTF-32
64
+
65
+ Koffi also supports wide strings (`wchar_t *` or `wstring`), which use:
66
+
67
+ - UTF-16 on Windows (where wchar_t is 2 bytes)
68
+ - UTF-32 on other platforms (where wchar_t is 4 bytes)
69
+
70
+ # Enum types
71
+
72
+ *New in Koffi 3.0*
73
+
74
+ C enumeration values are stored as integers. The underlying integer type is implementation-defined but Koffi tries to match usual platform behavior.
75
+
76
+ On POSIX platforms, Koffi follows the following rules:
77
+
78
+ - If no negative value exists: `unsigned int` by default, `uint64_t` if needed
79
+ - If any negative value exists: `int` by default, `int64_t` if needed
80
+
81
+ On Windows, things are simpler, and `int` is used all the time. Koffi will throw an error if any enumeration value does not fit in a 32-bit integer.
82
+
83
+ ```js
84
+ // For OpenResult, the underlying type will be unsigned int on POSIX, int on Windows
85
+ const OpenResult = koffi.enumeration('OpenResult', {
86
+ Success: 0,
87
+ MissingFile: 1,
88
+ AccessDenied: 2,
89
+ OtherError: 3
90
+ });
91
+
92
+ // For RelativePosition, the underlying type will be int everywhere
93
+ const RelativePosition = koffi.enumeration('RelativePosition', {
94
+ Left: -1,
95
+ Center: 0,
96
+ Right: 1
97
+ });
98
+
99
+ // For IntLimits, the underlying type will be int64_t on POSIX, and fail on Windows
100
+ const Int64Limits = koffi.enumeration('Int64Limits', {
101
+ Min: -9223372036854775808n,
102
+ Max: 9223372036854775807n
103
+ });
104
+ ```
105
+
106
+ > [!WARNING]
107
+ > This behavior may not match your compiler:
108
+ >
109
+ > - On POSIX platforms, GCC and Clang will use a short integer type if `-fshort-enums` is specified and the enumeration values fit in `short` or `unsigned short`.
110
+ > - On Windows, MSVC (and Clang) always use `int` even if some values do not fit, which matches what Koffi does... unless the compiler flag `/Zc:enumTypes` is set, maybe.
111
+ >
112
+ > Use an explicit type specifier to work around these problems, as shown below.
113
+
114
+ You can access the constants in `values` member of the type object.
115
+
116
+ ```js
117
+ console.log(OpenResult.values.MissingFile); // Prints 1
118
+ console.log(RelativePosition.values.Left); // Prints -1
119
+ ```
120
+
121
+ You can specify the storage type explicitly as the last argument: `koffi.enumeration(name, values, type)`.
122
+
123
+ ```js
124
+ // This one explictly uses int64_t as the underlying type, despite the fact that the values fit inside an int.
125
+ const ExplicitEnum = koffi.enumeration('ExplicitEnum', {
126
+ Zero: 0,
127
+ One: 1,
128
+ Two: 2
129
+ }, 'int64_t');
130
+ ```
131
+
132
+ # Endian-sensitive integers
133
+
134
+ Koffi defines a bunch of endian-sensitive types, which can be used when dealing with binary data (network payloads, binary file formats, etc.).
135
+
136
+ C type | Bytes | Signedness | Endianness
137
+ ---------------------- | ----- | ---------- | -------------
138
+ int16_le, int16_le_t | 2 | Signed | Little Endian
139
+ int16_be, int16_be_t | 2 | Signed | Big Endian
140
+ uint16_le, uint16_le_t | 2 | Unsigned | Little Endian
141
+ uint16_be, uint16_be_t | 2 | Unsigned | Big Endian
142
+ int32_le, int32_le_t | 4 | Signed | Little Endian
143
+ int32_be, int32_be_t | 4 | Signed | Big Endian
144
+ uint32_le, uint32_le_t | 4 | Unsigned | Little Endian
145
+ uint32_be, uint32_be_t | 4 | Unsigned | Big Endian
146
+ int64_le, int64_le_t | 8 | Signed | Little Endian
147
+ int64_be, int64_be_t | 8 | Signed | Big Endian
148
+ uint64_le, uint64_le_t | 8 | Unsigned | Little Endian
149
+ uint64_be, uint64_be_t | 8 | Unsigned | Big Endian
150
+
151
+ You can find an example that uses these types to [extract information from a PNG header](pointers#handling-void-pointers) with transparent endian conversion.
package/doc/start.md CHANGED
@@ -16,6 +16,9 @@ import koffi from 'koffi';
16
16
  const koffi = require('koffi');
17
17
  ```
18
18
 
19
+ > [!NOTE]
20
+ > Follow the [build instructions](contribute#build-from-source) if you want to build the native Koffi code yourself, to fix something or simply to study the code.
21
+
19
22
  # Simple examples
20
23
 
21
24
  Below you can find two examples:
@@ -105,16 +108,3 @@ let ret = MessageBoxA(null, 'Do you want another message box?', 'Koffi', MB_YESN
105
108
  if (ret == IDYES)
106
109
  MessageBoxW(null, 'Hello World!', 'Koffi', MB_ICONINFORMATION);
107
110
  ```
108
-
109
- # Bundling Koffi
110
-
111
- Please read the [dedicated page](packaging) for information about bundling and packaging applications using Koffi.
112
-
113
- # Build manually
114
-
115
- Follow the [build instructions](contribute#build-from-source) if you want to build the native Koffi code yourself.
116
-
117
- > [!NOTE]
118
- > This is only needed if you want to hack on Koffi. The official NPM package provides prebuilt binaries and you don't need to compile anything if you only want to use Koffi in Node.js.
119
- >
120
- > Just run `npm install koffi`!
package/doc/types.md ADDED
@@ -0,0 +1,88 @@
1
+ # Type specifiers
2
+
3
+ *Changed in Koffi 3.0*
4
+
5
+ > [!NOTE]
6
+ > 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.
7
+ >
8
+ > Consult the [migration guide](migration) for more information.
9
+
10
+ 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.
11
+
12
+ 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).
13
+
14
+ ```js
15
+ const FoobarType = koffi.struct('FoobarType', {
16
+ a: 'int',
17
+ b: 'char *',
18
+ c: 'double'
19
+ });
20
+
21
+ console.log(FoobarType);
22
+
23
+ // Expected result on 64-bit machines:
24
+ // {
25
+ // name: 'FoobarType',
26
+ // primitive: 'Record',
27
+ // size: 24,
28
+ // alignment: 8,
29
+ // disposable: false,
30
+ // members: {
31
+ // a: { name: 'a', type: [Type], offset: 0 },
32
+ // b: { name: 'b', type: [Type], offset: 8 },
33
+ // c: { name: 'c', type: [Type], offset: 16 }
34
+ // }
35
+ // }
36
+ ```
37
+
38
+ Koffi also exposes a few more utility functions to get a subset of this information:
39
+
40
+ - `koffi.sizeof(type)` to get the size of a type
41
+ - `koffi.alignof(type)` to get the alignment of a type
42
+ - `koffi.offsetof(type, member_name)` to get the offset of a record member
43
+ - `koffi.type(type)` to get the resolved type object from a type string
44
+
45
+ Just like before, you can refer to primitive types by their name or through `koffi.types`:
46
+
47
+ ```js
48
+ // These two lines do the same:
49
+ console.log(koffi.sizeof('long'));
50
+ console.log(koffi.sizeof(koffi.types.long));
51
+ ```
52
+
53
+ # Aliases
54
+
55
+ You can alias a type with `koffi.alias(name, type)`. Aliased types are completely equivalent.
56
+
57
+ # Circular references
58
+
59
+ 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.
60
+
61
+ To deal with this, you can create an opaque type and redefine it later to a concrete struct or union type, as shown below.
62
+
63
+ ```js
64
+ const Type1 = koffi.opaque('Type1');
65
+
66
+ const Type2 = koffi.struct('Type2', {
67
+ ptr: 'Type1 *',
68
+ i: 'int'
69
+ });
70
+
71
+ // Redefine Type1 to a concrete type
72
+ koffi.struct(Type1, {
73
+ ptr: 'Type2 *',
74
+ f: 'float'
75
+ });
76
+ ```
77
+
78
+ > [!NOTE]
79
+ > You must use a proper type object when you redefine the type. If you only have the name, use `koffi.type()` to get a type object from a type string.
80
+ >
81
+ > ```js
82
+ > const MyType = koffi.opaque('MyType');
83
+ >
84
+ > // This does not work, you must use the MyType object and not a type string
85
+ > koffi.struct('MyType', {
86
+ > ptr: 'Type2 *',
87
+ > f: 'float'
88
+ > });
package/doc/unions.md CHANGED
@@ -1,186 +0,0 @@
1
- # Union definition
2
-
3
- *New in Koffi 2.5*
4
-
5
- You can declare unions with a syntax similar to structs, but with the `koffi.union()` function. This function takes two arguments: the first one is the name of the type, and the second one is an object containing the union member names and types. You can omit the first argument to declare an anonymous union.
6
-
7
- The following example illustrates how to declare the same union in C and in JS with Koffi:
8
-
9
- ```c
10
- typedef union IntOrDouble {
11
- int64_t i;
12
- double d;
13
- } IntOrDouble;
14
- ```
15
-
16
- ```js
17
- const IntOrDouble = koffi.union('IntOrDouble', {
18
- i: 'int64_t',
19
- d: 'double'
20
- });
21
- ```
22
-
23
- # Input unions
24
-
25
- ## Passing union values to C
26
-
27
- You can instantiate an union object with `koffi.Union(type)`. This will create a special object that contains at most one active member.
28
-
29
- Once you have created an instance of your union, you can simply set the member with the dot operator as you would with a basic object. Then, simply pass your union value to the C function you wish.
30
-
31
- ```js
32
- const U = koffi.union('U', { i: 'int', str: 'char *' });
33
-
34
- const DoSomething = lib.func('void DoSomething(const char *type, U u)');
35
-
36
- const u1 = new koffi.Union('U'); u1.i = 42;
37
- const u2 = new koffi.Union('U'); u2.str = 'Hello!';
38
-
39
- DoSomething('int', u1);
40
- DoSomething('string', u2);
41
- ```
42
-
43
- For simplicity, Koffi also accepts object literals with one property (no more, no less) setting the corresponding union member. The example belows uses this to simplify the code shown above:
44
-
45
- ```js
46
- const U = koffi.union('U', { i: 'int', str: 'char *' });
47
-
48
- const DoSomething = lib.func('void DoSomething(const char *type, U u)');
49
-
50
- DoSomething('int', { i: 42 });
51
- DoSomething('string', { str: 'Hello!' });
52
- ```
53
-
54
- ## Win32 example
55
-
56
- The following example uses the [SendInput](https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput) Win32 API to emit the Win+D shortcut and hide windows (show the desktop).
57
-
58
- ```js
59
- import koffi from 'koffi';
60
- // CJS: const koffi = require('koffi');
61
-
62
- // Win32 type and functions
63
-
64
- const user32 = koffi.load('user32.dll');
65
-
66
- const INPUT_MOUSE = 0;
67
- const INPUT_KEYBOARD = 1;
68
- const INPUT_HARDWARE = 2;
69
-
70
- const KEYEVENTF_KEYUP = 0x2;
71
- const KEYEVENTF_SCANCODE = 0x8;
72
-
73
- const VK_LWIN = 0x5B;
74
- const VK_D = 0x44;
75
-
76
- const MOUSEINPUT = koffi.struct('MOUSEINPUT', {
77
- dx: 'long',
78
- dy: 'long',
79
- mouseData: 'uint32_t',
80
- dwFlags: 'uint32_t',
81
- time: 'uint32_t',
82
- dwExtraInfo: 'uintptr_t'
83
- });
84
- const KEYBDINPUT = koffi.struct('KEYBDINPUT', {
85
- wVk: 'uint16_t',
86
- wScan: 'uint16_t',
87
- dwFlags: 'uint32_t',
88
- time: 'uint32_t',
89
- dwExtraInfo: 'uintptr_t'
90
- });
91
- const HARDWAREINPUT = koffi.struct('HARDWAREINPUT', {
92
- uMsg: 'uint32_t',
93
- wParamL: 'uint16_t',
94
- wParamH: 'uint16_t'
95
- });
96
-
97
- const INPUT = koffi.struct('INPUT', {
98
- type: 'uint32_t',
99
- u: koffi.union({
100
- mi: MOUSEINPUT,
101
- ki: KEYBDINPUT,
102
- hi: HARDWAREINPUT
103
- })
104
- });
105
-
106
- const SendInput = user32.func('unsigned int __stdcall SendInput(unsigned int cInputs, INPUT *pInputs, int cbSize)');
107
-
108
- // Show/hide desktop with Win+D shortcut
109
-
110
- let events = [
111
- make_keyboard_event(VK_LWIN, true),
112
- make_keyboard_event(VK_D, true),
113
- make_keyboard_event(VK_D, false),
114
- make_keyboard_event(VK_LWIN, false)
115
- ];
116
-
117
- SendInput(events.length, events, koffi.sizeof(INPUT));
118
-
119
- // Utility
120
-
121
- function make_keyboard_event(vk, down) {
122
- let event = {
123
- type: INPUT_KEYBOARD,
124
- u: {
125
- ki: {
126
- wVk: vk,
127
- wScan: 0,
128
- dwFlags: down ? 0 : KEYEVENTF_KEYUP,
129
- time: 0,
130
- dwExtraInfo: 0
131
- }
132
- }
133
- };
134
-
135
- return event;
136
- }
137
- ```
138
-
139
- # Output unions
140
-
141
- Unlike structs, Koffi does not know which union member is valid, and it cannot decode it automatically. You can however use special `koffi.Union` objects for output parameters, and decode the memory after the call.
142
-
143
- To decode an output union pointer parameter, create a placeholder object with `new koffi.Union(type)` and pass the resulting object to the function.
144
-
145
- After the call, you can dereference the member value you want on this object and Koffi will decode it at this moment.
146
-
147
- The following example illustrates the use of `koffi.Union()` to decode output unions after the call.
148
-
149
- ```c
150
- #include <stdint.h>
151
-
152
- typedef union IntOrDouble {
153
- int64_t i;
154
- double d;
155
- } IntOrDouble;
156
-
157
- void SetUnionInt(int64_t i, IntOrDouble *out)
158
- {
159
- out->i = i;
160
- }
161
-
162
- void SetUnionDouble(double d, IntOrDouble *out)
163
- {
164
- out->d = d;
165
- }
166
- ```
167
-
168
- ```js
169
- const IntOrDouble = koffi.union('IntOrDouble', {
170
- i: 'int64_t',
171
- d: 'double',
172
- raw: koffi.array('uint8_t', 8)
173
- });
174
-
175
- const SetUnionInt = lib.func('void SetUnionInt(int64_t i, _Out_ IntOrDouble *out)');
176
- const SetUnionDouble = lib.func('void SetUnionDouble(double d, _Out_ IntOrDouble *out)');
177
-
178
- let u1 = new koffi.Union('IntOrDouble');
179
- let u2 = new koffi.Union('IntOrDouble');
180
-
181
- SetUnionInt(123, u1);
182
- SetUnionDouble(123, u2);
183
-
184
- console.log(u1.i, '---', u1.raw); // Prints 123 --- Uint8Array(8) [123, 0, 0, 0, 0, 0, 0, 0]
185
- console.log(u2.d, '---', u2.raw); // Prints 123 --- Uint8Array(8) [0, 0, 0, 0, 0, 0, 69, 64]
186
- ```
package/doc/values.md ADDED
@@ -0,0 +1,134 @@
1
+ # Decode to JS values
2
+
3
+ ## Decode numbers
4
+
5
+ *New in Koffi 3.1.0*
6
+
7
+ Use these functions to decode numeric values from a pointer. These functions match the [number types](primitives#number-types) of Koffi:
8
+
9
+ Type | Function | Result
10
+ --------- | ---------------------------- | ------------------------------------
11
+ char | `koffi.decode.char(ptr)` | Number
12
+ uchar | `koffi.decode.uchar(ptr)` | Number
13
+ short | `koffi.decode.short(ptr)` | Number
14
+ ushort | `koffi.decode.ushort(ptr)` | Number
15
+ int | `koffi.decode.int(ptr)` | Number
16
+ uint | `koffi.decode.uint(ptr)` | Number
17
+ long | `koffi.decode.long(ptr)` | Number or BigInt (on LP64 platforms)
18
+ ulong | `koffi.decode.ulong(ptr)` | Number or BigInt (on LP64 platforms)
19
+ longlong | `koffi.decode.longlong(ptr)` | Number or BigInt
20
+ ulonglong | `koffi.decode.ulonglong(ptr)`| Number or BigInt
21
+ int8 | `koffi.decode.int8(ptr)` | Number
22
+ uint8 | `koffi.decode.uint8(ptr)` | Number
23
+ int16 | `koffi.decode.int16(ptr)` | Number
24
+ uint16 | `koffi.decode.uint16(ptr)` | Number
25
+ int32 | `koffi.decode.int32(ptr)` | Number
26
+ uint32 | `koffi.decode.uint32(ptr)` | Number
27
+ int64 | `koffi.decode.int64(ptr)` | Number or BigInt
28
+ uint64 | `koffi.decode.uint64(ptr)` | Number or BigInt
29
+ float | `koffi.decode.float(ptr)` | Number
30
+ double | `koffi.decode.double(ptr)` | Number
31
+
32
+ You can also decode [endian-sensitive integers](primitives#endian-sensitive-integers) with these functions:
33
+
34
+ Type | Function | Endianness | Result
35
+ --------- | ---------------------------- | ------------- | ----------------
36
+ int16_le | `koffi.decode.int16le(ptr)` | Little Endian | Number
37
+ uint16_le | `koffi.decode.uint16le(ptr)` | Little Endian | Number
38
+ int32_le | `koffi.decode.int32le(ptr)` | Little Endian | Number
39
+ uint32_le | `koffi.decode.uint32le(ptr)` | Little Endian | Number
40
+ int64_le | `koffi.decode.int64le(ptr)` | Little Endian | Number or BigInt
41
+ uint64_le | `koffi.decode.uint64le(ptr)` | Little Endian | Number or BigInt
42
+ int16_be | `koffi.decode.int16be(ptr)` | Big Endian | Number
43
+ uint16_be | `koffi.decode.uint16be(ptr)` | Big Endian | Number
44
+ int32_be | `koffi.decode.int32be(ptr)` | Big Endian | Number
45
+ uint32_be | `koffi.decode.uint32be(ptr)` | Big Endian | Number
46
+ int64_be | `koffi.decode.int64be(ptr)` | Big Endian | Number or BigInt
47
+ uint64_be | `koffi.decode.uint64be(ptr)` | Big Endian | Number or BigInt
48
+
49
+ ## Decode strings
50
+
51
+ You can also decode strings, NUL-terminated or with an explicit length:
52
+
53
+ Type | Function | Conversion/encoding
54
+ -------- | ------------------------------------ | -------------------------------------
55
+ string | `koffi.decode.string(ptr)` | UTF-8 (NUL-terminated)
56
+ string | `koffi.decode.string(ptr, length)` | UTF-8 (explicit length)
57
+ string16 | `koffi.decode.string16(ptr)` | UTF-16 (NUL-terminated)
58
+ string16 | `koffi.decode.string16(ptr, length)` | UTF-16 (explicit length)
59
+ string32 | `koffi.decode.string32(ptr)` | UTF-32 (NUL-terminated)
60
+ string32 | `koffi.decode.string32(ptr, length)` | UTF-32 (explicit length)
61
+ wstring | `koffi.decode.wstring(ptr)` | UTF-16 or UTF-32 (platform-dependent)
62
+ wstring | `koffi.decode.wstring(ptr, length)` | UTF-16 or UTF-32 (platform-dependent)
63
+
64
+ ## Generic decode function
65
+
66
+ Use `koffi.decode()` to decode the data pointed to by a pointer (represented by a BigInt value).
67
+
68
+ Some arguments are optional and this function can be called in several ways:
69
+
70
+ - `koffi.decode(ptr, type)`: no offset
71
+ - `koffi.decode(ptr, offset, type)`: explicit offset to add to the pointer before decoding
72
+
73
+ By default, Koffi expects NUL terminated strings when decoding them. See below if you need to specify the string length.
74
+
75
+ The following example illustrates how to decode an integer and a C string variable.
76
+
77
+ ```c
78
+ int my_int = 42;
79
+ const char *my_string = "foobar";
80
+ ```
81
+
82
+ ```js
83
+ const my_int = lib.symbol('my_int');
84
+ const my_string = lib.symbol('my_string');
85
+
86
+ console.log(koffi.decode(my_int, 'int')) // Prints 42
87
+ console.log(koffi.decode(my_string, 'const char *')) // Prints "foobar"
88
+ ```
89
+
90
+ There is also an optional ending `length` argument that you can use in two cases:
91
+
92
+ - Use it to give the number of bytes to decode in non-NUL terminated strings: `koffi.decode(ptr, 'char *', 5)`
93
+ - Decode consecutive values into an array. For example, here is how you can decode an array with 3 float values: `koffi.decode(ptr, 'float', 3)`. This is equivalent to `koffi.decode(ptr, koffi.array('float', 3))`.
94
+
95
+ The example below will decode the symbol `my_string` defined above but only the first three bytes.
96
+
97
+ ```js
98
+ // Only decode 3 bytes from the C string my_string
99
+ console.log(koffi.decode(my_string, 'const char *', 3)) // Prints "foo"
100
+ ```
101
+
102
+ # Encode to C memory
103
+
104
+ Use `koffi.encode()` to encode JS values into C symbols or pointers, which are represented by BigInt numbers.
105
+
106
+ Some arguments are optional and this function can be called in several ways:
107
+
108
+ - `koffi.encode(ptr, type, value)`: no offset
109
+ - `koffi.encode(ptr, offset, type, value)`: explicit offset to add to the pointer before encoding
110
+
111
+ We'll reuse the examples shown above and change the variable values with `koffi.encode()`.
112
+
113
+ ```c
114
+ int my_int = 42;
115
+ const char *my_string = NULL;
116
+ ```
117
+
118
+ ```js
119
+ const my_int = lib.symbol('my_int');
120
+ const my_string = lib.symbol('my_string');
121
+
122
+ console.log(koffi.decode(my_int, 'int')) // Prints 42
123
+ console.log(koffi.decode(my_string, 'const char *')) // Prints null
124
+
125
+ koffi.encode(my_int, 'int', -1);
126
+ koffi.encode(my_string, 'const char *', 'Hello World!');
127
+
128
+ console.log(koffi.decode(my_int, 'int')) // Prints -1
129
+ console.log(koffi.decode(my_string, 'const char *')) // Prints "Hello World!"
130
+ ```
131
+
132
+ When encoding strings (either directly or embedded in arrays or structs), the memory will be bound to the raw pointer value and managed by Koffi. You can assign to the same string again and again without any leak or risk of use-after-free.
133
+
134
+ There is also an optional ending `length` argument that you can use to encode an array. For example, here is how you can encode an array with 3 float values: `koffi.encode(symbol, 'float', [1, 2, 3], 3)`. This is equivalent to `koffi.encode(symbol, koffi.array('float', 3), [1, 2, 3])`.