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 +15 -3
- 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.d.ts +210 -16
- package/lib/index.js +24 -0
- package/lib/memory/pointer.js +33 -0
- package/lib/structures/helpers/struct.js +88 -0
- package/lib/structures/helpers/union.js +7 -0
- package/lib/types/primitives.js +16 -0
- package/package.json +1 -1
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]);
|
|
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
|
|
Binary file
|
|
Binary file
|
|
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); //
|
|
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
|
-
/**
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
1063
|
-
*
|
|
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
|
|
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]);
|
|
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 }):
|
|
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
|
package/lib/memory/pointer.js
CHANGED
|
@@ -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
|
package/lib/types/primitives.js
CHANGED
|
@@ -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
|