koffi 2.8.10 → 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.
Files changed (47) hide show
  1. package/CHANGELOG.md +12 -1
  2. package/build/koffi/darwin_arm64/koffi.node +0 -0
  3. package/build/koffi/darwin_x64/koffi.node +0 -0
  4. package/build/koffi/freebsd_arm64/koffi.node +0 -0
  5. package/build/koffi/freebsd_i386/koffi.node +0 -0
  6. package/build/koffi/freebsd_x64/koffi.node +0 -0
  7. package/build/koffi/linux_arm32/koffi.node +0 -0
  8. package/build/koffi/linux_arm64/koffi.node +0 -0
  9. package/build/koffi/linux_i386/koffi.node +0 -0
  10. package/build/koffi/linux_riscv64/koffi.node +0 -0
  11. package/build/koffi/linux_x64/koffi.node +0 -0
  12. package/build/koffi/musl_x64/koffi.node +0 -0
  13. package/build/koffi/openbsd_i386/koffi.node +0 -0
  14. package/build/koffi/openbsd_x64/koffi.node +0 -0
  15. package/build/koffi/windows_arm64/koffi.node +0 -0
  16. package/build/koffi/{win32_ia32 → windows_i386}/koffi.node +0 -0
  17. package/build/koffi/{win32_x64 → windows_x64}/koffi.node +0 -0
  18. package/doc/contribute.md +3 -2
  19. package/doc/input.md +23 -13
  20. package/index.js +160 -97
  21. package/indirect.js +113 -81
  22. package/package.json +3 -3
  23. package/src/koffi/src/abi_arm32.cc +23 -0
  24. package/src/koffi/src/abi_arm64.cc +30 -0
  25. package/src/koffi/src/abi_riscv64.cc +22 -0
  26. package/src/koffi/src/abi_x64_sysv.cc +23 -0
  27. package/src/koffi/src/abi_x64_win.cc +23 -0
  28. package/src/koffi/src/abi_x86.cc +22 -0
  29. package/src/koffi/src/call.cc +155 -5
  30. package/src/koffi/src/call.hh +3 -0
  31. package/src/koffi/src/ffi.cc +26 -4
  32. package/src/koffi/src/ffi.hh +4 -0
  33. package/src/koffi/src/init.js +122 -0
  34. package/src/koffi/src/util.cc +85 -2
  35. package/src/koffi/src/util.hh +13 -0
  36. package/build/koffi/freebsd_ia32/koffi.node +0 -0
  37. package/build/koffi/linux_armhf/koffi.node +0 -0
  38. package/build/koffi/linux_ia32/koffi.node +0 -0
  39. package/build/koffi/linux_riscv64d/koffi.node +0 -0
  40. package/build/koffi/openbsd_ia32/koffi.node +0 -0
  41. package/build/koffi/win32_arm64/koffi.node +0 -0
  42. /package/build/koffi/{win32_arm64 → windows_arm64}/koffi.exp +0 -0
  43. /package/build/koffi/{win32_arm64 → windows_arm64}/koffi.lib +0 -0
  44. /package/build/koffi/{win32_ia32 → windows_i386}/koffi.exp +0 -0
  45. /package/build/koffi/{win32_ia32 → windows_i386}/koffi.lib +0 -0
  46. /package/build/koffi/{win32_x64 → windows_x64}/koffi.exp +0 -0
  47. /package/build/koffi/{win32_x64 → windows_x64}/koffi.lib +0 -0
@@ -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
 
@@ -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
- buf = AllocateSpan<char>(&call_alloc, (Size)len + 1);
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 = 1;
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
- buf = AllocateSpan<char16_t>(&call_alloc, ((Size)len + 1) * 2);
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
- out_kind = (type->ref.type->size == 2) ? OutArgument::Kind::String16 : OutArgument::Kind::String;
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
 
@@ -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);
@@ -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) [[unlikely]] {
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") || TestStr(type->name, "char16") || TestStr(type->name, "char16_t")) {
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
 
@@ -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
+ };