koffi 2.8.11 → 2.9.0-beta.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 +12 -1
- 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_i386/koffi.node +0 -0
- package/build/koffi/freebsd_x64/koffi.node +0 -0
- package/build/koffi/linux_arm32/koffi.node +0 -0
- package/build/koffi/linux_arm64/koffi.node +0 -0
- package/build/koffi/linux_i386/koffi.node +0 -0
- package/build/koffi/linux_riscv64/koffi.node +0 -0
- package/build/koffi/linux_x64/koffi.node +0 -0
- package/build/koffi/musl_x64/koffi.node +0 -0
- package/build/koffi/openbsd_i386/koffi.node +0 -0
- package/build/koffi/openbsd_x64/koffi.node +0 -0
- package/build/koffi/windows_arm64/koffi.node +0 -0
- package/build/koffi/{win32_ia32 → windows_i386}/koffi.node +0 -0
- package/build/koffi/{win32_x64 → windows_x64}/koffi.node +0 -0
- package/doc/contribute.md +3 -2
- package/doc/input.md +23 -13
- package/index.js +160 -97
- package/indirect.js +113 -81
- package/package.json +2 -2
- package/src/koffi/CMakeLists.txt +11 -1
- package/src/koffi/src/abi_arm32.cc +23 -0
- package/src/koffi/src/abi_arm64.cc +30 -0
- package/src/koffi/src/abi_riscv64.cc +22 -0
- package/src/koffi/src/abi_x64_sysv.cc +23 -0
- package/src/koffi/src/abi_x64_win.cc +23 -0
- package/src/koffi/src/abi_x86.cc +22 -0
- package/src/koffi/src/call.cc +155 -5
- package/src/koffi/src/call.hh +3 -0
- package/src/koffi/src/ffi.cc +26 -4
- package/src/koffi/src/ffi.hh +4 -0
- package/src/koffi/src/init.js +122 -0
- package/src/koffi/src/util.cc +85 -2
- package/src/koffi/src/util.hh +13 -0
- package/build/koffi/freebsd_ia32/koffi.node +0 -0
- package/build/koffi/linux_armhf/koffi.node +0 -0
- package/build/koffi/linux_ia32/koffi.node +0 -0
- package/build/koffi/linux_riscv64d/koffi.node +0 -0
- package/build/koffi/openbsd_ia32/koffi.node +0 -0
- package/build/koffi/win32_arm64/koffi.node +0 -0
- /package/build/koffi/{win32_arm64 → windows_arm64}/koffi.exp +0 -0
- /package/build/koffi/{win32_arm64 → windows_arm64}/koffi.lib +0 -0
- /package/build/koffi/{win32_ia32 → windows_i386}/koffi.exp +0 -0
- /package/build/koffi/{win32_ia32 → windows_i386}/koffi.lib +0 -0
- /package/build/koffi/{win32_x64 → windows_x64}/koffi.exp +0 -0
- /package/build/koffi/{win32_x64 → windows_x64}/koffi.lib +0 -0
package/src/koffi/src/abi_x86.cc
CHANGED
|
@@ -238,6 +238,13 @@ bool CallData::Prepare(const FunctionInfo *func, const Napi::CallbackInfo &info)
|
|
|
238
238
|
|
|
239
239
|
*(const char16_t **)((param.fast ? fast_ptr : args_ptr)++) = str16;
|
|
240
240
|
} break;
|
|
241
|
+
case PrimitiveKind::String32: {
|
|
242
|
+
const char32_t *str32;
|
|
243
|
+
if (!PushString32(value, param.directions, &str32)) [[unlikely]]
|
|
244
|
+
return false;
|
|
245
|
+
|
|
246
|
+
*(const char32_t **)((param.fast ? fast_ptr : args_ptr)++) = str32;
|
|
247
|
+
} break;
|
|
241
248
|
case PrimitiveKind::Pointer: {
|
|
242
249
|
void *ptr;
|
|
243
250
|
if (!PushPointer(value, param.type, param.directions, &ptr)) [[unlikely]]
|
|
@@ -380,6 +387,7 @@ void CallData::Execute(const FunctionInfo *func, void *native)
|
|
|
380
387
|
case PrimitiveKind::UInt64S:
|
|
381
388
|
case PrimitiveKind::String:
|
|
382
389
|
case PrimitiveKind::String16:
|
|
390
|
+
case PrimitiveKind::String32:
|
|
383
391
|
case PrimitiveKind::Pointer:
|
|
384
392
|
case PrimitiveKind::Callback: { result.u64 = PERFORM_CALL(G); } break;
|
|
385
393
|
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
|
@@ -438,6 +446,7 @@ Napi::Value CallData::Complete(const FunctionInfo *func)
|
|
|
438
446
|
case PrimitiveKind::UInt64S: return NewBigInt(env, ReverseBytes(result.u64));
|
|
439
447
|
case PrimitiveKind::String: return result.ptr ? Napi::String::New(env, (const char *)result.ptr) : env.Null();
|
|
440
448
|
case PrimitiveKind::String16: return result.ptr ? Napi::String::New(env, (const char16_t *)result.ptr) : env.Null();
|
|
449
|
+
case PrimitiveKind::String32: return result.ptr ? MakeStringFromUTF32(env, (const char32_t *)result.ptr) : env.Null();
|
|
441
450
|
case PrimitiveKind::Pointer:
|
|
442
451
|
case PrimitiveKind::Callback: {
|
|
443
452
|
if (result.ptr) {
|
|
@@ -652,6 +661,12 @@ void CallData::Relay(Size idx, uint8_t *, uint8_t *caller_sp, bool switch_stack,
|
|
|
652
661
|
param.type->dispose(env, param.type, str16);
|
|
653
662
|
}
|
|
654
663
|
} break;
|
|
664
|
+
case PrimitiveKind::String32: {
|
|
665
|
+
const char32_t *str32 = *(const char32_t **)(args_ptr++);
|
|
666
|
+
|
|
667
|
+
Napi::Value arg = str32 ? MakeStringFromUTF32(env, str32) : env.Null();
|
|
668
|
+
arguments.Append(arg);
|
|
669
|
+
} break;
|
|
655
670
|
case PrimitiveKind::Pointer:
|
|
656
671
|
case PrimitiveKind::Callback: {
|
|
657
672
|
void *ptr2 = *(void **)(args_ptr++);
|
|
@@ -798,6 +813,13 @@ void CallData::Relay(Size idx, uint8_t *, uint8_t *caller_sp, bool switch_stack,
|
|
|
798
813
|
|
|
799
814
|
out_reg->eax = (uint32_t)str16;
|
|
800
815
|
} break;
|
|
816
|
+
case PrimitiveKind::String32: {
|
|
817
|
+
const char32_t *str32;
|
|
818
|
+
if (!PushString32(value, 1, &str32)) [[unlikely]]
|
|
819
|
+
return;
|
|
820
|
+
|
|
821
|
+
out_reg->eax = (uint32_t)str32;
|
|
822
|
+
} break;
|
|
801
823
|
case PrimitiveKind::Pointer: {
|
|
802
824
|
uint8_t *ptr;
|
|
803
825
|
|
package/src/koffi/src/call.cc
CHANGED
|
@@ -234,7 +234,8 @@ Size CallData::PushStringValue(Napi::Value value, const char **out_str)
|
|
|
234
234
|
status = napi_get_value_string_utf8(env, value, nullptr, 0, &len);
|
|
235
235
|
RG_ASSERT(status == napi_ok);
|
|
236
236
|
|
|
237
|
-
|
|
237
|
+
len++;
|
|
238
|
+
buf = AllocateSpan<char>(&call_alloc, (Size)len);
|
|
238
239
|
|
|
239
240
|
status = napi_get_value_string_utf8(env, value, buf.ptr, (size_t)buf.len, &len);
|
|
240
241
|
RG_ASSERT(status == napi_ok);
|
|
@@ -290,7 +291,7 @@ bool CallData::PushString16(Napi::Value value, int directions, const char16_t **
|
|
|
290
291
|
type->name = "<temporary>";
|
|
291
292
|
|
|
292
293
|
type->primitive = PrimitiveKind::Array;
|
|
293
|
-
type->align =
|
|
294
|
+
type->align = 2;
|
|
294
295
|
type->size = (int32_t)(len * 2);
|
|
295
296
|
type->ref.type = instance->char16_type;
|
|
296
297
|
type->hint = ArrayHint::String;
|
|
@@ -335,7 +336,8 @@ Size CallData::PushString16Value(Napi::Value value, const char16_t **out_str16)
|
|
|
335
336
|
status = napi_get_value_string_utf16(env, value, nullptr, 0, &len);
|
|
336
337
|
RG_ASSERT(status == napi_ok);
|
|
337
338
|
|
|
338
|
-
|
|
339
|
+
len++;
|
|
340
|
+
buf = AllocateSpan<char16_t>(&call_alloc, (Size)len);
|
|
339
341
|
|
|
340
342
|
status = napi_get_value_string_utf16(env, value, buf.ptr, (size_t)buf.len, &len);
|
|
341
343
|
RG_ASSERT(status == napi_ok);
|
|
@@ -347,6 +349,116 @@ Size CallData::PushString16Value(Napi::Value value, const char16_t **out_str16)
|
|
|
347
349
|
return (Size)len;
|
|
348
350
|
}
|
|
349
351
|
|
|
352
|
+
bool CallData::PushString32(Napi::Value value, int directions, const char32_t **out_str32)
|
|
353
|
+
{
|
|
354
|
+
if (value.IsString()) {
|
|
355
|
+
if (directions & 2) [[unlikely]] {
|
|
356
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected string", GetValueType(instance, value));
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
PushString32Value(value, out_str32);
|
|
361
|
+
return true;
|
|
362
|
+
} else if (IsNullOrUndefined(value)) {
|
|
363
|
+
*out_str32 = nullptr;
|
|
364
|
+
return true;
|
|
365
|
+
} else if (value.IsArray()) {
|
|
366
|
+
Napi::Array array = value.As<Napi::Array>();
|
|
367
|
+
|
|
368
|
+
if (!(directions & 2)) [[unlikely]] {
|
|
369
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected string", GetValueType(instance, value));
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
if (array.Length() != 1) [[unlikely]] {
|
|
373
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected [string]", GetValueType(instance, value));
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
value = array[0u];
|
|
378
|
+
|
|
379
|
+
if (!value.IsString()) [[unlikely]] {
|
|
380
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected [string]", GetValueType(instance, array[0u]));
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
Size len = PushString32Value(value, out_str32);
|
|
385
|
+
if (len < 0) [[unlikely]]
|
|
386
|
+
return false;
|
|
387
|
+
|
|
388
|
+
// Create array type
|
|
389
|
+
TypeInfo *type;
|
|
390
|
+
{
|
|
391
|
+
type = AllocateOne<TypeInfo>(&call_alloc, (int)AllocFlag::Zero);
|
|
392
|
+
|
|
393
|
+
type->name = "<temporary>";
|
|
394
|
+
|
|
395
|
+
type->primitive = PrimitiveKind::Array;
|
|
396
|
+
type->align = 4;
|
|
397
|
+
type->size = (int32_t)(len * 4);
|
|
398
|
+
type->ref.type = instance->char32_type;
|
|
399
|
+
type->hint = ArrayHint::String;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Prepare output argument
|
|
403
|
+
{
|
|
404
|
+
OutArgument *out = out_arguments.AppendDefault();
|
|
405
|
+
|
|
406
|
+
napi_status status = napi_create_reference(env, array, 1, &out->ref);
|
|
407
|
+
RG_ASSERT(status == napi_ok);
|
|
408
|
+
|
|
409
|
+
out->kind = OutArgument::Kind::Array;
|
|
410
|
+
out->ptr = (const uint8_t *)*out_str32;
|
|
411
|
+
out->type = type;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
return true;
|
|
415
|
+
} else {
|
|
416
|
+
return PushPointer(value, instance->str32_type, directions, (void **)out_str32);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
Size CallData::PushString32Value(Napi::Value value, const char32_t **out_str32)
|
|
421
|
+
{
|
|
422
|
+
Span<char32_t> buf;
|
|
423
|
+
|
|
424
|
+
Span<const char16_t> buf16;
|
|
425
|
+
buf16.len = PushString16Value(value, &buf16.ptr);
|
|
426
|
+
if (buf16.len < 0) [[unlikely]]
|
|
427
|
+
return -1;
|
|
428
|
+
|
|
429
|
+
buf.ptr = (char32_t *)mem->heap.ptr;
|
|
430
|
+
buf.len = std::max((Size)0, mem->heap.len - Kibibytes(32)) / 4;
|
|
431
|
+
|
|
432
|
+
if (buf16.len < buf.len) [[likely]] {
|
|
433
|
+
mem->heap.ptr += buf16.len * 4;
|
|
434
|
+
mem->heap.len -= buf16.len * 4;
|
|
435
|
+
} else {
|
|
436
|
+
buf = AllocateSpan<char32_t>(&call_alloc, buf16.len);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
Size j = 0;
|
|
440
|
+
for (Size i = 0; i < buf16.len; i++) {
|
|
441
|
+
char32_t uc = buf16[i];
|
|
442
|
+
|
|
443
|
+
if (uc >= 0xD800 && uc <= 0xDBFF) {
|
|
444
|
+
char16_t uc2 = buf16.ptr[++i];
|
|
445
|
+
|
|
446
|
+
if (uc2 >= 0xDC00 && uc2 <= 0xDFFF) {
|
|
447
|
+
uc = ((uc - 0xD800) << 10) + (uc2 - 0xDC00) + 0x10000u;
|
|
448
|
+
} else {
|
|
449
|
+
uc = '?';
|
|
450
|
+
}
|
|
451
|
+
} else if (uc >= 0xDC00 && uc <= 0xDFFF) {
|
|
452
|
+
uc = '?';
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
buf[j++] = uc;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
*out_str32 = buf.ptr;
|
|
459
|
+
return j;
|
|
460
|
+
}
|
|
461
|
+
|
|
350
462
|
bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origin)
|
|
351
463
|
{
|
|
352
464
|
RG_ASSERT(IsObject(obj));
|
|
@@ -566,6 +678,13 @@ bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origi
|
|
|
566
678
|
|
|
567
679
|
*(const char16_t **)dest = str16;
|
|
568
680
|
} break;
|
|
681
|
+
case PrimitiveKind::String32: {
|
|
682
|
+
const char32_t *str32;
|
|
683
|
+
if (!PushString32(value, 1, &str32)) [[unlikely]]
|
|
684
|
+
return false;
|
|
685
|
+
|
|
686
|
+
*(const char32_t **)dest = str32;
|
|
687
|
+
} break;
|
|
569
688
|
case PrimitiveKind::Pointer: {
|
|
570
689
|
void *ptr;
|
|
571
690
|
if (!PushPointer(value, member.type, 1, &ptr)) [[unlikely]]
|
|
@@ -795,6 +914,15 @@ bool CallData::PushNormalArray(Napi::Array array, Size len, const TypeInfo *type
|
|
|
795
914
|
*(const char16_t **)dest = str16;
|
|
796
915
|
});
|
|
797
916
|
} break;
|
|
917
|
+
case PrimitiveKind::String32: {
|
|
918
|
+
PUSH_ARRAY(true, "string", {
|
|
919
|
+
const char32_t *str32;
|
|
920
|
+
if (!PushString32(value, 1, &str32)) [[unlikely]]
|
|
921
|
+
return false;
|
|
922
|
+
|
|
923
|
+
*(const char32_t **)dest = str32;
|
|
924
|
+
});
|
|
925
|
+
} break;
|
|
798
926
|
case PrimitiveKind::Pointer: {
|
|
799
927
|
PUSH_ARRAY(true, ref->name, {
|
|
800
928
|
void *ptr;
|
|
@@ -975,7 +1103,8 @@ bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directio
|
|
|
975
1103
|
case napi_external: {
|
|
976
1104
|
RG_ASSERT(type->primitive == PrimitiveKind::Pointer ||
|
|
977
1105
|
type->primitive == PrimitiveKind::String ||
|
|
978
|
-
type->primitive == PrimitiveKind::String16
|
|
1106
|
+
type->primitive == PrimitiveKind::String16 ||
|
|
1107
|
+
type->primitive == PrimitiveKind::String32);
|
|
979
1108
|
|
|
980
1109
|
if (!CheckValueTag(instance, value, type->ref.marker) &&
|
|
981
1110
|
!CheckValueTag(instance, value, instance->void_type) &&
|
|
@@ -1002,7 +1131,11 @@ bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directio
|
|
|
1002
1131
|
return false;
|
|
1003
1132
|
}
|
|
1004
1133
|
|
|
1005
|
-
|
|
1134
|
+
switch (type->ref.type->size) {
|
|
1135
|
+
default: { out_kind = OutArgument::Kind::String; } break;
|
|
1136
|
+
case 2: { out_kind = OutArgument::Kind::String16; } break;
|
|
1137
|
+
case 4: { out_kind = OutArgument::Kind::String32; } break;
|
|
1138
|
+
}
|
|
1006
1139
|
out_max_len = len;
|
|
1007
1140
|
} else {
|
|
1008
1141
|
if (!type->ref.type->size) [[unlikely]] {
|
|
@@ -1089,6 +1222,9 @@ bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directio
|
|
|
1089
1222
|
} else if (type->ref.type->primitive == PrimitiveKind::Int16) {
|
|
1090
1223
|
PushString16Value(value, (const char16_t **)out_ptr);
|
|
1091
1224
|
return true;
|
|
1225
|
+
} else if (type->ref.type->primitive == PrimitiveKind::Int32) {
|
|
1226
|
+
PushString32Value(value, (const char32_t **)out_ptr);
|
|
1227
|
+
return true;
|
|
1092
1228
|
} else {
|
|
1093
1229
|
goto unexpected;
|
|
1094
1230
|
}
|
|
@@ -1152,6 +1288,8 @@ Size CallData::PushIndirectString(Napi::Array array, const TypeInfo *ref, uint8_
|
|
|
1152
1288
|
return PushStringValue(value, (const char **)out_ptr);
|
|
1153
1289
|
} else if (ref->primitive == PrimitiveKind::Int16) {
|
|
1154
1290
|
return PushString16Value(value, (const char16_t **)out_ptr);
|
|
1291
|
+
} else if (ref->primitive == PrimitiveKind::Int32) {
|
|
1292
|
+
return PushString32Value(value, (const char32_t **)out_ptr);
|
|
1155
1293
|
} else {
|
|
1156
1294
|
return -1;
|
|
1157
1295
|
}
|
|
@@ -1267,6 +1405,18 @@ void CallData::PopOutArguments()
|
|
|
1267
1405
|
array.Set(0u, str);
|
|
1268
1406
|
} break;
|
|
1269
1407
|
|
|
1408
|
+
case OutArgument::Kind::String32: {
|
|
1409
|
+
Napi::Array array(env, value);
|
|
1410
|
+
|
|
1411
|
+
RG_ASSERT(array.IsArray());
|
|
1412
|
+
RG_ASSERT(array.Length() == 1);
|
|
1413
|
+
|
|
1414
|
+
Size len = NullTerminatedLength((const char32_t *)out.ptr, out.max_len);
|
|
1415
|
+
Napi::String str = MakeStringFromUTF32(env, (const char32_t *)out.ptr, len);
|
|
1416
|
+
|
|
1417
|
+
array.Set(0u, str);
|
|
1418
|
+
} break;
|
|
1419
|
+
|
|
1270
1420
|
case OutArgument::Kind::Object: {
|
|
1271
1421
|
Napi::Object obj = value.As<Napi::Object>();
|
|
1272
1422
|
|
package/src/koffi/src/call.hh
CHANGED
|
@@ -42,6 +42,7 @@ class alignas(8) CallData {
|
|
|
42
42
|
Buffer,
|
|
43
43
|
String,
|
|
44
44
|
String16,
|
|
45
|
+
String32,
|
|
45
46
|
Object
|
|
46
47
|
};
|
|
47
48
|
|
|
@@ -117,6 +118,8 @@ public:
|
|
|
117
118
|
Size PushStringValue(Napi::Value value, const char **out_str);
|
|
118
119
|
bool PushString16(Napi::Value value, int directions, const char16_t **out_str16);
|
|
119
120
|
Size PushString16Value(Napi::Value value, const char16_t **out_str16);
|
|
121
|
+
bool PushString32(Napi::Value value, int directions, const char32_t **out_str32);
|
|
122
|
+
Size PushString32Value(Napi::Value value, const char32_t **out_str32);
|
|
120
123
|
bool PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origin);
|
|
121
124
|
bool PushNormalArray(Napi::Array array, Size len, const TypeInfo *type, uint8_t *origin);
|
|
122
125
|
void PushBuffer(Span<const uint8_t> buffer, Size size, const TypeInfo *type, uint8_t *origin);
|
package/src/koffi/src/ffi.cc
CHANGED
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
#define MAP_STACK 0
|
|
47
47
|
#endif
|
|
48
48
|
#endif
|
|
49
|
+
#include <wchar.h>
|
|
49
50
|
|
|
50
51
|
#include <napi.h>
|
|
51
52
|
|
|
@@ -648,7 +649,8 @@ static Napi::Value EncodePointerDirection(const Napi::CallbackInfo &info, int di
|
|
|
648
649
|
|
|
649
650
|
if (type->primitive != PrimitiveKind::Pointer &&
|
|
650
651
|
type->primitive != PrimitiveKind::String &&
|
|
651
|
-
type->primitive != PrimitiveKind::String16
|
|
652
|
+
type->primitive != PrimitiveKind::String16 &&
|
|
653
|
+
type->primitive != PrimitiveKind::String32) {
|
|
652
654
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 type, expected pointer or string type", type->name);
|
|
653
655
|
return env.Null();
|
|
654
656
|
}
|
|
@@ -698,7 +700,8 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
|
|
|
698
700
|
return env.Null();
|
|
699
701
|
if (src->primitive != PrimitiveKind::Pointer &&
|
|
700
702
|
src->primitive != PrimitiveKind::String &&
|
|
701
|
-
src->primitive != PrimitiveKind::String16
|
|
703
|
+
src->primitive != PrimitiveKind::String16 &&
|
|
704
|
+
src->primitive != PrimitiveKind::String32) {
|
|
702
705
|
ThrowError<Napi::TypeError>(env, "Unexpected %1 type, expected pointer or string type", src->name);
|
|
703
706
|
return env.Null();
|
|
704
707
|
}
|
|
@@ -1241,6 +1244,7 @@ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
|
|
|
1241
1244
|
case PrimitiveKind::UInt64S:
|
|
1242
1245
|
case PrimitiveKind::String:
|
|
1243
1246
|
case PrimitiveKind::String16:
|
|
1247
|
+
case PrimitiveKind::String32:
|
|
1244
1248
|
case PrimitiveKind::Float32:
|
|
1245
1249
|
case PrimitiveKind::Float64:
|
|
1246
1250
|
case PrimitiveKind::Prototype:
|
|
@@ -1940,7 +1944,8 @@ static Napi::Value CastValue(const Napi::CallbackInfo &info)
|
|
|
1940
1944
|
if (type->primitive != PrimitiveKind::Pointer &&
|
|
1941
1945
|
type->primitive != PrimitiveKind::Callback &&
|
|
1942
1946
|
type->primitive != PrimitiveKind::String &&
|
|
1943
|
-
type->primitive != PrimitiveKind::String16
|
|
1947
|
+
type->primitive != PrimitiveKind::String16 &&
|
|
1948
|
+
type->primitive != PrimitiveKind::String32) [[unlikely]] {
|
|
1944
1949
|
ThrowError<Napi::TypeError>(env, "Only pointer or string types can be used for casting");
|
|
1945
1950
|
return env.Null();
|
|
1946
1951
|
}
|
|
@@ -2202,7 +2207,10 @@ static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initiali
|
|
|
2202
2207
|
if (IsInteger(type) || IsFloat(type)) {
|
|
2203
2208
|
type->flags |= (int)TypeFlag::HasTypedArray;
|
|
2204
2209
|
}
|
|
2205
|
-
if (TestStr(type->name, "char") ||
|
|
2210
|
+
if (TestStr(type->name, "char") ||
|
|
2211
|
+
TestStr(type->name, "char16") || TestStr(type->name, "char16_t") ||
|
|
2212
|
+
TestStr(type->name, "char32") || TestStr(type->name, "char32_t") ||
|
|
2213
|
+
TestStr(type->name, "wchar") || TestStr(type->name, "wchar_t")) {
|
|
2206
2214
|
type->flags |= (int)TypeFlag::IsCharLike;
|
|
2207
2215
|
}
|
|
2208
2216
|
|
|
@@ -2359,6 +2367,12 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
|
|
|
2359
2367
|
RegisterPrimitiveType(env, types, {"char"}, PrimitiveKind::Int8, 1, 1);
|
|
2360
2368
|
RegisterPrimitiveType(env, types, {"unsigned char", "uchar"}, PrimitiveKind::UInt8, 1, 1);
|
|
2361
2369
|
RegisterPrimitiveType(env, types, {"char16_t", "char16"}, PrimitiveKind::Int16, 2, 2);
|
|
2370
|
+
RegisterPrimitiveType(env, types, {"char32_t", "char32"}, PrimitiveKind::Int32, 4, 4);
|
|
2371
|
+
if (RG_SIZE(wchar_t) == 2) {
|
|
2372
|
+
RegisterPrimitiveType(env, types, {"wchar_t", "wchar"}, PrimitiveKind::Int16, 2, 2);
|
|
2373
|
+
} else if (RG_SIZE(wchar_t) == 4) {
|
|
2374
|
+
RegisterPrimitiveType(env, types, {"wchar_t", "wchar"}, PrimitiveKind::Int32, 4, 4);
|
|
2375
|
+
}
|
|
2362
2376
|
RegisterPrimitiveType(env, types, {"int16_t", "int16"}, PrimitiveKind::Int16, 2, 2);
|
|
2363
2377
|
RegisterPrimitiveType(env, types, {"int16_le_t", "int16_le"}, GetLittleEndianPrimitive(PrimitiveKind::Int16), 2, 2);
|
|
2364
2378
|
RegisterPrimitiveType(env, types, {"int16_be_t", "int16_be"}, GetBigEndianPrimitive(PrimitiveKind::Int16), 2, 2);
|
|
@@ -2392,12 +2406,20 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
|
|
|
2392
2406
|
RegisterPrimitiveType(env, types, {"double", "float64"}, PrimitiveKind::Float64, 8, alignof(double));
|
|
2393
2407
|
RegisterPrimitiveType(env, types, {"char *", "str", "string"}, PrimitiveKind::String, RG_SIZE(void *), alignof(void *), "char");
|
|
2394
2408
|
RegisterPrimitiveType(env, types, {"char16_t *", "char16 *", "str16", "string16"}, PrimitiveKind::String16, RG_SIZE(void *), alignof(void *), "char16_t");
|
|
2409
|
+
RegisterPrimitiveType(env, types, {"char32_t *", "char32 *", "str32", "string32"}, PrimitiveKind::String32, RG_SIZE(void *), alignof(void *), "char32_t");
|
|
2410
|
+
if (RG_SIZE(wchar_t) == 2) {
|
|
2411
|
+
RegisterPrimitiveType(env, types, {"wchar_t *", "wchar *"}, PrimitiveKind::String16, RG_SIZE(void *), alignof(void *), "wchar_t");
|
|
2412
|
+
} else if (RG_SIZE(wchar_t) == 4) {
|
|
2413
|
+
RegisterPrimitiveType(env, types, {"wchar_t *", "wchar *"}, PrimitiveKind::String32, RG_SIZE(void *), alignof(void *), "wchar_t");
|
|
2414
|
+
}
|
|
2395
2415
|
|
|
2396
2416
|
instance->void_type = instance->types_map.FindValue("void", nullptr);
|
|
2397
2417
|
instance->char_type = instance->types_map.FindValue("char", nullptr);
|
|
2398
2418
|
instance->char16_type = instance->types_map.FindValue("char16", nullptr);
|
|
2419
|
+
instance->char32_type = instance->types_map.FindValue("char32", nullptr);
|
|
2399
2420
|
instance->str_type = instance->types_map.FindValue("char *", nullptr);
|
|
2400
2421
|
instance->str16_type = instance->types_map.FindValue("char16_t *", nullptr);
|
|
2422
|
+
instance->str32_type = instance->types_map.FindValue("char32_t *", nullptr);
|
|
2401
2423
|
|
|
2402
2424
|
instance->active_symbol = Napi::Symbol::New(env, "active");
|
|
2403
2425
|
|
package/src/koffi/src/ffi.hh
CHANGED
|
@@ -60,6 +60,7 @@ enum class PrimitiveKind {
|
|
|
60
60
|
UInt64S,
|
|
61
61
|
String,
|
|
62
62
|
String16,
|
|
63
|
+
String32,
|
|
63
64
|
Pointer,
|
|
64
65
|
Record,
|
|
65
66
|
Union,
|
|
@@ -88,6 +89,7 @@ static const char *const PrimitiveKindNames[] = {
|
|
|
88
89
|
"UInt64S",
|
|
89
90
|
"String",
|
|
90
91
|
"String16",
|
|
92
|
+
"String32",
|
|
91
93
|
"Pointer",
|
|
92
94
|
"Record",
|
|
93
95
|
"Union",
|
|
@@ -283,8 +285,10 @@ struct InstanceData {
|
|
|
283
285
|
const TypeInfo *void_type;
|
|
284
286
|
const TypeInfo *char_type;
|
|
285
287
|
const TypeInfo *char16_type;
|
|
288
|
+
const TypeInfo *char32_type;
|
|
286
289
|
const TypeInfo *str_type;
|
|
287
290
|
const TypeInfo *str16_type;
|
|
291
|
+
const TypeInfo *str32_type;
|
|
288
292
|
|
|
289
293
|
Napi::Symbol active_symbol;
|
|
290
294
|
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
// Copyright 2023 Niels Martignène <niels.martignene@protonmail.com>
|
|
2
|
+
//
|
|
3
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
4
|
+
// this software and associated documentation files (the “Software”), to deal in
|
|
5
|
+
// the Software without restriction, including without limitation the rights to use,
|
|
6
|
+
// copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
|
7
|
+
// Software, and to permit persons to whom the Software is furnished to do so,
|
|
8
|
+
// subject to the following conditions:
|
|
9
|
+
//
|
|
10
|
+
// The above copyright notice and this permission notice shall be included in all
|
|
11
|
+
// copies or substantial portions of the Software.
|
|
12
|
+
//
|
|
13
|
+
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND,
|
|
14
|
+
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
15
|
+
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
16
|
+
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
17
|
+
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
18
|
+
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
19
|
+
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
20
|
+
// OTHER DEALINGS IN THE SOFTWARE.
|
|
21
|
+
|
|
22
|
+
const fs = require('fs');
|
|
23
|
+
const path = require('path');
|
|
24
|
+
const util = require('util');
|
|
25
|
+
const { get_napi_version, determine_arch } = require('../../cnoke/src/tools.js');
|
|
26
|
+
const pkg = require('../package.json');
|
|
27
|
+
|
|
28
|
+
function detect() {
|
|
29
|
+
if (process.versions.napi == null || process.versions.napi < pkg.cnoke.napi) {
|
|
30
|
+
let major = parseInt(process.versions.node, 10);
|
|
31
|
+
let required = get_napi_version(pkg.cnoke.napi, major);
|
|
32
|
+
|
|
33
|
+
if (required != null) {
|
|
34
|
+
throw new Error(`This engine is based on Node ${process.versions.node}, but ${pkg.name} requires Node >= ${required} in the Node ${major}.x branch (N-API >= ${pkg.cnoke.napi})`);
|
|
35
|
+
} else {
|
|
36
|
+
throw new Error(`This engine is based on Node ${process.versions.node}, but ${pkg.name} does not support the Node ${major}.x branch (N-API < ${pkg.cnoke.napi})`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let arch = determine_arch();
|
|
41
|
+
let triplet = `${process.platform}_${arch}`;
|
|
42
|
+
|
|
43
|
+
return triplet;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function init(triplet, native) {
|
|
47
|
+
if (native == null) {
|
|
48
|
+
let roots = [path.join(__dirname, '..')];
|
|
49
|
+
let triplets = [triplet];
|
|
50
|
+
|
|
51
|
+
if (process.resourcesPath != null)
|
|
52
|
+
roots.push(process.resourcesPath);
|
|
53
|
+
if (triplet.startsWith('linux_')) {
|
|
54
|
+
let musl = triplet.replace(/^linux_/, 'musl_');
|
|
55
|
+
triplets.push(musl);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let filenames = roots.flatMap(root => triplets.flatMap(triplet => [
|
|
59
|
+
`${root}/build/koffi/${triplet}/koffi.node`,
|
|
60
|
+
`${root}/koffi/${triplet}/koffi.node`,
|
|
61
|
+
`${root}/node_modules/koffi/build/koffi/${triplet}/koffi.node`,
|
|
62
|
+
`${root}/../../bin/Koffi/${triplet}/koffi.node`
|
|
63
|
+
]));
|
|
64
|
+
|
|
65
|
+
let first_err = null;
|
|
66
|
+
|
|
67
|
+
for (let filename of filenames) {
|
|
68
|
+
if (!fs.existsSync(filename))
|
|
69
|
+
continue;
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
// Trick so that webpack does not try to do anything with require() call
|
|
73
|
+
native = eval('require')(filename);
|
|
74
|
+
} catch (err) {
|
|
75
|
+
if (first_err == null)
|
|
76
|
+
first_err = err;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (first_err != null)
|
|
84
|
+
throw first_err;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (native == null)
|
|
88
|
+
throw new Error('Cannot find the native Koffi module; did you bundle it correctly?');
|
|
89
|
+
if (native.version != pkg.version)
|
|
90
|
+
throw new Error('Mismatched native Koffi modules');
|
|
91
|
+
|
|
92
|
+
let mod = wrap(native);
|
|
93
|
+
return mod;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function wrap(native) {
|
|
97
|
+
let obj = {
|
|
98
|
+
...native,
|
|
99
|
+
|
|
100
|
+
// Deprecated functions
|
|
101
|
+
handle: util.deprecate(native.opaque, 'The koffi.handle() function was deprecated in Koffi 2.1, use koffi.opaque() instead', 'KOFFI001'),
|
|
102
|
+
callback: util.deprecate(native.proto, 'The koffi.callback() function was deprecated in Koffi 2.4, use koffi.proto() instead', 'KOFFI002')
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
obj.load = (...args) => {
|
|
106
|
+
let lib = native.load(...args);
|
|
107
|
+
|
|
108
|
+
lib.cdecl = util.deprecate((...args) => lib.func('__cdecl', ...args), 'The koffi.cdecl() function was deprecated in Koffi 2.7, use koffi.func(...) instead', 'KOFFI003');
|
|
109
|
+
lib.stdcall = util.deprecate((...args) => lib.func('__stdcall', ...args), 'The koffi.stdcall() function was deprecated in Koffi 2.7, use koffi.func("__stdcall", ...) instead', 'KOFFI004');
|
|
110
|
+
lib.fastcall = util.deprecate((...args) => lib.func('__fastcall', ...args), 'The koffi.fastcall() function was deprecated in Koffi 2.7, use koffi.func("__fastcall", ...) instead', 'KOFFI005');
|
|
111
|
+
lib.thiscall = util.deprecate((...args) => lib.func('__thiscall', ...args), 'The koffi.thiscall() function was deprecated in Koffi 2.7, use koffi.func("__thiscall", ...) instead', 'KOFFI006');
|
|
112
|
+
|
|
113
|
+
return lib;
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
return obj;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
module.exports = {
|
|
120
|
+
detect,
|
|
121
|
+
init
|
|
122
|
+
};
|