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.
- package/README.md +14 -9
- 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/core/Library.js +312 -0
- package/lib/core/callback.js +275 -0
- package/lib/core/types.js +140 -0
- package/lib/index.d.ts +71 -124
- package/lib/index.js +215 -3096
- package/lib/memory/buffer.js +404 -0
- package/lib/memory/operations.js +295 -0
- package/lib/memory/pointer.js +358 -0
- package/lib/platform/constants.js +110 -0
- package/lib/platform/errors.js +403 -0
- package/lib/structures/Structure.js +414 -0
- package/lib/structures/Union.js +102 -0
- package/lib/structures/helpers/array.js +261 -0
- package/lib/structures/helpers/bitfield.js +147 -0
- package/lib/structures/helpers/common.js +129 -0
- package/lib/structures/helpers/struct.js +925 -0
- package/lib/structures/helpers/union.js +465 -0
- package/lib/types/SimpleCData.js +193 -0
- package/lib/types/primitives.js +392 -0
- package/lib/utils/cache.js +142 -0
- package/package.json +1 -1
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file buffer.js
|
|
3
|
+
* @module memory/buffer
|
|
4
|
+
* @description Buffer creation and string handling functions for C interoperability.
|
|
5
|
+
*
|
|
6
|
+
* This module provides Python ctypes-compatible functions for creating and managing
|
|
7
|
+
* buffers, C strings, and wide strings. It handles platform-specific differences in
|
|
8
|
+
* character encoding (UTF-16LE on Windows, UTF-32LE on Unix).
|
|
9
|
+
*
|
|
10
|
+
* **Python ctypes Compatibility**:
|
|
11
|
+
* - `create_string_buffer()` ≈ Python's `ctypes.create_string_buffer()`
|
|
12
|
+
* - `create_unicode_buffer()` ≈ Python's `ctypes.create_unicode_buffer()`
|
|
13
|
+
* - `string_at()` ≈ Python's `ctypes.string_at()`
|
|
14
|
+
* - `wstring_at()` ≈ Python's `ctypes.wstring_at()`
|
|
15
|
+
*
|
|
16
|
+
* @example Basic buffer operations
|
|
17
|
+
* ```javascript
|
|
18
|
+
* import { create_string_buffer, create_unicode_buffer } from 'node-ctypes';
|
|
19
|
+
*
|
|
20
|
+
* // Create C string buffer
|
|
21
|
+
* const buf1 = create_string_buffer(64); // 64-byte buffer
|
|
22
|
+
* const buf2 = create_string_buffer("Hello"); // Buffer with string
|
|
23
|
+
*
|
|
24
|
+
* // Create wide string buffer
|
|
25
|
+
* const wbuf1 = create_unicode_buffer(32); // 32 wchar_t buffer
|
|
26
|
+
* const wbuf2 = create_unicode_buffer("Hello"); // Wide string buffer
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Allocates a zero-initialized buffer of the specified size.
|
|
32
|
+
*
|
|
33
|
+
* This is a simple wrapper around `Buffer.alloc()` for consistency with
|
|
34
|
+
* the ctypes API. All bytes are initialized to zero.
|
|
35
|
+
*
|
|
36
|
+
* @param {number} size - Size in bytes to allocate
|
|
37
|
+
* @returns {Buffer} Zero-initialized buffer
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```javascript
|
|
41
|
+
* import { alloc } from 'node-ctypes';
|
|
42
|
+
*
|
|
43
|
+
* const buf = alloc(256); // 256-byte zero-filled buffer
|
|
44
|
+
* console.log(buf[0]); // 0
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export function alloc(size) {
|
|
48
|
+
return Buffer.alloc(size);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Creates a buffer containing a null-terminated C string.
|
|
53
|
+
*
|
|
54
|
+
* The resulting buffer is compatible with C `char*` strings and includes
|
|
55
|
+
* the null terminator.
|
|
56
|
+
*
|
|
57
|
+
* **Platform Notes**:
|
|
58
|
+
* - Uses the native module's cstring implementation
|
|
59
|
+
* - Automatically adds null terminator
|
|
60
|
+
* - Encoding is UTF-8 (standard for C strings)
|
|
61
|
+
*
|
|
62
|
+
* @param {string} str - JavaScript string to convert
|
|
63
|
+
* @param {Object} native - Native module reference
|
|
64
|
+
* @returns {Buffer} Buffer containing null-terminated C string
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```javascript
|
|
68
|
+
* import { cstring } from 'node-ctypes';
|
|
69
|
+
*
|
|
70
|
+
* const buf = cstring("Hello, World!");
|
|
71
|
+
* // Buffer: [72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33, 0]
|
|
72
|
+
* // H e l l o , ' ' W o r l d ! \0
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export function cstring(str, native) {
|
|
76
|
+
return native.cstring(str);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Creates a buffer containing a null-terminated wide string (wchar_t*).
|
|
81
|
+
*
|
|
82
|
+
* **Platform-Specific Behavior**:
|
|
83
|
+
* - **Windows**: 2 bytes per character (UTF-16LE)
|
|
84
|
+
* - **Unix/Linux/macOS**: 4 bytes per character (UTF-32LE)
|
|
85
|
+
*
|
|
86
|
+
* The function automatically detects the platform and encodes accordingly.
|
|
87
|
+
*
|
|
88
|
+
* **Python ctypes Compatibility**:
|
|
89
|
+
* Equivalent to creating a wide string in Python ctypes, handling the
|
|
90
|
+
* platform's native wchar_t representation.
|
|
91
|
+
*
|
|
92
|
+
* @param {string} str - JavaScript string to convert
|
|
93
|
+
* @param {Object} native - Native module reference (provides WCHAR_SIZE)
|
|
94
|
+
* @returns {Buffer} Buffer containing null-terminated wide string
|
|
95
|
+
*
|
|
96
|
+
* @example Windows (UTF-16LE)
|
|
97
|
+
* ```javascript
|
|
98
|
+
* import { wstring } from 'node-ctypes';
|
|
99
|
+
*
|
|
100
|
+
* // On Windows (WCHAR_SIZE = 2):
|
|
101
|
+
* const buf = wstring("Hi");
|
|
102
|
+
* // Buffer: [72, 0, 105, 0, 0, 0]
|
|
103
|
+
* // H i \0
|
|
104
|
+
* ```
|
|
105
|
+
*
|
|
106
|
+
* @example Unix (UTF-32LE)
|
|
107
|
+
* ```javascript
|
|
108
|
+
* // On Unix (WCHAR_SIZE = 4):
|
|
109
|
+
* const buf = wstring("Hi");
|
|
110
|
+
* // Buffer: [72, 0, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0]
|
|
111
|
+
* // H i \0
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
export function wstring(str, native) {
|
|
115
|
+
const wcharSize = native.WCHAR_SIZE;
|
|
116
|
+
|
|
117
|
+
// Windows: UTF-16LE (2 bytes per character)
|
|
118
|
+
if (wcharSize === 2) {
|
|
119
|
+
return Buffer.from(str + "\0", "utf16le");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Unix: UTF-32LE (4 bytes per character)
|
|
123
|
+
// Manually construct UTF-32LE buffer from code points
|
|
124
|
+
const codePoints = [];
|
|
125
|
+
for (const ch of str) {
|
|
126
|
+
codePoints.push(ch.codePointAt(0));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const buf = Buffer.alloc((codePoints.length + 1) * 4);
|
|
130
|
+
for (let i = 0; i < codePoints.length; i++) {
|
|
131
|
+
buf.writeUInt32LE(codePoints[i], i * 4);
|
|
132
|
+
}
|
|
133
|
+
// Null terminator already initialized (Buffer.alloc zeros memory)
|
|
134
|
+
|
|
135
|
+
return buf;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Creates a C string buffer (Python ctypes compatible).
|
|
140
|
+
*
|
|
141
|
+
* **Overloaded Function**:
|
|
142
|
+
* - `create_string_buffer(size)` - Allocates empty buffer of size bytes
|
|
143
|
+
* - `create_string_buffer(string)` - Creates buffer from string (with null terminator)
|
|
144
|
+
* - `create_string_buffer(bytes)` - Copies buffer and adds null terminator
|
|
145
|
+
*
|
|
146
|
+
* **Python ctypes Compatibility**:
|
|
147
|
+
* Direct equivalent to Python's `ctypes.create_string_buffer()`.
|
|
148
|
+
*
|
|
149
|
+
* @param {number|string|Buffer} init - Size, string, or buffer to copy
|
|
150
|
+
* @param {Object} native - Native module reference
|
|
151
|
+
* @returns {Buffer} Created buffer
|
|
152
|
+
* @throws {TypeError} If init is not number, string, or Buffer
|
|
153
|
+
*
|
|
154
|
+
* @example Empty buffer
|
|
155
|
+
* ```javascript
|
|
156
|
+
* import { create_string_buffer } from 'node-ctypes';
|
|
157
|
+
*
|
|
158
|
+
* const buf = create_string_buffer(256);
|
|
159
|
+
* // 256-byte zero-filled buffer
|
|
160
|
+
* ```
|
|
161
|
+
*
|
|
162
|
+
* @example From string
|
|
163
|
+
* ```javascript
|
|
164
|
+
* const buf = create_string_buffer("Hello");
|
|
165
|
+
* // Buffer: "Hello\0" (6 bytes including null terminator)
|
|
166
|
+
* ```
|
|
167
|
+
*
|
|
168
|
+
* @example From buffer
|
|
169
|
+
* ```javascript
|
|
170
|
+
* const src = Buffer.from([72, 101, 108, 108, 111]);
|
|
171
|
+
* const buf = create_string_buffer(src);
|
|
172
|
+
* // Buffer: [72, 101, 108, 108, 111, 0] (adds null terminator)
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
export function create_string_buffer(init, native) {
|
|
176
|
+
if (typeof init === "number") {
|
|
177
|
+
// create_string_buffer(size) - allocate empty buffer
|
|
178
|
+
return alloc(init);
|
|
179
|
+
} else if (typeof init === "string") {
|
|
180
|
+
// create_string_buffer("string") - create buffer with string
|
|
181
|
+
return cstring(init, native);
|
|
182
|
+
} else if (Buffer.isBuffer(init)) {
|
|
183
|
+
// create_string_buffer(bytes) - copy bytes and add null terminator
|
|
184
|
+
const buf = alloc(init.length + 1);
|
|
185
|
+
init.copy(buf);
|
|
186
|
+
buf[init.length] = 0; // null terminator
|
|
187
|
+
return buf;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
throw new TypeError("create_string_buffer requires number, string, or Buffer");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Creates a Unicode (wide string) buffer (Python ctypes compatible).
|
|
195
|
+
*
|
|
196
|
+
* **Overloaded Function**:
|
|
197
|
+
* - `create_unicode_buffer(size)` - Allocates buffer for size characters
|
|
198
|
+
* - `create_unicode_buffer(string)` - Creates wide string buffer from string
|
|
199
|
+
*
|
|
200
|
+
* **Platform-Specific Behavior**:
|
|
201
|
+
* - **Windows**: size * 2 bytes (UTF-16LE)
|
|
202
|
+
* - **Unix**: size * 4 bytes (UTF-32LE)
|
|
203
|
+
*
|
|
204
|
+
* **Python ctypes Compatibility**:
|
|
205
|
+
* Direct equivalent to Python's `ctypes.create_unicode_buffer()`.
|
|
206
|
+
*
|
|
207
|
+
* @param {number|string} init - Size in characters or string
|
|
208
|
+
* @param {Object} native - Native module reference (provides WCHAR_SIZE)
|
|
209
|
+
* @returns {Buffer} Created wide string buffer
|
|
210
|
+
* @throws {TypeError} If init is not number or string
|
|
211
|
+
*
|
|
212
|
+
* @example Empty wide buffer
|
|
213
|
+
* ```javascript
|
|
214
|
+
* import { create_unicode_buffer } from 'node-ctypes';
|
|
215
|
+
*
|
|
216
|
+
* // On Windows (2 bytes per wchar_t):
|
|
217
|
+
* const buf = create_unicode_buffer(64);
|
|
218
|
+
* // 128-byte buffer (64 characters * 2 bytes)
|
|
219
|
+
*
|
|
220
|
+
* // On Unix (4 bytes per wchar_t):
|
|
221
|
+
* const buf = create_unicode_buffer(64);
|
|
222
|
+
* // 256-byte buffer (64 characters * 4 bytes)
|
|
223
|
+
* ```
|
|
224
|
+
*
|
|
225
|
+
* @example From string
|
|
226
|
+
* ```javascript
|
|
227
|
+
* const buf = create_unicode_buffer("Hello");
|
|
228
|
+
* // Wide string buffer with "Hello\0"
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
export function create_unicode_buffer(init, native) {
|
|
232
|
+
const wcharSize = native.WCHAR_SIZE;
|
|
233
|
+
|
|
234
|
+
if (typeof init === "number") {
|
|
235
|
+
// create_unicode_buffer(size) - allocate empty buffer for N characters
|
|
236
|
+
return alloc(init * wcharSize);
|
|
237
|
+
} else if (typeof init === "string") {
|
|
238
|
+
// create_unicode_buffer("string") - create buffer with wide string
|
|
239
|
+
return wstring(init, native);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
throw new TypeError("create_unicode_buffer requires number or string");
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Reads a C string from a memory address (Python ctypes compatible).
|
|
247
|
+
*
|
|
248
|
+
* **Python ctypes Compatibility**:
|
|
249
|
+
* Direct equivalent to Python's `ctypes.string_at()`.
|
|
250
|
+
*
|
|
251
|
+
* @param {Buffer|bigint|number} address - Memory address or buffer
|
|
252
|
+
* @param {number} [size] - Number of bytes to read (default: until null terminator)
|
|
253
|
+
* @param {Object} native - Native module reference
|
|
254
|
+
* @returns {string|null} String read from memory
|
|
255
|
+
*
|
|
256
|
+
* @example Read until null terminator
|
|
257
|
+
* ```javascript
|
|
258
|
+
* import { string_at, cstring } from 'node-ctypes';
|
|
259
|
+
*
|
|
260
|
+
* const buf = cstring("Hello");
|
|
261
|
+
* const str = string_at(buf);
|
|
262
|
+
* console.log(str); // "Hello"
|
|
263
|
+
* ```
|
|
264
|
+
*
|
|
265
|
+
* @example Read fixed size
|
|
266
|
+
* ```javascript
|
|
267
|
+
* const buf = Buffer.from("Hello, World!\0");
|
|
268
|
+
* const str = string_at(buf, 5);
|
|
269
|
+
* console.log(str); // "Hello"
|
|
270
|
+
* ```
|
|
271
|
+
*/
|
|
272
|
+
export function string_at(address, size, native) {
|
|
273
|
+
return native.readCString(address, size);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Reads a wide string from a memory address (Python ctypes compatible).
|
|
278
|
+
*
|
|
279
|
+
* **Platform-Specific Behavior**:
|
|
280
|
+
* - **Windows**: Reads UTF-16LE (2 bytes per character)
|
|
281
|
+
* - **Unix**: Reads UTF-32LE (4 bytes per character)
|
|
282
|
+
*
|
|
283
|
+
* **Python ctypes Compatibility**:
|
|
284
|
+
* Direct equivalent to Python's `ctypes.wstring_at()`.
|
|
285
|
+
*
|
|
286
|
+
* @param {Buffer|bigint|number} address - Memory address or buffer
|
|
287
|
+
* @param {number} [size] - Number of wide characters to read (not bytes)
|
|
288
|
+
* @param {Object} native - Native module reference
|
|
289
|
+
* @returns {string|null} Wide string read from memory
|
|
290
|
+
*
|
|
291
|
+
* @example Read wide string
|
|
292
|
+
* ```javascript
|
|
293
|
+
* import { wstring_at, wstring } from 'node-ctypes';
|
|
294
|
+
*
|
|
295
|
+
* const buf = wstring("Hello");
|
|
296
|
+
* const str = wstring_at(buf);
|
|
297
|
+
* console.log(str); // "Hello"
|
|
298
|
+
* ```
|
|
299
|
+
*/
|
|
300
|
+
export function wstring_at(address, size, native) {
|
|
301
|
+
if (address === null || address === undefined) {
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const wcharSize = native.WCHAR_SIZE;
|
|
306
|
+
let buf;
|
|
307
|
+
|
|
308
|
+
if (Buffer.isBuffer(address)) {
|
|
309
|
+
buf = address;
|
|
310
|
+
} else {
|
|
311
|
+
// Convert BigInt/number to buffer
|
|
312
|
+
const maxBytes = size ? size * wcharSize : 1024;
|
|
313
|
+
buf = native.ptrToBuffer(address, maxBytes);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Windows: UTF-16LE
|
|
317
|
+
if (wcharSize === 2) {
|
|
318
|
+
if (size !== undefined) {
|
|
319
|
+
return buf.toString("utf16le", 0, size * 2);
|
|
320
|
+
}
|
|
321
|
+
// Read until null terminator
|
|
322
|
+
let end = 0;
|
|
323
|
+
while (end < buf.length - 1 && (buf[end] !== 0 || buf[end + 1] !== 0)) {
|
|
324
|
+
end += 2;
|
|
325
|
+
}
|
|
326
|
+
return buf.toString("utf16le", 0, end);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Unix: UTF-32LE
|
|
330
|
+
const chars = [];
|
|
331
|
+
const limit = size !== undefined ? size : Math.floor(buf.length / 4);
|
|
332
|
+
|
|
333
|
+
for (let i = 0; i < limit; i++) {
|
|
334
|
+
const codePoint = buf.readUInt32LE(i * 4);
|
|
335
|
+
if (codePoint === 0) break;
|
|
336
|
+
chars.push(String.fromCodePoint(codePoint));
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return chars.join("");
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Copies memory from source to destination (like C's memmove).
|
|
344
|
+
*
|
|
345
|
+
* **Python ctypes Compatibility**:
|
|
346
|
+
* Equivalent to Python's `ctypes.memmove()`.
|
|
347
|
+
*
|
|
348
|
+
* @param {Buffer} dst - Destination buffer
|
|
349
|
+
* @param {Buffer|bigint} src - Source buffer or address
|
|
350
|
+
* @param {number} count - Number of bytes to copy
|
|
351
|
+
* @param {Object} native - Native module reference
|
|
352
|
+
* @throws {TypeError} If dst is not a Buffer
|
|
353
|
+
*
|
|
354
|
+
* @example
|
|
355
|
+
* ```javascript
|
|
356
|
+
* import { memmove } from 'node-ctypes';
|
|
357
|
+
*
|
|
358
|
+
* const dst = Buffer.alloc(10);
|
|
359
|
+
* const src = Buffer.from("Hello");
|
|
360
|
+
* memmove(dst, src, 5);
|
|
361
|
+
* console.log(dst.toString('utf8', 0, 5)); // "Hello"
|
|
362
|
+
* ```
|
|
363
|
+
*/
|
|
364
|
+
export function memmove(dst, src, count, native) {
|
|
365
|
+
if (!Buffer.isBuffer(dst)) {
|
|
366
|
+
throw new TypeError("dst must be a Buffer");
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
let srcBuf;
|
|
370
|
+
if (Buffer.isBuffer(src)) {
|
|
371
|
+
srcBuf = src;
|
|
372
|
+
} else {
|
|
373
|
+
srcBuf = native.ptrToBuffer(src, count);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
srcBuf.copy(dst, 0, 0, count);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Fills memory with a byte value (like C's memset).
|
|
381
|
+
*
|
|
382
|
+
* **Python ctypes Compatibility**:
|
|
383
|
+
* Equivalent to Python's `ctypes.memset()`.
|
|
384
|
+
*
|
|
385
|
+
* @param {Buffer} dst - Destination buffer
|
|
386
|
+
* @param {number} value - Byte value to fill (0-255)
|
|
387
|
+
* @param {number} count - Number of bytes to fill
|
|
388
|
+
* @throws {TypeError} If dst is not a Buffer
|
|
389
|
+
*
|
|
390
|
+
* @example
|
|
391
|
+
* ```javascript
|
|
392
|
+
* import { memset } from 'node-ctypes';
|
|
393
|
+
*
|
|
394
|
+
* const buf = Buffer.alloc(10);
|
|
395
|
+
* memset(buf, 0xFF, 5);
|
|
396
|
+
* console.log([...buf]); // [255, 255, 255, 255, 255, 0, 0, 0, 0, 0]
|
|
397
|
+
* ```
|
|
398
|
+
*/
|
|
399
|
+
export function memset(dst, value, count) {
|
|
400
|
+
if (!Buffer.isBuffer(dst)) {
|
|
401
|
+
throw new TypeError("dst must be a Buffer");
|
|
402
|
+
}
|
|
403
|
+
dst.fill(value, 0, count);
|
|
404
|
+
}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file operations.js
|
|
3
|
+
* @module memory/operations
|
|
4
|
+
* @description Memory read/write operations and type size queries.
|
|
5
|
+
*
|
|
6
|
+
* This module provides low-level memory operations for reading and writing
|
|
7
|
+
* typed values to/from buffers, similar to Python ctypes memory access.
|
|
8
|
+
*
|
|
9
|
+
* **Python ctypes Compatibility**:
|
|
10
|
+
* These functions provide similar functionality to Python's struct module
|
|
11
|
+
* and ctypes memory operations.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```javascript
|
|
15
|
+
* import { readValue, writeValue, sizeof, c_int32, c_double } from 'node-ctypes';
|
|
16
|
+
*
|
|
17
|
+
* const buf = Buffer.alloc(16);
|
|
18
|
+
*
|
|
19
|
+
* // Write values
|
|
20
|
+
* writeValue(buf, c_int32, 42, 0);
|
|
21
|
+
* writeValue(buf, c_double, 3.14, 8);
|
|
22
|
+
*
|
|
23
|
+
* // Read values
|
|
24
|
+
* const int_val = readValue(buf, c_int32, 0); // 42
|
|
25
|
+
* const double_val = readValue(buf, c_double, 8); // 3.14
|
|
26
|
+
*
|
|
27
|
+
* // Get type sizes
|
|
28
|
+
* console.log(sizeof(c_int32)); // 4
|
|
29
|
+
* console.log(sizeof(c_double)); // 8
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Reads a typed value from memory at the specified offset.
|
|
35
|
+
*
|
|
36
|
+
* **Supported Types**:
|
|
37
|
+
* - SimpleCData classes (c_int32, c_uint64, c_float, c_double, etc.)
|
|
38
|
+
* - Structure classes (user-defined structs)
|
|
39
|
+
* - Union classes (user-defined unions)
|
|
40
|
+
*
|
|
41
|
+
* **Python ctypes Compatibility**:
|
|
42
|
+
* Similar to reading from a ctypes pointer or using struct.unpack.
|
|
43
|
+
*
|
|
44
|
+
* @param {Buffer|bigint|number} ptr - Buffer or memory address to read from
|
|
45
|
+
* @param {Function|Object} type - Type to read (SimpleCData class, Structure, or Union)
|
|
46
|
+
* @param {number} [offset=0] - Byte offset from ptr
|
|
47
|
+
* @param {Function} sizeof - sizeof function reference
|
|
48
|
+
* @param {Function} ptrToBuffer - ptrToBuffer function reference
|
|
49
|
+
* @param {Function} Structure - Structure class reference
|
|
50
|
+
* @param {Function} Union - Union class reference
|
|
51
|
+
* @returns {*} Value read from memory
|
|
52
|
+
* @throws {RangeError} If offset is negative or read exceeds buffer bounds
|
|
53
|
+
* @throws {TypeError} If ptr is not a Buffer/address or type is unsupported
|
|
54
|
+
*
|
|
55
|
+
* @example Read primitive types
|
|
56
|
+
* ```javascript
|
|
57
|
+
* import { readValue, c_int32, c_float } from 'node-ctypes';
|
|
58
|
+
*
|
|
59
|
+
* const buf = Buffer.from([0x2A, 0x00, 0x00, 0x00]); // 42 in little-endian
|
|
60
|
+
* const value = readValue(buf, c_int32, 0);
|
|
61
|
+
* console.log(value); // 42
|
|
62
|
+
* ```
|
|
63
|
+
*
|
|
64
|
+
* @example Read from address
|
|
65
|
+
* ```javascript
|
|
66
|
+
* const address = 0x1234567890ABCDEFn;
|
|
67
|
+
* const value = readValue(address, c_int32, 0);
|
|
68
|
+
* ```
|
|
69
|
+
*
|
|
70
|
+
* @example Read struct
|
|
71
|
+
* ```javascript
|
|
72
|
+
* class Point extends Structure {
|
|
73
|
+
* static _fields_ = [['x', c_int32], ['y', c_int32]];
|
|
74
|
+
* }
|
|
75
|
+
*
|
|
76
|
+
* const buf = Buffer.alloc(8);
|
|
77
|
+
* const point = readValue(buf, Point, 0);
|
|
78
|
+
* console.log(point); // { x: 0, y: 0 }
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export function readValue(ptr, type, offset = 0, sizeof, ptrToBuffer, Structure, Union) {
|
|
82
|
+
// Validate offset
|
|
83
|
+
if (typeof offset !== "number" || offset < 0) {
|
|
84
|
+
throw new RangeError("offset must be a non-negative number");
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// SimpleCData class - use its _reader directly
|
|
88
|
+
if (typeof type === "function" && type._isSimpleCData) {
|
|
89
|
+
if (Buffer.isBuffer(ptr)) {
|
|
90
|
+
const size = type._size || sizeof(type);
|
|
91
|
+
// Bounds check for buffer reads
|
|
92
|
+
if (offset + size > ptr.length) {
|
|
93
|
+
throw new RangeError(`Read would exceed buffer bounds (offset: ${offset}, size: ${size}, buffer length: ${ptr.length})`);
|
|
94
|
+
}
|
|
95
|
+
return type._reader(ptr, offset);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Allow passing an address (BigInt or number) and convert to buffer
|
|
99
|
+
if (typeof ptr === "bigint" || typeof ptr === "number") {
|
|
100
|
+
const size = type._size || sizeof(type);
|
|
101
|
+
const buf = ptrToBuffer(ptr, size + offset);
|
|
102
|
+
return type._reader(buf, offset);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
throw new TypeError("readValue requires a Buffer or pointer address");
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Struct type (class)
|
|
109
|
+
if (typeof type === "function" && type.prototype instanceof Structure) {
|
|
110
|
+
const def = type._structDef || type._buildStruct();
|
|
111
|
+
const tempBuf = ptr.subarray(offset, offset + def.size);
|
|
112
|
+
return def.toObject(tempBuf);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Union type (class)
|
|
116
|
+
if (typeof type === "function" && type.prototype instanceof Union) {
|
|
117
|
+
const def = type._unionDef || type._buildUnion();
|
|
118
|
+
const tempBuf = ptr.subarray(offset, offset + def.size);
|
|
119
|
+
return def.toObject(tempBuf);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
throw new TypeError(`readValue: unsupported type ${type}`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Writes a typed value to memory at the specified offset.
|
|
127
|
+
*
|
|
128
|
+
* **Supported Types**:
|
|
129
|
+
* - SimpleCData classes (c_int32, c_uint64, c_float, c_double, etc.)
|
|
130
|
+
* - Structure classes (user-defined structs)
|
|
131
|
+
* - Union classes (user-defined unions)
|
|
132
|
+
*
|
|
133
|
+
* **Python ctypes Compatibility**:
|
|
134
|
+
* Similar to writing to a ctypes pointer or using struct.pack.
|
|
135
|
+
*
|
|
136
|
+
* @param {Buffer} ptr - Buffer to write to (must be a Buffer, not an address)
|
|
137
|
+
* @param {Function|Object} type - Type to write (SimpleCData class, Structure, or Union)
|
|
138
|
+
* @param {*} value - Value to write
|
|
139
|
+
* @param {number} [offset=0] - Byte offset in buffer
|
|
140
|
+
* @param {Function} sizeof - sizeof function reference
|
|
141
|
+
* @param {Function} Structure - Structure class reference
|
|
142
|
+
* @param {Function} Union - Union class reference
|
|
143
|
+
* @returns {number} Number of bytes written
|
|
144
|
+
* @throws {RangeError} If offset is negative or write exceeds buffer bounds
|
|
145
|
+
* @throws {TypeError} If ptr is not a Buffer or type is unsupported
|
|
146
|
+
*
|
|
147
|
+
* @example Write primitive types
|
|
148
|
+
* ```javascript
|
|
149
|
+
* import { writeValue, c_int32, c_double } from 'node-ctypes';
|
|
150
|
+
*
|
|
151
|
+
* const buf = Buffer.alloc(16);
|
|
152
|
+
* writeValue(buf, c_int32, 42, 0);
|
|
153
|
+
* writeValue(buf, c_double, 3.14159, 8);
|
|
154
|
+
* ```
|
|
155
|
+
*
|
|
156
|
+
* @example Write struct
|
|
157
|
+
* ```javascript
|
|
158
|
+
* class Point extends Structure {
|
|
159
|
+
* static _fields_ = [['x', c_int32], ['y', c_int32]];
|
|
160
|
+
* }
|
|
161
|
+
*
|
|
162
|
+
* const buf = Buffer.alloc(8);
|
|
163
|
+
* writeValue(buf, Point, { x: 10, y: 20 }, 0);
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
export function writeValue(ptr, type, value, offset = 0, sizeof, Structure, Union) {
|
|
167
|
+
// Validate offset
|
|
168
|
+
if (typeof offset !== "number" || offset < 0) {
|
|
169
|
+
throw new RangeError("offset must be a non-negative number");
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// SimpleCData class - use its _writer directly
|
|
173
|
+
if (typeof type === "function" && type._isSimpleCData) {
|
|
174
|
+
if (!Buffer.isBuffer(ptr)) {
|
|
175
|
+
throw new TypeError("writeValue requires a Buffer");
|
|
176
|
+
}
|
|
177
|
+
const size = type._size || sizeof(type);
|
|
178
|
+
// Bounds check for buffer writes
|
|
179
|
+
if (offset + size > ptr.length) {
|
|
180
|
+
throw new RangeError(`Write would exceed buffer bounds (offset: ${offset}, size: ${size}, buffer length: ${ptr.length})`);
|
|
181
|
+
}
|
|
182
|
+
type._writer(ptr, offset, value);
|
|
183
|
+
return type._size;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Struct type (class)
|
|
187
|
+
if (typeof type === "function" && type.prototype instanceof Structure) {
|
|
188
|
+
const def = type._structDef || type._buildStruct();
|
|
189
|
+
const tempBuf = ptr.subarray(offset, offset + def.size);
|
|
190
|
+
if (Buffer.isBuffer(value)) {
|
|
191
|
+
value.copy(tempBuf, 0, 0, def.size);
|
|
192
|
+
} else if (typeof value === "object" && value !== null) {
|
|
193
|
+
for (const [k, v] of Object.entries(value)) {
|
|
194
|
+
def.set(tempBuf, k, v);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return def.size;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Union type (class)
|
|
201
|
+
if (typeof type === "function" && type.prototype instanceof Union) {
|
|
202
|
+
const def = type._unionDef || type._buildUnion();
|
|
203
|
+
const tempBuf = ptr.subarray(offset, offset + def.size);
|
|
204
|
+
if (Buffer.isBuffer(value)) {
|
|
205
|
+
value.copy(tempBuf, 0, 0, def.size);
|
|
206
|
+
} else if (typeof value === "object" && value !== null) {
|
|
207
|
+
for (const [k, v] of Object.entries(value)) {
|
|
208
|
+
def.set(tempBuf, k, v);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return def.size;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
throw new TypeError(`writeValue: unsupported type ${type}`);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Returns the size in bytes of a type or type instance.
|
|
219
|
+
*
|
|
220
|
+
* **Supported Inputs**:
|
|
221
|
+
* - SimpleCData classes (c_int32, c_uint64, etc.)
|
|
222
|
+
* - SimpleCData instances (new c_int32())
|
|
223
|
+
* - Structure classes (user-defined structs)
|
|
224
|
+
* - Union classes (user-defined unions)
|
|
225
|
+
* - Struct/Union definition objects
|
|
226
|
+
* - Array type objects
|
|
227
|
+
*
|
|
228
|
+
* **Python ctypes Compatibility**:
|
|
229
|
+
* Direct equivalent to Python's `ctypes.sizeof()`.
|
|
230
|
+
*
|
|
231
|
+
* @param {Function|Object} type - Type or instance to get size of
|
|
232
|
+
* @param {Function} Structure - Structure class reference
|
|
233
|
+
* @param {Function} Union - Union class reference
|
|
234
|
+
* @returns {number} Size in bytes
|
|
235
|
+
* @throws {TypeError} If type is unsupported
|
|
236
|
+
*
|
|
237
|
+
* @example Primitive type sizes
|
|
238
|
+
* ```javascript
|
|
239
|
+
* import { sizeof, c_int32, c_uint64, c_double } from 'node-ctypes';
|
|
240
|
+
*
|
|
241
|
+
* console.log(sizeof(c_int32)); // 4
|
|
242
|
+
* console.log(sizeof(c_uint64)); // 8
|
|
243
|
+
* console.log(sizeof(c_double)); // 8
|
|
244
|
+
* ```
|
|
245
|
+
*
|
|
246
|
+
* @example Struct size
|
|
247
|
+
* ```javascript
|
|
248
|
+
* class Point extends Structure {
|
|
249
|
+
* static _fields_ = [['x', c_int32], ['y', c_int32]];
|
|
250
|
+
* }
|
|
251
|
+
*
|
|
252
|
+
* console.log(sizeof(Point)); // 8
|
|
253
|
+
* ```
|
|
254
|
+
*
|
|
255
|
+
* @example Instance size
|
|
256
|
+
* ```javascript
|
|
257
|
+
* const val = new c_int32(42);
|
|
258
|
+
* console.log(sizeof(val)); // 4
|
|
259
|
+
* ```
|
|
260
|
+
*/
|
|
261
|
+
export function sizeof(type, Structure, Union) {
|
|
262
|
+
// SimpleCData class (e.g., sizeof(c_uint64))
|
|
263
|
+
if (typeof type === "function" && type._isSimpleCData) {
|
|
264
|
+
return type._size;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// SimpleCData instance (e.g., sizeof(new c_uint64()))
|
|
268
|
+
if (type && type._buffer && type.constructor && type.constructor._isSimpleCData) {
|
|
269
|
+
return type.constructor._size;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Struct type (class)
|
|
273
|
+
if (typeof type === "function" && type.prototype instanceof Structure) {
|
|
274
|
+
const def = type._structDef || type._buildStruct();
|
|
275
|
+
return def.size;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Union type (class)
|
|
279
|
+
if (typeof type === "function" && type.prototype instanceof Union) {
|
|
280
|
+
const def = type._unionDef || type._buildUnion();
|
|
281
|
+
return def.size;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Struct/Union definition object
|
|
285
|
+
if (typeof type === "object" && type !== null && typeof type.size === "number") {
|
|
286
|
+
return type.size;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Array type
|
|
290
|
+
if (typeof type === "object" && type !== null && typeof type.getSize === "function") {
|
|
291
|
+
return type.getSize();
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
throw new TypeError(`sizeof: unsupported type. Use SimpleCData classes like c_int32, c_uint64, etc.`);
|
|
295
|
+
}
|