node-ctypes 0.1.4 → 0.1.5
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 +17 -10
- package/build/Release/ctypes-darwin-arm64.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 +152 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -94,7 +94,10 @@ print(p.x, p.y) # 10 20
|
|
|
94
94
|
import { CDLL, c_int, Structure } from 'node-ctypes';
|
|
95
95
|
|
|
96
96
|
// Traditional syntax (always available)
|
|
97
|
-
const libc = new CDLL("libc.so.6");
|
|
97
|
+
const libc = new CDLL("libc.so.6"); // Linux
|
|
98
|
+
// const libc = new CDLL('msvcrt.dll'); // Windows
|
|
99
|
+
// const libc = new CDLL('libc.dylib'); // macOS
|
|
100
|
+
|
|
98
101
|
const abs = libc.func("abs", c_int, [c_int]);
|
|
99
102
|
console.log(abs(-42)); // 42
|
|
100
103
|
|
|
@@ -142,7 +145,10 @@ const strlen = libc.func('strlen', c_size_t, [c_char_p]);
|
|
|
142
145
|
console.log(strlen('Hello')); // 5n (BigInt)
|
|
143
146
|
|
|
144
147
|
// Load libm for math functions
|
|
145
|
-
const libm = new CDLL('libm.so.6');
|
|
148
|
+
const libm = new CDLL('libm.so.6'); // Linux
|
|
149
|
+
// const libb = new CDLL('ucrtbase.dll'); // Windows
|
|
150
|
+
// const libm = new CDLL('libm.dylib'); // macOS
|
|
151
|
+
|
|
146
152
|
const sqrt = libm.func('sqrt', c_double, [c_double]);
|
|
147
153
|
console.log(sqrt(16.0)); // 4.0
|
|
148
154
|
```
|
|
@@ -271,7 +277,7 @@ const pkt = new Packet({
|
|
|
271
277
|
data: new Array(256).fill(0)
|
|
272
278
|
});
|
|
273
279
|
|
|
274
|
-
console.log(pkt.header); // [1, 2, 3, 4, 5, 6, 7, 8]
|
|
280
|
+
console.log(pkt.header.toString()); // [1, 2, 3, 4, 5, 6, 7, 8]
|
|
275
281
|
```
|
|
276
282
|
|
|
277
283
|
### Complex Nested Structures
|
|
@@ -332,6 +338,7 @@ console.log(img.pixels[1].color.value); // -16711936 (0xFF00FF00 as signed)
|
|
|
332
338
|
|
|
333
339
|
// Union nested in struct - direct property access!
|
|
334
340
|
img.pixels[0].color.rgb.g = 128; // Works correctly!
|
|
341
|
+
console.log(img.pixels[0].color.rgb.g); // 128
|
|
335
342
|
```
|
|
336
343
|
|
|
337
344
|
### Callbacks - JavaScript Functions in C
|
|
@@ -349,7 +356,7 @@ const compare = callback(
|
|
|
349
356
|
const bVal = readValue(b, c_int32);
|
|
350
357
|
return aVal - bVal;
|
|
351
358
|
},
|
|
352
|
-
|
|
359
|
+
c_int32, // return type
|
|
353
360
|
[c_void_p, c_void_p] // argument types: two pointers
|
|
354
361
|
);
|
|
355
362
|
|
|
@@ -388,16 +395,16 @@ const sprintf = libc.func('sprintf', c_int, [c_void_p, c_char_p]);
|
|
|
388
395
|
const buffer = Buffer.alloc(256);
|
|
389
396
|
|
|
390
397
|
// Pass extra arguments - automatically handled as variadic
|
|
391
|
-
sprintf(buffer,
|
|
398
|
+
sprintf(buffer, 'Hello %s!', 'World');
|
|
392
399
|
console.log(string_at(buffer)); // "Hello World!"
|
|
393
400
|
|
|
394
|
-
sprintf(buffer,
|
|
401
|
+
sprintf(buffer, 'Number: %d', 42);
|
|
395
402
|
console.log(string_at(buffer)); // "Number: 42"
|
|
396
403
|
|
|
397
|
-
sprintf(buffer,
|
|
404
|
+
sprintf(buffer, '%s: %d + %d = %d', 'Sum', 10, 20, 30);
|
|
398
405
|
console.log(string_at(buffer)); // "Sum: 10 + 20 = 30"
|
|
399
406
|
|
|
400
|
-
sprintf(buffer,
|
|
407
|
+
sprintf(buffer, 'Pi ≈ %.2f', 3.14159);
|
|
401
408
|
console.log(string_at(buffer)); // "Pi ≈ 3.14"
|
|
402
409
|
```
|
|
403
410
|
|
|
@@ -713,8 +720,8 @@ Base class for Python-like union definitions. Subclasses should define `static _
|
|
|
713
720
|
| **Arrays** | `c_int * 5` | `array(c_int, 5)` |
|
|
714
721
|
| **Bit fields** | `("flags", c_uint, 3)` | `bitfield(c_uint32, 3)` |
|
|
715
722
|
| **Callbacks** | `CFUNCTYPE(c_int, c_int)` | `callback(fn, c_int, [c_int])` |
|
|
716
|
-
| **Strings** | `c_char_p(b"hello")` | `create_string_buffer("hello")` |
|
|
717
|
-
| **Pointers** | `POINTER(c_int)` | `c_void_p`
|
|
723
|
+
| **Strings** | `c_char_p(b"hello")` | `create_string_buffer("hello")`<br>**or**<br>`c_char_p(b"hello")` |
|
|
724
|
+
| **Pointers** | `POINTER(c_int)` | `c_void_p` |
|
|
718
725
|
| **Variadic** | `sprintf(buf, b"%d", 42)` | `sprintf(buf, fmt, 42)` (auto) |
|
|
719
726
|
| **Sizeof** | `sizeof(c_int)` | `sizeof(c_int)` |
|
|
720
727
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/lib/index.js
CHANGED
|
@@ -454,8 +454,23 @@ function cstring(str) {
|
|
|
454
454
|
* @returns {Buffer} Buffer con stringa wide
|
|
455
455
|
*/
|
|
456
456
|
function wstring(str) {
|
|
457
|
-
//
|
|
458
|
-
|
|
457
|
+
// Crea un buffer contenente la stringa wide null-terminata
|
|
458
|
+
// Su Windows wchar_t è 2 bytes (UTF-16LE), su Unix è 4 bytes (UTF-32LE)
|
|
459
|
+
const wcharSize = native.WCHAR_SIZE;
|
|
460
|
+
if (wcharSize === 2) {
|
|
461
|
+
return Buffer.from(str + "\0", "utf16le");
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Costruisci manualmente UTF-32LE
|
|
465
|
+
const codePoints = [];
|
|
466
|
+
for (const ch of str) {
|
|
467
|
+
codePoints.push(ch.codePointAt(0));
|
|
468
|
+
}
|
|
469
|
+
const buf = Buffer.alloc((codePoints.length + 1) * 4);
|
|
470
|
+
for (let i = 0; i < codePoints.length; i++) {
|
|
471
|
+
buf.writeUInt32LE(codePoints[i], i * 4);
|
|
472
|
+
}
|
|
473
|
+
// terminatore 0 già inizializzato
|
|
459
474
|
return buf;
|
|
460
475
|
}
|
|
461
476
|
|
|
@@ -825,12 +840,28 @@ function union(fields) {
|
|
|
825
840
|
let size, alignment;
|
|
826
841
|
let fieldDef = { name, type, offset: 0 };
|
|
827
842
|
|
|
828
|
-
// Nested struct
|
|
843
|
+
// Nested struct (object form)
|
|
829
844
|
if (_isStruct(type)) {
|
|
830
845
|
size = type.size;
|
|
831
846
|
alignment = type.alignment;
|
|
832
847
|
fieldDef.isNested = true;
|
|
833
848
|
}
|
|
849
|
+
// Struct class (declarata come `class X extends Structure`)
|
|
850
|
+
else if (typeof type === "function" && type.prototype instanceof Structure) {
|
|
851
|
+
const nested = type._structDef || type._buildStruct();
|
|
852
|
+
size = nested.size;
|
|
853
|
+
alignment = nested.alignment;
|
|
854
|
+
fieldDef.type = nested;
|
|
855
|
+
fieldDef.isNested = true;
|
|
856
|
+
}
|
|
857
|
+
// Union class (declarata come `class X extends Union`)
|
|
858
|
+
else if (typeof type === "function" && type.prototype instanceof Union) {
|
|
859
|
+
const nested = type._unionDef || type._buildUnion();
|
|
860
|
+
size = nested.size;
|
|
861
|
+
alignment = nested.alignment;
|
|
862
|
+
fieldDef.type = nested;
|
|
863
|
+
fieldDef.isNested = true;
|
|
864
|
+
}
|
|
834
865
|
// Array type
|
|
835
866
|
else if (_isArrayType(type)) {
|
|
836
867
|
size = type.getSize();
|
|
@@ -1520,24 +1551,31 @@ class Union extends Structure {
|
|
|
1520
1551
|
* console.log(arr[2]); // 42
|
|
1521
1552
|
*/
|
|
1522
1553
|
function array(elementType, count) {
|
|
1523
|
-
// Validate elementType
|
|
1524
|
-
|
|
1525
|
-
|
|
1554
|
+
// Validate elementType: accept SimpleCData classes, Structure/Union classes,
|
|
1555
|
+
// or native CType-like objects.
|
|
1556
|
+
const isSimple = typeof elementType === "function" && elementType._isSimpleCData;
|
|
1557
|
+
const isStruct = typeof elementType === "function" && (elementType.prototype instanceof Structure || elementType.prototype instanceof Union);
|
|
1558
|
+
const isNativeTypeObj = typeof elementType === "object" && elementType !== null && (typeof elementType.getSize === "function" || elementType.size !== undefined);
|
|
1559
|
+
if (!isSimple && !isStruct && !isNativeTypeObj) {
|
|
1560
|
+
throw new TypeError("array elementType must be a SimpleCData class or a Structure/Union class");
|
|
1526
1561
|
}
|
|
1527
1562
|
|
|
1528
|
-
const elementSize = elementType
|
|
1563
|
+
const elementSize = sizeof(elementType);
|
|
1529
1564
|
let nativeArray;
|
|
1530
|
-
if (
|
|
1565
|
+
if (isNativeTypeObj) {
|
|
1531
1566
|
nativeArray = new ArrayType(elementType, count);
|
|
1532
1567
|
} else {
|
|
1533
|
-
//
|
|
1568
|
+
// Provide a small JS-side shim implementing the minimal ArrayType API
|
|
1534
1569
|
nativeArray = {
|
|
1535
1570
|
getSize: () => count * elementSize,
|
|
1536
1571
|
getLength: () => count,
|
|
1537
|
-
getAlignment: () => elementSize,
|
|
1572
|
+
getAlignment: () => elementSize,
|
|
1538
1573
|
create: (values) => {
|
|
1539
|
-
//
|
|
1540
|
-
|
|
1574
|
+
// JS create is implemented below; this should not be invoked by JS code
|
|
1575
|
+
const size = count * elementSize;
|
|
1576
|
+
const buffer = alloc(size);
|
|
1577
|
+
buffer.fill(0);
|
|
1578
|
+
return buffer;
|
|
1541
1579
|
},
|
|
1542
1580
|
};
|
|
1543
1581
|
}
|
|
@@ -1567,7 +1605,13 @@ function array(elementType, count) {
|
|
|
1567
1605
|
if (prop === Symbol.iterator) {
|
|
1568
1606
|
return function* () {
|
|
1569
1607
|
for (let i = 0; i < count; i++) {
|
|
1570
|
-
|
|
1608
|
+
const off = i * elementSize;
|
|
1609
|
+
// If elementType is a struct/union class, return an instance bound to the slice
|
|
1610
|
+
if (typeof elementType === "function" && (elementType.prototype instanceof Structure || elementType.prototype instanceof Union)) {
|
|
1611
|
+
yield new elementType(target.subarray(off, off + elementSize));
|
|
1612
|
+
} else {
|
|
1613
|
+
yield readValue(target, elementType, off);
|
|
1614
|
+
}
|
|
1571
1615
|
}
|
|
1572
1616
|
};
|
|
1573
1617
|
}
|
|
@@ -1585,7 +1629,11 @@ function array(elementType, count) {
|
|
|
1585
1629
|
const index = Number(prop);
|
|
1586
1630
|
if (Number.isInteger(index) && !isNaN(index)) {
|
|
1587
1631
|
if (index >= 0 && index < count) {
|
|
1588
|
-
|
|
1632
|
+
const off = index * elementSize;
|
|
1633
|
+
if (typeof elementType === "function" && (elementType.prototype instanceof Structure || elementType.prototype instanceof Union)) {
|
|
1634
|
+
return new elementType(target.subarray(off, off + elementSize));
|
|
1635
|
+
}
|
|
1636
|
+
return readValue(target, elementType, off);
|
|
1589
1637
|
}
|
|
1590
1638
|
// Indice numerico fuori bounds -> undefined (comportamento JavaScript)
|
|
1591
1639
|
return undefined;
|
|
@@ -2066,6 +2114,66 @@ function struct(fields, options = {}) {
|
|
|
2066
2114
|
maxAlignment = alignment;
|
|
2067
2115
|
}
|
|
2068
2116
|
}
|
|
2117
|
+
// Caso 2a: Struct class (declarata come `class X extends Structure`)
|
|
2118
|
+
else if (typeof type === "function" && type.prototype instanceof Structure) {
|
|
2119
|
+
// Reset bit field state
|
|
2120
|
+
currentBitFieldBase = null;
|
|
2121
|
+
currentBitOffset = 0;
|
|
2122
|
+
|
|
2123
|
+
const nestedStruct = type._structDef || type._buildStruct();
|
|
2124
|
+
const size = nestedStruct.size;
|
|
2125
|
+
const alignment = packed ? 1 : nestedStruct.alignment;
|
|
2126
|
+
|
|
2127
|
+
// Applica padding per allineamento
|
|
2128
|
+
if (!packed && totalSize % alignment !== 0) {
|
|
2129
|
+
totalSize += alignment - (totalSize % alignment);
|
|
2130
|
+
}
|
|
2131
|
+
|
|
2132
|
+
fieldDef = {
|
|
2133
|
+
name,
|
|
2134
|
+
type: nestedStruct,
|
|
2135
|
+
offset: totalSize,
|
|
2136
|
+
size,
|
|
2137
|
+
alignment,
|
|
2138
|
+
isNested: true,
|
|
2139
|
+
};
|
|
2140
|
+
|
|
2141
|
+
totalSize += size;
|
|
2142
|
+
|
|
2143
|
+
if (alignment > maxAlignment) {
|
|
2144
|
+
maxAlignment = alignment;
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
// Caso 2b: Union class (declarata come `class X extends Union`)
|
|
2148
|
+
else if (typeof type === "function" && type.prototype instanceof Union) {
|
|
2149
|
+
// Reset bit field state
|
|
2150
|
+
currentBitFieldBase = null;
|
|
2151
|
+
currentBitOffset = 0;
|
|
2152
|
+
|
|
2153
|
+
const nestedUnion = type._unionDef || type._buildUnion();
|
|
2154
|
+
const size = nestedUnion.size;
|
|
2155
|
+
const alignment = packed ? 1 : nestedUnion.alignment;
|
|
2156
|
+
|
|
2157
|
+
// Applica padding per allineamento
|
|
2158
|
+
if (!packed && totalSize % alignment !== 0) {
|
|
2159
|
+
totalSize += alignment - (totalSize % alignment);
|
|
2160
|
+
}
|
|
2161
|
+
|
|
2162
|
+
fieldDef = {
|
|
2163
|
+
name,
|
|
2164
|
+
type: nestedUnion,
|
|
2165
|
+
offset: totalSize,
|
|
2166
|
+
size,
|
|
2167
|
+
alignment,
|
|
2168
|
+
isNested: true,
|
|
2169
|
+
};
|
|
2170
|
+
|
|
2171
|
+
totalSize += size;
|
|
2172
|
+
|
|
2173
|
+
if (alignment > maxAlignment) {
|
|
2174
|
+
maxAlignment = alignment;
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2069
2177
|
// Caso 2: Nested struct
|
|
2070
2178
|
else if (_isStruct(type)) {
|
|
2071
2179
|
// Reset bit field state
|
|
@@ -2875,7 +2983,10 @@ class c_int32 extends SimpleCData {
|
|
|
2875
2983
|
static _size = 4;
|
|
2876
2984
|
static _type = "int32";
|
|
2877
2985
|
static _reader = (buf, off) => buf.readInt32LE(off);
|
|
2878
|
-
static _writer = (buf, off, val) =>
|
|
2986
|
+
static _writer = (buf, off, val) => {
|
|
2987
|
+
const v = Number(val) | 0; // coerce to signed 32-bit
|
|
2988
|
+
return buf.writeInt32LE(v, off);
|
|
2989
|
+
};
|
|
2879
2990
|
}
|
|
2880
2991
|
|
|
2881
2992
|
class c_int64 extends SimpleCData {
|
|
@@ -2989,7 +3100,11 @@ class c_wchar extends SimpleCData {
|
|
|
2989
3100
|
class c_void_p extends SimpleCData {
|
|
2990
3101
|
static _size = native.POINTER_SIZE;
|
|
2991
3102
|
static _type = "pointer";
|
|
2992
|
-
static _reader = (buf, off) =>
|
|
3103
|
+
static _reader = (buf, off) => {
|
|
3104
|
+
const ptr = native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(off) : BigInt(buf.readUInt32LE(off));
|
|
3105
|
+
if (!ptr) return null;
|
|
3106
|
+
return ptr;
|
|
3107
|
+
};
|
|
2993
3108
|
static _writer = (buf, off, val) => {
|
|
2994
3109
|
// Accept Buffers (pointer to memory) and struct proxies with _buffer
|
|
2995
3110
|
if (Buffer.isBuffer(val)) {
|
|
@@ -3020,7 +3135,11 @@ class c_void_p extends SimpleCData {
|
|
|
3020
3135
|
class c_size_t extends SimpleCData {
|
|
3021
3136
|
static _size = native.POINTER_SIZE;
|
|
3022
3137
|
static _type = "size_t";
|
|
3023
|
-
static _reader = (buf, off) =>
|
|
3138
|
+
static _reader = (buf, off) => {
|
|
3139
|
+
const ptr = native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(off) : BigInt(buf.readUInt32LE(off));
|
|
3140
|
+
if (!ptr) return null;
|
|
3141
|
+
return ptr;
|
|
3142
|
+
};
|
|
3024
3143
|
static _writer = (buf, off, val) => {
|
|
3025
3144
|
const v = typeof val === "bigint" ? val : BigInt(val || 0);
|
|
3026
3145
|
if (native.POINTER_SIZE === 8) {
|
|
@@ -3058,8 +3177,15 @@ class c_ulong extends SimpleCData {
|
|
|
3058
3177
|
class c_char_p extends SimpleCData {
|
|
3059
3178
|
static _size = native.POINTER_SIZE;
|
|
3060
3179
|
static _type = "char_p";
|
|
3061
|
-
static _reader = (buf, off) =>
|
|
3180
|
+
static _reader = (buf, off) => {
|
|
3181
|
+
const ptr = native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(off) : BigInt(buf.readUInt32LE(off));
|
|
3182
|
+
if (!ptr) return null;
|
|
3183
|
+
return readCString(ptr);
|
|
3184
|
+
};
|
|
3062
3185
|
static _writer = (buf, off, val) => {
|
|
3186
|
+
if (typeof val === "string") {
|
|
3187
|
+
val = cstring(val);
|
|
3188
|
+
}
|
|
3063
3189
|
if (Buffer.isBuffer(val)) {
|
|
3064
3190
|
const addr = addressOf(val);
|
|
3065
3191
|
const v = typeof addr === "bigint" ? addr : BigInt(addr || 0);
|
|
@@ -3082,8 +3208,15 @@ class c_char_p extends SimpleCData {
|
|
|
3082
3208
|
class c_wchar_p extends SimpleCData {
|
|
3083
3209
|
static _size = native.POINTER_SIZE;
|
|
3084
3210
|
static _type = "wchar_p";
|
|
3085
|
-
static _reader = (buf, off) =>
|
|
3211
|
+
static _reader = (buf, off) => {
|
|
3212
|
+
const ptr = native.POINTER_SIZE === 8 ? buf.readBigUInt64LE(off) : BigInt(buf.readUInt32LE(off));
|
|
3213
|
+
if (!ptr) return null;
|
|
3214
|
+
return readWString(ptr);
|
|
3215
|
+
};
|
|
3086
3216
|
static _writer = (buf, off, val) => {
|
|
3217
|
+
if (typeof val === "string") {
|
|
3218
|
+
val = wstring(val);
|
|
3219
|
+
}
|
|
3087
3220
|
if (Buffer.isBuffer(val)) {
|
|
3088
3221
|
const addr = addressOf(val);
|
|
3089
3222
|
const v = typeof addr === "bigint" ? addr : BigInt(addr || 0);
|