node-ctypes 0.1.7 → 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,403 @@
1
+ /**
2
+ * @file errors.js
3
+ * @module platform/errors
4
+ * @description Platform-specific error handling for errno and Windows errors.
5
+ *
6
+ * This module provides Python ctypes-compatible error handling functions for both
7
+ * Unix-like systems (errno) and Windows (GetLastError/FormatError).
8
+ *
9
+ * **Python ctypes Compatibility**:
10
+ * - `get_errno()` / `set_errno()` ≈ Python's `ctypes.get_errno()` / `set_errno()`
11
+ * - `GetLastError()` / `SetLastError()` ≈ Python's `ctypes.GetLastError()` / `SetLastError()`
12
+ * - `FormatError()` ≈ Python's `ctypes.FormatError()`
13
+ * - `WinError()` ≈ Python's `ctypes.WinError()`
14
+ *
15
+ * @example Unix errno
16
+ * ```javascript
17
+ * import { get_errno, set_errno } from 'node-ctypes';
18
+ *
19
+ * // Call C function that might set errno
20
+ * const result = some_c_function();
21
+ * if (result === -1) {
22
+ * const err = get_errno();
23
+ * console.log(`errno: ${err}`);
24
+ * }
25
+ * ```
26
+ *
27
+ * @example Windows errors
28
+ * ```javascript
29
+ * import { GetLastError, WinError } from 'node-ctypes';
30
+ *
31
+ * // Call Windows API that might fail
32
+ * const result = some_win_api();
33
+ * if (!result) {
34
+ * throw WinError(); // Creates Error with formatted message
35
+ * }
36
+ * ```
37
+ */
38
+
39
+ // Lazy-loaded errno and Windows error functions
40
+ let _errno_funcs = null;
41
+ let _win_error_funcs = null;
42
+
43
+ /**
44
+ * Initializes errno functions (lazy loading).
45
+ *
46
+ * **Platform-Specific Behavior**:
47
+ * - **Windows**: Uses msvcrt.dll `_get_errno()` / `_set_errno()`
48
+ * - **macOS**: Uses `__error()` function (returns pointer to errno)
49
+ * - **Linux**: Uses `__errno_location()` function (returns pointer to errno)
50
+ *
51
+ * @param {Function} CDLL - CDLL class reference
52
+ * @param {Object} c_int32 - c_int32 type reference
53
+ * @param {Object} c_void_p - c_void_p type reference
54
+ * @returns {Object} Errno functions object
55
+ * @private
56
+ */
57
+ function _initErrno(CDLL, c_int32, c_void_p) {
58
+ if (_errno_funcs) return _errno_funcs;
59
+
60
+ try {
61
+ if (process.platform === "win32") {
62
+ const msvcrt = new CDLL("msvcrt.dll");
63
+ _errno_funcs = {
64
+ _get: msvcrt.func("_get_errno", c_int32, [c_void_p]),
65
+ _set: msvcrt.func("_set_errno", c_int32, [c_int32]),
66
+ _lib: msvcrt,
67
+ };
68
+ } else if (process.platform === "darwin") {
69
+ // macOS uses __error instead of __errno_location
70
+ const libc = new CDLL(null);
71
+ _errno_funcs = {
72
+ _location: libc.func("__error", c_void_p, []),
73
+ _lib: libc,
74
+ };
75
+ } else {
76
+ // Linux and other Unix systems use __errno_location
77
+ const libc = new CDLL(null);
78
+ _errno_funcs = {
79
+ _location: libc.func("__errno_location", c_void_p, []),
80
+ _lib: libc,
81
+ };
82
+ }
83
+ } catch (e) {
84
+ _errno_funcs = { error: e.message };
85
+ }
86
+
87
+ return _errno_funcs;
88
+ }
89
+
90
+ /**
91
+ * Gets the current value of errno.
92
+ *
93
+ * **Platform-Specific Behavior**:
94
+ * - **Windows**: Calls msvcrt `_get_errno()`
95
+ * - **Unix**: Reads from errno location pointer
96
+ *
97
+ * **Python ctypes Compatibility**:
98
+ * Direct equivalent to Python's `ctypes.get_errno()`.
99
+ *
100
+ * @param {Function} CDLL - CDLL class reference
101
+ * @param {Function} alloc - alloc function reference
102
+ * @param {Function} readValue - readValue function reference
103
+ * @param {Object} c_int32 - c_int32 type reference
104
+ * @param {Object} c_void_p - c_void_p type reference
105
+ * @returns {number} Current errno value
106
+ * @throws {Error} If errno is not available on this platform
107
+ *
108
+ * @example Get errno after failed system call
109
+ * ```javascript
110
+ * import { CDLL, get_errno, c_int } from 'node-ctypes';
111
+ *
112
+ * const libc = new CDLL(null);
113
+ * const open = libc.func('open', c_int, [c_char_p, c_int]);
114
+ *
115
+ * const fd = open('/nonexistent/file', 0);
116
+ * if (fd === -1) {
117
+ * const err = get_errno();
118
+ * console.log(`Error code: ${err}`); // e.g., 2 (ENOENT)
119
+ * }
120
+ * ```
121
+ */
122
+ export function get_errno(CDLL, alloc, readValue, c_int32, c_void_p) {
123
+ const funcs = _initErrno(CDLL, c_int32, c_void_p);
124
+ if (funcs.error) {
125
+ throw new Error("errno not available: " + funcs.error);
126
+ }
127
+
128
+ if (process.platform === "win32") {
129
+ const buf = alloc(4);
130
+ funcs._get(buf);
131
+ return readValue(buf, c_int32);
132
+ } else {
133
+ const ptr = funcs._location();
134
+ return readValue(ptr, c_int32);
135
+ }
136
+ }
137
+
138
+ /**
139
+ * Sets the value of errno.
140
+ *
141
+ * **Platform-Specific Behavior**:
142
+ * - **Windows**: Calls msvcrt `_set_errno()`
143
+ * - **Unix**: Writes to errno location pointer
144
+ *
145
+ * **Python ctypes Compatibility**:
146
+ * Direct equivalent to Python's `ctypes.set_errno()`.
147
+ *
148
+ * @param {number} value - New errno value
149
+ * @param {Function} CDLL - CDLL class reference
150
+ * @param {Function} writeValue - writeValue function reference
151
+ * @param {Object} c_int32 - c_int32 type reference
152
+ * @param {Object} c_void_p - c_void_p type reference
153
+ * @throws {Error} If errno is not available on this platform
154
+ *
155
+ * @example Set errno before calling function
156
+ * ```javascript
157
+ * import { set_errno } from 'node-ctypes';
158
+ *
159
+ * // Clear errno before call
160
+ * set_errno(0);
161
+ * const result = some_c_function();
162
+ * ```
163
+ */
164
+ export function set_errno(value, CDLL, writeValue, c_int32, c_void_p) {
165
+ const funcs = _initErrno(CDLL, c_int32, c_void_p);
166
+ if (funcs.error) {
167
+ throw new Error("errno not available: " + funcs.error);
168
+ }
169
+
170
+ if (process.platform === "win32") {
171
+ funcs._set(value);
172
+ } else {
173
+ const ptr = funcs._location();
174
+ writeValue(ptr, c_int32, value);
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Initializes Windows error functions (lazy loading).
180
+ *
181
+ * Loads kernel32.dll functions for Windows error handling.
182
+ * Only available on Windows platform.
183
+ *
184
+ * @param {Function} WinDLL - WinDLL class reference
185
+ * @param {Object} c_uint32 - c_uint32 type reference
186
+ * @param {Object} c_void - c_void type reference
187
+ * @param {Object} c_void_p - c_void_p type reference
188
+ * @returns {Object} Windows error functions object
189
+ * @private
190
+ */
191
+ function _initWinError(WinDLL, c_uint32, c_void, c_void_p) {
192
+ if (_win_error_funcs) return _win_error_funcs;
193
+
194
+ if (process.platform !== "win32") {
195
+ _win_error_funcs = { error: "Windows only" };
196
+ return _win_error_funcs;
197
+ }
198
+
199
+ try {
200
+ const kernel32 = new WinDLL("kernel32.dll");
201
+ _win_error_funcs = {
202
+ GetLastError: kernel32.func("GetLastError", c_uint32, []),
203
+ SetLastError: kernel32.func("SetLastError", c_void, [c_uint32]),
204
+ FormatMessageW: kernel32.func("FormatMessageW", c_uint32, [c_uint32, c_void_p, c_uint32, c_uint32, c_void_p, c_uint32, c_void_p]),
205
+ _lib: kernel32,
206
+ };
207
+ } catch (e) {
208
+ _win_error_funcs = { error: e.message };
209
+ }
210
+
211
+ return _win_error_funcs;
212
+ }
213
+
214
+ /**
215
+ * Gets the last Windows error code (GetLastError).
216
+ *
217
+ * **Windows Only**: This function is only available on Windows.
218
+ *
219
+ * **Python ctypes Compatibility**:
220
+ * Direct equivalent to Python's `ctypes.GetLastError()`.
221
+ *
222
+ * @param {Function} WinDLL - WinDLL class reference
223
+ * @param {Object} c_uint32 - c_uint32 type reference
224
+ * @param {Object} c_void - c_void type reference
225
+ * @param {Object} c_void_p - c_void_p type reference
226
+ * @returns {number} Windows error code
227
+ * @throws {Error} If not on Windows or kernel32.dll unavailable
228
+ *
229
+ * @example Get Windows error after failed API call
230
+ * ```javascript
231
+ * import { WinDLL, GetLastError } from 'node-ctypes';
232
+ *
233
+ * const kernel32 = new WinDLL('kernel32.dll');
234
+ * const CreateFileW = kernel32.func('CreateFileW', ...);
235
+ *
236
+ * const handle = CreateFileW(...);
237
+ * if (handle === -1) {
238
+ * const err = GetLastError();
239
+ * console.log(`Windows error code: ${err}`);
240
+ * }
241
+ * ```
242
+ */
243
+ export function GetLastError(WinDLL, c_uint32, c_void, c_void_p) {
244
+ const funcs = _initWinError(WinDLL, c_uint32, c_void, c_void_p);
245
+ if (funcs.error) {
246
+ throw new Error("GetLastError not available: " + funcs.error);
247
+ }
248
+ return funcs.GetLastError();
249
+ }
250
+
251
+ /**
252
+ * Sets the last Windows error code (SetLastError).
253
+ *
254
+ * **Windows Only**: This function is only available on Windows.
255
+ *
256
+ * **Python ctypes Compatibility**:
257
+ * Direct equivalent to Python's `ctypes.SetLastError()`.
258
+ *
259
+ * @param {number} code - Error code to set
260
+ * @param {Function} WinDLL - WinDLL class reference
261
+ * @param {Object} c_uint32 - c_uint32 type reference
262
+ * @param {Object} c_void - c_void type reference
263
+ * @param {Object} c_void_p - c_void_p type reference
264
+ * @throws {Error} If not on Windows or kernel32.dll unavailable
265
+ *
266
+ * @example Clear Windows error before call
267
+ * ```javascript
268
+ * import { SetLastError } from 'node-ctypes';
269
+ *
270
+ * // Clear error before Windows API call
271
+ * SetLastError(0);
272
+ * const result = some_win_api();
273
+ * ```
274
+ */
275
+ export function SetLastError(code, WinDLL, c_uint32, c_void, c_void_p) {
276
+ const funcs = _initWinError(WinDLL, c_uint32, c_void, c_void_p);
277
+ if (funcs.error) {
278
+ throw new Error("SetLastError not available: " + funcs.error);
279
+ }
280
+ funcs.SetLastError(code);
281
+ }
282
+
283
+ /**
284
+ * Formats a Windows error code into a human-readable message.
285
+ *
286
+ * **Windows Only**: This function is only available on Windows.
287
+ *
288
+ * **Python ctypes Compatibility**:
289
+ * Direct equivalent to Python's `ctypes.FormatError()`.
290
+ *
291
+ * @param {number} [code] - Error code (default: GetLastError())
292
+ * @param {Function} WinDLL - WinDLL class reference
293
+ * @param {Function} alloc - alloc function reference
294
+ * @param {Object} c_uint32 - c_uint32 type reference
295
+ * @param {Object} c_void - c_void type reference
296
+ * @param {Object} c_void_p - c_void_p type reference
297
+ * @returns {string} Formatted error message
298
+ * @throws {Error} If not on Windows or kernel32.dll unavailable
299
+ *
300
+ * @example Format current Windows error
301
+ * ```javascript
302
+ * import { FormatError } from 'node-ctypes';
303
+ *
304
+ * const result = some_win_api();
305
+ * if (!result) {
306
+ * const message = FormatError();
307
+ * console.log(`Error: ${message}`);
308
+ * }
309
+ * ```
310
+ *
311
+ * @example Format specific error code
312
+ * ```javascript
313
+ * const message = FormatError(5); // Access denied
314
+ * console.log(message); // "Access is denied."
315
+ * ```
316
+ */
317
+ export function FormatError(code, WinDLL, alloc, c_uint32, c_void, c_void_p) {
318
+ const funcs = _initWinError(WinDLL, c_uint32, c_void, c_void_p);
319
+ if (funcs.error) {
320
+ throw new Error("FormatError not available: " + funcs.error);
321
+ }
322
+
323
+ if (code === undefined) {
324
+ code = funcs.GetLastError();
325
+ }
326
+
327
+ const FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
328
+ const FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
329
+
330
+ const bufSize = 512;
331
+ const buf = alloc(bufSize * 2); // Wide chars
332
+
333
+ const len = funcs.FormatMessageW(
334
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
335
+ null,
336
+ code,
337
+ 0, // Default language
338
+ buf,
339
+ bufSize,
340
+ null,
341
+ );
342
+
343
+ if (len === 0) {
344
+ return `Unknown error ${code}`;
345
+ }
346
+
347
+ // Convert from UTF-16LE to string
348
+ return buf.toString("utf16le", 0, len * 2).replace(/\r?\n$/, "");
349
+ }
350
+
351
+ /**
352
+ * Creates an Error object from a Windows error code.
353
+ *
354
+ * **Windows Only**: This function is only available on Windows.
355
+ *
356
+ * The returned Error object has an additional `winerror` property containing
357
+ * the numeric error code.
358
+ *
359
+ * **Python ctypes Compatibility**:
360
+ * Direct equivalent to Python's `ctypes.WinError()`.
361
+ *
362
+ * @param {number} [code] - Error code (default: GetLastError())
363
+ * @param {Function} WinDLL - WinDLL class reference
364
+ * @param {Function} alloc - alloc function reference
365
+ * @param {Object} c_uint32 - c_uint32 type reference
366
+ * @param {Object} c_void - c_void type reference
367
+ * @param {Object} c_void_p - c_void_p type reference
368
+ * @returns {Error} Error object with formatted message and winerror property
369
+ *
370
+ * @example Throw WinError on failure
371
+ * ```javascript
372
+ * import { WinDLL, WinError } from 'node-ctypes';
373
+ *
374
+ * const kernel32 = new WinDLL('kernel32.dll');
375
+ * const CreateFileW = kernel32.func('CreateFileW', ...);
376
+ *
377
+ * const handle = CreateFileW(...);
378
+ * if (handle === -1) {
379
+ * throw WinError(); // Throws Error with formatted message
380
+ * }
381
+ * ```
382
+ *
383
+ * @example Check specific error code
384
+ * ```javascript
385
+ * try {
386
+ * const result = some_win_api();
387
+ * if (!result) throw WinError();
388
+ * } catch (err) {
389
+ * if (err.winerror === 5) {
390
+ * console.log('Access denied');
391
+ * }
392
+ * }
393
+ * ```
394
+ */
395
+ export function WinError(code, WinDLL, alloc, c_uint32, c_void, c_void_p) {
396
+ if (code === undefined) {
397
+ code = GetLastError(WinDLL, c_uint32, c_void, c_void_p);
398
+ }
399
+ const msg = FormatError(code, WinDLL, alloc, c_uint32, c_void, c_void_p);
400
+ const err = new Error(`[WinError ${code}] ${msg}`);
401
+ err.winerror = code;
402
+ return err;
403
+ }