node-ctypes 1.2.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.
package/lib/core/types.js CHANGED
@@ -88,6 +88,13 @@ export function _toNativeType(type, native) {
88
88
  return type._type;
89
89
  }
90
90
 
91
+ // POINTER types: return CType.POINTER (11)
92
+ // POINTER(baseType) returns an object with _pointerTo property
93
+ if (type && typeof type === "object" && type._pointerTo !== undefined) {
94
+ // All pointer types are passed as generic pointers to FFI
95
+ return native.CType.POINTER;
96
+ }
97
+
91
98
  // Structure/Union classes: pass through unchanged
92
99
  // These are handled specially by the FFI layer
93
100
  if (typeof type === "function" && type.prototype) {
package/lib/index.d.ts CHANGED
@@ -92,6 +92,16 @@ export class CDLL {
92
92
  close(): void;
93
93
  readonly path: string;
94
94
  readonly loaded: boolean;
95
+ /** Python-like function access: lib.FuncName returns a FunctionWrapper */
96
+ [funcName: string]: FunctionWrapper | any;
97
+ }
98
+
99
+ /** FunctionWrapper for Python-like argtypes/restype syntax */
100
+ export interface FunctionWrapper {
101
+ (...args: any[]): any;
102
+ argtypes: AnyType[];
103
+ restype: AnyType;
104
+ errcheck: ErrcheckCallback | null;
95
105
  }
96
106
 
97
107
  /** WinDLL - stdcall calling convention library (Windows) */
@@ -326,6 +336,7 @@ export function bitfield(baseType: AnyType, bits: number): BitFieldDef;
326
336
  export function byref(obj: Buffer | SimpleCDataInstance | { _buffer: Buffer }): Buffer;
327
337
  export function cast(ptr: Buffer | bigint, targetType: AnyType | StructDef): Buffer | { [key: string]: any };
328
338
  export function POINTER(baseType: AnyType | StructDef): PointerTypeDef;
339
+ export function pointer(obj: SimpleCDataInstance | { _buffer: Buffer }): SimpleCDataInstance & { contents: any; [index: number]: any };
329
340
 
330
341
  // Error handling
331
342
  export function get_errno(): number;
@@ -343,7 +354,7 @@ export function WinError(code?: number): Error & { winerror: number };
343
354
  export interface SimpleCDataConstructor {
344
355
  new (value?: any): SimpleCDataInstance;
345
356
  readonly _size: number;
346
- readonly _type: number; // CType numeric value from native module
357
+ readonly _type: number; // CType numeric value from native module
347
358
  readonly _isSimpleCData: true;
348
359
  _reader(buf: Buffer, offset: number): any;
349
360
  _writer(buf: Buffer, offset: number, value: any): void;
@@ -385,6 +396,17 @@ export const c_size_t: SimpleCDataConstructor;
385
396
  export const c_long: SimpleCDataConstructor;
386
397
  export const c_ulong: SimpleCDataConstructor;
387
398
 
399
+ // Python-compatible aliases
400
+ export const c_byte: SimpleCDataConstructor;
401
+ export const c_ubyte: SimpleCDataConstructor;
402
+ export const c_short: SimpleCDataConstructor;
403
+ export const c_ushort: SimpleCDataConstructor;
404
+ export const c_longlong: SimpleCDataConstructor;
405
+ export const c_ulonglong: SimpleCDataConstructor;
406
+
407
+ /** SimpleCData base class for creating custom simple types */
408
+ export const SimpleCData: SimpleCDataConstructor;
409
+
388
410
  // =============================================================================
389
411
  // Constants
390
412
  // =============================================================================
package/lib/index.js CHANGED
@@ -35,39 +35,12 @@ import {
35
35
  memmove as _memmove,
36
36
  memset as _memset,
37
37
  } from "./memory/buffer.js";
38
- import {
39
- readValue as _readValue,
40
- writeValue as _writeValue,
41
- sizeof as _sizeof,
42
- } from "./memory/operations.js";
43
- import {
44
- addressOf as _addressOf,
45
- byref as _byref,
46
- cast as _cast,
47
- ptrToBuffer as _ptrToBuffer,
48
- POINTER as _POINTER,
49
- } from "./memory/pointer.js";
50
- import {
51
- get_errno as _get_errno,
52
- set_errno as _set_errno,
53
- GetLastError as _GetLastError,
54
- SetLastError as _SetLastError,
55
- FormatError as _FormatError,
56
- WinError as _WinError,
57
- } from "./platform/errors.js";
58
- import {
59
- bitfield as _bitfield,
60
- _isStruct,
61
- _isArrayType,
62
- _isBitField,
63
- } from "./structures/helpers/common.js";
38
+ import { readValue as _readValue, writeValue as _writeValue, sizeof as _sizeof } from "./memory/operations.js";
39
+ import { addressOf as _addressOf, byref as _byref, cast as _cast, ptrToBuffer as _ptrToBuffer, POINTER as _POINTER, pointer as _pointer } from "./memory/pointer.js";
40
+ import { get_errno as _get_errno, set_errno as _set_errno, GetLastError as _GetLastError, SetLastError as _SetLastError, FormatError as _FormatError, WinError as _WinError } from "./platform/errors.js";
41
+ import { bitfield as _bitfield, _isStruct, _isArrayType, _isBitField } from "./structures/helpers/common.js";
64
42
  import { array as _array } from "./structures/helpers/array.js";
65
- import {
66
- _readBitField as _readBitFieldHelper,
67
- _writeBitField as _writeBitFieldHelper,
68
- _readUintFromBuffer,
69
- _writeUintToBuffer,
70
- } from "./structures/helpers/bitfield.js";
43
+ import { _readBitField as _readBitFieldHelper, _writeBitField as _writeBitFieldHelper, _readUintFromBuffer, _writeUintToBuffer } from "./structures/helpers/bitfield.js";
71
44
  import { union as _union } from "./structures/helpers/union.js";
72
45
  import { struct as _struct } from "./structures/helpers/struct.js";
73
46
  import { createStructureClass } from "./structures/Structure.js";
@@ -163,13 +136,7 @@ function load(libPath) {
163
136
  * Wrapper per funzioni con sintassi Python-like ctypes (argtypes/restype)
164
137
  */
165
138
  // Create Library classes (FunctionWrapper, CDLL, WinDLL)
166
- const { FunctionWrapper, CDLL, WinDLL } = createLibraryClasses(
167
- Library,
168
- LRUCache,
169
- _toNativeType,
170
- _toNativeTypes,
171
- native
172
- );
139
+ const { FunctionWrapper, CDLL, WinDLL } = createLibraryClasses(Library, LRUCache, _toNativeType, _toNativeTypes, native);
173
140
 
174
141
  // ============================================================================
175
142
  // Callback Functions
@@ -260,6 +227,26 @@ function POINTER(baseType) {
260
227
  return _POINTER(baseType, sizeof, alloc, readValue, writeValue, c_void_p, native);
261
228
  }
262
229
 
230
+ /**
231
+ * Creates a pointer to an existing ctypes object.
232
+ * Python ctypes compatible: pointer(obj) returns a pointer to obj.
233
+ *
234
+ * @param {Object} obj - Object to create pointer to (must have ._buffer or be a Buffer)
235
+ * @returns {Object} Pointer instance pointing to obj
236
+ *
237
+ * @example
238
+ * ```javascript
239
+ * const x = new c_int32(42);
240
+ * const p = pointer(x);
241
+ * console.log(p.contents); // 42
242
+ * p.contents = 100;
243
+ * console.log(x.value); // 100
244
+ * ```
245
+ */
246
+ function pointer(obj) {
247
+ return _pointer(obj, _POINTER, sizeof, alloc, readValue, writeValue, c_void_p, native);
248
+ }
249
+
263
250
  /**
264
251
  * Helper per definire union (tutti i campi condividono offset 0)
265
252
  * Supporta nested structs e bitfields come struct()
@@ -304,9 +291,8 @@ function defineUnion(fields) {
304
291
  // --------------------------------------------------------------------------
305
292
 
306
293
  // Create Structure and Union classes with injected dependencies
307
- const Structure = createStructureClass(alloc, struct);
308
- const Union = createUnionClass(Structure, union);
309
-
294
+ const Structure = createStructureClass(alloc, struct, bitfield);
295
+ const Union = createUnionClass(Structure, union, bitfield);
310
296
 
311
297
  /**
312
298
  * Helper per creare array a dimensione fissa (come c_int * 5 in Python)
@@ -412,28 +398,38 @@ function struct(fields, options = {}) {
412
398
  const SimpleCData = createSimpleCDataClass(alloc);
413
399
 
414
400
  // Create all primitive type classes
415
- const primitiveTypes = createPrimitiveTypes(
416
- SimpleCData,
417
- native,
418
- addressOf,
419
- cstring,
420
- wstring,
421
- readCString,
422
- readWString
423
- );
401
+ const primitiveTypes = createPrimitiveTypes(SimpleCData, native, addressOf, cstring, wstring, readCString, readWString);
424
402
 
425
403
  // Destructure all types for easy access
426
404
  const {
427
405
  c_void,
428
- c_int8, c_int16, c_int32, c_int64,
429
- c_uint8, c_uint16, c_uint32, c_uint64,
430
- c_float, c_double,
406
+ c_int8,
407
+ c_int16,
408
+ c_int32,
409
+ c_int64,
410
+ c_uint8,
411
+ c_uint16,
412
+ c_uint32,
413
+ c_uint64,
414
+ c_float,
415
+ c_double,
431
416
  c_bool,
432
- c_char, c_wchar,
433
- c_void_p, c_char_p, c_wchar_p,
434
- c_size_t, c_long, c_ulong,
435
- c_byte, c_ubyte, c_short, c_ushort,
436
- c_int, c_uint, c_longlong, c_ulonglong,
417
+ c_char,
418
+ c_wchar,
419
+ c_void_p,
420
+ c_char_p,
421
+ c_wchar_p,
422
+ c_size_t,
423
+ c_long,
424
+ c_ulong,
425
+ c_byte,
426
+ c_ubyte,
427
+ c_short,
428
+ c_ushort,
429
+ c_int,
430
+ c_uint,
431
+ c_longlong,
432
+ c_ulonglong,
437
433
  } = primitiveTypes;
438
434
 
439
435
  // ============================================================================
@@ -523,6 +519,7 @@ export {
523
519
  byref,
524
520
  cast,
525
521
  POINTER,
522
+ pointer,
526
523
 
527
524
  // Error handling
528
525
  get_errno,
@@ -289,54 +289,225 @@ export function POINTER(baseType, sizeof, alloc, readValue, writeValue, c_void_p
289
289
  const baseSize = typeof baseType === "object" ? baseType.size : sizeof(baseType);
290
290
  const typeName = typeof baseType === "object" ? "struct" : baseType._type || "unknown";
291
291
 
292
- return {
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 = {
293
462
  _pointerTo: baseType,
294
463
  _baseSize: baseSize,
295
464
  size: native.POINTER_SIZE,
296
465
 
297
466
  /**
298
- * Creates a NULL pointer.
299
- * @returns {Buffer} Buffer containing NULL pointer
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
300
470
  */
301
- create() {
302
- const buf = alloc(native.POINTER_SIZE);
303
- writeValue(buf, c_void_p, 0n);
304
- return buf;
471
+ create(value) {
472
+ return createPointerInstance(value);
305
473
  },
306
474
 
307
475
  /**
308
- * Creates a pointer to an existing buffer.
309
- * @param {Buffer} targetBuf - Target buffer to point to
310
- * @returns {Buffer} Buffer containing pointer to targetBuf
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
311
479
  */
312
480
  fromBuffer(targetBuf) {
313
- const buf = alloc(native.POINTER_SIZE);
314
- writeValue(buf, c_void_p, targetBuf);
315
- return buf;
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));
316
491
  },
317
492
 
318
493
  /**
319
- * Dereferences the pointer (reads the address it points to).
320
- * @param {Buffer} ptrBuf - Buffer containing the pointer
321
- * @returns {bigint|null} Address value, or null if NULL pointer
494
+ * Legacy API: Dereferences a pointer buffer.
495
+ * @deprecated Use pointer instance .contents instead
322
496
  */
323
497
  deref(ptrBuf) {
324
498
  const addr = readValue(ptrBuf, c_void_p);
325
499
  if (addr === 0n || addr === null) {
326
500
  return null;
327
501
  }
328
- // For struct types, return address (can't safely create buffer without native support)
329
502
  if (typeof baseType === "object" && baseType.toObject) {
330
503
  return addr;
331
504
  }
332
- // For primitive types, return address
333
505
  return addr;
334
506
  },
335
507
 
336
508
  /**
337
- * Sets the pointer to point to a value or buffer.
338
- * @param {Buffer} ptrBuf - Buffer containing the pointer
339
- * @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
340
511
  */
341
512
  set(ptrBuf, value) {
342
513
  if (Buffer.isBuffer(value)) {
@@ -346,12 +517,59 @@ export function POINTER(baseType, sizeof, alloc, readValue, writeValue, c_void_p
346
517
  }
347
518
  },
348
519
 
349
- /**
350
- * Returns string representation of pointer type.
351
- * @returns {string} Type name
352
- */
353
520
  toString() {
354
521
  return `POINTER(${typeName})`;
355
522
  },
356
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);
357
575
  }