node-ctypes 0.1.3 → 0.1.5
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/README.md +66 -37
- package/build/Release/ctypes-darwin-arm64.node +0 -0
- package/build/Release/ctypes-linux-arm64.node +0 -0
- package/build/Release/ctypes-linux-x64.node +0 -0
- package/build/Release/ctypes-win32-arm64.node +0 -0
- package/build/Release/ctypes-win32-x64.node +0 -0
- package/lib/index.d.ts +24 -127
- package/lib/index.js +386 -435
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -23,12 +23,7 @@ const getNativeModulePath = (moduleName, nativeFile, config = "Release") => {
|
|
|
23
23
|
if (process.versions?.electron) {
|
|
24
24
|
const electronProcess = process;
|
|
25
25
|
if (electronProcess.resourcesPath) {
|
|
26
|
-
const unpackedPath = path.join(
|
|
27
|
-
electronProcess.resourcesPath,
|
|
28
|
-
"app.asar.unpacked",
|
|
29
|
-
"node_modules",
|
|
30
|
-
moduleName,
|
|
31
|
-
);
|
|
26
|
+
const unpackedPath = path.join(electronProcess.resourcesPath, "app.asar.unpacked", "node_modules", moduleName);
|
|
32
27
|
if (existsSync(buildPath(unpackedPath))) {
|
|
33
28
|
return buildPath(unpackedPath);
|
|
34
29
|
}
|
|
@@ -36,9 +31,7 @@ const getNativeModulePath = (moduleName, nativeFile, config = "Release") => {
|
|
|
36
31
|
}
|
|
37
32
|
|
|
38
33
|
// Check in current working directory's node_modules
|
|
39
|
-
const cwdPath = buildPath(
|
|
40
|
-
path.join(process.cwd(), "node_modules", moduleName),
|
|
41
|
-
);
|
|
34
|
+
const cwdPath = buildPath(path.join(process.cwd(), "node_modules", moduleName));
|
|
42
35
|
if (existsSync(cwdPath)) {
|
|
43
36
|
return cwdPath;
|
|
44
37
|
}
|
|
@@ -58,10 +51,7 @@ const getNativeModulePath = (moduleName, nativeFile, config = "Release") => {
|
|
|
58
51
|
}
|
|
59
52
|
}
|
|
60
53
|
|
|
61
|
-
throw new Error(
|
|
62
|
-
`Native module "${nativeFile}" not found for "${moduleName}". ` +
|
|
63
|
-
`Searched in Electron resources, node_modules, and local build.`,
|
|
64
|
-
);
|
|
54
|
+
throw new Error(`Native module "${nativeFile}" not found for "${moduleName}". ` + `Searched in Electron resources, node_modules, and local build.`);
|
|
65
55
|
};
|
|
66
56
|
|
|
67
57
|
// Load the native module
|
|
@@ -71,25 +61,13 @@ try {
|
|
|
71
61
|
} catch (e) {
|
|
72
62
|
const platform = process.platform;
|
|
73
63
|
const arch = process.arch;
|
|
74
|
-
nativeModulePath = getNativeModulePath(
|
|
75
|
-
"node-ctypes",
|
|
76
|
-
`ctypes-${platform}-${arch}.node`,
|
|
77
|
-
);
|
|
64
|
+
nativeModulePath = getNativeModulePath("node-ctypes", `ctypes-${platform}-${arch}.node`);
|
|
78
65
|
}
|
|
79
66
|
const require = createRequire(path.join(process.cwd(), "index.js"));
|
|
80
67
|
const native = require(nativeModulePath);
|
|
81
68
|
|
|
82
69
|
// Re-esporta le classi native
|
|
83
|
-
const {
|
|
84
|
-
Version,
|
|
85
|
-
Library,
|
|
86
|
-
FFIFunction,
|
|
87
|
-
Callback,
|
|
88
|
-
ThreadSafeCallback,
|
|
89
|
-
CType,
|
|
90
|
-
StructType,
|
|
91
|
-
ArrayType,
|
|
92
|
-
} = native;
|
|
70
|
+
const { Version, Library, FFIFunction, Callback, ThreadSafeCallback, CType, StructType, ArrayType } = native;
|
|
93
71
|
|
|
94
72
|
// Tipi predefiniti
|
|
95
73
|
const types = native.types;
|
|
@@ -112,10 +90,7 @@ function _toNativeType(type) {
|
|
|
112
90
|
return type._type;
|
|
113
91
|
}
|
|
114
92
|
// Struct/Union classes pass through
|
|
115
|
-
if (
|
|
116
|
-
typeof type === "function" &&
|
|
117
|
-
(type.prototype instanceof Structure || type.prototype instanceof Union)
|
|
118
|
-
) {
|
|
93
|
+
if (typeof type === "function" && (type.prototype instanceof Structure || type.prototype instanceof Union)) {
|
|
119
94
|
return type;
|
|
120
95
|
}
|
|
121
96
|
// Native CType objects pass through
|
|
@@ -132,18 +107,6 @@ function _toNativeTypes(types) {
|
|
|
132
107
|
return types.map(_toNativeType);
|
|
133
108
|
}
|
|
134
109
|
|
|
135
|
-
// ============================================================================
|
|
136
|
-
// Type Lookup Tables
|
|
137
|
-
// Centralizes type information to avoid duplicated switch statements
|
|
138
|
-
// ============================================================================
|
|
139
|
-
|
|
140
|
-
// TYPE_READERS removed - using SimpleCData._reader directly
|
|
141
|
-
|
|
142
|
-
// TYPE_WRITERS removed - using SimpleCData._writer directly
|
|
143
|
-
|
|
144
|
-
/** @type {Map<string, number>} */
|
|
145
|
-
// TYPE_SIZES removed - using SimpleCData._size directly
|
|
146
|
-
|
|
147
110
|
/**
|
|
148
111
|
* Carica una libreria dinamica
|
|
149
112
|
* @param {string|null} libPath - Percorso della libreria o null per l'eseguibile corrente
|
|
@@ -153,6 +116,62 @@ function load(libPath) {
|
|
|
153
116
|
return new Library(libPath);
|
|
154
117
|
}
|
|
155
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Wrapper per funzioni con sintassi Python-like ctypes (argtypes/restype)
|
|
121
|
+
*/
|
|
122
|
+
class FunctionWrapper {
|
|
123
|
+
constructor(cdll, name) {
|
|
124
|
+
const argtypes = [];
|
|
125
|
+
let restype = undefined;
|
|
126
|
+
let cachedFunc = null;
|
|
127
|
+
|
|
128
|
+
// Create a function and proxy it to make it callable
|
|
129
|
+
const func = (...args) => {
|
|
130
|
+
if (restype === undefined) {
|
|
131
|
+
throw new Error(`Function ${name}: restype not set`);
|
|
132
|
+
}
|
|
133
|
+
if (!cachedFunc) {
|
|
134
|
+
cachedFunc = cdll.func(name, restype, argtypes);
|
|
135
|
+
}
|
|
136
|
+
return cachedFunc(...args);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// Proxy the function to intercept property access
|
|
140
|
+
return new Proxy(func, {
|
|
141
|
+
get(target, prop) {
|
|
142
|
+
if (prop === "argtypes") return argtypes;
|
|
143
|
+
if (prop === "restype") return restype;
|
|
144
|
+
if (prop === "errcheck") return cachedFunc ? cachedFunc.errcheck : undefined;
|
|
145
|
+
return target[prop];
|
|
146
|
+
},
|
|
147
|
+
set(target, prop, value) {
|
|
148
|
+
if (prop === "argtypes") {
|
|
149
|
+
argtypes.splice(0, argtypes.length, ...value);
|
|
150
|
+
cachedFunc = null; // Invalidate cache
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
if (prop === "restype") {
|
|
154
|
+
restype = value;
|
|
155
|
+
cachedFunc = null; // Invalidate cache
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
if (prop === "errcheck") {
|
|
159
|
+
if (!cachedFunc) {
|
|
160
|
+
if (restype === undefined) {
|
|
161
|
+
throw new Error(`Function ${name}: restype not set`);
|
|
162
|
+
}
|
|
163
|
+
cachedFunc = cdll.func(name, restype, argtypes);
|
|
164
|
+
}
|
|
165
|
+
cachedFunc.errcheck = value;
|
|
166
|
+
return true;
|
|
167
|
+
}
|
|
168
|
+
target[prop] = value;
|
|
169
|
+
return true;
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
156
175
|
/**
|
|
157
176
|
* Wrapper conveniente per CDLL (come in Python ctypes)
|
|
158
177
|
*/
|
|
@@ -160,6 +179,18 @@ class CDLL {
|
|
|
160
179
|
constructor(libPath) {
|
|
161
180
|
this._lib = new Library(libPath);
|
|
162
181
|
this._cache = new Map();
|
|
182
|
+
|
|
183
|
+
// Return a proxy to enable Python-like syntax: libc.abs.argtypes = [...]; libc.abs.restype = ...; libc.abs(...)
|
|
184
|
+
return new Proxy(this, {
|
|
185
|
+
get(target, prop, receiver) {
|
|
186
|
+
// Allow access to existing properties/methods
|
|
187
|
+
if (prop in target || typeof prop !== "string") {
|
|
188
|
+
return Reflect.get(target, prop, receiver);
|
|
189
|
+
}
|
|
190
|
+
// Assume it's a function name from the library
|
|
191
|
+
return new FunctionWrapper(target, prop);
|
|
192
|
+
},
|
|
193
|
+
});
|
|
163
194
|
}
|
|
164
195
|
|
|
165
196
|
/**
|
|
@@ -177,44 +208,99 @@ class CDLL {
|
|
|
177
208
|
return this._cache.get(cacheKey);
|
|
178
209
|
}
|
|
179
210
|
|
|
180
|
-
const ffiFunc = this._lib.func(
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
211
|
+
const ffiFunc = this._lib.func(name, _toNativeType(returnType), _toNativeTypes(argTypes), options);
|
|
212
|
+
|
|
213
|
+
// =========================================================================
|
|
214
|
+
// OPTIMIZATION: Create specialized wrapper based on argument types
|
|
215
|
+
// For primitive-only args, bypass the processing loop entirely
|
|
216
|
+
// =========================================================================
|
|
217
|
+
|
|
218
|
+
const argCount = argTypes.length;
|
|
219
|
+
|
|
220
|
+
// Check if all args are primitive types (no structs/buffers that need _buffer extraction)
|
|
221
|
+
const allPrimitive = argTypes.every((t) => {
|
|
222
|
+
if (typeof t === "function" && t._isSimpleCData) {
|
|
223
|
+
// SimpleCData types that are NOT pointers are primitive
|
|
224
|
+
const typeName = t._type;
|
|
225
|
+
return typeName !== "pointer" && typeName !== "char_p" && typeName !== "wchar_p";
|
|
226
|
+
}
|
|
227
|
+
if (typeof t === "string") {
|
|
228
|
+
return t !== "pointer" && t !== "char_p" && t !== "wchar_p" && t !== "void_p";
|
|
229
|
+
}
|
|
230
|
+
// CType objects from native - check if it's a pointer type
|
|
231
|
+
if (t && typeof t === "object" && t.name) {
|
|
232
|
+
return !t.name.includes("pointer") && !t.name.includes("char_p");
|
|
233
|
+
}
|
|
234
|
+
return false;
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
let callMethod;
|
|
238
|
+
|
|
239
|
+
if (argCount === 0) {
|
|
240
|
+
// FAST PATH: No arguments - direct call
|
|
241
|
+
callMethod = function () {
|
|
242
|
+
return ffiFunc.call();
|
|
243
|
+
};
|
|
244
|
+
} else if (allPrimitive) {
|
|
245
|
+
// FAST PATH: All primitive args - direct call without processing
|
|
246
|
+
switch (argCount) {
|
|
247
|
+
case 1:
|
|
248
|
+
callMethod = function (a0) {
|
|
249
|
+
return ffiFunc.call(a0);
|
|
250
|
+
};
|
|
251
|
+
break;
|
|
252
|
+
case 2:
|
|
253
|
+
callMethod = function (a0, a1) {
|
|
254
|
+
return ffiFunc.call(a0, a1);
|
|
255
|
+
};
|
|
256
|
+
break;
|
|
257
|
+
case 3:
|
|
258
|
+
callMethod = function (a0, a1, a2) {
|
|
259
|
+
return ffiFunc.call(a0, a1, a2);
|
|
260
|
+
};
|
|
261
|
+
break;
|
|
262
|
+
case 4:
|
|
263
|
+
callMethod = function (a0, a1, a2, a3) {
|
|
264
|
+
return ffiFunc.call(a0, a1, a2, a3);
|
|
265
|
+
};
|
|
266
|
+
break;
|
|
267
|
+
default:
|
|
268
|
+
// Fallback for many args
|
|
269
|
+
callMethod = function (...args) {
|
|
270
|
+
return ffiFunc.call(...args);
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
} else {
|
|
274
|
+
// SLOW PATH: Has buffer/struct args - need to extract _buffer
|
|
275
|
+
callMethod = function (...args) {
|
|
276
|
+
const processedArgs = [];
|
|
277
|
+
|
|
278
|
+
for (let i = 0; i < args.length; i++) {
|
|
279
|
+
const arg = args[i];
|
|
280
|
+
// Check for _buffer FIRST (handles Proxy-wrapped structs)
|
|
281
|
+
// This avoids calling Buffer.isBuffer() on Proxy which can cause issues
|
|
282
|
+
if (arg && typeof arg === "object") {
|
|
283
|
+
// Check for struct proxy FIRST - accessing _buffer on Proxy is safe
|
|
284
|
+
// but Buffer.isBuffer(proxy) can cause hangs
|
|
285
|
+
if (arg._buffer !== undefined && Buffer.isBuffer(arg._buffer)) {
|
|
286
|
+
// Struct proxy or object with _buffer
|
|
287
|
+
processedArgs.push(arg._buffer);
|
|
288
|
+
} else if (Buffer.isBuffer(arg)) {
|
|
289
|
+
// Already a buffer, use directly
|
|
290
|
+
processedArgs.push(arg);
|
|
291
|
+
} else {
|
|
292
|
+
// Other object, pass as-is
|
|
293
|
+
processedArgs.push(arg);
|
|
294
|
+
}
|
|
206
295
|
} else {
|
|
207
|
-
//
|
|
296
|
+
// Primitive value (number, string, bigint, null, undefined)
|
|
208
297
|
processedArgs.push(arg);
|
|
209
298
|
}
|
|
210
|
-
} else {
|
|
211
|
-
// Primitive value (number, string, bigint, null, undefined)
|
|
212
|
-
processedArgs.push(arg);
|
|
213
299
|
}
|
|
214
|
-
}
|
|
215
300
|
|
|
216
|
-
|
|
217
|
-
|
|
301
|
+
return ffiFunc.call(...processedArgs);
|
|
302
|
+
};
|
|
303
|
+
}
|
|
218
304
|
|
|
219
305
|
// Aggiungi metadata come proprietà non-enumerable per non interferire
|
|
220
306
|
Object.defineProperties(callMethod, {
|
|
@@ -256,11 +342,7 @@ class CDLL {
|
|
|
256
342
|
* @returns {Object} Oggetto callback con proprietà pointer e metodi
|
|
257
343
|
*/
|
|
258
344
|
callback(fn, returnType, argTypes = []) {
|
|
259
|
-
return this._lib.callback(
|
|
260
|
-
_toNativeType(returnType),
|
|
261
|
-
_toNativeTypes(argTypes),
|
|
262
|
-
fn,
|
|
263
|
-
);
|
|
345
|
+
return this._lib.callback(_toNativeType(returnType), _toNativeTypes(argTypes), fn);
|
|
264
346
|
}
|
|
265
347
|
|
|
266
348
|
/**
|
|
@@ -306,11 +388,7 @@ class WinDLL extends CDLL {
|
|
|
306
388
|
* @returns {Object} Oggetto con .pointer (BigInt), .release()
|
|
307
389
|
*/
|
|
308
390
|
function callback(fn, returnType, argTypes = []) {
|
|
309
|
-
const cb = new Callback(
|
|
310
|
-
fn,
|
|
311
|
-
_toNativeType(returnType),
|
|
312
|
-
_toNativeTypes(argTypes),
|
|
313
|
-
);
|
|
391
|
+
const cb = new Callback(fn, _toNativeType(returnType), _toNativeTypes(argTypes));
|
|
314
392
|
|
|
315
393
|
return {
|
|
316
394
|
get pointer() {
|
|
@@ -338,11 +416,7 @@ function callback(fn, returnType, argTypes = []) {
|
|
|
338
416
|
* @returns {Object} Oggetto con .pointer (BigInt), .release()
|
|
339
417
|
*/
|
|
340
418
|
function threadSafeCallback(fn, returnType, argTypes = []) {
|
|
341
|
-
const cb = new ThreadSafeCallback(
|
|
342
|
-
fn,
|
|
343
|
-
_toNativeType(returnType),
|
|
344
|
-
_toNativeTypes(argTypes),
|
|
345
|
-
);
|
|
419
|
+
const cb = new ThreadSafeCallback(fn, _toNativeType(returnType), _toNativeTypes(argTypes));
|
|
346
420
|
|
|
347
421
|
return {
|
|
348
422
|
get pointer() {
|
|
@@ -380,8 +454,23 @@ function cstring(str) {
|
|
|
380
454
|
* @returns {Buffer} Buffer con stringa wide
|
|
381
455
|
*/
|
|
382
456
|
function wstring(str) {
|
|
383
|
-
//
|
|
384
|
-
|
|
457
|
+
// Crea un buffer contenente la stringa wide null-terminata
|
|
458
|
+
// Su Windows wchar_t è 2 bytes (UTF-16LE), su Unix è 4 bytes (UTF-32LE)
|
|
459
|
+
const wcharSize = native.WCHAR_SIZE;
|
|
460
|
+
if (wcharSize === 2) {
|
|
461
|
+
return Buffer.from(str + "\0", "utf16le");
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Costruisci manualmente UTF-32LE
|
|
465
|
+
const codePoints = [];
|
|
466
|
+
for (const ch of str) {
|
|
467
|
+
codePoints.push(ch.codePointAt(0));
|
|
468
|
+
}
|
|
469
|
+
const buf = Buffer.alloc((codePoints.length + 1) * 4);
|
|
470
|
+
for (let i = 0; i < codePoints.length; i++) {
|
|
471
|
+
buf.writeUInt32LE(codePoints[i], i * 4);
|
|
472
|
+
}
|
|
473
|
+
// terminatore 0 già inizializzato
|
|
385
474
|
return buf;
|
|
386
475
|
}
|
|
387
476
|
|
|
@@ -547,12 +636,7 @@ function sizeof(type) {
|
|
|
547
636
|
}
|
|
548
637
|
|
|
549
638
|
// SimpleCData instance (e.g., sizeof(new c_uint64()))
|
|
550
|
-
if (
|
|
551
|
-
type &&
|
|
552
|
-
type._buffer &&
|
|
553
|
-
type.constructor &&
|
|
554
|
-
type.constructor._isSimpleCData
|
|
555
|
-
) {
|
|
639
|
+
if (type && type._buffer && type.constructor && type.constructor._isSimpleCData) {
|
|
556
640
|
return type.constructor._size;
|
|
557
641
|
}
|
|
558
642
|
|
|
@@ -569,26 +653,16 @@ function sizeof(type) {
|
|
|
569
653
|
}
|
|
570
654
|
|
|
571
655
|
// Struct type
|
|
572
|
-
if (
|
|
573
|
-
typeof type === "object" &&
|
|
574
|
-
type !== null &&
|
|
575
|
-
typeof type.size === "number"
|
|
576
|
-
) {
|
|
656
|
+
if (typeof type === "object" && type !== null && typeof type.size === "number") {
|
|
577
657
|
return type.size;
|
|
578
658
|
}
|
|
579
659
|
|
|
580
660
|
// Array type
|
|
581
|
-
if (
|
|
582
|
-
typeof type === "object" &&
|
|
583
|
-
type !== null &&
|
|
584
|
-
typeof type.getSize === "function"
|
|
585
|
-
) {
|
|
661
|
+
if (typeof type === "object" && type !== null && typeof type.getSize === "function") {
|
|
586
662
|
return type.getSize();
|
|
587
663
|
}
|
|
588
664
|
|
|
589
|
-
throw new TypeError(
|
|
590
|
-
`sizeof: unsupported type. Use SimpleCData classes like c_int32, c_uint64, etc.`,
|
|
591
|
-
);
|
|
665
|
+
throw new TypeError(`sizeof: unsupported type. Use SimpleCData classes like c_int32, c_uint64, etc.`);
|
|
592
666
|
}
|
|
593
667
|
|
|
594
668
|
/**
|
|
@@ -690,8 +764,7 @@ function ptrToBuffer(address, size) {
|
|
|
690
764
|
* @returns {Object} Tipo puntatore
|
|
691
765
|
*/
|
|
692
766
|
function POINTER(baseType) {
|
|
693
|
-
const baseSize =
|
|
694
|
-
typeof baseType === "object" ? baseType.size : sizeof(baseType);
|
|
767
|
+
const baseSize = typeof baseType === "object" ? baseType.size : sizeof(baseType);
|
|
695
768
|
const typeName = typeof baseType === "object" ? "struct" : baseType;
|
|
696
769
|
|
|
697
770
|
return {
|
|
@@ -767,12 +840,28 @@ function union(fields) {
|
|
|
767
840
|
let size, alignment;
|
|
768
841
|
let fieldDef = { name, type, offset: 0 };
|
|
769
842
|
|
|
770
|
-
// Nested struct
|
|
843
|
+
// Nested struct (object form)
|
|
771
844
|
if (_isStruct(type)) {
|
|
772
845
|
size = type.size;
|
|
773
846
|
alignment = type.alignment;
|
|
774
847
|
fieldDef.isNested = true;
|
|
775
848
|
}
|
|
849
|
+
// Struct class (declarata come `class X extends Structure`)
|
|
850
|
+
else if (typeof type === "function" && type.prototype instanceof Structure) {
|
|
851
|
+
const nested = type._structDef || type._buildStruct();
|
|
852
|
+
size = nested.size;
|
|
853
|
+
alignment = nested.alignment;
|
|
854
|
+
fieldDef.type = nested;
|
|
855
|
+
fieldDef.isNested = true;
|
|
856
|
+
}
|
|
857
|
+
// Union class (declarata come `class X extends Union`)
|
|
858
|
+
else if (typeof type === "function" && type.prototype instanceof Union) {
|
|
859
|
+
const nested = type._unionDef || type._buildUnion();
|
|
860
|
+
size = nested.size;
|
|
861
|
+
alignment = nested.alignment;
|
|
862
|
+
fieldDef.type = nested;
|
|
863
|
+
fieldDef.isNested = true;
|
|
864
|
+
}
|
|
776
865
|
// Array type
|
|
777
866
|
else if (_isArrayType(type)) {
|
|
778
867
|
size = type.getSize();
|
|
@@ -794,9 +883,7 @@ function union(fields) {
|
|
|
794
883
|
else {
|
|
795
884
|
// Validate type is a SimpleCData class
|
|
796
885
|
if (!(typeof type === "function" && type._isSimpleCData)) {
|
|
797
|
-
throw new TypeError(
|
|
798
|
-
`union field "${name}": type must be a SimpleCData class, struct, union, or array`,
|
|
799
|
-
);
|
|
886
|
+
throw new TypeError(`union field "${name}": type must be a SimpleCData class, struct, union, or array`);
|
|
800
887
|
}
|
|
801
888
|
size = type._size;
|
|
802
889
|
alignment = Math.min(size, native.POINTER_SIZE);
|
|
@@ -854,13 +941,7 @@ function union(fields) {
|
|
|
854
941
|
if (prop === Symbol.iterator) return undefined;
|
|
855
942
|
|
|
856
943
|
// Handle Buffer/TypedArray properties FIRST before field checks
|
|
857
|
-
if (
|
|
858
|
-
prop === "length" ||
|
|
859
|
-
prop === "byteLength" ||
|
|
860
|
-
prop === "byteOffset" ||
|
|
861
|
-
prop === "buffer" ||
|
|
862
|
-
prop === "BYTES_PER_ELEMENT"
|
|
863
|
-
) {
|
|
944
|
+
if (prop === "length" || prop === "byteLength" || prop === "byteOffset" || prop === "buffer" || prop === "BYTES_PER_ELEMENT") {
|
|
864
945
|
return target[prop];
|
|
865
946
|
}
|
|
866
947
|
|
|
@@ -895,10 +976,7 @@ function union(fields) {
|
|
|
895
976
|
return fieldDefs.map((f) => f.name);
|
|
896
977
|
},
|
|
897
978
|
getOwnPropertyDescriptor(target, prop) {
|
|
898
|
-
if (
|
|
899
|
-
typeof prop === "string" &&
|
|
900
|
-
(fieldMap.has(prop) || prop === "_buffer" || prop === "toObject")
|
|
901
|
-
) {
|
|
979
|
+
if (typeof prop === "string" && (fieldMap.has(prop) || prop === "_buffer" || prop === "toObject")) {
|
|
902
980
|
return {
|
|
903
981
|
enumerable: prop !== "_buffer" && prop !== "toObject",
|
|
904
982
|
configurable: true,
|
|
@@ -928,13 +1006,7 @@ function union(fields) {
|
|
|
928
1006
|
|
|
929
1007
|
// Bit field
|
|
930
1008
|
if (field.isBitField) {
|
|
931
|
-
return _readBitField(
|
|
932
|
-
buf,
|
|
933
|
-
field.offset,
|
|
934
|
-
field.type,
|
|
935
|
-
field.bitOffset,
|
|
936
|
-
field.bitSize,
|
|
937
|
-
);
|
|
1009
|
+
return _readBitField(buf, field.offset, field.type, field.bitOffset, field.bitSize);
|
|
938
1010
|
}
|
|
939
1011
|
|
|
940
1012
|
// Nested struct
|
|
@@ -948,19 +1020,11 @@ function union(fields) {
|
|
|
948
1020
|
if (prop === Symbol.toStringTag) return "NestedUnionInstance";
|
|
949
1021
|
if (prop === Symbol.iterator) return undefined;
|
|
950
1022
|
// Handle Buffer/TypedArray properties
|
|
951
|
-
if (
|
|
952
|
-
prop === "length" ||
|
|
953
|
-
prop === "byteLength" ||
|
|
954
|
-
prop === "byteOffset" ||
|
|
955
|
-
prop === "buffer" ||
|
|
956
|
-
prop === "BYTES_PER_ELEMENT"
|
|
957
|
-
) {
|
|
1023
|
+
if (prop === "length" || prop === "byteLength" || prop === "byteOffset" || prop === "buffer" || prop === "BYTES_PER_ELEMENT") {
|
|
958
1024
|
return target[prop];
|
|
959
1025
|
}
|
|
960
1026
|
if (typeof prop === "string" && field.type.fields) {
|
|
961
|
-
if (
|
|
962
|
-
field.type.fields.some((f) => f.name === prop && !f.isAnonymous)
|
|
963
|
-
) {
|
|
1027
|
+
if (field.type.fields.some((f) => f.name === prop && !f.isAnonymous)) {
|
|
964
1028
|
return field.type.get(target, prop);
|
|
965
1029
|
}
|
|
966
1030
|
}
|
|
@@ -970,9 +1034,7 @@ function union(fields) {
|
|
|
970
1034
|
},
|
|
971
1035
|
set(target, prop, value, receiver) {
|
|
972
1036
|
if (typeof prop === "string" && field.type.fields) {
|
|
973
|
-
if (
|
|
974
|
-
field.type.fields.some((f) => f.name === prop && !f.isAnonymous)
|
|
975
|
-
) {
|
|
1037
|
+
if (field.type.fields.some((f) => f.name === prop && !f.isAnonymous)) {
|
|
976
1038
|
field.type.set(target, prop, value);
|
|
977
1039
|
return true;
|
|
978
1040
|
}
|
|
@@ -987,16 +1049,10 @@ function union(fields) {
|
|
|
987
1049
|
return Reflect.has(target, prop);
|
|
988
1050
|
},
|
|
989
1051
|
ownKeys(target) {
|
|
990
|
-
return (field.type.fields || [])
|
|
991
|
-
.filter((f) => !f.isAnonymous)
|
|
992
|
-
.map((f) => f.name);
|
|
1052
|
+
return (field.type.fields || []).filter((f) => !f.isAnonymous).map((f) => f.name);
|
|
993
1053
|
},
|
|
994
1054
|
getOwnPropertyDescriptor(target, prop) {
|
|
995
|
-
if (
|
|
996
|
-
typeof prop === "string" &&
|
|
997
|
-
field.type.fields &&
|
|
998
|
-
field.type.fields.some((f) => f.name === prop)
|
|
999
|
-
) {
|
|
1055
|
+
if (typeof prop === "string" && field.type.fields && field.type.fields.some((f) => f.name === prop)) {
|
|
1000
1056
|
return {
|
|
1001
1057
|
enumerable: true,
|
|
1002
1058
|
configurable: true,
|
|
@@ -1010,9 +1066,7 @@ function union(fields) {
|
|
|
1010
1066
|
|
|
1011
1067
|
// Array
|
|
1012
1068
|
if (field.isArray) {
|
|
1013
|
-
return field.type.wrap(
|
|
1014
|
-
buf.subarray(field.offset, field.offset + field.size),
|
|
1015
|
-
);
|
|
1069
|
+
return field.type.wrap(buf.subarray(field.offset, field.offset + field.size));
|
|
1016
1070
|
}
|
|
1017
1071
|
|
|
1018
1072
|
// Tipo base
|
|
@@ -1038,14 +1092,7 @@ function union(fields) {
|
|
|
1038
1092
|
|
|
1039
1093
|
// Bit field
|
|
1040
1094
|
if (field.isBitField) {
|
|
1041
|
-
_writeBitField(
|
|
1042
|
-
buf,
|
|
1043
|
-
field.offset,
|
|
1044
|
-
field.type,
|
|
1045
|
-
field.bitOffset,
|
|
1046
|
-
field.bitSize,
|
|
1047
|
-
value,
|
|
1048
|
-
);
|
|
1095
|
+
_writeBitField(buf, field.offset, field.type, field.bitOffset, field.bitSize, value);
|
|
1049
1096
|
return;
|
|
1050
1097
|
}
|
|
1051
1098
|
|
|
@@ -1054,10 +1101,7 @@ function union(fields) {
|
|
|
1054
1101
|
if (Buffer.isBuffer(value)) {
|
|
1055
1102
|
value.copy(buf, field.offset, 0, field.size);
|
|
1056
1103
|
} else if (typeof value === "object") {
|
|
1057
|
-
const nestedBuf = buf.subarray(
|
|
1058
|
-
field.offset,
|
|
1059
|
-
field.offset + field.size,
|
|
1060
|
-
);
|
|
1104
|
+
const nestedBuf = buf.subarray(field.offset, field.offset + field.size);
|
|
1061
1105
|
for (const [k, v] of Object.entries(value)) {
|
|
1062
1106
|
field.type.set(nestedBuf, k, v);
|
|
1063
1107
|
}
|
|
@@ -1070,9 +1114,7 @@ function union(fields) {
|
|
|
1070
1114
|
if (Buffer.isBuffer(value)) {
|
|
1071
1115
|
value.copy(buf, field.offset, 0, field.size);
|
|
1072
1116
|
} else if (Array.isArray(value)) {
|
|
1073
|
-
const wrapped = field.type.wrap(
|
|
1074
|
-
buf.subarray(field.offset, field.offset + field.size),
|
|
1075
|
-
);
|
|
1117
|
+
const wrapped = field.type.wrap(buf.subarray(field.offset, field.offset + field.size));
|
|
1076
1118
|
for (let i = 0; i < Math.min(value.length, field.type.length); i++) {
|
|
1077
1119
|
wrapped[i] = value[i];
|
|
1078
1120
|
}
|
|
@@ -1090,11 +1132,7 @@ function union(fields) {
|
|
|
1090
1132
|
toObject(bufOrObj) {
|
|
1091
1133
|
// Se è già un object (non buffer), ritorna così com'è
|
|
1092
1134
|
if (!Buffer.isBuffer(bufOrObj)) {
|
|
1093
|
-
if (
|
|
1094
|
-
bufOrObj &&
|
|
1095
|
-
bufOrObj._buffer &&
|
|
1096
|
-
bufOrObj._buffer.length === maxSize
|
|
1097
|
-
) {
|
|
1135
|
+
if (bufOrObj && bufOrObj._buffer && bufOrObj._buffer.length === maxSize) {
|
|
1098
1136
|
return bufOrObj; // Già convertito
|
|
1099
1137
|
}
|
|
1100
1138
|
// Se è un plain object, convertilo in union
|
|
@@ -1128,13 +1166,7 @@ function union(fields) {
|
|
|
1128
1166
|
Object.defineProperty(obj, field.name, {
|
|
1129
1167
|
get() {
|
|
1130
1168
|
if (field.isBitField) {
|
|
1131
|
-
return _readBitField(
|
|
1132
|
-
buf,
|
|
1133
|
-
0,
|
|
1134
|
-
field.type,
|
|
1135
|
-
field.bitOffset,
|
|
1136
|
-
field.bitSize,
|
|
1137
|
-
);
|
|
1169
|
+
return _readBitField(buf, 0, field.type, field.bitOffset, field.bitSize);
|
|
1138
1170
|
} else if (field.isNested) {
|
|
1139
1171
|
// Cache nested objects per evitare di ricrearli ogni volta
|
|
1140
1172
|
if (!nestedCache.has(field.name)) {
|
|
@@ -1152,14 +1184,7 @@ function union(fields) {
|
|
|
1152
1184
|
},
|
|
1153
1185
|
set(value) {
|
|
1154
1186
|
if (field.isBitField) {
|
|
1155
|
-
_writeBitField(
|
|
1156
|
-
buf,
|
|
1157
|
-
0,
|
|
1158
|
-
field.type,
|
|
1159
|
-
field.bitOffset,
|
|
1160
|
-
field.bitSize,
|
|
1161
|
-
value,
|
|
1162
|
-
);
|
|
1187
|
+
_writeBitField(buf, 0, field.type, field.bitOffset, field.bitSize, value);
|
|
1163
1188
|
} else {
|
|
1164
1189
|
writeValue(buf, field.type, value, 0);
|
|
1165
1190
|
}
|
|
@@ -1229,12 +1254,7 @@ class Structure {
|
|
|
1229
1254
|
buf.fill(0);
|
|
1230
1255
|
|
|
1231
1256
|
// Support positional args: new Point(10,20)
|
|
1232
|
-
if (
|
|
1233
|
-
args.length === 1 &&
|
|
1234
|
-
typeof args[0] === "object" &&
|
|
1235
|
-
!Array.isArray(args[0]) &&
|
|
1236
|
-
!Buffer.isBuffer(args[0])
|
|
1237
|
-
) {
|
|
1257
|
+
if (args.length === 1 && typeof args[0] === "object" && !Array.isArray(args[0]) && !Buffer.isBuffer(args[0])) {
|
|
1238
1258
|
const initial = args[0];
|
|
1239
1259
|
for (const [k, v] of Object.entries(initial)) {
|
|
1240
1260
|
def.set(buf, k, v);
|
|
@@ -1312,8 +1332,7 @@ class Structure {
|
|
|
1312
1332
|
return Reflect.set(target, prop, value, receiver);
|
|
1313
1333
|
},
|
|
1314
1334
|
has(target, prop) {
|
|
1315
|
-
if (prop === "_buffer" || prop === "_structDef" || prop === "toObject")
|
|
1316
|
-
return true;
|
|
1335
|
+
if (prop === "_buffer" || prop === "_structDef" || prop === "toObject") return true;
|
|
1317
1336
|
if (typeof prop === "string" && fieldMap.has(prop)) return true;
|
|
1318
1337
|
if (typeof prop === "string" && anonFieldNames.has(prop)) return true;
|
|
1319
1338
|
return Reflect.has(target, prop);
|
|
@@ -1332,10 +1351,7 @@ class Structure {
|
|
|
1332
1351
|
return keys;
|
|
1333
1352
|
},
|
|
1334
1353
|
getOwnPropertyDescriptor(target, prop) {
|
|
1335
|
-
if (
|
|
1336
|
-
typeof prop === "string" &&
|
|
1337
|
-
(fieldMap.has(prop) || anonFieldNames.has(prop))
|
|
1338
|
-
) {
|
|
1354
|
+
if (typeof prop === "string" && (fieldMap.has(prop) || anonFieldNames.has(prop))) {
|
|
1339
1355
|
return {
|
|
1340
1356
|
enumerable: true,
|
|
1341
1357
|
configurable: true,
|
|
@@ -1465,19 +1481,11 @@ class Structure {
|
|
|
1465
1481
|
|
|
1466
1482
|
// Direct typed array access for numeric fields (maximum performance)
|
|
1467
1483
|
getInt32Array(offset = 0, length) {
|
|
1468
|
-
return new Int32Array(
|
|
1469
|
-
this.__buffer.buffer,
|
|
1470
|
-
this.__buffer.byteOffset + offset,
|
|
1471
|
-
length,
|
|
1472
|
-
);
|
|
1484
|
+
return new Int32Array(this.__buffer.buffer, this.__buffer.byteOffset + offset, length);
|
|
1473
1485
|
}
|
|
1474
1486
|
|
|
1475
1487
|
getFloat64Array(offset = 0, length) {
|
|
1476
|
-
return new Float64Array(
|
|
1477
|
-
this.__buffer.buffer,
|
|
1478
|
-
this.__buffer.byteOffset + offset,
|
|
1479
|
-
length,
|
|
1480
|
-
);
|
|
1488
|
+
return new Float64Array(this.__buffer.buffer, this.__buffer.byteOffset + offset, length);
|
|
1481
1489
|
}
|
|
1482
1490
|
|
|
1483
1491
|
// Get raw buffer slice for external operations
|
|
@@ -1543,26 +1551,31 @@ class Union extends Structure {
|
|
|
1543
1551
|
* console.log(arr[2]); // 42
|
|
1544
1552
|
*/
|
|
1545
1553
|
function array(elementType, count) {
|
|
1546
|
-
// Validate elementType
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1554
|
+
// Validate elementType: accept SimpleCData classes, Structure/Union classes,
|
|
1555
|
+
// or native CType-like objects.
|
|
1556
|
+
const isSimple = typeof elementType === "function" && elementType._isSimpleCData;
|
|
1557
|
+
const isStruct = typeof elementType === "function" && (elementType.prototype instanceof Structure || elementType.prototype instanceof Union);
|
|
1558
|
+
const isNativeTypeObj = typeof elementType === "object" && elementType !== null && (typeof elementType.getSize === "function" || elementType.size !== undefined);
|
|
1559
|
+
if (!isSimple && !isStruct && !isNativeTypeObj) {
|
|
1560
|
+
throw new TypeError("array elementType must be a SimpleCData class or a Structure/Union class");
|
|
1551
1561
|
}
|
|
1552
1562
|
|
|
1553
|
-
const elementSize = elementType
|
|
1563
|
+
const elementSize = sizeof(elementType);
|
|
1554
1564
|
let nativeArray;
|
|
1555
|
-
if (
|
|
1565
|
+
if (isNativeTypeObj) {
|
|
1556
1566
|
nativeArray = new ArrayType(elementType, count);
|
|
1557
1567
|
} else {
|
|
1558
|
-
//
|
|
1568
|
+
// Provide a small JS-side shim implementing the minimal ArrayType API
|
|
1559
1569
|
nativeArray = {
|
|
1560
1570
|
getSize: () => count * elementSize,
|
|
1561
1571
|
getLength: () => count,
|
|
1562
|
-
getAlignment: () => elementSize,
|
|
1572
|
+
getAlignment: () => elementSize,
|
|
1563
1573
|
create: (values) => {
|
|
1564
|
-
//
|
|
1565
|
-
|
|
1574
|
+
// JS create is implemented below; this should not be invoked by JS code
|
|
1575
|
+
const size = count * elementSize;
|
|
1576
|
+
const buffer = alloc(size);
|
|
1577
|
+
buffer.fill(0);
|
|
1578
|
+
return buffer;
|
|
1566
1579
|
},
|
|
1567
1580
|
};
|
|
1568
1581
|
}
|
|
@@ -1592,7 +1605,13 @@ function array(elementType, count) {
|
|
|
1592
1605
|
if (prop === Symbol.iterator) {
|
|
1593
1606
|
return function* () {
|
|
1594
1607
|
for (let i = 0; i < count; i++) {
|
|
1595
|
-
|
|
1608
|
+
const off = i * elementSize;
|
|
1609
|
+
// If elementType is a struct/union class, return an instance bound to the slice
|
|
1610
|
+
if (typeof elementType === "function" && (elementType.prototype instanceof Structure || elementType.prototype instanceof Union)) {
|
|
1611
|
+
yield new elementType(target.subarray(off, off + elementSize));
|
|
1612
|
+
} else {
|
|
1613
|
+
yield readValue(target, elementType, off);
|
|
1614
|
+
}
|
|
1596
1615
|
}
|
|
1597
1616
|
};
|
|
1598
1617
|
}
|
|
@@ -1610,7 +1629,11 @@ function array(elementType, count) {
|
|
|
1610
1629
|
const index = Number(prop);
|
|
1611
1630
|
if (Number.isInteger(index) && !isNaN(index)) {
|
|
1612
1631
|
if (index >= 0 && index < count) {
|
|
1613
|
-
|
|
1632
|
+
const off = index * elementSize;
|
|
1633
|
+
if (typeof elementType === "function" && (elementType.prototype instanceof Structure || elementType.prototype instanceof Union)) {
|
|
1634
|
+
return new elementType(target.subarray(off, off + elementSize));
|
|
1635
|
+
}
|
|
1636
|
+
return readValue(target, elementType, off);
|
|
1614
1637
|
}
|
|
1615
1638
|
// Indice numerico fuori bounds -> undefined (comportamento JavaScript)
|
|
1616
1639
|
return undefined;
|
|
@@ -1666,12 +1689,7 @@ function array(elementType, count) {
|
|
|
1666
1689
|
}
|
|
1667
1690
|
} else if (typeof values === "string") {
|
|
1668
1691
|
for (let i = 0; i < Math.min(values.length, count); i++) {
|
|
1669
|
-
writeValue(
|
|
1670
|
-
buffer,
|
|
1671
|
-
elementType,
|
|
1672
|
-
values.charCodeAt(i),
|
|
1673
|
-
i * sizeof(elementType),
|
|
1674
|
-
);
|
|
1692
|
+
writeValue(buffer, elementType, values.charCodeAt(i), i * sizeof(elementType));
|
|
1675
1693
|
}
|
|
1676
1694
|
}
|
|
1677
1695
|
return wrap(buffer);
|
|
@@ -1786,15 +1804,7 @@ function _initWinError() {
|
|
|
1786
1804
|
_win_error_funcs = {
|
|
1787
1805
|
GetLastError: kernel32.func("GetLastError", c_uint32, []),
|
|
1788
1806
|
SetLastError: kernel32.func("SetLastError", c_void, [c_uint32]),
|
|
1789
|
-
FormatMessageW: kernel32.func("FormatMessageW", c_uint32, [
|
|
1790
|
-
c_uint32,
|
|
1791
|
-
c_void_p,
|
|
1792
|
-
c_uint32,
|
|
1793
|
-
c_uint32,
|
|
1794
|
-
c_void_p,
|
|
1795
|
-
c_uint32,
|
|
1796
|
-
c_void_p,
|
|
1797
|
-
]),
|
|
1807
|
+
FormatMessageW: kernel32.func("FormatMessageW", c_uint32, [c_uint32, c_void_p, c_uint32, c_uint32, c_void_p, c_uint32, c_void_p]),
|
|
1798
1808
|
_lib: kernel32,
|
|
1799
1809
|
};
|
|
1800
1810
|
} catch (e) {
|
|
@@ -1893,9 +1903,7 @@ function bitfield(baseType, bits) {
|
|
|
1893
1903
|
const maxBits = baseSize * 8;
|
|
1894
1904
|
|
|
1895
1905
|
if (bits < 1 || bits > maxBits) {
|
|
1896
|
-
throw new Error(
|
|
1897
|
-
`Bit field size must be between 1 and ${maxBits} for ${baseType}`,
|
|
1898
|
-
);
|
|
1906
|
+
throw new Error(`Bit field size must be between 1 and ${maxBits} for ${baseType}`);
|
|
1899
1907
|
}
|
|
1900
1908
|
|
|
1901
1909
|
return {
|
|
@@ -1910,22 +1918,14 @@ function bitfield(baseType, bits) {
|
|
|
1910
1918
|
* Helper per verificare se un tipo è una struct
|
|
1911
1919
|
*/
|
|
1912
1920
|
function _isStruct(type) {
|
|
1913
|
-
return (
|
|
1914
|
-
typeof type === "object" &&
|
|
1915
|
-
type !== null &&
|
|
1916
|
-
typeof type.size === "number" &&
|
|
1917
|
-
Array.isArray(type.fields) &&
|
|
1918
|
-
typeof type.create === "function"
|
|
1919
|
-
);
|
|
1921
|
+
return typeof type === "object" && type !== null && typeof type.size === "number" && Array.isArray(type.fields) && typeof type.create === "function";
|
|
1920
1922
|
}
|
|
1921
1923
|
|
|
1922
1924
|
/**
|
|
1923
1925
|
* Helper per verificare se un tipo è un array type
|
|
1924
1926
|
*/
|
|
1925
1927
|
function _isArrayType(type) {
|
|
1926
|
-
return
|
|
1927
|
-
typeof type === "object" && type !== null && type._isArrayType === true
|
|
1928
|
-
);
|
|
1928
|
+
return typeof type === "object" && type !== null && type._isArrayType === true;
|
|
1929
1929
|
}
|
|
1930
1930
|
|
|
1931
1931
|
/**
|
|
@@ -2007,8 +2007,7 @@ function _writeBitField(buf, offset, baseType, bitOffset, bitSize, newValue) {
|
|
|
2007
2007
|
if (baseSize === 8) {
|
|
2008
2008
|
const mask = (1n << BigInt(bitSize)) - 1n;
|
|
2009
2009
|
const clearMask = ~(mask << BigInt(bitOffset));
|
|
2010
|
-
value =
|
|
2011
|
-
(value & clearMask) | ((BigInt(newValue) & mask) << BigInt(bitOffset));
|
|
2010
|
+
value = (value & clearMask) | ((BigInt(newValue) & mask) << BigInt(bitOffset));
|
|
2012
2011
|
} else {
|
|
2013
2012
|
const mask = (1 << bitSize) - 1;
|
|
2014
2013
|
const clearMask = ~(mask << bitOffset);
|
|
@@ -2046,12 +2045,7 @@ function struct(fields, options = {}) {
|
|
|
2046
2045
|
let fieldDef;
|
|
2047
2046
|
|
|
2048
2047
|
// Caso 0: Anonymous field - { type: SomeStruct, anonymous: true }
|
|
2049
|
-
if (
|
|
2050
|
-
typeof type === "object" &&
|
|
2051
|
-
type !== null &&
|
|
2052
|
-
type.anonymous === true &&
|
|
2053
|
-
type.type
|
|
2054
|
-
) {
|
|
2048
|
+
if (typeof type === "object" && type !== null && type.anonymous === true && type.type) {
|
|
2055
2049
|
// Reset bit field state
|
|
2056
2050
|
currentBitFieldBase = null;
|
|
2057
2051
|
currentBitOffset = 0;
|
|
@@ -2087,9 +2081,7 @@ function struct(fields, options = {}) {
|
|
|
2087
2081
|
const alignment = packed ? 1 : Math.min(baseSize, native.POINTER_SIZE);
|
|
2088
2082
|
|
|
2089
2083
|
// Verifica se possiamo continuare nel bit field corrente
|
|
2090
|
-
const canContinue =
|
|
2091
|
-
currentBitFieldBase === baseType &&
|
|
2092
|
-
currentBitOffset + bits <= baseSize * 8;
|
|
2084
|
+
const canContinue = currentBitFieldBase === baseType && currentBitOffset + bits <= baseSize * 8;
|
|
2093
2085
|
|
|
2094
2086
|
if (!canContinue) {
|
|
2095
2087
|
// Inizia un nuovo bit field
|
|
@@ -2122,6 +2114,66 @@ function struct(fields, options = {}) {
|
|
|
2122
2114
|
maxAlignment = alignment;
|
|
2123
2115
|
}
|
|
2124
2116
|
}
|
|
2117
|
+
// Caso 2a: Struct class (declarata come `class X extends Structure`)
|
|
2118
|
+
else if (typeof type === "function" && type.prototype instanceof Structure) {
|
|
2119
|
+
// Reset bit field state
|
|
2120
|
+
currentBitFieldBase = null;
|
|
2121
|
+
currentBitOffset = 0;
|
|
2122
|
+
|
|
2123
|
+
const nestedStruct = type._structDef || type._buildStruct();
|
|
2124
|
+
const size = nestedStruct.size;
|
|
2125
|
+
const alignment = packed ? 1 : nestedStruct.alignment;
|
|
2126
|
+
|
|
2127
|
+
// Applica padding per allineamento
|
|
2128
|
+
if (!packed && totalSize % alignment !== 0) {
|
|
2129
|
+
totalSize += alignment - (totalSize % alignment);
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
fieldDef = {
|
|
2133
|
+
name,
|
|
2134
|
+
type: nestedStruct,
|
|
2135
|
+
offset: totalSize,
|
|
2136
|
+
size,
|
|
2137
|
+
alignment,
|
|
2138
|
+
isNested: true,
|
|
2139
|
+
};
|
|
2140
|
+
|
|
2141
|
+
totalSize += size;
|
|
2142
|
+
|
|
2143
|
+
if (alignment > maxAlignment) {
|
|
2144
|
+
maxAlignment = alignment;
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
// Caso 2b: Union class (declarata come `class X extends Union`)
|
|
2148
|
+
else if (typeof type === "function" && type.prototype instanceof Union) {
|
|
2149
|
+
// Reset bit field state
|
|
2150
|
+
currentBitFieldBase = null;
|
|
2151
|
+
currentBitOffset = 0;
|
|
2152
|
+
|
|
2153
|
+
const nestedUnion = type._unionDef || type._buildUnion();
|
|
2154
|
+
const size = nestedUnion.size;
|
|
2155
|
+
const alignment = packed ? 1 : nestedUnion.alignment;
|
|
2156
|
+
|
|
2157
|
+
// Applica padding per allineamento
|
|
2158
|
+
if (!packed && totalSize % alignment !== 0) {
|
|
2159
|
+
totalSize += alignment - (totalSize % alignment);
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
fieldDef = {
|
|
2163
|
+
name,
|
|
2164
|
+
type: nestedUnion,
|
|
2165
|
+
offset: totalSize,
|
|
2166
|
+
size,
|
|
2167
|
+
alignment,
|
|
2168
|
+
isNested: true,
|
|
2169
|
+
};
|
|
2170
|
+
|
|
2171
|
+
totalSize += size;
|
|
2172
|
+
|
|
2173
|
+
if (alignment > maxAlignment) {
|
|
2174
|
+
maxAlignment = alignment;
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2125
2177
|
// Caso 2: Nested struct
|
|
2126
2178
|
else if (_isStruct(type)) {
|
|
2127
2179
|
// Reset bit field state
|
|
@@ -2190,9 +2242,7 @@ function struct(fields, options = {}) {
|
|
|
2190
2242
|
|
|
2191
2243
|
// Validate type is a SimpleCData class
|
|
2192
2244
|
if (!(typeof type === "function" && type._isSimpleCData)) {
|
|
2193
|
-
throw new TypeError(
|
|
2194
|
-
`struct field "${name}": type must be a SimpleCData class, struct, union, or array`,
|
|
2195
|
-
);
|
|
2245
|
+
throw new TypeError(`struct field "${name}": type must be a SimpleCData class, struct, union, or array`);
|
|
2196
2246
|
}
|
|
2197
2247
|
|
|
2198
2248
|
const size = type._size;
|
|
@@ -2252,9 +2302,7 @@ function struct(fields, options = {}) {
|
|
|
2252
2302
|
if (fieldType && fieldType._isSimpleCData) {
|
|
2253
2303
|
const fieldOffset = offset; // Capture offset for closure
|
|
2254
2304
|
fieldReaders.set(name, (buf) => fieldType._reader(buf, fieldOffset));
|
|
2255
|
-
fieldWriters.set(name, (buf, val) =>
|
|
2256
|
-
fieldType._writer(buf, fieldOffset, val),
|
|
2257
|
-
);
|
|
2305
|
+
fieldWriters.set(name, (buf, val) => fieldType._writer(buf, fieldOffset, val));
|
|
2258
2306
|
}
|
|
2259
2307
|
}
|
|
2260
2308
|
|
|
@@ -2303,13 +2351,7 @@ function struct(fields, options = {}) {
|
|
|
2303
2351
|
|
|
2304
2352
|
// Handle Buffer/TypedArray properties FIRST before field checks
|
|
2305
2353
|
// TypedArray methods need direct access to avoid Proxy interference
|
|
2306
|
-
if (
|
|
2307
|
-
prop === "length" ||
|
|
2308
|
-
prop === "byteLength" ||
|
|
2309
|
-
prop === "byteOffset" ||
|
|
2310
|
-
prop === "buffer" ||
|
|
2311
|
-
prop === "BYTES_PER_ELEMENT"
|
|
2312
|
-
) {
|
|
2354
|
+
if (prop === "length" || prop === "byteLength" || prop === "byteOffset" || prop === "buffer" || prop === "BYTES_PER_ELEMENT") {
|
|
2313
2355
|
return target[prop];
|
|
2314
2356
|
}
|
|
2315
2357
|
|
|
@@ -2394,10 +2436,7 @@ function struct(fields, options = {}) {
|
|
|
2394
2436
|
return keys;
|
|
2395
2437
|
},
|
|
2396
2438
|
getOwnPropertyDescriptor(target, prop) {
|
|
2397
|
-
if (
|
|
2398
|
-
typeof prop === "string" &&
|
|
2399
|
-
(fieldMap.has(prop) || prop === "_buffer" || prop === "toObject")
|
|
2400
|
-
) {
|
|
2439
|
+
if (typeof prop === "string" && (fieldMap.has(prop) || prop === "_buffer" || prop === "toObject")) {
|
|
2401
2440
|
return {
|
|
2402
2441
|
enumerable: prop !== "_buffer" && prop !== "toObject",
|
|
2403
2442
|
configurable: true,
|
|
@@ -2469,47 +2508,28 @@ function struct(fields, options = {}) {
|
|
|
2469
2508
|
if (field) {
|
|
2470
2509
|
// Bit field
|
|
2471
2510
|
if (field.isBitField) {
|
|
2472
|
-
return _readBitField(
|
|
2473
|
-
buf,
|
|
2474
|
-
field.offset,
|
|
2475
|
-
field.type,
|
|
2476
|
-
field.bitOffset,
|
|
2477
|
-
field.bitSize,
|
|
2478
|
-
);
|
|
2511
|
+
return _readBitField(buf, field.offset, field.type, field.bitOffset, field.bitSize);
|
|
2479
2512
|
}
|
|
2480
2513
|
|
|
2481
2514
|
// Nested struct (senza dot = ritorna intero oggetto)
|
|
2482
2515
|
if (field.isNested) {
|
|
2483
|
-
const nestedBuf = buf.subarray(
|
|
2484
|
-
field.offset,
|
|
2485
|
-
field.offset + field.size,
|
|
2486
|
-
);
|
|
2516
|
+
const nestedBuf = buf.subarray(field.offset, field.offset + field.size);
|
|
2487
2517
|
// Proxy-based nested instance
|
|
2488
2518
|
return field.type.create
|
|
2489
2519
|
? // Se ha create(), usa quello per creare il proxy
|
|
2490
2520
|
new Proxy(nestedBuf, {
|
|
2491
2521
|
get(target, prop, receiver) {
|
|
2492
2522
|
if (prop === "_buffer") return target;
|
|
2493
|
-
if (prop === "toObject")
|
|
2494
|
-
|
|
2495
|
-
if (prop === Symbol.toStringTag)
|
|
2496
|
-
return "NestedStructInstance";
|
|
2523
|
+
if (prop === "toObject") return () => field.type.toObject(target);
|
|
2524
|
+
if (prop === Symbol.toStringTag) return "NestedStructInstance";
|
|
2497
2525
|
if (prop === Symbol.iterator) return undefined;
|
|
2498
2526
|
// Handle Buffer/TypedArray properties
|
|
2499
|
-
if (
|
|
2500
|
-
prop === "length" ||
|
|
2501
|
-
prop === "byteLength" ||
|
|
2502
|
-
prop === "byteOffset" ||
|
|
2503
|
-
prop === "buffer" ||
|
|
2504
|
-
prop === "BYTES_PER_ELEMENT"
|
|
2505
|
-
) {
|
|
2527
|
+
if (prop === "length" || prop === "byteLength" || prop === "byteOffset" || prop === "buffer" || prop === "BYTES_PER_ELEMENT") {
|
|
2506
2528
|
return target[prop];
|
|
2507
2529
|
}
|
|
2508
2530
|
if (typeof prop === "string") {
|
|
2509
2531
|
// Check direct fields
|
|
2510
|
-
const nestedFieldMap = field.type.fields
|
|
2511
|
-
? new Map(field.type.fields.map((f) => [f.name, f]))
|
|
2512
|
-
: new Map();
|
|
2532
|
+
const nestedFieldMap = field.type.fields ? new Map(field.type.fields.map((f) => [f.name, f])) : new Map();
|
|
2513
2533
|
if (nestedFieldMap.has(prop)) {
|
|
2514
2534
|
return field.type.get(target, prop);
|
|
2515
2535
|
}
|
|
@@ -2528,9 +2548,7 @@ function struct(fields, options = {}) {
|
|
|
2528
2548
|
},
|
|
2529
2549
|
set(target, prop, value, receiver) {
|
|
2530
2550
|
if (typeof prop === "string") {
|
|
2531
|
-
const nestedFieldMap = field.type.fields
|
|
2532
|
-
? new Map(field.type.fields.map((f) => [f.name, f]))
|
|
2533
|
-
: new Map();
|
|
2551
|
+
const nestedFieldMap = field.type.fields ? new Map(field.type.fields.map((f) => [f.name, f])) : new Map();
|
|
2534
2552
|
if (nestedFieldMap.has(prop)) {
|
|
2535
2553
|
field.type.set(target, prop, value);
|
|
2536
2554
|
return true;
|
|
@@ -2550,8 +2568,7 @@ function struct(fields, options = {}) {
|
|
|
2550
2568
|
has(target, prop) {
|
|
2551
2569
|
if (prop === "_buffer" || prop === "toObject") return true;
|
|
2552
2570
|
if (typeof prop === "string" && field.type.fields) {
|
|
2553
|
-
if (field.type.fields.some((f) => f.name === prop))
|
|
2554
|
-
return true;
|
|
2571
|
+
if (field.type.fields.some((f) => f.name === prop)) return true;
|
|
2555
2572
|
}
|
|
2556
2573
|
return Reflect.has(target, prop);
|
|
2557
2574
|
},
|
|
@@ -2559,11 +2576,7 @@ function struct(fields, options = {}) {
|
|
|
2559
2576
|
return (field.type.fields || []).map((f) => f.name);
|
|
2560
2577
|
},
|
|
2561
2578
|
getOwnPropertyDescriptor(target, prop) {
|
|
2562
|
-
if (
|
|
2563
|
-
typeof prop === "string" &&
|
|
2564
|
-
field.type.fields &&
|
|
2565
|
-
field.type.fields.some((f) => f.name === prop)
|
|
2566
|
-
) {
|
|
2579
|
+
if (typeof prop === "string" && field.type.fields && field.type.fields.some((f) => f.name === prop)) {
|
|
2567
2580
|
return {
|
|
2568
2581
|
enumerable: true,
|
|
2569
2582
|
configurable: true,
|
|
@@ -2578,10 +2591,7 @@ function struct(fields, options = {}) {
|
|
|
2578
2591
|
|
|
2579
2592
|
// Array field
|
|
2580
2593
|
if (field.isArray) {
|
|
2581
|
-
const arrayBuf = buf.subarray(
|
|
2582
|
-
field.offset,
|
|
2583
|
-
field.offset + field.size,
|
|
2584
|
-
);
|
|
2594
|
+
const arrayBuf = buf.subarray(field.offset, field.offset + field.size);
|
|
2585
2595
|
return field.type.wrap(arrayBuf);
|
|
2586
2596
|
}
|
|
2587
2597
|
|
|
@@ -2599,9 +2609,7 @@ function struct(fields, options = {}) {
|
|
|
2599
2609
|
if (!field) {
|
|
2600
2610
|
for (const f of fieldDefs) {
|
|
2601
2611
|
if (f.isAnonymous && f.type && f.type.fields) {
|
|
2602
|
-
const hasField = f.type.fields.some(
|
|
2603
|
-
(subField) => subField.name === firstPart,
|
|
2604
|
-
);
|
|
2612
|
+
const hasField = f.type.fields.some((subField) => subField.name === firstPart);
|
|
2605
2613
|
if (hasField) {
|
|
2606
2614
|
const nestedBuf = buf.subarray(f.offset, f.offset + f.size);
|
|
2607
2615
|
return f.type.get(nestedBuf, fieldName);
|
|
@@ -2650,14 +2658,7 @@ function struct(fields, options = {}) {
|
|
|
2650
2658
|
if (field) {
|
|
2651
2659
|
// Bit field
|
|
2652
2660
|
if (field.isBitField) {
|
|
2653
|
-
_writeBitField(
|
|
2654
|
-
buf,
|
|
2655
|
-
field.offset,
|
|
2656
|
-
field.type,
|
|
2657
|
-
field.bitOffset,
|
|
2658
|
-
field.bitSize,
|
|
2659
|
-
value,
|
|
2660
|
-
);
|
|
2661
|
+
_writeBitField(buf, field.offset, field.type, field.bitOffset, field.bitSize, value);
|
|
2661
2662
|
return;
|
|
2662
2663
|
}
|
|
2663
2664
|
|
|
@@ -2666,10 +2667,7 @@ function struct(fields, options = {}) {
|
|
|
2666
2667
|
if (Buffer.isBuffer(value)) {
|
|
2667
2668
|
value.copy(buf, field.offset, 0, field.size);
|
|
2668
2669
|
} else if (typeof value === "object") {
|
|
2669
|
-
const nestedBuf = buf.subarray(
|
|
2670
|
-
field.offset,
|
|
2671
|
-
field.offset + field.size,
|
|
2672
|
-
);
|
|
2670
|
+
const nestedBuf = buf.subarray(field.offset, field.offset + field.size);
|
|
2673
2671
|
for (const [k, v] of Object.entries(value)) {
|
|
2674
2672
|
field.type.set(nestedBuf, k, v);
|
|
2675
2673
|
}
|
|
@@ -2682,16 +2680,9 @@ function struct(fields, options = {}) {
|
|
|
2682
2680
|
if (Buffer.isBuffer(value)) {
|
|
2683
2681
|
value.copy(buf, field.offset, 0, field.size);
|
|
2684
2682
|
} else if (Array.isArray(value)) {
|
|
2685
|
-
const arrayBuf = buf.subarray(
|
|
2686
|
-
field.offset,
|
|
2687
|
-
field.offset + field.size,
|
|
2688
|
-
);
|
|
2683
|
+
const arrayBuf = buf.subarray(field.offset, field.offset + field.size);
|
|
2689
2684
|
const wrapped = field.type.wrap(arrayBuf);
|
|
2690
|
-
for (
|
|
2691
|
-
let i = 0;
|
|
2692
|
-
i < Math.min(value.length, field.type.length);
|
|
2693
|
-
i++
|
|
2694
|
-
) {
|
|
2685
|
+
for (let i = 0; i < Math.min(value.length, field.type.length); i++) {
|
|
2695
2686
|
wrapped[i] = value[i];
|
|
2696
2687
|
}
|
|
2697
2688
|
}
|
|
@@ -2714,9 +2705,7 @@ function struct(fields, options = {}) {
|
|
|
2714
2705
|
for (const f of fieldDefs) {
|
|
2715
2706
|
if (f.isAnonymous && f.type && f.type.fields) {
|
|
2716
2707
|
// Verifica se il campo esiste nel tipo anonimo
|
|
2717
|
-
const hasField = f.type.fields.some(
|
|
2718
|
-
(subField) => subField.name === firstPart,
|
|
2719
|
-
);
|
|
2708
|
+
const hasField = f.type.fields.some((subField) => subField.name === firstPart);
|
|
2720
2709
|
if (hasField) {
|
|
2721
2710
|
// Scrive nel campo dell'anonymous field
|
|
2722
2711
|
const nestedBuf = buf.subarray(f.offset, f.offset + f.size);
|
|
@@ -2730,14 +2719,7 @@ function struct(fields, options = {}) {
|
|
|
2730
2719
|
|
|
2731
2720
|
// Bit field
|
|
2732
2721
|
if (field.isBitField) {
|
|
2733
|
-
_writeBitField(
|
|
2734
|
-
buf,
|
|
2735
|
-
field.offset,
|
|
2736
|
-
field.type,
|
|
2737
|
-
field.bitOffset,
|
|
2738
|
-
field.bitSize,
|
|
2739
|
-
value,
|
|
2740
|
-
);
|
|
2722
|
+
_writeBitField(buf, field.offset, field.type, field.bitOffset, field.bitSize, value);
|
|
2741
2723
|
return;
|
|
2742
2724
|
}
|
|
2743
2725
|
|
|
@@ -2745,20 +2727,14 @@ function struct(fields, options = {}) {
|
|
|
2745
2727
|
if (field.isNested) {
|
|
2746
2728
|
if (parts.length > 1) {
|
|
2747
2729
|
// Accesso a campo annidato singolo
|
|
2748
|
-
const nestedBuf = buf.subarray(
|
|
2749
|
-
field.offset,
|
|
2750
|
-
field.offset + field.size,
|
|
2751
|
-
);
|
|
2730
|
+
const nestedBuf = buf.subarray(field.offset, field.offset + field.size);
|
|
2752
2731
|
field.type.set(nestedBuf, parts.slice(1).join("."), value);
|
|
2753
2732
|
} else if (Buffer.isBuffer(value)) {
|
|
2754
2733
|
// Copia buffer
|
|
2755
2734
|
value.copy(buf, field.offset, 0, field.size);
|
|
2756
2735
|
} else if (typeof value === "object") {
|
|
2757
2736
|
// Imposta campi da oggetto
|
|
2758
|
-
const nestedBuf = buf.subarray(
|
|
2759
|
-
field.offset,
|
|
2760
|
-
field.offset + field.size,
|
|
2761
|
-
);
|
|
2737
|
+
const nestedBuf = buf.subarray(field.offset, field.offset + field.size);
|
|
2762
2738
|
for (const [k, v] of Object.entries(value)) {
|
|
2763
2739
|
field.type.set(nestedBuf, k, v);
|
|
2764
2740
|
}
|
|
@@ -2773,10 +2749,7 @@ function struct(fields, options = {}) {
|
|
|
2773
2749
|
value.copy(buf, field.offset, 0, field.size);
|
|
2774
2750
|
} else if (Array.isArray(value)) {
|
|
2775
2751
|
// Inizializza da array JavaScript
|
|
2776
|
-
const arrayBuf = buf.subarray(
|
|
2777
|
-
field.offset,
|
|
2778
|
-
field.offset + field.size,
|
|
2779
|
-
);
|
|
2752
|
+
const arrayBuf = buf.subarray(field.offset, field.offset + field.size);
|
|
2780
2753
|
const wrapped = field.type.wrap(arrayBuf);
|
|
2781
2754
|
for (let i = 0; i < Math.min(value.length, field.type.length); i++) {
|
|
2782
2755
|
wrapped[i] = value[i];
|
|
@@ -2819,18 +2792,9 @@ function struct(fields, options = {}) {
|
|
|
2819
2792
|
// Leggi tutti i campi in una volta (eager approach)
|
|
2820
2793
|
for (const field of fieldDefs) {
|
|
2821
2794
|
if (field.isBitField) {
|
|
2822
|
-
result[field.name] = _readBitField(
|
|
2823
|
-
buf,
|
|
2824
|
-
field.offset,
|
|
2825
|
-
field.type,
|
|
2826
|
-
field.bitOffset,
|
|
2827
|
-
field.bitSize,
|
|
2828
|
-
);
|
|
2795
|
+
result[field.name] = _readBitField(buf, field.offset, field.type, field.bitOffset, field.bitSize);
|
|
2829
2796
|
} else if (field.isNested) {
|
|
2830
|
-
const nestedBuf = buf.subarray(
|
|
2831
|
-
field.offset,
|
|
2832
|
-
field.offset + field.size,
|
|
2833
|
-
);
|
|
2797
|
+
const nestedBuf = buf.subarray(field.offset, field.offset + field.size);
|
|
2834
2798
|
const nestedObj = field.type.toObject(nestedBuf);
|
|
2835
2799
|
if (field.isAnonymous) {
|
|
2836
2800
|
// Anonymous fields: promote their fields to parent level
|
|
@@ -2839,10 +2803,7 @@ function struct(fields, options = {}) {
|
|
|
2839
2803
|
result[field.name] = nestedObj;
|
|
2840
2804
|
}
|
|
2841
2805
|
} else if (field.isArray) {
|
|
2842
|
-
const arrayBuf = buf.subarray(
|
|
2843
|
-
field.offset,
|
|
2844
|
-
field.offset + field.size,
|
|
2845
|
-
);
|
|
2806
|
+
const arrayBuf = buf.subarray(field.offset, field.offset + field.size);
|
|
2846
2807
|
result[field.name] = field.type.wrap(arrayBuf);
|
|
2847
2808
|
} else {
|
|
2848
2809
|
// Tipo base - lettura diretta
|
|
@@ -2863,8 +2824,7 @@ function struct(fields, options = {}) {
|
|
|
2863
2824
|
// O(1) lookup con Map
|
|
2864
2825
|
const field = fieldMap.get(fieldName);
|
|
2865
2826
|
if (!field) throw new Error(`Unknown field: ${fieldName}`);
|
|
2866
|
-
if (!field.isNested)
|
|
2867
|
-
throw new Error(`Field ${fieldName} is not a nested struct`);
|
|
2827
|
+
if (!field.isNested) throw new Error(`Field ${fieldName} is not a nested struct`);
|
|
2868
2828
|
return buf.subarray(field.offset, field.offset + field.size);
|
|
2869
2829
|
},
|
|
2870
2830
|
};
|
|
@@ -2876,10 +2836,7 @@ function struct(fields, options = {}) {
|
|
|
2876
2836
|
structDef._cppStructType = cppStructType;
|
|
2877
2837
|
} catch (e) {
|
|
2878
2838
|
// Se fallisce, continua senza C++ (fallback a JS)
|
|
2879
|
-
console.warn(
|
|
2880
|
-
"Failed to create C++ StructType, using JavaScript fallback:",
|
|
2881
|
-
e.message,
|
|
2882
|
-
);
|
|
2839
|
+
console.warn("Failed to create C++ StructType, using JavaScript fallback:", e.message);
|
|
2883
2840
|
}
|
|
2884
2841
|
|
|
2885
2842
|
// fromObject: write plain object values into buffer
|
|
@@ -3026,7 +2983,10 @@ class c_int32 extends SimpleCData {
|
|
|
3026
2983
|
static _size = 4;
|
|
3027
2984
|
static _type = "int32";
|
|
3028
2985
|
static _reader = (buf, off) => buf.readInt32LE(off);
|
|
3029
|
-
static _writer = (buf, off, val) =>
|
|
2986
|
+
static _writer = (buf, off, val) => {
|
|
2987
|
+
const v = Number(val) | 0; // coerce to signed 32-bit
|
|
2988
|
+
return buf.writeInt32LE(v, off);
|
|
2989
|
+
};
|
|
3030
2990
|
}
|
|
3031
2991
|
|
|
3032
2992
|
class c_int64 extends SimpleCData {
|
|
@@ -3140,10 +3100,11 @@ class c_wchar extends SimpleCData {
|
|
|
3140
3100
|
class c_void_p extends SimpleCData {
|
|
3141
3101
|
static _size = native.POINTER_SIZE;
|
|
3142
3102
|
static _type = "pointer";
|
|
3143
|
-
static _reader = (buf, off) =>
|
|
3144
|
-
native.POINTER_SIZE === 8
|
|
3145
|
-
|
|
3146
|
-
|
|
3103
|
+
static _reader = (buf, off) => {
|
|
3104
|
+
const ptr = native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(off) : BigInt(buf.readUInt32LE(off));
|
|
3105
|
+
if (!ptr) return null;
|
|
3106
|
+
return ptr;
|
|
3107
|
+
};
|
|
3147
3108
|
static _writer = (buf, off, val) => {
|
|
3148
3109
|
// Accept Buffers (pointer to memory) and struct proxies with _buffer
|
|
3149
3110
|
if (Buffer.isBuffer(val)) {
|
|
@@ -3153,12 +3114,7 @@ class c_void_p extends SimpleCData {
|
|
|
3153
3114
|
else buf.writeUInt32LE(Number(v), off);
|
|
3154
3115
|
return;
|
|
3155
3116
|
}
|
|
3156
|
-
if (
|
|
3157
|
-
val &&
|
|
3158
|
-
typeof val === "object" &&
|
|
3159
|
-
val._buffer &&
|
|
3160
|
-
Buffer.isBuffer(val._buffer)
|
|
3161
|
-
) {
|
|
3117
|
+
if (val && typeof val === "object" && val._buffer && Buffer.isBuffer(val._buffer)) {
|
|
3162
3118
|
const addr = addressOf(val._buffer);
|
|
3163
3119
|
const v = typeof addr === "bigint" ? addr : BigInt(addr || 0);
|
|
3164
3120
|
if (native.POINTER_SIZE === 8) buf.writeBigUInt64LE(v, off);
|
|
@@ -3179,10 +3135,11 @@ class c_void_p extends SimpleCData {
|
|
|
3179
3135
|
class c_size_t extends SimpleCData {
|
|
3180
3136
|
static _size = native.POINTER_SIZE;
|
|
3181
3137
|
static _type = "size_t";
|
|
3182
|
-
static _reader = (buf, off) =>
|
|
3183
|
-
native.POINTER_SIZE === 8
|
|
3184
|
-
|
|
3185
|
-
|
|
3138
|
+
static _reader = (buf, off) => {
|
|
3139
|
+
const ptr = native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(off) : BigInt(buf.readUInt32LE(off));
|
|
3140
|
+
if (!ptr) return null;
|
|
3141
|
+
return ptr;
|
|
3142
|
+
};
|
|
3186
3143
|
static _writer = (buf, off, val) => {
|
|
3187
3144
|
const v = typeof val === "bigint" ? val : BigInt(val || 0);
|
|
3188
3145
|
if (native.POINTER_SIZE === 8) {
|
|
@@ -3202,27 +3159,15 @@ const _longSize = native.sizeof ? native.sizeof("long") : 4;
|
|
|
3202
3159
|
class c_long extends SimpleCData {
|
|
3203
3160
|
static _size = _longSize;
|
|
3204
3161
|
static _type = "long";
|
|
3205
|
-
static _reader =
|
|
3206
|
-
|
|
3207
|
-
? (buf, off) => buf.readBigInt64LE(off)
|
|
3208
|
-
: (buf, off) => buf.readInt32LE(off);
|
|
3209
|
-
static _writer =
|
|
3210
|
-
_longSize === 8
|
|
3211
|
-
? (buf, off, val) => buf.writeBigInt64LE(BigInt(val), off)
|
|
3212
|
-
: (buf, off, val) => buf.writeInt32LE(val, off);
|
|
3162
|
+
static _reader = _longSize === 8 ? (buf, off) => buf.readBigInt64LE(off) : (buf, off) => buf.readInt32LE(off);
|
|
3163
|
+
static _writer = _longSize === 8 ? (buf, off, val) => buf.writeBigInt64LE(BigInt(val), off) : (buf, off, val) => buf.writeInt32LE(val, off);
|
|
3213
3164
|
}
|
|
3214
3165
|
|
|
3215
3166
|
class c_ulong extends SimpleCData {
|
|
3216
3167
|
static _size = _longSize;
|
|
3217
3168
|
static _type = "ulong";
|
|
3218
|
-
static _reader =
|
|
3219
|
-
|
|
3220
|
-
? (buf, off) => buf.readBigUInt64LE(off)
|
|
3221
|
-
: (buf, off) => buf.readUInt32LE(off);
|
|
3222
|
-
static _writer =
|
|
3223
|
-
_longSize === 8
|
|
3224
|
-
? (buf, off, val) => buf.writeBigUInt64LE(BigInt(val), off)
|
|
3225
|
-
: (buf, off, val) => buf.writeUInt32LE(val, off);
|
|
3169
|
+
static _reader = _longSize === 8 ? (buf, off) => buf.readBigUInt64LE(off) : (buf, off) => buf.readUInt32LE(off);
|
|
3170
|
+
static _writer = _longSize === 8 ? (buf, off, val) => buf.writeBigUInt64LE(BigInt(val), off) : (buf, off, val) => buf.writeUInt32LE(val, off);
|
|
3226
3171
|
}
|
|
3227
3172
|
|
|
3228
3173
|
// ============================================================================
|
|
@@ -3232,11 +3177,15 @@ class c_ulong extends SimpleCData {
|
|
|
3232
3177
|
class c_char_p extends SimpleCData {
|
|
3233
3178
|
static _size = native.POINTER_SIZE;
|
|
3234
3179
|
static _type = "char_p";
|
|
3235
|
-
static _reader = (buf, off) =>
|
|
3236
|
-
native.POINTER_SIZE === 8
|
|
3237
|
-
|
|
3238
|
-
|
|
3180
|
+
static _reader = (buf, off) => {
|
|
3181
|
+
const ptr = native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(off) : BigInt(buf.readUInt32LE(off));
|
|
3182
|
+
if (!ptr) return null;
|
|
3183
|
+
return readCString(ptr);
|
|
3184
|
+
};
|
|
3239
3185
|
static _writer = (buf, off, val) => {
|
|
3186
|
+
if (typeof val === "string") {
|
|
3187
|
+
val = cstring(val);
|
|
3188
|
+
}
|
|
3240
3189
|
if (Buffer.isBuffer(val)) {
|
|
3241
3190
|
const addr = addressOf(val);
|
|
3242
3191
|
const v = typeof addr === "bigint" ? addr : BigInt(addr || 0);
|
|
@@ -3259,11 +3208,15 @@ class c_char_p extends SimpleCData {
|
|
|
3259
3208
|
class c_wchar_p extends SimpleCData {
|
|
3260
3209
|
static _size = native.POINTER_SIZE;
|
|
3261
3210
|
static _type = "wchar_p";
|
|
3262
|
-
static _reader = (buf, off) =>
|
|
3263
|
-
native.POINTER_SIZE === 8
|
|
3264
|
-
|
|
3265
|
-
|
|
3211
|
+
static _reader = (buf, off) => {
|
|
3212
|
+
const ptr = native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(off) : BigInt(buf.readUInt32LE(off));
|
|
3213
|
+
if (!ptr) return null;
|
|
3214
|
+
return readWString(ptr);
|
|
3215
|
+
};
|
|
3266
3216
|
static _writer = (buf, off, val) => {
|
|
3217
|
+
if (typeof val === "string") {
|
|
3218
|
+
val = wstring(val);
|
|
3219
|
+
}
|
|
3267
3220
|
if (Buffer.isBuffer(val)) {
|
|
3268
3221
|
const addr = addressOf(val);
|
|
3269
3222
|
const v = typeof addr === "bigint" ? addr : BigInt(addr || 0);
|
|
@@ -3319,9 +3272,7 @@ function create_string_buffer(init) {
|
|
|
3319
3272
|
buf[init.length] = 0; // null terminator
|
|
3320
3273
|
return buf;
|
|
3321
3274
|
}
|
|
3322
|
-
throw new TypeError(
|
|
3323
|
-
"create_string_buffer requires number, string, or Buffer",
|
|
3324
|
-
);
|
|
3275
|
+
throw new TypeError("create_string_buffer requires number, string, or Buffer");
|
|
3325
3276
|
}
|
|
3326
3277
|
|
|
3327
3278
|
/**
|