koffi 2.6.11 → 2.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/CHANGELOG.md +12 -0
- package/build/koffi/darwin_arm64/koffi.node +0 -0
- package/build/koffi/darwin_x64/koffi.node +0 -0
- package/build/koffi/freebsd_arm64/koffi.node +0 -0
- package/build/koffi/freebsd_ia32/koffi.node +0 -0
- package/build/koffi/freebsd_x64/koffi.node +0 -0
- package/build/koffi/linux_arm32hf/koffi.node +0 -0
- package/build/koffi/linux_arm64/koffi.node +0 -0
- package/build/koffi/linux_ia32/koffi.node +0 -0
- package/build/koffi/linux_riscv64hf64/koffi.node +0 -0
- package/build/koffi/linux_x64/koffi.node +0 -0
- package/build/koffi/openbsd_ia32/koffi.node +0 -0
- package/build/koffi/openbsd_x64/koffi.node +0 -0
- package/build/koffi/win32_arm64/koffi.node +0 -0
- package/build/koffi/win32_ia32/koffi.node +0 -0
- package/build/koffi/win32_x64/koffi.node +0 -0
- package/doc/callbacks.md +19 -0
- package/doc/functions.md +15 -7
- package/doc/start.md +2 -2
- package/index.d.ts +11 -11
- package/index.js +11 -2
- package/indirect.js +11 -2
- package/package.json +2 -2
- package/src/core/libcc/libcc.cc +73 -6
- package/src/core/libcc/libcc.hh +10 -2
- package/src/core/libcc/mimetypes.inc +1228 -0
- package/src/core/libcc/mimetypes_gen.py +77 -0
- package/src/koffi/src/ffi.cc +40 -34
- package/src/koffi/src/ffi.hh +3 -0
- package/src/koffi/src/parser.cc +1 -9
- package/src/koffi/src/util.cc +21 -0
- package/src/koffi/src/util.hh +2 -0
- package/build/koffi/win32_x64/koffi.pdb +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,8 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
## Version history
|
|
4
4
|
|
|
5
|
+
### Koffi 2.7
|
|
6
|
+
|
|
7
|
+
#### Koffi 2.7.0 (2023-12-21)
|
|
8
|
+
|
|
9
|
+
- Support alternative [callback calling convention](callbacks.md#callback-types) in classic syntax
|
|
10
|
+
- Change syntax for [calling conventions](functions.md#calling-conventions) with classic syntax
|
|
11
|
+
- Drop unused "internal" property from Koffi
|
|
12
|
+
|
|
5
13
|
### Koffi 2.6
|
|
6
14
|
|
|
15
|
+
#### Koffi 2.6.12 (2023-12-11)
|
|
16
|
+
|
|
17
|
+
- Fix possible crash introduced in Koffi 2.6.11
|
|
18
|
+
|
|
7
19
|
#### Koffi 2.6.11 (2023-12-05)
|
|
8
20
|
|
|
9
21
|
- Speed up resolving simple and often used type names
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/doc/callbacks.md
CHANGED
|
@@ -8,6 +8,8 @@ The function `koffi.proto()` was introduced in Koffi 2.4, it was called `koffi.c
|
|
|
8
8
|
|
|
9
9
|
## Callback types
|
|
10
10
|
|
|
11
|
+
*Changed in Koffi 2.7*
|
|
12
|
+
|
|
11
13
|
In order to pass a JS function to a C function expecting a callback, you must first create a callback type with the expected return type and parameters. The syntax is similar to the one used to load functions from a shared library.
|
|
12
14
|
|
|
13
15
|
```js
|
|
@@ -21,6 +23,23 @@ const ExampleCallback = koffi.proto('ExampleCallback', 'void', ['int']);
|
|
|
21
23
|
const AddDoubleFloat = koffi.proto('double AddDoubleFloat(double d, float f)');
|
|
22
24
|
```
|
|
23
25
|
|
|
26
|
+
For alternative [calling conventions](functions.md#calling-conventions) (such as `stdcall` on Windows x86 32-bit), you can specify as the first argument with the classic syntax, or after the return type in prototype strings, like this:
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
const HANDLE = koffi.pointer('HANDLE', koffi.opaque());
|
|
30
|
+
const HWND = koffi.alias('HWND', HANDLE);
|
|
31
|
+
|
|
32
|
+
// These two declarations work the same, and use the __stdcall convention on Windows x86
|
|
33
|
+
const EnumWindowsProc = koffi.proto('bool __stdcall EnumWindowsProc (HWND hwnd, long lParam)');
|
|
34
|
+
const EnumWindowsProc = koffi.proto('__stdcall', 'EnumWindowsProc', 'bool', ['HWND', 'long']);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```{warning}
|
|
38
|
+
You have to make sure you **get the calling convention right** (such as specifying __stdcall for a Windows API callback), or your code will crash on Windows 32-bit.
|
|
39
|
+
|
|
40
|
+
Before Koffi 2.7, it was *impossible to use an alternative callback calling convention with the classic syntax*. Use a prototype string or *upgrade to Koffi 2.7* to solve this limitation.
|
|
41
|
+
```
|
|
42
|
+
|
|
24
43
|
Once your callback type is declared, you can use a pointer to it in struct definitions, as function parameters and/or return types, or to call/decode function pointers.
|
|
25
44
|
|
|
26
45
|
```{note}
|
package/doc/functions.md
CHANGED
|
@@ -83,19 +83,27 @@ On x86 platforms, only the Cdecl convention can be used for variadic functions.
|
|
|
83
83
|
|
|
84
84
|
### Calling conventions
|
|
85
85
|
|
|
86
|
+
*Changed in Koffi 2.7*
|
|
87
|
+
|
|
86
88
|
By default, calling a C function happens synchronously.
|
|
87
89
|
|
|
88
90
|
Most architectures only support one procedure call standard per process. The 32-bit x86 platform is an exception to this, and Koffi supports several x86 conventions:
|
|
89
91
|
|
|
90
|
-
Convention | Classic form
|
|
91
|
-
------------- |
|
|
92
|
-
**Cdecl** | `koffi.
|
|
93
|
-
**Stdcall** | `koffi.
|
|
94
|
-
**Fastcall** | `koffi.
|
|
95
|
-
**Thiscall** | `koffi.
|
|
92
|
+
Convention | Classic form | Prototype form | Description
|
|
93
|
+
------------- | --------------------------------------------- | -------------- | -------------------------------------------------------------------
|
|
94
|
+
**Cdecl** | `koffi.func(name, ret, params)` | _(default)_ | This is the default convention, and the only one on other platforms
|
|
95
|
+
**Stdcall** | `koffi.func('__stdcall', name, ret, params)` | __stdcall | This convention is used extensively within the Win32 API
|
|
96
|
+
**Fastcall** | `koffi.func('__fastcall', name, ret, params)` | __fastcall | Rarely used, uses ECX and EDX for first two parameters
|
|
97
|
+
**Thiscall** | `koffi.func('__thiscall', name, ret, params)` | __thiscall | Rarely used, uses ECX for first parameter
|
|
96
98
|
|
|
97
99
|
You can safely use these on non-x86 platforms, they are simply ignored.
|
|
98
100
|
|
|
101
|
+
```{note}
|
|
102
|
+
Support for specifying the convention as the first argument of the classic form was introduced in Koffi 2.7.
|
|
103
|
+
|
|
104
|
+
In earlier versions, you had to use `koffi.stdcall()` and similar functions. These functions are still supported but deprecated, and will be removed in Koffi 3.0.
|
|
105
|
+
```
|
|
106
|
+
|
|
99
107
|
Below you can find a small example showing how to use a non-default calling convention, with the two syntaxes:
|
|
100
108
|
|
|
101
109
|
```js
|
|
@@ -105,7 +113,7 @@ const koffi = require('koffi');
|
|
|
105
113
|
const lib = koffi.load('user32.dll');
|
|
106
114
|
|
|
107
115
|
// The following two declarations are equivalent, and use stdcall on x86 (and the default ABI on other platforms)
|
|
108
|
-
const MessageBoxA_1 = lib.
|
|
116
|
+
const MessageBoxA_1 = lib.func('__stdcall', 'MessageBoxA', 'int', ['void *', 'str', 'str', 'uint']);
|
|
109
117
|
const MessageBoxA_2 = lib.func('int __stdcall MessageBoxA(void *hwnd, str text, str caption, uint type)');
|
|
110
118
|
```
|
|
111
119
|
|
package/doc/start.md
CHANGED
|
@@ -99,8 +99,8 @@ const IDYES = 6;
|
|
|
99
99
|
const IDNO = 7;
|
|
100
100
|
|
|
101
101
|
// Find functions
|
|
102
|
-
const MessageBoxA = lib.
|
|
103
|
-
const MessageBoxW = lib.
|
|
102
|
+
const MessageBoxA = lib.func('__stdcall', 'MessageBoxA', 'int', ['void *', 'str', 'str', 'uint']);
|
|
103
|
+
const MessageBoxW = lib.func('__stdcall', 'MessageBoxW', 'int', ['void *', 'str16', 'str16', 'uint']);
|
|
104
104
|
|
|
105
105
|
let ret = MessageBoxA(null, 'Do you want another message box?', 'Koffi', MB_YESNO | MB_ICONQUESTION);
|
|
106
106
|
if (ret == IDYES)
|
package/index.d.ts
CHANGED
|
@@ -67,18 +67,16 @@ declare module 'koffi' {
|
|
|
67
67
|
export interface IKoffiLib {
|
|
68
68
|
func(definition: string): KoffiFunction;
|
|
69
69
|
func(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
70
|
+
func(convention: string, name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
70
71
|
|
|
71
|
-
cdecl(definition: string): KoffiFunction;
|
|
72
|
-
cdecl(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
73
|
-
|
|
74
|
-
stdcall(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
thiscall(definition: string): KoffiFunction;
|
|
81
|
-
thiscall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
72
|
+
/** @deprecated */ cdecl(definition: string): KoffiFunction;
|
|
73
|
+
/** @deprecated */ cdecl(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
74
|
+
/** @deprecated */ stdcall(definition: string): KoffiFunction;
|
|
75
|
+
/** @deprecated */ stdcall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
76
|
+
/** @deprecated */ fastcall(definition: string): KoffiFunction;
|
|
77
|
+
/** @deprecated */ fastcall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
78
|
+
/** @deprecated */ thiscall(definition: string): KoffiFunction;
|
|
79
|
+
/** @deprecated */ thiscall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
82
80
|
|
|
83
81
|
symbol(name: string, type: TypeSpec): any;
|
|
84
82
|
|
|
@@ -118,8 +116,10 @@ declare module 'koffi' {
|
|
|
118
116
|
|
|
119
117
|
export function proto(definition: string): IKoffiCType;
|
|
120
118
|
export function proto(name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
|
|
119
|
+
export function proto(convention: string, name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
|
|
121
120
|
/** @deprecated */ export function callback(definition: string): IKoffiCType;
|
|
122
121
|
/** @deprecated */ export function callback(name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
|
|
122
|
+
/** @deprecated */ export function callback(convention: string, name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
|
|
123
123
|
|
|
124
124
|
export function register(callback: Function, type: TypeSpec): IKoffiRegisteredCallback;
|
|
125
125
|
export function register(thisValue: any, callback: Function, type: TypeSpec): IKoffiRegisteredCallback;
|
package/index.js
CHANGED
|
@@ -378,8 +378,8 @@ var require_package = __commonJS({
|
|
|
378
378
|
"build/dist/src/koffi/package.json"(exports2, module2) {
|
|
379
379
|
module2.exports = {
|
|
380
380
|
name: "koffi",
|
|
381
|
-
version: "2.
|
|
382
|
-
stable: "2.
|
|
381
|
+
version: "2.7.0",
|
|
382
|
+
stable: "2.7.0",
|
|
383
383
|
description: "Fast and simple C FFI (foreign function interface) for Node.js",
|
|
384
384
|
keywords: [
|
|
385
385
|
"foreign",
|
|
@@ -557,3 +557,12 @@ module.exports = {
|
|
|
557
557
|
handle: util.deprecate(native.opaque, "The koffi.handle() function was deprecated in Koffi 2.1, use koffi.opaque() instead", "KOFFI001"),
|
|
558
558
|
callback: util.deprecate(native.proto, "The koffi.callback() function was deprecated in Koffi 2.4, use koffi.proto() instead", "KOFFI002")
|
|
559
559
|
};
|
|
560
|
+
var load = module.exports.load;
|
|
561
|
+
module.exports.load = (...args) => {
|
|
562
|
+
let lib = load(...args);
|
|
563
|
+
lib.cdecl = util.deprecate((...args2) => lib.func("__cdecl", ...args2), "The koffi.stdcall() function was deprecated in Koffi 2.7, use koffi.func(...) instead", "KOFFI003");
|
|
564
|
+
lib.stdcall = util.deprecate((...args2) => lib.func("__stdcall", ...args2), 'The koffi.stdcall() function was deprecated in Koffi 2.7, use koffi.func("__stdcall", ...) instead', "KOFFI004");
|
|
565
|
+
lib.fastcall = util.deprecate((...args2) => lib.func("__fastcall", ...args2), 'The koffi.fastcall() function was deprecated in Koffi 2.7, use koffi.func("__fastcall", ...) instead', "KOFFI005");
|
|
566
|
+
lib.thiscall = util.deprecate((...args2) => lib.func("__thiscall", ...args2), 'The koffi.thiscall() function was deprecated in Koffi 2.7, use koffi.func("__thiscall", ...) instead', "KOFFI006");
|
|
567
|
+
return lib;
|
|
568
|
+
};
|
package/indirect.js
CHANGED
|
@@ -378,8 +378,8 @@ var require_package = __commonJS({
|
|
|
378
378
|
"build/dist/src/koffi/package.json"(exports2, module2) {
|
|
379
379
|
module2.exports = {
|
|
380
380
|
name: "koffi",
|
|
381
|
-
version: "2.
|
|
382
|
-
stable: "2.
|
|
381
|
+
version: "2.7.0",
|
|
382
|
+
stable: "2.7.0",
|
|
383
383
|
description: "Fast and simple C FFI (foreign function interface) for Node.js",
|
|
384
384
|
keywords: [
|
|
385
385
|
"foreign",
|
|
@@ -477,3 +477,12 @@ module.exports = {
|
|
|
477
477
|
handle: util.deprecate(native.opaque, "The koffi.handle() function was deprecated in Koffi 2.1, use koffi.opaque() instead", "KOFFI001"),
|
|
478
478
|
callback: util.deprecate(native.proto, "The koffi.callback() function was deprecated in Koffi 2.4, use koffi.proto() instead", "KOFFI002")
|
|
479
479
|
};
|
|
480
|
+
var load = module.exports.load;
|
|
481
|
+
module.exports.load = (...args) => {
|
|
482
|
+
let lib = load(...args);
|
|
483
|
+
lib.cdecl = util.deprecate((...args2) => lib.func("__cdecl", ...args2), "The koffi.stdcall() function was deprecated in Koffi 2.7, use koffi.func(...) instead", "KOFFI003");
|
|
484
|
+
lib.stdcall = util.deprecate((...args2) => lib.func("__stdcall", ...args2), 'The koffi.stdcall() function was deprecated in Koffi 2.7, use koffi.func("__stdcall", ...) instead', "KOFFI004");
|
|
485
|
+
lib.fastcall = util.deprecate((...args2) => lib.func("__fastcall", ...args2), 'The koffi.fastcall() function was deprecated in Koffi 2.7, use koffi.func("__fastcall", ...) instead', "KOFFI005");
|
|
486
|
+
lib.thiscall = util.deprecate((...args2) => lib.func("__thiscall", ...args2), 'The koffi.thiscall() function was deprecated in Koffi 2.7, use koffi.func("__thiscall", ...) instead', "KOFFI006");
|
|
487
|
+
return lib;
|
|
488
|
+
};
|
package/package.json
CHANGED
package/src/core/libcc/libcc.cc
CHANGED
|
@@ -5599,7 +5599,6 @@ public:
|
|
|
5599
5599
|
AsyncPool(int threads, bool leak);
|
|
5600
5600
|
|
|
5601
5601
|
int GetWorkerCount() const { return (int)workers.len; }
|
|
5602
|
-
int CountPendingTasks() const { return pending_tasks; }
|
|
5603
5602
|
|
|
5604
5603
|
void RegisterAsync();
|
|
5605
5604
|
void UnregisterAsync();
|
|
@@ -5673,11 +5672,6 @@ bool Async::Sync()
|
|
|
5673
5672
|
return success;
|
|
5674
5673
|
}
|
|
5675
5674
|
|
|
5676
|
-
int Async::CountPendingTasks()
|
|
5677
|
-
{
|
|
5678
|
-
return pool->CountPendingTasks();
|
|
5679
|
-
}
|
|
5680
|
-
|
|
5681
5675
|
bool Async::IsTaskRunning()
|
|
5682
5676
|
{
|
|
5683
5677
|
return async_running_task;
|
|
@@ -5806,6 +5800,11 @@ void AsyncPool::AddTask(Async *async, const std::function<bool()> &func)
|
|
|
5806
5800
|
pending_cv.notify_all();
|
|
5807
5801
|
sync_cv.notify_all();
|
|
5808
5802
|
}
|
|
5803
|
+
|
|
5804
|
+
// Limit queue size (back pressure)
|
|
5805
|
+
while (pending_tasks >= RG_ASYNC_MAX_PENDING_TASKS) {
|
|
5806
|
+
RunTasks(0);
|
|
5807
|
+
}
|
|
5809
5808
|
}
|
|
5810
5809
|
|
|
5811
5810
|
void AsyncPool::RunWorker(int worker_idx)
|
|
@@ -8372,4 +8371,72 @@ bool PromptYN(const char *prompt, bool *out_value)
|
|
|
8372
8371
|
return prompter.ReadYN(out_value);
|
|
8373
8372
|
}
|
|
8374
8373
|
|
|
8374
|
+
// ------------------------------------------------------------------------
|
|
8375
|
+
// Mime types
|
|
8376
|
+
// ------------------------------------------------------------------------
|
|
8377
|
+
|
|
8378
|
+
const char *GetMimeType(Span<const char> extension, const char *default_type)
|
|
8379
|
+
{
|
|
8380
|
+
static const HashMap<Span<const char>, const char *> mime_types = {
|
|
8381
|
+
#define MIMETYPE(Extension, MimeType) { (Extension), (MimeType) },
|
|
8382
|
+
#include "mimetypes.inc"
|
|
8383
|
+
|
|
8384
|
+
{"", "application/octet-stream"}
|
|
8385
|
+
};
|
|
8386
|
+
|
|
8387
|
+
const char *mime_type = mime_types.FindValue(extension, nullptr);
|
|
8388
|
+
|
|
8389
|
+
if (!mime_type) {
|
|
8390
|
+
LogError("Unknown MIME type for extension '%1'", extension);
|
|
8391
|
+
mime_type = default_type;
|
|
8392
|
+
}
|
|
8393
|
+
|
|
8394
|
+
return mime_type;
|
|
8395
|
+
}
|
|
8396
|
+
|
|
8397
|
+
bool CanCompressFile(const char *filename)
|
|
8398
|
+
{
|
|
8399
|
+
char extension[8];
|
|
8400
|
+
{
|
|
8401
|
+
const char *ptr = GetPathExtension(filename).ptr;
|
|
8402
|
+
|
|
8403
|
+
Size i = 0;
|
|
8404
|
+
while (i < RG_SIZE(extension) - 1 && ptr[i]) {
|
|
8405
|
+
extension[i] = LowerAscii(ptr[i]);
|
|
8406
|
+
i++;
|
|
8407
|
+
}
|
|
8408
|
+
extension[i] = 0;
|
|
8409
|
+
}
|
|
8410
|
+
|
|
8411
|
+
if (TestStrI(extension, ".zip"))
|
|
8412
|
+
return false;
|
|
8413
|
+
if (TestStrI(extension, ".rar"))
|
|
8414
|
+
return false;
|
|
8415
|
+
if (TestStrI(extension, ".7z"))
|
|
8416
|
+
return false;
|
|
8417
|
+
if (TestStrI(extension, ".gz") || TestStrI(extension, ".tgz"))
|
|
8418
|
+
return false;
|
|
8419
|
+
if (TestStrI(extension, ".bz2") || TestStrI(extension, ".tbz2"))
|
|
8420
|
+
return false;
|
|
8421
|
+
if (TestStrI(extension, ".xz") || TestStrI(extension, ".txz"))
|
|
8422
|
+
return false;
|
|
8423
|
+
if (TestStrI(extension, ".zst") || TestStrI(extension, ".tzst"))
|
|
8424
|
+
return false;
|
|
8425
|
+
if (TestStrI(extension, ".woff") || TestStrI(extension, ".woff2"))
|
|
8426
|
+
return false;
|
|
8427
|
+
if (TestStrI(extension, ".db") || TestStrI(extension, ".sqlite3"))
|
|
8428
|
+
return false;
|
|
8429
|
+
|
|
8430
|
+
const char *mime_type = GetMimeType(extension);
|
|
8431
|
+
|
|
8432
|
+
if (StartsWith(mime_type, "video/"))
|
|
8433
|
+
return false;
|
|
8434
|
+
if (StartsWith(mime_type, "audio/"))
|
|
8435
|
+
return false;
|
|
8436
|
+
if (StartsWith(mime_type, "image/") && !TestStr(mime_type, "image/svg+xml"))
|
|
8437
|
+
return false;
|
|
8438
|
+
|
|
8439
|
+
return true;
|
|
8440
|
+
}
|
|
8441
|
+
|
|
8375
8442
|
}
|
package/src/core/libcc/libcc.hh
CHANGED
|
@@ -93,6 +93,8 @@ namespace RG {
|
|
|
93
93
|
|
|
94
94
|
#define RG_ASYNC_MAX_THREADS 2048
|
|
95
95
|
#define RG_ASYNC_MAX_IDLE_TIME 10000
|
|
96
|
+
#define RG_ASYNC_MAX_PENDING_TASKS 1024
|
|
97
|
+
|
|
96
98
|
#define RG_FIBER_DEFAULT_STACK_SIZE Kibibytes(128)
|
|
97
99
|
|
|
98
100
|
// ------------------------------------------------------------------------
|
|
@@ -4265,8 +4267,6 @@ public:
|
|
|
4265
4267
|
void Run(const std::function<bool()> &f);
|
|
4266
4268
|
bool Sync();
|
|
4267
4269
|
|
|
4268
|
-
int CountPendingTasks();
|
|
4269
|
-
|
|
4270
4270
|
static bool IsTaskRunning();
|
|
4271
4271
|
static int GetWorkerIdx();
|
|
4272
4272
|
static int GetWorkerCount();
|
|
@@ -5016,4 +5016,12 @@ static inline const char *Prompt(const char *prompt, Allocator *alloc)
|
|
|
5016
5016
|
{ return Prompt(prompt, nullptr, nullptr, alloc); }
|
|
5017
5017
|
bool PromptYN(const char *prompt, bool *out_value);
|
|
5018
5018
|
|
|
5019
|
+
// ------------------------------------------------------------------------
|
|
5020
|
+
// Mime types
|
|
5021
|
+
// ------------------------------------------------------------------------
|
|
5022
|
+
|
|
5023
|
+
const char *GetMimeType(Span<const char> extension, const char *default_typ = "application/octet-stream");
|
|
5024
|
+
|
|
5025
|
+
bool CanCompressFile(const char *filename);
|
|
5026
|
+
|
|
5019
5027
|
}
|