node-ctypes 1.6.0 → 1.7.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/README.md CHANGED
@@ -119,13 +119,22 @@ const buf = Buffer.alloc(4);
119
119
  buf.writeInt32LE(42, 0);
120
120
 
121
121
  const p = IntPtr.fromBuffer(buf);
122
- console.log(p.contents); // 42
123
- console.log(p[0]); // 42
122
+ console.log(p.contents); // 42 (like *p in C)
123
+ console.log(p[0]); // 42 (like p[0] in C)
124
124
 
125
125
  // pointer() function
126
126
  const x = new c_int32(42);
127
127
  const px = pointer(x);
128
128
  console.log(px.contents); // 42
129
+
130
+ // fromAddress() — typed access to native memory
131
+ const pValues = POINTER(MyStruct).fromAddress(nativeAddr);
132
+ console.log(pValues[0].field); // pointer arithmetic (like pValues[0] in C)
133
+ console.log(pValues[5].field); // pValues + 5 * sizeof(MyStruct)
134
+
135
+ // cast() to POINTER — Python: cast(c_void_p(addr), POINTER(MyStruct))
136
+ const pData = cast(rawAddr, POINTER(MyStruct));
137
+ console.log(pData[0].field); // same result as fromAddress()
129
138
  ```
130
139
 
131
140
  ### Callbacks
@@ -194,11 +203,12 @@ console.log(`${st.wYear}-${st.wMonth}-${st.wDay}`);
194
203
  | Callbacks | `CFUNCTYPE(c_int, c_int)` | `CFUNCTYPE(c_int, c_int)` |
195
204
  | Pointers | `POINTER(c_int)` / `pointer(obj)` | `POINTER(c_int)` / `pointer(obj)` |
196
205
  | Sizeof | `sizeof(c_int)` | `sizeof(c_int)` |
206
+ | Alignment | `alignment(c_int)` | `alignment(c_int)` |
197
207
  | Strings | `c_char_p(b"hello")` | `create_string_buffer("hello")` |
198
208
  | Variadic | `sprintf(buf, b"%d", 42)` | `sprintf(buf, "%d", 42)` |
199
209
  | Errno | `get_errno()` | `get_errno()` |
200
210
  | byref | `byref(obj)` | `byref(obj)` |
201
- | cast | `cast(ptr, type)` | `cast(ptr, type)` |
211
+ | cast | `cast(ptr, type)` | `cast(ptr, type)` (supports `POINTER()` target) |
202
212
 
203
213
  ## Supported Types
204
214
 
@@ -219,6 +229,7 @@ console.log(`${st.wYear}-${st.wMonth}-${st.wDay}`);
219
229
  | `c_wchar_p` | wide string | pointer |
220
230
  | `c_bool` | | 1 |
221
231
  | `c_size_t` | | platform |
232
+ | `c_ssize_t` | | platform |
222
233
 
223
234
  ## Key Differences from Python ctypes
224
235
 
@@ -233,6 +244,7 @@ console.log(`${st.wYear}-${st.wMonth}-${st.wDay}`);
233
244
  - `string_at(address, size)` / `wstring_at(address, size)` — read strings from memory
234
245
  - `readValue(ptr, type, offset)` / `writeValue(ptr, type, value, offset)` — direct memory access
235
246
  - `sizeof(type)` — type size in bytes
247
+ - `alignment(type)` — type alignment in bytes
236
248
  - `addressof(ptr)` — get address as BigInt
237
249
  - `memmove(dst, src, count)` / `memset(dst, value, count)` — memory operations
238
250
  - `GetLastError()` / `FormatError(code)` — Windows error helpers
Binary file
Binary file
package/lib/index.d.ts CHANGED
@@ -373,7 +373,7 @@ export class ThreadSafeCallback extends Callback {}
373
373
  */
374
374
  export interface FieldDef {
375
375
  name: string;
376
- type: AnyType | StructDef | ArrayTypeDef | BitFieldDef;
376
+ type: AnyType | StructDef | ArrayTypeDef | BitFieldDef | PointerTypeDef;
377
377
  offset: number;
378
378
  size: number;
379
379
  alignment: number;
@@ -419,7 +419,7 @@ export interface StructDef {
419
419
  }
420
420
 
421
421
  /** @category Structures */
422
- export type FieldSpec = AnyType | StructDef | ArrayTypeDef | BitFieldDef | AnonymousField;
422
+ export type FieldSpec = AnyType | StructDef | ArrayTypeDef | BitFieldDef | AnonymousField | PointerTypeDef;
423
423
 
424
424
  type JsFromCType<T> = T extends "int64" | "uint64" | "size_t"
425
425
  ? bigint
@@ -544,14 +544,109 @@ export interface AnonymousField {
544
544
  // Pointers
545
545
  // =============================================================================
546
546
 
547
+ /**
548
+ * A pointer instance created by {@link PointerTypeDef.create}, {@link PointerTypeDef.fromBuffer},
549
+ * or {@link PointerTypeDef.fromAddress}.
550
+ *
551
+ * Supports Python ctypes-compatible `.contents` property and C-like `[index]` pointer arithmetic.
552
+ *
553
+ * @example
554
+ * ```javascript
555
+ * const IntPtr = POINTER(c_int32);
556
+ * const p = IntPtr.fromBuffer(buf);
557
+ * console.log(p.contents); // dereferenced value (like *p in C)
558
+ * console.log(p[0]); // same as p.contents
559
+ * console.log(p[5]); // pointer arithmetic (like p[5] in C)
560
+ * ```
561
+ *
562
+ * @example Access a native array via pointer from a struct field
563
+ * ```javascript
564
+ * // When a struct has a c_void_p field pointing to an array of structs:
565
+ * const pValues = POINTER(ADSVALUE).fromAddress(col.pADsValues);
566
+ * for (let i = 0; i < col.dwNumValues; i++) {
567
+ * console.log(pValues[i].dwType); // struct view at pValues + i * sizeof(ADSVALUE)
568
+ * }
569
+ * ```
570
+ *
571
+ * @category Pointers
572
+ */
573
+ export interface PointerInstance {
574
+ /** The pointer type definition this instance was created from. */
575
+ readonly _pointerType: PointerTypeDef;
576
+ /** The base type this pointer points to. */
577
+ readonly _baseType: AnyType | StructDef;
578
+ /** Size of the pointed-to type in bytes. */
579
+ readonly _baseSize: number;
580
+
581
+ /** Raw memory address as BigInt. */
582
+ readonly address: bigint;
583
+
584
+ /**
585
+ * Dereference the pointer — read/write the value at the pointed location.
586
+ *
587
+ * Python equivalent: `p.contents`
588
+ *
589
+ * @example
590
+ * ```javascript
591
+ * const p = POINTER(c_int32).fromBuffer(buf);
592
+ * console.log(p.contents); // read value
593
+ * p.contents = 42; // write value
594
+ * ```
595
+ */
596
+ contents: any;
597
+
598
+ /** The underlying buffer (if created from a buffer), or null. */
599
+ readonly _buffer: Buffer | null;
600
+
601
+ /** Alias for contents getter. */
602
+ deref(): any;
603
+
604
+ /**
605
+ * Set pointer to a new target (buffer or address).
606
+ * @param value - Buffer to point to, or BigInt/number address
607
+ */
608
+ set(value: Buffer | bigint | number): void;
609
+
610
+ /** Check if this is a NULL pointer. */
611
+ readonly isNull: boolean;
612
+
613
+ /** Get pointer as an 8-byte buffer containing the address. */
614
+ toBuffer(): Buffer;
615
+
616
+ toString(): string;
617
+
618
+ /**
619
+ * Pointer arithmetic — access elements at offset from the pointer.
620
+ *
621
+ * `p[i]` reads `sizeof(baseType)` bytes at `address + i * sizeof(baseType)`,
622
+ * exactly like C pointer indexing.
623
+ *
624
+ * @example
625
+ * ```javascript
626
+ * const arr = POINTER(c_int32).fromAddress(arrayAddr);
627
+ * arr[0] // first element
628
+ * arr[5] // sixth element
629
+ * arr[2] = 99; // write to third element
630
+ * ```
631
+ */
632
+ [index: number]: any;
633
+ }
634
+
547
635
  /**
548
636
  * A pointer type created by {@link POINTER}.
549
637
  *
550
638
  * @example
551
639
  * ```javascript
