koffi 2.2.6-beta.3 → 2.3.0-beta.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.
Files changed (40) hide show
  1. package/CHANGELOG.md +53 -32
  2. package/doc/callbacks.md +12 -5
  3. package/doc/calls.md +45 -1
  4. package/doc/contribute.md +0 -13
  5. package/package.json +1 -1
  6. package/src/koffi/build/2.3.0-beta.2/koffi_darwin_arm64.tar.gz +0 -0
  7. package/src/koffi/build/2.3.0-beta.2/koffi_darwin_x64.tar.gz +0 -0
  8. package/src/koffi/build/2.3.0-beta.2/koffi_freebsd_arm64.tar.gz +0 -0
  9. package/src/koffi/build/2.3.0-beta.2/koffi_freebsd_ia32.tar.gz +0 -0
  10. package/src/koffi/build/2.3.0-beta.2/koffi_freebsd_x64.tar.gz +0 -0
  11. package/src/koffi/build/2.3.0-beta.2/koffi_linux_arm32hf.tar.gz +0 -0
  12. package/src/koffi/build/2.3.0-beta.2/koffi_linux_arm64.tar.gz +0 -0
  13. package/src/koffi/build/2.3.0-beta.2/koffi_linux_ia32.tar.gz +0 -0
  14. package/src/koffi/build/2.3.0-beta.2/koffi_linux_riscv64hf64.tar.gz +0 -0
  15. package/src/koffi/build/2.3.0-beta.2/koffi_linux_x64.tar.gz +0 -0
  16. package/src/koffi/build/2.3.0-beta.2/koffi_openbsd_ia32.tar.gz +0 -0
  17. package/src/koffi/build/2.3.0-beta.2/koffi_openbsd_x64.tar.gz +0 -0
  18. package/src/koffi/build/2.3.0-beta.2/koffi_win32_arm64.tar.gz +0 -0
  19. package/src/koffi/build/2.3.0-beta.2/koffi_win32_ia32.tar.gz +0 -0
  20. package/src/koffi/build/2.3.0-beta.2/koffi_win32_x64.tar.gz +0 -0
  21. package/src/koffi/src/call.cc +6 -4
  22. package/src/koffi/src/ffi.cc +18 -20
  23. package/src/koffi/src/util.cc +44 -0
  24. package/src/koffi/src/util.hh +4 -1
  25. package/src/koffi/NUMERO SEQUENCE = PREFIXE ET SUFFIXE +0 -0
  26. package/src/koffi/build/2.2.6-beta.3/koffi_darwin_arm64.tar.gz +0 -0
  27. package/src/koffi/build/2.2.6-beta.3/koffi_darwin_x64.tar.gz +0 -0
  28. package/src/koffi/build/2.2.6-beta.3/koffi_freebsd_arm64.tar.gz +0 -0
  29. package/src/koffi/build/2.2.6-beta.3/koffi_freebsd_ia32.tar.gz +0 -0
  30. package/src/koffi/build/2.2.6-beta.3/koffi_freebsd_x64.tar.gz +0 -0
  31. package/src/koffi/build/2.2.6-beta.3/koffi_linux_arm32hf.tar.gz +0 -0
  32. package/src/koffi/build/2.2.6-beta.3/koffi_linux_arm64.tar.gz +0 -0
  33. package/src/koffi/build/2.2.6-beta.3/koffi_linux_ia32.tar.gz +0 -0
  34. package/src/koffi/build/2.2.6-beta.3/koffi_linux_riscv64hf64.tar.gz +0 -0
  35. package/src/koffi/build/2.2.6-beta.3/koffi_linux_x64.tar.gz +0 -0
  36. package/src/koffi/build/2.2.6-beta.3/koffi_openbsd_ia32.tar.gz +0 -0
  37. package/src/koffi/build/2.2.6-beta.3/koffi_openbsd_x64.tar.gz +0 -0
  38. package/src/koffi/build/2.2.6-beta.3/koffi_win32_arm64.tar.gz +0 -0
  39. package/src/koffi/build/2.2.6-beta.3/koffi_win32_ia32.tar.gz +0 -0
  40. package/src/koffi/build/2.2.6-beta.3/koffi_win32_x64.tar.gz +0 -0
