koffi 2.3.15 → 2.3.17

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 (49) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/build/2.3.17/koffi_darwin_arm64/koffi.node +0 -0
  3. package/build/2.3.17/koffi_darwin_x64/koffi.node +0 -0
  4. package/build/2.3.17/koffi_freebsd_arm64/koffi.node +0 -0
  5. package/build/2.3.17/koffi_freebsd_ia32/koffi.node +0 -0
  6. package/build/2.3.17/koffi_freebsd_x64/koffi.node +0 -0
  7. package/build/2.3.17/koffi_linux_arm32hf/koffi.node +0 -0
  8. package/build/2.3.17/koffi_linux_arm64/koffi.node +0 -0
  9. package/build/2.3.17/koffi_linux_ia32/koffi.node +0 -0
  10. package/build/2.3.17/koffi_linux_riscv64hf64/koffi.node +0 -0
  11. package/build/2.3.17/koffi_linux_x64/koffi.node +0 -0
  12. package/build/2.3.17/koffi_openbsd_ia32/koffi.node +0 -0
  13. package/build/2.3.17/koffi_openbsd_x64/koffi.node +0 -0
  14. package/build/2.3.17/koffi_win32_arm64/koffi.exp +0 -0
  15. package/build/2.3.17/koffi_win32_arm64/koffi.lib +0 -0
  16. package/build/2.3.17/koffi_win32_arm64/koffi.node +0 -0
  17. package/build/{2.3.15 → 2.3.17}/koffi_win32_ia32/koffi.exp +0 -0
  18. package/build/{2.3.15 → 2.3.17}/koffi_win32_ia32/koffi.lib +0 -0
  19. package/build/2.3.17/koffi_win32_ia32/koffi.node +0 -0
  20. package/build/{2.3.15 → 2.3.17}/koffi_win32_x64/koffi.exp +0 -0
  21. package/build/{2.3.15/koffi_win32_arm64 → 2.3.17/koffi_win32_x64}/koffi.lib +0 -0
  22. package/build/2.3.17/koffi_win32_x64/koffi.node +0 -0
  23. package/package.json +2 -2
  24. package/src/cnoke/cnoke.js +1 -1
  25. package/src/cnoke/package.json +1 -1
  26. package/src/cnoke/src/builder.js +2 -2
  27. package/src/koffi/CMakeLists.txt +4 -0
  28. package/src/koffi/src/call.cc +118 -24
  29. package/src/koffi/src/call.hh +13 -0
  30. package/src/koffi/src/ffi.cc +30 -21
  31. package/src/koffi/src/util.cc +1 -1
  32. package/src/koffi/src/util.hh +2 -0
  33. package/build/2.3.15/koffi_darwin_arm64/koffi.node +0 -0
  34. package/build/2.3.15/koffi_darwin_x64/koffi.node +0 -0
  35. package/build/2.3.15/koffi_freebsd_arm64/koffi.node +0 -0
  36. package/build/2.3.15/koffi_freebsd_ia32/koffi.node +0 -0
  37. package/build/2.3.15/koffi_freebsd_x64/koffi.node +0 -0
  38. package/build/2.3.15/koffi_linux_arm32hf/koffi.node +0 -0
  39. package/build/2.3.15/koffi_linux_arm64/koffi.node +0 -0
  40. package/build/2.3.15/koffi_linux_ia32/koffi.node +0 -0
  41. package/build/2.3.15/koffi_linux_riscv64hf64/koffi.node +0 -0
  42. package/build/2.3.15/koffi_linux_x64/koffi.node +0 -0
  43. package/build/2.3.15/koffi_openbsd_ia32/koffi.node +0 -0
  44. package/build/2.3.15/koffi_openbsd_x64/koffi.node +0 -0
  45. package/build/2.3.15/koffi_win32_arm64/koffi.exp +0 -0
  46. package/build/2.3.15/koffi_win32_arm64/koffi.node +0 -0
  47. package/build/2.3.15/koffi_win32_ia32/koffi.node +0 -0
  48. package/build/2.3.15/koffi_win32_x64/koffi.lib +0 -0
  49. package/build/2.3.15/koffi_win32_x64/koffi.node +0 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,24 @@
4
4
 