552
640
  * const IntPtr = POINTER(c_int32);
641
+ *
642
+ * // From existing buffer
553
643
  * const p = IntPtr.fromBuffer(buf);
554
- * console.log(p.contents); // dereferenced value
644
+ * console.log(p.contents); // 42
645
+ * console.log(p[0]); // 42
646
+ *
647
+ * // From raw address (e.g., from a struct's c_void_p field)
648
+ * const pValues = POINTER(MyStruct).fromAddress(someStruct.pData);
649
+ * console.log(pValues[0].field1);
555
650
  * ```
556
651
  *
557
652
  * @category Pointers
@@ -564,14 +659,63 @@ export interface PointerTypeDef {
564
659
  /** Pointer size (always 8 on 64-bit). */
565
660
  readonly size: number;
566
661
 
567
- /** Create a NULL pointer. */
568
- create(): Buffer;
569
- /** Create a pointer to an existing buffer. */
570
- fromBuffer(targetBuf: Buffer): Buffer;
571
- /** Dereference the pointer, returning the target address or null. */
662
+ /**
663
+ * Create a NULL pointer instance.
664
+ *
665
+ * @example
666
+ * ```javascript
667
+ * const p = POINTER(c_int32).create();
668
+ * console.log(p.isNull); // true
669
+ * ```
670
+ */
671
+ create(value?: Buffer | bigint | number): PointerInstance;
672
+
673
+ /**
674
+ * Create a pointer from an existing buffer (points to that buffer's memory).
675
+ *
676
+ * @param targetBuf - Buffer to point to
677
+ *
678
+ * @example
679
+ * ```javascript
680
+ * const buf = Buffer.alloc(4);
681
+ * buf.writeInt32LE(42, 0);
682
+ * const p = POINTER(c_int32).fromBuffer(buf);
683
+ * console.log(p.contents); // 42
684
+ * ```
685
+ */
686
+ fromBuffer(targetBuf: Buffer): PointerInstance;
687
+
688
+ /**
689
+ * Create a pointer from a raw memory address.
690
+ *
691
+ * Use this to create typed access to native memory, especially useful with
692
+ * `c_void_p` struct fields that point to arrays of structs.
693
+ *
694
+ * @param address - Memory address as BigInt or number
695
+ *
696
+ * @example
697
+ * ```javascript
698
+ * // Access array of structs from a c_void_p field
699
+ * const pValues = POINTER(ADSVALUE).fromAddress(col.pADsValues);
700
+ * for (let i = 0; i < col.dwNumValues; i++) {
701
+ * console.log(pValues[i].dwType);
702
+ * }
703
+ * ```
704
+ */
705
+ fromAddress(address: bigint | number): PointerInstance;
706
+
707
+ /**
708
+ * @deprecated Use pointer instance `.contents` instead.
709
+ * Legacy API: Dereferences a pointer buffer.
710
+ */
572
711
  deref(ptrBuf: Buffer): bigint | null;
573
- /** Update the pointer target. */
712
+
713
+ /**
714
+ * @deprecated Use pointer instance `.set()` instead.
715
+ * Legacy API: Sets pointer buffer value.
716
+ */
574
717
  set(ptrBuf: Buffer, value: Buffer | bigint): void;
718
+
575
719
  toString(): string;
576
720
  }
577
721
 
@@ -943,6 +1087,22 @@ export function writeValue(ptr: Buffer | bigint | number, type: AnyType, value:
943
1087
  */
944
1088
  export function sizeof(type: AnyType | StructDef | ArrayTypeDef): number;
945
1089
 
1090
+ /**
1091
+ * Get the alignment requirement of a type in bytes.
1092
+ *
1093
+ * Python equivalent: `ctypes.alignment`
1094
+ *
1095
+ * @example
1096
+ * ```javascript
1097
+ * alignment(c_int32) // 4
1098
+ * alignment(c_double) // 8
1099
+ * alignment(MyStruct) // max field alignment
1100
+ * ```
1101
+ *
1102
+ * @category Memory
1103
+ */
1104
+ export function alignment(type: AnyType | StructDef | ArrayTypeDef | typeof Structure | typeof Union): number;
1105
+
946
1106
  /**
947
1107
  * Create a Buffer view of native memory at a given address.
948
1108
  *
@@ -1059,12 +1219,31 @@ export function byref(obj: Buffer | SimpleCDataInstance | { _buffer: Buffer }):
1059
1219
  *
1060
1220
  * Python equivalent: `ctypes.cast`
1061
1221
  *
1062
- * @param ptr - Buffer or BigInt address to cast
1063
- * @param targetType - The target type
1222
+ * When the target is a {@link PointerTypeDef}, returns a {@link PointerInstance} with
1223
+ * `.contents` and `[index]` access equivalent to Python's
1224
+ * `cast(c_void_p(addr), POINTER(MyStruct))`.
1225
+ *
1226
+ * @param ptr - Buffer, BigInt address, number, or SimpleCData instance (e.g., `c_void_p`)
1227
+ * @param targetType - The target type (primitive, struct, or POINTER type)
1228
+ *
1229
+ * @example Cast to POINTER for typed array access
1230
+ * ```javascript
1231
+ * // Python: cast(c_void_p(addr), POINTER(MyStruct))
1232
+ * const pValues = cast(col.pADsValues, POINTER(ADSVALUE));
1233
+ * for (let i = 0; i < col.dwNumValues; i++) {
1234
+ * console.log(pValues[i].dwType);
1235
+ * }
1236
+ * ```
1237
+ *
1238
+ * @example Cast to primitive type
1239
+ * ```javascript
1240
+ * const floatVal = cast(intBuf, c_float);
1241
+ * ```
1064
1242
  *
1065
1243
  * @category Pointers
1066
1244
  */
1067
- export function cast(ptr: Buffer | bigint, targetType: AnyType | StructDef): Buffer | { [key: string]: any };
1245
+ export function cast(ptr: Buffer | bigint | number | SimpleCDataInstance, targetType: PointerTypeDef): PointerInstance;
1246
+ export function cast(ptr: Buffer | bigint | number | SimpleCDataInstance, targetType: AnyType | StructDef): any;
1068
1247
 
1069
1248
  /**
1070
1249
  * Create a pointer type for a given base type.
@@ -1074,7 +1253,7 @@ export function cast(ptr: Buffer | bigint, targetType: AnyType | StructDef): Buf
1074
1253
  * @param baseType - The type to point to
1075
1254
  * @returns A pointer type with `create()`, `fromBuffer()`, etc.
1076
1255
  *
1077
- * @example
1256
+ * @example Basic pointer
1078
1257
  * ```javascript
