koffi 2.3.14 → 2.3.15
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 +7 -0
- package/build/2.3.15/koffi_darwin_arm64/koffi.node +0 -0
- package/build/{2.3.14 → 2.3.15}/koffi_darwin_x64/koffi.node +0 -0
- package/build/2.3.15/koffi_freebsd_arm64/koffi.node +0 -0
- package/build/2.3.15/koffi_freebsd_ia32/koffi.node +0 -0
- package/build/2.3.15/koffi_freebsd_x64/koffi.node +0 -0
- package/build/2.3.15/koffi_linux_arm32hf/koffi.node +0 -0
- package/build/2.3.15/koffi_linux_arm64/koffi.node +0 -0
- package/build/2.3.15/koffi_linux_ia32/koffi.node +0 -0
- package/build/2.3.15/koffi_linux_riscv64hf64/koffi.node +0 -0
- package/build/2.3.15/koffi_linux_x64/koffi.node +0 -0
- package/build/2.3.15/koffi_openbsd_ia32/koffi.node +0 -0
- package/build/2.3.15/koffi_openbsd_x64/koffi.node +0 -0
- package/build/2.3.15/koffi_win32_arm64/koffi.node +0 -0
- package/build/2.3.15/koffi_win32_ia32/koffi.node +0 -0
- package/build/2.3.15/koffi_win32_x64/koffi.node +0 -0
- package/doc/calls.md +54 -0
- package/package.json +2 -2
- package/src/core/libcc/libcc.cc +15 -0
- package/src/core/libcc/libcc.hh +7 -1
- package/src/koffi/src/ffi.cc +21 -4
- package/src/koffi/src/ffi.hh +6 -0
- package/src/koffi/src/util.cc +35 -12
- package/src/koffi/src/util.hh +2 -2
- package/build/2.3.14/koffi_darwin_arm64/koffi.node +0 -0
- package/build/2.3.14/koffi_freebsd_arm64/koffi.node +0 -0
- package/build/2.3.14/koffi_freebsd_ia32/koffi.node +0 -0
- package/build/2.3.14/koffi_freebsd_x64/koffi.node +0 -0
- package/build/2.3.14/koffi_linux_arm32hf/koffi.node +0 -0
- package/build/2.3.14/koffi_linux_arm64/koffi.node +0 -0
- package/build/2.3.14/koffi_linux_ia32/koffi.node +0 -0
- package/build/2.3.14/koffi_linux_riscv64hf64/koffi.node +0 -0
- package/build/2.3.14/koffi_linux_x64/koffi.node +0 -0
- package/build/2.3.14/koffi_openbsd_ia32/koffi.node +0 -0
- package/build/2.3.14/koffi_openbsd_x64/koffi.node +0 -0
- package/build/2.3.14/koffi_win32_arm64/koffi.node +0 -0
- package/build/2.3.14/koffi_win32_ia32/koffi.node +0 -0
- package/build/2.3.14/koffi_win32_x64/koffi.node +0 -0
- /package/build/{2.3.14 → 2.3.15}/koffi_win32_arm64/koffi.exp +0 -0
- /package/build/{2.3.14 → 2.3.15}/koffi_win32_arm64/koffi.lib +0 -0
- /package/build/{2.3.14 → 2.3.15}/koffi_win32_ia32/koffi.exp +0 -0
- /package/build/{2.3.14 → 2.3.15}/koffi_win32_ia32/koffi.lib +0 -0
- /package/build/{2.3.14 → 2.3.15}/koffi_win32_x64/koffi.exp +0 -0
- /package/build/{2.3.14 → 2.3.15}/koffi_win32_x64/koffi.lib +0 -0
package/CHANGELOG.md
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/doc/calls.md
CHANGED
|
@@ -68,6 +68,60 @@ The same can be done when declaring a function with a C-like prototype string, w
|
|
|
68
68
|
- `_Out_` for output parameters
|
|
69
69
|
- `_Inout_` for dual input/output parameters
|
|
70
70
|
|
|
71
|
+
### Primitive value
|
|
72
|
+
|
|
73
|
+
This Windows example enumerate all Chrome windows along with their PID and their title. The `GetWindowThreadProcessId()` function illustrates how to get a primitive value from an output argument.
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
const koffi = require('koffi');
|
|
77
|
+
const user32 = koffi.load('user32.dll');
|
|
78
|
+
|
|
79
|
+
const DWORD = koffi.alias('DWORD', 'uint32_t');
|
|
80
|
+
const HANDLE = koffi.pointer(koffi.opaque('HANDLE'));
|
|
81
|
+
const HWND = koffi.alias('HWND', HANDLE);
|
|
82
|
+
|
|
83
|
+
const FindWindowEx = user32.func('HWND __stdcall FindWindowExW(HWND hWndParent, HWND hWndChildAfter, const char16_t *lpszClass, const char16_t *lpszWindow)');
|
|
84
|
+
const GetWindowThreadProcessId = user32.func('DWORD __stdcall GetWindowThreadProcessId(HWND hWnd, _Out_ DWORD *lpdwProcessId)');
|
|
85
|
+
const GetWindowText = user32.func('int __stdcall GetWindowTextA(HWND hWnd, _Out_ uint8_t *lpString, int nMaxCount)');
|
|
86
|
+
|
|
87
|
+
for (let hwnd = null;;) {
|
|
88
|
+
hwnd = FindWindowEx(0, hwnd, 'Chrome_WidgetWin_1', null);
|
|
89
|
+
|
|
90
|
+
if (!hwnd)
|
|
91
|
+
break;
|
|
92
|
+
|
|
93
|
+
// Get PID
|
|
94
|
+
let pid;
|
|
95
|
+
{
|
|
96
|
+
let ptr = [null];
|
|
97
|
+
let tid = GetWindowThreadProcessId(hwnd, ptr);
|
|
98
|
+
|
|
99
|
+
if (!tid) {
|
|
100
|
+
// Maybe the process ended in-between?
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
pid = ptr[0];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Get window title
|
|
108
|
+
let title;
|
|
109
|
+
{
|
|
110
|
+
let buf = Buffer.allocUnsafe(1024);
|
|
111
|
+
let length = GetWindowText(hwnd, buf, buf.length);
|
|
112
|
+
|
|
113
|
+
if (!length) {
|
|
114
|
+
// Maybe the process ended in-between?
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
title = koffi.decode(buf, 'char', length);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
console.log({ PID: pid, Title: title });
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
71
125
|
### Struct example
|
|
72
126
|
|
|
73
127
|
This example calls the POSIX function `gettimeofday()`, and uses the prototype-like syntax.
|
package/package.json
CHANGED
package/src/core/libcc/libcc.cc
CHANGED
|
@@ -5891,6 +5891,8 @@ bool StreamReader::Open(Span<const uint8_t> buf, const char *filename,
|
|
|
5891
5891
|
RG_DEFER_N(err_guard) { error = true; };
|
|
5892
5892
|
error = false;
|
|
5893
5893
|
raw_read = 0;
|
|
5894
|
+
read_total = 0;
|
|
5895
|
+
read_max = -1;
|
|
5894
5896
|
|
|
5895
5897
|
this->filename = filename ? DuplicateString(filename, &str_alloc).ptr : "<memory>";
|
|
5896
5898
|
|
|
@@ -5912,6 +5914,8 @@ bool StreamReader::Open(FILE *fp, const char *filename, CompressionType compress
|
|
|
5912
5914
|
RG_DEFER_N(err_guard) { error = true; };
|
|
5913
5915
|
error = false;
|
|
5914
5916
|
raw_read = 0;
|
|
5917
|
+
read_total = 0;
|
|
5918
|
+
read_max = -1;
|
|
5915
5919
|
|
|
5916
5920
|
RG_ASSERT(fp);
|
|
5917
5921
|
RG_ASSERT(filename);
|
|
@@ -5935,6 +5939,8 @@ OpenResult StreamReader::Open(const char *filename, CompressionType compression_
|
|
|
5935
5939
|
RG_DEFER_N(err_guard) { error = true; };
|
|
5936
5940
|
error = false;
|
|
5937
5941
|
raw_read = 0;
|
|
5942
|
+
read_total = 0;
|
|
5943
|
+
read_max = -1;
|
|
5938
5944
|
|
|
5939
5945
|
RG_ASSERT(filename);
|
|
5940
5946
|
this->filename = DuplicateString(filename, &str_alloc).ptr;
|
|
@@ -5962,6 +5968,8 @@ bool StreamReader::Open(const std::function<Size(Span<uint8_t>)> &func, const ch
|
|
|
5962
5968
|
RG_DEFER_N(err_guard) { error = true; };
|
|
5963
5969
|
error = false;
|
|
5964
5970
|
raw_read = 0;
|
|
5971
|
+
read_total = 0;
|
|
5972
|
+
read_max = -1;
|
|
5965
5973
|
|
|
5966
5974
|
this->filename = filename ? DuplicateString(filename, &str_alloc).ptr : "<closure>";
|
|
5967
5975
|
|
|
@@ -6081,6 +6089,13 @@ Size StreamReader::Read(Span<uint8_t> out_buf)
|
|
|
6081
6089
|
eof = source.eof;
|
|
6082
6090
|
}
|
|
6083
6091
|
|
|
6092
|
+
if (RG_UNLIKELY(!error && read_max >= 0 && read_len > read_max - read_total)) {
|
|
6093
|
+
LogError("Exceeded max stream size of %1", FmtDiskSize(read_max));
|
|
6094
|
+
error = true;
|
|
6095
|
+
return -1;
|
|
6096
|
+
}
|
|
6097
|
+
read_total += read_len;
|
|
6098
|
+
|
|
6084
6099
|
return read_len;
|
|
6085
6100
|
}
|
|
6086
6101
|
|
package/src/core/libcc/libcc.hh
CHANGED
|
@@ -4229,6 +4229,9 @@ class StreamReader {
|
|
|
4229
4229
|
const char *filename = nullptr;
|
|
4230
4230
|
bool error = true;
|
|
4231
4231
|
|
|
4232
|
+
int64_t read_total = 0;
|
|
4233
|
+
int64_t read_max = -1;
|
|
4234
|
+
|
|
4232
4235
|
struct {
|
|
4233
4236
|
SourceType type = SourceType::Memory;
|
|
4234
4237
|
union U {
|
|
@@ -4289,15 +4292,18 @@ public:
|
|
|
4289
4292
|
|
|
4290
4293
|
const char *GetFileName() const { return filename; }
|
|
4291
4294
|
CompressionType GetCompressionType() const { return compression_type; }
|
|
4295
|
+
int64_t GetReadLimit() { return read_max; }
|
|
4292
4296
|
bool IsValid() const { return filename && !error; }
|
|
4293
4297
|
bool IsEOF() const { return eof; }
|
|
4294
4298
|
|
|
4295
4299
|
FILE *GetFile() const;
|
|
4296
4300
|
int GetDescriptor() const;
|
|
4297
4301
|
|
|
4302
|
+
void SetReadLimit(int64_t limit) { read_max = limit; }
|
|
4303
|
+
|
|
4298
4304
|
Size Read(Span<uint8_t> out_buf);
|
|
4299
4305
|
Size Read(Span<char> out_buf) { return Read(out_buf.As<uint8_t>()); }
|
|
4300
|
-
Size Read(Size
|
|
4306
|
+
Size Read(Size buf_len, void *out_buf) { return Read(MakeSpan((uint8_t *)out_buf, buf_len)); }
|
|
4301
4307
|
|
|
4302
4308
|
Size ReadAll(Size max_len, HeapArray<uint8_t> *out_buf);
|
|
4303
4309
|
Size ReadAll(Size max_len, HeapArray<char> *out_buf)
|
package/src/koffi/src/ffi.cc
CHANGED
|
@@ -816,6 +816,11 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
|
816
816
|
ArrayHint hint = {};
|
|
817
817
|
|
|
818
818
|
if (to == "Typed" || to == "typed") {
|
|
819
|
+
if (!(ref->flags & (int)TypeFlag::HasTypedArray)) {
|
|
820
|
+
ThrowError<Napi::Error>(env, "Array hint 'Typed' cannot be used with type %1", ref->name);
|
|
821
|
+
return env.Null();
|
|
822
|
+
}
|
|
823
|
+
|
|
819
824
|
hint = ArrayHint::Typed;
|
|
820
825
|
} else if (to == "Array" || to == "array") {
|
|
821
826
|
hint = ArrayHint::Array;
|
|
@@ -1733,7 +1738,6 @@ void LibraryHolder::Unref() const
|
|
|
1733
1738
|
}
|
|
1734
1739
|
}
|
|
1735
1740
|
|
|
1736
|
-
|
|
1737
1741
|
static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initializer_list<const char *> names,
|
|
1738
1742
|
PrimitiveKind primitive, int32_t size, int16_t align, const char *ref = nullptr)
|
|
1739
1743
|
{
|
|
@@ -1750,6 +1754,13 @@ static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initiali
|
|
|
1750
1754
|
type->size = size;
|
|
1751
1755
|
type->align = align;
|
|
1752
1756
|
|
|
1757
|
+
if (IsInteger(type) || IsFloat(type)) {
|
|
1758
|
+
type->flags |= (int)TypeFlag::HasTypedArray;
|
|
1759
|
+
}
|
|
1760
|
+
if (TestStr(type->name, "char") || TestStr(type->name, "char16") || TestStr(type->name, "char16_t")) {
|
|
1761
|
+
type->flags |= (int)TypeFlag::IsCharLike;
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1753
1764
|
if (ref) {
|
|
1754
1765
|
const TypeInfo *marker = instance->types_map.FindValue(ref, nullptr);
|
|
1755
1766
|
RG_ASSERT(marker);
|
|
@@ -1999,10 +2010,16 @@ static Napi::Value DecodeValue(const Napi::CallbackInfo &info)
|
|
|
1999
2010
|
|
|
2000
2011
|
Napi::Value value = info[0];
|
|
2001
2012
|
int64_t offset = has_offset ? info[1].As<Napi::Number>().Int64Value() : 0;
|
|
2002
|
-
int64_t len = has_len ? info[2u + has_offset].As<Napi::Number>().Int64Value() : -1;
|
|
2003
2013
|
|
|
2004
|
-
|
|
2005
|
-
|
|
2014
|
+
if (has_len) {
|
|
2015
|
+
Size len = info[2u + has_offset].As<Napi::Number>();
|
|
2016
|
+
|
|
2017
|
+
Napi::Value ret = Decode(value, offset, type, &len);
|
|
2018
|
+
return ret;
|
|
2019
|
+
} else {
|
|
2020
|
+
Napi::Value ret = Decode(value, offset, type);
|
|
2021
|
+
return ret;
|
|
2022
|
+
}
|
|
2006
2023
|
}
|
|
2007
2024
|
|
|
2008
2025
|
static Napi::Value GetPointerAddress(const Napi::CallbackInfo &info)
|
package/src/koffi/src/ffi.hh
CHANGED
|
@@ -103,6 +103,11 @@ struct FunctionInfo;
|
|
|
103
103
|
|
|
104
104
|
typedef void DisposeFunc (Napi::Env env, const TypeInfo *type, const void *ptr);
|
|
105
105
|
|
|
106
|
+
enum class TypeFlag {
|
|
107
|
+
HasTypedArray = 1 << 0,
|
|
108
|
+
IsCharLike = 1 << 1
|
|
109
|
+
};
|
|
110
|
+
|
|
106
111
|
enum class ArrayHint {
|
|
107
112
|
Array,
|
|
108
113
|
Typed,
|
|
@@ -120,6 +125,7 @@ struct TypeInfo {
|
|
|
120
125
|
PrimitiveKind primitive;
|
|
121
126
|
int32_t size;
|
|
122
127
|
int16_t align;
|
|
128
|
+
uint16_t flags;
|
|
123
129
|
|
|
124
130
|
DisposeFunc *dispose;
|
|
125
131
|
Napi::FunctionReference dispose_ref;
|
package/src/koffi/src/util.cc
CHANGED
|
@@ -329,11 +329,12 @@ const TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size
|
|
|
329
329
|
{
|
|
330
330
|
ArrayHint hint = {};
|
|
331
331
|
|
|
332
|
-
if (
|
|
333
|
-
TestStr(ref->name, "char16_t")) {
|
|
332
|
+
if (ref->flags & (int)TypeFlag::IsCharLike) {
|
|
334
333
|
hint = ArrayHint::String;
|
|
335
|
-
} else {
|
|
334
|
+
} else if (ref->flags & (int)TypeFlag::HasTypedArray) {
|
|
336
335
|
hint = ArrayHint::Typed;
|
|
336
|
+
} else {
|
|
337
|
+
hint = ArrayHint::Array;
|
|
337
338
|
}
|
|
338
339
|
|
|
339
340
|
return MakeArrayType(instance, ref, len, hint, true);
|
|
@@ -1002,7 +1003,7 @@ void DecodeBuffer(Span<uint8_t> buffer, const uint8_t *origin, const TypeInfo *r
|
|
|
1002
1003
|
#undef SWAP
|
|
1003
1004
|
}
|
|
1004
1005
|
|
|
1005
|
-
Napi::Value Decode(Napi::Value value, Size offset, const TypeInfo *type, Size len)
|
|
1006
|
+
Napi::Value Decode(Napi::Value value, Size offset, const TypeInfo *type, const Size *len)
|
|
1006
1007
|
{
|
|
1007
1008
|
Napi::Env env = value.Env();
|
|
1008
1009
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
@@ -1035,13 +1036,35 @@ Napi::Value Decode(Napi::Value value, Size offset, const TypeInfo *type, Size le
|
|
|
1035
1036
|
return ret;
|
|
1036
1037
|
}
|
|
1037
1038
|
|
|
1038
|
-
Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, Size len)
|
|
1039
|
+
Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, const Size *len)
|
|
1039
1040
|
{
|
|
1040
1041
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
1041
1042
|
|
|
1042
|
-
if (len
|
|
1043
|
-
|
|
1044
|
-
|
|
1043
|
+
if (len && type->primitive != PrimitiveKind::String &&
|
|
1044
|
+
type->primitive != PrimitiveKind::String16) {
|
|
1045
|
+
if (*len >= 0) {
|
|
1046
|
+
type = MakeArrayType(instance, type, *len);
|
|
1047
|
+
} else {
|
|
1048
|
+
if (RG_UNLIKELY(!(type->flags & (int)TypeFlag::IsCharLike))) {
|
|
1049
|
+
ThrowError<Napi::TypeError>(env, "Only char-like types can find their length automatically", type->name);
|
|
1050
|
+
return env.Null();
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
switch (type->primitive) {
|
|
1054
|
+
case PrimitiveKind::Int8: {
|
|
1055
|
+
Size count = strlen((const char *)ptr);
|
|
1056
|
+
type = MakeArrayType(instance, type, count);
|
|
1057
|
+
} break;
|
|
1058
|
+
case PrimitiveKind::Int16: {
|
|
1059
|
+
Size count = WideStringLength((const char16_t *)ptr, RG_SIZE_MAX);
|
|
1060
|
+
type = MakeArrayType(instance, type, count);
|
|
1061
|
+
} break;
|
|
1062
|
+
|
|
1063
|
+
default: { RG_UNREACHABLE(); } break;
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1045
1068
|
}
|
|
1046
1069
|
|
|
1047
1070
|
#define RETURN_INT(Type, NewCall) \
|
|
@@ -1080,18 +1103,18 @@ Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, Size
|
|
|
1080
1103
|
case PrimitiveKind::UInt64: { RETURN_INT(uint64_t, NewBigInt); } break;
|
|
1081
1104
|
case PrimitiveKind::UInt64S: { RETURN_INT_SWAP(uint64_t, NewBigInt); } break;
|
|
1082
1105
|
case PrimitiveKind::String: {
|
|
1083
|
-
if (len
|
|
1106
|
+
if (len) {
|
|
1084
1107
|
const char *str = *(const char **)ptr;
|
|
1085
|
-
return str ? Napi::String::New(env, str, len) : env.Null();
|
|
1108
|
+
return str ? Napi::String::New(env, str, *len) : env.Null();
|
|
1086
1109
|
} else {
|
|
1087
1110
|
const char *str = *(const char **)ptr;
|
|
1088
1111
|
return str ? Napi::String::New(env, str) : env.Null();
|
|
1089
1112
|
}
|
|
1090
1113
|
} break;
|
|
1091
1114
|
case PrimitiveKind::String16: {
|
|
1092
|
-
if (len
|
|
1115
|
+
if (len) {
|
|
1093
1116
|
const char16_t *str16 = *(const char16_t **)ptr;
|
|
1094
|
-
return str16 ? Napi::String::New(env, str16, len) : env.Null();
|
|
1117
|
+
return str16 ? Napi::String::New(env, str16, *len) : env.Null();
|
|
1095
1118
|
} else {
|
|
1096
1119
|
const char16_t *str16 = *(const char16_t **)ptr;
|
|
1097
1120
|
return str16 ? Napi::String::New(env, str16) : env.Null();
|
package/src/koffi/src/util.hh
CHANGED
|
@@ -160,8 +160,8 @@ Napi::Value DecodeArray(Napi::Env env, const uint8_t *origin, const TypeInfo *ty
|
|
|
160
160
|
void DecodeNormalArray(Napi::Array array, const uint8_t *origin, const TypeInfo *ref);
|
|
161
161
|
void DecodeBuffer(Span<uint8_t> buffer, const uint8_t *origin, const TypeInfo *ref);
|
|
162
162
|
|
|
163
|
-
Napi::Value Decode(Napi::Value value, Size offset, const TypeInfo *type, Size len =
|
|
164
|
-
Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, Size len =
|
|
163
|
+
Napi::Value Decode(Napi::Value value, Size offset, const TypeInfo *type, const Size *len = nullptr);
|
|
164
|
+
Napi::Value Decode(Napi::Env env, const uint8_t *ptr, const TypeInfo *type, const Size *len = nullptr);
|
|
165
165
|
|
|
166
166
|
static inline Napi::Value NewBigInt(Napi::Env env, int64_t value)
|
|
167
167
|
{
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|