koffi 1.1.1 → 1.1.2
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/CMakeLists.txt +3 -0
- package/build/qemu/1.1.2/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.1.2/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.1.2/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.1.2/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.1.2/koffi_linux_arm.tar.gz +0 -0
- package/build/qemu/1.1.2/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.1.2/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.1.2/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.1.2/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.1.2/koffi_win32_x64.tar.gz +0 -0
- package/package.json +2 -2
- package/src/call.cc +18 -18
- package/src/call.hh +1 -1
- package/src/ffi.cc +8 -3
- package/src/parser.cc +30 -20
- package/src/parser.hh +3 -1
- package/build/qemu/1.1.1/koffi_darwin_x64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_freebsd_arm64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_freebsd_ia32.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_freebsd_x64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_linux_arm.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_linux_arm64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_linux_ia32.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_linux_x64.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_win32_ia32.tar.gz +0 -0
- package/build/qemu/1.1.1/koffi_win32_x64.tar.gz +0 -0
package/CMakeLists.txt
CHANGED
|
@@ -23,6 +23,9 @@ if(MSVC)
|
|
|
23
23
|
else()
|
|
24
24
|
add_compile_options(-Wall -Wextra -Wno-missing-field-initializers
|
|
25
25
|
-Wno-unused-parameter -Wno-class-memaccess)
|
|
26
|
+
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
|
27
|
+
add_compile_options(-Wno-unknown-warning-option)
|
|
28
|
+
endif()
|
|
26
29
|
endif()
|
|
27
30
|
|
|
28
31
|
# ---- Koffi ----
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koffi",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "Fast and simple FFI (foreign function interface) for Node.js",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"foreign",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"license": "AGPL-3.0",
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"cnoke": "^1.0.
|
|
27
|
+
"cnoke": "^1.0.9"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"chalk": "^4.1.2",
|
package/src/call.cc
CHANGED
|
@@ -252,8 +252,8 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
|
|
|
252
252
|
return false;
|
|
253
253
|
}
|
|
254
254
|
|
|
255
|
-
Napi::Object
|
|
256
|
-
if (!PushObject(
|
|
255
|
+
Napi::Object obj2 = value.As<Napi::Object>();
|
|
256
|
+
if (!PushObject(obj2, member.type, dest, realign))
|
|
257
257
|
return false;
|
|
258
258
|
} break;
|
|
259
259
|
case PrimitiveKind::Array: {
|
|
@@ -292,15 +292,15 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
|
|
|
292
292
|
return true;
|
|
293
293
|
}
|
|
294
294
|
|
|
295
|
-
bool CallData::PushArray(const Napi::Value &
|
|
295
|
+
bool CallData::PushArray(const Napi::Value &obj, const TypeInfo *type, uint8_t *dest, int16_t realign)
|
|
296
296
|
{
|
|
297
|
-
RG_ASSERT(
|
|
297
|
+
RG_ASSERT(obj.IsArray() || obj.IsTypedArray() || obj.IsString());
|
|
298
298
|
RG_ASSERT(type->primitive == PrimitiveKind::Array);
|
|
299
299
|
|
|
300
300
|
uint32_t len = type->size / type->ref->size;
|
|
301
301
|
|
|
302
|
-
if (
|
|
303
|
-
Napi::Array array =
|
|
302
|
+
if (obj.IsArray()) {
|
|
303
|
+
Napi::Array array = obj.As<Napi::Array>();
|
|
304
304
|
|
|
305
305
|
if (RG_UNLIKELY(array.Length() != len)) {
|
|
306
306
|
ThrowError<Napi::Error>(env, "Expected array of length %1, got %2", len, array.Length());
|
|
@@ -407,15 +407,15 @@ bool CallData::PushArray(const Napi::Value &value, const TypeInfo *type, uint8_t
|
|
|
407
407
|
} break;
|
|
408
408
|
case PrimitiveKind::Record: {
|
|
409
409
|
PUSH_ARRAY(IsObject(value), "object", {
|
|
410
|
-
Napi::Object
|
|
411
|
-
if (!PushObject(
|
|
410
|
+
Napi::Object obj2 = value.As<Napi::Object>();
|
|
411
|
+
if (!PushObject(obj2, type->ref, dest, realign))
|
|
412
412
|
return false;
|
|
413
413
|
});
|
|
414
414
|
} break;
|
|
415
415
|
case PrimitiveKind::Array: {
|
|
416
416
|
PUSH_ARRAY(value.IsArray() || value.IsTypedArray() || value.IsString(), "array", {
|
|
417
|
-
Napi::Object
|
|
418
|
-
if (!PushArray(
|
|
417
|
+
Napi::Object array2 = value.As<Napi::Array>();
|
|
418
|
+
if (!PushArray(array2, type->ref, dest, realign))
|
|
419
419
|
return false;
|
|
420
420
|
});
|
|
421
421
|
} break;
|
|
@@ -434,8 +434,8 @@ bool CallData::PushArray(const Napi::Value &value, const TypeInfo *type, uint8_t
|
|
|
434
434
|
}
|
|
435
435
|
|
|
436
436
|
#undef PUSH_ARRAY
|
|
437
|
-
} else if (
|
|
438
|
-
Napi::TypedArray array =
|
|
437
|
+
} else if (obj.IsTypedArray()) {
|
|
438
|
+
Napi::TypedArray array = obj.As<Napi::TypedArray>();
|
|
439
439
|
const uint8_t *buf = (const uint8_t *)array.ArrayBuffer().Data();
|
|
440
440
|
|
|
441
441
|
if (RG_UNLIKELY(array.ElementLength() != len)) {
|
|
@@ -469,23 +469,23 @@ bool CallData::PushArray(const Napi::Value &value, const TypeInfo *type, uint8_t
|
|
|
469
469
|
|
|
470
470
|
dest += type->ref->size;
|
|
471
471
|
}
|
|
472
|
-
} else if (
|
|
473
|
-
size_t
|
|
472
|
+
} else if (obj.IsString()) {
|
|
473
|
+
size_t encoded = 0;
|
|
474
474
|
|
|
475
475
|
if (type->ref->primitive == PrimitiveKind::Int8 || type->ref->primitive == PrimitiveKind::UInt8) {
|
|
476
|
-
napi_status status = napi_get_value_string_utf8(env,
|
|
476
|
+
napi_status status = napi_get_value_string_utf8(env, obj, (char *)dest, type->size, &encoded);
|
|
477
477
|
RG_ASSERT(status == napi_ok);
|
|
478
478
|
} else if (type->ref->primitive == PrimitiveKind::Int16 || type->ref->primitive == PrimitiveKind::UInt16) {
|
|
479
|
-
napi_status status = napi_get_value_string_utf16(env,
|
|
479
|
+
napi_status status = napi_get_value_string_utf16(env, obj, (char16_t *)dest, type->size / 2, &encoded);
|
|
480
480
|
RG_ASSERT(status == napi_ok);
|
|
481
481
|
|
|
482
|
-
|
|
482
|
+
encoded *= 2;
|
|
483
483
|
} else {
|
|
484
484
|
ThrowError<Napi::TypeError>(env, "Strings cannot be converted to %1 array", type->ref->name);
|
|
485
485
|
return false;
|
|
486
486
|
}
|
|
487
487
|
|
|
488
|
-
memset_safe(dest +
|
|
488
|
+
memset_safe(dest + encoded, 0, type->size - encoded);
|
|
489
489
|
} else {
|
|
490
490
|
RG_UNREACHABLE();
|
|
491
491
|
}
|
package/src/call.hh
CHANGED
|
@@ -78,7 +78,7 @@ private:
|
|
|
78
78
|
const char *PushString(const Napi::Value &value);
|
|
79
79
|
const char16_t *PushString16(const Napi::Value &value);
|
|
80
80
|
bool PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t *dest, int16_t realign = 0);
|
|
81
|
-
bool PushArray(const Napi::Value &
|
|
81
|
+
bool PushArray(const Napi::Value &obj, const TypeInfo *type, uint8_t *dest, int16_t realign = 0);
|
|
82
82
|
|
|
83
83
|
void PopObject(Napi::Object obj, const uint8_t *src, const TypeInfo *type, int16_t realign = 0);
|
|
84
84
|
Napi::Object PopObject(const uint8_t *src, const TypeInfo *type, int16_t realign = 0);
|
package/src/ffi.cc
CHANGED
|
@@ -653,9 +653,13 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
|
|
|
653
653
|
if (!ParseClassicFunction(env, info[0u].As<Napi::String>(), info[1u], info[2u].As<Napi::Array>(), func))
|
|
654
654
|
return env.Null();
|
|
655
655
|
} else if (info.Length() >= 1) {
|
|
656
|
-
|
|
656
|
+
if (!info[0].IsString()) {
|
|
657
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for prototype, expected string", GetValueType(instance, info[0]));
|
|
658
|
+
return env.Null();
|
|
659
|
+
}
|
|
657
660
|
|
|
658
|
-
|
|
661
|
+
std::string proto = info[0u].As<Napi::String>();
|
|
662
|
+
if (!ParsePrototype(env, proto.c_str(), func))
|
|
659
663
|
return env.Null();
|
|
660
664
|
} else {
|
|
661
665
|
ThrowError<Napi::TypeError>(env, "Expected 1 or 3 arguments, not %1", info.Length());
|
|
@@ -957,7 +961,6 @@ static void SetExports(Napi::Env env, Func func)
|
|
|
957
961
|
func("out", Napi::Function::New(env, MarkOut));
|
|
958
962
|
func("inout", Napi::Function::New(env, MarkInOut));
|
|
959
963
|
|
|
960
|
-
func("internal", Napi::Boolean::New(env, true));
|
|
961
964
|
#if defined(_WIN32)
|
|
962
965
|
func("extension", Napi::String::New(env, ".dll"));
|
|
963
966
|
#elif defined(__APPLE__)
|
|
@@ -1009,6 +1012,7 @@ static void InitInternal(v8::Local<v8::Object> target, v8::Local<v8::Value>,
|
|
|
1009
1012
|
FillRandomSafe(&instance->tag_lower, RG_SIZE(instance->tag_lower));
|
|
1010
1013
|
|
|
1011
1014
|
SetExports(env_napi, [&](const char *name, Napi::Value value) { SetValue(env, target, name, value); });
|
|
1015
|
+
SetValue(env, target, "internal", Napi::Boolean::New(env_cxx, true));
|
|
1012
1016
|
}
|
|
1013
1017
|
|
|
1014
1018
|
#else
|
|
@@ -1024,6 +1028,7 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
|
|
|
1024
1028
|
FillRandomSafe(&instance->tag_lower, RG_SIZE(instance->tag_lower));
|
|
1025
1029
|
|
|
1026
1030
|
SetExports(env, [&](const char *name, Napi::Value value) { exports.Set(name, value); });
|
|
1031
|
+
exports.Set("internal", Napi::Boolean::New(env, false));
|
|
1027
1032
|
|
|
1028
1033
|
return exports;
|
|
1029
1034
|
}
|
package/src/parser.cc
CHANGED
|
@@ -19,34 +19,27 @@
|
|
|
19
19
|
|
|
20
20
|
namespace RG {
|
|
21
21
|
|
|
22
|
-
bool PrototypeParser::Parse(
|
|
22
|
+
bool PrototypeParser::Parse(const char *str, FunctionInfo *out_func)
|
|
23
23
|
{
|
|
24
|
-
if (!proto.IsString()) {
|
|
25
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for prototype, expected string", GetValueType(instance, proto));
|
|
26
|
-
return false;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
std::string hold = proto;
|
|
30
|
-
|
|
31
24
|
tokens.Clear();
|
|
32
25
|
offset = 0;
|
|
33
26
|
valid = true;
|
|
34
27
|
|
|
35
|
-
Tokenize(
|
|
28
|
+
Tokenize(str);
|
|
36
29
|
|
|
37
|
-
|
|
38
|
-
if (
|
|
30
|
+
out_func->ret.type = ParseType();
|
|
31
|
+
if (out_func->ret.type->primitive == PrimitiveKind::Array) {
|
|
39
32
|
MarkError("You are not allowed to directly return C arrays");
|
|
40
33
|
return false;
|
|
41
34
|
}
|
|
42
35
|
if (Match("__cdecl")) {
|
|
43
|
-
|
|
36
|
+
out_func->convention = CallConvention::Cdecl;
|
|
44
37
|
} else if (Match("__stdcall")) {
|
|
45
|
-
|
|
38
|
+
out_func->convention = CallConvention::Stdcall;
|
|
46
39
|
} else if (Match("__fastcall")) {
|
|
47
|
-
|
|
40
|
+
out_func->convention = CallConvention::Fastcall;
|
|
48
41
|
}
|
|
49
|
-
|
|
42
|
+
out_func->name = ParseIdentifier();
|
|
50
43
|
|
|
51
44
|
Consume("(");
|
|
52
45
|
if (offset < tokens.len && tokens[offset] != ")") {
|
|
@@ -54,7 +47,7 @@ bool PrototypeParser::Parse(Napi::String proto, FunctionInfo *func)
|
|
|
54
47
|
ParameterInfo param = {};
|
|
55
48
|
|
|
56
49
|
if (Match("...")) {
|
|
57
|
-
|
|
50
|
+
out_func->variadic = true;
|
|
58
51
|
break;
|
|
59
52
|
}
|
|
60
53
|
|
|
@@ -83,18 +76,18 @@ bool PrototypeParser::Parse(Napi::String proto, FunctionInfo *func)
|
|
|
83
76
|
|
|
84
77
|
offset += (offset < tokens.len && IsIdentifier(tokens[offset]));
|
|
85
78
|
|
|
86
|
-
if (
|
|
79
|
+
if (out_func->parameters.len >= MaxParameters) {
|
|
87
80
|
MarkError("Functions cannot have more than %1 parameters", MaxParameters);
|
|
88
81
|
return false;
|
|
89
82
|
}
|
|
90
|
-
if ((param.directions & 2) && ++
|
|
83
|
+
if ((param.directions & 2) && ++out_func->out_parameters >= MaxOutParameters) {
|
|
91
84
|
MarkError("Functions cannot have more than out %1 parameters", MaxOutParameters);
|
|
92
85
|
return false;
|
|
93
86
|
}
|
|
94
87
|
|
|
95
|
-
param.offset =
|
|
88
|
+
param.offset = out_func->parameters.len;
|
|
96
89
|
|
|
97
|
-
|
|
90
|
+
out_func->parameters.Append(param);
|
|
98
91
|
|
|
99
92
|
if (offset >= tokens.len || tokens[offset] != ",")
|
|
100
93
|
break;
|
|
@@ -125,6 +118,17 @@ void PrototypeParser::Tokenize(const char *str)
|
|
|
125
118
|
Span<const char> tok = MakeSpan(str + i, j - i);
|
|
126
119
|
tokens.Append(tok);
|
|
127
120
|
|
|
121
|
+
i = j - 1;
|
|
122
|
+
} else if (IsAsciiDigit(c)) {
|
|
123
|
+
Size j = i;
|
|
124
|
+
while (str[++j] && IsAsciiDigit(str[j]));
|
|
125
|
+
if (str[j] == '.') {
|
|
126
|
+
while (str[++j] && IsAsciiDigit(str[j]));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
Span<const char> tok = MakeSpan(str + i, j - i);
|
|
130
|
+
tokens.Append(tok);
|
|
131
|
+
|
|
128
132
|
i = j - 1;
|
|
129
133
|
} else if (c == '.' && str[i + 1] == '.' && str[i + 2] == '.') {
|
|
130
134
|
tokens.Append("...");
|
|
@@ -250,4 +254,10 @@ bool PrototypeParser::IsIdentifier(Span<const char> tok) const
|
|
|
250
254
|
return IsAsciiAlpha(tok[0]) || tok[0] == '_';
|
|
251
255
|
}
|
|
252
256
|
|
|
257
|
+
bool ParsePrototype(Napi::Env env, const char *str, FunctionInfo *out_func)
|
|
258
|
+
{
|
|
259
|
+
PrototypeParser parser(env);
|
|
260
|
+
return parser.Parse(str, out_func);
|
|
261
|
+
}
|
|
262
|
+
|
|
253
263
|
}
|
package/src/parser.hh
CHANGED
|
@@ -36,7 +36,7 @@ class PrototypeParser {
|
|
|
36
36
|
public:
|
|
37
37
|
PrototypeParser(Napi::Env env) : env(env), instance(env.GetInstanceData<InstanceData>()) {}
|
|
38
38
|
|
|
39
|
-
bool Parse(
|
|
39
|
+
bool Parse(const char *str, FunctionInfo *out_func);
|
|
40
40
|
|
|
41
41
|
private:
|
|
42
42
|
void Tokenize(const char *str);
|
|
@@ -60,4 +60,6 @@ private:
|
|
|
60
60
|
}
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
+
bool ParsePrototype(Napi::Env env, const char *str, FunctionInfo *out_func);
|
|
64
|
+
|
|
63
65
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|