1079
1258
  * const IntPtr = POINTER(c_int32);
1080
1259
  * const buf = Buffer.alloc(4);
@@ -1082,7 +1261,20 @@ export function cast(ptr: Buffer | bigint, targetType: AnyType | StructDef): Buf
1082
1261
  *
1083
1262
  * const p = IntPtr.fromBuffer(buf);
1084
1263
  * console.log(p.contents); // 42
1085
- * console.log(p[0]); // 42
1264
+ * console.log(p[0]); // 42
1265
+ * ```
1266
+ *
1267
+ * @example Typed access to native array via c_void_p struct field
1268
+ * ```javascript
1269
+ * // Structure fields don't accept POINTER() types directly — use c_void_p,
1270
+ * // then wrap with POINTER().fromAddress() for typed indexed access:
1271
+ * class Column extends Structure {
1272
+ * static _fields_ = [["pValues", c_void_p], ["count", c_uint32]];
1273
+ * }
1274
+ * const pValues = POINTER(ValueStruct).fromAddress(col.pValues);
1275
+ * for (let i = 0; i < col.count; i++) {
1276
+ * console.log(pValues[i].field); // struct view at offset i
1277
+ * }
1086
1278
  * ```
1087
1279
  *
1088
1280
  * @category Pointers
@@ -1108,7 +1300,7 @@ export function POINTER(baseType: AnyType | StructDef): PointerTypeDef;
1108
1300
  *
1109
1301
  * @category Pointers
1110
1302
  */
1111
- export function pointer(obj: SimpleCDataInstance | { _buffer: Buffer }): SimpleCDataInstance & { contents: any; [index: number]: any };
1303
+ export function pointer(obj: SimpleCDataInstance | { _buffer: Buffer }): PointerInstance;
1112
1304
 
1113
1305
  /**
1114
1306
  * Get the C library errno value.
@@ -1264,8 +1456,10 @@ export const c_wchar_p: SimpleCDataConstructor;
1264
1456
  export const c_void_p: SimpleCDataConstructor;
1265
1457
  /** Boolean (1 byte). Python: `ctypes.c_bool` @category Types */
1266
1458
  export const c_bool: SimpleCDataConstructor;
1267
- /** Platform-dependent size type (BigInt). Python: `ctypes.c_size_t` @category Types */
1459
+ /** Platform-dependent unsigned size type (BigInt). Python: `ctypes.c_size_t` @category Types */
1268
1460
  export const c_size_t: SimpleCDataConstructor;
1461
+ /** Platform-dependent signed size type (BigInt). Python: `ctypes.c_ssize_t` @category Types */
1462
+ export const c_ssize_t: SimpleCDataConstructor;
1269
1463
  /** Platform-dependent signed long. Python: `ctypes.c_long` @category Types */
1270
1464
  export const c_long: SimpleCDataConstructor;
1271
1465
  /** Platform-dependent unsigned long. Python: `ctypes.c_ulong` @category Types */
package/lib/index.js CHANGED
@@ -207,6 +207,27 @@ function sizeof(type) {
207
207
  return _sizeof(type, Structure, Union);
208
208
  }
209
209
 
210
+ function alignment(type) {
211
+ // Structure/Union class
212
+ if (typeof type === "function" && (type.prototype instanceof Structure || type.prototype instanceof Union)) {
213
+ const def = type._structDef || type._unionDef || type._buildStruct?.() || type._buildUnion?.();
214
+ return def ? def.alignment : 1;
215
+ }
216
+ // StructDef / UnionDef object
217
+ if (typeof type === "object" && type !== null && type._isStructType && type.alignment !== undefined) {
218
+ return type.alignment;
219
+ }
220
+ // ArrayTypeDef
221
+ if (typeof type === "object" && type !== null && type._isArrayType) {
222
+ return type.getAlignment();
223
+ }
224
+ // SimpleCData class — natural alignment = min(size, POINTER_SIZE)
225
+ if (typeof type === "function" && type._isSimpleCData) {
226
+ return Math.min(type._size, native.POINTER_SIZE);
227
+ }
228
+ throw new TypeError("alignment() argument must be a ctypes type");
229
+ }
230
+
210
231
  // ============================================================================
211
232
  // Pointer Operations
212
233
  // Now imported from ./memory/pointer.js - see that file for implementation details
@@ -425,6 +446,7 @@ const {
425
446
  c_char_p,
426
447
  c_wchar_p,
427
448
  c_size_t,
449
+ c_ssize_t,
428
450
  c_long,
429
451
  c_ulong,
430
452
  c_byte,
@@ -505,6 +527,7 @@ export {
505
527
  readValue,
506
528
  writeValue,
507
529
  sizeof,
530
+ alignment,
508
531
  ptrToBuffer,
509
532
 
510
533
  // Strutture
@@ -560,6 +583,7 @@ export {
560
583
  c_void_p,
561
584
  c_bool,
562
585
  c_size_t,
586
+ c_ssize_t,
563
587
  c_long,
564
588
  c_ulong,
565
589
  // Python-compatible aliases
@@ -173,6 +173,39 @@ export function cast(ptr, targetType, readValue, sizeof, ptrToBuffer) {
173
173
  throw new TypeError("cast() requires a target type");
174
174
  }
175
175
 
176
+ // PointerTypeDef — return a PointerInstance via fromAddress()
177
+ // Python equivalent: cast(c_void_p(addr), POINTER(MyStruct))
178
+ if (typeof targetType === "object" && targetType._pointerTo !== undefined) {
179
+ let addr;
180
+ if (typeof ptr === "bigint") {
181
+ addr = ptr;
182
+ } else if (typeof ptr === "number") {
183
+ addr = BigInt(ptr);
184
+ } else if (Buffer.isBuffer(ptr)) {
185
+ // Read the pointer value from the buffer
186
+ if (ptr.length >= 8) {
187
+ addr = ptr.readBigUInt64LE(0);
188
+ } else if (ptr.length >= 4) {
189
+ addr = BigInt(ptr.readUInt32LE(0));
190
+ } else {
191
+ throw new TypeError("cast(): buffer too small to contain a pointer");
192
+ }
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
+ } else {
204
+ throw new TypeError("cast(): ptr must be a BigInt, number, Buffer, or ctypes instance");
205
+ }
206
+ return targetType.fromAddress(addr);
207
+ }
208
+
176
209
  // Struct type - return wrapper object
177
210
  if (typeof targetType === "object" && targetType.size !== undefined) {
178
211
  const buf = Buffer.isBuffer(ptr) ? ptr : ptrToBuffer(ptr, targetType.size);
@@ -307,6 +307,34 @@ export function struct(fields, options = {}, sizeof, alloc, readValue, writeValu
307
307
  maxAlignment = alignment;
308
308
  }
309
309
  }
310
+ // Caso 4b: POINTER() type — stored as pointer-sized field with typed access
311
+ else if (typeof type === "object" && type !== null && type._pointerTo !== undefined) {
312
+ // Reset bit field state
313
+ currentBitFieldBase = null;
314
+ currentBitOffset = 0;
315
+
316
+ const size = native.POINTER_SIZE;
317
+ const alignment = packed ? 1 : Math.min(size, native.POINTER_SIZE);
318
+
319
+ if (!packed && totalSize % alignment !== 0) {
320
+ totalSize += alignment - (totalSize % alignment);
321
+ }
322
+
323
+ fieldDef = {
324
+ name,
325
+ type,
326
+ offset: totalSize,
327
+ size,
328
+ alignment,
329
+ isPointer: true,
330
+ };
331
+
332
+ totalSize += size;
333
+
334
+ if (alignment > maxAlignment) {
335
+ maxAlignment = alignment;
336
+ }
337
+ }
310
338
  // Caso 4: Tipo base (SimpleCData)
311
339
  else {
312
340
  // Reset bit field state
@@ -369,6 +397,37 @@ export function struct(fields, options = {}, sizeof, alloc, readValue, writeValu
369
397
  continue;
370
398
  }
371
399
 
400
+ // POINTER() type field — read returns PointerInstance, write accepts BigInt/PointerInstance
401
+ if (field.isPointer) {
402
+ const fieldOffset = offset;
403
+ const ptrType = field.type;
404
+ fieldReaders.set(name, (buf) => {
405
+ const addr = native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(fieldOffset) : BigInt(buf.readUInt32LE(fieldOffset));
406
+ return ptrType.fromAddress(addr);
407
+ });
408
+ fieldWriters.set(name, (buf, val) => {
409
+ let addr;
410
+ if (typeof val === "bigint") {
411
+ addr = val;
412
+ } else if (typeof val === "number") {
413
+ addr = BigInt(val);
414
+ } else if (val && typeof val.address === "bigint") {
415
+ // PointerInstance
416
+ addr = val.address;
417
+ } else if (Buffer.isBuffer(val)) {
418
+ addr = native.POINTER_SIZE === 8 ? val.readBigUInt64LE(0) : BigInt(val.readUInt32LE(0));
419
+ } else {
420
+ addr = 0n;
421
+ }
422
+ if (native.POINTER_SIZE === 8) {
423
+ buf.writeBigUInt64LE(addr, fieldOffset);
424
+ } else {
425
+ buf.writeUInt32LE(Number(addr), fieldOffset);
426
+ }
427
+ });
428
+ continue;
429
+ }
430
+
372
431
  // Pre-compile based on SimpleCData type
373
432
  // Use the type's _reader and _writer directly for optimization
374
433
  const fieldType = field.type;
@@ -662,6 +721,12 @@ export function struct(fields, options = {}, sizeof, alloc, readValue, writeValu
662
721
  : field.type.toObject(nestedBuf);
663
722
  }
664
723
 
724
+ // POINTER() field — return PointerInstance
725
+ if (field.isPointer) {
726
+ const addr = native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(field.offset) : BigInt(buf.readUInt32LE(field.offset));
727
+ return field.type.fromAddress(addr);
728
+ }
729
+
665
730
  // Array field
666
731
  if (field.isArray) {
667
732
  const arrayBuf = buf.subarray(field.offset, field.offset + field.size);
@@ -748,6 +813,26 @@ export function struct(fields, options = {}, sizeof, alloc, readValue, writeValu
748
813
  return;
749
814
  }
750
815
 
816
+ // POINTER() field — write address
817
+ if (field.isPointer) {
818
+ let addr;
819
+ if (typeof value === "bigint") {
820
+ addr = value;
821
+ } else if (typeof value === "number") {
822
+ addr = BigInt(value);
823
+ } else if (value && typeof value.address === "bigint") {
824
+ addr = value.address;
825
+ } else {
826
+ addr = 0n;
827
+ }
828
+ if (native.POINTER_SIZE === 8) {
829
+ buf.writeBigUInt64LE(addr, field.offset);
830
+ } else {
831
+ buf.writeUInt32LE(Number(addr), field.offset);
832
+ }
833
+ return;
834
+ }
835
+
751
836
  // Array field
752
837
  if (field.isArray) {
753
838
  if (Buffer.isBuffer(value)) {
@@ -875,6 +960,9 @@ export function struct(fields, options = {}, sizeof, alloc, readValue, writeValu
875
960
  } else {
876
961
  result[field.name] = nestedObj;
877
962
  }
963
+ } else if (field.isPointer) {
964
+ const addr = native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(field.offset) : BigInt(buf.readUInt32LE(field.offset));
965
+ result[field.name] = field.type.fromAddress(addr);
878
966
  } else if (field.isArray) {
879
967
  const arrayBuf = buf.subarray(field.offset, field.offset + field.size);
880
968
  result[field.name] = field.type.wrap(arrayBuf);
@@ -123,6 +123,13 @@ export function union(fields, sizeof, alloc, readValue, writeValue, _isStruct, _
123
123
  fieldDef.baseSize = type.baseSize;
124
124
  fieldDef.type = type.baseType; // Usa il tipo base per lettura/scrittura
125
125
  }
126
+ // POINTER() type
127
+ else if (typeof type === "object" && type !== null && type._pointerTo !== undefined) {
128
+ size = native.POINTER_SIZE;
129
+ alignment = Math.min(size, native.POINTER_SIZE);
130
+ fieldDef.type = type;
131
+ fieldDef.isPointer = true;
132
+ }
126
133
  // Tipo base (SimpleCData)
127
134
  else {
128
135
  // Validate type is a SimpleCData class
@@ -284,6 +284,21 @@ export function createPrimitiveTypes(SimpleCData, native, addressOf, cstring, ws
284
284
  };
285
285
  }
286
286
 
287
+ class c_ssize_t extends SimpleCData {
288
+ static _size = native.POINTER_SIZE;
289
+ static _type = CType.SSIZE_T;
290
+ static _reader = (buf, off) => {
291
+ return native.POINTER_SIZE === 8 ? buf.readBigInt64LE(off) : buf.readInt32LE(off);
292
+ };
293
+ static _writer = (buf, off, val) => {
294
+ if (native.POINTER_SIZE === 8) {
295
+ buf.writeBigInt64LE(BigInt(val), off);
296
+ } else {
297
+ buf.writeInt32LE(Number(val), off);
298
+ }
299
+ };
300
+ }
301
+
287
302
  // Get actual long size from native module (4 on Windows, 4 or 8 on Unix depending on arch)
288
303
  const _longSize = native.sizeof ? native.sizeof(CType.LONG) : 4;
289
304
 
@@ -408,6 +423,7 @@ export function createPrimitiveTypes(SimpleCData, native, addressOf, cstring, ws
408
423
  c_wchar_p,
409
424
  // Platform-specific
410
425
  c_size_t,
426
+ c_ssize_t,
411
427
  c_long,
412
428
  c_ulong,
413
429
  // Python-compatible aliases
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-ctypes",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "Python ctypes-like FFI for Node.js using libffi",
5
5
  "author": "Damiano Mazzella",
6
6
  "license": "MIT",