koffi 2.6.12 → 2.7.1
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 +13 -0
- package/build/koffi/darwin_arm64/koffi.node +0 -0
- package/build/koffi/darwin_x64/koffi.node +0 -0
- package/build/koffi/freebsd_arm64/koffi.node +0 -0
- package/build/koffi/freebsd_ia32/koffi.node +0 -0
- package/build/koffi/freebsd_x64/koffi.node +0 -0
- package/build/koffi/linux_arm32hf/koffi.node +0 -0
- package/build/koffi/linux_arm64/koffi.node +0 -0
- package/build/koffi/linux_ia32/koffi.node +0 -0
- package/build/koffi/linux_riscv64hf64/koffi.node +0 -0
- package/build/koffi/linux_x64/koffi.node +0 -0
- package/build/koffi/openbsd_ia32/koffi.node +0 -0
- package/build/koffi/openbsd_x64/koffi.node +0 -0
- package/build/koffi/win32_arm64/koffi.node +0 -0
- package/build/koffi/win32_ia32/koffi.node +0 -0
- package/build/koffi/win32_x64/koffi.node +0 -0
- package/doc/callbacks.md +19 -0
- package/doc/functions.md +16 -8
- package/doc/input.md +19 -4
- package/doc/start.md +2 -2
- package/index.d.ts +14 -13
- package/index.js +11 -2
- package/indirect.js +11 -2
- package/package.json +2 -2
- package/src/core/libcc/libcc.cc +28 -24
- package/src/core/libcc/libcc.hh +20 -6
- package/src/koffi/src/ffi.cc +40 -34
- package/src/koffi/src/ffi.hh +3 -0
- package/src/koffi/src/parser.cc +5 -9
- package/src/koffi/src/util.cc +83 -14
- package/src/koffi/src/util.hh +3 -4
- package/src/koffi/src/win32.cc +1 -0
- package/src/koffi/src/win32.hh +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
## Version history
|
|
4
4
|
|
|
5
|
+
### Koffi 2.7
|
|
6
|
+
|
|
7
|
+
#### Koffi 2.7.1 (2024-01-02)
|
|
8
|
+
|
|
9
|
+
- Support C-like `int[3]` syntax for [fixed array types](input.md#fixed-size-c-arrays)
|
|
10
|
+
- Refuse type specifiers with invalid tokens at the end (previously ignored)
|
|
11
|
+
|
|
12
|
+
#### Koffi 2.7.0 (2023-12-21)
|
|
13
|
+
|
|
14
|
+
- Support alternative [callback calling convention](callbacks.md#callback-types) in classic syntax
|
|
15
|
+
- Change syntax for [calling conventions](functions.md#calling-conventions) with classic syntax
|
|
16
|
+
- Drop unused "internal" property from Koffi
|
|
17
|
+
|
|
5
18
|
### Koffi 2.6
|
|
6
19
|
|
|
7
20
|
#### Koffi 2.6.12 (2023-12-11)
|
|
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/callbacks.md
CHANGED
|
@@ -8,6 +8,8 @@ The function `koffi.proto()` was introduced in Koffi 2.4, it was called `koffi.c
|
|
|
8
8
|
|
|
9
9
|
## Callback types
|
|
10
10
|
|
|
11
|
+
*Changed in Koffi 2.7*
|
|
12
|
+
|
|
11
13
|
In order to pass a JS function to a C function expecting a callback, you must first create a callback type with the expected return type and parameters. The syntax is similar to the one used to load functions from a shared library.
|
|
12
14
|
|
|
13
15
|
```js
|
|
@@ -21,6 +23,23 @@ const ExampleCallback = koffi.proto('ExampleCallback', 'void', ['int']);
|
|
|
21
23
|
const AddDoubleFloat = koffi.proto('double AddDoubleFloat(double d, float f)');
|
|
22
24
|
```
|
|
23
25
|
|
|
26
|
+
For alternative [calling conventions](functions.md#calling-conventions) (such as `stdcall` on Windows x86 32-bit), you can specify as the first argument with the classic syntax, or after the return type in prototype strings, like this:
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
const HANDLE = koffi.pointer('HANDLE', koffi.opaque());
|
|
30
|
+
const HWND = koffi.alias('HWND', HANDLE);
|
|
31
|
+
|
|
32
|
+
// These two declarations work the same, and use the __stdcall convention on Windows x86
|
|
33
|
+
const EnumWindowsProc = koffi.proto('bool __stdcall EnumWindowsProc (HWND hwnd, long lParam)');
|
|
34
|
+
const EnumWindowsProc = koffi.proto('__stdcall', 'EnumWindowsProc', 'bool', ['HWND', 'long']);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```{warning}
|
|
38
|
+
You have to make sure you **get the calling convention right** (such as specifying __stdcall for a Windows API callback), or your code will crash on Windows 32-bit.
|
|
39
|
+
|
|
40
|
+
Before Koffi 2.7, it was *impossible to use an alternative callback calling convention with the classic syntax*. Use a prototype string or *upgrade to Koffi 2.7* to solve this limitation.
|
|
41
|
+
```
|
|
42
|
+
|
|
24
43
|
Once your callback type is declared, you can use a pointer to it in struct definitions, as function parameters and/or return types, or to call/decode function pointers.
|
|
25
44
|
|
|
26
45
|
```{note}
|
package/doc/functions.md
CHANGED
|
@@ -9,7 +9,7 @@ To declare functions, start by loading the shared library with `koffi.load(filen
|
|
|
9
9
|
const koffi = require('koffi');
|
|
10
10
|
|
|
11
11
|
const lib = koffi.load('/path/to/shared/library'); // File extension depends on platforms: .so, .dll, .dylib, etc.
|
|
12
|
-
|
|
12
|
+
```
|
|
13
13
|
|
|
14
14
|
This library will be automatically unloaded once all references to it are gone (including all the functions that use it, as described below).
|
|
15
15
|
|
|
@@ -83,19 +83,27 @@ On x86 platforms, only the Cdecl convention can be used for variadic functions.
|
|
|
83
83
|
|
|
84
84
|
### Calling conventions
|
|
85
85
|
|
|
86
|
+
*Changed in Koffi 2.7*
|
|
87
|
+
|
|
86
88
|
By default, calling a C function happens synchronously.
|
|
87
89
|
|
|
88
90
|
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:
|
|
89
91
|
|
|
90
|
-
Convention | Classic form
|
|
91
|
-
------------- |
|
|
92
|
-
**Cdecl** | `koffi.
|
|
93
|
-
**Stdcall** | `koffi.
|
|
94
|
-
**Fastcall** | `koffi.
|
|
95
|
-
**Thiscall** | `koffi.
|
|
92
|
+
Convention | Classic form | Prototype form | Description
|
|
93
|
+
------------- | --------------------------------------------- | -------------- | -------------------------------------------------------------------
|
|
94
|
+
**Cdecl** | `koffi.func(name, ret, params)` | _(default)_ | This is the default convention, and the only one on other platforms
|
|
95
|
+
**Stdcall** | `koffi.func('__stdcall', name, ret, params)` | __stdcall | This convention is used extensively within the Win32 API
|
|
96
|
+
**Fastcall** | `koffi.func('__fastcall', name, ret, params)` | __fastcall | Rarely used, uses ECX and EDX for first two parameters
|
|
97
|
+
**Thiscall** | `koffi.func('__thiscall', name, ret, params)` | __thiscall | Rarely used, uses ECX for first parameter
|
|
96
98
|
|
|
97
99
|
You can safely use these on non-x86 platforms, they are simply ignored.
|
|
98
100
|
|
|
101
|
+
```{note}
|
|
102
|
+
Support for specifying the convention as the first argument of the classic form was introduced in Koffi 2.7.
|
|
103
|
+
|
|
104
|
+
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.
|
|
105
|
+
```
|
|
106
|
+
|
|
99
107
|
Below you can find a small example showing how to use a non-default calling convention, with the two syntaxes:
|
|
100
108
|
|
|
101
109
|
```js
|
|
@@ -105,7 +113,7 @@ const koffi = require('koffi');
|
|
|
105
113
|
const lib = koffi.load('user32.dll');
|
|
106
114
|
|
|
107
115
|
// The following two declarations are equivalent, and use stdcall on x86 (and the default ABI on other platforms)
|
|
108
|
-
const MessageBoxA_1 = lib.
|
|
116
|
+
const MessageBoxA_1 = lib.func('__stdcall', 'MessageBoxA', 'int', ['void *', 'str', 'str', 'uint']);
|
|
109
117
|
const MessageBoxA_2 = lib.func('int __stdcall MessageBoxA(void *hwnd, str text, str caption, uint type)');
|
|
110
118
|
```
|
|
111
119
|
|
package/doc/input.md
CHANGED
|
@@ -336,6 +336,8 @@ try {
|
|
|
336
336
|
|
|
337
337
|
### Fixed-size C arrays
|
|
338
338
|
|
|
339
|
+
*Changed in Koffi 2.7.1*
|
|
340
|
+
|
|
339
341
|
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.
|
|
340
342
|
|
|
341
343
|
Koffi applies the following conversion rules when passing arrays to/from C:
|
|
@@ -350,13 +352,13 @@ See the example below:
|
|
|
350
352
|
const koffi = require('koffi');
|
|
351
353
|
|
|
352
354
|
// Those two structs are exactly the same, only the array conversion hint is different
|
|
353
|
-
const Foo1 = koffi.struct('
|
|
355
|
+
const Foo1 = koffi.struct('Foo1', {
|
|
354
356
|
i: 'int',
|
|
355
|
-
a16: koffi.array('int16_t',
|
|
357
|
+
a16: koffi.array('int16_t', 2)
|
|
356
358
|
});
|
|
357
|
-
const Foo2 = koffi.struct('
|
|
359
|
+
const Foo2 = koffi.struct('Foo2', {
|
|
358
360
|
i: 'int',
|
|
359
|
-
a16: koffi.array('int16_t',
|
|
361
|
+
a16: koffi.array('int16_t', 2, 'Array')
|
|
360
362
|
});
|
|
361
363
|
|
|
362
364
|
// Uses an hypothetical C function that just returns the struct passed as a parameter
|
|
@@ -367,6 +369,19 @@ console.log(ReturnFoo1({ i: 5, a16: [6, 8] })) // Prints { i: 5, a16: Int16Array
|
|
|
367
369
|
console.log(ReturnFoo2({ i: 5, a16: [6, 8] })) // Prints { i: 5, a16: [6, 8] }
|
|
368
370
|
```
|
|
369
371
|
|
|
372
|
+
You can also declare arrays with the C-like short syntax in type declarations, as shown below:
|
|
373
|
+
|
|
374
|
+
```js
|
|
375
|
+
const StructType = koffi.struct('StructType', {
|
|
376
|
+
f8: 'float [8]',
|
|
377
|
+
self4: 'StructType *[4]'
|
|
378
|
+
});
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
```{note}
|
|
382
|
+
The short C-like syntax was introduced in Koffi 2.7.1, use `koffi.array()` for older versions.
|
|
383
|
+
```
|
|
384
|
+
|
|
370
385
|
### Fixed-size string buffers
|
|
371
386
|
|
|
372
387
|
Koffi can also convert JS strings to fixed-sized arrays in the following cases:
|
package/doc/start.md
CHANGED
|
@@ -99,8 +99,8 @@ const IDYES = 6;
|
|
|
99
99
|
const IDNO = 7;
|
|
100
100
|
|
|
101
101
|
// Find functions
|
|
102
|
-
const MessageBoxA = lib.
|
|
103
|
-
const MessageBoxW = lib.
|
|
102
|
+
const MessageBoxA = lib.func('__stdcall', 'MessageBoxA', 'int', ['void *', 'str', 'str', 'uint']);
|
|
103
|
+
const MessageBoxW = lib.func('__stdcall', 'MessageBoxW', 'int', ['void *', 'str16', 'str16', 'uint']);
|
|
104
104
|
|
|
105
105
|
let ret = MessageBoxA(null, 'Do you want another message box?', 'Koffi', MB_YESNO | MB_ICONQUESTION);
|
|
106
106
|
if (ret == IDYES)
|
package/index.d.ts
CHANGED
|
@@ -67,18 +67,16 @@ declare module 'koffi' {
|
|
|
67
67
|
export interface IKoffiLib {
|
|
68
68
|
func(definition: string): KoffiFunction;
|
|
69
69
|
func(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
70
|
+
func(convention: string, name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
70
71
|
|
|
71
|
-
cdecl(definition: string): KoffiFunction;
|
|
72
|
-
cdecl(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
73
|
-
|
|
74
|
-
stdcall(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
thiscall(definition: string): KoffiFunction;
|
|
81
|
-
thiscall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
72
|
+
/** @deprecated */ cdecl(definition: string): KoffiFunction;
|
|
73
|
+
/** @deprecated */ cdecl(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
74
|
+
/** @deprecated */ stdcall(definition: string): KoffiFunction;
|
|
75
|
+
/** @deprecated */ stdcall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
76
|
+
/** @deprecated */ fastcall(definition: string): KoffiFunction;
|
|
77
|
+
/** @deprecated */ fastcall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
78
|
+
/** @deprecated */ thiscall(definition: string): KoffiFunction;
|
|
79
|
+
/** @deprecated */ thiscall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
82
80
|
|
|
83
81
|
symbol(name: string, type: TypeSpec): any;
|
|
84
82
|
|
|
@@ -106,8 +104,8 @@ declare module 'koffi' {
|
|
|
106
104
|
/** @deprecated */ export function handle(): IKoffiCType;
|
|
107
105
|
|
|
108
106
|
export function pointer(ref: TypeSpec): IKoffiCType;
|
|
109
|
-
export function pointer(ref: TypeSpec, asteriskCount
|
|
110
|
-
export function pointer(name: string, ref: TypeSpec, asteriskCount
|
|
107
|
+
export function pointer(ref: TypeSpec, asteriskCount?: number): IKoffiCType;
|
|
108
|
+
export function pointer(name: string, ref: TypeSpec, asteriskCount?: number): IKoffiCType;
|
|
111
109
|
|
|
112
110
|
export function out(type: TypeSpec): IKoffiCType;
|
|
113
111
|
export function inout(type: TypeSpec): IKoffiCType;
|
|
@@ -118,8 +116,10 @@ declare module 'koffi' {
|
|
|
118
116
|
|
|
119
117
|
export function proto(definition: string): IKoffiCType;
|
|
120
118
|
export function proto(name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
|
|
119
|
+
export function proto(convention: string, name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
|
|
121
120
|
/** @deprecated */ export function callback(definition: string): IKoffiCType;
|
|
122
121
|
/** @deprecated */ export function callback(name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
|
|
122
|
+
/** @deprecated */ export function callback(convention: string, name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
|
|
123
123
|
|
|
124
124
|
export function register(callback: Function, type: TypeSpec): IKoffiRegisteredCallback;
|
|
125
125
|
export function register(thisValue: any, callback: Function, type: TypeSpec): IKoffiRegisteredCallback;
|
|
@@ -131,6 +131,7 @@ declare module 'koffi' {
|
|
|
131
131
|
export function decode(value: any, offset: number, type: TypeSpec): any;
|
|
132
132
|
export function decode(value: any, offset: number, type: TypeSpec, len: number): any;
|
|
133
133
|
export function address(value: any): bigint;
|
|
134
|
+
export function call(value: any, type: TypeSpec, ...args: any[]): any;
|
|
134
135
|
export function encode(ref: any, type: TypeSpec): void;
|
|
135
136
|
export function encode(ref: any, type: TypeSpec, value: any): void;
|
|
136
137
|
export function encode(ref: any, type: TypeSpec, value: any, len: number): void;
|
package/index.js
CHANGED
|
@@ -378,8 +378,8 @@ var require_package = __commonJS({
|
|
|
378
378
|
"build/dist/src/koffi/package.json"(exports2, module2) {
|
|
379
379
|
module2.exports = {
|
|
380
380
|
name: "koffi",
|
|
381
|
-
version: "2.
|
|
382
|
-
stable: "2.
|
|
381
|
+
version: "2.7.1",
|
|
382
|
+
stable: "2.7.1",
|
|
383
383
|
description: "Fast and simple C FFI (foreign function interface) for Node.js",
|
|
384
384
|
keywords: [
|
|
385
385
|
"foreign",
|
|
@@ -557,3 +557,12 @@ module.exports = {
|
|
|
557
557
|
handle: util.deprecate(native.opaque, "The koffi.handle() function was deprecated in Koffi 2.1, use koffi.opaque() instead", "KOFFI001"),
|
|
558
558
|
callback: util.deprecate(native.proto, "The koffi.callback() function was deprecated in Koffi 2.4, use koffi.proto() instead", "KOFFI002")
|
|
559
559
|
};
|
|
560
|
+
var load = module.exports.load;
|
|
561
|
+
module.exports.load = (...args) => {
|
|
562
|
+
let lib = load(...args);
|
|
563
|
+
lib.cdecl = util.deprecate((...args2) => lib.func("__cdecl", ...args2), "The koffi.stdcall() function was deprecated in Koffi 2.7, use koffi.func(...) instead", "KOFFI003");
|
|
564
|
+
lib.stdcall = util.deprecate((...args2) => lib.func("__stdcall", ...args2), 'The koffi.stdcall() function was deprecated in Koffi 2.7, use koffi.func("__stdcall", ...) instead', "KOFFI004");
|
|
565
|
+
lib.fastcall = util.deprecate((...args2) => lib.func("__fastcall", ...args2), 'The koffi.fastcall() function was deprecated in Koffi 2.7, use koffi.func("__fastcall", ...) instead', "KOFFI005");
|
|
566
|
+
lib.thiscall = util.deprecate((...args2) => lib.func("__thiscall", ...args2), 'The koffi.thiscall() function was deprecated in Koffi 2.7, use koffi.func("__thiscall", ...) instead', "KOFFI006");
|
|
567
|
+
return lib;
|
|
568
|
+
};
|
package/indirect.js
CHANGED
|
@@ -378,8 +378,8 @@ var require_package = __commonJS({
|
|
|
378
378
|
"build/dist/src/koffi/package.json"(exports2, module2) {
|
|
379
379
|
module2.exports = {
|
|
380
380
|
name: "koffi",
|
|
381
|
-
version: "2.
|
|
382
|
-
stable: "2.
|
|
381
|
+
version: "2.7.1",
|
|
382
|
+
stable: "2.7.1",
|
|
383
383
|
description: "Fast and simple C FFI (foreign function interface) for Node.js",
|
|
384
384
|
keywords: [
|
|
385
385
|
"foreign",
|
|
@@ -477,3 +477,12 @@ module.exports = {
|
|
|
477
477
|
handle: util.deprecate(native.opaque, "The koffi.handle() function was deprecated in Koffi 2.1, use koffi.opaque() instead", "KOFFI001"),
|
|
478
478
|
callback: util.deprecate(native.proto, "The koffi.callback() function was deprecated in Koffi 2.4, use koffi.proto() instead", "KOFFI002")
|
|
479
479
|
};
|
|
480
|
+
var load = module.exports.load;
|
|
481
|
+
module.exports.load = (...args) => {
|
|
482
|
+
let lib = load(...args);
|
|
483
|
+
lib.cdecl = util.deprecate((...args2) => lib.func("__cdecl", ...args2), "The koffi.stdcall() function was deprecated in Koffi 2.7, use koffi.func(...) instead", "KOFFI003");
|
|
484
|
+
lib.stdcall = util.deprecate((...args2) => lib.func("__stdcall", ...args2), 'The koffi.stdcall() function was deprecated in Koffi 2.7, use koffi.func("__stdcall", ...) instead', "KOFFI004");
|
|
485
|
+
lib.fastcall = util.deprecate((...args2) => lib.func("__fastcall", ...args2), 'The koffi.fastcall() function was deprecated in Koffi 2.7, use koffi.func("__fastcall", ...) instead', "KOFFI005");
|
|
486
|
+
lib.thiscall = util.deprecate((...args2) => lib.func("__thiscall", ...args2), 'The koffi.thiscall() function was deprecated in Koffi 2.7, use koffi.func("__thiscall", ...) instead', "KOFFI006");
|
|
487
|
+
return lib;
|
|
488
|
+
};
|
package/package.json
CHANGED
package/src/core/libcc/libcc.cc
CHANGED
|
@@ -3881,8 +3881,11 @@ bool CreateOverlappedPipe(bool overlap0, bool overlap1, PipeMode mode, HANDLE ou
|
|
|
3881
3881
|
|
|
3882
3882
|
void CloseHandleSafe(HANDLE *handle_ptr)
|
|
3883
3883
|
{
|
|
3884
|
-
|
|
3885
|
-
|
|
3884
|
+
HANDLE h = *handle_ptr;
|
|
3885
|
+
|
|
3886
|
+
if (h && h != INVALID_HANDLE_VALUE) {
|
|
3887
|
+
CancelIo(h);
|
|
3888
|
+
CloseHandle(h);
|
|
3886
3889
|
}
|
|
3887
3890
|
|
|
3888
3891
|
*handle_ptr = nullptr;
|
|
@@ -4021,6 +4024,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
|
|
|
4021
4024
|
CloseHandleSafe(&si.hStdOutput);
|
|
4022
4025
|
CloseHandleSafe(&si.hStdError);
|
|
4023
4026
|
};
|
|
4027
|
+
|
|
4024
4028
|
if (in_func.IsValid() || out_func.IsValid()) {
|
|
4025
4029
|
if (!DuplicateHandle(GetCurrentProcess(), in_func.IsValid() ? in_pipe[0] : GetStdHandle(STD_INPUT_HANDLE),
|
|
4026
4030
|
GetCurrentProcess(), &si.hStdInput, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
|
|
@@ -4095,6 +4099,7 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
|
|
|
4095
4099
|
if (proc_in.err && proc_in.err != ERROR_BROKEN_PIPE && proc_in.err != ERROR_NO_DATA) {
|
|
4096
4100
|
LogError("Failed to write to process: %1", GetWin32ErrorString(proc_in.err));
|
|
4097
4101
|
}
|
|
4102
|
+
|
|
4098
4103
|
proc_in.pending = true;
|
|
4099
4104
|
}
|
|
4100
4105
|
|
|
@@ -4111,30 +4116,23 @@ bool ExecuteCommandLine(const char *cmd_line, const ExecuteInfo &info,
|
|
|
4111
4116
|
}
|
|
4112
4117
|
}
|
|
4113
4118
|
|
|
4114
|
-
if (proc_out.err
|
|
4115
|
-
|
|
4119
|
+
if (proc_out.err) {
|
|
4120
|
+
if (proc_out.err != ERROR_BROKEN_PIPE && proc_out.err != ERROR_NO_DATA) {
|
|
4121
|
+
LogError("Failed to read process output: %1", GetWin32ErrorString(proc_out.err));
|
|
4122
|
+
}
|
|
4123
|
+
break;
|
|
4116
4124
|
}
|
|
4125
|
+
|
|
4117
4126
|
proc_out.pending = true;
|
|
4118
4127
|
}
|
|
4119
4128
|
|
|
4120
|
-
|
|
4121
|
-
process_handle,
|
|
4122
|
-
console_ctrl_event
|
|
4123
|
-
};
|
|
4124
|
-
|
|
4125
|
-
running = (WaitForMultipleObjectsEx(RG_LEN(events), events, FALSE, INFINITE, TRUE) > WAIT_OBJECT_0 + 1);
|
|
4129
|
+
running = (WaitForSingleObjectEx(console_ctrl_event, INFINITE, TRUE) != WAIT_OBJECT_0);
|
|
4126
4130
|
}
|
|
4127
4131
|
}
|
|
4128
4132
|
|
|
4129
4133
|
// Terminate any remaining I/O
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
CloseHandleSafe(&in_pipe[1]);
|
|
4133
|
-
}
|
|
4134
|
-
if (out_pipe[0]) {
|
|
4135
|
-
CancelIo(out_pipe[0]);
|
|
4136
|
-
CloseHandleSafe(&out_pipe[0]);
|
|
4137
|
-
}
|
|
4134
|
+
CloseHandleSafe(&in_pipe[1]);
|
|
4135
|
+
CloseHandleSafe(&out_pipe[0]);
|
|
4138
4136
|
|
|
4139
4137
|
// Wait for process exit
|
|
4140
4138
|
{
|
|
@@ -5599,7 +5597,6 @@ public:
|
|
|
5599
5597
|
AsyncPool(int threads, bool leak);
|
|
5600
5598
|
|
|
5601
5599
|
int GetWorkerCount() const { return (int)workers.len; }
|
|
5602
|
-
int CountPendingTasks() const { return pending_tasks; }
|
|
5603
5600
|
|
|
5604
5601
|
void RegisterAsync();
|
|
5605
5602
|
void UnregisterAsync();
|
|
@@ -5673,11 +5670,6 @@ bool Async::Sync()
|
|
|
5673
5670
|
return success;
|
|
5674
5671
|
}
|
|
5675
5672
|
|
|
5676
|
-
int Async::CountPendingTasks()
|
|
5677
|
-
{
|
|
5678
|
-
return pool->CountPendingTasks();
|
|
5679
|
-
}
|
|
5680
|
-
|
|
5681
5673
|
bool Async::IsTaskRunning()
|
|
5682
5674
|
{
|
|
5683
5675
|
return async_running_task;
|
|
@@ -5806,6 +5798,11 @@ void AsyncPool::AddTask(Async *async, const std::function<bool()> &func)
|
|
|
5806
5798
|
pending_cv.notify_all();
|
|
5807
5799
|
sync_cv.notify_all();
|
|
5808
5800
|
}
|
|
5801
|
+
|
|
5802
|
+
// Limit queue size (back pressure)
|
|
5803
|
+
while (pending_tasks >= RG_ASYNC_MAX_PENDING_TASKS) {
|
|
5804
|
+
RunTasks(0);
|
|
5805
|
+
}
|
|
5809
5806
|
}
|
|
5810
5807
|
|
|
5811
5808
|
void AsyncPool::RunWorker(int worker_idx)
|
|
@@ -7519,6 +7516,13 @@ void OptionParser::LogUnknownError() const
|
|
|
7519
7516
|
}
|
|
7520
7517
|
}
|
|
7521
7518
|
|
|
7519
|
+
void OptionParser::LogUnusedArguments() const
|
|
7520
|
+
{
|
|
7521
|
+
if (pos < args.len) {
|
|
7522
|
+
LogWarning("Unused command-line arguments");
|
|
7523
|
+
}
|
|
7524
|
+
}
|
|
7525
|
+
|
|
7522
7526
|
// ------------------------------------------------------------------------
|
|
7523
7527
|
// Console prompter (simplified readline)
|
|
7524
7528
|
// ------------------------------------------------------------------------
|
package/src/core/libcc/libcc.hh
CHANGED
|
@@ -93,6 +93,8 @@ namespace RG {
|
|
|
93
93
|
|
|
94
94
|
#define RG_ASYNC_MAX_THREADS 2048
|
|
95
95
|
#define RG_ASYNC_MAX_IDLE_TIME 10000
|
|
96
|
+
#define RG_ASYNC_MAX_PENDING_TASKS 1024
|
|
97
|
+
|
|
96
98
|
#define RG_FIBER_DEFAULT_STACK_SIZE Kibibytes(128)
|
|
97
99
|
|
|
98
100
|
// ------------------------------------------------------------------------
|
|
@@ -1218,11 +1220,22 @@ public:
|
|
|
1218
1220
|
{
|
|
1219
1221
|
RG_ASSERT(len <= N - count);
|
|
1220
1222
|
|
|
1221
|
-
T *
|
|
1222
|
-
|
|
1223
|
-
|
|
1223
|
+
T *first = data + len;
|
|
1224
|
+
#if __cplusplus >= 201703L
|
|
1225
|
+
if constexpr(!std::is_trivial<T>::value) {
|
|
1226
|
+
#else
|
|
1227
|
+
if (true) {
|
|
1228
|
+
#endif
|
|
1229
|
+
for (Size i = 0; i < count; i++) {
|
|
1230
|
+
new (data + len) T();
|
|
1231
|
+
len++;
|
|
1232
|
+
}
|
|
1233
|
+
} else {
|
|
1234
|
+
memset_safe(first, 0, count * RG_SIZE(T));
|
|
1235
|
+
len += count;
|
|
1236
|
+
}
|
|
1224
1237
|
|
|
1225
|
-
return
|
|
1238
|
+
return first;
|
|
1226
1239
|
}
|
|
1227
1240
|
|
|
1228
1241
|
T *Append(const T &value)
|
|
@@ -1432,6 +1445,7 @@ public:
|
|
|
1432
1445
|
memset_safe(first, 0, count * RG_SIZE(T));
|
|
1433
1446
|
len += count;
|
|
1434
1447
|
}
|
|
1448
|
+
|
|
1435
1449
|
return first;
|
|
1436
1450
|
}
|
|
1437
1451
|
|
|
@@ -4265,8 +4279,6 @@ public:
|
|
|
4265
4279
|
void Run(const std::function<bool()> &f);
|
|
4266
4280
|
bool Sync();
|
|
4267
4281
|
|
|
4268
|
-
int CountPendingTasks();
|
|
4269
|
-
|
|
4270
4282
|
static bool IsTaskRunning();
|
|
4271
4283
|
static int GetWorkerIdx();
|
|
4272
4284
|
static int GetWorkerCount();
|
|
@@ -4887,7 +4899,9 @@ public:
|
|
|
4887
4899
|
{ return Test(test1, nullptr, type); }
|
|
4888
4900
|
|
|
4889
4901
|
bool TestHasFailed() const { return test_failed; }
|
|
4902
|
+
|
|
4890
4903
|
void LogUnknownError() const;
|
|
4904
|
+
void LogUnusedArguments() const;
|
|
4891
4905
|
};
|
|
4892
4906
|
|
|
4893
4907
|
template <typename T>
|
package/src/koffi/src/ffi.cc
CHANGED
|
@@ -880,35 +880,50 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
|
880
880
|
return WrapType(env, instance, type);
|
|
881
881
|
}
|
|
882
882
|
|
|
883
|
-
static bool ParseClassicFunction(
|
|
884
|
-
Napi::Array parameters, FunctionInfo *func)
|
|
883
|
+
static bool ParseClassicFunction(const Napi::CallbackInfo &info, FunctionInfo *out_func)
|
|
885
884
|
{
|
|
885
|
+
Napi::Env env = info.Env();
|
|
886
886
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
887
887
|
|
|
888
|
+
Napi::String name = info[0u].As<Napi::String>();
|
|
889
|
+
Napi::Value ret = info[1u];
|
|
890
|
+
Napi::Array parameters = info[2u].As<Napi::Array>();
|
|
891
|
+
|
|
892
|
+
// Detect optional call convention
|
|
893
|
+
if (name.IsString() && DetectCallConvention(name.Utf8Value().c_str(), &out_func->convention)) {
|
|
894
|
+
if (info.Length() < 4) {
|
|
895
|
+
ThrowError<Napi::TypeError>(env, "Expected 4 arguments, got %1", info.Length());
|
|
896
|
+
return false;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
name = info[1u].As<Napi::String>();
|
|
900
|
+
ret = info[2u];
|
|
901
|
+
parameters = info[3u].As<Napi::Array>();
|
|
902
|
+
}
|
|
903
|
+
|
|
888
904
|
#ifdef _WIN32
|
|
889
|
-
if (
|
|
890
|
-
|
|
891
|
-
|
|
905
|
+
if (name.IsNumber()) {
|
|
906
|
+
out_func->ordinal_name = name.As<Napi::Number>().Int32Value();
|
|
907
|
+
name = name.ToString();
|
|
892
908
|
}
|
|
893
|
-
#
|
|
909
|
+
#endif
|
|
894
910
|
if (!name.IsString()) {
|
|
895
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, name));
|
|
911
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string or integer", GetValueType(instance, name));
|
|
896
912
|
return false;
|
|
897
913
|
}
|
|
898
|
-
#endif
|
|
899
914
|
|
|
900
|
-
|
|
915
|
+
out_func->name = DuplicateString(name.ToString().Utf8Value().c_str(), &instance->str_alloc).ptr;
|
|
901
916
|
|
|
902
|
-
|
|
903
|
-
if (!
|
|
917
|
+
out_func->ret.type = ResolveType(ret);
|
|
918
|
+
if (!out_func->ret.type)
|
|
904
919
|
return false;
|
|
905
|
-
if (!CanReturnType(
|
|
906
|
-
ThrowError<Napi::TypeError>(env, "You are not allowed to directly return %1 values (maybe try %1 *)",
|
|
920
|
+
if (!CanReturnType(out_func->ret.type)) {
|
|
921
|
+
ThrowError<Napi::TypeError>(env, "You are not allowed to directly return %1 values (maybe try %1 *)", out_func->ret.type->name);
|
|
907
922
|
return false;
|
|
908
923
|
}
|
|
909
924
|
|
|
910
925
|
if (!parameters.IsArray()) {
|
|
911
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for parameters of '%2', expected an array", GetValueType(instance, parameters),
|
|
926
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for parameters of '%2', expected an array", GetValueType(instance, parameters), out_func->name);
|
|
912
927
|
return false;
|
|
913
928
|
}
|
|
914
929
|
|
|
@@ -918,7 +933,7 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
|
|
|
918
933
|
Napi::String str = parameters.Get(parameters_len - 1).As<Napi::String>();
|
|
919
934
|
|
|
920
935
|
if (str.IsString() && str.Utf8Value() == "...") {
|
|
921
|
-
|
|
936
|
+
out_func->variadic = true;
|
|
922
937
|
parameters_len--;
|
|
923
938
|
}
|
|
924
939
|
}
|
|
@@ -934,21 +949,21 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
|
|
|
934
949
|
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", param.type->name);
|
|
935
950
|
return false;
|
|
936
951
|
}
|
|
937
|
-
if (
|
|
952
|
+
if (out_func->parameters.len >= MaxParameters) {
|
|
938
953
|
ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 parameters", MaxParameters);
|
|
939
954
|
return false;
|
|
940
955
|
}
|
|
941
|
-
if ((param.directions & 2) && ++
|
|
956
|
+
if ((param.directions & 2) && ++out_func->out_parameters >= MaxParameters) {
|
|
942
957
|
ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 output parameters", MaxParameters);
|
|
943
958
|
return false;
|
|
944
959
|
}
|
|
945
960
|
|
|
946
961
|
param.offset = (int8_t)j;
|
|
947
962
|
|
|
948
|
-
|
|
963
|
+
out_func->parameters.Append(param);
|
|
949
964
|
}
|
|
950
965
|
|
|
951
|
-
|
|
966
|
+
out_func->required_parameters = (int8_t)out_func->parameters.len;
|
|
952
967
|
|
|
953
968
|
return true;
|
|
954
969
|
}
|
|
@@ -962,7 +977,7 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
|
|
|
962
977
|
RG_DEFER_N(err_guard) { instance->callbacks.RemoveLast(1); };
|
|
963
978
|
|
|
964
979
|
if (info.Length() >= 3) {
|
|
965
|
-
if (!ParseClassicFunction(
|
|
980
|
+
if (!ParseClassicFunction(info, func))
|
|
966
981
|
return env.Null();
|
|
967
982
|
} else if (info.Length() >= 1) {
|
|
968
983
|
if (!info[0].IsString()) {
|
|
@@ -1519,7 +1534,7 @@ extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, Bac
|
|
|
1519
1534
|
}
|
|
1520
1535
|
}
|
|
1521
1536
|
|
|
1522
|
-
static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info
|
|
1537
|
+
static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info)
|
|
1523
1538
|
{
|
|
1524
1539
|
Napi::Env env = info.Env();
|
|
1525
1540
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
@@ -1529,10 +1544,9 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
|
|
|
1529
1544
|
RG_DEFER { func->Unref(); };
|
|
1530
1545
|
|
|
1531
1546
|
func->lib = lib->Ref();
|
|
1532
|
-
func->convention = convention;
|
|
1533
1547
|
|
|
1534
1548
|
if (info.Length() >= 3) {
|
|
1535
|
-
if (!ParseClassicFunction(
|
|
1549
|
+
if (!ParseClassicFunction(info, func))
|
|
1536
1550
|
return env.Null();
|
|
1537
1551
|
} else if (info.Length() >= 1) {
|
|
1538
1552
|
if (!info[0].IsString()) {
|
|
@@ -1562,7 +1576,7 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
|
|
|
1562
1576
|
}
|
|
1563
1577
|
|
|
1564
1578
|
#ifdef _WIN32
|
|
1565
|
-
if (
|
|
1579
|
+
if (func->ordinal_name < 0) {
|
|
1566
1580
|
if (func->decorated_name) {
|
|
1567
1581
|
func->native = (void *)GetProcAddress((HMODULE)lib->module, func->decorated_name);
|
|
1568
1582
|
}
|
|
@@ -1570,7 +1584,7 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
|
|
|
1570
1584
|
func->native = (void *)GetProcAddress((HMODULE)lib->module, func->name);
|
|
1571
1585
|
}
|
|
1572
1586
|
} else {
|
|
1573
|
-
uint16_t ordinal = (uint16_t)
|
|
1587
|
+
uint16_t ordinal = (uint16_t)func->ordinal_name;
|
|
1574
1588
|
|
|
1575
1589
|
func->decorated_name = nullptr;
|
|
1576
1590
|
func->native = (void *)GetProcAddress((HMODULE)lib->module, (LPCSTR)(size_t)ordinal);
|
|
@@ -1720,20 +1734,13 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
|
|
|
1720
1734
|
func.AddFinalizer([](Napi::Env, LibraryHolder *lib) { lib->Unref(); }, lib); \
|
|
1721
1735
|
obj.Set((Name), func); \
|
|
1722
1736
|
} while (false)
|
|
1723
|
-
#define ADD_CONVENTION(Name, Value) ADD_METHOD((Name), FindLibraryFunction(info, Value))
|
|
1724
|
-
|
|
1725
|
-
ADD_CONVENTION("func", CallConvention::Cdecl);
|
|
1726
|
-
ADD_CONVENTION("cdecl", CallConvention::Cdecl);
|
|
1727
|
-
ADD_CONVENTION("stdcall", CallConvention::Stdcall);
|
|
1728
|
-
ADD_CONVENTION("fastcall", CallConvention::Fastcall);
|
|
1729
|
-
ADD_CONVENTION("thiscall", CallConvention::Thiscall);
|
|
1730
1737
|
|
|
1738
|
+
ADD_METHOD("func", FindLibraryFunction(info));
|
|
1731
1739
|
ADD_METHOD("symbol", FindSymbol(info));
|
|
1732
1740
|
|
|
1733
1741
|
// We can't unref the library after unload, obviously
|
|
1734
1742
|
obj.Set("unload", Napi::Function::New(env, UnloadLibrary, "unload", (void *)lib->Ref()));
|
|
1735
1743
|
|
|
1736
|
-
#undef ADD_CONVENTION
|
|
1737
1744
|
#undef ADD_METHOD
|
|
1738
1745
|
|
|
1739
1746
|
return obj;
|
|
@@ -2326,7 +2333,6 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
|
|
|
2326
2333
|
Napi::Object types = InitBaseTypes(env);
|
|
2327
2334
|
exports.Set("types", types);
|
|
2328
2335
|
|
|
2329
|
-
exports.Set("internal", Napi::Boolean::New(env, false));
|
|
2330
2336
|
exports.Set("version", Napi::String::New(env, RG_STRINGIFY(VERSION)));
|
|
2331
2337
|
|
|
2332
2338
|
return exports;
|
package/src/koffi/src/ffi.hh
CHANGED
package/src/koffi/src/parser.cc
CHANGED
|
@@ -40,15 +40,7 @@ bool PrototypeParser::Parse(const char *str, FunctionInfo *out_func)
|
|
|
40
40
|
MarkError("You are not allowed to directly return %1 values (maybe try %1 *)", out_func->ret.type->name);
|
|
41
41
|
return false;
|
|
42
42
|
}
|
|
43
|
-
|
|
44
|
-
out_func->convention = CallConvention::Cdecl;
|
|
45
|
-
} else if (Match("__stdcall")) {
|
|
46
|
-
out_func->convention = CallConvention::Stdcall;
|
|
47
|
-
} else if (Match("__fastcall")) {
|
|
48
|
-
out_func->convention = CallConvention::Fastcall;
|
|
49
|
-
} else if (Match("__thiscall")) {
|
|
50
|
-
out_func->convention = CallConvention::Thiscall;
|
|
51
|
-
}
|
|
43
|
+
offset += (offset < tokens.len && DetectCallConvention(tokens[offset], &out_func->convention));
|
|
52
44
|
out_func->name = ParseIdentifier();
|
|
53
45
|
|
|
54
46
|
Consume("(");
|
|
@@ -152,6 +144,10 @@ const TypeInfo *PrototypeParser::ParseType(int *out_directions)
|
|
|
152
144
|
while (++offset < tokens.len && (tokens[offset] == '*' ||
|
|
153
145
|
tokens[offset] == '!' ||
|
|
154
146
|
tokens[offset] == "const"));
|
|
147
|
+
if (offset < tokens.len && tokens[offset] == "[") [[unlikely]] {
|
|
148
|
+
MarkError("Array types decay to pointers in prototypes (C standard), use pointers");
|
|
149
|
+
return instance->void_type;
|
|
150
|
+
}
|
|
155
151
|
offset--;
|
|
156
152
|
|
|
157
153
|
while (offset >= start) {
|
package/src/koffi/src/util.cc
CHANGED
|
@@ -192,7 +192,8 @@ const TypeInfo *ResolveType(Napi::Env env, Span<const char> str, int *out_direct
|
|
|
192
192
|
{
|
|
193
193
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
194
194
|
|
|
195
|
-
|
|
195
|
+
// Each item can be > 0 for array or 0 for a pointer
|
|
196
|
+
LocalArray<Size, 8> arrays;
|
|
196
197
|
uint8_t disposables = 0;
|
|
197
198
|
|
|
198
199
|
// Consume parameter direction qualifier
|
|
@@ -223,18 +224,18 @@ const TypeInfo *ResolveType(Napi::Env env, Span<const char> str, int *out_direct
|
|
|
223
224
|
Span<const char> remain = str;
|
|
224
225
|
|
|
225
226
|
// Skip initial const qualifiers
|
|
226
|
-
remain =
|
|
227
|
+
remain = TrimStrLeft(remain);
|
|
227
228
|
while (SplitIdentifier(remain) == "const") {
|
|
228
229
|
remain = remain.Take(6, remain.len - 6);
|
|
229
|
-
remain =
|
|
230
|
+
remain = TrimStrLeft(remain);
|
|
230
231
|
}
|
|
231
|
-
remain =
|
|
232
|
+
remain = TrimStrLeft(remain);
|
|
232
233
|
|
|
233
234
|
after = remain;
|
|
234
235
|
|
|
235
236
|
// Consume one or more identifiers (e.g. unsigned int)
|
|
236
237
|
for (;;) {
|
|
237
|
-
after =
|
|
238
|
+
after = TrimStrLeft(after);
|
|
238
239
|
|
|
239
240
|
Span<const char> token = SplitIdentifier(after);
|
|
240
241
|
if (!token.len)
|
|
@@ -245,26 +246,57 @@ const TypeInfo *ResolveType(Napi::Env env, Span<const char> str, int *out_direct
|
|
|
245
246
|
name = TrimStr(MakeSpan(remain.ptr, after.ptr - remain.ptr));
|
|
246
247
|
}
|
|
247
248
|
|
|
248
|
-
// Consume pointer
|
|
249
|
+
// Consume type indirections (pointer, array, etc.)
|
|
249
250
|
while (after.len) {
|
|
250
251
|
if (after[0] == '*') {
|
|
251
252
|
after = after.Take(1, after.len - 1);
|
|
252
|
-
indirect++;
|
|
253
253
|
|
|
254
|
-
if (
|
|
255
|
-
ThrowError<Napi::Error>(env, "Too many
|
|
254
|
+
if (!arrays.Available()) [[unlikely]] {
|
|
255
|
+
ThrowError<Napi::Error>(env, "Too many type indirections");
|
|
256
256
|
return nullptr;
|
|
257
257
|
}
|
|
258
|
+
|
|
259
|
+
arrays.Append(0);
|
|
258
260
|
} else if (after[0] == '!') {
|
|
259
261
|
after = after.Take(1, after.len - 1);
|
|
260
|
-
disposables |= (1u <<
|
|
262
|
+
disposables |= (1u << arrays.len);
|
|
263
|
+
} else if (after[0] == '[') {
|
|
264
|
+
after = after.Take(1, after.len - 1);
|
|
265
|
+
|
|
266
|
+
Size len = 0;
|
|
267
|
+
|
|
268
|
+
after = TrimStrLeft(after);
|
|
269
|
+
if (!ParseInt(after, &len, 0, &after) || len < 0) [[unlikely]] {
|
|
270
|
+
ThrowError<Napi::Error>(env, "Invalid array length");
|
|
271
|
+
return nullptr;
|
|
272
|
+
}
|
|
273
|
+
after = TrimStrLeft(after);
|
|
274
|
+
if (!after.len || after[0] != ']') [[unlikely]] {
|
|
275
|
+
ThrowError<Napi::Error>(env, "Expected ']' after array length");
|
|
276
|
+
return nullptr;
|
|
277
|
+
}
|
|
278
|
+
after = after.Take(1, after.len - 1);
|
|
279
|
+
|
|
280
|
+
if (!arrays.Available()) [[unlikely]] {
|
|
281
|
+
ThrowError<Napi::Error>(env, "Too many type indirections");
|
|
282
|
+
return nullptr;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
arrays.Append(len);
|
|
261
286
|
} else if (SplitIdentifier(after) == "const") {
|
|
262
287
|
after = after.Take(6, after.len - 6);
|
|
263
288
|
} else {
|
|
289
|
+
after = TrimStrRight(after);
|
|
290
|
+
|
|
291
|
+
if (after.len) [[unlikely]] {
|
|
292
|
+
ThrowError<Napi::Error>(env, "Unexpected character '%1' in type specifier", after[0]);
|
|
293
|
+
return nullptr;
|
|
294
|
+
}
|
|
295
|
+
|
|
264
296
|
break;
|
|
265
297
|
}
|
|
266
298
|
|
|
267
|
-
after =
|
|
299
|
+
after = TrimStrLeft(after);
|
|
268
300
|
}
|
|
269
301
|
|
|
270
302
|
const TypeInfo *type = instance->types_map.FindValue(name, nullptr);
|
|
@@ -317,11 +349,29 @@ const TypeInfo *ResolveType(Napi::Env env, Span<const char> str, int *out_direct
|
|
|
317
349
|
type = copy;
|
|
318
350
|
}
|
|
319
351
|
|
|
320
|
-
if (i >=
|
|
352
|
+
if (i >= arrays.len)
|
|
321
353
|
break;
|
|
354
|
+
Size len = arrays[i];
|
|
322
355
|
|
|
323
|
-
|
|
324
|
-
|
|
356
|
+
if (len > 0) {
|
|
357
|
+
if (type->flags & (int)TypeFlag::IsIncomplete) [[unlikely]] {
|
|
358
|
+
ThrowError<Napi::TypeError>(env, "Cannot make array of incomplete type");
|
|
359
|
+
return nullptr;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
if (len > instance->config.max_type_size / type->size) {
|
|
363
|
+
ThrowError<Napi::TypeError>(env, "Array length is too high (max = %1)", instance->config.max_type_size / type->size);
|
|
364
|
+
return nullptr;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
type = MakeArrayType(instance, type, len);
|
|
368
|
+
RG_ASSERT(type);
|
|
369
|
+
} else {
|
|
370
|
+
RG_ASSERT(!len);
|
|
371
|
+
|
|
372
|
+
type = MakePointerType(instance, type);
|
|
373
|
+
RG_ASSERT(type);
|
|
374
|
+
}
|
|
325
375
|
}
|
|
326
376
|
|
|
327
377
|
if (type->flags & (int)TypeFlag::IsIncomplete) [[unlikely]] {
|
|
@@ -1508,6 +1558,25 @@ Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func)
|
|
|
1508
1558
|
return wrapper;
|
|
1509
1559
|
}
|
|
1510
1560
|
|
|
1561
|
+
bool DetectCallConvention(Span<const char> name, CallConvention *out_convention)
|
|
1562
|
+
{
|
|
1563
|
+
if (name == "__cdecl") {
|
|
1564
|
+
*out_convention = CallConvention::Cdecl;
|
|
1565
|
+
return true;
|
|
1566
|
+
} else if (name == "__stdcall") {
|
|
1567
|
+
*out_convention = CallConvention::Stdcall;
|
|
1568
|
+
return true;
|
|
1569
|
+
} else if (name == "__fastcall") {
|
|
1570
|
+
*out_convention = CallConvention::Fastcall;
|
|
1571
|
+
return true;
|
|
1572
|
+
} else if (name == "__thiscall") {
|
|
1573
|
+
*out_convention = CallConvention::Thiscall;
|
|
1574
|
+
return true;
|
|
1575
|
+
} else {
|
|
1576
|
+
return false;
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1511
1580
|
static int AnalyseFlatRec(const TypeInfo *type, int offset, int count, FunctionRef<void(const TypeInfo *type, int offset, int count)> func)
|
|
1512
1581
|
{
|
|
1513
1582
|
if (type->primitive == PrimitiveKind::Record) {
|
package/src/koffi/src/util.hh
CHANGED
|
@@ -22,15 +22,12 @@
|
|
|
22
22
|
#pragma once
|
|
23
23
|
|
|
24
24
|
#include "src/core/libcc/libcc.hh"
|
|
25
|
+
#include "ffi.hh"
|
|
25
26
|
|
|
26
27
|
#include <napi.h>
|
|
27
28
|
|
|
28
29
|
namespace RG {
|
|
29
30
|
|
|
30
|
-
struct InstanceData;
|
|
31
|
-
struct TypeInfo;
|
|
32
|
-
struct FunctionInfo;
|
|
33
|
-
|
|
34
31
|
extern const int TypeInfoMarker;
|
|
35
32
|
extern const int CastMarker;
|
|
36
33
|
extern const int MagicUnionMarker;
|
|
@@ -208,6 +205,8 @@ static inline Napi::Array GetOwnPropertyNames(Napi::Object obj)
|
|
|
208
205
|
|
|
209
206
|
Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func);
|
|
210
207
|
|
|
208
|
+
bool DetectCallConvention(Span<const char> name, CallConvention *out_convention);
|
|
209
|
+
|
|
211
210
|
int AnalyseFlat(const TypeInfo *type, FunctionRef<void(const TypeInfo *type, int offset, int count)> func);
|
|
212
211
|
|
|
213
212
|
void DumpMemory(const char *type, Span<const uint8_t> bytes);
|
package/src/koffi/src/win32.cc
CHANGED