package/CHANGELOG.md CHANGED
@@ -1,14 +1,16 @@
1
1
  # Changelog
2
2
 
3
- ## Koffi 2.x
3
+ ## Version history
4
4
 
5
- ### Koffi 2.2.5
5
+ ### Koffi 2.2
6
+
7
+ #### Koffi 2.2.5
6
8
 
7
9
  **Main changes:**
8
10
 
9
11
  - Relicense Koffi under LGPL 3.0
10
12
 
11
- ### Koffi 2.2.4
13
+ #### Koffi 2.2.4
12
14
 
13
15
  **Main fixes:**
14
16
 
@@ -18,7 +20,7 @@
18
20
 
19
21
  - Reorganize documentation pages
20
22
 
21
- ### Koffi 2.2.3
23
+ #### Koffi 2.2.3
22
24
 
23
25
  **Main fixes:**
24
26
 
@@ -28,7 +30,7 @@
28
30
 
29
31
  - Try to use ebp/rbp as frame pointer in x86/x64 ASM code
30
32
 
31
- ### Koffi 2.2.2
33
+ #### Koffi 2.2.2
32
34
 
33
35
  **Main fixes:**
34
36
 
@@ -42,13 +44,13 @@
42
44
  - Check N-API version when module is loaded
43
45
  - Optimize callback unregistration
44
46
 
45
- ### Koffi 2.2.1
47
+ #### Koffi 2.2.1
46
48
 
47
49
  **Main fixes:**
48
50
 
