@swf2es/desktop 0.1.19 → 0.1.21
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 +13 -8
- package/dist/main/air-bridge.d.ts +7 -0
- package/dist/main/air-bridge.d.ts.map +1 -0
- package/dist/main/air-bridge.js +166 -0
- package/dist/main/air-bridge.js.map +1 -0
- package/dist/main/dialogs.d.ts +18 -0
- package/dist/main/dialogs.d.ts.map +1 -0
- package/dist/main/dialogs.js +128 -0
- package/dist/main/dialogs.js.map +1 -0
- package/dist/main/main.js +24 -789
- package/dist/main/main.js.map +1 -1
- package/dist/main/menu.d.ts +2 -0
- package/dist/main/menu.d.ts.map +1 -0
- package/dist/main/menu.js +80 -0
- package/dist/main/menu.js.map +1 -0
- package/dist/main/network-rules.d.ts +35 -0
- package/dist/main/network-rules.d.ts.map +1 -0
- package/dist/main/network-rules.js +167 -0
- package/dist/main/network-rules.js.map +1 -0
- package/dist/main/network-types.d.ts +131 -0
- package/dist/main/network-types.d.ts.map +1 -0
- package/dist/main/network-types.js +21 -0
- package/dist/main/network-types.js.map +1 -0
- package/dist/main/network.d.ts +1 -113
- package/dist/main/network.d.ts.map +1 -1
- package/dist/main/network.js +8 -181
- package/dist/main/network.js.map +1 -1
- package/dist/main/open.d.ts +55 -0
- package/dist/main/open.d.ts.map +1 -0
- package/dist/main/open.js +256 -0
- package/dist/main/open.js.map +1 -0
- package/dist/main/permissions.d.ts +17 -0
- package/dist/main/permissions.d.ts.map +1 -0
- package/dist/main/permissions.js +113 -0
- package/dist/main/permissions.js.map +1 -0
- package/dist/main/settings.d.ts +8 -1
- package/dist/main/settings.d.ts.map +1 -1
- package/dist/main/settings.js +9 -4
- package/dist/main/settings.js.map +1 -1
- package/dist/main/state.d.ts +17 -0
- package/dist/main/state.d.ts.map +1 -0
- package/dist/main/state.js +30 -0
- package/dist/main/state.js.map +1 -0
- package/dist/main/switches.d.ts +25 -0
- package/dist/main/switches.d.ts.map +1 -0
- package/dist/main/switches.js +69 -0
- package/dist/main/switches.js.map +1 -0
- package/dist/renderer/index.js +11 -8
- package/dist/renderer/index.js.map +1 -1
- package/package.json +7 -7
- package/src/main/air-bridge.ts +185 -0
- package/src/main/dialogs.ts +147 -0
- package/src/main/main.ts +52 -938
- package/src/main/menu.ts +84 -0
- package/src/main/network-rules.ts +199 -0
- package/src/main/network-types.ts +150 -0
- package/src/main/network.ts +30 -337
- package/src/main/open.ts +302 -0
- package/src/main/permissions.ts +135 -0
- package/src/main/settings.ts +16 -5
- package/src/main/state.ts +44 -0
- package/src/main/switches.ts +87 -0
- package/src/renderer/index.ts +18 -7
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// The command line's switches for this run alone, and what they make:
|
|
2
|
+
// --trace and the network's logs, --ignore-certificate-errors and --proxy,
|
|
3
|
+
// the network judged through them and what opens an AIR application's
|
|
4
|
+
// WebSockets. Each said on stderr as the app starts.
|
|
5
|
+
import { Network } from "./network.js";
|
|
6
|
+
import { unverifiedHosts } from "./network-rules.js";
|
|
7
|
+
import { describeProxy, proxyArgument } from "./proxy.js";
|
|
8
|
+
import { dispatchedOpener, proxiedDispatcher, unverifiedDispatcher, webSocketOpener, } from "./websocket-connections.js";
|
|
9
|
+
/** --trace: what the page logs, a SWF's trace() among it, goes to the terminal. */
|
|
10
|
+
export const trace = process.argv.includes("--trace");
|
|
11
|
+
// Each request and socket of the SWF's said on stderr: the page's DevTools show none of them.
|
|
12
|
+
// --log-sockets says what each socket sends and receives as well, and so the rest too.
|
|
13
|
+
export const logSockets = process.argv.includes("--log-sockets");
|
|
14
|
+
const logNetwork = logSockets || process.argv.includes("--log-network");
|
|
15
|
+
export const netLog = logNetwork ? (line) => process.stderr.write(`${line}\n`) : null;
|
|
16
|
+
/** The SWF's http and https requests, judged as Flash's sandboxes had them. */
|
|
17
|
+
/**
|
|
18
|
+
* --ignore-certificate-errors[=host,...]: HTTPS servers whose certificates go
|
|
19
|
+
* unchecked, for one's own with a certificate it signed itself. For this
|
|
20
|
+
* run alone, never kept, and said aloud: anyone on the way to such a host
|
|
21
|
+
* can read and change what the SWF loads from it.
|
|
22
|
+
*/
|
|
23
|
+
const unverified = unverifiedHosts(process.argv.slice(1));
|
|
24
|
+
if (unverified) {
|
|
25
|
+
process.stderr.write(unverified.all
|
|
26
|
+
? "swf2es: --ignore-certificate-errors: no HTTPS or WSS server's certificate is verified\n"
|
|
27
|
+
: `swf2es: --ignore-certificate-errors: certificates are not verified for ${unverified.hosts.join(", ") || "no host"}\n`);
|
|
28
|
+
}
|
|
29
|
+
const unverifiedHost = (host) => !!unverified && (unverified.all || unverified.hosts.includes(host.toLowerCase()));
|
|
30
|
+
/**
|
|
31
|
+
* --proxy=<url>: what the SWF's requests, sockets and WebSockets go
|
|
32
|
+
* through. For this run alone, never kept, and said aloud, without its
|
|
33
|
+
* credentials. One that does not parse stops the app rather than letting
|
|
34
|
+
* it run without.
|
|
35
|
+
*/
|
|
36
|
+
export const proxied = proxyArgument(process.argv.slice(1));
|
|
37
|
+
if (proxied && "error" in proxied) {
|
|
38
|
+
process.stderr.write(`swf2es: ${proxied.error}\n`);
|
|
39
|
+
process.exit(2);
|
|
40
|
+
}
|
|
41
|
+
export const proxy = proxied?.proxy ?? null;
|
|
42
|
+
if (proxy) {
|
|
43
|
+
process.stderr.write(`swf2es: --proxy: the SWF's requests, sockets and WebSockets go through ${describeProxy(proxy)}\n`);
|
|
44
|
+
}
|
|
45
|
+
/** What --log-network adds to a line of a connection that went through the proxy. */
|
|
46
|
+
export const via = proxy ? " via proxy" : "";
|
|
47
|
+
export const warn = (message) => process.stderr.write(`swf2es: ${message}\n`);
|
|
48
|
+
export const network = new Network({ unverified: unverifiedHost, proxy });
|
|
49
|
+
// What opens an AIR application's WebSockets: the global's client, a wss: server's certificate
|
|
50
|
+
// unchecked where the switch names its host; or every one through the proxy.
|
|
51
|
+
const insecureWebSockets = unverified && !proxy ? unverifiedDispatcher() : null;
|
|
52
|
+
if (unverified && !proxy && !insecureWebSockets) {
|
|
53
|
+
process.stderr.write("swf2es: --ignore-certificate-errors: a WebSocket's certificate is verified all the same\n");
|
|
54
|
+
}
|
|
55
|
+
export const proxiedWebSockets = proxy ? proxiedDispatcher(proxy, unverifiedHost, warn) : null;
|
|
56
|
+
// Never past the proxy: where none can be made, no WebSocket opens.
|
|
57
|
+
export const webSocketOpen = proxy
|
|
58
|
+
? proxiedWebSockets
|
|
59
|
+
? dispatchedOpener(proxiedWebSockets)
|
|
60
|
+
: () => {
|
|
61
|
+
throw new Error("no WebSocket through the proxy");
|
|
62
|
+
}
|
|
63
|
+
: insecureWebSockets
|
|
64
|
+
? webSocketOpener(unverifiedHost, insecureWebSockets)
|
|
65
|
+
: undefined;
|
|
66
|
+
if (proxy && !proxiedWebSockets) {
|
|
67
|
+
process.stderr.write("swf2es: --proxy: this Electron's WebSocket cannot go through a proxy\n");
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=switches.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"switches.js","sourceRoot":"","sources":["../../src/main/switches.ts"],"names":[],"mappings":"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"}
|
package/dist/renderer/index.js
CHANGED
|
@@ -91,7 +91,7 @@ document.addEventListener("drop", (event) => {
|
|
|
91
91
|
desktop.openDropped(file);
|
|
92
92
|
}
|
|
93
93
|
});
|
|
94
|
-
// An open or close
|
|
94
|
+
// An open or close while the page starts takes precedence over the startup snapshot.
|
|
95
95
|
let started = false;
|
|
96
96
|
let pending;
|
|
97
97
|
desktop.onOpen((movie) => {
|
|
@@ -113,13 +113,16 @@ desktop.onClose(() => {
|
|
|
113
113
|
const state = await desktop.start();
|
|
114
114
|
configure({ build: state.build ?? undefined });
|
|
115
115
|
if (state.stage3D) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
116
|
+
// The WebGL2 backend loads when a SWF first asks for a context, so that one that never does
|
|
117
|
+
// starts without waiting for it.
|
|
118
|
+
configure({
|
|
119
|
+
stage3D: {
|
|
120
|
+
load: () => import("./stage3d.js").then((backend) => backend.createStage3D, (error) => {
|
|
121
|
+
console.warn("swf2es: Stage3D backend could not be loaded; Context3D unavailable.", error);
|
|
122
|
+
throw error;
|
|
123
|
+
}),
|
|
124
|
+
},
|
|
125
|
+
});
|
|
123
126
|
}
|
|
124
127
|
useLibraries(state.libraries);
|
|
125
128
|
started = true;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/renderer/index.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,4BAA4B;AAC5B,0EAA0E;AAC1E,OAAO,EAAE,SAAS,EAA4B,MAAM,aAAa,CAAC;AAElE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAQrD,MAAM,OAAO,GAAG,MAAM,CAAC,aAAa,CAAC;AACrC,gGAAgG;AAChG,IAAI,SAAS,GAAqB,IAAI,CAAC;AAEvC,SAAS,CAAC;IACR,KAAK,EAAE,IAAI;IACX,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC;IACnC,OAAO,EAAE,eAAe,CAAC,OAAO,CAAC,OAAO,CAAC;IACzC,UAAU,EAAE,kBAAkB,CAAC,OAAO,CAAC,UAAU,CAAC;IAClD,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE;QACtC,MAAM,MAAM,GAAG,SAAS,CAAC;QACzB,OAAO,MAAM;YACX,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE;gBACN,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;gBAClC,OAAO,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACvD,CAAC;YACH,CAAC,CAAC,IAAI,CAAC;IACX,CAAC,CAAC;IACF,cAAc,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,CAAC;IAC5D,UAAU,EAAE,gBAAgB,CAAC,OAAO,CAAC,UAAU,CAAC;CACjD,CAAC,CAAC;AAEH,MAAM,IAAI,GAAG,CAAwB,EAAU,EAAE,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAM,CAAC;AACrF,MAAM,MAAM,GAAG,IAAI,CAAsB,QAAQ,CAAC,CAAC;AACnD,MAAM,OAAO,GAAG,IAAI,CAAc,SAAS,CAAC,CAAC;AAC7C,MAAM,OAAO,GAAG,IAAI,CAAc,SAAS,CAAC,CAAC;AAE7C,2FAA2F;AAC3F,SAAS,YAAY,CAAC,KAAmB;IACvC,SAAS,CAAC;QACR,SAAS,EAAE;YACT,YAAY,EAAE,KAAK,CAAC,YAAY,KAAK,IAAI,CAAC,CAAC,CAAC,6BAA6B,CAAC,CAAC,CAAC,SAAS;SACtF;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,WAAW,CAAC,OAAsB;IACzC,OAAO,CAAC,MAAM,GAAG,OAAO,KAAK,IAAI,CAAC;IAClC,OAAO,CAAC,WAAW,GAAG,OAAO,IAAI,EAAE,CAAC;AACtC,CAAC;AAED,IAAI,cAAc,GAAG,CAAC,CAAC;AAEvB,SAAS,IAAI,CAAC,KAAkB;IAC9B,MAAM,UAAU,GAAG,EAAE,cAAc,CAAC;IACpC,SAAS,GAAG,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC;IAC9B,SAAS,CAAC;QACR,WAAW,EAAE,KAAK,CAAC,OAAO;QAC1B,GAAG,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI;KACzD,CAAC,CAAC;IACH,WAAW,CAAC,IAAI,CAAC,CAAC;IAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CACzB,GAAG,EAAE;QACH,IAAI,UAAU,KAAK,cAAc,EAAE,CAAC;YAClC,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,CAAC;IACH,CAAC,EACD,CAAC,KAAc,EAAE,EAAE;QACjB,IAAI,UAAU,KAAK,cAAc,EAAE,CAAC;YAClC,OAAO;QACT,CAAC;QAED,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC;QACrB,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC;QACvB,WAAW,CAAC,GAAG,KAAK,CAAC,IAAI,kBAAkB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;IAC/F,CAAC,CACF,CAAC;AACJ,CAAC;AAED,SAAS,KAAK;IACZ,cAAc,EAAE,CAAC;IACjB,MAAM,CAAC,OAAO,EAAE,CAAC;IACjB,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC;IACrB,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC;IACvB,WAAW,CAAC,IAAI,CAAC,CAAC;AACpB,CAAC;AAED,IAAI,CAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;AACnE,IAAI,CAAC,UAAU,CAAC,CAAC,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;AAE1E,mFAAmF;AACnF,QAAQ,CAAC,gBAAgB,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,EAAE;IAC9C,KAAK,CAAC,cAAc,EAAE,CAAC;IACvB,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;QACvB,KAAK,CAAC,YAAY,CAAC,UAAU,GAAG,MAAM,CAAC;IACzC,CAAC;AACH,CAAC,CAAC,CAAC;AACH,QAAQ,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;IAC1C,KAAK,CAAC,cAAc,EAAE,CAAC;IACvB,MAAM,IAAI,GAAG,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC1C,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;AACH,CAAC,CAAC,CAAC;AAEH
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/renderer/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swf2es/desktop",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"description": "swf2es's desktop app: local and remote SWFs, and AIR applications, in an Electron window",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"swf",
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"electron": "44.10.2",
|
|
38
|
-
"@swf2es/codegen": "0.1.
|
|
39
|
-
"@swf2es/context3d": "0.1.
|
|
40
|
-
"@swf2es/format": "0.1.
|
|
41
|
-
"@swf2es/player
|
|
42
|
-
"@swf2es/player": "0.1.
|
|
43
|
-
"@swf2es/web": "0.1.
|
|
38
|
+
"@swf2es/codegen": "0.1.21",
|
|
39
|
+
"@swf2es/context3d": "0.1.21",
|
|
40
|
+
"@swf2es/format": "0.1.21",
|
|
41
|
+
"@swf2es/player": "0.1.21",
|
|
42
|
+
"@swf2es/player-hosts": "0.1.21",
|
|
43
|
+
"@swf2es/web": "0.1.21"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"fetch-electron": "node node_modules/electron/install.js",
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
// An AIR application's reach through the main process (shared/api.ts
|
|
2
|
+
// DesktopAir): its file system, its EncryptedLocalStore, its window and
|
|
3
|
+
// the screens. air.ts does the work apart from Electron.
|
|
4
|
+
import { readFile, realpath } from "node:fs/promises";
|
|
5
|
+
import {
|
|
6
|
+
app,
|
|
7
|
+
type BrowserWindow,
|
|
8
|
+
type IpcMainEvent,
|
|
9
|
+
type IpcMainInvokeEvent,
|
|
10
|
+
ipcMain,
|
|
11
|
+
screen,
|
|
12
|
+
} from "electron";
|
|
13
|
+
import type { AirScreenState, AirWindowState } from "../shared/api.js";
|
|
14
|
+
import { createDirectoryOf, listOf, moveOf, readOf, removeOf, statOf, writeOf } from "./air.ts";
|
|
15
|
+
import { resolveCase } from "./case-paths.ts";
|
|
16
|
+
import { air, encryptedItems } from "./open.ts";
|
|
17
|
+
import { sandbox, trusted, window } from "./state.ts";
|
|
18
|
+
|
|
19
|
+
/** The window as an AIR application's NativeWindow reads it. */
|
|
20
|
+
function windowState(w: BrowserWindow): AirWindowState {
|
|
21
|
+
const bounds = w.getBounds();
|
|
22
|
+
const content = w.getContentBounds();
|
|
23
|
+
return {
|
|
24
|
+
bounds,
|
|
25
|
+
contentOffset: { x: content.x - bounds.x, y: content.y - bounds.y },
|
|
26
|
+
title: w.getTitle(),
|
|
27
|
+
displayState: w.isMinimized() ? "minimized" : w.isMaximized() ? "maximized" : "normal",
|
|
28
|
+
active: w.isFocused(),
|
|
29
|
+
visible: w.isVisible(),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The displays as an AIR application's Screen reads them: the work area is past the system's bars. */
|
|
34
|
+
function screenStates(): AirScreenState[] {
|
|
35
|
+
const primary = screen.getPrimaryDisplay().id;
|
|
36
|
+
return screen.getAllDisplays().map((display) => ({
|
|
37
|
+
bounds: display.bounds,
|
|
38
|
+
visibleBounds: display.workArea,
|
|
39
|
+
colorDepth: display.colorDepth,
|
|
40
|
+
main: display.id === primary,
|
|
41
|
+
}));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* An AIR application's reach, shared/api.ts DesktopAir: the file system
|
|
46
|
+
* and the window, only while one the user opened plays and only for its
|
|
47
|
+
* page. The file system is read synchronously where File reads it so.
|
|
48
|
+
*/
|
|
49
|
+
export function listenForAir(): void {
|
|
50
|
+
const playing = (event: IpcMainEvent | IpcMainInvokeEvent) =>
|
|
51
|
+
trusted(event) && sandbox.application;
|
|
52
|
+
ipcMain.on("air:stat", (event, path: unknown) => {
|
|
53
|
+
event.returnValue = playing(event) && typeof path === "string" ? statOf(path) : null;
|
|
54
|
+
});
|
|
55
|
+
ipcMain.on("air:list", (event, path: unknown) => {
|
|
56
|
+
event.returnValue = playing(event) && typeof path === "string" ? listOf(path) : null;
|
|
57
|
+
});
|
|
58
|
+
// FileStream's open, which reads a file at once, as stat does: only once the application plays.
|
|
59
|
+
ipcMain.on("air:read-sync", (event, path: unknown) => {
|
|
60
|
+
event.returnValue = playing(event) && typeof path === "string" ? readOf(path) : null;
|
|
61
|
+
});
|
|
62
|
+
// EncryptedLocalStore, at once as its methods are: only the application playing's.
|
|
63
|
+
const items = (event: IpcMainEvent) => (playing(event) ? encryptedItems : null);
|
|
64
|
+
ipcMain.on("air:item-get", (event, name: unknown) => {
|
|
65
|
+
event.returnValue = typeof name === "string" ? (items(event)?.get(name) ?? null) : null;
|
|
66
|
+
});
|
|
67
|
+
ipcMain.on("air:item-set", (event, name: unknown, bytes: unknown) => {
|
|
68
|
+
if (typeof name === "string" && bytes instanceof Uint8Array) {
|
|
69
|
+
items(event)?.set(name, bytes);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
event.returnValue = null;
|
|
73
|
+
});
|
|
74
|
+
ipcMain.on("air:item-remove", (event, name: unknown) => {
|
|
75
|
+
if (typeof name === "string") {
|
|
76
|
+
items(event)?.remove(name);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
event.returnValue = null;
|
|
80
|
+
});
|
|
81
|
+
ipcMain.on("air:items-reset", (event) => {
|
|
82
|
+
items(event)?.reset();
|
|
83
|
+
event.returnValue = null;
|
|
84
|
+
});
|
|
85
|
+
// FileStream's writes and File's changes, at once as adl's: only once the application plays.
|
|
86
|
+
ipcMain.on(
|
|
87
|
+
"air:write-sync",
|
|
88
|
+
(event, path: unknown, bytes: unknown, offset: unknown, length: unknown) => {
|
|
89
|
+
event.returnValue =
|
|
90
|
+
playing(event) &&
|
|
91
|
+
typeof path === "string" &&
|
|
92
|
+
bytes instanceof Uint8Array &&
|
|
93
|
+
Number.isSafeInteger(offset) &&
|
|
94
|
+
Number.isSafeInteger(length) &&
|
|
95
|
+
(offset as number) >= 0 &&
|
|
96
|
+
(length as number) >= 0 &&
|
|
97
|
+
writeOf(path, bytes, offset as number, length as number);
|
|
98
|
+
},
|
|
99
|
+
);
|
|
100
|
+
ipcMain.on("air:create-directory", (event, path: unknown) => {
|
|
101
|
+
event.returnValue = playing(event) && typeof path === "string" && createDirectoryOf(path);
|
|
102
|
+
});
|
|
103
|
+
ipcMain.on("air:remove", (event, path: unknown) => {
|
|
104
|
+
event.returnValue = playing(event) && typeof path === "string" && removeOf(path);
|
|
105
|
+
});
|
|
106
|
+
ipcMain.on("air:move", (event, from: unknown, to: unknown) => {
|
|
107
|
+
event.returnValue =
|
|
108
|
+
playing(event) && typeof from === "string" && typeof to === "string" && moveOf(from, to);
|
|
109
|
+
});
|
|
110
|
+
// A read is what starts the application's grant: the page reads its content SWF first.
|
|
111
|
+
ipcMain.handle("air:read", async (event, path: unknown) => {
|
|
112
|
+
if (!trusted(event) || typeof path !== "string" || !air) {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
const real = await realpath(resolveCase(path));
|
|
118
|
+
return sandbox.startApplication(real) ? new Uint8Array(await readFile(real)) : null;
|
|
119
|
+
} catch {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
ipcMain.on("air:window", (event) => {
|
|
124
|
+
event.returnValue = playing(event) && window ? windowState(window) : null;
|
|
125
|
+
});
|
|
126
|
+
ipcMain.on("air:screens", (event) => {
|
|
127
|
+
event.returnValue = playing(event) ? screenStates() : [];
|
|
128
|
+
});
|
|
129
|
+
ipcMain.on("air:set-bounds", (event, bounds: unknown) => {
|
|
130
|
+
const b = bounds as { x?: unknown; y?: unknown; width?: unknown; height?: unknown } | null;
|
|
131
|
+
const n = (v: unknown) => (typeof v === "number" && Number.isFinite(v) ? Math.round(v) : null);
|
|
132
|
+
const [x, y, width, height] = [n(b?.x), n(b?.y), n(b?.width), n(b?.height)];
|
|
133
|
+
if (
|
|
134
|
+
playing(event) &&
|
|
135
|
+
window &&
|
|
136
|
+
x !== null &&
|
|
137
|
+
y !== null &&
|
|
138
|
+
width &&
|
|
139
|
+
height &&
|
|
140
|
+
width > 0 &&
|
|
141
|
+
height > 0
|
|
142
|
+
) {
|
|
143
|
+
window.setBounds({ x, y, width, height });
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
ipcMain.on("air:set-title", (event, title: unknown) => {
|
|
147
|
+
if (playing(event) && window && typeof title === "string") {
|
|
148
|
+
window.setTitle(title.slice(0, 1024));
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
ipcMain.on("air:window-do", (event, what: unknown) => {
|
|
152
|
+
if (!playing(event) || !window) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
switch (what) {
|
|
157
|
+
case "minimize":
|
|
158
|
+
window.minimize();
|
|
159
|
+
break;
|
|
160
|
+
case "maximize":
|
|
161
|
+
window.maximize();
|
|
162
|
+
break;
|
|
163
|
+
case "restore":
|
|
164
|
+
window.restore();
|
|
165
|
+
break;
|
|
166
|
+
case "activate":
|
|
167
|
+
window.focus();
|
|
168
|
+
break;
|
|
169
|
+
case "show":
|
|
170
|
+
window.show();
|
|
171
|
+
break;
|
|
172
|
+
case "hide":
|
|
173
|
+
window.hide();
|
|
174
|
+
break;
|
|
175
|
+
case "close":
|
|
176
|
+
window.close();
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
ipcMain.on("air:exit", (event, code: unknown) => {
|
|
181
|
+
if (playing(event)) {
|
|
182
|
+
app.exit(typeof code === "number" ? code | 0 : 0);
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// The app's dialogs: an error, File › Open, the library chooser, and the
|
|
2
|
+
// URL dialog, a window of its own.
|
|
3
|
+
import { basename } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { BrowserWindow, dialog, type IpcMainEvent, type IpcMainInvokeEvent } from "electron";
|
|
6
|
+
import type { LibraryName } from "../shared/api.js";
|
|
7
|
+
import { buildMenu } from "./menu.ts";
|
|
8
|
+
import { openChosen, readStart } from "./open.ts";
|
|
9
|
+
import { APP_ORIGIN } from "./protocol.ts";
|
|
10
|
+
import { settings, window } from "./state.ts";
|
|
11
|
+
|
|
12
|
+
const promptPreload = fileURLToPath(new URL("../preload/prompt.cjs", import.meta.url));
|
|
13
|
+
const PROMPT_URL = `${APP_ORIGIN}/open-url.html`;
|
|
14
|
+
|
|
15
|
+
/** The dialog that asks for a URL, while it is open. */
|
|
16
|
+
export let prompt: BrowserWindow | null = null;
|
|
17
|
+
|
|
18
|
+
export function refuse(message: string, detail: string): void {
|
|
19
|
+
if (window) {
|
|
20
|
+
void dialog.showMessageBox(window, { type: "error", message, detail });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function showOpenDialog(): Promise<void> {
|
|
25
|
+
if (!window) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const result = await dialog.showOpenDialog(window, {
|
|
30
|
+
title: "Open a SWF or an AIR application",
|
|
31
|
+
properties: ["openFile"],
|
|
32
|
+
filters: [
|
|
33
|
+
{ name: "SWF and AIR application descriptors", extensions: ["swf", "xml"] },
|
|
34
|
+
{ name: "All files", extensions: ["*"] },
|
|
35
|
+
],
|
|
36
|
+
});
|
|
37
|
+
if (!result.canceled && result.filePaths[0]) {
|
|
38
|
+
await openChosen(result.filePaths[0]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Ask for a library, check that it is ABC, keep its path, and start the page again with it. */
|
|
43
|
+
export async function chooseLibrary(name: LibraryName): Promise<void> {
|
|
44
|
+
if (!window) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const result = await dialog.showOpenDialog(window, {
|
|
49
|
+
title: `Choose ${name}.abc`,
|
|
50
|
+
properties: ["openFile"],
|
|
51
|
+
filters: [
|
|
52
|
+
{ name: "ActionScript bytecode", extensions: ["abc"] },
|
|
53
|
+
{ name: "All files", extensions: ["*"] },
|
|
54
|
+
],
|
|
55
|
+
});
|
|
56
|
+
const path = result.filePaths[0];
|
|
57
|
+
if (result.canceled || !path) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// An ABC starts with its minor version, then its major one, 46.
|
|
62
|
+
const head = await readStart(path, 4);
|
|
63
|
+
if (head?.[2] !== 46 || head[3] !== 0) {
|
|
64
|
+
refuse(`${basename(path)} is not an ABC file.`, `swf2es needs ${name}.abc itself.`);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!settings.setLibrary(name, path)) {
|
|
69
|
+
refuse("The settings could not be saved.", `swf2es uses ${path} until it quits.`);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
buildMenu();
|
|
73
|
+
|
|
74
|
+
// The page fetched the libraries once; a fresh page fetches the new one.
|
|
75
|
+
window.webContents.reload();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Play on the library the app ships again, in place of one the user chose. */
|
|
79
|
+
export function resetLibrary(name: LibraryName): void {
|
|
80
|
+
if (!settings.clearLibrary(name)) {
|
|
81
|
+
refuse("The settings could not be saved.", `swf2es uses its own ${name} until it quits.`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
buildMenu();
|
|
85
|
+
window?.webContents.reload();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* The dialog that asks for a SWF's URL: a window of its own, apart from the
|
|
90
|
+
* page, so that only the user, and never a SWF, opens one by its URL.
|
|
91
|
+
*/
|
|
92
|
+
export function showUrlDialog(): void {
|
|
93
|
+
if (!window) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (prompt) {
|
|
98
|
+
prompt.focus();
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const dialogWindow = new BrowserWindow({
|
|
103
|
+
parent: window,
|
|
104
|
+
modal: true,
|
|
105
|
+
width: 560,
|
|
106
|
+
height: 180,
|
|
107
|
+
resizable: false,
|
|
108
|
+
minimizable: false,
|
|
109
|
+
maximizable: false,
|
|
110
|
+
fullscreenable: false,
|
|
111
|
+
title: "Open URL",
|
|
112
|
+
show: false,
|
|
113
|
+
webPreferences: {
|
|
114
|
+
preload: promptPreload,
|
|
115
|
+
contextIsolation: true,
|
|
116
|
+
sandbox: true,
|
|
117
|
+
nodeIntegration: false,
|
|
118
|
+
webSecurity: true,
|
|
119
|
+
spellcheck: false,
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
prompt = dialogWindow;
|
|
123
|
+
dialogWindow.setMenu(null);
|
|
124
|
+
dialogWindow.on("page-title-updated", (event) => event.preventDefault());
|
|
125
|
+
dialogWindow.once("ready-to-show", () => dialogWindow.show());
|
|
126
|
+
dialogWindow.on("closed", () => {
|
|
127
|
+
if (prompt === dialogWindow) {
|
|
128
|
+
prompt = null;
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
const contents = dialogWindow.webContents;
|
|
132
|
+
contents.on("will-navigate", (event) => event.preventDefault());
|
|
133
|
+
contents.setWindowOpenHandler(() => ({ action: "deny" }));
|
|
134
|
+
void dialogWindow.loadURL(PROMPT_URL);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Whether a message comes from the URL dialog's own page. */
|
|
138
|
+
export function fromPrompt(event: IpcMainEvent | IpcMainInvokeEvent): boolean {
|
|
139
|
+
const frame = event.senderFrame;
|
|
140
|
+
return (
|
|
141
|
+
prompt !== null &&
|
|
142
|
+
event.sender === prompt.webContents &&
|
|
143
|
+
frame !== null &&
|
|
144
|
+
frame.parent === null &&
|
|
145
|
+
frame.url === PROMPT_URL
|
|
146
|
+
);
|
|
147
|
+
}
|