koffi 2.6.9 → 2.6.11
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 +9 -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/build/koffi/win32_x64/koffi.pdb +0 -0
- package/doc/variables.md +8 -2
- package/index.js +2 -2
- package/indirect.js +2 -2
- package/package.json +2 -2
- package/src/core/libcc/libcc.cc +34 -16
- package/src/core/libcc/libcc.hh +8 -0
- package/src/koffi/src/abi_arm64.cc +4 -0
- package/src/koffi/src/abi_x64_win.cc +4 -0
- package/src/koffi/src/abi_x86.cc +4 -0
- package/src/koffi/src/ffi.cc +3 -48
- package/src/koffi/src/ffi.hh +2 -0
- package/src/koffi/src/util.cc +51 -30
- package/src/koffi/src/win32.cc +43 -0
- package/src/koffi/src/win32.hh +10 -4
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
### Koffi 2.6
|
|
6
6
|
|
|
7
|
+
#### Koffi 2.6.11 (2023-12-05)
|
|
8
|
+
|
|
9
|
+
- Speed up resolving simple and often used type names
|
|
10
|
+
- Fix use of optional length argument with [koffi.encode()](variables.md#encode-to-c-memory)
|
|
11
|
+
|
|
12
|
+
#### Koffi 2.6.10 (2023-11-29)
|
|
13
|
+
|
|
14
|
+
- Protect GetLastError() value from Node.js and V8 on Windows
|
|
15
|
+
|
|
7
16
|
#### Koffi 2.6.9 (2023-11-25)
|
|
8
17
|
|
|
9
18
|
- Search in DLL directory for additional dependencies on Windows
|
|
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
|
|
Binary file
|
package/doc/variables.md
CHANGED
|
@@ -54,7 +54,7 @@ There is also an optional ending `length` argument that you can use in two cases
|
|
|
54
54
|
- Use it to give the number of bytes to decode in non-NUL terminated strings: `koffi.decode(value, 'char *', 5)`
|
|
55
55
|
- Decode consecutive values into an array. For example, here is how you can decode an array with 3 float values: `koffi.decode(value, 'float', 3)`. This is equivalent to `koffi.decode(value, koffi.array('float', 3))`.
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
The example below will decode the symbol `my_string` defined above but only the first three bytes.
|
|
58
58
|
|
|
59
59
|
```js
|
|
60
60
|
// Only decode 3 bytes from the C string my_string
|
|
@@ -69,7 +69,7 @@ In Koffi 2.2 and earlier versions, the length argument is only used to decode st
|
|
|
69
69
|
|
|
70
70
|
*New in Koffi 2.6*
|
|
71
71
|
|
|
72
|
-
Use `koffi.encode()` to encode C pointers, wrapped as external objects or as simple numbers.
|
|
72
|
+
Use `koffi.encode()` to encode JS values into C symbols or pointers, wrapped as external objects or as simple numbers.
|
|
73
73
|
|
|
74
74
|
Some arguments are optional and this function can be called in several ways:
|
|
75
75
|
|
|
@@ -98,3 +98,9 @@ console.log(koffi.decode(my_string, 'const char *')) // Prints "Hello World!"
|
|
|
98
98
|
```
|
|
99
99
|
|
|
100
100
|
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.
|
|
101
|
+
|
|
102
|
+
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])`.
|
|
103
|
+
|
|
104
|
+
```{note}
|
|
105
|
+
The length argument did not work correctly before Koffi 2.6.11.
|
|
106
|
+
```
|
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.6.
|
|
382
|
-
stable: "2.6.
|
|
381
|
+
version: "2.6.11",
|
|
382
|
+
stable: "2.6.11",
|
|
383
383
|
description: "Fast and simple C FFI (foreign function interface) for Node.js",
|
|
384
384
|
keywords: [
|
|
385
385
|
"foreign",
|
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.6.
|
|
382
|
-
stable: "2.6.
|
|
381
|
+
version: "2.6.11",
|
|
382
|
+
stable: "2.6.11",
|
|
383
383
|
description: "Fast and simple C FFI (foreign function interface) for Node.js",
|
|
384
384
|
keywords: [
|
|
385
385
|
"foreign",
|
package/package.json
CHANGED
package/src/core/libcc/libcc.cc
CHANGED
|
@@ -931,6 +931,35 @@ static Span<char> FormatUnsignedToDecimal(uint64_t value, char out_buf[32])
|
|
|
931
931
|
return MakeSpan(out_buf + offset, 32 - offset);
|
|
932
932
|
}
|
|
933
933
|
|
|
934
|
+
static Span<char> FormatUnsignedToBinary(uint64_t value, char out_buf[64])
|
|
935
|
+
{
|
|
936
|
+
Size msb = 64 - (Size)CountLeadingZeros(value);
|
|
937
|
+
if (!msb) {
|
|
938
|
+
msb = 1;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
for (Size i = 0; i < msb; i++) {
|
|
942
|
+
bool bit = (value >> (msb - i - 1)) & 0x1;
|
|
943
|
+
out_buf[i] = bit ? '1' : '0';
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
return MakeSpan(out_buf, msb);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
static Span<char> FormatUnsignedToOctal(uint64_t value, char out_buf[64])
|
|
950
|
+
{
|
|
951
|
+
static const char literals[] = "012345678";
|
|
952
|
+
|
|
953
|
+
Size offset = 64;
|
|
954
|
+
do {
|
|
955
|
+
uint64_t digit = value & 0x7;
|
|
956
|
+
value >>= 3;
|
|
957
|
+
out_buf[--offset] = literals[digit];
|
|
958
|
+
} while (value);
|
|
959
|
+
|
|
960
|
+
return MakeSpan(out_buf + offset, 64 - offset);
|
|
961
|
+
}
|
|
962
|
+
|
|
934
963
|
static Span<char> FormatUnsignedToBigHex(uint64_t value, char out_buf[32])
|
|
935
964
|
{
|
|
936
965
|
static const char literals[] = "0123456789ABCDEF";
|
|
@@ -959,21 +988,6 @@ static Span<char> FormatUnsignedToSmallHex(uint64_t value, char out_buf[32])
|
|
|
959
988
|
return MakeSpan(out_buf + offset, 32 - offset);
|
|
960
989
|
}
|
|
961
990
|
|
|
962
|
-
static Span<char> FormatUnsignedToBinary(uint64_t value, char out_buf[64])
|
|
963
|
-
{
|
|
964
|
-
Size msb = 64 - (Size)CountLeadingZeros(value);
|
|
965
|
-
if (!msb) {
|
|
966
|
-
msb = 1;
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
for (Size i = 0; i < msb; i++) {
|
|
970
|
-
bool bit = (value >> (msb - i - 1)) & 0x1;
|
|
971
|
-
out_buf[i] = bit ? '1' : '0';
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
return MakeSpan(out_buf, msb);
|
|
975
|
-
}
|
|
976
|
-
|
|
977
991
|
#ifdef JKJ_HEADER_DRAGONBOX
|
|
978
992
|
static Size FakeFloatPrecision(Span<char> buf, int K, int min_prec, int max_prec, int *out_K)
|
|
979
993
|
{
|
|
@@ -1250,6 +1264,9 @@ static inline void ProcessArg(const FmtArg &arg, AppendFunc append)
|
|
|
1250
1264
|
case FmtType::Binary: {
|
|
1251
1265
|
out = FormatUnsignedToBinary(arg.u.u, num_buf);
|
|
1252
1266
|
} break;
|
|
1267
|
+
case FmtType::Octal: {
|
|
1268
|
+
out = FormatUnsignedToOctal(arg.u.u, num_buf);
|
|
1269
|
+
} break;
|
|
1253
1270
|
case FmtType::BigHex: {
|
|
1254
1271
|
out = FormatUnsignedToBigHex(arg.u.u, num_buf);
|
|
1255
1272
|
} break;
|
|
@@ -1480,6 +1497,7 @@ static inline void ProcessArg(const FmtArg &arg, AppendFunc append)
|
|
|
1480
1497
|
case FmtType::Integer:
|
|
1481
1498
|
case FmtType::Unsigned:
|
|
1482
1499
|
case FmtType::Binary:
|
|
1500
|
+
case FmtType::Octal:
|
|
1483
1501
|
case FmtType::BigHex:
|
|
1484
1502
|
case FmtType::SmallHex: {
|
|
1485
1503
|
switch (arg.u.span.type_len) {
|
|
@@ -2155,7 +2173,7 @@ fail:
|
|
|
2155
2173
|
return str_buf;
|
|
2156
2174
|
}
|
|
2157
2175
|
|
|
2158
|
-
static FileType FileAttributesToType(uint32_t attr)
|
|
2176
|
+
static inline FileType FileAttributesToType(uint32_t attr)
|
|
2159
2177
|
{
|
|
2160
2178
|
if (attr & FILE_ATTRIBUTE_DIRECTORY) {
|
|
2161
2179
|
return FileType::Directory;
|
package/src/core/libcc/libcc.hh
CHANGED
|
@@ -2862,6 +2862,7 @@ enum class FmtType {
|
|
|
2862
2862
|
Float,
|
|
2863
2863
|
Double,
|
|
2864
2864
|
Binary,
|
|
2865
|
+
Octal,
|
|
2865
2866
|
BigHex,
|
|
2866
2867
|
SmallHex,
|
|
2867
2868
|
MemorySize,
|
|
@@ -2960,6 +2961,13 @@ static inline FmtArg FmtBin(uint64_t u)
|
|
|
2960
2961
|
arg.u.u = u;
|
|
2961
2962
|
return arg;
|
|
2962
2963
|
}
|
|
2964
|
+
static inline FmtArg FmtOctal(uint64_t u)
|
|
2965
|
+
{
|
|
2966
|
+
FmtArg arg;
|
|
2967
|
+
arg.type = FmtType::Octal;
|
|
2968
|
+
arg.u.u = u;
|
|
2969
|
+
return arg;
|
|
2970
|
+
}
|
|
2963
2971
|
static inline FmtArg FmtHex(uint64_t u, FmtType type = FmtType::BigHex)
|
|
2964
2972
|
{
|
|
2965
2973
|
RG_ASSERT(type == FmtType::BigHex || type == FmtType::SmallHex);
|
|
@@ -577,6 +577,8 @@ void CallData::Execute(const FunctionInfo *func, void *native)
|
|
|
577
577
|
teb->StackLimit = limit;
|
|
578
578
|
teb->DeallocationStack = dealloc;
|
|
579
579
|
teb->GuaranteedStackBytes = guaranteed;
|
|
580
|
+
|
|
581
|
+
instance->last_error = teb->LastErrorValue;
|
|
580
582
|
};
|
|
581
583
|
|
|
582
584
|
// Adjust stack limits so SEH works correctly
|
|
@@ -585,6 +587,8 @@ void CallData::Execute(const FunctionInfo *func, void *native)
|
|
|
585
587
|
teb->StackLimit = mem->stack0.ptr;
|
|
586
588
|
teb->DeallocationStack = mem->stack0.ptr;
|
|
587
589
|
teb->GuaranteedStackBytes = 0;
|
|
590
|
+
|
|
591
|
+
teb->LastErrorValue = instance->last_error;
|
|
588
592
|
#endif
|
|
589
593
|
|
|
590
594
|
#define PERFORM_CALL(Suffix) \
|
|
@@ -239,6 +239,8 @@ void CallData::Execute(const FunctionInfo *func, void *native)
|
|
|
239
239
|
teb->StackLimit = limit;
|
|
240
240
|
teb->DeallocationStack = dealloc;
|
|
241
241
|
teb->GuaranteedStackBytes = guaranteed;
|
|
242
|
+
|
|
243
|
+
instance->last_error = teb->LastErrorValue;
|
|
242
244
|
};
|
|
243
245
|
|
|
244
246
|
// Adjust stack limits so SEH works correctly
|
|
@@ -248,6 +250,8 @@ void CallData::Execute(const FunctionInfo *func, void *native)
|
|
|
248
250
|
teb->DeallocationStack = mem->stack0.ptr;
|
|
249
251
|
teb->GuaranteedStackBytes = 0;
|
|
250
252
|
|
|
253
|
+
teb->LastErrorValue = instance->last_error;
|
|
254
|
+
|
|
251
255
|
#define PERFORM_CALL(Suffix) \
|
|
252
256
|
([&]() { \
|
|
253
257
|
auto ret = (func->forward_fp ? ForwardCallX ## Suffix(native, new_sp, &old_sp) \
|
package/src/koffi/src/abi_x86.cc
CHANGED
|
@@ -336,6 +336,8 @@ void CallData::Execute(const FunctionInfo *func, void *native)
|
|
|
336
336
|
teb->StackLimit = limit;
|
|
337
337
|
teb->DeallocationStack = dealloc;
|
|
338
338
|
teb->GuaranteedStackBytes = guaranteed;
|
|
339
|
+
|
|
340
|
+
instance->last_error = teb->LastErrorValue;
|
|
339
341
|
};
|
|
340
342
|
|
|
341
343
|
// Adjust stack limits so SEH works correctly
|
|
@@ -344,6 +346,8 @@ void CallData::Execute(const FunctionInfo *func, void *native)
|
|
|
344
346
|
teb->StackLimit = mem->stack0.ptr;
|
|
345
347
|
teb->DeallocationStack = mem->stack0.ptr;
|
|
346
348
|
teb->GuaranteedStackBytes = 0;
|
|
349
|
+
|
|
350
|
+
teb->LastErrorValue = instance->last_error;
|
|
347
351
|
#endif
|
|
348
352
|
|
|
349
353
|
#define PERFORM_CALL(Suffix) \
|
package/src/koffi/src/ffi.cc
CHANGED
|
@@ -1639,51 +1639,6 @@ static Napi::Value UnloadLibrary(const Napi::CallbackInfo &info)
|
|
|
1639
1639
|
return env.Undefined();
|
|
1640
1640
|
}
|
|
1641
1641
|
|
|
1642
|
-
#ifdef _WIN32
|
|
1643
|
-
static HANDLE LoadWindowsLibrary(Napi::Env env, Span<const char> path)
|
|
1644
|
-
{
|
|
1645
|
-
BlockAllocator temp_alloc;
|
|
1646
|
-
|
|
1647
|
-
Span<wchar_t> filename_w = AllocateSpan<wchar_t>(&temp_alloc, path.len + 1);
|
|
1648
|
-
|
|
1649
|
-
if (ConvertUtf8ToWin32Wide(path, filename_w) < 0)
|
|
1650
|
-
return nullptr;
|
|
1651
|
-
|
|
1652
|
-
HMODULE module = LoadLibraryW(filename_w.ptr);
|
|
1653
|
-
|
|
1654
|
-
if (!module) {
|
|
1655
|
-
DWORD flags = LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR;
|
|
1656
|
-
|
|
1657
|
-
Span<const char> filename = NormalizePath(path, GetWorkingDirectory(), &temp_alloc);
|
|
1658
|
-
Span<wchar_t> filename_w = AllocateSpan<wchar_t>(&temp_alloc, filename.len + 1);
|
|
1659
|
-
|
|
1660
|
-
if (ConvertUtf8ToWin32Wide(filename, filename_w) < 0)
|
|
1661
|
-
return nullptr;
|
|
1662
|
-
|
|
1663
|
-
module = LoadLibraryExW(filename_w.ptr, nullptr, flags);
|
|
1664
|
-
}
|
|
1665
|
-
|
|
1666
|
-
if (!module) {
|
|
1667
|
-
if (GetLastError() == ERROR_BAD_EXE_FORMAT) {
|
|
1668
|
-
int process = GetSelfMachine();
|
|
1669
|
-
int dll = GetDllMachine(filename_w.ptr);
|
|
1670
|
-
|
|
1671
|
-
if (process >= 0 && dll >= 0 && dll != process) {
|
|
1672
|
-
ThrowError<Napi::Error>(env, "Cannot load '%1' DLL in '%2' process",
|
|
1673
|
-
WindowsMachineNames.FindValue(dll, "Unknown"),
|
|
1674
|
-
WindowsMachineNames.FindValue(process, "Unknown"));
|
|
1675
|
-
return nullptr;
|
|
1676
|
-
}
|
|
1677
|
-
}
|
|
1678
|
-
|
|
1679
|
-
ThrowError<Napi::Error>(env, "Failed to load shared library: %1", GetWin32ErrorString());
|
|
1680
|
-
return nullptr;
|
|
1681
|
-
}
|
|
1682
|
-
|
|
1683
|
-
return module;
|
|
1684
|
-
}
|
|
1685
|
-
#endif
|
|
1686
|
-
|
|
1687
1642
|
static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
|
|
1688
1643
|
{
|
|
1689
1644
|
Napi::Env env = info.Env();
|
|
@@ -2011,7 +1966,7 @@ static Napi::Value EncodeValue(const Napi::CallbackInfo &info)
|
|
|
2011
1966
|
Napi::Env env = info.Env();
|
|
2012
1967
|
|
|
2013
1968
|
bool has_offset = (info.Length() >= 2 && info[1].IsNumber());
|
|
2014
|
-
bool has_len = (info.Length() >= 4u + has_offset && info[
|
|
1969
|
+
bool has_len = (info.Length() >= 4u + has_offset && info[3u + has_offset].IsNumber());
|
|
2015
1970
|
|
|
2016
1971
|
if (info.Length() < 3u + has_offset) [[unlikely]] {
|
|
2017
1972
|
ThrowError<Napi::TypeError>(env, "Expected %1 to 5 arguments, got %2", 3 + has_offset, info.Length());
|
|
@@ -2024,10 +1979,10 @@ static Napi::Value EncodeValue(const Napi::CallbackInfo &info)
|
|
|
2024
1979
|
|
|
2025
1980
|
Napi::Value ref = info[0];
|
|
2026
1981
|
int64_t offset = has_offset ? info[1].As<Napi::Number>().Int64Value() : 0;
|
|
2027
|
-
Napi::Value value = info[2u + has_offset
|
|
1982
|
+
Napi::Value value = info[2u + has_offset];
|
|
2028
1983
|
|
|
2029
1984
|
if (has_len) {
|
|
2030
|
-
Size len = info[
|
|
1985
|
+
Size len = info[3u + has_offset].As<Napi::Number>();
|
|
2031
1986
|
|
|
2032
1987
|
if (!Encode(ref, offset, value, type, &len))
|
|
2033
1988
|
return env.Null();
|
package/src/koffi/src/ffi.hh
CHANGED
package/src/koffi/src/util.cc
CHANGED
|
@@ -117,13 +117,28 @@ const TypeInfo *ResolveType(Napi::Value value, int *out_directions)
|
|
|
117
117
|
|
|
118
118
|
if (value.IsString()) {
|
|
119
119
|
std::string str = value.As<Napi::String>();
|
|
120
|
-
const TypeInfo *type = ResolveType(env, str.c_str(), out_directions);
|
|
121
120
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
121
|
+
// Quick path for known types (int, float *, etc.)
|
|
122
|
+
const TypeInfo *type = instance->types_map.FindValue(str.c_str(), nullptr);
|
|
123
|
+
|
|
124
|
+
if (!type || (type->flags & (int)TypeFlag::IsIncomplete)) {
|
|
125
|
+
type = ResolveType(env, str.c_str(), out_directions);
|
|
126
|
+
|
|
127
|
+
if (!type) {
|
|
128
|
+
if (!env.IsExceptionPending()) {
|
|
129
|
+
ThrowError<Napi::TypeError>(env, "Unknown or invalid type name '%1'", str.c_str());
|
|
130
|
+
}
|
|
131
|
+
return nullptr;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Cache for quick future access
|
|
135
|
+
bool inserted;
|
|
136
|
+
auto bucket = instance->types_map.TrySetDefault(str.c_str(), &inserted);
|
|
137
|
+
|
|
138
|
+
if (inserted) {
|
|
139
|
+
bucket->key = DuplicateString(str.c_str(), &instance->str_alloc).ptr;
|
|
140
|
+
bucket->value = type;
|
|
125
141
|
}
|
|
126
|
-
return nullptr;
|
|
127
142
|
}
|
|
128
143
|
|
|
129
144
|
return type;
|
|
@@ -200,48 +215,54 @@ const TypeInfo *ResolveType(Napi::Env env, Span<const char> str, int *out_direct
|
|
|
200
215
|
}
|
|
201
216
|
}
|
|
202
217
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
str = TrimStr(str);
|
|
208
|
-
}
|
|
209
|
-
str = TrimStr(str);
|
|
210
|
-
|
|
211
|
-
Span<const char> remain = str;
|
|
218
|
+
Span<const char> name;
|
|
219
|
+
Span<const char> after;
|
|
220
|
+
{
|
|
221
|
+
Span<const char> remain = str;
|
|
212
222
|
|
|
213
|
-
|
|
214
|
-
|
|
223
|
+
// Skip initial const qualifiers
|
|
224
|
+
remain = TrimStr(remain);
|
|
225
|
+
while (SplitIdentifier(remain) == "const") {
|
|
226
|
+
remain = remain.Take(6, remain.len - 6);
|
|
227
|
+
remain = TrimStr(remain);
|
|
228
|
+
}
|
|
215
229
|
remain = TrimStr(remain);
|
|
216
230
|
|
|
217
|
-
|
|
218
|
-
if (!token.len)
|
|
219
|
-
break;
|
|
220
|
-
remain = remain.Take(token.len, remain.len - token.len);
|
|
221
|
-
}
|
|
231
|
+
after = remain;
|
|
222
232
|
|
|
223
|
-
|
|
233
|
+
// Consume one or more identifiers (e.g. unsigned int)
|
|
234
|
+
for (;;) {
|
|
235
|
+
after = TrimStr(after);
|
|
236
|
+
|
|
237
|
+
Span<const char> token = SplitIdentifier(after);
|
|
238
|
+
if (!token.len)
|
|
239
|
+
break;
|
|
240
|
+
after = after.Take(token.len, after.len - token.len);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
name = TrimStr(MakeSpan(remain.ptr, after.ptr - remain.ptr));
|
|
244
|
+
}
|
|
224
245
|
|
|
225
246
|
// Consume pointer indirections
|
|
226
|
-
while (
|
|
227
|
-
if (
|
|
228
|
-
|
|
247
|
+
while (after.len) {
|
|
248
|
+
if (after[0] == '*') {
|
|
249
|
+
after = after.Take(1, after.len - 1);
|
|
229
250
|
indirect++;
|
|
230
251
|
|
|
231
252
|
if (indirect >= RG_SIZE(disposables) * 8) [[unlikely]] {
|
|
232
253
|
ThrowError<Napi::Error>(env, "Too many pointer indirections");
|
|
233
254
|
return nullptr;
|
|
234
255
|
}
|
|
235
|
-
} else if (
|
|
236
|
-
|
|
256
|
+
} else if (after[0] == '!') {
|
|
257
|
+
after = after.Take(1, after.len - 1);
|
|
237
258
|
disposables |= (1u << indirect);
|
|
238
|
-
} else if (SplitIdentifier(
|
|
239
|
-
|
|
259
|
+
} else if (SplitIdentifier(after) == "const") {
|
|
260
|
+
after = after.Take(6, after.len - 6);
|
|
240
261
|
} else {
|
|
241
262
|
break;
|
|
242
263
|
}
|
|
243
264
|
|
|
244
|
-
|
|
265
|
+
after = TrimStr(after);
|
|
245
266
|
}
|
|
246
267
|
|
|
247
268
|
const TypeInfo *type = instance->types_map.FindValue(name, nullptr);
|
package/src/koffi/src/win32.cc
CHANGED
|
@@ -67,6 +67,49 @@ const HashMap<int, const char *> WindowsMachineNames = {
|
|
|
67
67
|
{ 0x169, "MIPS little-endian WCE v2" }
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
+
HANDLE LoadWindowsLibrary(Napi::Env env, Span<const char> path)
|
|
71
|
+
{
|
|
72
|
+
BlockAllocator temp_alloc;
|
|
73
|
+
|
|
74
|
+
Span<wchar_t> filename_w = AllocateSpan<wchar_t>(&temp_alloc, path.len + 1);
|
|
75
|
+
|
|
76
|
+
if (ConvertUtf8ToWin32Wide(path, filename_w) < 0)
|
|
77
|
+
return nullptr;
|
|
78
|
+
|
|
79
|
+
HMODULE module = LoadLibraryW(filename_w.ptr);
|
|
80
|
+
|
|
81
|
+
if (!module) {
|
|
82
|
+
DWORD flags = LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR;
|
|
83
|
+
|
|
84
|
+
Span<const char> filename = NormalizePath(path, GetWorkingDirectory(), &temp_alloc);
|
|
85
|
+
Span<wchar_t> filename_w = AllocateSpan<wchar_t>(&temp_alloc, filename.len + 1);
|
|
86
|
+
|
|
87
|
+
if (ConvertUtf8ToWin32Wide(filename, filename_w) < 0)
|
|
88
|
+
return nullptr;
|
|
89
|
+
|
|
90
|
+
module = LoadLibraryExW(filename_w.ptr, nullptr, flags);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!module) {
|
|
94
|
+
if (GetLastError() == ERROR_BAD_EXE_FORMAT) {
|
|
95
|
+
int process = GetSelfMachine();
|
|
96
|
+
int dll = GetDllMachine(filename_w.ptr);
|
|
97
|
+
|
|
98
|
+
if (process >= 0 && dll >= 0 && dll != process) {
|
|
99
|
+
ThrowError<Napi::Error>(env, "Cannot load '%1' DLL in '%2' process",
|
|
100
|
+
WindowsMachineNames.FindValue(dll, "Unknown"),
|
|
101
|
+
WindowsMachineNames.FindValue(process, "Unknown"));
|
|
102
|
+
return nullptr;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
ThrowError<Napi::Error>(env, "Failed to load shared library: %1", GetWin32ErrorString());
|
|
107
|
+
return nullptr;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return module;
|
|
111
|
+
}
|
|
112
|
+
|
|
70
113
|
// Fails silently on purpose
|
|
71
114
|
static bool ReadAt(HANDLE h, int32_t offset, void *buf, int len)
|
|
72
115
|
{
|
package/src/koffi/src/win32.hh
CHANGED
|
@@ -72,9 +72,11 @@ struct TEB {
|
|
|
72
72
|
void *ExceptionList;
|
|
73
73
|
void *StackBase;
|
|
74
74
|
void *StackLimit;
|
|
75
|
-
char _pad1[
|
|
75
|
+
char _pad1[80];
|
|
76
|
+
unsigned long LastErrorValue;
|
|
77
|
+
char _pad2[5132];
|
|
76
78
|
void *DeallocationStack;
|
|
77
|
-
char
|
|
79
|
+
char _pad3[712];
|
|
78
80
|
uint32_t GuaranteedStackBytes;
|
|
79
81
|
};
|
|
80
82
|
static_assert(RG_OFFSET_OF(TEB, DeallocationStack) == 0x1478);
|
|
@@ -86,9 +88,11 @@ struct TEB {
|
|
|
86
88
|
void *ExceptionList;
|
|
87
89
|
void *StackBase;
|
|
88
90
|
void *StackLimit;
|
|
89
|
-
char _pad1[
|
|
91
|
+
char _pad1[40];
|
|
92
|
+
unsigned long LastErrorValue;
|
|
93
|
+
char _pad2[3540];
|
|
90
94
|
void *DeallocationStack;
|
|
91
|
-
char
|
|
95
|
+
char _pad3[360];
|
|
92
96
|
uint32_t GuaranteedStackBytes;
|
|
93
97
|
};
|
|
94
98
|
static_assert(RG_OFFSET_OF(TEB, DeallocationStack) == 0xE0C);
|
|
@@ -111,6 +115,8 @@ static inline TEB *GetTEB()
|
|
|
111
115
|
|
|
112
116
|
extern const HashMap<int, const char *> WindowsMachineNames;
|
|
113
117
|
|
|
118
|
+
void *LoadWindowsLibrary(Napi::Env env, Span<const char> path); // Returns HANDLE
|
|
119
|
+
|
|
114
120
|
int GetSelfMachine();
|
|
115
121
|
int GetDllMachine(const wchar_t *filename);
|
|
116
122
|
|