49
51
  - Fix crash when [calling callback again after FFI call inside previous callback](https://github.com/Koromix/rygel/issues/15)
50
52
 
51
- ### Koffi 2.2.0
53
+ #### Koffi 2.2.0
52
54
 
53
55
  **New features:**
54
56
 
@@ -62,13 +64,15 @@
62
64
  - Correctly validate output parameter types
63
65
  - Fix assertion with `void *` parameters
64
66
 
65
- ### Koffi 2.1.5
67
+ ### Koffi 2.1
68
+
69
+ #### Koffi 2.1.5
66
70
 
67
71
  **Main fixes:**
68
72
 
69
73
  - Add missing README.md file to NPM package
70
74
 
71
- ### Koffi 2.1.4
75
+ #### Koffi 2.1.4
72
76
 
73
77
  **Main changes:**
74
78
 
@@ -79,25 +83,25 @@
79
83
 
80
84
  - Moved Koffi to a new repository: https://github.com/Koromix/rygel/
81
85
 
82
- ### Koffi 2.1.3
86
+ #### Koffi 2.1.3
83
87
 
84
88
  **Main changes:**
85
89
 
86
90
  - Support up to 16 output parameters (instead of 8)
87
91
 
88
- ### Koffi 2.1.2
92
+ #### Koffi 2.1.2
89
93
 
90
94
  **Main changes:**
91
95
 
92
96
  - Support up to 8 output parameters (instead of 4)
93
97
 
94
- ### Koffi 2.1.1
98
+ #### Koffi 2.1.1
95
99
 
96
100
  **Main fixes:**
97
101
 
98
102
  - Fix potential memory allocation bugs
99
103
 
100
- ### Koffi 2.1.0
104
+ #### Koffi 2.1.0
101
105
 
102
106
  **Main changes:**
103
107
 
@@ -115,13 +119,15 @@
115
119
  - Detect impossible parameter and return types (such as non-pointer opaque types)
116
120
  - Various documentation fixes and improvements
117
121
 
118
- ### Koffi 2.0.1
122
+ ### Koffi 2.0
123
+
124
+ #### Koffi 2.0.1
119
125
 
120
126
  **Main changes:**
121
127
 
122
128
  - Return `undefined` (instead of null) for `void` functions
123
129
 
124
- ### Koffi 2.0.0
130
+ #### Koffi 2.0.0
125
131
 
126
132
  **Major new features:**
127
133
 
@@ -145,21 +151,21 @@
145
151
 
146
152
  Consult the [migration guide](migration.md) for more information.
147
153
 
148
- ## Koffi 1.x
154
+ ### Koffi 1.3
149
155
 
150
- ### Koffi 1.3.12
156
+ #### Koffi 1.3.12
151
157
 
152
158
  **Main fixes:**
153
159
 
154
160
  - Fix support for Yarn package manager
155
161
 
156
- ### Koffi 1.3.11
162
+ #### Koffi 1.3.11
157
163
 
158
164
  **Main fixes:**
159
165
 
160
166
  - Fix broken parsing of `void *` when used for first parameter
161
167
 
162
- ### Koffi 1.3.10
168
+ #### Koffi 1.3.10
163
169
 
164
170
  **Main fixes:**
165
171
 
@@ -171,13 +177,13 @@ Consult the [migration guide](migration.md) for more information.
171
177
 
172
178
  - Various documentation fixes and improvements
173
179
 
174
- ### Koffi 1.3.9
180
+ #### Koffi 1.3.9
175
181
 
176
182
  **Main fixes:**
177
183
 
178
184
  - Fix prebuild compatibility with Electron on Windows x64
179
185
 
180
- ### Koffi 1.3.8
186
+ #### Koffi 1.3.8
181
187
 
182
188
  **Main changes:**
183
189
 
@@ -188,7 +194,7 @@ Consult the [migration guide](migration.md) for more information.
188
194
 
189
195
  - Fix and harmonize a few error messages
190
196
 
191
- ### Koffi 1.3.7
197
+ #### Koffi 1.3.7
192
198
 
193
199
  **Main fixes:**
194
200
 
@@ -201,7 +207,7 @@ Consult the [migration guide](migration.md) for more information.
201
207
  - Add str/str16 type aliases for string/string16
202
208
  - Various documentation fixes and improvements
203
209
 
204
- ### Koffi 1.3.6
210
+ #### Koffi 1.3.6
205
211
 
206
212
  **Main fixes:**
207
213
 
@@ -213,7 +219,7 @@ Consult the [migration guide](migration.md) for more information.
213
219
  - Prebuild with Clang for Windows x64 and Linux x64 binaries
214
220
  - Various documentation improvements
215
221
 
216
- ### Koffi 1.3.5
222
+ #### Koffi 1.3.5
217
223
 
218
224
  **Main changes:**
219
225
 
@@ -225,13 +231,13 @@ Consult the [migration guide](migration.md) for more information.
225
231
  - Reduce default async memory stack and heap size
226
232
  - Various documentation improvements
227
233
 
228
- ### Koffi 1.3.4
234
+ #### Koffi 1.3.4
229
235
 
230
236
  **Main fixes:**
231
237
 
232
238
  - Fix possible OpenBSD i386 crash with `(void)` functions
233
239
 
234
- ### Koffi 1.3.3
240
+ #### Koffi 1.3.3
235
241
 
236
242
  **Main fixes:**
237
243
 
@@ -243,20 +249,20 @@ Consult the [migration guide](migration.md) for more information.
243
249
  - Disable unsafe compiler optimizations
244
250
  - Various documentation improvements
245
251
 
246
- ### Koffi 1.3.2
252
+ #### Koffi 1.3.2
247
253
 
248
254
  **Main fixes:**
249
255
 
250
256
  - Support compilation in C++14 mode (graceful degradation)
251
257
  - Support older toolchains on Linux (tested on Debian 9)
252
258
 
253
- ### Koffi 1.3.1
259
+ #### Koffi 1.3.1
254
260
 
255
261
  **Main fixes:**
256
262
 
257
263
  - The prebuilt binary is tested when Koffi is installed, and a rebuild happens if it fails to load
258
264
 
259
- ### Koffi 1.3.0
265
+ #### Koffi 1.3.0
260
266
 
261
267
  **Major changes:**
262
268
 
@@ -272,19 +278,21 @@ Consult the [migration guide](migration.md) for more information.
272
278
  - Detect floating-point ABI before using prebuilt binaries (ARM32, RISC-V)
273
279
  - Forbid duplicate member names in struct types
274
280
 
275
- ### Koffi 1.2.4
281
+ ### Koffi 1.2
282
+
283
+ #### Koffi 1.2.4
276
284
 
277
285
  **New features:**
278
286
 
279
287
  - Windows ARM64 is now supported
280
288
 
281
- ### Koffi 1.2.3
289
+ #### Koffi 1.2.3
282
290
 
283
291
  **New features:**
284
292
 
285
293
  - A prebuilt binary for macOS ARM64 (M1) is now included
286
294
 
287
- ### Koffi 1.2.1
295
+ #### Koffi 1.2.1
288
296
 
289
297
  This entry documents changes since version 1.1.0.
290
298
 
@@ -308,3 +316,16 @@ This entry documents changes since version 1.1.0.
308
316
  - Fix value `koffi.internal` to false in module (normal) builds
309
317
  - Make sure we have a redzone below the stack for all architectures
310
318
  - Use slower allocation for big objects instead of failing
319
+
320
+ ## Todo list
321
+
322
+ The following features and improvements are planned, not necessarily in that order:
323
+
324
+ - Optimize passing of structs and arrays (avoid setting named properties one by one? separate HFA-specific helper functions?)
325
+ - Automate Windows/AArch64 (qemu) and macOS/AArch64 (how? ... thanks Apple) tests
326
+ - Create a real-world example, using several libraries (Raylib, SQLite, libsodium) to illustrate various C API styles
327
+ - Add simple struct type parser
328
+ - Add more ways to manually encode and decode various types to and from byte arrays
329
+ - Add support for unions
330
+ - Port Koffi to PowerPC (POWER9+) ABI
331
+ - Fix assembly unwind and CFI directives for better debugging experience
package/doc/callbacks.md CHANGED
@@ -136,18 +136,16 @@ let cb2 = koffi.register(store, store.get, 'IntCallback *'); // However in this
136
136
 
137
137
  ## Pointer arguments
138
138
 
139
- *New in Koffi 2.2*
139
+ *New in Koffi 2.2, changed in Koffi 2.3*
140
140
 
141
141
  Koffi does not have enough information to convert callback pointer arguments to an appropriate JS value. In this case, your JS function will receive an opaque *External* object.
142
142
 
143
- You can pass this value through to another C function that expects a pointer of the same type, or you can use `koffi.decode(value, offset, type, len)` to decode it into something you can use in Javascript.
143
+ You can pass this value through to another C function that expects a pointer of the same type, or you can use `koffi.decode()` to decode it into something you can use in Javascript.
144
144
 
145
145
  Some arguments are optional and this function can be called in several ways:
146
146
 
147
- - `koffi.decode(value, offset, type, len)`: this is the full signature, value is the JS external object, offset (optional, defaults to 0) is specified in bytes, type is the value type, and length (optional) can be used for arrays and strings.
148
147
  - `koffi.decode(value, type)`: no offset, expect NUL-terminated strings
149
- - `koffi.decode(value, type, len)`: use specified length when decoding strings and arrays
150
- - `koffi.decode(value, offset, type)`
148
+ - `koffi.decode(value, offset, type)`: explicit offset to add to the pointer before decoding
151
149
 
152
150
  The following example sorts an array of strings (in-place) with `qsort()`:
153
151
 
@@ -170,6 +168,15 @@ qsort(koffi.as(array, 'char **'), array.length, koffi.sizeof('void *'), (ptr1, p
170
168
  console.log(array); // Prints ['123', 'bar', 'foo', 'foobar']
171
169
  ```
172
170
 
171
+ There is also an optional ending `length` argument that you can use in two cases:
172
+
173
+ - Use it to give the number of bytes to decode in non-NUL terminated strings: `koffi.decode(value, 'char *', 5)`
174
+ - Decode consecutive values into an array. For example, here is how you can decode an array with 3 float values: `koffi.decode(value, 'float', 3)`. This is equivalent to `koffi.decode(value, koffi.array('float', 3))`.
175
+
176
+ ```{note}
177
+ In Koffi 2.2 and earlier versions, the length argument is only used to decode strings and is ignored otherwise.
178
+ ```
179
+
173
180
  ## Asynchronous callbacks
174
181
 
175
182
  *New in Koffi 2.2.2*
package/doc/calls.md CHANGED
@@ -159,13 +159,15 @@ console.log(out[0]);
159
159
 
160
160
  ## Polymorphic parameters
161
161
 
162
+ ### Input parameters
163
+
162
164
  *New in Koffi 2.1*
163
165
 
164
166
  Many C functions use `void *` parameters in order to pass polymorphic objects and arrays, meaning that the data format changes can change depending on one other argument, or on some kind of struct tag member.
165
167
 
166
168
  Koffi provides two features to deal with this:
167
169
 
168
- - Typed JS arrays can be used as values in place everywhere `void *` is expected. See [dynamic arrays](types.md#array-pointers-dynamic-arrays) for more information, for input or output.
170
+ - Buffers and typed JS arrays can be used as values in place everywhere a pointer is expected. See [dynamic arrays](pointers.md#array-pointers-dynamic-arrays) for more information, for input or output.
169
171
  - You can use `koffi.as(value, type)` to tell Koffi what kind of type is actually expected.
170
172
 
171
173
  The example below shows the use of `koffi.as()` to read the header of a PNG file with `fread()`.
@@ -219,6 +221,48 @@ let hdr = {};
219
221
  console.log('PNG header:', hdr);
220
222
  ```
221
223
 
224
+ ### Output parameters
225
+
226
+ *New in Koffi 2.3*
227
+
228
+ You can use buffers and typed arrays for output (and input/output) pointer parameters. Simply pass the buffer as an argument and the native function will receive a pointer to its contents.
229
+
230
+ Once the native function returns, you can decode the content with `koffi.decode(value, type)` as in the following example:
231
+
232
+ ```js
233
+ const koffi = require('koffi');
234
+ const lib = koffi.load('libc.so.6');
235
+
236
+ const Vec3 = koffi.struct('Vec3', {
237
+ x: 'float32',
238
+ y: 'float32',
239
+ z: 'float32'
240
+ })
241
+
242
+ const memcpy = lib.func('void *memcpy(_Out_ void *dest, const void *src, size_t size)');
243
+
244
+ let vec1 = { x: 1, y: 2, z: 3 };
245
+ let vec2 = null;
246
+
247
+ // Copy the vector in a convoluted way through memcpy
248
+ {
249
+ let src = koffi.as(vec1, 'Vec3 *');
250
+ let dest = Buffer.allocUnsafe(koffi.sizeof(Vec3));
251
+
252
+ memcpy(dest, src, koffi.sizeof(Vec3));
253
+
254
+ vec2 = koffi.decode(dest, Vec3);
255
+ }
256
+
257
+ // CHange vector1, leaving copy alone
258
+ [vec1.x, vec1.y, vec1.z] = [vec1.z, vec1.y, vec1.x];
259
+
260
+ console.log(vec1); // { x: 3, y: 2, z: 1 }
261
+ console.log(vec2); // { x: 1, y: 2, z: 3 }
262
+ ```
263
+
264
+ See [pointer arguments](callbacks.md#pointer-arguments) for more information about the decode function.
265
+
222
266
  ## Heap-allocated values
223
267
 
224
268
  *New in Koffi 2.0*
package/doc/contribute.md CHANGED
@@ -107,19 +107,6 @@ Each machine is configured to run a VNC server available locally, which you can
107
107
  node qemu.js info debian_x64
108
108
  ```
109
109
 
110
- ## Todo list
111
-
112
- The following features and improvements are planned, not necessarily in that order:
113
-
114
- - Optimize passing of structs and arrays (avoid setting named properties one by one? separate HFA-specific helper functions?)
115
- - Automate Windows/AArch64 (qemu) and macOS/AArch64 (how? ... thanks Apple) tests
116
- - Create a real-world example, using several libraries (Raylib, SQLite, libsodium) to illustrate various C API styles
117
- - Add simple struct type parser
118
- - Add more ways to manually encode and decode various types to and from byte arrays
119
- - Add support for unions
120
- - Port Koffi to PowerPC (POWER9+) ABI
121
- - Fix assembly unwind and CFI directives for better debugging experience
122
-
123
110
  ## Code style
124
111
 
125
112
  Koffi is programmed in a mix of C++ and assembly code (architecture-specific code). It uses [node-addon-api](https://github.com/nodejs/node-addon-api) (C++ N-API wrapper) to interact with Node.js.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "2.2.6-beta.3",
3
+ "version": "2.3.0-beta.2",
4
4
  "stable": "2.2.5",
5
5
  "description": "Fast and simple C FFI (foreign function interface) for Node.js",
6
6
  "keywords": [
@@ -923,15 +923,17 @@ bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directio
923
923
  memset_safe(ptr, 0, size);
924
924
  }
925
925
  } else if (IsRawBuffer(value)) {
926
- Span<const uint8_t> buffer = GetRawBuffer(value);
926
+ Span<uint8_t> buffer = GetRawBuffer(value);
927
927
 
928
- ptr = AllocHeap(buffer.len, 16);
928
+ if (directions == 1) {
929
+ ptr = AllocHeap(buffer.len, 16);
929
930
 
930
- if (directions & 1) {
931
931
  if (!PushBuffer(buffer, buffer.len, type, ptr))
932
932
  return false;
933
933
  } else {
934
- memset_safe(ptr, 0, (size_t)buffer.len);
934
+ // Fast no-copy path
935
+ ptr = buffer.ptr;
936
+ directions = 1;
935
937
  }
936
938
  } else if (RG_LIKELY(type->ref.type->primitive == PrimitiveKind::Record)) {
937
939
  Napi::Object obj = value.As<Napi::Object>();
@@ -626,7 +626,8 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
626
626
  return env.Null();
627
627
  }
628
628
 
629
- TypeInfo::ArrayHint hint;
629
+ const TypeInfo *type = nullptr;
630
+
630
631
  if (info.Length() >= 3 && !IsNullOrUndefined(info[2])) {
631
632
  if (!info[2].IsString()) {
632
633
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for hint, expected string", GetValueType(instance, info[2]));
@@ -634,6 +635,7 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
634
635
  }
635
636
 
636
637
  std::string to = info[2].As<Napi::String>();
638
+ TypeInfo::ArrayHint hint = {};
637
639
 
638
640
  if (to == "typed") {
639
641
  hint = TypeInfo::ArrayHint::TypedArray;
@@ -650,24 +652,13 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
650
652
  ThrowError<Napi::Error>(env, "Array conversion hint must be 'typed', 'array' or 'string'");
651
653
  return env.Null();
652
654
  }
653
- } else if (TestStr(ref->name, "char") || TestStr(ref->name, "char16") ||
654
- TestStr(ref->name, "char16_t")) {
655
- hint = TypeInfo::ArrayHint::String;
655
+
656
+ type = MakeArrayType(instance, ref, len, hint);
656
657
  } else {
657
- hint = TypeInfo::ArrayHint::TypedArray;
658
+ type = MakeArrayType(instance, ref, len);
658
659
  }
659
660
 
660
- TypeInfo *type = instance->types.AppendDefault();
661
-
662
- type->name = Fmt(&instance->str_alloc, "%1[%2]", ref->name, len).ptr;
663
-
664
- type->primitive = PrimitiveKind::Array;
665
- type->align = ref->align;
666
- type->size = (int32_t)(len * ref->size);
667
- type->ref.type = ref;
668
- type->hint = hint;
669
-
670
- Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, type);
661
+ Napi::External<TypeInfo> external = Napi::External<TypeInfo>::New(env, (TypeInfo *)type);
671
662
  SetValueTag(instance, external, &TypeInfoMarker);
672
663
 
673
664
  return external;
@@ -1837,10 +1828,6 @@ static Napi::Value DecodeValue(const Napi::CallbackInfo &info)
1837
1828
  ThrowError<Napi::TypeError>(env, "Expected %1 to 4 arguments, got %2", 2 + has_offset, info.Length());
1838
1829
  return env.Null();
1839
1830
  }
1840
- if (has_len && RG_UNLIKELY(!info[2u + has_offset].IsNumber())) {
1841
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for length, expected number", GetValueType(instance, info[2 + has_offset]));
1842
- return env.Null();
1843
- }
1844
1831
 
1845
1832
  const TypeInfo *type = ResolveType(info[1u + has_offset]);
1846
1833
  if (RG_UNLIKELY(!type))
@@ -1876,6 +1863,17 @@ static Napi::Value DecodeValue(const Napi::CallbackInfo &info)
1876
1863
  // Used for strings and arrays, ignored otherwise
1877
1864
  int64_t len = has_len ? info[2u + has_offset].As<Napi::Number>().Int64Value() : -1;
1878
1865
 
1866
+ if (has_len) {
1867
+ if (RG_UNLIKELY(len < 0)) {
1868
+ ThrowError<Napi::TypeError>(env, "Length must not be a negative value");
1869
+ return env.Null();
1870
+ }
1871
+
1872
+ if (type->primitive != PrimitiveKind::String && type->primitive != PrimitiveKind::String16) {
1873
+ type = MakeArrayType(instance, type, len);
1874
+ }
1875
+ }
1876
+
1879
1877
  #define RETURN_INT(Type, NewCall) \
1880
1878
  do { \
1881
1879
  Type v = *(Type *)ptr; \
@@ -170,6 +170,50 @@ const TypeInfo *MakePointerType(InstanceData *instance, const TypeInfo *ref, int
170
170
  return ref;
171
171
  }
172
172
 
173
+ static const TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len,
174
+ TypeInfo::ArrayHint hint, bool insert)
175
+ {
176
+ RG_ASSERT(len > 0);
177
+ RG_ASSERT(len <= instance->max_type_size / ref->size);
178
+
179
+ TypeInfo *type = instance->types.AppendDefault();
180
+
181
+ type->name = Fmt(&instance->str_alloc, "%1[%2]", ref->name, len).ptr;
182
+
183
+ type->primitive = PrimitiveKind::Array;
184
+ type->align = ref->align;
185
+ type->size = (int32_t)(len * ref->size);
186
+ type->ref.type = ref;
187
+ type->hint = hint;
188
+
189
+ if (insert) {
190
+ bool inserted;
191
+ type = (TypeInfo *)*instance->types_map.TrySet(type->name, type, &inserted);
192
+ instance->types.RemoveLast(!inserted);
193
+ }
194
+
195
+ return type;
196
+ }
197
+
198
+ const TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len)
199
+ {
200
+ TypeInfo::ArrayHint hint = {};
201
+
202
+ if (TestStr(ref->name, "char") || TestStr(ref->name, "char16") ||
203
+ TestStr(ref->name, "char16_t")) {
204
+ hint = TypeInfo::ArrayHint::String;
205
+ } else {
206
+ hint = TypeInfo::ArrayHint::TypedArray;
207
+ }
208
+
209
+ return MakeArrayType(instance, ref, len, hint, true);
210
+ }
211
+
212
+ const TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len, TypeInfo::ArrayHint hint)
213
+ {
214
+ return MakeArrayType(instance, ref, len, hint, false);
215
+ }
216
+
173
217
  bool CanPassType(const TypeInfo *type, int directions)
174
218
  {
175
219
  if (directions & 2) {
@@ -55,7 +55,10 @@ static inline bool IsRegularSize(Size size, Size max)
55
55
 
56
56
  const TypeInfo *ResolveType(Napi::Value value, int *out_directions = nullptr);
57
57
  const TypeInfo *ResolveType(InstanceData *instance, Span<const char> str, int *out_directions = nullptr);
58
- const TypeInfo *MakePointerType(InstanceData *instance, const TypeInfo *type, int count = 1);
58
+
59
+ const TypeInfo *MakePointerType(InstanceData *instance, const TypeInfo *ref, int count = 1);
60
+ const TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len);
61
+ const TypeInfo *MakeArrayType(InstanceData *instance, const TypeInfo *ref, Size len, TypeInfo::ArrayHint hint);
59
62
 
60
63
  bool CanPassType(const TypeInfo *type, int directions);
61
64
  bool CanReturnType(const TypeInfo *type);
File without changes