koffi 2.3.16 → 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 (42) hide show
  1. package/CHANGELOG.md +8 -1
  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.node +0 -0
  15. package/build/2.3.17/koffi_win32_ia32/koffi.node +0 -0
  16. package/build/{2.3.16 → 2.3.17}/koffi_win32_x64/koffi.node +0 -0
  17. package/package.json +2 -2
  18. package/src/koffi/src/call.cc +118 -24
  19. package/src/koffi/src/call.hh +13 -0
  20. package/src/koffi/src/ffi.cc +11 -7
  21. package/src/koffi/src/util.cc +1 -1
  22. package/src/koffi/src/util.hh +2 -0
  23. package/build/2.3.16/koffi_darwin_arm64/koffi.node +0 -0
  24. package/build/2.3.16/koffi_darwin_x64/koffi.node +0 -0
  25. package/build/2.3.16/koffi_freebsd_arm64/koffi.node +0 -0
  26. package/build/2.3.16/koffi_freebsd_ia32/koffi.node +0 -0
  27. package/build/2.3.16/koffi_freebsd_x64/koffi.node +0 -0
  28. package/build/2.3.16/koffi_linux_arm32hf/koffi.node +0 -0
  29. package/build/2.3.16/koffi_linux_arm64/koffi.node +0 -0
  30. package/build/2.3.16/koffi_linux_ia32/koffi.node +0 -0
  31. package/build/2.3.16/koffi_linux_riscv64hf64/koffi.node +0 -0
  32. package/build/2.3.16/koffi_linux_x64/koffi.node +0 -0
  33. package/build/2.3.16/koffi_openbsd_ia32/koffi.node +0 -0
  34. package/build/2.3.16/koffi_openbsd_x64/koffi.node +0 -0
  35. package/build/2.3.16/koffi_win32_arm64/koffi.node +0 -0
  36. package/build/2.3.16/koffi_win32_ia32/koffi.node +0 -0
  37. /package/build/{2.3.16 → 2.3.17}/koffi_win32_arm64/koffi.exp +0 -0
  38. /package/build/{2.3.16 → 2.3.17}/koffi_win32_arm64/koffi.lib +0 -0
  39. /package/build/{2.3.16 → 2.3.17}/koffi_win32_ia32/koffi.exp +0 -0
  40. /package/build/{2.3.16 → 2.3.17}/koffi_win32_ia32/koffi.lib +0 -0
  41. /package/build/{2.3.16 → 2.3.17}/koffi_win32_x64/koffi.exp +0 -0
  42. /package/build/{2.3.16 → 2.3.17}/koffi_win32_x64/koffi.lib +0 -0
package/CHANGELOG.md CHANGED
@@ -4,6 +4,13 @@
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
+
7
14
  #### Koffi 2.3.16
8
15
 
9
16
  **Main changes:**
@@ -13,7 +20,7 @@
13
20
 
14
21
  **Other changes:**
15
22
 
16
- - Support null in koffi.free() and koffi.address()
23
+ - Support null in `koffi.free()` and `koffi.address()`
17
24
 
18
25
  #### Koffi 2.3.15
19
26
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.3.16",
4
- "stable": "2.3.16",
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",
@@ -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
  }
@@ -1982,8 +1984,10 @@ static Napi::Value CastValue(const Napi::CallbackInfo &info)
1982
1984
  const TypeInfo *type = ResolveType(info[1]);
1983
1985
  if (RG_UNLIKELY(!type))
1984
1986
  return env.Null();
1985
- if (type->primitive != PrimitiveKind::Pointer) {
1986
- 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");
1987
1991
  return env.Null();
1988
1992
  }
1989
1993
 
@@ -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);