node-ctypes 0.1.5 → 1.0.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.

@@ -0,0 +1,358 @@
1
+ /**
2
+ * @file pointer.js
3
+ * @module memory/pointer
4
+ * @description Pointer manipulation and address operations for C interoperability.
5
+ *
6
+ * This module provides Python ctypes-compatible functions for working with pointers,
7
+ * addresses, and pointer types. It handles pointer creation, dereferencing, casting,
8
+ * and address operations.
9
+ *
10
+ * **Python ctypes Compatibility**:
11
+ * - `addressOf()` ≈ Python's `ctypes.addressof()`
12
+ * - `byref()` ≈ Python's `ctypes.byref()`
13
+ * - `cast()` ≈ Python's `ctypes.cast()`
14
+ * - `POINTER()` ≈ Python's `ctypes.POINTER()`
15
+ *
16
+ * @example Basic pointer operations
17
+ * ```javascript
18
+ * import { addressOf, byref, cast, POINTER, c_int32 } from 'node-ctypes';
19
+ *
20
+ * const buf = Buffer.alloc(4);
21
+ * const addr = addressOf(buf); // Get buffer address
22
+ * const ref = byref(buf); // Pass by reference
23
+ *
24
+ * const IntPtr = POINTER(c_int32); // Create pointer type
25
+ * const ptr = IntPtr.create(); // NULL pointer
26
+ * ```
27
+ */
28
+
29
+ /**
30
+ * Gets the memory address of a buffer or pointer.
31
+ *
32
+ * **Python ctypes Compatibility**:
33
+ * Direct equivalent to Python's `ctypes.addressof()`.
34
+ *
35
+ * @param {Buffer|bigint|number} ptr - Buffer or address to get address of
36
+ * @param {Function} alloc - alloc function reference
37
+ * @param {Object} native - Native module reference
38
+ * @returns {bigint} Memory address as BigInt
39
+ *
40
+ * @example Get buffer address
41
+ * ```javascript
42
+ * import { addressOf } from 'node-ctypes';
43
+ *
44
+ * const buf = Buffer.alloc(64);
45
+ * const addr = addressOf(buf);
46
+ * console.log(addr); // 0x7f8e4c000000n (example address)
47
+ * ```
48
+ *
49
+ * @example Address of SimpleCData instance
50
+ * ```javascript
51
+ * const val = new c_int32(42);
52
+ * const addr = addressOf(val._buffer);
53
+ * ```
54
+ */
55
+ export function addressOf(ptr, alloc, native) {
56
+ if (Buffer.isBuffer(ptr)) {
57
+ // Get the buffer's memory address
58
+ const tempBuf = alloc(native.POINTER_SIZE);
59
+ // Use native.writeValue with string 'pointer' to avoid JS-level recursion
60
+ native.writeValue(tempBuf, "pointer", ptr, 0);
61
+ if (native.POINTER_SIZE === 8) return tempBuf.readBigUInt64LE(0);
62
+ return BigInt(tempBuf.readUInt32LE(0));
63
+ }
64
+ if (typeof ptr === "bigint") {
65
+ return ptr;
66
+ }
67
+ return BigInt(ptr);
68
+ }
69
+
70
+ /**
71
+ * Passes an object by reference (Python byref equivalent).
72
+ *
73
+ * Returns the underlying buffer of a SimpleCData instance or the buffer itself.
74
+ * This is useful for passing arguments to C functions that expect pointers.
75
+ *
76
+ * **Python ctypes Compatibility**:
77
+ * Direct equivalent to Python's `ctypes.byref()`. Used to pass arguments by
78
+ * reference without creating a full POINTER() type.
79
+ *
80
+ * @param {Buffer|Object} obj - Object to pass by reference
81
+ * - SimpleCData instance (has _buffer property)
82
+ * - Buffer object
83
+ * - Structure instance (has _buffer property)
84
+ * @returns {Buffer} The underlying buffer
85
+ * @throws {TypeError} If obj is not a ctypes instance or Buffer
86
+ *
87
+ * @example Pass SimpleCData by reference
88
+ * ```javascript
89
+ * import { byref, c_int32, CDLL } from 'node-ctypes';
90
+ *
91
+ * const libc = new CDLL(null);
92
+ * const value = new c_int32(0);
93
+ *
94
+ * // C function: void get_value(int *out);
95
+ * const get_value = libc.func('get_value', c_void, [c_void_p]);
96
+ * get_value(byref(value));
97
+ *
98
+ * console.log(value.value); // Value set by C function
99
+ * ```
100
+ *
101
+ * @example Pass struct by reference
102
+ * ```javascript
103
+ * class Point extends Structure {
104
+ * static _fields_ = [['x', c_int32], ['y', c_int32]];
105
+ * }
106
+ *
107
+ * const point = Point.create({ x: 10, y: 20 });
108
+ *
109
+ * // C function: void move_point(Point *p, int dx, int dy);
110
+ * const move_point = libc.func('move_point', c_void, [c_void_p, c_int32, c_int32]);
111
+ * move_point(byref(point), 5, 10);
112
+ * ```
113
+ */
114
+ export function byref(obj) {
115
+ // SimpleCData instance or Structure instance - return its buffer
116
+ if (obj && obj._buffer && Buffer.isBuffer(obj._buffer)) {
117
+ return obj._buffer;
118
+ }
119
+ // Buffer - return as-is
120
+ if (Buffer.isBuffer(obj)) {
121
+ return obj;
122
+ }
123
+ throw new TypeError("byref() argument must be a ctypes instance or Buffer");
124
+ }
125
+
126
+ /**
127
+ * Casts a pointer to a different type.
128
+ *
129
+ * Interprets the memory at the pointer location as a different type.
130
+ * This is a low-level operation that should be used with caution.
131
+ *
132
+ * **Python ctypes Compatibility**:
133
+ * Direct equivalent to Python's `ctypes.cast()`.
134
+ *
135
+ * @param {Buffer|bigint} ptr - Source pointer
136
+ * @param {Function|Object} targetType - Target type (SimpleCData class or struct def)
137
+ * @param {Function} readValue - readValue function reference
138
+ * @param {Function} sizeof - sizeof function reference
139
+ * @param {Function} ptrToBuffer - ptrToBuffer function reference
140
+ * @returns {*} Value read as target type, or wrapper object for structs
141
+ * @throws {TypeError} If ptr or targetType is invalid
142
+ *
143
+ * @example Cast pointer to different primitive type
144
+ * ```javascript
145
+ * import { cast, c_int32, c_float } from 'node-ctypes';
146
+ *
147
+ * const buf = Buffer.from([0x00, 0x00, 0x80, 0x3F]); // 1.0 as float
148
+ * const int_val = cast(buf, c_int32); // Read as int32
149
+ * const float_val = cast(buf, c_float); // Read as float
150
+ * console.log(int_val); // 1065353216
151
+ * console.log(float_val); // 1.0
152
+ * ```
153
+ *
154
+ * @example Cast to struct
155
+ * ```javascript
156
+ * class Header extends Structure {
157
+ * static _fields_ = [
158
+ * ['magic', c_uint32],
159
+ * ['version', c_uint32]
160
+ * ];
161
+ * }
162
+ *
163
+ * const buf = Buffer.from([0x4D, 0x5A, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00]);
164
+ * const header = cast(buf, Header._structDef);
165
+ * console.log(header.contents); // { magic: 23117, version: 1 }
166
+ * ```
167
+ */
168
+ export function cast(ptr, targetType, readValue, sizeof, ptrToBuffer) {
169
+ // Validate inputs
170
+ if (!ptr) {
171
+ throw new TypeError("cast() requires a non-null pointer");
172
+ }
173
+ if (!targetType) {
174
+ throw new TypeError("cast() requires a target type");
175
+ }
176
+
177
+ // Struct type - return wrapper object
178
+ if (typeof targetType === "object" && targetType.size !== undefined) {
179
+ const buf = Buffer.isBuffer(ptr) ? ptr : ptrToBuffer(ptr, targetType.size);
180
+ return {
181
+ _buffer: buf,
182
+ _struct: targetType,
183
+ get contents() {
184
+ return targetType.toObject(buf);
185
+ },
186
+ getField(name) {
187
+ return targetType.get(buf, name);
188
+ },
189
+ setField(name, value) {
190
+ targetType.set(buf, name, value);
191
+ },
192
+ };
193
+ }
194
+
195
+ // Primitive type - read and return value
196
+ if (Buffer.isBuffer(ptr)) {
197
+ return readValue(ptr, targetType, 0);
198
+ }
199
+
200
+ // BigInt/number address - convert to buffer and read
201
+ const tempBuf = ptrToBuffer(ptr, sizeof(targetType));
202
+ return readValue(tempBuf, targetType, 0);
203
+ }
204
+
205
+ /**
206
+ * Creates a buffer backed by a specific memory address.
207
+ *
208
+ * **WARNING**: This is a low-level operation! Accessing invalid memory will
209
+ * crash the process. Only use with addresses from trusted sources (FFI returns,
210
+ * addressOf, etc.).
211
+ *
212
+ * @param {bigint|number} address - Memory address
213
+ * @param {number} size - Size in bytes
214
+ * @param {Object} native - Native module reference
215
+ * @returns {Buffer} Buffer pointing to the address
216
+ *
217
+ * @example Read C string from pointer
218
+ * ```javascript
219
+ * import { ptrToBuffer } from 'node-ctypes';
220
+ *
221
+ * // Got pointer from C function
222
+ * const str_ptr = some_c_function(); // Returns pointer
223
+ * const buf = ptrToBuffer(str_ptr, 256);
224
+ * const str = buf.toString('utf8');
225
+ * ```
226
+ *
227
+ * @example Access struct at address
228
+ * ```javascript
229
+ * const addr = get_struct_ptr(); // From C
230
+ * const buf = ptrToBuffer(addr, sizeof(MyStruct));
231
+ * const struct_data = MyStruct.toObject(buf);
232
+ * ```
233
+ */
234
+ export function ptrToBuffer(address, size, native) {
235
+ return native.ptrToBuffer(address, size);
236
+ }
237
+
238
+ /**
239
+ * Creates a POINTER type for a base type.
240
+ *
241
+ * **Python ctypes Compatibility**:
242
+ * Direct equivalent to Python's `ctypes.POINTER()`.
243
+ *
244
+ * Returns a type definition object with methods to create, dereference, and
245
+ * manipulate pointers to the specified base type.
246
+ *
247
+ * @param {Function|Object} baseType - Type to create pointer for
248
+ * @param {Function} sizeof - sizeof function reference
249
+ * @param {Function} alloc - alloc function reference
250
+ * @param {Function} readValue - readValue function reference
251
+ * @param {Function} writeValue - writeValue function reference
252
+ * @param {Function} c_void_p - c_void_p type reference
253
+ * @param {Object} native - Native module reference
254
+ * @returns {Object} Pointer type definition with methods
255
+ *
256
+ * @example Create pointer type and NULL pointer
257
+ * ```javascript
258
+ * import { POINTER, c_int32 } from 'node-ctypes';
259
+ *
260
+ * const IntPtr = POINTER(c_int32);
261
+ * const ptr = IntPtr.create(); // NULL pointer
262
+ * ```
263
+ *
264
+ * @example Create pointer to existing buffer
265
+ * ```javascript
266
+ * const value_buf = Buffer.from([0x2A, 0x00, 0x00, 0x00]); // 42
267
+ * const ptr = IntPtr.fromBuffer(value_buf);
268
+ * ```
269
+ *
270
+ * @example Dereference pointer
271
+ * ```javascript
272
+ * const addr = ptr_func(); // Get pointer from C function
273
+ * const IntPtr = POINTER(c_int32);
274
+ * const ptr_buf = Buffer.alloc(8);
275
+ * writeValue(ptr_buf, c_void_p, addr);
276
+ * const addr_value = IntPtr.deref(ptr_buf);
277
+ * ```
278
+ *
279
+ * @example Pointer to struct
280
+ * ```javascript
281
+ * class Point extends Structure {
282
+ * static _fields_ = [['x', c_int32], ['y', c_int32]];
283
+ * }
284
+ *
285
+ * const PointPtr = POINTER(Point._structDef);
286
+ * const ptr = PointPtr.create();
287
+ * ```
288
+ */
289
+ export function POINTER(baseType, sizeof, alloc, readValue, writeValue, c_void_p, native) {
290
+ const baseSize = typeof baseType === "object" ? baseType.size : sizeof(baseType);
291
+ const typeName = typeof baseType === "object" ? "struct" : baseType._type || "unknown";
292
+
293
+ return {
294
+ _pointerTo: baseType,
295
+ _baseSize: baseSize,
296
+ size: native.POINTER_SIZE,
297
+
298
+ /**
299
+ * Creates a NULL pointer.
300
+ * @returns {Buffer} Buffer containing NULL pointer
301
+ */
302
+ create() {
303
+ const buf = alloc(native.POINTER_SIZE);
304
+ writeValue(buf, c_void_p, 0n);
305
+ return buf;
306
+ },
307
+
308
+ /**
309
+ * Creates a pointer to an existing buffer.
310
+ * @param {Buffer} targetBuf - Target buffer to point to
311
+ * @returns {Buffer} Buffer containing pointer to targetBuf
312
+ */
313
+ fromBuffer(targetBuf) {
314
+ const buf = alloc(native.POINTER_SIZE);
315
+ writeValue(buf, c_void_p, targetBuf);
316
+ return buf;
317
+ },
318
+
319
+ /**
320
+ * Dereferences the pointer (reads the address it points to).
321
+ * @param {Buffer} ptrBuf - Buffer containing the pointer
322
+ * @returns {bigint|null} Address value, or null if NULL pointer
323
+ */
324
+ deref(ptrBuf) {
325
+ const addr = readValue(ptrBuf, c_void_p);
326
+ if (addr === 0n || addr === null) {
327
+ return null;
328
+ }
329
+ // For struct types, return address (can't safely create buffer without native support)
330
+ if (typeof baseType === "object" && baseType.toObject) {
331
+ return addr;
332
+ }
333
+ // For primitive types, return address
334
+ return addr;
335
+ },
336
+
337
+ /**
338
+ * Sets the pointer to point to a value or buffer.
339
+ * @param {Buffer} ptrBuf - Buffer containing the pointer
340
+ * @param {Buffer|bigint|number} value - Value to set (buffer or address)
341
+ */
342
+ set(ptrBuf, value) {
343
+ if (Buffer.isBuffer(value)) {
344
+ writeValue(ptrBuf, c_void_p, value);
345
+ } else {
346
+ writeValue(ptrBuf, c_void_p, value);
347
+ }
348
+ },
349
+
350
+ /**
351
+ * Returns string representation of pointer type.
352
+ * @returns {string} Type name
353
+ */
354
+ toString() {
355
+ return `POINTER(${typeName})`;
356
+ },
357
+ };
358
+ }
@@ -0,0 +1,110 @@
1
+ /**
2
+ * @file constants.js
3
+ * @module platform/constants
4
+ * @description Platform-specific constants exported from the native module.
5
+ * These values are determined at compile-time based on the target platform and architecture.
6
+ *
7
+ * @example
8
+ * import { POINTER_SIZE, WCHAR_SIZE, NULL } from './platform/constants.js';
9
+ *
10
+ * console.log(`Pointer size: ${POINTER_SIZE} bytes`);
11
+ * console.log(`Wide char size: ${WCHAR_SIZE} bytes`);
12
+ */
13
+
14
+ import { createRequire } from "node:module";
15
+ import path from "node:path";
16
+
17
+ /**
18
+ * Get the path to the native module
19
+ * @private
20
+ */
21
+ function getNativeModule() {
22
+ // This will be replaced by the actual native module loading logic from index.js
23
+ // For now, we assume the native module is already loaded in the parent
24
+ // In the refactored version, this should import from a shared native module loader
25
+ throw new Error("This module should be imported through index.js");
26
+ }
27
+
28
+ /**
29
+ * Size of a pointer in bytes on the current platform.
30
+ *
31
+ * - **32-bit systems**: 4 bytes
32
+ * - **64-bit systems**: 8 bytes
33
+ *
34
+ * This constant is determined at compile-time based on `sizeof(void*)` in C.
35
+ *
36
+ * @constant {number} POINTER_SIZE
37
+ * @example
38
+ * import { POINTER_SIZE } from 'node-ctypes';
39
+ *
40
+ * console.log(`Running on ${POINTER_SIZE * 8}-bit architecture`);
41
+ * // Output: "Running on 64-bit architecture" (on 64-bit systems)
42
+ *
43
+ * @example
44
+ * // Allocate buffer for pointer
45
+ * const ptrBuf = Buffer.alloc(POINTER_SIZE);
46
+ */
47
+ export let POINTER_SIZE;
48
+
49
+ /**
50
+ * Size of wchar_t in bytes on the current platform.
51
+ *
52
+ * - **Windows**: 2 bytes (UTF-16LE)
53
+ * - **Unix/Linux/macOS**: 4 bytes (UTF-32LE)
54
+ *
55
+ * This constant is determined at compile-time based on `sizeof(wchar_t)` in C.
56
+ * The difference affects how wide strings are encoded and decoded.
57
+ *
58
+ * @constant {number} WCHAR_SIZE
59
+ * @example
60
+ * import { WCHAR_SIZE } from 'node-ctypes';
61
+ *
62
+ * if (WCHAR_SIZE === 2) {
63
+ * console.log('Windows platform detected (UTF-16LE wide strings)');
64
+ * } else {
65
+ * console.log('Unix-like platform detected (UTF-32LE wide strings)');
66
+ * }
67
+ *
68
+ * @example
69
+ * // Allocate buffer for wide string (10 characters)
70
+ * const wcharBuf = Buffer.alloc(10 * WCHAR_SIZE);
71
+ */
72
+ export let WCHAR_SIZE;
73
+
74
+ /**
75
+ * Null pointer constant (JavaScript `null`).
76
+ *
77
+ * Represents a NULL pointer in C. This is provided for Python ctypes compatibility,
78
+ * where `None` is used to represent NULL pointers.
79
+ *
80
+ * @constant {null} NULL
81
+ * @example
82
+ * import { NULL, c_void_p } from 'node-ctypes';
83
+ *
84
+ * // Create a NULL pointer
85
+ * const nullPtr = new c_void_p(NULL);
86
+ * console.log(nullPtr.value); // 0n (BigInt zero)
87
+ *
88
+ * @example
89
+ * // Check for NULL pointer
90
+ * function processPointer(ptr) {
91
+ * if (ptr === NULL) {
92
+ * throw new Error('NULL pointer provided');
93
+ * }
94
+ * // ... process pointer
95
+ * }
96
+ */
97
+ export const NULL = null;
98
+
99
+ /**
100
+ * Initialize constants from native module.
101
+ * This function is called internally by index.js after loading the native module.
102
+ *
103
+ * @param {Object} native - The native module object
104
+ * @private
105
+ * @internal
106
+ */
107
+ export function _initConstants(native) {
108
+ POINTER_SIZE = native.POINTER_SIZE;
109
+ WCHAR_SIZE = native.WCHAR_SIZE;
110
+ }