node-ctypes 1.7.0 → 1.8.0
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/build/Release/ctypes-darwin-arm64.node +0 -0
- package/build/Release/ctypes-darwin-x64.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.js +10 -1
- package/lib/memory/operations.js +19 -0
- package/lib/memory/pointer.js +49 -19
- package/lib/structures/helpers/union.js +49 -0
- package/package.json +1 -1
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/lib/index.js
CHANGED
|
@@ -208,6 +208,15 @@ function sizeof(type) {
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
function alignment(type) {
|
|
211
|
+
// Instance of Structure/Union — use _structDef/_unionDef (Python: alignment(instance) works)
|
|
212
|
+
if (type instanceof Structure || type instanceof Union) {
|
|
213
|
+
const def = type._structDef || type._unionDef;
|
|
214
|
+
return def ? def.alignment : 1;
|
|
215
|
+
}
|
|
216
|
+
// SimpleCData instance — delegate to class (Python: alignment(c_int32(42)) works)
|
|
217
|
+
if (typeof type === "object" && type !== null && type.constructor && type.constructor._isSimpleCData) {
|
|
218
|
+
return alignment(type.constructor);
|
|
219
|
+
}
|
|
211
220
|
// Structure/Union class
|
|
212
221
|
if (typeof type === "function" && (type.prototype instanceof Structure || type.prototype instanceof Union)) {
|
|
213
222
|
const def = type._structDef || type._unionDef || type._buildStruct?.() || type._buildUnion?.();
|
|
@@ -242,7 +251,7 @@ function byref(obj) {
|
|
|
242
251
|
}
|
|
243
252
|
|
|
244
253
|
function cast(ptr, targetType) {
|
|
245
|
-
return _cast(ptr, targetType, readValue, sizeof, ptrToBuffer);
|
|
254
|
+
return _cast(ptr, targetType, readValue, sizeof, ptrToBuffer, native);
|
|
246
255
|
}
|
|
247
256
|
|
|
248
257
|
function ptrToBuffer(address, size) {
|
package/lib/memory/operations.js
CHANGED
|
@@ -119,6 +119,12 @@ export function readValue(ptr, type, offset = 0, sizeof, ptrToBuffer, Structure,
|
|
|
119
119
|
return def.toObject(tempBuf);
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
// Struct/Union def object (has _isStructType and toObject)
|
|
123
|
+
if (typeof type === "object" && type !== null && type._isStructType && typeof type.toObject === "function") {
|
|
124
|
+
const tempBuf = ptr.subarray(offset, offset + type.size);
|
|
125
|
+
return type.toObject(tempBuf);
|
|
126
|
+
}
|
|
127
|
+
|
|
122
128
|
throw new TypeError(`readValue: unsupported type ${type}`);
|
|
123
129
|
}
|
|
124
130
|
|
|
@@ -211,6 +217,19 @@ export function writeValue(ptr, type, value, offset = 0, sizeof, Structure, Unio
|
|
|
211
217
|
return def.size;
|
|
212
218
|
}
|
|
213
219
|
|
|
220
|
+
// Struct/Union def object (has _isStructType and set/fromObject)
|
|
221
|
+
if (typeof type === "object" && type !== null && type._isStructType && typeof type.set === "function") {
|
|
222
|
+
const tempBuf = ptr.subarray(offset, offset + type.size);
|
|
223
|
+
if (Buffer.isBuffer(value)) {
|
|
224
|
+
value.copy(tempBuf, 0, 0, type.size);
|
|
225
|
+
} else if (typeof value === "object" && value !== null) {
|
|
226
|
+
for (const [k, v] of Object.entries(value)) {
|
|
227
|
+
type.set(tempBuf, k, v);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return type.size;
|
|
231
|
+
}
|
|
232
|
+
|
|
214
233
|
throw new TypeError(`writeValue: unsupported type ${type}`);
|
|
215
234
|
}
|
|
216
235
|
|
package/lib/memory/pointer.js
CHANGED
|
@@ -53,6 +53,10 @@
|
|
|
53
53
|
* ```
|
|
54
54
|
*/
|
|
55
55
|
export function addressOf(ptr, alloc, native) {
|
|
56
|
+
// If it's an object with _buffer (SimpleCData, Structure, Union, array proxy), use its buffer
|
|
57
|
+
if (!Buffer.isBuffer(ptr) && ptr && ptr._buffer && Buffer.isBuffer(ptr._buffer)) {
|
|
58
|
+
ptr = ptr._buffer;
|
|
59
|
+
}
|
|
56
60
|
if (Buffer.isBuffer(ptr)) {
|
|
57
61
|
// Get the buffer's memory address
|
|
58
62
|
const tempBuf = alloc(native.POINTER_SIZE);
|
|
@@ -164,7 +168,7 @@ export function byref(obj) {
|
|
|
164
168
|
* console.log(header.contents); // { magic: 23117, version: 1 }
|
|
165
169
|
* ```
|
|
166
170
|
*/
|
|
167
|
-
export function cast(ptr, targetType, readValue, sizeof, ptrToBuffer) {
|
|
171
|
+
export function cast(ptr, targetType, readValue, sizeof, ptrToBuffer, native) {
|
|
168
172
|
// Validate inputs
|
|
169
173
|
if (!ptr) {
|
|
170
174
|
throw new TypeError("cast() requires a non-null pointer");
|
|
@@ -173,9 +177,42 @@ export function cast(ptr, targetType, readValue, sizeof, ptrToBuffer) {
|
|
|
173
177
|
throw new TypeError("cast() requires a target type");
|
|
174
178
|
}
|
|
175
179
|
|
|
176
|
-
// PointerTypeDef — return a PointerInstance via fromAddress()
|
|
177
|
-
// Python equivalent: cast(c_void_p(addr), POINTER(
|
|
180
|
+
// PointerTypeDef — return a PointerInstance via fromAddress() or fromBuffer()
|
|
181
|
+
// Python equivalent: cast(c_void_p(addr), POINTER(c_int32)) — read stored address
|
|
182
|
+
// Python equivalent: cast(arr, POINTER(c_int32)) — pointer to arr's memory
|
|
183
|
+
// Python equivalent: cast(p, POINTER(c_double)) — pointer to same memory as p
|
|
178
184
|
if (typeof targetType === "object" && targetType._pointerTo !== undefined) {
|
|
185
|
+
// PointerInstance — use its address/buffer (Python: cast(p, POINTER(OtherType)))
|
|
186
|
+
if (ptr && typeof ptr === "object" && typeof ptr.address === "bigint") {
|
|
187
|
+
if (ptr._buffer) {
|
|
188
|
+
return targetType.fromBuffer(ptr._buffer);
|
|
189
|
+
}
|
|
190
|
+
return targetType.fromAddress(ptr.address);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// ctypes object with _buffer — distinguish data objects from pointer-value objects
|
|
194
|
+
// Note: array proxies are Buffer.isBuffer()==true but also have ._buffer, so don't exclude Buffers
|
|
195
|
+
if (ptr && typeof ptr === "object" && ptr._buffer && Buffer.isBuffer(ptr._buffer)) {
|
|
196
|
+
// SimpleCData storing a pointer/address value (c_void_p, c_char_p, etc.)
|
|
197
|
+
// → read the stored address value from the buffer
|
|
198
|
+
if (ptr.constructor && ptr.constructor._isSimpleCData && ptr.constructor._type === native.CType.POINTER) {
|
|
199
|
+
// This is a pointer-valued SimpleCData — read address from buffer
|
|
200
|
+
const buf = ptr._buffer;
|
|
201
|
+
let addr;
|
|
202
|
+
if (buf.length >= 8) {
|
|
203
|
+
addr = buf.readBigUInt64LE(0);
|
|
204
|
+
} else if (buf.length >= 4) {
|
|
205
|
+
addr = BigInt(buf.readUInt32LE(0));
|
|
206
|
+
} else {
|
|
207
|
+
throw new TypeError("cast(): buffer too small to contain a pointer");
|
|
208
|
+
}
|
|
209
|
+
return targetType.fromAddress(addr);
|
|
210
|
+
}
|
|
211
|
+
// Array, Structure, Union — pointer to their data buffer
|
|
212
|
+
// Python: cast(arr, POINTER(c_int32)) points to arr's memory
|
|
213
|
+
return targetType.fromBuffer(ptr._buffer);
|
|
214
|
+
}
|
|
215
|
+
|
|
179
216
|
let addr;
|
|
180
217
|
if (typeof ptr === "bigint") {
|
|
181
218
|
addr = ptr;
|
|
@@ -190,18 +227,8 @@ export function cast(ptr, targetType, readValue, sizeof, ptrToBuffer) {
|
|
|
190
227
|
} else {
|
|
191
228
|
throw new TypeError("cast(): buffer too small to contain a pointer");
|
|
192
229
|
}
|
|
193
|
-
} else if (ptr && ptr._buffer) {
|
|
194
|
-
// SimpleCData instance (e.g., c_void_p)
|
|
195
|
-
const buf = ptr._buffer;
|
|
196
|
-
if (buf.length >= 8) {
|
|
197
|
-
addr = buf.readBigUInt64LE(0);
|
|
198
|
-
} else if (buf.length >= 4) {
|
|
199
|
-
addr = BigInt(buf.readUInt32LE(0));
|
|
200
|
-
} else {
|
|
201
|
-
throw new TypeError("cast(): buffer too small to contain a pointer");
|
|
202
|
-
}
|
|
203
230
|
} else {
|
|
204
|
-
throw new TypeError("cast(): ptr must be a BigInt, number, Buffer,
|
|
231
|
+
throw new TypeError("cast(): ptr must be a BigInt, number, Buffer, ctypes instance, or PointerInstance");
|
|
205
232
|
}
|
|
206
233
|
return targetType.fromAddress(addr);
|
|
207
234
|
}
|
|
@@ -320,7 +347,7 @@ export function ptrToBuffer(address, size, native) {
|
|
|
320
347
|
*/
|
|
321
348
|
export function POINTER(baseType, sizeof, alloc, readValue, writeValue, c_void_p, native) {
|
|
322
349
|
const baseSize = typeof baseType === "object" ? baseType.size : sizeof(baseType);
|
|
323
|
-
const typeName = typeof baseType === "object" ? "struct" : baseType._type || "unknown";
|
|
350
|
+
const typeName = typeof baseType === "object" ? "struct" : baseType._type || baseType.name || "unknown";
|
|
324
351
|
|
|
325
352
|
/**
|
|
326
353
|
* Helper to get buffer's memory address using native writeValue
|
|
@@ -591,13 +618,16 @@ export function pointer(obj, POINTER_fn, sizeof, alloc, readValue, writeValue, c
|
|
|
591
618
|
} else if (obj && obj._buffer) {
|
|
592
619
|
// Structure/Union instance or SimpleCData with _buffer
|
|
593
620
|
targetBuffer = obj._buffer;
|
|
594
|
-
// Get the base type
|
|
621
|
+
// Get the base type for POINTER creation
|
|
595
622
|
if (obj.constructor && obj.constructor._type) {
|
|
596
|
-
// SimpleCData instance - use the class itself
|
|
623
|
+
// SimpleCData instance - use the class itself (c_int32, c_double, etc.)
|
|
597
624
|
baseType = obj.constructor;
|
|
625
|
+
} else if (obj._structDef) {
|
|
626
|
+
// Structure/Union instance - use the struct def object
|
|
627
|
+
// (obj.constructor is a bound function from Proxy, so we use _structDef directly)
|
|
628
|
+
baseType = obj._structDef;
|
|
598
629
|
} else {
|
|
599
|
-
|
|
600
|
-
baseType = obj._structDef || obj.__structDef || c_void_p;
|
|
630
|
+
baseType = c_void_p;
|
|
601
631
|
}
|
|
602
632
|
} else {
|
|
603
633
|
throw new TypeError("pointer() argument must be a ctypes instance or Buffer");
|
|
@@ -320,6 +320,12 @@ export function union(fields, sizeof, alloc, readValue, writeValue, _isStruct, _
|
|
|
320
320
|
return field.type.wrap(buf.subarray(field.offset, field.offset + field.size));
|
|
321
321
|
}
|
|
322
322
|
|
|
323
|
+
// POINTER() field — return PointerInstance
|
|
324
|
+
if (field.isPointer) {
|
|
325
|
+
const addr = native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(field.offset) : BigInt(buf.readUInt32LE(field.offset));
|
|
326
|
+
return field.type.fromAddress(addr);
|
|
327
|
+
}
|
|
328
|
+
|
|
323
329
|
// Tipo base
|
|
324
330
|
return readValue(buf, field.type, field.offset);
|
|
325
331
|
},
|
|
@@ -376,6 +382,28 @@ export function union(fields, sizeof, alloc, readValue, writeValue, _isStruct, _
|
|
|
376
382
|
return;
|
|
377
383
|
}
|
|
378
384
|
|
|
385
|
+
// POINTER() field — write address
|
|
386
|
+
if (field.isPointer) {
|
|
387
|
+
let addr;
|
|
388
|
+
if (typeof value === "bigint") {
|
|
389
|
+
addr = value;
|
|
390
|
+
} else if (typeof value === "number") {
|
|
391
|
+
addr = BigInt(value);
|
|
392
|
+
} else if (value && typeof value.address === "bigint") {
|
|
393
|
+
addr = value.address;
|
|
394
|
+
} else if (Buffer.isBuffer(value)) {
|
|
395
|
+
addr = native.POINTER_SIZE === 8 ? value.readBigUInt64LE(0) : BigInt(value.readUInt32LE(0));
|
|
396
|
+
} else {
|
|
397
|
+
addr = 0n;
|
|
398
|
+
}
|
|
399
|
+
if (native.POINTER_SIZE === 8) {
|
|
400
|
+
buf.writeBigUInt64LE(addr, field.offset);
|
|
401
|
+
} else {
|
|
402
|
+
buf.writeUInt32LE(Number(addr), field.offset);
|
|
403
|
+
}
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
|
|
379
407
|
// Tipo base
|
|
380
408
|
writeValue(buf, field.type, value, field.offset);
|
|
381
409
|
},
|
|
@@ -429,6 +457,9 @@ export function union(fields, sizeof, alloc, readValue, writeValue, _isStruct, _
|
|
|
429
457
|
} else if (field.isArray) {
|
|
430
458
|
const wrapped = field.type.wrap(buf.subarray(0, field.size));
|
|
431
459
|
return [...wrapped];
|
|
460
|
+
} else if (field.isPointer) {
|
|
461
|
+
const addr = native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(0) : BigInt(buf.readUInt32LE(0));
|
|
462
|
+
return field.type.fromAddress(addr);
|
|
432
463
|
} else {
|
|
433
464
|
return readValue(buf, field.type, 0);
|
|
434
465
|
}
|
|
@@ -436,6 +467,24 @@ export function union(fields, sizeof, alloc, readValue, writeValue, _isStruct, _
|
|
|
436
467
|
set(value) {
|
|
437
468
|
if (field.isBitField) {
|
|
438
469
|
_writeBitField(buf, 0, field.type, field.bitOffset, field.bitSize, value, sizeof);
|
|
470
|
+
} else if (field.isPointer) {
|
|
471
|
+
let addr;
|
|
472
|
+
if (typeof value === "bigint") {
|
|
473
|
+
addr = value;
|
|
474
|
+
} else if (typeof value === "number") {
|
|
475
|
+
addr = BigInt(value);
|
|
476
|
+
} else if (value && typeof value.address === "bigint") {
|
|
477
|
+
addr = value.address;
|
|
478
|
+
} else if (Buffer.isBuffer(value)) {
|
|
479
|
+
addr = native.POINTER_SIZE === 8 ? value.readBigUInt64LE(0) : BigInt(value.readUInt32LE(0));
|
|
480
|
+
} else {
|
|
481
|
+
addr = 0n;
|
|
482
|
+
}
|
|
483
|
+
if (native.POINTER_SIZE === 8) {
|
|
484
|
+
buf.writeBigUInt64LE(addr, 0);
|
|
485
|
+
} else {
|
|
486
|
+
buf.writeUInt32LE(Number(addr), 0);
|
|
487
|
+
}
|
|
439
488
|
} else {
|
|
440
489
|
writeValue(buf, field.type, value, 0);
|
|
441
490
|
}
|