5
5
  ### Koffi 2.3
6
6
 
7
+ #### Koffi 2.3.17
8
+
9
+ **Main changes:**
10
+
11
+ - Allow strings for input `void *`, `int8_t *` and `int16_t *` pointer arguments
12
+ - Support using `[string]` (single-element string arrays) for polymorphic input/output arguments
13
+
14
+ #### Koffi 2.3.16
15
+
16
+ **Main changes:**
17
+
18
+ - Fix Windows ARM64 build to work with official Node.js version
19
+ - Compile Windows builds with Visual Studio 2022 17.5.3
20
+
21
+ **Other changes:**
22
+
23
+ - Support null in `koffi.free()` and `koffi.address()`
24
+
7
25
  #### Koffi 2.3.15
8
26
 
9
27
  **Main changes:**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.3.15",
4
- "stable": "2.3.15",
3
+ "version": "2.3.17",
4
+ "stable": "2.3.17",
5
5
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
6
6
  "keywords": [
7
7
  "foreign",
@@ -155,7 +155,7 @@ Options:
155
155
  (default: ${cnoke.DefaultOptions.mode})
156
156
  -D, --debug Shortcut for --config Debug
157
157
 
158
- --prebuild Use prebuilt binari if available
158
+ --prebuild Use prebuilt binary if available
159
159
 
160
160
  -a, --arch <ARCH> Change architecture and ABI
161
161
  (default: ${cnoke.determine_arch()})
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cnoke",
3
- "version": "3.3.1",
3
+ "version": "3.3.2",
4
4
  "description": "Build native Node addons based on CMake, without extra dependency",
5
5
  "keywords": [
6
6
  "native",
@@ -103,7 +103,7 @@ function Builder(config = {}) {
103
103
  let basename = `node-v${runtime_version}-headers.tar.gz`;
104
104
  let urls = [
105
105
  `https://nodejs.org/dist/v${runtime_version}/${basename}`,
106
- `https://unofficial-builds.nodejs.org/download/release/v${runtime_version}/${basename}`
106
+ // `https://unofficial-builds.nodejs.org/download/release/v${runtime_version}/${basename}`
107
107
  ];
108
108
  let destname = `${cache_dir}/${basename}`;
109
109
 
@@ -130,7 +130,7 @@ function Builder(config = {}) {
130
130
  if (!fs.existsSync(destname)) {
131
131
  let urls = [
132
132
  `https://nodejs.org/dist/v${runtime_version}/${dirname}/node.lib`,
133
- `https://unofficial-builds.nodejs.org/download/release/v${runtime_version}/${dirname}/node.lib`
133
+ // `https://unofficial-builds.nodejs.org/download/release/v${runtime_version}/${dirname}/node.lib`
134
134
  ];
135
135
  await tools.download_http(urls, destname);
136
136
  }
@@ -20,6 +20,8 @@
20
20
  # OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
22
  cmake_minimum_required(VERSION 3.6)
23
+ cmake_policy(SET CMP0091 NEW)
24
+
23
25
  project(koffi C CXX ASM)
24
26
 
25
27
  include(CheckCXXCompilerFlag)
@@ -58,6 +60,8 @@ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
58
60
  # CMAKE_SYSTEM_PROCESSOR is wrong on Windows ARM64
59
61
 
60
62
  if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch|arm" OR CMAKE_GENERATOR_PLATFORM STREQUAL "ARM64" OR CMAKE_OSX_ARCHITECTURES MATCHES "arm")
63
+ set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded)
64
+
61
65
  if(WIN32)
62
66
  get_filename_component(cl_dir "${CMAKE_CXX_COMPILER}" DIRECTORY)
63
67
  file(TO_CMAKE_PATH "${cl_dir}/armasm64.exe" asm_compiler)
@@ -147,7 +147,7 @@ bool CallData::PushString(Napi::Value value, int directions, const char **out_st
147
147
  {
148
148
  if (value.IsString()) {
149
149
  if (RG_UNLIKELY(directions & 2)) {
150
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected string", GetValueType(instance, value));
150
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected [string]", GetValueType(instance, value));
151
151
  return false;
152
152
  }
153
153
 
@@ -200,6 +200,7 @@ bool CallData::PushString(Napi::Value value, int directions, const char **out_st
200
200
  napi_status status = napi_create_reference(env, array, 1, &out->ref);
201
201
  RG_ASSERT(status == napi_ok);
202
202
 
203
+ out->kind = OutArgument::Kind::Array;
203
204
  out->ptr = (const uint8_t *)*out_str;
204
205
  out->type = type;
205
206
  }
@@ -301,6 +302,7 @@ bool CallData::PushString16(Napi::Value value, int directions, const char16_t **
301
302
  napi_status status = napi_create_reference(env, array, 1, &out->ref);
302
303
  RG_ASSERT(status == napi_ok);
303
304
 
305
+ out->kind = OutArgument::Kind::Array;
304
306
  out->ptr = (const uint8_t *)*out_str16;
305
307
  out->type = type;
306
308
  }
@@ -973,6 +975,9 @@ bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directio
973
975
  case napi_object: {
974
976
  uint8_t *ptr = nullptr;
975
977
 
978
+ OutArgument::Kind out_kind;
979
+ Size out_max_len = -1;
980
+
976
981
  if (value.IsArray()) {
977
982
  if (RG_UNLIKELY(!type->ref.type->size)) {
978
983
  ThrowError<Napi::TypeError>(env, "Cannot pass %1 value to void *, use koffi.as()",
@@ -981,17 +986,25 @@ bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directio
981
986
  }
982
987
 
983
988
  Napi::Array array = value.As<Napi::Array>();
989
+ Size len = PushIndirectString(array, type->ref.type, &ptr);
984
990
 
985
- Size len = (Size)array.Length();
986
- Size size = len * type->ref.type->size;
991
+ if (len >= 0) {
992
+ out_kind = (type->ref.type->size == 2) ? OutArgument::Kind::String16 : OutArgument::Kind::String;
993
+ out_max_len = len;
994
+ } else {
995
+ Size len = (Size)array.Length();
996
+ Size size = len * type->ref.type->size;
987
997
 
988
- ptr = AllocHeap(size, 16);
998
+ ptr = AllocHeap(size, 16);
989
999
 
990
- if (directions & 1) {
991
- if (!PushNormalArray(array, len, type, ptr))
992
- return false;
993
- } else {
994
- memset_safe(ptr, 0, size);
1000
+ if (directions & 1) {
1001
+ if (!PushNormalArray(array, len, type, ptr))
1002
+ return false;
1003
+ } else {
1004
+ memset_safe(ptr, 0, size);
1005
+ }
1006
+
1007
+ out_kind = OutArgument::Kind::Array;
995
1008
  }
996
1009
  } else if (IsRawBuffer(value)) {
997
1010
  Span<uint8_t> buffer = GetRawBuffer(value);
@@ -1006,6 +1019,8 @@ bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directio
1006
1019
  ptr = buffer.ptr;
1007
1020
  directions = 1;
1008
1021
  }
1022
+
1023
+ out_kind = OutArgument::Kind::Buffer;
1009
1024
  } else if (RG_LIKELY(type->ref.type->primitive == PrimitiveKind::Record ||
1010
1025
  type->ref.type->primitive == PrimitiveKind::Union)) {
1011
1026
  if (RG_UNLIKELY(!type->ref.type->size)) {
@@ -1031,6 +1046,8 @@ bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directio
1031
1046
 
1032
1047
  memset_safe(ptr, 0, type->size);
1033
1048
  }
1049
+
1050
+ out_kind = OutArgument::Kind::Object;
1034
1051
  } else {
1035
1052
  goto unexpected;
1036
1053
  }
@@ -1041,14 +1058,36 @@ bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directio
1041
1058
  napi_status status = napi_create_reference(env, value, 1, &out->ref);
1042
1059
  RG_ASSERT(status == napi_ok);
1043
1060
 
1061
+ out->kind = out_kind;
1044
1062
  out->ptr = ptr;
1045
1063
  out->type = type->ref.type;
1064
+ out->max_len = out_max_len;
1046
1065
  }
1047
1066
 
1048
1067
  *out_ptr = ptr;
1049
1068
  return true;
1050
1069
  } break;
1051
1070
 
1071
+ case napi_string: {
1072
+ RG_ASSERT(type->primitive == PrimitiveKind::Pointer);
1073
+
1074
+ if (RG_UNLIKELY(directions & 2))
1075
+ goto unexpected;
1076
+
1077
+ if (type->ref.type == instance->void_type) {
1078
+ PushStringValue(value, (const char **)out_ptr);
1079
+ return true;
1080
+ } else if (type->ref.type->primitive == PrimitiveKind::Int8) {
1081
+ PushStringValue(value, (const char **)out_ptr);
1082
+ return true;
1083
+ } else if (type->ref.type->primitive == PrimitiveKind::Int16) {
1084
+ PushString16Value(value, (const char16_t **)out_ptr);
1085
+ return true;
1086
+ } else {
1087
+ goto unexpected;
1088
+ }
1089
+ } break;
1090
+
1052
1091
  case napi_number: {
1053
1092
  Napi::Number number = value.As<Napi::Number>();
1054
1093
  intptr_t ptr = (intptr_t)number.Int32Value();
@@ -1075,6 +1114,27 @@ unexpected:
1075
1114
  return false;
1076
1115
  }
1077
1116
 
1117
+ Size CallData::PushIndirectString(Napi::Array array, const TypeInfo *ref, uint8_t **out_ptr)
1118
+ {
1119
+ if (array.Length() != 1)
1120
+ return -1;
1121
+
1122
+ Napi::Value value = array[0u];
1123
+
1124
+ if (!value.IsString())
1125
+ return -1;
1126
+
1127
+ if (ref == instance->void_type) {
1128
+ return PushStringValue(value, (const char **)out_ptr);
1129
+ } else if (ref->primitive == PrimitiveKind::Int8) {
1130
+ return PushStringValue(value, (const char **)out_ptr);
1131
+ } else if (ref->primitive == PrimitiveKind::Int16) {
1132
+ return PushString16Value(value, (const char16_t **)out_ptr);
1133
+ } else {
1134
+ return -1;
1135
+ }
1136
+ }
1137
+
1078
1138
  static inline Napi::Value GetReferenceValue(Napi::Env env, napi_ref ref)
1079
1139
  {
1080
1140
  napi_value value;
@@ -1091,21 +1151,55 @@ void CallData::PopOutArguments()
1091
1151
  Napi::Value value = GetReferenceValue(env, out.ref);
1092
1152
  RG_ASSERT(!value.IsEmpty());
1093
1153
 
1094
- if (value.IsArray()) {
1095
- Napi::Array array(env, value);
1096
- DecodeNormalArray(array, out.ptr, out.type);
1097
- } else if (IsRawBuffer(value)) {
1098
- Span<uint8_t> buffer = GetRawBuffer(value);
1099
- DecodeBuffer(buffer, out.ptr, out.type);
1100
- } else {
1101
- Napi::Object obj = value.As<Napi::Object>();
1102
-
1103
- if (CheckValueTag(instance, value, &MagicUnionMarker)) {
1104
- MagicUnion *u = MagicUnion::Unwrap(obj);
1105
- u->SetRaw(out.ptr);
1106
- } else {
1107
- DecodeObject(obj, out.ptr, out.type);
1108
- }
1154
+ switch (out.kind) {
1155
+ case OutArgument::Kind::Array: {
1156
+ RG_ASSERT(value.IsArray());
1157
+
1158
+ Napi::Array array(env, value);
1159
+ DecodeNormalArray(array, out.ptr, out.type);
1160
+ } break;
1161
+
1162
+ case OutArgument::Kind::Buffer: {
1163
+ RG_ASSERT(IsRawBuffer(value));
1164
+
1165
+ Span<uint8_t> buffer = GetRawBuffer(value);
1166
+ DecodeBuffer(buffer, out.ptr, out.type);
1167
+ } break;
1168
+
1169
+ case OutArgument::Kind::String: {
1170
+ Napi::Array array(env, value);
1171
+
1172
+ RG_ASSERT(array.IsArray());
1173
+ RG_ASSERT(array.Length() == 1);
1174
+
1175
+ Size len = strnlen((const char *)out.ptr, out.max_len);
1176
+ Napi::String str = Napi::String::New(env, (const char *)out.ptr, len);
1177
+
1178
+ array.Set(0u, str);
1179
+ } break;
1180
+
1181
+ case OutArgument::Kind::String16: {
1182
+ Napi::Array array(env, value);
1183
+
1184
+ RG_ASSERT(array.IsArray());
1185
+ RG_ASSERT(array.Length() == 1);
1186
+
1187
+ Size len = WideStringLength((const char16_t *)out.ptr, out.max_len);
1188
+ Napi::String str = Napi::String::New(env, (const char16_t *)out.ptr, len);
1189
+
1190
+ array.Set(0u, str);
1191
+ } break;
1192
+
1193
+ case OutArgument::Kind::Object: {
1194
+ Napi::Object obj = value.As<Napi::Object>();
1195
+
1196
+ if (CheckValueTag(instance, value, &MagicUnionMarker)) {
1197
+ MagicUnion *u = MagicUnion::Unwrap(obj);
1198
+ u->SetRaw(out.ptr);
1199
+ } else {
1200
+ DecodeObject(obj, out.ptr, out.type);
1201
+ }
1202
+ } break;
1109
1203
  }
1110
1204
  }
1111
1205
  }
@@ -37,9 +37,21 @@ struct BackRegisters;
37
37
  // But on Windows i386, without it, the alignment may not be correct (compiler bug?).
38
38
  class alignas(8) CallData {
39
39
  struct OutArgument {
40
+ enum class Kind {
41
+ Array,
42
+ Buffer,
43
+ String,
44
+ String16,
45
+ Object
46
+ };
47
+
48
+ Kind kind;
49
+
40
50
  napi_ref ref;
41
51
  const uint8_t *ptr;
42
52
  const TypeInfo *type;
53
+
54
+ Size max_len; // Only for indirect strings
43
55
  };
44
56
 
45
57
  Napi::Env env;
@@ -116,6 +128,7 @@ private:
116
128
  bool PushBuffer(Span<const uint8_t> buffer, Size size, const TypeInfo *type, uint8_t *origin);
117
129
  bool PushStringArray(Napi::Value value, const TypeInfo *type, uint8_t *origin);
118
130
  bool PushPointer(Napi::Value value, const TypeInfo *type, int directions, void **out_ptr);
131
+ Size PushIndirectString(Napi::Array array, const TypeInfo *ref, uint8_t **out_ptr);
119
132
 
120
133
  void PopOutArguments();
121
134
 
@@ -605,8 +605,10 @@ static Napi::Value EncodePointerDirection(const Napi::CallbackInfo &info, int di
605
605
  if (!type)
606
606
  return env.Null();
607
607
 
608
- if (type->primitive != PrimitiveKind::Pointer) {
609
- ThrowError<Napi::TypeError>(env, "Unexpected %1 type, expected pointer type", type->name);
608
+ if (type->primitive != PrimitiveKind::Pointer &&
609
+ type->primitive != PrimitiveKind::String &&
610
+ type->primitive != PrimitiveKind::String16) {
611
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 type, expected pointer or string type", type->name);
610
612
  return env.Null();
611
613
  }
612
614
 
@@ -653,9 +655,9 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
653
655
  const TypeInfo *src = ResolveType(info[named]);
654
656
  if (!src)
655
657
  return env.Null();
656
- if (src->primitive != PrimitiveKind::String &&
657
- src->primitive != PrimitiveKind::String16 &&
658
- src->primitive != PrimitiveKind::Pointer) {
658
+ if (src->primitive != PrimitiveKind::Pointer &&
659
+ src->primitive != PrimitiveKind::String &&
660
+ src->primitive != PrimitiveKind::String16) {
659
661
  ThrowError<Napi::TypeError>(env, "Unexpected %1 type, expected pointer or string type", src->name);
660
662
  return env.Null();
661
663
  }
@@ -723,18 +725,25 @@ static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
723
725
  return WrapType(env, instance, type);
724
726
  }
725
727
 
726
- static inline bool CheckExternalPointer(Napi::Env env, Napi::Value value)
728
+ static inline bool GetExternalPointer(Napi::Env env, Napi::Value value, void **out_ptr)
727
729
  {
728
730
  InstanceData *instance = env.GetInstanceData<InstanceData>();
729
731
 
730
- if (!value.IsExternal() || CheckValueTag(instance, value, &TypeInfoMarker) ||
731
- CheckValueTag(instance, value, &CastMarker) ||
732
- CheckValueTag(instance, value, &MagicUnionMarker)) {
732
+ if (IsNullOrUndefined(value)) {
733
+ *out_ptr = 0;
734
+ return true;
735
+ } else if (value.IsExternal() && !CheckValueTag(instance, value, &TypeInfoMarker) &&
736
+ !CheckValueTag(instance, value, &CastMarker) &&
737
+ !CheckValueTag(instance, value, &MagicUnionMarker)) {
738
+ Napi::External<void> external = value.As<Napi::External<void>>();
739
+ void *ptr = external.Data();
740
+
741
+ *out_ptr = ptr;
742
+ return true;
743
+ } else {
733
744
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected external pointer", GetValueType(instance, value));
734
745
  return false;
735
746
  }
736
-
737
- return true;
738
747
  }
739
748
 
740
749
  static Napi::Value CallFree(const Napi::CallbackInfo &info)
@@ -745,11 +754,10 @@ static Napi::Value CallFree(const Napi::CallbackInfo &info)
745
754
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
746
755
  return env.Null();
747
756
  }
748
- if (!CheckExternalPointer(env, info[0]))
749
- return env.Null();
750
757
 
751
- Napi::External<void> external = info[0].As<Napi::External<void>>();
752
- void *ptr = external.Data();
758
+ void *ptr = nullptr;
759
+ if (!GetExternalPointer(env, info[0], &ptr))
760
+ return env.Null();
753
761
 
754
762
  free(ptr);
755
763
 
@@ -1976,8 +1984,10 @@ static Napi::Value CastValue(const Napi::CallbackInfo &info)
1976
1984
  const TypeInfo *type = ResolveType(info[1]);
1977
1985
  if (RG_UNLIKELY(!type))
1978
1986
  return env.Null();
1979
- if (type->primitive != PrimitiveKind::Pointer) {
1980
- ThrowError<Napi::TypeError>(env, "Only pointer types can be used for casting");
1987
+ if (type->primitive != PrimitiveKind::Pointer &&
1988
+ type->primitive != PrimitiveKind::String &&
1989
+ type->primitive != PrimitiveKind::String16) {
1990
+ ThrowError<Napi::TypeError>(env, "Only pointer or string types can be used for casting");
1981
1991
  return env.Null();
1982
1992
  }
1983
1993
 
@@ -2030,11 +2040,10 @@ static Napi::Value GetPointerAddress(const Napi::CallbackInfo &info)
2030
2040
  ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
2031
2041
  return env.Null();
2032
2042
  }
2033
- if (!CheckExternalPointer(env, info[0]))
2034
- return env.Null();
2035
2043
 
2036
- Napi::External<void> external = info[0].As<Napi::External<void>>();
2037
- void *ptr = external.Data();
2044
+ void *ptr = nullptr;
2045
+ if (!GetExternalPointer(env, info[0], &ptr))
2046
+ return env.Null();
2038
2047
 
2039
2048
  uint64_t ptr64 = (uint64_t)(uintptr_t)ptr;
2040
2049
  Napi::BigInt bigint = Napi::BigInt::New(env, ptr64);
@@ -647,7 +647,7 @@ void DecodeObject(Napi::Object obj, const uint8_t *origin, const TypeInfo *type)
647
647
  }
648
648
  }
649
649
 
650
- static Size WideStringLength(const char16_t *str16, Size max)
650
+ Size WideStringLength(const char16_t *str16, Size max)
651
651
  {
652
652
  Size len = 0;
653
653
 
@@ -154,6 +154,8 @@ T GetNumber(Napi::Value value)
154
154
  RG_UNREACHABLE();
155
155
  }
156
156
 
157
+ Size WideStringLength(const char16_t *str16, Size max);
158
+
157
159
  Napi::Object DecodeObject(Napi::Env env, const uint8_t *origin, const TypeInfo *type);
158
160
  void DecodeObject(Napi::Object obj, const uint8_t *origin, const TypeInfo *type);
159
161
  Napi::Value DecodeArray(Napi::Env env, const uint8_t *origin, const TypeInfo *type);