node-ctypes 1.1.0 → 1.3.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.
Potentially problematic release.
This version of node-ctypes might be problematic. Click here for more details.
- package/README.md +125 -10
- 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/core/Library.js +222 -221
- package/lib/core/callback.js +4 -4
- package/lib/core/types.js +41 -25
- package/lib/index.d.ts +57 -7
- package/lib/index.js +57 -60
- package/lib/memory/pointer.js +244 -27
- package/lib/structures/Structure.js +261 -230
- package/lib/structures/Union.js +10 -2
- package/lib/structures/helpers/common.js +9 -1
- package/lib/structures/helpers/struct.js +6 -1
- package/lib/structures/helpers/union.js +9 -19
- package/lib/types/SimpleCData.js +5 -5
- package/lib/types/primitives.js +37 -23
- package/package.json +2 -2
package/lib/memory/pointer.js
CHANGED
|
@@ -56,8 +56,7 @@ export function addressOf(ptr, alloc, native) {
|
|
|
56
56
|
if (Buffer.isBuffer(ptr)) {
|
|
57
57
|
// Get the buffer's memory address
|
|
58
58
|
const tempBuf = alloc(native.POINTER_SIZE);
|
|
59
|
-
|
|
60
|
-
native.writeValue(tempBuf, "pointer", ptr, 0);
|
|
59
|
+
native.writeValue(tempBuf, native.CType.POINTER, ptr, 0);
|
|
61
60
|
if (native.POINTER_SIZE === 8) return tempBuf.readBigUInt64LE(0);
|
|
62
61
|
return BigInt(tempBuf.readUInt32LE(0));
|
|
63
62
|
}
|
|
@@ -290,54 +289,225 @@ export function POINTER(baseType, sizeof, alloc, readValue, writeValue, c_void_p
|
|
|
290
289
|
const baseSize = typeof baseType === "object" ? baseType.size : sizeof(baseType);
|
|
291
290
|
const typeName = typeof baseType === "object" ? "struct" : baseType._type || "unknown";
|
|
292
291
|
|
|
293
|
-
|
|
292
|
+
/**
|
|
293
|
+
* Helper to get buffer's memory address using native writeValue
|
|
294
|
+
*/
|
|
295
|
+
function getBufferAddress(buf) {
|
|
296
|
+
const tempBuf = alloc(native.POINTER_SIZE);
|
|
297
|
+
native.writeValue(tempBuf, native.CType.POINTER, buf, 0);
|
|
298
|
+
if (native.POINTER_SIZE === 8) return tempBuf.readBigUInt64LE(0);
|
|
299
|
+
return BigInt(tempBuf.readUInt32LE(0));
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Creates a pointer instance with Python ctypes-compatible API.
|
|
304
|
+
* Supports .contents property and [index] access for pointer arithmetic.
|
|
305
|
+
*/
|
|
306
|
+
function createPointerInstance(addressOrBuffer) {
|
|
307
|
+
let _address = 0n;
|
|
308
|
+
let _buffer = null;
|
|
309
|
+
|
|
310
|
+
if (addressOrBuffer === undefined || addressOrBuffer === null) {
|
|
311
|
+
_address = 0n;
|
|
312
|
+
} else if (typeof addressOrBuffer === "bigint") {
|
|
313
|
+
_address = addressOrBuffer;
|
|
314
|
+
} else if (typeof addressOrBuffer === "number") {
|
|
315
|
+
_address = BigInt(addressOrBuffer);
|
|
316
|
+
} else if (Buffer.isBuffer(addressOrBuffer)) {
|
|
317
|
+
// This is a buffer we're pointing TO
|
|
318
|
+
_buffer = addressOrBuffer;
|
|
319
|
+
_address = getBufferAddress(addressOrBuffer);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const instance = {
|
|
323
|
+
_pointerType: PointerType,
|
|
324
|
+
_baseType: baseType,
|
|
325
|
+
_baseSize: baseSize,
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Get the raw address as BigInt
|
|
329
|
+
*/
|
|
330
|
+
get address() {
|
|
331
|
+
return _address;
|
|
332
|
+
},
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Python ctypes compatible: get/set the value at the pointed location.
|
|
336
|
+
* In Python: p.contents returns the dereferenced value.
|
|
337
|
+
*/
|
|
338
|
+
get contents() {
|
|
339
|
+
if (_address === 0n && !_buffer) {
|
|
340
|
+
throw new Error("NULL pointer access");
|
|
341
|
+
}
|
|
342
|
+
if (_buffer) {
|
|
343
|
+
// We have the actual buffer, read from it
|
|
344
|
+
return readValue(_buffer, baseType, 0);
|
|
345
|
+
}
|
|
346
|
+
// We only have address - need native support to read
|
|
347
|
+
const buf = native.ptrToBuffer(_address, baseSize);
|
|
348
|
+
return readValue(buf, baseType, 0);
|
|
349
|
+
},
|
|
350
|
+
|
|
351
|
+
set contents(value) {
|
|
352
|
+
if (_address === 0n && !_buffer) {
|
|
353
|
+
throw new Error("NULL pointer access");
|
|
354
|
+
}
|
|
355
|
+
if (_buffer) {
|
|
356
|
+
writeValue(_buffer, baseType, value, 0);
|
|
357
|
+
} else {
|
|
358
|
+
const buf = native.ptrToBuffer(_address, baseSize);
|
|
359
|
+
writeValue(buf, baseType, value, 0);
|
|
360
|
+
}
|
|
361
|
+
},
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Returns the buffer this pointer points to (if available)
|
|
365
|
+
*/
|
|
366
|
+
get _buffer() {
|
|
367
|
+
return _buffer;
|
|
368
|
+
},
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Dereference - alias for contents getter
|
|
372
|
+
*/
|
|
373
|
+
deref() {
|
|
374
|
+
return this.contents;
|
|
375
|
+
},
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Set pointer to point to a new address/buffer
|
|
379
|
+
*/
|
|
380
|
+
set(value) {
|
|
381
|
+
if (Buffer.isBuffer(value)) {
|
|
382
|
+
_buffer = value;
|
|
383
|
+
_address = getBufferAddress(value);
|
|
384
|
+
} else if (typeof value === "bigint") {
|
|
385
|
+
_address = value;
|
|
386
|
+
_buffer = null;
|
|
387
|
+
} else if (typeof value === "number") {
|
|
388
|
+
_address = BigInt(value);
|
|
389
|
+
_buffer = null;
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Check if pointer is NULL
|
|
395
|
+
*/
|
|
396
|
+
get isNull() {
|
|
397
|
+
return _address === 0n && !_buffer;
|
|
398
|
+
},
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* For compatibility - get pointer as buffer (8 bytes containing address)
|
|
402
|
+
*/
|
|
403
|
+
toBuffer() {
|
|
404
|
+
const buf = alloc(native.POINTER_SIZE);
|
|
405
|
+
writeValue(buf, c_void_p, _address);
|
|
406
|
+
return buf;
|
|
407
|
+
},
|
|
408
|
+
|
|
409
|
+
toString() {
|
|
410
|
+
return `<${typeName} pointer at 0x${_address.toString(16)}>`;
|
|
411
|
+
},
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
// Use Proxy for [index] access (pointer arithmetic)
|
|
415
|
+
return new Proxy(instance, {
|
|
416
|
+
get(target, prop, receiver) {
|
|
417
|
+
// Numeric index access: p[0], p[1], etc.
|
|
418
|
+
if (typeof prop === "string" && /^\d+$/.test(prop)) {
|
|
419
|
+
const index = parseInt(prop, 10);
|
|
420
|
+
if (target.isNull) {
|
|
421
|
+
throw new Error("NULL pointer access");
|
|
422
|
+
}
|
|
423
|
+
const offset = index * baseSize;
|
|
424
|
+
if (_buffer && offset + baseSize <= _buffer.length) {
|
|
425
|
+
return readValue(_buffer, baseType, offset);
|
|
426
|
+
}
|
|
427
|
+
// Use native to read at address + offset
|
|
428
|
+
const addr = _address + BigInt(offset);
|
|
429
|
+
const buf = native.ptrToBuffer(addr, baseSize);
|
|
430
|
+
return readValue(buf, baseType, 0);
|
|
431
|
+
}
|
|
432
|
+
return Reflect.get(target, prop, receiver);
|
|
433
|
+
},
|
|
434
|
+
|
|
435
|
+
set(target, prop, value, receiver) {
|
|
436
|
+
// Numeric index access: p[0] = value, p[1] = value, etc.
|
|
437
|
+
if (typeof prop === "string" && /^\d+$/.test(prop)) {
|
|
438
|
+
const index = parseInt(prop, 10);
|
|
439
|
+
if (target.isNull) {
|
|
440
|
+
throw new Error("NULL pointer access");
|
|
441
|
+
}
|
|
442
|
+
const offset = index * baseSize;
|
|
443
|
+
if (_buffer && offset + baseSize <= _buffer.length) {
|
|
444
|
+
writeValue(_buffer, baseType, value, offset);
|
|
445
|
+
return true;
|
|
446
|
+
}
|
|
447
|
+
// Use native to write at address + offset
|
|
448
|
+
const addr = _address + BigInt(offset);
|
|
449
|
+
const buf = native.ptrToBuffer(addr, baseSize);
|
|
450
|
+
writeValue(buf, baseType, value, 0);
|
|
451
|
+
return true;
|
|
452
|
+
}
|
|
453
|
+
return Reflect.set(target, prop, value, receiver);
|
|
454
|
+
},
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Pointer type factory - creates pointer instances
|
|
460
|
+
*/
|
|
461
|
+
const PointerType = {
|
|
294
462
|
_pointerTo: baseType,
|
|
295
463
|
_baseSize: baseSize,
|
|
296
464
|
size: native.POINTER_SIZE,
|
|
297
465
|
|
|
298
466
|
/**
|
|
299
|
-
* Creates a
|
|
300
|
-
* @
|
|
467
|
+
* Creates a new pointer instance.
|
|
468
|
+
* @param {Buffer|bigint|number} [value] - Initial value (buffer to point to, or address)
|
|
469
|
+
* @returns {Object} Pointer instance with .contents and [index] access
|
|
301
470
|
*/
|
|
302
|
-
create() {
|
|
303
|
-
|
|
304
|
-
writeValue(buf, c_void_p, 0n);
|
|
305
|
-
return buf;
|
|
471
|
+
create(value) {
|
|
472
|
+
return createPointerInstance(value);
|
|
306
473
|
},
|
|
307
474
|
|
|
308
475
|
/**
|
|
309
|
-
* Creates a pointer
|
|
310
|
-
* @param {Buffer} targetBuf -
|
|
311
|
-
* @returns {
|
|
476
|
+
* Creates a pointer from an existing buffer (points to that buffer).
|
|
477
|
+
* @param {Buffer} targetBuf - Buffer to point to
|
|
478
|
+
* @returns {Object} Pointer instance
|
|
312
479
|
*/
|
|
313
480
|
fromBuffer(targetBuf) {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
481
|
+
return createPointerInstance(targetBuf);
|
|
482
|
+
},
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Creates a pointer from a raw address.
|
|
486
|
+
* @param {bigint|number} address - Memory address
|
|
487
|
+
* @returns {Object} Pointer instance
|
|
488
|
+
*/
|
|
489
|
+
fromAddress(address) {
|
|
490
|
+
return createPointerInstance(typeof address === "bigint" ? address : BigInt(address));
|
|
317
491
|
},
|
|
318
492
|
|
|
319
493
|
/**
|
|
320
|
-
* Dereferences
|
|
321
|
-
* @
|
|
322
|
-
* @returns {bigint|null} Address value, or null if NULL pointer
|
|
494
|
+
* Legacy API: Dereferences a pointer buffer.
|
|
495
|
+
* @deprecated Use pointer instance .contents instead
|
|
323
496
|
*/
|
|
324
497
|
deref(ptrBuf) {
|
|
325
498
|
const addr = readValue(ptrBuf, c_void_p);
|
|
326
499
|
if (addr === 0n || addr === null) {
|
|
327
500
|
return null;
|
|
328
501
|
}
|
|
329
|
-
// For struct types, return address (can't safely create buffer without native support)
|
|
330
502
|
if (typeof baseType === "object" && baseType.toObject) {
|
|
331
503
|
return addr;
|
|
332
504
|
}
|
|
333
|
-
// For primitive types, return address
|
|
334
505
|
return addr;
|
|
335
506
|
},
|
|
336
507
|
|
|
337
508
|
/**
|
|
338
|
-
* Sets
|
|
339
|
-
* @
|
|
340
|
-
* @param {Buffer|bigint|number} value - Value to set (buffer or address)
|
|
509
|
+
* Legacy API: Sets pointer buffer value.
|
|
510
|
+
* @deprecated Use pointer instance .set() instead
|
|
341
511
|
*/
|
|
342
512
|
set(ptrBuf, value) {
|
|
343
513
|
if (Buffer.isBuffer(value)) {
|
|
@@ -347,12 +517,59 @@ export function POINTER(baseType, sizeof, alloc, readValue, writeValue, c_void_p
|
|
|
347
517
|
}
|
|
348
518
|
},
|
|
349
519
|
|
|
350
|
-
/**
|
|
351
|
-
* Returns string representation of pointer type.
|
|
352
|
-
* @returns {string} Type name
|
|
353
|
-
*/
|
|
354
520
|
toString() {
|
|
355
521
|
return `POINTER(${typeName})`;
|
|
356
522
|
},
|
|
357
523
|
};
|
|
524
|
+
|
|
525
|
+
return PointerType;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
/**
|
|
529
|
+
* Creates a pointer to an existing ctypes object.
|
|
530
|
+
* Python ctypes compatible: pointer(obj) returns a pointer to obj.
|
|
531
|
+
*
|
|
532
|
+
* @param {Object} obj - Object to create pointer to (must have ._buffer or be a Buffer)
|
|
533
|
+
* @param {Function} POINTER_fn - POINTER function reference
|
|
534
|
+
* @param {Function} sizeof - sizeof function reference
|
|
535
|
+
* @param {Function} alloc - alloc function reference
|
|
536
|
+
* @param {Function} readValue - readValue function reference
|
|
537
|
+
* @param {Function} writeValue - writeValue function reference
|
|
538
|
+
* @param {Function} c_void_p - c_void_p type reference
|
|
539
|
+
* @param {Object} native - Native module reference
|
|
540
|
+
* @returns {Object} Pointer instance pointing to obj
|
|
541
|
+
*
|
|
542
|
+
* @example
|
|
543
|
+
* ```javascript
|
|
544
|
+
* const x = new c_int32(42);
|
|
545
|
+
* const p = pointer(x);
|
|
546
|
+
* console.log(p.contents); // 42
|
|
547
|
+
* p.contents = 100;
|
|
548
|
+
* console.log(x.value); // 100
|
|
549
|
+
* ```
|
|
550
|
+
*/
|
|
551
|
+
export function pointer(obj, POINTER_fn, sizeof, alloc, readValue, writeValue, c_void_p, native) {
|
|
552
|
+
let targetBuffer;
|
|
553
|
+
let baseType;
|
|
554
|
+
|
|
555
|
+
if (Buffer.isBuffer(obj)) {
|
|
556
|
+
targetBuffer = obj;
|
|
557
|
+
baseType = c_void_p; // Generic pointer
|
|
558
|
+
} else if (obj && obj._buffer) {
|
|
559
|
+
// Structure/Union instance or SimpleCData with _buffer
|
|
560
|
+
targetBuffer = obj._buffer;
|
|
561
|
+
// Get the base type - use constructor for SimpleCData, _structDef for structures
|
|
562
|
+
if (obj.constructor && obj.constructor._type) {
|
|
563
|
+
// SimpleCData instance - use the class itself
|
|
564
|
+
baseType = obj.constructor;
|
|
565
|
+
} else {
|
|
566
|
+
// Structure/Union instance
|
|
567
|
+
baseType = obj._structDef || obj.__structDef || c_void_p;
|
|
568
|
+
}
|
|
569
|
+
} else {
|
|
570
|
+
throw new TypeError("pointer() argument must be a ctypes instance or Buffer");
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
const PtrType = POINTER_fn(baseType, sizeof, alloc, readValue, writeValue, c_void_p, native);
|
|
574
|
+
return PtrType.fromBuffer(targetBuffer);
|
|
358
575
|
}
|