diff --git a/CHANGELOG.md b/CHANGELOG.md index f454749ffe..3a4a9cf285 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,47 +10,47 @@ format. #### Boot Flow -- [Boot] Verify permalink structure is actually set. ([#2902](https://github.com/WordPress/wordpress-playground/pull/2902)) +- [Boot] Verify permalink structure is actually set. ([#2902](https://github.com/WordPress/wordpress-playground/pull/2902)) ### Blueprints -- V1] Rewrite github.com/owner/repo/raw URLs. ([#2892](https://github.com/WordPress/wordpress-playground/pull/2892)) +- V1] Rewrite github.com/owner/repo/raw URLs. ([#2892](https://github.com/WordPress/wordpress-playground/pull/2892)) ### Documentation -- Document the new GitHub Preview button action. ([#2893](https://github.com/WordPress/wordpress-playground/pull/2893)) -- [Docs] Adding link at the documentation sidebar for PR preview link page. ([#2895](https://github.com/WordPress/wordpress-playground/pull/2895)) -- [Docs] Documentation Expansion for php-wasm/node. ([#2780](https://github.com/WordPress/wordpress-playground/pull/2780)) -- [Docs] Updating sidebar to add Xdebug pages. ([#2881](https://github.com/WordPress/wordpress-playground/pull/2881)) +- Document the new GitHub Preview button action. ([#2893](https://github.com/WordPress/wordpress-playground/pull/2893)) +- [Docs] Adding link at the documentation sidebar for PR preview link page. ([#2895](https://github.com/WordPress/wordpress-playground/pull/2895)) +- [Docs] Documentation Expansion for php-wasm/node. ([#2780](https://github.com/WordPress/wordpress-playground/pull/2780)) +- [Docs] Updating sidebar to add Xdebug pages. ([#2881](https://github.com/WordPress/wordpress-playground/pull/2881)) ### PHP WebAssembly -- Try avoiding URL.canParse for older version of Safari. ([#2887](https://github.com/WordPress/wordpress-playground/pull/2887)) +- Try avoiding URL.canParse for older version of Safari. ([#2887](https://github.com/WordPress/wordpress-playground/pull/2887)) ### Website -- Remove "preview WordPress core branch" feature. ([#2894](https://github.com/WordPress/wordpress-playground/pull/2894)) -- Support previewing WordPress and Gutenberg branches, not just PRs. ([#2868](https://github.com/WordPress/wordpress-playground/pull/2868)) +- Remove "preview WordPress core branch" feature. ([#2894](https://github.com/WordPress/wordpress-playground/pull/2894)) +- Support previewing WordPress and Gutenberg branches, not just PRs. ([#2868](https://github.com/WordPress/wordpress-playground/pull/2868)) ### Bug Fixes -- [CLI] Fix null and "latest" WP version resolution and improve unzip error message. ([#2889](https://github.com/WordPress/wordpress-playground/pull/2889)) -- [CLI] Fix run-cli leak which was revealed by repeated runCLI() calls during test. ([#2888](https://github.com/WordPress/wordpress-playground/pull/2888)) +- [CLI] Fix null and "latest" WP version resolution and improve unzip error message. ([#2889](https://github.com/WordPress/wordpress-playground/pull/2889)) +- [CLI] Fix run-cli leak which was revealed by repeated runCLI() calls during test. ([#2888](https://github.com/WordPress/wordpress-playground/pull/2888)) ### -- CLI] Allow API consumers to rely upon option validation and default values. ([#2883](https://github.com/WordPress/wordpress-playground/pull/2883)) +- CLI] Allow API consumers to rely upon option validation and default values. ([#2883](https://github.com/WordPress/wordpress-playground/pull/2883)) ### Various -- Minor stylistic and punctuation improvements. ([#2884](https://github.com/WordPress/wordpress-playground/pull/2884)) -- Revise error messages and coding guidelines. ([#2879](https://github.com/WordPress/wordpress-playground/pull/2879)) -- Update footer labels in localization file. ([#2878](https://github.com/WordPress/wordpress-playground/pull/2878)) -- [i18n] Add Japanese translations to Blueprints JSON and the API Client and Mount data. ([#2882](https://github.com/WordPress/wordpress-playground/pull/2882)) -- [i18n] Adding Italian translations. ([#2865](https://github.com/WordPress/wordpress-playground/pull/2865)) -- [i18n] Create contributor-day-table-lead.md for Gujarati. ([#2866](https://github.com/WordPress/wordpress-playground/pull/2866)) -- i18n: Full Translation of "Build" to Spanish. ([#2906](https://github.com/WordPress/wordpress-playground/pull/2906)) -- i18n: Minor fixes on web-instance.md Spanish translation. ([#2899](https://github.com/WordPress/wordpress-playground/pull/2899)) +- Minor stylistic and punctuation improvements. ([#2884](https://github.com/WordPress/wordpress-playground/pull/2884)) +- Revise error messages and coding guidelines. ([#2879](https://github.com/WordPress/wordpress-playground/pull/2879)) +- Update footer labels in localization file. ([#2878](https://github.com/WordPress/wordpress-playground/pull/2878)) +- [i18n] Add Japanese translations to Blueprints JSON and the API Client and Mount data. ([#2882](https://github.com/WordPress/wordpress-playground/pull/2882)) +- [i18n] Adding Italian translations. ([#2865](https://github.com/WordPress/wordpress-playground/pull/2865)) +- [i18n] Create contributor-day-table-lead.md for Gujarati. ([#2866](https://github.com/WordPress/wordpress-playground/pull/2866)) +- i18n: Full Translation of "Build" to Spanish. ([#2906](https://github.com/WordPress/wordpress-playground/pull/2906)) +- i18n: Minor fixes on web-instance.md Spanish translation. ([#2899](https://github.com/WordPress/wordpress-playground/pull/2899)) ### Contributors @@ -62,14 +62,14 @@ The following contributors merged PRs in this release: ### Bug Fixes -- Docs: Fix grammar, typos, and formatting issues across documentation. ([#2877](https://github.com/WordPress/wordpress-playground/pull/2877)) -- Docs: Fix typo in resources.md. ([#2876](https://github.com/WordPress/wordpress-playground/pull/2876)) -- docs: Fix MDN link for Access-Control-Allow-Origin header. ([#2875](https://github.com/WordPress/wordpress-playground/pull/2875)) +- Docs: Fix grammar, typos, and formatting issues across documentation. ([#2877](https://github.com/WordPress/wordpress-playground/pull/2877)) +- Docs: Fix typo in resources.md. ([#2876](https://github.com/WordPress/wordpress-playground/pull/2876)) +- docs: Fix MDN link for Access-Control-Allow-Origin header. ([#2875](https://github.com/WordPress/wordpress-playground/pull/2875)) ### Various -- [Docs] Adding ask AI Button. ([#2858](https://github.com/WordPress/wordpress-playground/pull/2858)) -- [i18n] Add Japanese translations to Blueprints JSON and the API Client. ([#2873](https://github.com/WordPress/wordpress-playground/pull/2873)) +- [Docs] Adding ask AI Button. ([#2858](https://github.com/WordPress/wordpress-playground/pull/2858)) +- [i18n] Add Japanese translations to Blueprints JSON and the API Client. ([#2873](https://github.com/WordPress/wordpress-playground/pull/2873)) ### Contributors @@ -81,25 +81,25 @@ The following contributors merged PRs in this release: ### Enhancements -- [CLI] Add --wordpress-install-mode flag. ([#2803](https://github.com/WordPress/wordpress-playground/pull/2803)) +- [CLI] Add --wordpress-install-mode flag. ([#2803](https://github.com/WordPress/wordpress-playground/pull/2803)) ### Tools #### PHP WebAssembly -- [PHP.wasm] Major overhaul of URL rewriting and setting $\_SERVER variables. ([#2864](https://github.com/WordPress/wordpress-playground/pull/2864)) +- [PHP.wasm] Major overhaul of URL rewriting and setting $\_SERVER variables. ([#2864](https://github.com/WordPress/wordpress-playground/pull/2864)) ### PHP WebAssembly -- [PHP.wasm] ImageMagick extension. ([#2834](https://github.com/WordPress/wordpress-playground/pull/2834)) +- [PHP.wasm] ImageMagick extension. ([#2834](https://github.com/WordPress/wordpress-playground/pull/2834)) ### Bug Fixes -- [CLI] Make messaging clearer for errors and Xdebug IDE integration. ([#2869](https://github.com/WordPress/wordpress-playground/pull/2869)) +- [CLI] Make messaging clearer for errors and Xdebug IDE integration. ([#2869](https://github.com/WordPress/wordpress-playground/pull/2869)) ### Various -- [Docs] Add xdebug testing page. ([#2840](https://github.com/WordPress/wordpress-playground/pull/2840)) +- [Docs] Add xdebug testing page. ([#2840](https://github.com/WordPress/wordpress-playground/pull/2840)) ### Contributors @@ -111,30 +111,30 @@ The following contributors merged PRs in this release: ### Enhancements -- [CLI] Support .0 versions, e.g. 6.4.0. ([#2848](https://github.com/WordPress/wordpress-playground/pull/2848)) +- [CLI] Support .0 versions, e.g. 6.4.0. ([#2848](https://github.com/WordPress/wordpress-playground/pull/2848)) ### Documentation -- [Docs] Remove kapa AI button. ([#2849](https://github.com/WordPress/wordpress-playground/pull/2849)) +- [Docs] Remove kapa AI button. ([#2849](https://github.com/WordPress/wordpress-playground/pull/2849)) ### PHP WebAssembly -- Fix unmount of nested mounts in PHP runtime hotswap. ([#2859](https://github.com/WordPress/wordpress-playground/pull/2859)) +- Fix unmount of nested mounts in PHP runtime hotswap. ([#2859](https://github.com/WordPress/wordpress-playground/pull/2859)) ### Website -- Controlled iframe for the latest Guteneberg version. ([#2857](https://github.com/WordPress/wordpress-playground/pull/2857)) -- [TCP Proxy] Produce the correct request path in parseHttpRequest(). ([#2852](https://github.com/WordPress/wordpress-playground/pull/2852)) +- Controlled iframe for the latest Guteneberg version. ([#2857](https://github.com/WordPress/wordpress-playground/pull/2857)) +- [TCP Proxy] Produce the correct request path in parseHttpRequest(). ([#2852](https://github.com/WordPress/wordpress-playground/pull/2852)) ### Bug Fixes -- [CLI] Avoid breaks during Playground boot when `--xdebug` enabled. ([#2835](https://github.com/WordPress/wordpress-playground/pull/2835)) -- [CLI] Fix incorrect Xdebug mappings for absolute host paths. ([#2860](https://github.com/WordPress/wordpress-playground/pull/2860)) +- [CLI] Avoid breaks during Playground boot when `--xdebug` enabled. ([#2835](https://github.com/WordPress/wordpress-playground/pull/2835)) +- [CLI] Fix incorrect Xdebug mappings for absolute host paths. ([#2860](https://github.com/WordPress/wordpress-playground/pull/2860)) ### Various -- Translate to bangla in contributing index file. ([#2851](https://github.com/WordPress/wordpress-playground/pull/2851)) -- [i18n] Add Japanese translations to Playground API Client. ([#2854](https://github.com/WordPress/wordpress-playground/pull/2854)) +- Translate to bangla in contributing index file. ([#2851](https://github.com/WordPress/wordpress-playground/pull/2851)) +- [i18n] Add Japanese translations to Playground API Client. ([#2854](https://github.com/WordPress/wordpress-playground/pull/2854)) ### Contributors @@ -146,7 +146,7 @@ The following contributors merged PRs in this release: ### PHP WebAssembly -- Remove old, unused .wasm files from @php-wasm/web. ([#2847](https://github.com/WordPress/wordpress-playground/pull/2847)) +- Remove old, unused .wasm files from @php-wasm/web. ([#2847](https://github.com/WordPress/wordpress-playground/pull/2847)) ### Contributors @@ -158,19 +158,19 @@ The following contributors merged PRs in this release: ### PHP WebAssembly -- Remove old, unused php-wasm .wasm files. ([#2846](https://github.com/WordPress/wordpress-playground/pull/2846)) +- Remove old, unused php-wasm .wasm files. ([#2846](https://github.com/WordPress/wordpress-playground/pull/2846)) ### Website -- Remove client package from the list of offline mode assets. ([#2841](https://github.com/WordPress/wordpress-playground/pull/2841)) +- Remove client package from the list of offline mode assets. ([#2841](https://github.com/WordPress/wordpress-playground/pull/2841)) ### Bug Fixes -- [CLI] Fix temp dir cleanup when Playground CLI server is killed. ([#2836](https://github.com/WordPress/wordpress-playground/pull/2836)) +- [CLI] Fix temp dir cleanup when Playground CLI server is killed. ([#2836](https://github.com/WordPress/wordpress-playground/pull/2836)) ### Various -- Translate contributor-badge page to bangla. ([#2843](https://github.com/WordPress/wordpress-playground/pull/2843)) +- Translate contributor-badge page to bangla. ([#2843](https://github.com/WordPress/wordpress-playground/pull/2843)) ### Contributors @@ -182,35 +182,35 @@ The following contributors merged PRs in this release: ### Enhancements -- [ xdebug ] Add `--experimental-unsafe-ide-integration` option in Playground CLI. ([#2777](https://github.com/WordPress/wordpress-playground/pull/2777)) +- [ xdebug ] Add `--experimental-unsafe-ide-integration` option in Playground CLI. ([#2777](https://github.com/WordPress/wordpress-playground/pull/2777)) ### Tools #### PHP WebAssembly -- Add support for AVIF in GD. ([#2814](https://github.com/WordPress/wordpress-playground/pull/2814)) +- Add support for AVIF in GD. ([#2814](https://github.com/WordPress/wordpress-playground/pull/2814)) ### Documentation -- [Docs] Adding data persistence information. ([#2798](https://github.com/WordPress/wordpress-playground/pull/2798)) -- [i18n] Adding cli flags to Portuguese and Spanish. ([#2829](https://github.com/WordPress/wordpress-playground/pull/2829)) +- [Docs] Adding data persistence information. ([#2798](https://github.com/WordPress/wordpress-playground/pull/2798)) +- [i18n] Adding cli flags to Portuguese and Spanish. ([#2829](https://github.com/WordPress/wordpress-playground/pull/2829)) ### PHP WebAssembly -- [PHP] SOAP extension. ([#2832](https://github.com/WordPress/wordpress-playground/pull/2832)) +- [PHP] SOAP extension. ([#2832](https://github.com/WordPress/wordpress-playground/pull/2832)) ### Website -- Make saved sites sidebar more narrow. ([#2826](https://github.com/WordPress/wordpress-playground/pull/2826)) -- Add refresh button to the left of address bar. ([#2828](https://github.com/WordPress/wordpress-playground/pull/2828)) -- Wider site info on smaller breakpoints. ([#2830](https://github.com/WordPress/wordpress-playground/pull/2830)) +- Make saved sites sidebar more narrow. ([#2826](https://github.com/WordPress/wordpress-playground/pull/2826)) +- Add refresh button to the left of address bar. ([#2828](https://github.com/WordPress/wordpress-playground/pull/2828)) +- Wider site info on smaller breakpoints. ([#2830](https://github.com/WordPress/wordpress-playground/pull/2830)) ### Various -- Translate documentation content to Bangla language. ([#2839](https://github.com/WordPress/wordpress-playground/pull/2839)) -- [Docs] Updating CLI flags list. ([#2812](https://github.com/WordPress/wordpress-playground/pull/2812)) -- [i18n] Adding Luganda structure. ([#2774](https://github.com/WordPress/wordpress-playground/pull/2774)) -- [i18n] Create contributor-day.md for Gujarati. ([#2791](https://github.com/WordPress/wordpress-playground/pull/2791)) +- Translate documentation content to Bangla language. ([#2839](https://github.com/WordPress/wordpress-playground/pull/2839)) +- [Docs] Updating CLI flags list. ([#2812](https://github.com/WordPress/wordpress-playground/pull/2812)) +- [i18n] Adding Luganda structure. ([#2774](https://github.com/WordPress/wordpress-playground/pull/2774)) +- [i18n] Create contributor-day.md for Gujarati. ([#2791](https://github.com/WordPress/wordpress-playground/pull/2791)) ### Contributors @@ -224,22 +224,22 @@ The following contributors merged PRs in this release: #### Import/Export -- [Blueprints] Use \_SERVER['HTTPS'] in the import step. ([#2802](https://github.com/WordPress/wordpress-playground/pull/2802)) +- [Blueprints] Use \_SERVER['HTTPS'] in the import step. ([#2802](https://github.com/WordPress/wordpress-playground/pull/2802)) ### Website -- Add Playground logo and 'import' menu to the sidebar. ([#2806](https://github.com/WordPress/wordpress-playground/pull/2806)) -- Ask for a Playground name before saving. ([#2768](https://github.com/WordPress/wordpress-playground/pull/2768)) -- File browser and code editor. ([#2813](https://github.com/WordPress/wordpress-playground/pull/2813)) -- Move the sidebar icon to the right. ([#2811](https://github.com/WordPress/wordpress-playground/pull/2811)) -- Refresh button icons next to the browser bar. ([#2807](https://github.com/WordPress/wordpress-playground/pull/2807)) -- Resizable sidebar. ([#2809](https://github.com/WordPress/wordpress-playground/pull/2809)) -- Restore the visible button selection in the sidebar. ([#2804](https://github.com/WordPress/wordpress-playground/pull/2804)) -- Retain address bar when opening the sidebar. ([#2808](https://github.com/WordPress/wordpress-playground/pull/2808)) +- Add Playground logo and 'import' menu to the sidebar. ([#2806](https://github.com/WordPress/wordpress-playground/pull/2806)) +- Ask for a Playground name before saving. ([#2768](https://github.com/WordPress/wordpress-playground/pull/2768)) +- File browser and code editor. ([#2813](https://github.com/WordPress/wordpress-playground/pull/2813)) +- Move the sidebar icon to the right. ([#2811](https://github.com/WordPress/wordpress-playground/pull/2811)) +- Refresh button icons next to the browser bar. ([#2807](https://github.com/WordPress/wordpress-playground/pull/2807)) +- Resizable sidebar. ([#2809](https://github.com/WordPress/wordpress-playground/pull/2809)) +- Restore the visible button selection in the sidebar. ([#2804](https://github.com/WordPress/wordpress-playground/pull/2804)) +- Retain address bar when opening the sidebar. ([#2808](https://github.com/WordPress/wordpress-playground/pull/2808)) ### Various -- [i18n] Add Japanese translations to `remote.html` vs `index.html`. ([#2817](https://github.com/WordPress/wordpress-playground/pull/2817)) +- [i18n] Add Japanese translations to `remote.html` vs `index.html`. ([#2817](https://github.com/WordPress/wordpress-playground/pull/2817)) ### Contributors @@ -251,7 +251,7 @@ The following contributors merged PRs in this release: ### Various -- [i18n] Add Japanese translations to JavaScript API. ([#2800](https://github.com/WordPress/wordpress-playground/pull/2800)) +- [i18n] Add Japanese translations to JavaScript API. ([#2800](https://github.com/WordPress/wordpress-playground/pull/2800)) ### Contributors @@ -263,31 +263,31 @@ The following contributors merged PRs in this release: ### Enhancements -- Playground CLI: Print temp dir and mounts when `--verbosity=debug`. ([#2799](https://github.com/WordPress/wordpress-playground/pull/2799)) +- Playground CLI: Print temp dir and mounts when `--verbosity=debug`. ([#2799](https://github.com/WordPress/wordpress-playground/pull/2799)) ### Blueprints -- Support creating a local .git directory via git:Directory resource. ([#2787](https://github.com/WordPress/wordpress-playground/pull/2787)) -- ensure git:Directory resource returns non-empty-name. ([#2779](https://github.com/WordPress/wordpress-playground/pull/2779)) +- Support creating a local .git directory via git:Directory resource. ([#2787](https://github.com/WordPress/wordpress-playground/pull/2787)) +- ensure git:Directory resource returns non-empty-name. ([#2779](https://github.com/WordPress/wordpress-playground/pull/2779)) ### Documentation -- [Docs] Adding table lead guide documentation. ([#2708](https://github.com/WordPress/wordpress-playground/pull/2708)) -- [docs] Removing deprecated run method reference. ([#2778](https://github.com/WordPress/wordpress-playground/pull/2778)) -- [i18n] Updating translation guide for Portuguese and Spanish. ([#2773](https://github.com/WordPress/wordpress-playground/pull/2773)) +- [Docs] Adding table lead guide documentation. ([#2708](https://github.com/WordPress/wordpress-playground/pull/2708)) +- [docs] Removing deprecated run method reference. ([#2778](https://github.com/WordPress/wordpress-playground/pull/2778)) +- [i18n] Updating translation guide for Portuguese and Spanish. ([#2773](https://github.com/WordPress/wordpress-playground/pull/2773)) ### Internal -- Document the rationale for setting php.ini values in wordpress/src/boot.ts. ([#2784](https://github.com/WordPress/wordpress-playground/pull/2784)) +- Document the rationale for setting php.ini values in wordpress/src/boot.ts. ([#2784](https://github.com/WordPress/wordpress-playground/pull/2784)) ### Various -- Add some improvements in the Spanish translations. ([#2788](https://github.com/WordPress/wordpress-playground/pull/2788)) -- [i18n] Add Japanese translations to Query API. ([#2781](https://github.com/WordPress/wordpress-playground/pull/2781)) -- [i18n] Adding French translation to guides/index.md. ([#2790](https://github.com/WordPress/wordpress-playground/pull/2790)) -- [i18n] Adding quick start guide and web instance pages in Spanish. ([#2785](https://github.com/WordPress/wordpress-playground/pull/2785)) -- [i18n] Fixing typos in French translation of documentation.md. ([#2792](https://github.com/WordPress/wordpress-playground/pull/2792)) -- [i18n] Updating Contributor badge and Contributor day pages. ([#2782](https://github.com/WordPress/wordpress-playground/pull/2782)) +- Add some improvements in the Spanish translations. ([#2788](https://github.com/WordPress/wordpress-playground/pull/2788)) +- [i18n] Add Japanese translations to Query API. ([#2781](https://github.com/WordPress/wordpress-playground/pull/2781)) +- [i18n] Adding French translation to guides/index.md. ([#2790](https://github.com/WordPress/wordpress-playground/pull/2790)) +- [i18n] Adding quick start guide and web instance pages in Spanish. ([#2785](https://github.com/WordPress/wordpress-playground/pull/2785)) +- [i18n] Fixing typos in French translation of documentation.md. ([#2792](https://github.com/WordPress/wordpress-playground/pull/2792)) +- [i18n] Updating Contributor badge and Contributor day pages. ([#2782](https://github.com/WordPress/wordpress-playground/pull/2782)) ### Contributors @@ -299,7 +299,7 @@ The following contributors merged PRs in this release: ### Internal -- [CI] Remove a few predefined runner files before releasing npm packages. ([#2775](https://github.com/WordPress/wordpress-playground/pull/2775)) +- [CI] Remove a few predefined runner files before releasing npm packages. ([#2775](https://github.com/WordPress/wordpress-playground/pull/2775)) ### Contributors @@ -313,54 +313,54 @@ The following contributors merged PRs in this release: ### Enhancements -- Update form-data npm dependency via package.json overrides. ([#2761](https://github.com/WordPress/wordpress-playground/pull/2761)) -- Update sha to 2.4.12. ([#2729](https://github.com/WordPress/wordpress-playground/pull/2729)) -- Update tmp package to the latest version. ([#2730](https://github.com/WordPress/wordpress-playground/pull/2730)) -- [XDebug Bridge] Read files from VFS when a PHP instance is provided. ([#2722](https://github.com/WordPress/wordpress-playground/pull/2722)) +- Update form-data npm dependency via package.json overrides. ([#2761](https://github.com/WordPress/wordpress-playground/pull/2761)) +- Update sha to 2.4.12. ([#2729](https://github.com/WordPress/wordpress-playground/pull/2729)) +- Update tmp package to the latest version. ([#2730](https://github.com/WordPress/wordpress-playground/pull/2730)) +- [XDebug Bridge] Read files from VFS when a PHP instance is provided. ([#2722](https://github.com/WordPress/wordpress-playground/pull/2722)) ### Blueprints -- Accept branch names and tags in git:Directory resource. ([#2760](https://github.com/WordPress/wordpress-playground/pull/2760)) +- Accept branch names and tags in git:Directory resource. ([#2760](https://github.com/WordPress/wordpress-playground/pull/2760)) ### Tools -- [CLI] Respond with HTTP 500 response when the request handler throws an error. ([#2715](https://github.com/WordPress/wordpress-playground/pull/2715)) +- [CLI] Respond with HTTP 500 response when the request handler throws an error. ([#2715](https://github.com/WordPress/wordpress-playground/pull/2715)) ### Documentation -- Add docblock for createInvertedReadableStream. ([#2726](https://github.com/WordPress/wordpress-playground/pull/2726)) -- Adding Kapa AI script tag. ([#2727](https://github.com/WordPress/wordpress-playground/pull/2727)) -- [Docs] Updating resources page. ([#2771](https://github.com/WordPress/wordpress-playground/pull/2771)) -- [i18n] Adding Bengali Structure. ([#2754](https://github.com/WordPress/wordpress-playground/pull/2754)) +- Add docblock for createInvertedReadableStream. ([#2726](https://github.com/WordPress/wordpress-playground/pull/2726)) +- Adding Kapa AI script tag. ([#2727](https://github.com/WordPress/wordpress-playground/pull/2727)) +- [Docs] Updating resources page. ([#2771](https://github.com/WordPress/wordpress-playground/pull/2771)) +- [i18n] Adding Bengali Structure. ([#2754](https://github.com/WordPress/wordpress-playground/pull/2754)) ### PHP WebAssembly -- [ xdebug ] Configure `xdebug` for phpstorm compatibility. ([#2747](https://github.com/WordPress/wordpress-playground/pull/2747)) +- [ xdebug ] Configure `xdebug` for phpstorm compatibility. ([#2747](https://github.com/WordPress/wordpress-playground/pull/2747)) ### Website -- Adding new icons to Playground web instance. ([#2696](https://github.com/WordPress/wordpress-playground/pull/2696)) -- Allow remote.html from same origin as Playground client script. ([#2765](https://github.com/WordPress/wordpress-playground/pull/2765)) -- Make deployment script more usable for self-hosting. ([#2764](https://github.com/WordPress/wordpress-playground/pull/2764)) +- Adding new icons to Playground web instance. ([#2696](https://github.com/WordPress/wordpress-playground/pull/2696)) +- Allow remote.html from same origin as Playground client script. ([#2765](https://github.com/WordPress/wordpress-playground/pull/2765)) +- Make deployment script more usable for self-hosting. ([#2764](https://github.com/WordPress/wordpress-playground/pull/2764)) ### Internal -- Add Dependabot configuration for npm updates. ([#2733](https://github.com/WordPress/wordpress-playground/pull/2733)) -- [Meta] Fix package-lock.json after dependabot. ([#2745](https://github.com/WordPress/wordpress-playground/pull/2745)) +- Add Dependabot configuration for npm updates. ([#2733](https://github.com/WordPress/wordpress-playground/pull/2733)) +- [Meta] Fix package-lock.json after dependabot. ([#2745](https://github.com/WordPress/wordpress-playground/pull/2745)) ### Bug Fixes -- Fixing old documentation regarding PHP code examples. ([#2721](https://github.com/WordPress/wordpress-playground/pull/2721)) -- [i18n] Fix issue related to link in french translation. ([#2748](https://github.com/WordPress/wordpress-playground/pull/2748)) +- Fixing old documentation regarding PHP code examples. ([#2721](https://github.com/WordPress/wordpress-playground/pull/2721)) +- [i18n] Fix issue related to link in french translation. ([#2748](https://github.com/WordPress/wordpress-playground/pull/2748)) ### Various -- Deploy web app less often to reduce cache invalidation. ([#2762](https://github.com/WordPress/wordpress-playground/pull/2762)) -- [Meta] Fix package-lock.json after dependabot. ([#2746](https://github.com/WordPress/wordpress-playground/pull/2746)) -- [i18n] Add Japanese translations to APIs overview. ([#2770](https://github.com/WordPress/wordpress-playground/pull/2770)) -- [i18n] Add translation to page title in resources.md. ([#2728](https://github.com/WordPress/wordpress-playground/pull/2728)) -- [i18n] Adding French translation to intro.md. ([#2724](https://github.com/WordPress/wordpress-playground/pull/2724)) -- [i18n] Fixing typos in French translation quick-start-guide.md. ([#2725](https://github.com/WordPress/wordpress-playground/pull/2725)) +- Deploy web app less often to reduce cache invalidation. ([#2762](https://github.com/WordPress/wordpress-playground/pull/2762)) +- [Meta] Fix package-lock.json after dependabot. ([#2746](https://github.com/WordPress/wordpress-playground/pull/2746)) +- [i18n] Add Japanese translations to APIs overview. ([#2770](https://github.com/WordPress/wordpress-playground/pull/2770)) +- [i18n] Add translation to page title in resources.md. ([#2728](https://github.com/WordPress/wordpress-playground/pull/2728)) +- [i18n] Adding French translation to intro.md. ([#2724](https://github.com/WordPress/wordpress-playground/pull/2724)) +- [i18n] Fixing typos in French translation quick-start-guide.md. ([#2725](https://github.com/WordPress/wordpress-playground/pull/2725)) ### Contributors @@ -372,13 +372,13 @@ The following contributors merged PRs in this release: ### Tools -- Fix local package repository command running issue. ([#2720](https://github.com/WordPress/wordpress-playground/pull/2720)) +- Fix local package repository command running issue. ([#2720](https://github.com/WordPress/wordpress-playground/pull/2720)) ### Various -- [i18n] Added Gujarati Translation for Local Development 02-vscode-extension.md File. ([#2718](https://github.com/WordPress/wordpress-playground/pull/2718)) -- [i18n] Added Gujarati Translation for Local Development 03-php-wasm-node File. ([#2719](https://github.com/WordPress/wordpress-playground/pull/2719)) -- docs: Add browser support information to limitations documentation. ([#2711](https://github.com/WordPress/wordpress-playground/pull/2711)) +- [i18n] Added Gujarati Translation for Local Development 02-vscode-extension.md File. ([#2718](https://github.com/WordPress/wordpress-playground/pull/2718)) +- [i18n] Added Gujarati Translation for Local Development 03-php-wasm-node File. ([#2719](https://github.com/WordPress/wordpress-playground/pull/2719)) +- docs: Add browser support information to limitations documentation. ([#2711](https://github.com/WordPress/wordpress-playground/pull/2711)) ### Contributors @@ -390,19 +390,19 @@ The following contributors merged PRs in this release: ### Documentation -- [i18n] Added Gujarati Translation for Documentation Contributions. ([#2610](https://github.com/WordPress/wordpress-playground/pull/2610)) +- [i18n] Added Gujarati Translation for Documentation Contributions. ([#2610](https://github.com/WordPress/wordpress-playground/pull/2610)) ### Website -- [PHP Playground] Attach client to https://playground.wordpress.net/remote.html. ([#2717](https://github.com/WordPress/wordpress-playground/pull/2717)) +- [PHP Playground] Attach client to https://playground.wordpress.net/remote.html. ([#2717](https://github.com/WordPress/wordpress-playground/pull/2717)) ### Internal -- Add name to Playground Website and Website extras cli packages. ([#2716](https://github.com/WordPress/wordpress-playground/pull/2716)) +- Add name to Playground Website and Website extras cli packages. ([#2716](https://github.com/WordPress/wordpress-playground/pull/2716)) ### Various -- [i18n] Fixing typos in French translation of quick-start-guide.md. ([#2712](https://github.com/WordPress/wordpress-playground/pull/2712)) +- [i18n] Fixing typos in French translation of quick-start-guide.md. ([#2712](https://github.com/WordPress/wordpress-playground/pull/2712)) ### Contributors @@ -416,37 +416,37 @@ The following contributors merged PRs in this release: #### PHP WebAssembly -- [PHP] Add "ls" and "pwd" CLI commands. ([#2701](https://github.com/WordPress/wordpress-playground/pull/2701)) +- [PHP] Add "ls" and "pwd" CLI commands. ([#2701](https://github.com/WordPress/wordpress-playground/pull/2701)) ### Documentation -- Revert Quick guide to the English version. ([#2709](https://github.com/WordPress/wordpress-playground/pull/2709)) -- [i18n] Add French translation for quick-start-guide.md. ([#2710](https://github.com/WordPress/wordpress-playground/pull/2710)) +- Revert Quick guide to the English version. ([#2709](https://github.com/WordPress/wordpress-playground/pull/2709)) +- [i18n] Add French translation for quick-start-guide.md. ([#2710](https://github.com/WordPress/wordpress-playground/pull/2710)) ### PHP WebAssembly -- Preserve chroot across all worker-managed PHP instances. ([#2704](https://github.com/WordPress/wordpress-playground/pull/2704)) -- [PHP] Allow removing CWD during runtime rotation. ([#2714](https://github.com/WordPress/wordpress-playground/pull/2714)) -- [PHP] Do not reap() PHP in the worker until the streaming response ends. ([#2703](https://github.com/WordPress/wordpress-playground/pull/2703)) -- [PHP] Move registerWorkerListeners() from a specific worker to the parent PHPWorker. ([#2705](https://github.com/WordPress/wordpress-playground/pull/2705)) -- [PHP] Support subprocesses in cli() calls. ([#2702](https://github.com/WordPress/wordpress-playground/pull/2702)) +- Preserve chroot across all worker-managed PHP instances. ([#2704](https://github.com/WordPress/wordpress-playground/pull/2704)) +- [PHP] Allow removing CWD during runtime rotation. ([#2714](https://github.com/WordPress/wordpress-playground/pull/2714)) +- [PHP] Do not reap() PHP in the worker until the streaming response ends. ([#2703](https://github.com/WordPress/wordpress-playground/pull/2703)) +- [PHP] Move registerWorkerListeners() from a specific worker to the parent PHPWorker. ([#2705](https://github.com/WordPress/wordpress-playground/pull/2705)) +- [PHP] Support subprocesses in cli() calls. ([#2702](https://github.com/WordPress/wordpress-playground/pull/2702)) ### Website -- IDE-like PHP playground. ([#2699](https://github.com/WordPress/wordpress-playground/pull/2699)) +- IDE-like PHP playground. ([#2699](https://github.com/WordPress/wordpress-playground/pull/2699)) ### Internal -- [PHP utils] Export splitShellCommand. ([#2706](https://github.com/WordPress/wordpress-playground/pull/2706)) +- [PHP utils] Export splitShellCommand. ([#2706](https://github.com/WordPress/wordpress-playground/pull/2706)) ### Bug Fixes -- CORS proxy: Fix custom origin validation during deployment. ([#2698](https://github.com/WordPress/wordpress-playground/pull/2698)) +- CORS proxy: Fix custom origin validation during deployment. ([#2698](https://github.com/WordPress/wordpress-playground/pull/2698)) ### Various -- [i18] Add French translation for launch.md. ([#2697](https://github.com/WordPress/wordpress-playground/pull/2697)) -- [i18n] Add French translation for quick-start-guide.md. ([#2692](https://github.com/WordPress/wordpress-playground/pull/2692)) +- [i18] Add French translation for launch.md. ([#2697](https://github.com/WordPress/wordpress-playground/pull/2697)) +- [i18n] Add French translation for quick-start-guide.md. ([#2692](https://github.com/WordPress/wordpress-playground/pull/2692)) ### Contributors @@ -458,16 +458,16 @@ The following contributors merged PRs in this release: ### Documentation -- [i18n] Add French translation for resources.md. ([#2680](https://github.com/WordPress/wordpress-playground/pull/2680)) +- [i18n] Add French translation for resources.md. ([#2680](https://github.com/WordPress/wordpress-playground/pull/2680)) ### Website -- [Client] Enable calling playground.runStream() and .cli() from the client. ([#2688](https://github.com/WordPress/wordpress-playground/pull/2688)) +- [Client] Enable calling playground.runStream() and .cli() from the client. ([#2688](https://github.com/WordPress/wordpress-playground/pull/2688)) ### Various -- Update Playground JS API tutorial Link. ([#2685](https://github.com/WordPress/wordpress-playground/pull/2685)) -- [i18n] Add Japanese translations to Playground CLI. ([#2683](https://github.com/WordPress/wordpress-playground/pull/2683)) +- Update Playground JS API tutorial Link. ([#2685](https://github.com/WordPress/wordpress-playground/pull/2685)) +- [i18n] Add Japanese translations to Playground CLI. ([#2683](https://github.com/WordPress/wordpress-playground/pull/2683)) ### Contributors @@ -479,7 +479,7 @@ The following contributors merged PRs in this release: ### Bug Fixes -- Playground CLI: Log unhandled rejections and stop them from crashing workers. ([#2682](https://github.com/WordPress/wordpress-playground/pull/2682)) +- Playground CLI: Log unhandled rejections and stop them from crashing workers. ([#2682](https://github.com/WordPress/wordpress-playground/pull/2682)) ### Contributors @@ -493,17 +493,17 @@ The following contributors merged PRs in this release: #### GitHub integration -- [CLI] Polyfill the Buffer class without making it an empty object in CLI. ([#2681](https://github.com/WordPress/wordpress-playground/pull/2681)) +- [CLI] Polyfill the Buffer class without making it an empty object in CLI. ([#2681](https://github.com/WordPress/wordpress-playground/pull/2681)) ### PHP WebAssembly #### Website -- [Website] Disable curl_share_init by default (to make Composer work). ([#2679](https://github.com/WordPress/wordpress-playground/pull/2679)) +- [Website] Disable curl_share_init by default (to make Composer work). ([#2679](https://github.com/WordPress/wordpress-playground/pull/2679)) ### Website -- Resolve the Blueprint declaration for the 'View Blueprint' button. ([#2675](https://github.com/WordPress/wordpress-playground/pull/2675)) +- Resolve the Blueprint declaration for the 'View Blueprint' button. ([#2675](https://github.com/WordPress/wordpress-playground/pull/2675)) ### Contributors @@ -515,30 +515,30 @@ The following contributors merged PRs in this release: ### Blueprints -- Replace randomString() with randomFilename() in installAsset(). ([#2677](https://github.com/WordPress/wordpress-playground/pull/2677)) +- Replace randomString() with randomFilename() in installAsset(). ([#2677](https://github.com/WordPress/wordpress-playground/pull/2677)) ### Documentation -- [Docs] Adding steps to translate documentation with GitHub UI. ([#2666](https://github.com/WordPress/wordpress-playground/pull/2666)) -- [i18n] Add French translation for documentation.md. ([#2670](https://github.com/WordPress/wordpress-playground/pull/2670)) -- [i18n] Adding Architecture page to Brazilian Portuguese. ([#2667](https://github.com/WordPress/wordpress-playground/pull/2667)) +- [Docs] Adding steps to translate documentation with GitHub UI. ([#2666](https://github.com/WordPress/wordpress-playground/pull/2666)) +- [i18n] Add French translation for documentation.md. ([#2670](https://github.com/WordPress/wordpress-playground/pull/2670)) +- [i18n] Adding Architecture page to Brazilian Portuguese. ([#2667](https://github.com/WordPress/wordpress-playground/pull/2667)) ### PHP WebAssembly -- [PHP Worker] listen to all PHP instances events via worker.addEventListener(). ([#2673](https://github.com/WordPress/wordpress-playground/pull/2673)) +- [PHP Worker] listen to all PHP instances events via worker.addEventListener(). ([#2673](https://github.com/WordPress/wordpress-playground/pull/2673)) ### Website #### Blueprints -- Flatten the stored runtime configuration format. ([#2671](https://github.com/WordPress/wordpress-playground/pull/2671)) -- Report Blueprint v2 progress. ([#2674](https://github.com/WordPress/wordpress-playground/pull/2674)) -- [Blueprints] Separate computing the runtime configuration from compiling a Blueprint. ([#2672](https://github.com/WordPress/wordpress-playground/pull/2672)) +- Flatten the stored runtime configuration format. ([#2671](https://github.com/WordPress/wordpress-playground/pull/2671)) +- Report Blueprint v2 progress. ([#2674](https://github.com/WordPress/wordpress-playground/pull/2674)) +- [Blueprints] Separate computing the runtime configuration from compiling a Blueprint. ([#2672](https://github.com/WordPress/wordpress-playground/pull/2672)) ### Various -- [i18n] Add Japanese translations to VS Code extension. ([#2668](https://github.com/WordPress/wordpress-playground/pull/2668)) -- [i18n] Add Japanese translations to php-wasm/node. ([#2669](https://github.com/WordPress/wordpress-playground/pull/2669)) +- [i18n] Add Japanese translations to VS Code extension. ([#2668](https://github.com/WordPress/wordpress-playground/pull/2668)) +- [i18n] Add Japanese translations to php-wasm/node. ([#2669](https://github.com/WordPress/wordpress-playground/pull/2669)) ### Contributors @@ -550,24 +550,24 @@ The following contributors merged PRs in this release: ### Blueprints -- [Website] Split Playground remote initialization logic into Blueprint-version specific workers. ([#2652](https://github.com/WordPress/wordpress-playground/pull/2652)) +- [Website] Split Playground remote initialization logic into Blueprint-version specific workers. ([#2652](https://github.com/WordPress/wordpress-playground/pull/2652)) ### Documentation -- [i18n] Added Gujarati Translation for Local Development 01-wp-now.md file. ([#2664](https://github.com/WordPress/wordpress-playground/pull/2664)) +- [i18n] Added Gujarati Translation for Local Development 01-wp-now.md file. ([#2664](https://github.com/WordPress/wordpress-playground/pull/2664)) ### Website #### Blueprints -- Add Blueprint v2 handlers (noop). ([#2657](https://github.com/WordPress/wordpress-playground/pull/2657)) -- Declare the correct Blueprints v2 types. ([#2655](https://github.com/WordPress/wordpress-playground/pull/2655)) -- Isolate resolveBlueprintFromURL() calls. ([#2654](https://github.com/WordPress/wordpress-playground/pull/2654)) -- [Client] Expose Blueprints v2 runner via a feature flag. ([#2658](https://github.com/WordPress/wordpress-playground/pull/2658)) +- Add Blueprint v2 handlers (noop). ([#2657](https://github.com/WordPress/wordpress-playground/pull/2657)) +- Declare the correct Blueprints v2 types. ([#2655](https://github.com/WordPress/wordpress-playground/pull/2655)) +- Isolate resolveBlueprintFromURL() calls. ([#2654](https://github.com/WordPress/wordpress-playground/pull/2654)) +- [Client] Expose Blueprints v2 runner via a feature flag. ([#2658](https://github.com/WordPress/wordpress-playground/pull/2658)) ### Various -- [i18n] Added Missing Description in Intro and Quick Start Guide Pages for Gujarati Language. ([#2660](https://github.com/WordPress/wordpress-playground/pull/2660)) +- [i18n] Added Missing Description in Intro and Quick Start Guide Pages for Gujarati Language. ([#2660](https://github.com/WordPress/wordpress-playground/pull/2660)) ### Contributors @@ -579,7 +579,7 @@ The following contributors merged PRs in this release: ### Blueprints -- [Client] Explicit Blueprints v1 handler. ([#2651](https://github.com/WordPress/wordpress-playground/pull/2651)) +- [Client] Explicit Blueprints v1 handler. ([#2651](https://github.com/WordPress/wordpress-playground/pull/2651)) ### Contributors @@ -593,55 +593,55 @@ The following contributors merged PRs in this release: #### Blueprints -- [Blueprints] Rename Blueprints v1 types, add Blueprint v2 types. ([#2648](https://github.com/WordPress/wordpress-playground/pull/2648)) +- [Blueprints] Rename Blueprints v1 types, add Blueprint v2 types. ([#2648](https://github.com/WordPress/wordpress-playground/pull/2648)) ### Blueprints -- Move Blueprints v1-specific files to v1 subdirectory. ([#2644](https://github.com/WordPress/wordpress-playground/pull/2644)) -- Rename BlueprintDeclaration to BlueprintV1Declaration. ([#2645](https://github.com/WordPress/wordpress-playground/pull/2645)) -- V1] Use the wordpress-importer plugin for the importWxr step. ([#2640](https://github.com/WordPress/wordpress-playground/pull/2640)) +- Move Blueprints v1-specific files to v1 subdirectory. ([#2644](https://github.com/WordPress/wordpress-playground/pull/2644)) +- Rename BlueprintDeclaration to BlueprintV1Declaration. ([#2645](https://github.com/WordPress/wordpress-playground/pull/2645)) +- V1] Use the wordpress-importer plugin for the importWxr step. ([#2640](https://github.com/WordPress/wordpress-playground/pull/2640)) ### Documentation -- [i18n] Added Gujarati Translation for 01 What are Blueprints and What you can do with them File. ([#2617](https://github.com/WordPress/wordpress-playground/pull/2617)) -- [i18n] Added Gujarati Translation for Local Development Intro.md file. ([#2623](https://github.com/WordPress/wordpress-playground/pull/2623)) -- [i18n] Tagalog translations for using blueprints page. ([#2628](https://github.com/WordPress/wordpress-playground/pull/2628)) -- [i18n] Tagalog translations of API Consistency. ([#2629](https://github.com/WordPress/wordpress-playground/pull/2629)) -- [i18n] Tagalog version of Blueprints/Steps/Shorthands. ([#2630](https://github.com/WordPress/wordpress-playground/pull/2630)) +- [i18n] Added Gujarati Translation for 01 What are Blueprints and What you can do with them File. ([#2617](https://github.com/WordPress/wordpress-playground/pull/2617)) +- [i18n] Added Gujarati Translation for Local Development Intro.md file. ([#2623](https://github.com/WordPress/wordpress-playground/pull/2623)) +- [i18n] Tagalog translations for using blueprints page. ([#2628](https://github.com/WordPress/wordpress-playground/pull/2628)) +- [i18n] Tagalog translations of API Consistency. ([#2629](https://github.com/WordPress/wordpress-playground/pull/2629)) +- [i18n] Tagalog version of Blueprints/Steps/Shorthands. ([#2630](https://github.com/WordPress/wordpress-playground/pull/2630)) ### Experiments #### PHP WebAssembly -- Playground CLI: Mount /wordpress, /internal, and /tmp dirs within real temporary dir. ([#2446](https://github.com/WordPress/wordpress-playground/pull/2446)) +- Playground CLI: Mount /wordpress, /internal, and /tmp dirs within real temporary dir. ([#2446](https://github.com/WordPress/wordpress-playground/pull/2446)) ### PHP WebAssembly -- Function mismatch fix in GD jpeg extension for PHP below 8.0. ([#2634](https://github.com/WordPress/wordpress-playground/pull/2634)) -- [PHP] Add unit tests for nested mounts. ([#2639](https://github.com/WordPress/wordpress-playground/pull/2639)) +- Function mismatch fix in GD jpeg extension for PHP below 8.0. ([#2634](https://github.com/WordPress/wordpress-playground/pull/2634)) +- [PHP] Add unit tests for nested mounts. ([#2639](https://github.com/WordPress/wordpress-playground/pull/2639)) ### Website -- [WordPress] Separate bootWordPress() from bootRequestHandler(). ([#2650](https://github.com/WordPress/wordpress-playground/pull/2650)) +- [WordPress] Separate bootWordPress() from bootRequestHandler(). ([#2650](https://github.com/WordPress/wordpress-playground/pull/2650)) #### Blueprints -- [Blueprints] Log step names without parsing. ([#2649](https://github.com/WordPress/wordpress-playground/pull/2649)) +- [Blueprints] Log step names without parsing. ([#2649](https://github.com/WordPress/wordpress-playground/pull/2649)) ### Bug Fixes -- [Xdebug Bridge] Fix issue if non existent file is read. ([#2625](https://github.com/WordPress/wordpress-playground/pull/2625)) +- [Xdebug Bridge] Fix issue if non existent file is read. ([#2625](https://github.com/WordPress/wordpress-playground/pull/2625)) ### Reliability -- Fix Playground CLI boot from native dirs on Windows. ([#2642](https://github.com/WordPress/wordpress-playground/pull/2642)) +- Fix Playground CLI boot from native dirs on Windows. ([#2642](https://github.com/WordPress/wordpress-playground/pull/2642)) ### Various -- Keep wordpress-importer.zip for older versions of Playground. ([#2647](https://github.com/WordPress/wordpress-playground/pull/2647)) -- Update build.md. ([#2638](https://github.com/WordPress/wordpress-playground/pull/2638)) -- [Documentation] Adding troubleshooting sections for WP-CLI database connections. ([#2333](https://github.com/WordPress/wordpress-playground/pull/2333)) -- [i18n] Add Japanese translations to wp-now NPM package. ([#2615](https://github.com/WordPress/wordpress-playground/pull/2615)) +- Keep wordpress-importer.zip for older versions of Playground. ([#2647](https://github.com/WordPress/wordpress-playground/pull/2647)) +- Update build.md. ([#2638](https://github.com/WordPress/wordpress-playground/pull/2638)) +- [Documentation] Adding troubleshooting sections for WP-CLI database connections. ([#2333](https://github.com/WordPress/wordpress-playground/pull/2333)) +- [i18n] Add Japanese translations to wp-now NPM package. ([#2615](https://github.com/WordPress/wordpress-playground/pull/2615)) ### Contributors @@ -653,7 +653,7 @@ The following contributors merged PRs in this release: ### Enhancements -- Statically analyzable build. ([#2632](https://github.com/WordPress/wordpress-playground/pull/2632)) +- Statically analyzable build. ([#2632](https://github.com/WordPress/wordpress-playground/pull/2632)) ### Contributors @@ -665,7 +665,7 @@ The following contributors merged PRs in this release: ### Enhancements -- [CLI] Build worker thread with stable filenames. ([#2631](https://github.com/WordPress/wordpress-playground/pull/2631)) +- [CLI] Build worker thread with stable filenames. ([#2631](https://github.com/WordPress/wordpress-playground/pull/2631)) ### Contributors @@ -679,20 +679,20 @@ The following contributors merged PRs in this release: #### Blueprints -- Fix to ensure that Site Editor templates are associated with the correct taxonomy upon import. ([#2584](https://github.com/WordPress/wordpress-playground/pull/2584)) +- Fix to ensure that Site Editor templates are associated with the correct taxonomy upon import. ([#2584](https://github.com/WordPress/wordpress-playground/pull/2584)) ### PHP WebAssembly -- Translate 'localhost' to 127.0.0.1 in MySQL connections. ([#2627](https://github.com/WordPress/wordpress-playground/pull/2627)) -- [PHP] Rebuild with sync fd_close on the web. ([#2620](https://github.com/WordPress/wordpress-playground/pull/2620)) +- Translate 'localhost' to 127.0.0.1 in MySQL connections. ([#2627](https://github.com/WordPress/wordpress-playground/pull/2627)) +- [PHP] Rebuild with sync fd_close on the web. ([#2620](https://github.com/WordPress/wordpress-playground/pull/2620)) ### Website -- [Web Client] Remove onBeforeBlueprint. ([#2622](https://github.com/WordPress/wordpress-playground/pull/2622)) +- [Web Client] Remove onBeforeBlueprint. ([#2622](https://github.com/WordPress/wordpress-playground/pull/2622)) ### Internal -- [CI] Do not block CI tests on linter. ([#2619](https://github.com/WordPress/wordpress-playground/pull/2619)) +- [CI] Do not block CI tests on linter. ([#2619](https://github.com/WordPress/wordpress-playground/pull/2619)) ### Contributors @@ -704,11 +704,11 @@ The following contributors merged PRs in this release: ### PHP WebAssembly -- [Intl] Correct intl errors during compilation and build. ([#2613](https://github.com/WordPress/wordpress-playground/pull/2613)) +- [Intl] Correct intl errors during compilation and build. ([#2613](https://github.com/WordPress/wordpress-playground/pull/2613)) ### Bug Fixes -- Playground CLI: Skip WP install when using existing WP files. ([#2616](https://github.com/WordPress/wordpress-playground/pull/2616)) +- Playground CLI: Skip WP install when using existing WP files. ([#2616](https://github.com/WordPress/wordpress-playground/pull/2616)) ### Contributors @@ -720,14 +720,14 @@ The following contributors merged PRs in this release: ### Documentation -- Added Gujarati Translation for Code.md File. ([#2606](https://github.com/WordPress/wordpress-playground/pull/2606)) -- Tagalog translations of Blueprints -> Blueprint Data Format. ([#2609](https://github.com/WordPress/wordpress-playground/pull/2609)) -- [Translations] Adding local environment section to pt-BR. ([#2572](https://github.com/WordPress/wordpress-playground/pull/2572)) +- Added Gujarati Translation for Code.md File. ([#2606](https://github.com/WordPress/wordpress-playground/pull/2606)) +- Tagalog translations of Blueprints -> Blueprint Data Format. ([#2609](https://github.com/WordPress/wordpress-playground/pull/2609)) +- [Translations] Adding local environment section to pt-BR. ([#2572](https://github.com/WordPress/wordpress-playground/pull/2572)) ### Bug Fixes -- Fixing header from Gujarati translation. ([#2614](https://github.com/WordPress/wordpress-playground/pull/2614)) -- [Xdebug Bridge] Fix create hash error in xdebug bridge. ([#2612](https://github.com/WordPress/wordpress-playground/pull/2612)) +- Fixing header from Gujarati translation. ([#2614](https://github.com/WordPress/wordpress-playground/pull/2614)) +- [Xdebug Bridge] Fix create hash error in xdebug bridge. ([#2612](https://github.com/WordPress/wordpress-playground/pull/2612)) ### Contributors @@ -739,12 +739,12 @@ The following contributors merged PRs in this release: ### Documentation -- Add Japanese translations to Local Development. ([#2604](https://github.com/WordPress/wordpress-playground/pull/2604)) +- Add Japanese translations to Local Development. ([#2604](https://github.com/WordPress/wordpress-playground/pull/2604)) ### Various -- Added Gujarati Translation for Blueprints Tutorials Index.md file. ([#2607](https://github.com/WordPress/wordpress-playground/pull/2607)) -- Added Gujarati Translation for How to Run Blueprints. ([#2611](https://github.com/WordPress/wordpress-playground/pull/2611)) +- Added Gujarati Translation for Blueprints Tutorials Index.md file. ([#2607](https://github.com/WordPress/wordpress-playground/pull/2607)) +- Added Gujarati Translation for How to Run Blueprints. ([#2611](https://github.com/WordPress/wordpress-playground/pull/2611)) ### Contributors @@ -756,48 +756,48 @@ The following contributors merged PRs in this release: ### Enhancements -- Add structured issue templates for bugs, enhancements, and documentation. ([#2571](https://github.com/WordPress/wordpress-playground/pull/2571)) -- Allow installing multiple themes via URL, as required by parent/child themes. ([#2581](https://github.com/WordPress/wordpress-playground/pull/2581)) +- Add structured issue templates for bugs, enhancements, and documentation. ([#2571](https://github.com/WordPress/wordpress-playground/pull/2571)) +- Allow installing multiple themes via URL, as required by parent/child themes. ([#2581](https://github.com/WordPress/wordpress-playground/pull/2581)) ### Blueprints -- Move blueprints.phar to the Blueprints package. ([#2471](https://github.com/WordPress/wordpress-playground/pull/2471)) -- Move runBlueprintV2 to the blueprints package. ([#2594](https://github.com/WordPress/wordpress-playground/pull/2594)) +- Move blueprints.phar to the Blueprints package. ([#2471](https://github.com/WordPress/wordpress-playground/pull/2471)) +- Move runBlueprintV2 to the blueprints package. ([#2594](https://github.com/WordPress/wordpress-playground/pull/2594)) ### Tools -- [XDebug Bridge] Highlight syntax of php scripts from mime type in Devtools. ([#2566](https://github.com/WordPress/wordpress-playground/pull/2566)) -- [XDebug Bridge] Load files in Devtools before running PHP with Xdebug enabled. ([#2527](https://github.com/WordPress/wordpress-playground/pull/2527)) +- [XDebug Bridge] Highlight syntax of php scripts from mime type in Devtools. ([#2566](https://github.com/WordPress/wordpress-playground/pull/2566)) +- [XDebug Bridge] Load files in Devtools before running PHP with Xdebug enabled. ([#2527](https://github.com/WordPress/wordpress-playground/pull/2527)) ### Documentation -- Added Gujarati Translation for Index.md File. ([#2576](https://github.com/WordPress/wordpress-playground/pull/2576)) -- Added Gujarati Translation for JSON API and Function API File. ([#2577](https://github.com/WordPress/wordpress-playground/pull/2577)) -- Adding french translation guide. ([#2541](https://github.com/WordPress/wordpress-playground/pull/2541)) -- Adding more internal links between pages. ([#2499](https://github.com/WordPress/wordpress-playground/pull/2499)) -- Adding reference to multiple theme URL parameter. ([#2593](https://github.com/WordPress/wordpress-playground/pull/2593)) -- Adding runCLI section to the Playground CLI page. ([#2583](https://github.com/WordPress/wordpress-playground/pull/2583)) -- Updating runCLI demo at wp-playground/cli README file. ([#2553](https://github.com/WordPress/wordpress-playground/pull/2553)) -- Updating wp versions blueprints. ([#2573](https://github.com/WordPress/wordpress-playground/pull/2573)) -- [Docs] Adding how to contribute to the WordPress Playground. ([#2597](https://github.com/WordPress/wordpress-playground/pull/2597)) +- Added Gujarati Translation for Index.md File. ([#2576](https://github.com/WordPress/wordpress-playground/pull/2576)) +- Added Gujarati Translation for JSON API and Function API File. ([#2577](https://github.com/WordPress/wordpress-playground/pull/2577)) +- Adding french translation guide. ([#2541](https://github.com/WordPress/wordpress-playground/pull/2541)) +- Adding more internal links between pages. ([#2499](https://github.com/WordPress/wordpress-playground/pull/2499)) +- Adding reference to multiple theme URL parameter. ([#2593](https://github.com/WordPress/wordpress-playground/pull/2593)) +- Adding runCLI section to the Playground CLI page. ([#2583](https://github.com/WordPress/wordpress-playground/pull/2583)) +- Updating runCLI demo at wp-playground/cli README file. ([#2553](https://github.com/WordPress/wordpress-playground/pull/2553)) +- Updating wp versions blueprints. ([#2573](https://github.com/WordPress/wordpress-playground/pull/2573)) +- [Docs] Adding how to contribute to the WordPress Playground. ([#2597](https://github.com/WordPress/wordpress-playground/pull/2597)) ### PHP WebAssembly -- Increase file locking safety. ([#2506](https://github.com/WordPress/wordpress-playground/pull/2506)) -- [ php-wasm ] Add `intl` dynamic extension to @php-wasm/node ASYNCIFY #2501. ([#2557](https://github.com/WordPress/wordpress-playground/pull/2557)) -- [PHP] Expose php.cli() on the web. ([#2590](https://github.com/WordPress/wordpress-playground/pull/2590)) -- [PHP] Include CLI SAPI in the web PHP.wasm build. ([#2589](https://github.com/WordPress/wordpress-playground/pull/2589)) -- [PHP] Inline rotatePHPRuntime() into the PHP class. ([#2559](https://github.com/WordPress/wordpress-playground/pull/2559)) -- [PHP] Rotate the spawn handler in hotSwapPHPRuntime(). ([#2588](https://github.com/WordPress/wordpress-playground/pull/2588)) +- Increase file locking safety. ([#2506](https://github.com/WordPress/wordpress-playground/pull/2506)) +- [ php-wasm ] Add `intl` dynamic extension to @php-wasm/node ASYNCIFY #2501. ([#2557](https://github.com/WordPress/wordpress-playground/pull/2557)) +- [PHP] Expose php.cli() on the web. ([#2590](https://github.com/WordPress/wordpress-playground/pull/2590)) +- [PHP] Include CLI SAPI in the web PHP.wasm build. ([#2589](https://github.com/WordPress/wordpress-playground/pull/2589)) +- [PHP] Inline rotatePHPRuntime() into the PHP class. ([#2559](https://github.com/WordPress/wordpress-playground/pull/2559)) +- [PHP] Rotate the spawn handler in hotSwapPHPRuntime(). ([#2588](https://github.com/WordPress/wordpress-playground/pull/2588)) ### Website -- A specific error when a GitHub artifact is not found. ([#2596](https://github.com/WordPress/wordpress-playground/pull/2596)) -- Apply base URLs to relative redirection URLs. ([#2595](https://github.com/WordPress/wordpress-playground/pull/2595)) +- A specific error when a GitHub artifact is not found. ([#2596](https://github.com/WordPress/wordpress-playground/pull/2596)) +- Apply base URLs to relative redirection URLs. ([#2595](https://github.com/WordPress/wordpress-playground/pull/2595)) ### Various -- Add Japanese translations to Quick Start Guide for Developers. ([#2587](https://github.com/WordPress/wordpress-playground/pull/2587)) +- Add Japanese translations to Quick Start Guide for Developers. ([#2587](https://github.com/WordPress/wordpress-playground/pull/2587)) ### Contributors @@ -809,17 +809,17 @@ The following contributors merged PRs in this release: ### Documentation -- Added Gujarati Translation for intro-devs.md file. ([#2574](https://github.com/WordPress/wordpress-playground/pull/2574)) +- Added Gujarati Translation for intro-devs.md file. ([#2574](https://github.com/WordPress/wordpress-playground/pull/2574)) ### Experiments #### File Synchronization -- [Website] Renaming stored Playgrounds. ([#2486](https://github.com/WordPress/wordpress-playground/pull/2486)) +- [Website] Renaming stored Playgrounds. ([#2486](https://github.com/WordPress/wordpress-playground/pull/2486)) ### Bug Fixes -- Fix error from adding blank target to external links. ([#2575](https://github.com/WordPress/wordpress-playground/pull/2575)) +- Fix error from adding blank target to external links. ([#2575](https://github.com/WordPress/wordpress-playground/pull/2575)) ### Contributors @@ -831,14 +831,14 @@ The following contributors merged PRs in this release: ### PHP WebAssembly -- Add test to verify mount() correctly handles files (closes #503). ([#2564](https://github.com/WordPress/wordpress-playground/pull/2564)) -- Use unique tmp.zip filename in unzipFile() to avoid conflicts in async calls. ([#2567](https://github.com/WordPress/wordpress-playground/pull/2567)) -- [ php-wasm ] Add `intl` dynamic extension to @php-wasm/node JSPI. ([#2501](https://github.com/WordPress/wordpress-playground/pull/2501)) -- [WordPress][CLI] Allow requesting internal URLs via http_request_host_is_external. ([#2569](https://github.com/WordPress/wordpress-playground/pull/2569)) +- Add test to verify mount() correctly handles files (closes #503). ([#2564](https://github.com/WordPress/wordpress-playground/pull/2564)) +- Use unique tmp.zip filename in unzipFile() to avoid conflicts in async calls. ([#2567](https://github.com/WordPress/wordpress-playground/pull/2567)) +- [ php-wasm ] Add `intl` dynamic extension to @php-wasm/node JSPI. ([#2501](https://github.com/WordPress/wordpress-playground/pull/2501)) +- [WordPress][CLI] Allow requesting internal URLs via http_request_host_is_external. ([#2569](https://github.com/WordPress/wordpress-playground/pull/2569)) ### Various -- Tagalog translations of Blueprints -> Tutorial -> Build Your 1st Blueprint. ([#2546](https://github.com/WordPress/wordpress-playground/pull/2546)) +- Tagalog translations of Blueprints -> Tutorial -> Build Your 1st Blueprint. ([#2546](https://github.com/WordPress/wordpress-playground/pull/2546)) ### Contributors @@ -850,32 +850,32 @@ The following contributors merged PRs in this release: ### Enhancements -- [CLI] --site-url option for Playground CLI. ([#2558](https://github.com/WordPress/wordpress-playground/pull/2558)) +- [CLI] --site-url option for Playground CLI. ([#2558](https://github.com/WordPress/wordpress-playground/pull/2558)) ### Tools -- [XDebug Bridge] Fetch all array keys when inspecting an array. ([#2409](https://github.com/WordPress/wordpress-playground/pull/2409)) +- [XDebug Bridge] Fetch all array keys when inspecting an array. ([#2409](https://github.com/WordPress/wordpress-playground/pull/2409)) ### PHP WebAssembly -- [PHP web] Export setErrNo() to make `less` work as pager. ([#2554](https://github.com/WordPress/wordpress-playground/pull/2554)) +- [PHP web] Export setErrNo() to make `less` work as pager. ([#2554](https://github.com/WordPress/wordpress-playground/pull/2554)) ### Website -- [Web] tolerate empty e.target in addTargetBlankToExternalLinks. ([#2555](https://github.com/WordPress/wordpress-playground/pull/2555)) +- [Web] tolerate empty e.target in addTargetBlankToExternalLinks. ([#2555](https://github.com/WordPress/wordpress-playground/pull/2555)) ### Bug Fixes -- Playground CLI: Wire up execution modes for Blueprints v2. ([#2519](https://github.com/WordPress/wordpress-playground/pull/2519)) +- Playground CLI: Wire up execution modes for Blueprints v2. ([#2519](https://github.com/WordPress/wordpress-playground/pull/2519)) ### Reliability -- [php-wasm-logger] Filter logs by severity in Logger and assign severity based on verbosity argument in CLIs. ([#2436](https://github.com/WordPress/wordpress-playground/pull/2436)) +- [php-wasm-logger] Filter logs by severity in Logger and assign severity based on verbosity argument in CLIs. ([#2436](https://github.com/WordPress/wordpress-playground/pull/2436)) ### Various -- Added Gujarati Translation for Index.md file. ([#2550](https://github.com/WordPress/wordpress-playground/pull/2550)) -- Use SQLite AST driver also with Blueprints v2. ([#2538](https://github.com/WordPress/wordpress-playground/pull/2538)) +- Added Gujarati Translation for Index.md file. ([#2550](https://github.com/WordPress/wordpress-playground/pull/2550)) +- Use SQLite AST driver also with Blueprints v2. ([#2538](https://github.com/WordPress/wordpress-playground/pull/2538)) ### Contributors @@ -887,22 +887,22 @@ The following contributors merged PRs in this release: ### Enhancements -- Playground CLI: Support --auto-mount=path option. ([#2525](https://github.com/WordPress/wordpress-playground/pull/2525)) +- Playground CLI: Support --auto-mount=path option. ([#2525](https://github.com/WordPress/wordpress-playground/pull/2525)) ### Documentation -- Added Gujarati Translation for Contributor Badge File. ([#2549](https://github.com/WordPress/wordpress-playground/pull/2549)) -- Added Gujarati Translation for coding-standards.md file. ([#2507](https://github.com/WordPress/wordpress-playground/pull/2507)) -- Japanese translations: Blueprints Unifying assets folder. ([#2536](https://github.com/WordPress/wordpress-playground/pull/2536)) -- Updating Translation Documentation Page. ([#2534](https://github.com/WordPress/wordpress-playground/pull/2534)) +- Added Gujarati Translation for Contributor Badge File. ([#2549](https://github.com/WordPress/wordpress-playground/pull/2549)) +- Added Gujarati Translation for coding-standards.md file. ([#2507](https://github.com/WordPress/wordpress-playground/pull/2507)) +- Japanese translations: Blueprints Unifying assets folder. ([#2536](https://github.com/WordPress/wordpress-playground/pull/2536)) +- Updating Translation Documentation Page. ([#2534](https://github.com/WordPress/wordpress-playground/pull/2534)) ### Various -- Add Japanese translations to WordPress Playground Developers documentation. ([#2551](https://github.com/WordPress/wordpress-playground/pull/2551)) -- Add Japanese translations to WordPress Playground badge. ([#2545](https://github.com/WordPress/wordpress-playground/pull/2545)) -- Added Gujarati translation for about, build, test, launch pages. ([#2533](https://github.com/WordPress/wordpress-playground/pull/2533)) -- Added Original Comment and Description in Launch.md file. ([#2542](https://github.com/WordPress/wordpress-playground/pull/2542)) -- Tagalog translations of Blueprints -> Getting Started. ([#2547](https://github.com/WordPress/wordpress-playground/pull/2547)) +- Add Japanese translations to WordPress Playground Developers documentation. ([#2551](https://github.com/WordPress/wordpress-playground/pull/2551)) +- Add Japanese translations to WordPress Playground badge. ([#2545](https://github.com/WordPress/wordpress-playground/pull/2545)) +- Added Gujarati translation for about, build, test, launch pages. ([#2533](https://github.com/WordPress/wordpress-playground/pull/2533)) +- Added Original Comment and Description in Launch.md file. ([#2542](https://github.com/WordPress/wordpress-playground/pull/2542)) +- Tagalog translations of Blueprints -> Getting Started. ([#2547](https://github.com/WordPress/wordpress-playground/pull/2547)) ### Contributors @@ -916,26 +916,26 @@ The following contributors merged PRs in this release: #### Blueprints -- [Blueprints] Use the local worker in Builder in development mode. ([#2495](https://github.com/WordPress/wordpress-playground/pull/2495)) +- [Blueprints] Use the local worker in Builder in development mode. ([#2495](https://github.com/WordPress/wordpress-playground/pull/2495)) ### Documentation -- Adding blueprints documentation description. ([#2524](https://github.com/WordPress/wordpress-playground/pull/2524)) +- Adding blueprints documentation description. ([#2524](https://github.com/WordPress/wordpress-playground/pull/2524)) ### PHP WebAssembly -- Fix corrupt zip download from Site Editor export. ([#2531](https://github.com/WordPress/wordpress-playground/pull/2531)) +- Fix corrupt zip download from Site Editor export. ([#2531](https://github.com/WordPress/wordpress-playground/pull/2531)) ### Bug Fixes -- Fix wrong license page within the languages es, pt-BR and ja. ([#2483](https://github.com/WordPress/wordpress-playground/pull/2483)) +- Fix wrong license page within the languages es, pt-BR and ja. ([#2483](https://github.com/WordPress/wordpress-playground/pull/2483)) ### Various -- Add Japanese translations to Build your first Blueprint. ([#2529](https://github.com/WordPress/wordpress-playground/pull/2529)) -- Add Japanese translations to How to run Blueprints. ([#2526](https://github.com/WordPress/wordpress-playground/pull/2526)) -- Added Gujarati Translation for web-instance.md file. ([#2532](https://github.com/WordPress/wordpress-playground/pull/2532)) -- Unifying assets folder. ([#2521](https://github.com/WordPress/wordpress-playground/pull/2521)) +- Add Japanese translations to Build your first Blueprint. ([#2529](https://github.com/WordPress/wordpress-playground/pull/2529)) +- Add Japanese translations to How to run Blueprints. ([#2526](https://github.com/WordPress/wordpress-playground/pull/2526)) +- Added Gujarati Translation for web-instance.md file. ([#2532](https://github.com/WordPress/wordpress-playground/pull/2532)) +- Unifying assets folder. ([#2521](https://github.com/WordPress/wordpress-playground/pull/2521)) ### Contributors @@ -947,36 +947,36 @@ The following contributors merged PRs in this release: ### Documentation -- Add Japanese translations to Blueprints 101 and What are Blueprints?. ([#2511](https://github.com/WordPress/wordpress-playground/pull/2511)) -- Adding the documentation meta description to the main folder. ([#2504](https://github.com/WordPress/wordpress-playground/pull/2504)) -- Translating fragments documentation and adding Contributor badge page. ([#2503](https://github.com/WordPress/wordpress-playground/pull/2503)) -- Add GitDirectoryReference resource documentation. ([#2492](https://github.com/WordPress/wordpress-playground/pull/2492)) +- Add Japanese translations to Blueprints 101 and What are Blueprints?. ([#2511](https://github.com/WordPress/wordpress-playground/pull/2511)) +- Adding the documentation meta description to the main folder. ([#2504](https://github.com/WordPress/wordpress-playground/pull/2504)) +- Translating fragments documentation and adding Contributor badge page. ([#2503](https://github.com/WordPress/wordpress-playground/pull/2503)) +- Add GitDirectoryReference resource documentation. ([#2492](https://github.com/WordPress/wordpress-playground/pull/2492)) ### PHP WebAssembly -- Re-enable and fix native file locking tests. ([#2505](https://github.com/WordPress/wordpress-playground/pull/2505)) +- Re-enable and fix native file locking tests. ([#2505](https://github.com/WordPress/wordpress-playground/pull/2505)) ### Website #### Documentation -- Fix customize bundle instructions in "Host Own Playground" documentation. ([#2510](https://github.com/WordPress/wordpress-playground/pull/2510)) +- Fix customize bundle instructions in "Host Own Playground" documentation. ([#2510](https://github.com/WordPress/wordpress-playground/pull/2510)) ### Bug Fixes -- Fix: "referrences" should be "references". ([#2514](https://github.com/WordPress/wordpress-playground/pull/2514)) +- Fix: "referrences" should be "references". ([#2514](https://github.com/WordPress/wordpress-playground/pull/2514)) ### Various -- Add Japanese documentation meta description to the main folder. ([#2518](https://github.com/WordPress/wordpress-playground/pull/2518)) -- Add Japanese translations to Introduction. ([#2489](https://github.com/WordPress/wordpress-playground/pull/2489)) -- Add docs-description blueprints tutorial and What are Blueprints?. ([#2512](https://github.com/WordPress/wordpress-playground/pull/2512)) -- Added Gujarati Translation for Launch.md file. ([#2480](https://github.com/WordPress/wordpress-playground/pull/2480)) -- Added Gujarati Translation for quick-start-guide.md. ([#2494](https://github.com/WordPress/wordpress-playground/pull/2494)) -- Adding Contributor Badge page at the documentation. ([#2491](https://github.com/WordPress/wordpress-playground/pull/2491)) -- Tagalog translations of Blueprints -> Tutorial -> What are Blueprints?. ([#2520](https://github.com/WordPress/wordpress-playground/pull/2520)) -- Translation: Blueprints -> Tutorial -> How to run Blueprints. ([#2522](https://github.com/WordPress/wordpress-playground/pull/2522)) -- Updated Typos in contributor-badge.md File. ([#2493](https://github.com/WordPress/wordpress-playground/pull/2493)) +- Add Japanese documentation meta description to the main folder. ([#2518](https://github.com/WordPress/wordpress-playground/pull/2518)) +- Add Japanese translations to Introduction. ([#2489](https://github.com/WordPress/wordpress-playground/pull/2489)) +- Add docs-description blueprints tutorial and What are Blueprints?. ([#2512](https://github.com/WordPress/wordpress-playground/pull/2512)) +- Added Gujarati Translation for Launch.md file. ([#2480](https://github.com/WordPress/wordpress-playground/pull/2480)) +- Added Gujarati Translation for quick-start-guide.md. ([#2494](https://github.com/WordPress/wordpress-playground/pull/2494)) +- Adding Contributor Badge page at the documentation. ([#2491](https://github.com/WordPress/wordpress-playground/pull/2491)) +- Tagalog translations of Blueprints -> Tutorial -> What are Blueprints?. ([#2520](https://github.com/WordPress/wordpress-playground/pull/2520)) +- Translation: Blueprints -> Tutorial -> How to run Blueprints. ([#2522](https://github.com/WordPress/wordpress-playground/pull/2522)) +- Updated Typos in contributor-badge.md File. ([#2493](https://github.com/WordPress/wordpress-playground/pull/2493)) ### Contributors @@ -988,32 +988,32 @@ The following contributors merged PRs in this release: ### **Breaking Changes** -- [Website] Default demo content. ([#2412](https://github.com/WordPress/wordpress-playground/pull/2412)) +- [Website] Default demo content. ([#2412](https://github.com/WordPress/wordpress-playground/pull/2412)) ### Enhancements -- [PHP Playground] Select WordPress version. ([#2472](https://github.com/WordPress/wordpress-playground/pull/2472)) +- [PHP Playground] Select WordPress version. ([#2472](https://github.com/WordPress/wordpress-playground/pull/2472)) ### Blueprints -- [WordPress] Support auto-login with customize.php as a landing page. ([#2467](https://github.com/WordPress/wordpress-playground/pull/2467)) +- [WordPress] Support auto-login with customize.php as a landing page. ([#2467](https://github.com/WordPress/wordpress-playground/pull/2467)) ### Documentation -- Tagalog: Add translations for Blueprints Tutorial. ([#2477](https://github.com/WordPress/wordpress-playground/pull/2477)) -- Tagalog: Translations of Blueprints documentation page. ([#2476](https://github.com/WordPress/wordpress-playground/pull/2476)) +- Tagalog: Add translations for Blueprints Tutorial. ([#2477](https://github.com/WordPress/wordpress-playground/pull/2477)) +- Tagalog: Translations of Blueprints documentation page. ([#2476](https://github.com/WordPress/wordpress-playground/pull/2476)) ### Website -- Open external links in a new tab/window. ([#2468](https://github.com/WordPress/wordpress-playground/pull/2468)) +- Open external links in a new tab/window. ([#2468](https://github.com/WordPress/wordpress-playground/pull/2468)) ### Internal -- Skip flaky end-to-end tests. ([#2475](https://github.com/WordPress/wordpress-playground/pull/2475)) +- Skip flaky end-to-end tests. ([#2475](https://github.com/WordPress/wordpress-playground/pull/2475)) ### Various -- Add Japanese translations to Blueprint Examples and Troubleshoot and debug. ([#2474](https://github.com/WordPress/wordpress-playground/pull/2474)) +- Add Japanese translations to Blueprint Examples and Troubleshoot and debug. ([#2474](https://github.com/WordPress/wordpress-playground/pull/2474)) ### Contributors @@ -1025,27 +1025,27 @@ The following contributors merged PRs in this release: ### Blueprints -- Fallback to URL-based file name when fetching remote ZIP files. ([#2470](https://github.com/WordPress/wordpress-playground/pull/2470)) +- Fallback to URL-based file name when fetching remote ZIP files. ([#2470](https://github.com/WordPress/wordpress-playground/pull/2470)) ### Documentation -- [Docs] Adding Resources, Web instance, and guides pages on Brazilian Portuguese. ([#2351](https://github.com/WordPress/wordpress-playground/pull/2351)) -- [Docs] Enabling language switcher. ([#2465](https://github.com/WordPress/wordpress-playground/pull/2465)) +- [Docs] Adding Resources, Web instance, and guides pages on Brazilian Portuguese. ([#2351](https://github.com/WordPress/wordpress-playground/pull/2351)) +- [Docs] Enabling language switcher. ([#2465](https://github.com/WordPress/wordpress-playground/pull/2465)) ### PHP WebAssembly -- Fix resolving mounted symlinks in secondary PHP instances. ([#2444](https://github.com/WordPress/wordpress-playground/pull/2444)) -- [XDebug Bridge] List additional ASYNCIFY_ONLY functions to prevent `unreachable` crashes when using Devtools. ([#2454](https://github.com/WordPress/wordpress-playground/pull/2454)) +- Fix resolving mounted symlinks in secondary PHP instances. ([#2444](https://github.com/WordPress/wordpress-playground/pull/2444)) +- [XDebug Bridge] List additional ASYNCIFY_ONLY functions to prevent `unreachable` crashes when using Devtools. ([#2454](https://github.com/WordPress/wordpress-playground/pull/2454)) ### Website -- [Browser] Do not use the Buffer class in web browsers. ([#2469](https://github.com/WordPress/wordpress-playground/pull/2469)) -- Add PHP Playground. ([#2463](https://github.com/WordPress/wordpress-playground/pull/2463)) -- Suppress PHP warnings when pre-fetching WordPress updates. ([#2458](https://github.com/WordPress/wordpress-playground/pull/2458)) +- [Browser] Do not use the Buffer class in web browsers. ([#2469](https://github.com/WordPress/wordpress-playground/pull/2469)) +- Add PHP Playground. ([#2463](https://github.com/WordPress/wordpress-playground/pull/2463)) +- Suppress PHP warnings when pre-fetching WordPress updates. ([#2458](https://github.com/WordPress/wordpress-playground/pull/2458)) ### Bug Fixes -- Fix invalid filename "<7.4" on Windows. ([#2461](https://github.com/WordPress/wordpress-playground/pull/2461)) +- Fix invalid filename "<7.4" on Windows. ([#2461](https://github.com/WordPress/wordpress-playground/pull/2461)) ### Contributors @@ -1057,29 +1057,29 @@ The following contributors merged PRs in this release: ### Tools -- [ CLI ] Rename CLI binaries in `@php-wasm/cli` and `@wp-playground/cli`. ([#2441](https://github.com/WordPress/wordpress-playground/pull/2441)) +- [ CLI ] Rename CLI binaries in `@php-wasm/cli` and `@wp-playground/cli`. ([#2441](https://github.com/WordPress/wordpress-playground/pull/2441)) ### Documentation -- Updating Docusaurus version from 3.7 to 3.8. ([#2457](https://github.com/WordPress/wordpress-playground/pull/2457)) -- [Docs] Adding fixes to broken URLs. ([#2451](https://github.com/WordPress/wordpress-playground/pull/2451)) -- [Docs] Bump PHP version to avoid WordPress PHP version Warning. ([#2443](https://github.com/WordPress/wordpress-playground/pull/2443)) +- Updating Docusaurus version from 3.7 to 3.8. ([#2457](https://github.com/WordPress/wordpress-playground/pull/2457)) +- [Docs] Adding fixes to broken URLs. ([#2451](https://github.com/WordPress/wordpress-playground/pull/2451)) +- [Docs] Bump PHP version to avoid WordPress PHP version Warning. ([#2443](https://github.com/WordPress/wordpress-playground/pull/2443)) ### PHP WebAssembly -- Patch the premature "request in progress" semaphore release. ([#2455](https://github.com/WordPress/wordpress-playground/pull/2455)) +- Patch the premature "request in progress" semaphore release. ([#2455](https://github.com/WordPress/wordpress-playground/pull/2455)) ### Bug Fixes -- Re-enable Playground CLI tests. ([#2445](https://github.com/WordPress/wordpress-playground/pull/2445)) +- Re-enable Playground CLI tests. ([#2445](https://github.com/WordPress/wordpress-playground/pull/2445)) ### Various -- Add check for SQLite driver missing in target folder. ([#2440](https://github.com/WordPress/wordpress-playground/pull/2440)) -- Adding CLI reference to Playground README. ([#2433](https://github.com/WordPress/wordpress-playground/pull/2433)) -- Adding Gujarati Intro documentation. ([#2450](https://github.com/WordPress/wordpress-playground/pull/2450)) -- Bump WordPress old version demo to version 6.2.1. ([#2460](https://github.com/WordPress/wordpress-playground/pull/2460)) -- Removing blog references on Docusaurus. ([#2456](https://github.com/WordPress/wordpress-playground/pull/2456)) +- Add check for SQLite driver missing in target folder. ([#2440](https://github.com/WordPress/wordpress-playground/pull/2440)) +- Adding CLI reference to Playground README. ([#2433](https://github.com/WordPress/wordpress-playground/pull/2433)) +- Adding Gujarati Intro documentation. ([#2450](https://github.com/WordPress/wordpress-playground/pull/2450)) +- Bump WordPress old version demo to version 6.2.1. ([#2460](https://github.com/WordPress/wordpress-playground/pull/2460)) +- Removing blog references on Docusaurus. ([#2456](https://github.com/WordPress/wordpress-playground/pull/2456)) ### Contributors @@ -1091,20 +1091,20 @@ The following contributors merged PRs in this release: ### Documentation -- Adding Contribution pages Spanish translation. ([#2431](https://github.com/WordPress/wordpress-playground/pull/2431)) +- Adding Contribution pages Spanish translation. ([#2431](https://github.com/WordPress/wordpress-playground/pull/2431)) ### PHP WebAssembly -- Fix file locking for PROXYFS nodes that wrap NODEFS. ([#2437](https://github.com/WordPress/wordpress-playground/pull/2437)) +- Fix file locking for PROXYFS nodes that wrap NODEFS. ([#2437](https://github.com/WordPress/wordpress-playground/pull/2437)) ### Bug Fixes -- Translations: Fix command typo in docs. ([#2449](https://github.com/WordPress/wordpress-playground/pull/2449)) +- Translations: Fix command typo in docs. ([#2449](https://github.com/WordPress/wordpress-playground/pull/2449)) ### Various -- Add Japanese translations to Blueprint Bundles and API Consistency. ([#2438](https://github.com/WordPress/wordpress-playground/pull/2438)) -- Translations: Clean up version from PR #2336. ([#2448](https://github.com/WordPress/wordpress-playground/pull/2448)) +- Add Japanese translations to Blueprint Bundles and API Consistency. ([#2438](https://github.com/WordPress/wordpress-playground/pull/2438)) +- Translations: Clean up version from PR #2336. ([#2448](https://github.com/WordPress/wordpress-playground/pull/2448)) ### Contributors @@ -1116,11 +1116,11 @@ The following contributors merged PRs in this release: ### Bug Fixes -- Fix fcntl() F_GETLK fatal due to undefined flock struct address. ([#2432](https://github.com/WordPress/wordpress-playground/pull/2432)) +- Fix fcntl() F_GETLK fatal due to undefined flock struct address. ([#2432](https://github.com/WordPress/wordpress-playground/pull/2432)) ### Various -- Add Japanese translations to contributing index and sidebar. ([#2434](https://github.com/WordPress/wordpress-playground/pull/2434)) +- Add Japanese translations to contributing index and sidebar. ([#2434](https://github.com/WordPress/wordpress-playground/pull/2434)) ### Contributors @@ -1134,32 +1134,32 @@ The following contributors merged PRs in this release: #### Blueprints -- Distribute @wp-playground/client without any package.json dependencies. ([#2426](https://github.com/WordPress/wordpress-playground/pull/2426)) +- Distribute @wp-playground/client without any package.json dependencies. ([#2426](https://github.com/WordPress/wordpress-playground/pull/2426)) ### Tools -- Fix ESLint 9 linting in VSCode. ([#2417](https://github.com/WordPress/wordpress-playground/pull/2417)) -- [ xdebug ] Add `--experimental-devtools` option in Playground CLI. ([#2411](https://github.com/WordPress/wordpress-playground/pull/2411)) +- Fix ESLint 9 linting in VSCode. ([#2417](https://github.com/WordPress/wordpress-playground/pull/2417)) +- [ xdebug ] Add `--experimental-devtools` option in Playground CLI. ([#2411](https://github.com/WordPress/wordpress-playground/pull/2411)) ### PHP WebAssembly -- [PHP] Dispatch request.error for all non-zero-exit request handler errors. ([#2429](https://github.com/WordPress/wordpress-playground/pull/2429)) +- [PHP] Dispatch request.error for all non-zero-exit request handler errors. ([#2429](https://github.com/WordPress/wordpress-playground/pull/2429)) ### Website -- Query Monitor plugin support. ([#2415](https://github.com/WordPress/wordpress-playground/pull/2415)) +- Query Monitor plugin support. ([#2415](https://github.com/WordPress/wordpress-playground/pull/2415)) ### Internal -- Skip flaky end-to-end tests in Firefox and Webkit. ([#2425](https://github.com/WordPress/wordpress-playground/pull/2425)) +- Skip flaky end-to-end tests in Firefox and Webkit. ([#2425](https://github.com/WordPress/wordpress-playground/pull/2425)) ### Bug Fixes -- [Xdebug Bridge] Correct error related to unresolved promises in bridge. ([#2422](https://github.com/WordPress/wordpress-playground/pull/2422)) +- [Xdebug Bridge] Correct error related to unresolved promises in bridge. ([#2422](https://github.com/WordPress/wordpress-playground/pull/2422)) ### Various -- Documentation add sidebar to blueprints bundles. ([#2397](https://github.com/WordPress/wordpress-playground/pull/2397)) +- Documentation add sidebar to blueprints bundles. ([#2397](https://github.com/WordPress/wordpress-playground/pull/2397)) ### Contributors @@ -1171,11 +1171,11 @@ The following contributors merged PRs in this release: ### Tools -- [ xdebug ] Add `--experimental-devtools` option in php-wasm CLI. ([#2408](https://github.com/WordPress/wordpress-playground/pull/2408)) +- [ xdebug ] Add `--experimental-devtools` option in php-wasm CLI. ([#2408](https://github.com/WordPress/wordpress-playground/pull/2408)) ### Bug Fixes -- Playground CLI Allow /wordpress subdirs to be mounted before WP install. ([#2382](https://github.com/WordPress/wordpress-playground/pull/2382)) +- Playground CLI Allow /wordpress subdirs to be mounted before WP install. ([#2382](https://github.com/WordPress/wordpress-playground/pull/2382)) ### Contributors @@ -1189,15 +1189,15 @@ The following contributors merged PRs in this release: #### PHP WebAssembly -- [ xdebug ] Bridge DBGP session with CDP server. ([#2402](https://github.com/WordPress/wordpress-playground/pull/2402)) +- [ xdebug ] Bridge DBGP session with CDP server. ([#2402](https://github.com/WordPress/wordpress-playground/pull/2402)) ### Internal -- [Build] Preserve optionalDependencies in built package.json. ([#2410](https://github.com/WordPress/wordpress-playground/pull/2410)) +- [Build] Preserve optionalDependencies in built package.json. ([#2410](https://github.com/WordPress/wordpress-playground/pull/2410)) ### -- Comlink] Throw the original error in the error handler. ([#2407](https://github.com/WordPress/wordpress-playground/pull/2407)) +- Comlink] Throw the original error in the error handler. ([#2407](https://github.com/WordPress/wordpress-playground/pull/2407)) ### Contributors @@ -1209,7 +1209,7 @@ The following contributors merged PRs in this release: ### Blueprints -- Rewrite paths in the wp-cli step. Improve error reporting. ([#2406](https://github.com/WordPress/wordpress-playground/pull/2406)) +- Rewrite paths in the wp-cli step. Improve error reporting. ([#2406](https://github.com/WordPress/wordpress-playground/pull/2406)) ### Contributors @@ -1221,36 +1221,36 @@ The following contributors merged PRs in this release: ### Enhancements -- [Playground CLI] Improve error reporting. ([#2401](https://github.com/WordPress/wordpress-playground/pull/2401)) -- [Playground CLI] Kebab-case yargs options declarations. ([#2399](https://github.com/WordPress/wordpress-playground/pull/2399)) +- [Playground CLI] Improve error reporting. ([#2401](https://github.com/WordPress/wordpress-playground/pull/2401)) +- [Playground CLI] Kebab-case yargs options declarations. ([#2399](https://github.com/WordPress/wordpress-playground/pull/2399)) ### Blueprints -- Expose Blueprints v2 runner in Playground CLI. ([#2394](https://github.com/WordPress/wordpress-playground/pull/2394)) -- Extract Blueprint v1-specific parts of Playground CLI. ([#2392](https://github.com/WordPress/wordpress-playground/pull/2392)) -- [Playground CLI] Separate Blueprints v1 and Blueprints v2 code paths. ([#2396](https://github.com/WordPress/wordpress-playground/pull/2396)) +- Expose Blueprints v2 runner in Playground CLI. ([#2394](https://github.com/WordPress/wordpress-playground/pull/2394)) +- Extract Blueprint v1-specific parts of Playground CLI. ([#2392](https://github.com/WordPress/wordpress-playground/pull/2392)) +- [Playground CLI] Separate Blueprints v1 and Blueprints v2 code paths. ([#2396](https://github.com/WordPress/wordpress-playground/pull/2396)) ### Tools -- [XDebug] Add a mock @php-wasm/xdebug-bridge package. ([#2398](https://github.com/WordPress/wordpress-playground/pull/2398)) +- [XDebug] Add a mock @php-wasm/xdebug-bridge package. ([#2398](https://github.com/WordPress/wordpress-playground/pull/2398)) ### Documentation -- Adding Brazilian Portuguese translation for developer documentation. ([#2391](https://github.com/WordPress/wordpress-playground/pull/2391)) +- Adding Brazilian Portuguese translation for developer documentation. ([#2391](https://github.com/WordPress/wordpress-playground/pull/2391)) ### Website -- [Remote] Use CORS proxy in embedded Playgrounds. ([#2369](https://github.com/WordPress/wordpress-playground/pull/2369)) +- [Remote] Use CORS proxy in embedded Playgrounds. ([#2369](https://github.com/WordPress/wordpress-playground/pull/2369)) ### Bug Fixes -- CLI: Fix --login option and "landingPage" Blueprint property. ([#2344](https://github.com/WordPress/wordpress-playground/pull/2344)) +- CLI: Fix --login option and "landingPage" Blueprint property. ([#2344](https://github.com/WordPress/wordpress-playground/pull/2344)) ### Various -- Add Japanese translations to steps and steps shorthands. ([#2386](https://github.com/WordPress/wordpress-playground/pull/2386)) -- Add OPCache support. ([#2400](https://github.com/WordPress/wordpress-playground/pull/2400)) -- [Node] Gracefully handle connection errors in the outbound network proxy. ([#2370](https://github.com/WordPress/wordpress-playground/pull/2370)) +- Add Japanese translations to steps and steps shorthands. ([#2386](https://github.com/WordPress/wordpress-playground/pull/2386)) +- Add OPCache support. ([#2400](https://github.com/WordPress/wordpress-playground/pull/2400)) +- [Node] Gracefully handle connection errors in the outbound network proxy. ([#2370](https://github.com/WordPress/wordpress-playground/pull/2370)) ### Contributors @@ -1262,60 +1262,60 @@ The following contributors merged PRs in this release: ### Enhancements -- [Playground CLI] Consolidate auto mounting logic. ([#2360](https://github.com/WordPress/wordpress-playground/pull/2360)) -- [Playground CLI] Move mounting code to mount.ts. ([#2362](https://github.com/WordPress/wordpress-playground/pull/2362)) +- [Playground CLI] Consolidate auto mounting logic. ([#2360](https://github.com/WordPress/wordpress-playground/pull/2360)) +- [Playground CLI] Move mounting code to mount.ts. ([#2362](https://github.com/WordPress/wordpress-playground/pull/2362)) ### Blueprints -- [CLI] Move Blueprints v2 to Playground CLI package. ([#2364](https://github.com/WordPress/wordpress-playground/pull/2364)) +- [CLI] Move Blueprints v2 to Playground CLI package. ([#2364](https://github.com/WordPress/wordpress-playground/pull/2364)) ### Public API #### Blueprints -- [Client] Accept wasm.wordpress.net as an official origin. ([#2368](https://github.com/WordPress/wordpress-playground/pull/2368)) +- [Client] Accept wasm.wordpress.net as an official origin. ([#2368](https://github.com/WordPress/wordpress-playground/pull/2368)) ### Tools -- Make PHP 8.3 the default version. ([#2371](https://github.com/WordPress/wordpress-playground/pull/2371)) +- Make PHP 8.3 the default version. ([#2371](https://github.com/WordPress/wordpress-playground/pull/2371)) #### PHP WebAssembly -- Add `--xdebug` option in php-wasm CLI and wp-playground CLI. ([#2346](https://github.com/WordPress/wordpress-playground/pull/2346)) +- Add `--xdebug` option in php-wasm CLI and wp-playground CLI. ([#2346](https://github.com/WordPress/wordpress-playground/pull/2346)) ### Documentation -- Adding Playground CLI page and removing wp-now references. ([#2337](https://github.com/WordPress/wordpress-playground/pull/2337)) -- Adding pt-br About and Launch Page. ([#2358](https://github.com/WordPress/wordpress-playground/pull/2358)) -- Adding three new flags on the CLI README file. ([#2325](https://github.com/WordPress/wordpress-playground/pull/2325)) -- Adding video content in Japanese to resources page. ([#2354](https://github.com/WordPress/wordpress-playground/pull/2354)) -- Updating web instance page documentation. ([#2365](https://github.com/WordPress/wordpress-playground/pull/2365)) +- Adding Playground CLI page and removing wp-now references. ([#2337](https://github.com/WordPress/wordpress-playground/pull/2337)) +- Adding pt-br About and Launch Page. ([#2358](https://github.com/WordPress/wordpress-playground/pull/2358)) +- Adding three new flags on the CLI README file. ([#2325](https://github.com/WordPress/wordpress-playground/pull/2325)) +- Adding video content in Japanese to resources page. ([#2354](https://github.com/WordPress/wordpress-playground/pull/2354)) +- Updating web instance page documentation. ([#2365](https://github.com/WordPress/wordpress-playground/pull/2365)) ### PHP WebAssembly -- [PHP-wasm Node] Remove unused node creation code from createNodeFsMountHandler. ([#2379](https://github.com/WordPress/wordpress-playground/pull/2379)) -- [PHP-wasm] File mounting in NODEFS. ([#2338](https://github.com/WordPress/wordpress-playground/pull/2338)) -- [PHP] Improve error logging. ([#2357](https://github.com/WordPress/wordpress-playground/pull/2357)) -- [PHP] Isomorphic, reusable spawn handler. ([#2359](https://github.com/WordPress/wordpress-playground/pull/2359)) -- [PHP] Refresh the latest PHP versions before recompiling. ([#2372](https://github.com/WordPress/wordpress-playground/pull/2372)) -- [php-wasm/universal] Try require() before dynamic imprt in comlink-sync.ts. ([#2363](https://github.com/WordPress/wordpress-playground/pull/2363)) +- [PHP-wasm Node] Remove unused node creation code from createNodeFsMountHandler. ([#2379](https://github.com/WordPress/wordpress-playground/pull/2379)) +- [PHP-wasm] File mounting in NODEFS. ([#2338](https://github.com/WordPress/wordpress-playground/pull/2338)) +- [PHP] Improve error logging. ([#2357](https://github.com/WordPress/wordpress-playground/pull/2357)) +- [PHP] Isomorphic, reusable spawn handler. ([#2359](https://github.com/WordPress/wordpress-playground/pull/2359)) +- [PHP] Refresh the latest PHP versions before recompiling. ([#2372](https://github.com/WordPress/wordpress-playground/pull/2372)) +- [php-wasm/universal] Try require() before dynamic imprt in comlink-sync.ts. ([#2363](https://github.com/WordPress/wordpress-playground/pull/2363)) ### Website -- Deploy public web app after WP major/beta update. ([#2378](https://github.com/WordPress/wordpress-playground/pull/2378)) +- Deploy public web app after WP major/beta update. ([#2378](https://github.com/WordPress/wordpress-playground/pull/2378)) ### Bug Fixes -- Allow the WP update and changelog workflows to commit to trunk again. ([#2377](https://github.com/WordPress/wordpress-playground/pull/2377)) -- Fix failing WP update workflows. ([#2376](https://github.com/WordPress/wordpress-playground/pull/2376)) +- Allow the WP update and changelog workflows to commit to trunk again. ([#2377](https://github.com/WordPress/wordpress-playground/pull/2377)) +- Fix failing WP update workflows. ([#2376](https://github.com/WordPress/wordpress-playground/pull/2376)) ### Various -- Add Japanese translations to Resources References. ([#2352](https://github.com/WordPress/wordpress-playground/pull/2352)) -- Add new logo and open graph image. ([#2350](https://github.com/WordPress/wordpress-playground/pull/2350)) -- Adding Portuguese version for Code Standards, Code, and Documentation.. ([#2343](https://github.com/WordPress/wordpress-playground/pull/2343)) -- Adding new icons and og:Image for the Playground Web instance. ([#2367](https://github.com/WordPress/wordpress-playground/pull/2367)) -- Update Japanese translations to main directory. ([#2375](https://github.com/WordPress/wordpress-playground/pull/2375)) +- Add Japanese translations to Resources References. ([#2352](https://github.com/WordPress/wordpress-playground/pull/2352)) +- Add new logo and open graph image. ([#2350](https://github.com/WordPress/wordpress-playground/pull/2350)) +- Adding Portuguese version for Code Standards, Code, and Documentation.. ([#2343](https://github.com/WordPress/wordpress-playground/pull/2343)) +- Adding new icons and og:Image for the Playground Web instance. ([#2367](https://github.com/WordPress/wordpress-playground/pull/2367)) +- Update Japanese translations to main directory. ([#2375](https://github.com/WordPress/wordpress-playground/pull/2375)) ### Contributors @@ -1327,31 +1327,31 @@ The following contributors merged PRs in this release: ### Enhancements -- Add --internal-cookie-store option for Playground CLI. ([#2323](https://github.com/WordPress/wordpress-playground/pull/2323)) +- Add --internal-cookie-store option for Playground CLI. ([#2323](https://github.com/WordPress/wordpress-playground/pull/2323)) ### Tools #### PHP WebAssembly -- [ php-wasm ] Add `xdebug` shared extension to @php-wasm/node ASYNCIFY. ([#2326](https://github.com/WordPress/wordpress-playground/pull/2326)) +- [ php-wasm ] Add `xdebug` shared extension to @php-wasm/node ASYNCIFY. ([#2326](https://github.com/WordPress/wordpress-playground/pull/2326)) ### Documentation -- Add Japanese translations to Using Blueprints. ([#2330](https://github.com/WordPress/wordpress-playground/pull/2330)) -- Add Japanese translations to Blueprint data Format. ([#2340](https://github.com/WordPress/wordpress-playground/pull/2340)) -- Adding new videos about WordPress Playground. ([#2348](https://github.com/WordPress/wordpress-playground/pull/2348)) -- Translate How to contribute pages to Brazilian Portuguese. ([#2329](https://github.com/WordPress/wordpress-playground/pull/2329)) -- Updating Translation Guide. ([#2342](https://github.com/WordPress/wordpress-playground/pull/2342)) -- Updating slack channel from #meta-playground to #playground. ([#2345](https://github.com/WordPress/wordpress-playground/pull/2345)) +- Add Japanese translations to Using Blueprints. ([#2330](https://github.com/WordPress/wordpress-playground/pull/2330)) +- Add Japanese translations to Blueprint data Format. ([#2340](https://github.com/WordPress/wordpress-playground/pull/2340)) +- Adding new videos about WordPress Playground. ([#2348](https://github.com/WordPress/wordpress-playground/pull/2348)) +- Translate How to contribute pages to Brazilian Portuguese. ([#2329](https://github.com/WordPress/wordpress-playground/pull/2329)) +- Updating Translation Guide. ([#2342](https://github.com/WordPress/wordpress-playground/pull/2342)) +- Updating slack channel from #meta-playground to #playground. ([#2345](https://github.com/WordPress/wordpress-playground/pull/2345)) ### PHP WebAssembly -- Support multiple workers for NODEFS /wordpress mounts – Asyncify. ([#2317](https://github.com/WordPress/wordpress-playground/pull/2317)) -- [PHP] Support non-blocking read streams. ([#2339](https://github.com/WordPress/wordpress-playground/pull/2339)) +- Support multiple workers for NODEFS /wordpress mounts – Asyncify. ([#2317](https://github.com/WordPress/wordpress-playground/pull/2317)) +- [PHP] Support non-blocking read streams. ([#2339](https://github.com/WordPress/wordpress-playground/pull/2339)) ### Bug Fixes -- Fix: Set an explicit path for docsaurus.config.js. ([#2335](https://github.com/WordPress/wordpress-playground/pull/2335)) +- Fix: Set an explicit path for docsaurus.config.js. ([#2335](https://github.com/WordPress/wordpress-playground/pull/2335)) ### Contributors @@ -1363,14 +1363,14 @@ The following contributors merged PRs in this release: ### Various -- Revert "[ php-wasm ] add Intl support (#150)". ([#154](https://github.com/Automattic/wordpress-playground-private/pull/154)) -- Use the new SQLite driver. ([#144](https://github.com/Automattic/wordpress-playground-private/pull/144)) -- [ php-wasm ] Add intl support. ([#155](https://github.com/Automattic/wordpress-playground-private/pull/155)) -- [ php-wasm ] Intl : Improve integration. ([#159](https://github.com/Automattic/wordpress-playground-private/pull/159)) -- [ php-wasm ] add Intl support. ([#150](https://github.com/Automattic/wordpress-playground-private/pull/150)) -- [CLI] Enable users to automatically mount their current working directory into Playground. ([#39](https://github.com/Automattic/wordpress-playground-private/pull/39)) -- [PHP-wasm Node] Fix Identifier '\_\_filename' has already been declared. ([#143](https://github.com/Automattic/wordpress-playground-private/pull/143)) -- [Website] Support data URLs in blueprint-url query parameter. ([#158](https://github.com/Automattic/wordpress-playground-private/pull/158)) +- Revert "[ php-wasm ] add Intl support (#150)". ([#154](https://github.com/Automattic/wordpress-playground-private/pull/154)) +- Use the new SQLite driver. ([#144](https://github.com/Automattic/wordpress-playground-private/pull/144)) +- [ php-wasm ] Add intl support. ([#155](https://github.com/Automattic/wordpress-playground-private/pull/155)) +- [ php-wasm ] Intl : Improve integration. ([#159](https://github.com/Automattic/wordpress-playground-private/pull/159)) +- [ php-wasm ] add Intl support. ([#150](https://github.com/Automattic/wordpress-playground-private/pull/150)) +- [CLI] Enable users to automatically mount their current working directory into Playground. ([#39](https://github.com/Automattic/wordpress-playground-private/pull/39)) +- [PHP-wasm Node] Fix Identifier '\_\_filename' has already been declared. ([#143](https://github.com/Automattic/wordpress-playground-private/pull/143)) +- [Website] Support data URLs in blueprint-url query parameter. ([#158](https://github.com/Automattic/wordpress-playground-private/pull/158)) ### Contributors @@ -1382,8 +1382,8 @@ The following contributors merged PRs in this release: ### Various -- Define `DB_NAME` constant when it's missing. ([#140](https://github.com/Automattic/wordpress-playground-private/pull/140)) -- Support limiting files added to self-hosted packages. ([#149](https://github.com/Automattic/wordpress-playground-private/pull/149)) +- Define `DB_NAME` constant when it's missing. ([#140](https://github.com/Automattic/wordpress-playground-private/pull/140)) +- Support limiting files added to self-hosted packages. ([#149](https://github.com/Automattic/wordpress-playground-private/pull/149)) ### Contributors @@ -1395,10 +1395,10 @@ The following contributors merged PRs in this release: ### Various -- Document mounting OPFS storage _after_ the boot. ([#141](https://github.com/Automattic/wordpress-playground-private/pull/141)) -- QUERY_STRING should default to empty string. ([#139](https://github.com/Automattic/wordpress-playground-private/pull/139)) -- Remove null steps that are added. ([#135](https://github.com/Automattic/wordpress-playground-private/pull/135)) -- [CLI] Fix package entry point path. ([#136](https://github.com/Automattic/wordpress-playground-private/pull/136)) +- Document mounting OPFS storage _after_ the boot. ([#141](https://github.com/Automattic/wordpress-playground-private/pull/141)) +- QUERY_STRING should default to empty string. ([#139](https://github.com/Automattic/wordpress-playground-private/pull/139)) +- Remove null steps that are added. ([#135](https://github.com/Automattic/wordpress-playground-private/pull/135)) +- [CLI] Fix package entry point path. ([#136](https://github.com/Automattic/wordpress-playground-private/pull/136)) ### Contributors @@ -1412,7 +1412,7 @@ The following contributors merged PRs in this release: ### Various -- Document mounting OPFS storage _after_ the boot. ([#141](https://github.com/Automattic/wordpress-playground-private/pull/141)) +- Document mounting OPFS storage _after_ the boot. ([#141](https://github.com/Automattic/wordpress-playground-private/pull/141)) ### Contributors @@ -1424,15 +1424,15 @@ The following contributors merged PRs in this release: ### Various -- Add MySQL network calls to Asyncify tests. ([#108](https://github.com/Automattic/wordpress-playground-private/pull/108)) -- Format the plugin-proxy file. ([#127](https://github.com/Automattic/wordpress-playground-private/pull/127)) -- Plugin proxy: Allow all repos from WordPress, Automattic and Woocommerce organizations. ([#128](https://github.com/Automattic/wordpress-playground-private/pull/128)) -- QUERY_STRING should default to empty string. ([#139](https://github.com/Automattic/wordpress-playground-private/pull/139)) -- Remove null steps that are added. ([#135](https://github.com/Automattic/wordpress-playground-private/pull/135)) -- Remove unused dependencies. ([#116](https://github.com/Automattic/wordpress-playground-private/pull/116)) -- [CLI] Fix package entry point path. ([#136](https://github.com/Automattic/wordpress-playground-private/pull/136)) -- [PHP-wasm Node] Add support for resolving wasm paths in Windows. ([#129](https://github.com/Automattic/wordpress-playground-private/pull/129)) -- [PHP-wasm Node] Dynamically mount symlinks. ([#125](https://github.com/Automattic/wordpress-playground-private/pull/125)) +- Add MySQL network calls to Asyncify tests. ([#108](https://github.com/Automattic/wordpress-playground-private/pull/108)) +- Format the plugin-proxy file. ([#127](https://github.com/Automattic/wordpress-playground-private/pull/127)) +- Plugin proxy: Allow all repos from WordPress, Automattic and Woocommerce organizations. ([#128](https://github.com/Automattic/wordpress-playground-private/pull/128)) +- QUERY_STRING should default to empty string. ([#139](https://github.com/Automattic/wordpress-playground-private/pull/139)) +- Remove null steps that are added. ([#135](https://github.com/Automattic/wordpress-playground-private/pull/135)) +- Remove unused dependencies. ([#116](https://github.com/Automattic/wordpress-playground-private/pull/116)) +- [CLI] Fix package entry point path. ([#136](https://github.com/Automattic/wordpress-playground-private/pull/136)) +- [PHP-wasm Node] Add support for resolving wasm paths in Windows. ([#129](https://github.com/Automattic/wordpress-playground-private/pull/129)) +- [PHP-wasm Node] Dynamically mount symlinks. ([#125](https://github.com/Automattic/wordpress-playground-private/pull/125)) ### Contributors @@ -1444,12 +1444,12 @@ The following contributors merged PRs in this release: ### Various -- Add MySQL network calls to Asyncify tests. ([#108](https://github.com/Automattic/wordpress-playground-private/pull/108)) -- Format the plugin-proxy file. ([#127](https://github.com/Automattic/wordpress-playground-private/pull/127)) -- Plugin proxy: Allow all repos from WordPress, Automattic and Woocommerce organizations. ([#128](https://github.com/Automattic/wordpress-playground-private/pull/128)) -- Remove unused dependencies. ([#116](https://github.com/Automattic/wordpress-playground-private/pull/116)) -- [PHP-wasm Node] Add support for resolving wasm paths in Windows. ([#129](https://github.com/Automattic/wordpress-playground-private/pull/129)) -- [PHP-wasm Node] Dynamically mount symlinks. ([#125](https://github.com/Automattic/wordpress-playground-private/pull/125)) +- Add MySQL network calls to Asyncify tests. ([#108](https://github.com/Automattic/wordpress-playground-private/pull/108)) +- Format the plugin-proxy file. ([#127](https://github.com/Automattic/wordpress-playground-private/pull/127)) +- Plugin proxy: Allow all repos from WordPress, Automattic and Woocommerce organizations. ([#128](https://github.com/Automattic/wordpress-playground-private/pull/128)) +- Remove unused dependencies. ([#116](https://github.com/Automattic/wordpress-playground-private/pull/116)) +- [PHP-wasm Node] Add support for resolving wasm paths in Windows. ([#129](https://github.com/Automattic/wordpress-playground-private/pull/129)) +- [PHP-wasm Node] Dynamically mount symlinks. ([#125](https://github.com/Automattic/wordpress-playground-private/pull/125)) ### Contributors @@ -1461,21 +1461,21 @@ The following contributors merged PRs in this release: ### Bug Fixes -- Fix changelog version order. ([#100](https://github.com/Automattic/wordpress-playground-private/pull/100)) -- Fix openssl library paths in php-wasm build. ([#102](https://github.com/Automattic/wordpress-playground-private/pull/102)) +- Fix changelog version order. ([#100](https://github.com/Automattic/wordpress-playground-private/pull/100)) +- Fix openssl library paths in php-wasm build. ([#102](https://github.com/Automattic/wordpress-playground-private/pull/102)) ### Various -- Add private fork links to the changelog. ([#98](https://github.com/Automattic/wordpress-playground-private/pull/98)) -- Allow public access to A8C Playground instance. ([#119](https://github.com/Automattic/wordpress-playground-private/pull/119)) -- Make php-wasm and Playground CLI's fast to run with Node.js. ([#107](https://github.com/Automattic/wordpress-playground-private/pull/107)) -- Playground CLI: Add `skipSqliteSetup` flag for MySQL support. ([#97](https://github.com/Automattic/wordpress-playground-private/pull/97)) -- Prep the WP update workflows to be re-enabled. ([#110](https://github.com/Automattic/wordpress-playground-private/pull/110)) -- Support building for additional remote origins. ([#122](https://github.com/Automattic/wordpress-playground-private/pull/122)) -- Tweak Blueprint test string to match WP 6.8. ([#117](https://github.com/Automattic/wordpress-playground-private/pull/117)) -- Update Nx, Vite, and ESLint dependencies. ([#35](https://github.com/Automattic/wordpress-playground-private/pull/35)) -- Upgrade octokit to 3.1.2 to fix vulnerability. ([#106](https://github.com/Automattic/wordpress-playground-private/pull/106)) -- Use Node as the Vitest environment. ([#96](https://github.com/Automattic/wordpress-playground-private/pull/96)) +- Add private fork links to the changelog. ([#98](https://github.com/Automattic/wordpress-playground-private/pull/98)) +- Allow public access to A8C Playground instance. ([#119](https://github.com/Automattic/wordpress-playground-private/pull/119)) +- Make php-wasm and Playground CLI's fast to run with Node.js. ([#107](https://github.com/Automattic/wordpress-playground-private/pull/107)) +- Playground CLI: Add `skipSqliteSetup` flag for MySQL support. ([#97](https://github.com/Automattic/wordpress-playground-private/pull/97)) +- Prep the WP update workflows to be re-enabled. ([#110](https://github.com/Automattic/wordpress-playground-private/pull/110)) +- Support building for additional remote origins. ([#122](https://github.com/Automattic/wordpress-playground-private/pull/122)) +- Tweak Blueprint test string to match WP 6.8. ([#117](https://github.com/Automattic/wordpress-playground-private/pull/117)) +- Update Nx, Vite, and ESLint dependencies. ([#35](https://github.com/Automattic/wordpress-playground-private/pull/35)) +- Upgrade octokit to 3.1.2 to fix vulnerability. ([#106](https://github.com/Automattic/wordpress-playground-private/pull/106)) +- Use Node as the Vitest environment. ([#96](https://github.com/Automattic/wordpress-playground-private/pull/96)) ### Contributors @@ -1487,18 +1487,18 @@ The following contributors merged PRs in this release: ### Bug Fixes -- Fix changelog workflow and backfill changelog entries from recent versions. ([#83](https://github.com/Automattic/wordpress-playground-private/pull/83)) +- Fix changelog workflow and backfill changelog entries from recent versions. ([#83](https://github.com/Automattic/wordpress-playground-private/pull/83)) ### Various -- Consider unexpected undefined symbols to be errors. ([#86](https://github.com/Automattic/wordpress-playground-private/pull/86)) -- Ignore ca-bundle created by @php-wasm/cli. ([#88](https://github.com/Automattic/wordpress-playground-private/pull/88)) -- Support Node.js args to built-script executor. ([#92](https://github.com/Automattic/wordpress-playground-private/pull/92)) -- Support quickly testing php-wasm CLI changes with bun. ([#85](https://github.com/Automattic/wordpress-playground-private/pull/85)) -- Update Emscripten version to 4.0.5. ([#93](https://github.com/Automattic/wordpress-playground-private/pull/93)) -- Update Playground Node version to 20.9.0. ([#89](https://github.com/Automattic/wordpress-playground-private/pull/89)) -- Upgrade express to 4.21.2. ([#90](https://github.com/Automattic/wordpress-playground-private/pull/90)) -- [PHP-wasm] Use statfs from NODEFS in the Node version. ([#94](https://github.com/Automattic/wordpress-playground-private/pull/94)) +- Consider unexpected undefined symbols to be errors. ([#86](https://github.com/Automattic/wordpress-playground-private/pull/86)) +- Ignore ca-bundle created by @php-wasm/cli. ([#88](https://github.com/Automattic/wordpress-playground-private/pull/88)) +- Support Node.js args to built-script executor. ([#92](https://github.com/Automattic/wordpress-playground-private/pull/92)) +- Support quickly testing php-wasm CLI changes with bun. ([#85](https://github.com/Automattic/wordpress-playground-private/pull/85)) +- Update Emscripten version to 4.0.5. ([#93](https://github.com/Automattic/wordpress-playground-private/pull/93)) +- Update Playground Node version to 20.9.0. ([#89](https://github.com/Automattic/wordpress-playground-private/pull/89)) +- Upgrade express to 4.21.2. ([#90](https://github.com/Automattic/wordpress-playground-private/pull/90)) +- [PHP-wasm] Use statfs from NODEFS in the Node version. ([#94](https://github.com/Automattic/wordpress-playground-private/pull/94)) ### Contributors @@ -1510,13 +1510,13 @@ The following contributors merged PRs in this release: ### Various -- Blueprint bundles. ([#75](https://github.com/Automattic/wordpress-playground-private/pull/75)) -- CORS Proxy: fetch() with credentials: "include". ([#66](https://github.com/Automattic/wordpress-playground-private/pull/66)) -- Exif support for PHP-wasm. ([#72](https://github.com/Automattic/wordpress-playground-private/pull/72)) -- Remove Data Liberation PHP modules. ([#79](https://github.com/Automattic/wordpress-playground-private/pull/79)) -- Stop suppressing 64bit integer PHP warnings as 64bit longs are now suppoted. ([#76](https://github.com/Automattic/wordpress-playground-private/pull/76)) -- [Blueprints] setSiteLanguage fetch translation package URL from WP.org. ([#81](https://github.com/Automattic/wordpress-playground-private/pull/81)) -- [Website] Drop the static <link rel="manifest"> tag and generate one in JavaScript instead. ([#78](https://github.com/Automattic/wordpress-playground-private/pull/78)) +- Blueprint bundles. ([#75](https://github.com/Automattic/wordpress-playground-private/pull/75)) +- CORS Proxy: fetch() with credentials: "include". ([#66](https://github.com/Automattic/wordpress-playground-private/pull/66)) +- Exif support for PHP-wasm. ([#72](https://github.com/Automattic/wordpress-playground-private/pull/72)) +- Remove Data Liberation PHP modules. ([#79](https://github.com/Automattic/wordpress-playground-private/pull/79)) +- Stop suppressing 64bit integer PHP warnings as 64bit longs are now suppoted. ([#76](https://github.com/Automattic/wordpress-playground-private/pull/76)) +- [Blueprints] setSiteLanguage fetch translation package URL from WP.org. ([#81](https://github.com/Automattic/wordpress-playground-private/pull/81)) +- [Website] Drop the static <link rel="manifest"> tag and generate one in JavaScript instead. ([#78](https://github.com/Automattic/wordpress-playground-private/pull/78)) ### Contributors @@ -1528,17 +1528,17 @@ The following contributors merged PRs in this release: ### Various -- 64bit integer support, drop PHP 7.0 and 7.1 support. ([#74](https://github.com/Automattic/wordpress-playground-private/pull/74)) -- FS Journal: Handle renaming OPFS files via delete + create (instead of file.move()). ([#64](https://github.com/Automattic/wordpress-playground-private/pull/64)) -- GitHub: Cache node_modules per arch to avoid nx error. ([#70](https://github.com/Automattic/wordpress-playground-private/pull/70)) -- Merge from public Playground repo. ([#59](https://github.com/Automattic/wordpress-playground-private/pull/59)) -- OPFS site creation: Use the same "is this directory a site?" check as the site list. ([#65](https://github.com/Automattic/wordpress-playground-private/pull/65)) -- Stop adding source maps to offline assets list. ([#68](https://github.com/Automattic/wordpress-playground-private/pull/68)) -- Support mobile access to private Playground instance. ([#73](https://github.com/Automattic/wordpress-playground-private/pull/73)) -- TLS->HTTP Proxy: Support outbound request body. ([#61](https://github.com/Automattic/wordpress-playground-private/pull/61)) -- TLS: Only use the server_name extension during server hello. ([#62](https://github.com/Automattic/wordpress-playground-private/pull/62)) -- Website: Blueprints as PWAs with a dynamic manifest.json file. ([#67](https://github.com/Automattic/wordpress-playground-private/pull/67)) -- Website: Preserve the `mode` query arg when opening OPFS site. ([#63](https://github.com/Automattic/wordpress-playground-private/pull/63)) +- 64bit integer support, drop PHP 7.0 and 7.1 support. ([#74](https://github.com/Automattic/wordpress-playground-private/pull/74)) +- FS Journal: Handle renaming OPFS files via delete + create (instead of file.move()). ([#64](https://github.com/Automattic/wordpress-playground-private/pull/64)) +- GitHub: Cache node_modules per arch to avoid nx error. ([#70](https://github.com/Automattic/wordpress-playground-private/pull/70)) +- Merge from public Playground repo. ([#59](https://github.com/Automattic/wordpress-playground-private/pull/59)) +- OPFS site creation: Use the same "is this directory a site?" check as the site list. ([#65](https://github.com/Automattic/wordpress-playground-private/pull/65)) +- Stop adding source maps to offline assets list. ([#68](https://github.com/Automattic/wordpress-playground-private/pull/68)) +- Support mobile access to private Playground instance. ([#73](https://github.com/Automattic/wordpress-playground-private/pull/73)) +- TLS->HTTP Proxy: Support outbound request body. ([#61](https://github.com/Automattic/wordpress-playground-private/pull/61)) +- TLS: Only use the server_name extension during server hello. ([#62](https://github.com/Automattic/wordpress-playground-private/pull/62)) +- Website: Blueprints as PWAs with a dynamic manifest.json file. ([#67](https://github.com/Automattic/wordpress-playground-private/pull/67)) +- Website: Preserve the `mode` query arg when opening OPFS site. ([#63](https://github.com/Automattic/wordpress-playground-private/pull/63)) ### Contributors @@ -1550,38 +1550,38 @@ The following contributors merged PRs in this release: ### Bug Fixes -- Fix php-wasm build error for WITH_SOURCEMAPS=yes. ([#44](https://github.com/Automattic/wordpress-playground-private/pull/44)) -- Fix php-wasm source map base. ([#46](https://github.com/Automattic/wordpress-playground-private/pull/46)) -- Fix private website deployment workflow. ([#57](https://github.com/Automattic/wordpress-playground-private/pull/57)) -- Fix up private website deployment workflow after initial commit. ([#29](https://github.com/Automattic/wordpress-playground-private/pull/29)) +- Fix php-wasm build error for WITH_SOURCEMAPS=yes. ([#44](https://github.com/Automattic/wordpress-playground-private/pull/44)) +- Fix php-wasm source map base. ([#46](https://github.com/Automattic/wordpress-playground-private/pull/46)) +- Fix private website deployment workflow. ([#57](https://github.com/Automattic/wordpress-playground-private/pull/57)) +- Fix up private website deployment workflow after initial commit. ([#29](https://github.com/Automattic/wordpress-playground-private/pull/29)) ### Various -- Add WITH_DEBUG option for building php-wasm with DWARF debug info. ([#47](https://github.com/Automattic/wordpress-playground-private/pull/47)) -- Add `janjakes` to GitHub workflows actors. ([#33](https://github.com/Automattic/wordpress-playground-private/pull/33)) -- Add a dedicated workflow for deploying private playground. ([#28](https://github.com/Automattic/wordpress-playground-private/pull/28)) -- Add remote data blocks to the allowlist. ([#30](https://github.com/Automattic/wordpress-playground-private/pull/30)) -- Allow ashfame to run self-hosted package release workflow. ([#22](https://github.com/Automattic/wordpress-playground-private/pull/22)) -- Allow deploying custom supported domains for CORS proxy. ([#54](https://github.com/Automattic/wordpress-playground-private/pull/54)) -- CORS proxy: Make allowed origins configurable. ([#43](https://github.com/Automattic/wordpress-playground-private/pull/43)) -- Make further fixes for unreliable end-to-end tests. ([#9](https://github.com/Automattic/wordpress-playground-private/pull/9)) -- Move DNS polyfills to a PHP extension and add missing constants. ([#27](https://github.com/Automattic/wordpress-playground-private/pull/27)) -- New playground CLI function interface. ([#40](https://github.com/Automattic/wordpress-playground-private/pull/40)) -- Replace some hardcoded refs to playground.wordpress.net web app. ([#42](https://github.com/Automattic/wordpress-playground-private/pull/42)) -- Restore safety condition for CORS proxy deployment workflow. ([#55](https://github.com/Automattic/wordpress-playground-private/pull/55)) -- Revert "Add the launch browser flag to CLI". ([#24](https://github.com/Automattic/wordpress-playground-private/pull/24)) -- Revert "Support file URL resources in command line environment". ([#41](https://github.com/Automattic/wordpress-playground-private/pull/41)) -- Schedule private deployment and use private environment. ([#37](https://github.com/Automattic/wordpress-playground-private/pull/37)) -- Stop assuming CLI stdout is a TTY write stream. ([#51](https://github.com/Automattic/wordpress-playground-private/pull/51)) -- Store WordPress site cookies in the browser instead of a custom Cookie Store. ([#20](https://github.com/Automattic/wordpress-playground-private/pull/20)) -- Support file URL resources in command line environment. ([#34](https://github.com/Automattic/wordpress-playground-private/pull/34)) -- Switch to relative paths in app manifest. ([#36](https://github.com/Automattic/wordpress-playground-private/pull/36)) -- Switch to runner with more CPU and RAM. ([#45](https://github.com/Automattic/wordpress-playground-private/pull/45)) -- Treat zip files as zip files regardless of file name. ([#58](https://github.com/Automattic/wordpress-playground-private/pull/58)) -- Try more Playwright workers since we have a runner with more resources. ([#48](https://github.com/Automattic/wordpress-playground-private/pull/48)) -- Update private Playground instance to use dedicated CORS proxy. ([#56](https://github.com/Automattic/wordpress-playground-private/pull/56)) -- Use rsync instead of scp in website deploy workflow. ([#26](https://github.com/Automattic/wordpress-playground-private/pull/26)) -- Use specified SQLite version also for PHP < 7.4. ([#32](https://github.com/Automattic/wordpress-playground-private/pull/32)) +- Add WITH_DEBUG option for building php-wasm with DWARF debug info. ([#47](https://github.com/Automattic/wordpress-playground-private/pull/47)) +- Add `janjakes` to GitHub workflows actors. ([#33](https://github.com/Automattic/wordpress-playground-private/pull/33)) +- Add a dedicated workflow for deploying private playground. ([#28](https://github.com/Automattic/wordpress-playground-private/pull/28)) +- Add remote data blocks to the allowlist. ([#30](https://github.com/Automattic/wordpress-playground-private/pull/30)) +- Allow ashfame to run self-hosted package release workflow. ([#22](https://github.com/Automattic/wordpress-playground-private/pull/22)) +- Allow deploying custom supported domains for CORS proxy. ([#54](https://github.com/Automattic/wordpress-playground-private/pull/54)) +- CORS proxy: Make allowed origins configurable. ([#43](https://github.com/Automattic/wordpress-playground-private/pull/43)) +- Make further fixes for unreliable end-to-end tests. ([#9](https://github.com/Automattic/wordpress-playground-private/pull/9)) +- Move DNS polyfills to a PHP extension and add missing constants. ([#27](https://github.com/Automattic/wordpress-playground-private/pull/27)) +- New playground CLI function interface. ([#40](https://github.com/Automattic/wordpress-playground-private/pull/40)) +- Replace some hardcoded refs to playground.wordpress.net web app. ([#42](https://github.com/Automattic/wordpress-playground-private/pull/42)) +- Restore safety condition for CORS proxy deployment workflow. ([#55](https://github.com/Automattic/wordpress-playground-private/pull/55)) +- Revert "Add the launch browser flag to CLI". ([#24](https://github.com/Automattic/wordpress-playground-private/pull/24)) +- Revert "Support file URL resources in command line environment". ([#41](https://github.com/Automattic/wordpress-playground-private/pull/41)) +- Schedule private deployment and use private environment. ([#37](https://github.com/Automattic/wordpress-playground-private/pull/37)) +- Stop assuming CLI stdout is a TTY write stream. ([#51](https://github.com/Automattic/wordpress-playground-private/pull/51)) +- Store WordPress site cookies in the browser instead of a custom Cookie Store. ([#20](https://github.com/Automattic/wordpress-playground-private/pull/20)) +- Support file URL resources in command line environment. ([#34](https://github.com/Automattic/wordpress-playground-private/pull/34)) +- Switch to relative paths in app manifest. ([#36](https://github.com/Automattic/wordpress-playground-private/pull/36)) +- Switch to runner with more CPU and RAM. ([#45](https://github.com/Automattic/wordpress-playground-private/pull/45)) +- Treat zip files as zip files regardless of file name. ([#58](https://github.com/Automattic/wordpress-playground-private/pull/58)) +- Try more Playwright workers since we have a runner with more resources. ([#48](https://github.com/Automattic/wordpress-playground-private/pull/48)) +- Update private Playground instance to use dedicated CORS proxy. ([#56](https://github.com/Automattic/wordpress-playground-private/pull/56)) +- Use rsync instead of scp in website deploy workflow. ([#26](https://github.com/Automattic/wordpress-playground-private/pull/26)) +- Use specified SQLite version also for PHP < 7.4. ([#32](https://github.com/Automattic/wordpress-playground-private/pull/32)) ### Contributors @@ -1593,12 +1593,12 @@ The following contributors merged PRs in this release: ### Bug Fixes -- Fix workflow for deploying self-hosted packages. ([#6](https://github.com/Automattic/wordpress-playground-private/pull/6)) +- Fix workflow for deploying self-hosted packages. ([#6](https://github.com/Automattic/wordpress-playground-private/pull/6)) ### Various -- Add the launch browser flag to CLI. ([#18](https://github.com/Automattic/wordpress-playground-private/pull/18)) -- [Fix] Zip spec compliance for exported backup file. ([#7](https://github.com/Automattic/wordpress-playground-private/pull/7)) +- Add the launch browser flag to CLI. ([#18](https://github.com/Automattic/wordpress-playground-private/pull/18)) +- [Fix] Zip spec compliance for exported backup file. ([#7](https://github.com/Automattic/wordpress-playground-private/pull/7)) ### Contributors @@ -1610,8 +1610,8 @@ The following contributors merged PRs in this release: ### Various -- Add missing node external to Playground CLI. ([#19](https://github.com/Automattic/wordpress-playground-private/pull/19)) -- Add self-hosted package publishing. ([#5](https://github.com/Automattic/wordpress-playground-private/pull/5)) +- Add missing node external to Playground CLI. ([#19](https://github.com/Automattic/wordpress-playground-private/pull/19)) +- Add self-hosted package publishing. ([#5](https://github.com/Automattic/wordpress-playground-private/pull/5)) ### Contributors @@ -1629,21 +1629,21 @@ The following contributors merged PRs in this release: ### Enhancements -- [Data Liberation] Add EPub to Blocks converter. ([#2097](https://github.com/WordPress/wordpress-playground/pull/2097)) -- [Data Liberation] Block markup consumers and producers. ([#2121](https://github.com/WordPress/wordpress-playground/pull/2121)) -- [Data Liberation] Filesystem entity reader. ([#2125](https://github.com/WordPress/wordpress-playground/pull/2125)) -- [Data Liberation] Recognize self-closing blocks in WP_Block_Markup_Processor. ([#2120](https://github.com/WordPress/wordpress-playground/pull/2120)) -- [Data Liberation] Refactor Entity Readers class diagram. ([#2096](https://github.com/WordPress/wordpress-playground/pull/2096)) +- [Data Liberation] Add EPub to Blocks converter. ([#2097](https://github.com/WordPress/wordpress-playground/pull/2097)) +- [Data Liberation] Block markup consumers and producers. ([#2121](https://github.com/WordPress/wordpress-playground/pull/2121)) +- [Data Liberation] Filesystem entity reader. ([#2125](https://github.com/WordPress/wordpress-playground/pull/2125)) +- [Data Liberation] Recognize self-closing blocks in WP_Block_Markup_Processor. ([#2120](https://github.com/WordPress/wordpress-playground/pull/2120)) +- [Data Liberation] Refactor Entity Readers class diagram. ([#2096](https://github.com/WordPress/wordpress-playground/pull/2096)) ### PHP WebAssembly -- PHP 8.4 support. ([#2038](https://github.com/WordPress/wordpress-playground/pull/2038)) -- Rewrote fileToUint8Array function to be also NodeJS/Deno compatible. ([#2117](https://github.com/WordPress/wordpress-playground/pull/2117)) -- [PHP] Restore /internal files and Filesystem mounts after hotswapPhpRuntime is called. ([#2119](https://github.com/WordPress/wordpress-playground/pull/2119)) +- PHP 8.4 support. ([#2038](https://github.com/WordPress/wordpress-playground/pull/2038)) +- Rewrote fileToUint8Array function to be also NodeJS/Deno compatible. ([#2117](https://github.com/WordPress/wordpress-playground/pull/2117)) +- [PHP] Restore /internal files and Filesystem mounts after hotswapPhpRuntime is called. ([#2119](https://github.com/WordPress/wordpress-playground/pull/2119)) ### Bug Fixes -- [CORS Proxy] Support chunked encoding when running in Apache/Nginx/etc. ([#2114](https://github.com/WordPress/wordpress-playground/pull/2114)) +- [CORS Proxy] Support chunked encoding when running in Apache/Nginx/etc. ([#2114](https://github.com/WordPress/wordpress-playground/pull/2114)) ### Contributors @@ -1655,7 +1655,7 @@ The following contributors merged PRs in this release: ### Website -- Avoid login issue in deployment end-to-end tests. ([#2065](https://github.com/WordPress/wordpress-playground/pull/2065)) +- Avoid login issue in deployment end-to-end tests. ([#2065](https://github.com/WordPress/wordpress-playground/pull/2065)) ### Contributors @@ -1669,33 +1669,33 @@ The following contributors merged PRs in this release: ### Enhancements -- [Data Liberation] Add HTML to Blocks converter. ([#2095](https://github.com/WordPress/wordpress-playground/pull/2095)) -- [Data Liberation] Add Markdown parsing libraries. ([#2092](https://github.com/WordPress/wordpress-playground/pull/2092)) -- [Data Liberation] Build markdown importer as phar. ([#2094](https://github.com/WordPress/wordpress-playground/pull/2094)) -- [Data Liberation] Move Markdown importer to a separate package. ([#2093](https://github.com/WordPress/wordpress-playground/pull/2093)) +- [Data Liberation] Add HTML to Blocks converter. ([#2095](https://github.com/WordPress/wordpress-playground/pull/2095)) +- [Data Liberation] Add Markdown parsing libraries. ([#2092](https://github.com/WordPress/wordpress-playground/pull/2092)) +- [Data Liberation] Build markdown importer as phar. ([#2094](https://github.com/WordPress/wordpress-playground/pull/2094)) +- [Data Liberation] Move Markdown importer to a separate package. ([#2093](https://github.com/WordPress/wordpress-playground/pull/2093)) ### Blueprints -- Prevent WSOD when autologin is enabled and a plugin logs a notice. ([#2079](https://github.com/WordPress/wordpress-playground/pull/2079)) +- Prevent WSOD when autologin is enabled and a plugin logs a notice. ([#2079](https://github.com/WordPress/wordpress-playground/pull/2079)) ### Tools #### GitHub integration -- [Website] GitHub export modal: Correctly compute the root path when exporting the entire site. ([#2103](https://github.com/WordPress/wordpress-playground/pull/2103)) +- [Website] GitHub export modal: Correctly compute the root path when exporting the entire site. ([#2103](https://github.com/WordPress/wordpress-playground/pull/2103)) ### Website -- Enable separate source maps for all package builds. ([#2088](https://github.com/WordPress/wordpress-playground/pull/2088)) +- Enable separate source maps for all package builds. ([#2088](https://github.com/WordPress/wordpress-playground/pull/2088)) ### Bug Fixes -- Fix README.md typos. ([#2091](https://github.com/WordPress/wordpress-playground/pull/2091)) +- Fix README.md typos. ([#2091](https://github.com/WordPress/wordpress-playground/pull/2091)) ### Various -- Add small comment about lazy init of WXR reader. ([#2102](https://github.com/WordPress/wordpress-playground/pull/2102)) -- [Blueprints] Prevent plugin activation error if plugin redirects during activation or produces an output. ([#2066](https://github.com/WordPress/wordpress-playground/pull/2066)) +- Add small comment about lazy init of WXR reader. ([#2102](https://github.com/WordPress/wordpress-playground/pull/2102)) +- [Blueprints] Prevent plugin activation error if plugin redirects during activation or produces an output. ([#2066](https://github.com/WordPress/wordpress-playground/pull/2066)) ### Contributors @@ -1709,15 +1709,15 @@ The following contributors merged PRs in this release: #### Blueprints Builder -- Use transparent CORS proxy in Blueprint Builder. ([#2089](https://github.com/WordPress/wordpress-playground/pull/2089)) +- Use transparent CORS proxy in Blueprint Builder. ([#2089](https://github.com/WordPress/wordpress-playground/pull/2089)) ### PHP WebAssembly -- Build `@php-wasm` packages as dual ESM + CJS. ([#2087](https://github.com/WordPress/wordpress-playground/pull/2087)) +- Build `@php-wasm` packages as dual ESM + CJS. ([#2087](https://github.com/WordPress/wordpress-playground/pull/2087)) ### -- Add ESLint rule to avoid unintentional dependency on @wp-playgrounds/wordpress-builds. ([#2048](https://github.com/WordPress/wordpress-playground/pull/2048)) +- Add ESLint rule to avoid unintentional dependency on @wp-playgrounds/wordpress-builds. ([#2048](https://github.com/WordPress/wordpress-playground/pull/2048)) ### Contributors @@ -1729,46 +1729,46 @@ The following contributors merged PRs in this release: ### Enhancements -- Allow Authorization header pass-through with X-Cors-Proxy-Allowed-Request-Headers. ([#2007](https://github.com/WordPress/wordpress-playground/pull/2007)) -- [Cors Proxy] Support Transfer-Encoding: Chunked. ([#2077](https://github.com/WordPress/wordpress-playground/pull/2077)) -- [Website] Enable CORS proxy for all fetches. ([#2076](https://github.com/WordPress/wordpress-playground/pull/2076)) +- Allow Authorization header pass-through with X-Cors-Proxy-Allowed-Request-Headers. ([#2007](https://github.com/WordPress/wordpress-playground/pull/2007)) +- [Cors Proxy] Support Transfer-Encoding: Chunked. ([#2077](https://github.com/WordPress/wordpress-playground/pull/2077)) +- [Website] Enable CORS proxy for all fetches. ([#2076](https://github.com/WordPress/wordpress-playground/pull/2076)) ### Tools #### Blueprints -- [Blueprints] Preserve the first char of all filenames sourced from GitDirectoryReference. ([#2070](https://github.com/WordPress/wordpress-playground/pull/2070)) +- [Blueprints] Preserve the first char of all filenames sourced from GitDirectoryReference. ([#2070](https://github.com/WordPress/wordpress-playground/pull/2070)) #### Import/Export -- [Blueprints] Support Data Liberation importer in the importWxr step. ([#2058](https://github.com/WordPress/wordpress-playground/pull/2058)) +- [Blueprints] Support Data Liberation importer in the importWxr step. ([#2058](https://github.com/WordPress/wordpress-playground/pull/2058)) ### PHP WebAssembly #### Website -- [Webiste] Switch the CORS Proxy URL to wordpress-playground-cors-proxy.net. ([#2074](https://github.com/WordPress/wordpress-playground/pull/2074)) +- [Webiste] Switch the CORS Proxy URL to wordpress-playground-cors-proxy.net. ([#2074](https://github.com/WordPress/wordpress-playground/pull/2074)) ### Website -- Bugfix: Delist data-liberation-core.phar from the preloaded offline mode assets. ([#2072](https://github.com/WordPress/wordpress-playground/pull/2072)) -- Don't show the error reporting modal on the initial load. ([#2068](https://github.com/WordPress/wordpress-playground/pull/2068)) -- Prevent the initial flash of "You have no Playgrounds" message. ([#2069](https://github.com/WordPress/wordpress-playground/pull/2069)) -- Remove old PR preview HTML files and add redirects to new preview modals. ([#2081](https://github.com/WordPress/wordpress-playground/pull/2081)) +- Bugfix: Delist data-liberation-core.phar from the preloaded offline mode assets. ([#2072](https://github.com/WordPress/wordpress-playground/pull/2072)) +- Don't show the error reporting modal on the initial load. ([#2068](https://github.com/WordPress/wordpress-playground/pull/2068)) +- Prevent the initial flash of "You have no Playgrounds" message. ([#2069](https://github.com/WordPress/wordpress-playground/pull/2069)) +- Remove old PR preview HTML files and add redirects to new preview modals. ([#2081](https://github.com/WordPress/wordpress-playground/pull/2081)) ### Internal -- [Meta] Remove GitHub Board Automation workflow. ([#2073](https://github.com/WordPress/wordpress-playground/pull/2073)) +- [Meta] Remove GitHub Board Automation workflow. ([#2073](https://github.com/WordPress/wordpress-playground/pull/2073)) ### Bug Fixes -- Temporary: Skip more CI-only deployment test failures. ([#2071](https://github.com/WordPress/wordpress-playground/pull/2071)) +- Temporary: Skip more CI-only deployment test failures. ([#2071](https://github.com/WordPress/wordpress-playground/pull/2071)) ### Various -- Ensure that Site Editor templates are associated with the correct taxonomy. ([#1997](https://github.com/WordPress/wordpress-playground/pull/1997)) -- PR Preview: Document and simplify targetParams. ([#2052](https://github.com/WordPress/wordpress-playground/pull/2052)) -- Revert "Remove old PR preview HTML files and add redirects to new preview modals". ([#2082](https://github.com/WordPress/wordpress-playground/pull/2082)) +- Ensure that Site Editor templates are associated with the correct taxonomy. ([#1997](https://github.com/WordPress/wordpress-playground/pull/1997)) +- PR Preview: Document and simplify targetParams. ([#2052](https://github.com/WordPress/wordpress-playground/pull/2052)) +- Revert "Remove old PR preview HTML files and add redirects to new preview modals". ([#2082](https://github.com/WordPress/wordpress-playground/pull/2082)) ### Contributors @@ -1780,31 +1780,31 @@ The following contributors merged PRs in this release: ### Enhancements -- Shorten and simplify path to CORS proxy. ([#2063](https://github.com/WordPress/wordpress-playground/pull/2063)) -- Support users choosing how to handle URLs for sites that do not exist. ([#2059](https://github.com/WordPress/wordpress-playground/pull/2059)) +- Shorten and simplify path to CORS proxy. ([#2063](https://github.com/WordPress/wordpress-playground/pull/2063)) +- Support users choosing how to handle URLs for sites that do not exist. ([#2059](https://github.com/WordPress/wordpress-playground/pull/2059)) ### Tools #### GitHub integration -- Add zaerl to GitHub workflows actors. ([#2041](https://github.com/WordPress/wordpress-playground/pull/2041)) +- Add zaerl to GitHub workflows actors. ([#2041](https://github.com/WordPress/wordpress-playground/pull/2041)) ### PHP WebAssembly -- [Networking] Decrypt TLS 1.2 alert messages. ([#2060](https://github.com/WordPress/wordpress-playground/pull/2060)) +- [Networking] Decrypt TLS 1.2 alert messages. ([#2060](https://github.com/WordPress/wordpress-playground/pull/2060)) ### Website -- Fix CORS proxy deploy workflow. ([#2049](https://github.com/WordPress/wordpress-playground/pull/2049)) -- Nightly build bugfix – ship the actual nightly build, not the latest release. ([#2056](https://github.com/WordPress/wordpress-playground/pull/2056)) -- Remove duplicate "Saved Playgrounds" label. ([#2044](https://github.com/WordPress/wordpress-playground/pull/2044)) +- Fix CORS proxy deploy workflow. ([#2049](https://github.com/WordPress/wordpress-playground/pull/2049)) +- Nightly build bugfix – ship the actual nightly build, not the latest release. ([#2056](https://github.com/WordPress/wordpress-playground/pull/2056)) +- Remove duplicate "Saved Playgrounds" label. ([#2044](https://github.com/WordPress/wordpress-playground/pull/2044)) ### Various -- Add deploy workflow for standalone CORS proxy. ([#2022](https://github.com/WordPress/wordpress-playground/pull/2022)) -- Restore CORS support to CORS proxy. ([#2023](https://github.com/WordPress/wordpress-playground/pull/2023)) -- [Data Liberation] "Fetch from a different URL" button for failed media downloads, Interactivity API support. ([#2040](https://github.com/WordPress/wordpress-playground/pull/2040)) -- [Data Liberation] Sync WP_HTML API with WordPress 6.7.1 (and add a new test). ([#2062](https://github.com/WordPress/wordpress-playground/pull/2062)) +- Add deploy workflow for standalone CORS proxy. ([#2022](https://github.com/WordPress/wordpress-playground/pull/2022)) +- Restore CORS support to CORS proxy. ([#2023](https://github.com/WordPress/wordpress-playground/pull/2023)) +- [Data Liberation] "Fetch from a different URL" button for failed media downloads, Interactivity API support. ([#2040](https://github.com/WordPress/wordpress-playground/pull/2040)) +- [Data Liberation] Sync WP_HTML API with WordPress 6.7.1 (and add a new test). ([#2062](https://github.com/WordPress/wordpress-playground/pull/2062)) ### Contributors @@ -1816,25 +1816,25 @@ The following contributors merged PRs in this release: ### Blueprints -- Resolve the latest WordPress version from the API instead of assuming it's the same as the last minified build. ([#2027](https://github.com/WordPress/wordpress-playground/pull/2027)) +- Resolve the latest WordPress version from the API instead of assuming it's the same as the last minified build. ([#2027](https://github.com/WordPress/wordpress-playground/pull/2027)) ### Tools #### Blueprints Builder -- Add installPlugin support for single plugin files. ([#2033](https://github.com/WordPress/wordpress-playground/pull/2033)) +- Add installPlugin support for single plugin files. ([#2033](https://github.com/WordPress/wordpress-playground/pull/2033)) ### PHP WebAssembly -- Networking: Preserve the content-type header when fetch()-ing. ([#2028](https://github.com/WordPress/wordpress-playground/pull/2028)) +- Networking: Preserve the content-type header when fetch()-ing. ([#2028](https://github.com/WordPress/wordpress-playground/pull/2028)) ### Website -- [Web] Re-enable wp-cron. ([#2039](https://github.com/WordPress/wordpress-playground/pull/2039)) +- [Web] Re-enable wp-cron. ([#2039](https://github.com/WordPress/wordpress-playground/pull/2039)) ### Various -- [Data Liberation] WP_Stream_Importer: User-driven incremental import. ([#2013](https://github.com/WordPress/wordpress-playground/pull/2013)) +- [Data Liberation] WP_Stream_Importer: User-driven incremental import. ([#2013](https://github.com/WordPress/wordpress-playground/pull/2013)) ### Contributors @@ -1846,35 +1846,35 @@ The following contributors merged PRs in this release: ### Enhancements -- E2E: Disable a flaky deployment test. ([#2016](https://github.com/WordPress/wordpress-playground/pull/2016)) -- [Data Liberation] Add WXR import CLI script. ([#2012](https://github.com/WordPress/wordpress-playground/pull/2012)) -- [Data Liberation] Re-entrant WP_Stream_Importer. ([#2004](https://github.com/WordPress/wordpress-playground/pull/2004)) -- [Data Liberation] wp-admin importer page. ([#2003](https://github.com/WordPress/wordpress-playground/pull/2003)) +- E2E: Disable a flaky deployment test. ([#2016](https://github.com/WordPress/wordpress-playground/pull/2016)) +- [Data Liberation] Add WXR import CLI script. ([#2012](https://github.com/WordPress/wordpress-playground/pull/2012)) +- [Data Liberation] Re-entrant WP_Stream_Importer. ([#2004](https://github.com/WordPress/wordpress-playground/pull/2004)) +- [Data Liberation] wp-admin importer page. ([#2003](https://github.com/WordPress/wordpress-playground/pull/2003)) ### Blueprints -- SetSiteLanguage step – download the latest RC translations for Nightly and Beta builds of WordPress. ([#1987](https://github.com/WordPress/wordpress-playground/pull/1987)) -- Use the major WordPress version to download RC/beta translations. ([#2017](https://github.com/WordPress/wordpress-playground/pull/2017)) +- SetSiteLanguage step – download the latest RC translations for Nightly and Beta builds of WordPress. ([#1987](https://github.com/WordPress/wordpress-playground/pull/1987)) +- Use the major WordPress version to download RC/beta translations. ([#2017](https://github.com/WordPress/wordpress-playground/pull/2017)) ### Tools #### Pull Request Previewer -- Fix path of PR preview URL in production. ([#2014](https://github.com/WordPress/wordpress-playground/pull/2014)) -- Support submitting PR preview modal with ENTER key. ([#2015](https://github.com/WordPress/wordpress-playground/pull/2015)) +- Fix path of PR preview URL in production. ([#2014](https://github.com/WordPress/wordpress-playground/pull/2014)) +- Support submitting PR preview modal with ENTER key. ([#2015](https://github.com/WordPress/wordpress-playground/pull/2015)) ### Website -- Move WordPress & Gutenberg PR Preview to Playground website. ([#1938](https://github.com/WordPress/wordpress-playground/pull/1938)) -- Restore basic element styles for modal dialog content. ([#2021](https://github.com/WordPress/wordpress-playground/pull/2021)) +- Move WordPress & Gutenberg PR Preview to Playground website. ([#1938](https://github.com/WordPress/wordpress-playground/pull/1938)) +- Restore basic element styles for modal dialog content. ([#2021](https://github.com/WordPress/wordpress-playground/pull/2021)) ### Bug Fixes -- Fix test.md link. ([#2005](https://github.com/WordPress/wordpress-playground/pull/2005)) +- Fix test.md link. ([#2005](https://github.com/WordPress/wordpress-playground/pull/2005)) ### Various -- [Data Liberation] WP_Stream_Importer with support for WXR and Markdown files. ([#1982](https://github.com/WordPress/wordpress-playground/pull/1982)) +- [Data Liberation] WP_Stream_Importer with support for WXR and Markdown files. ([#1982](https://github.com/WordPress/wordpress-playground/pull/1982)) ### Contributors @@ -1886,11 +1886,11 @@ The following contributors merged PRs in this release: ### Website -- [Service Worker] Support redirects to relative URLs in Safari. ([#1978](https://github.com/WordPress/wordpress-playground/pull/1978)) +- [Service Worker] Support redirects to relative URLs in Safari. ([#1978](https://github.com/WordPress/wordpress-playground/pull/1978)) #### Blueprints -- [Query API] Use the exact redirect URL provided in the ?url= query param. ([#1945](https://github.com/WordPress/wordpress-playground/pull/1945)) +- [Query API] Use the exact redirect URL provided in the ?url= query param. ([#1945](https://github.com/WordPress/wordpress-playground/pull/1945)) ### Contributors @@ -1904,11 +1904,11 @@ The following contributors merged PRs in this release: ### Enhancements -- [CLI] Set debug constants during boot. ([#1983](https://github.com/WordPress/wordpress-playground/pull/1983)) +- [CLI] Set debug constants during boot. ([#1983](https://github.com/WordPress/wordpress-playground/pull/1983)) ### Bug Fixes -- [CLI] Restore the "login" argument handler. ([#1985](https://github.com/WordPress/wordpress-playground/pull/1985)) +- [CLI] Restore the "login" argument handler. ([#1985](https://github.com/WordPress/wordpress-playground/pull/1985)) ### Contributors @@ -1920,28 +1920,28 @@ The following contributors merged PRs in this release: ### Enhancements -- [Data Liberation] Fork humanmade/WordPress-Importer. ([#1968](https://github.com/WordPress/wordpress-playground/pull/1968)) -- [Data Liberation] Merge both XML processors into a single WP_XML_Processor. ([#1960](https://github.com/WordPress/wordpress-playground/pull/1960)) -- [Data liberation] Add blueprints-library as a submodule. ([#1967](https://github.com/WordPress/wordpress-playground/pull/1967)) +- [Data Liberation] Fork humanmade/WordPress-Importer. ([#1968](https://github.com/WordPress/wordpress-playground/pull/1968)) +- [Data Liberation] Merge both XML processors into a single WP_XML_Processor. ([#1960](https://github.com/WordPress/wordpress-playground/pull/1960)) +- [Data liberation] Add blueprints-library as a submodule. ([#1967](https://github.com/WordPress/wordpress-playground/pull/1967)) ### Tools #### Import/Export -- [Data Liberation] WP_WXR_Reader. ([#1972](https://github.com/WordPress/wordpress-playground/pull/1972)) +- [Data Liberation] WP_WXR_Reader. ([#1972](https://github.com/WordPress/wordpress-playground/pull/1972)) ### Documentation -- Rewrite clone examples to use HTTPS instead of SSH. ([#1963](https://github.com/WordPress/wordpress-playground/pull/1963)) +- Rewrite clone examples to use HTTPS instead of SSH. ([#1963](https://github.com/WordPress/wordpress-playground/pull/1963)) ### Website -- Consistent width of settings, logs, and blueprint gallery sidebars. ([#1964](https://github.com/WordPress/wordpress-playground/pull/1964)) +- Consistent width of settings, logs, and blueprint gallery sidebars. ([#1964](https://github.com/WordPress/wordpress-playground/pull/1964)) ### Bug Fixes -- Fix: Import & Export from Github causes reloading the playground even before accept this step. ([#1908](https://github.com/WordPress/wordpress-playground/pull/1908)) -- [WordPress build] Only build the latest patch version of WordPress. ([#1955](https://github.com/WordPress/wordpress-playground/pull/1955)) +- Fix: Import & Export from Github causes reloading the playground even before accept this step. ([#1908](https://github.com/WordPress/wordpress-playground/pull/1908)) +- [WordPress build] Only build the latest patch version of WordPress. ([#1955](https://github.com/WordPress/wordpress-playground/pull/1955)) ### Contributors @@ -1953,19 +1953,19 @@ The following contributors merged PRs in this release: ### Enhancements -- [Data liberation] wp_rewrite_urls(). ([#1893](https://github.com/WordPress/wordpress-playground/pull/1893)) +- [Data liberation] wp_rewrite_urls(). ([#1893](https://github.com/WordPress/wordpress-playground/pull/1893)) ### PHP WebAssembly -- [PHP.wasm for Node] Fix php.js import path in the published npm package. ([#1958](https://github.com/WordPress/wordpress-playground/pull/1958)) +- [PHP.wasm for Node] Fix php.js import path in the published npm package. ([#1958](https://github.com/WordPress/wordpress-playground/pull/1958)) ### Website -- Restore .d.ts files missing from the published @wp-playground/remote npm package. ([#1949](https://github.com/WordPress/wordpress-playground/pull/1949)) +- Restore .d.ts files missing from the published @wp-playground/remote npm package. ([#1949](https://github.com/WordPress/wordpress-playground/pull/1949)) ### Various -- [Data Liberation] Add XML API, Stream API, WXR URL Rewriter API. ([#1952](https://github.com/WordPress/wordpress-playground/pull/1952)) +- [Data Liberation] Add XML API, Stream API, WXR URL Rewriter API. ([#1952](https://github.com/WordPress/wordpress-playground/pull/1952)) ### Contributors @@ -1979,8 +1979,8 @@ The following contributors merged PRs in this release: ### Website -- Query API: Preserve multiple ?plugin= query params. ([#1947](https://github.com/WordPress/wordpress-playground/pull/1947)) -- [Remote] Enable releasing @wp-playground/remote by making it public. ([#1948](https://github.com/WordPress/wordpress-playground/pull/1948)) +- Query API: Preserve multiple ?plugin= query params. ([#1947](https://github.com/WordPress/wordpress-playground/pull/1947)) +- [Remote] Enable releasing @wp-playground/remote by making it public. ([#1948](https://github.com/WordPress/wordpress-playground/pull/1948)) ### Contributors @@ -1992,34 +1992,34 @@ The following contributors merged PRs in this release: ### Enhancements -- [CORS Proxy] Rate-limits IPv6 requests based on /64 subnets, not specific addresses. ([#1923](https://github.com/WordPress/wordpress-playground/pull/1923)) +- [CORS Proxy] Rate-limits IPv6 requests based on /64 subnets, not specific addresses. ([#1923](https://github.com/WordPress/wordpress-playground/pull/1923)) ### Blueprints -- Reload after autologin to set login cookies during boot. ([#1914](https://github.com/WordPress/wordpress-playground/pull/1914)) -- Skip empty lines in the runSql step. ([#1939](https://github.com/WordPress/wordpress-playground/pull/1939)) +- Reload after autologin to set login cookies during boot. ([#1914](https://github.com/WordPress/wordpress-playground/pull/1914)) +- Skip empty lines in the runSql step. ([#1939](https://github.com/WordPress/wordpress-playground/pull/1939)) ### Documentation -- Clarified wp beta to also include rc version. ([#1936](https://github.com/WordPress/wordpress-playground/pull/1936)) +- Clarified wp beta to also include rc version. ([#1936](https://github.com/WordPress/wordpress-playground/pull/1936)) ### PHP WebAssembly -- Enable CURL in Playground Web. ([#1935](https://github.com/WordPress/wordpress-playground/pull/1935)) -- PHP: Implement TLS 1.2 to decrypt https:// and ssl:// traffic and translate it into fetch(). ([#1926](https://github.com/WordPress/wordpress-playground/pull/1926)) +- Enable CURL in Playground Web. ([#1935](https://github.com/WordPress/wordpress-playground/pull/1935)) +- PHP: Implement TLS 1.2 to decrypt https:// and ssl:// traffic and translate it into fetch(). ([#1926](https://github.com/WordPress/wordpress-playground/pull/1926)) ### Website -- Hide Settings menu after clicking "Restore from .zip. ([#1904](https://github.com/WordPress/wordpress-playground/pull/1904)) -- Publish @wp-playground/remote (types only). ([#1924](https://github.com/WordPress/wordpress-playground/pull/1924)) +- Hide Settings menu after clicking "Restore from .zip. ([#1904](https://github.com/WordPress/wordpress-playground/pull/1904)) +- Publish @wp-playground/remote (types only). ([#1924](https://github.com/WordPress/wordpress-playground/pull/1924)) ### Bug Fixes -- CORS Proxy: Index update_at column because it is used for lookup. ([#1931](https://github.com/WordPress/wordpress-playground/pull/1931)) -- CORS Proxy: Reject targeting self. ([#1932](https://github.com/WordPress/wordpress-playground/pull/1932)) -- Docs: Fix typo. ([#1934](https://github.com/WordPress/wordpress-playground/pull/1934)) -- Explicitly request no-cache to discourage WP Cloud from edge caching CORS proxy results. ([#1930](https://github.com/WordPress/wordpress-playground/pull/1930)) -- Remove test code added in #1914. ([#1928](https://github.com/WordPress/wordpress-playground/pull/1928)) +- CORS Proxy: Index update_at column because it is used for lookup. ([#1931](https://github.com/WordPress/wordpress-playground/pull/1931)) +- CORS Proxy: Reject targeting self. ([#1932](https://github.com/WordPress/wordpress-playground/pull/1932)) +- Docs: Fix typo. ([#1934](https://github.com/WordPress/wordpress-playground/pull/1934)) +- Explicitly request no-cache to discourage WP Cloud from edge caching CORS proxy results. ([#1930](https://github.com/WordPress/wordpress-playground/pull/1930)) +- Remove test code added in #1914. ([#1928](https://github.com/WordPress/wordpress-playground/pull/1928)) ### Contributors @@ -2031,50 +2031,50 @@ The following contributors merged PRs in this release: ### Enhancements -- Support CORS proxy rate-limiting. ([#1879](https://github.com/WordPress/wordpress-playground/pull/1879)) +- Support CORS proxy rate-limiting. ([#1879](https://github.com/WordPress/wordpress-playground/pull/1879)) ### Blueprints -- Allow multisites to load wp-admin pages with the landingPage attribute. ([#1913](https://github.com/WordPress/wordpress-playground/pull/1913)) +- Allow multisites to load wp-admin pages with the landingPage attribute. ([#1913](https://github.com/WordPress/wordpress-playground/pull/1913)) ### Tools #### GitHub integration -- Blueprints: Use `?` instead of `/` to CORS Proxy URLs. ([#1899](https://github.com/WordPress/wordpress-playground/pull/1899)) +- Blueprints: Use `?` instead of `/` to CORS Proxy URLs. ([#1899](https://github.com/WordPress/wordpress-playground/pull/1899)) #### Import/Export -- Kickoff Data Liberation: Let's Build WordPress-first Data Migration Tools. ([#1888](https://github.com/WordPress/wordpress-playground/pull/1888)) +- Kickoff Data Liberation: Let's Build WordPress-first Data Migration Tools. ([#1888](https://github.com/WordPress/wordpress-playground/pull/1888)) ### Experiments #### File Synchronization -- [Remote] Preserve PHP constants when saving a temporary site. ([#1911](https://github.com/WordPress/wordpress-playground/pull/1911)) +- [Remote] Preserve PHP constants when saving a temporary site. ([#1911](https://github.com/WordPress/wordpress-playground/pull/1911)) ### Website -- Do not display "You have no Playgrounds" message before loading the site. ([#1912](https://github.com/WordPress/wordpress-playground/pull/1912)) -- Fix build error that only appeared during deployment. ([#1896](https://github.com/WordPress/wordpress-playground/pull/1896)) -- Fix use of secrets on WP Cloud site. ([#1909](https://github.com/WordPress/wordpress-playground/pull/1909)) -- Maintain Query API parameters on temporary Playground settings update. ([#1910](https://github.com/WordPress/wordpress-playground/pull/1910)) -- Stop adding all CORS proxy files to website build. ([#1895](https://github.com/WordPress/wordpress-playground/pull/1895)) -- Stop responding with default MIME type. ([#1897](https://github.com/WordPress/wordpress-playground/pull/1897)) -- Stop short-circuiting web host PHP execution. ([#1898](https://github.com/WordPress/wordpress-playground/pull/1898)) -- Fix progress reporting during Playground load. ([#1915](https://github.com/WordPress/wordpress-playground/pull/1915)) -- Include CORS proxy with website builds. ([#1880](https://github.com/WordPress/wordpress-playground/pull/1880)) -- [Blueprints] Stop escaping landingPage URLs when loading WP Admin. ([#1891](https://github.com/WordPress/wordpress-playground/pull/1891)) +- Do not display "You have no Playgrounds" message before loading the site. ([#1912](https://github.com/WordPress/wordpress-playground/pull/1912)) +- Fix build error that only appeared during deployment. ([#1896](https://github.com/WordPress/wordpress-playground/pull/1896)) +- Fix use of secrets on WP Cloud site. ([#1909](https://github.com/WordPress/wordpress-playground/pull/1909)) +- Maintain Query API parameters on temporary Playground settings update. ([#1910](https://github.com/WordPress/wordpress-playground/pull/1910)) +- Stop adding all CORS proxy files to website build. ([#1895](https://github.com/WordPress/wordpress-playground/pull/1895)) +- Stop responding with default MIME type. ([#1897](https://github.com/WordPress/wordpress-playground/pull/1897)) +- Stop short-circuiting web host PHP execution. ([#1898](https://github.com/WordPress/wordpress-playground/pull/1898)) +- Fix progress reporting during Playground load. ([#1915](https://github.com/WordPress/wordpress-playground/pull/1915)) +- Include CORS proxy with website builds. ([#1880](https://github.com/WordPress/wordpress-playground/pull/1880)) +- [Blueprints] Stop escaping landingPage URLs when loading WP Admin. ([#1891](https://github.com/WordPress/wordpress-playground/pull/1891)) ### Bug Fixes #### Boot Flow -- Prefer pretty permalinks like WP install does. ([#1832](https://github.com/WordPress/wordpress-playground/pull/1832)) +- Prefer pretty permalinks like WP install does. ([#1832](https://github.com/WordPress/wordpress-playground/pull/1832)) ### Various -- Improve self-host documentation. ([#1884](https://github.com/WordPress/wordpress-playground/pull/1884)) +- Improve self-host documentation. ([#1884](https://github.com/WordPress/wordpress-playground/pull/1884)) ### Contributors @@ -2086,18 +2086,18 @@ The following contributors merged PRs in this release: ### Enhancements -- Website: Remove unused React components. ([#1887](https://github.com/WordPress/wordpress-playground/pull/1887)) +- Website: Remove unused React components. ([#1887](https://github.com/WordPress/wordpress-playground/pull/1887)) ### Tools #### Blueprints Builder -- Blueprints sidebar section for single-click Playground presets. ([#1759](https://github.com/WordPress/wordpress-playground/pull/1759)) +- Blueprints sidebar section for single-click Playground presets. ([#1759](https://github.com/WordPress/wordpress-playground/pull/1759)) ### Website -- Replace 100vh with 100dvh to fix an "unscrollable" state on mobile devices. ([#1883](https://github.com/WordPress/wordpress-playground/pull/1883)) -- Use modal for Site settings form on mobile – mobile Safari l…. ([#1885](https://github.com/WordPress/wordpress-playground/pull/1885)) +- Replace 100vh with 100dvh to fix an "unscrollable" state on mobile devices. ([#1883](https://github.com/WordPress/wordpress-playground/pull/1883)) +- Use modal for Site settings form on mobile – mobile Safari l…. ([#1885](https://github.com/WordPress/wordpress-playground/pull/1885)) ### Contributors @@ -2109,7 +2109,7 @@ The following contributors merged PRs in this release: ### PHP WebAssembly -- PHP.wasm: Load correct php.wasm paths in the built Node.js packages. ([#1877](https://github.com/WordPress/wordpress-playground/pull/1877)) +- PHP.wasm: Load correct php.wasm paths in the built Node.js packages. ([#1877](https://github.com/WordPress/wordpress-playground/pull/1877)) ### Contributors @@ -2123,53 +2123,53 @@ The following contributors merged PRs in this release: ### Blueprints -- Directory Resources. ([#1793](https://github.com/WordPress/wordpress-playground/pull/1793)) -- Login step – handle passwordless autologin via a PHP mu-plugin. ([#1856](https://github.com/WordPress/wordpress-playground/pull/1856)) +- Directory Resources. ([#1793](https://github.com/WordPress/wordpress-playground/pull/1793)) +- Login step – handle passwordless autologin via a PHP mu-plugin. ([#1856](https://github.com/WordPress/wordpress-playground/pull/1856)) ### Tools #### Blueprints -- GitDirectoryResource. ([#1858](https://github.com/WordPress/wordpress-playground/pull/1858)) -- GitDirectoryResource: Accept "/", "", "." as root paths. ([#1860](https://github.com/WordPress/wordpress-playground/pull/1860)) +- GitDirectoryResource. ([#1858](https://github.com/WordPress/wordpress-playground/pull/1858)) +- GitDirectoryResource: Accept "/", "", "." as root paths. ([#1860](https://github.com/WordPress/wordpress-playground/pull/1860)) #### GitHub integration -- Native git support: LsRefs(), sparseCheckout(), GitPathControl. ([#1764](https://github.com/WordPress/wordpress-playground/pull/1764)) +- Native git support: LsRefs(), sparseCheckout(), GitPathControl. ([#1764](https://github.com/WordPress/wordpress-playground/pull/1764)) #### Website -- Add core-pr and gutenberg-pr Query API parameters. ([#1761](https://github.com/WordPress/wordpress-playground/pull/1761)) +- Add core-pr and gutenberg-pr Query API parameters. ([#1761](https://github.com/WordPress/wordpress-playground/pull/1761)) ### PHP WebAssembly -- Refreshless website deployments – load remote.html using the network-first strategy. ([#1849](https://github.com/WordPress/wordpress-playground/pull/1849)) -- JSPI: Pass all unit tests, remove stale PHP builds. ([#1876](https://github.com/WordPress/wordpress-playground/pull/1876)) -- [Remote] Remove the "light" PHP.wasm bundle and only ship the "kitchen-sink" build. ([#1861](https://github.com/WordPress/wordpress-playground/pull/1861)) +- Refreshless website deployments – load remote.html using the network-first strategy. ([#1849](https://github.com/WordPress/wordpress-playground/pull/1849)) +- JSPI: Pass all unit tests, remove stale PHP builds. ([#1876](https://github.com/WordPress/wordpress-playground/pull/1876)) +- [Remote] Remove the "light" PHP.wasm bundle and only ship the "kitchen-sink" build. ([#1861](https://github.com/WordPress/wordpress-playground/pull/1861)) ### Website -- Restore the single-click "Edit Settings" flow. ([#1854](https://github.com/WordPress/wordpress-playground/pull/1854)) -- Restrict CORS proxy to requests from Playground website origin. ([#1865](https://github.com/WordPress/wordpress-playground/pull/1865)) +- Restore the single-click "Edit Settings" flow. ([#1854](https://github.com/WordPress/wordpress-playground/pull/1854)) +- Restrict CORS proxy to requests from Playground website origin. ([#1865](https://github.com/WordPress/wordpress-playground/pull/1865)) #### Documentation -- Add /release redirect to WP beta/RC blueprint. ([#1866](https://github.com/WordPress/wordpress-playground/pull/1866)) +- Add /release redirect to WP beta/RC blueprint. ([#1866](https://github.com/WordPress/wordpress-playground/pull/1866)) ### Internal -- Make isomorphic-git submodule use https, not ssh. ([#1863](https://github.com/WordPress/wordpress-playground/pull/1863)) +- Make isomorphic-git submodule use https, not ssh. ([#1863](https://github.com/WordPress/wordpress-playground/pull/1863)) ### Bug Fixes -- [CLI] Fix `isWordPressInstalled()` in CLI by inlining the auto_login.php in index.ts instead of using import ?raw. ([#1869](https://github.com/WordPress/wordpress-playground/pull/1869)) +- [CLI] Fix `isWordPressInstalled()` in CLI by inlining the auto_login.php in index.ts instead of using import ?raw. ([#1869](https://github.com/WordPress/wordpress-playground/pull/1869)) ### Various -- Add documentation around the GPL license and implications for contribution. ([#1776](https://github.com/WordPress/wordpress-playground/pull/1776)) -- Allow installing Plugins/Themes into an arbitrary folder. ([#1803](https://github.com/WordPress/wordpress-playground/pull/1803)) -- Improve documentation. ([#1862](https://github.com/WordPress/wordpress-playground/pull/1862)) -- [Website] Fix "undefined" as className. ([#1870](https://github.com/WordPress/wordpress-playground/pull/1870)) +- Add documentation around the GPL license and implications for contribution. ([#1776](https://github.com/WordPress/wordpress-playground/pull/1776)) +- Allow installing Plugins/Themes into an arbitrary folder. ([#1803](https://github.com/WordPress/wordpress-playground/pull/1803)) +- Improve documentation. ([#1862](https://github.com/WordPress/wordpress-playground/pull/1862)) +- [Website] Fix "undefined" as className. ([#1870](https://github.com/WordPress/wordpress-playground/pull/1870)) ### Contributors @@ -2181,24 +2181,24 @@ The following contributors merged PRs in this release: ### Enhancements -- Webapp upgrade protocol: Disable HTTP caching and reload other browser tabs to prevent fatal errors after new deployments. ([#1822](https://github.com/WordPress/wordpress-playground/pull/1822)) +- Webapp upgrade protocol: Disable HTTP caching and reload other browser tabs to prevent fatal errors after new deployments. ([#1822](https://github.com/WordPress/wordpress-playground/pull/1822)) ### Documentation -- Docs: Disable localeDropdown until more pages are translated. ([#1824](https://github.com/WordPress/wordpress-playground/pull/1824)) -- Docs: Review playground documentation translations page. ([#1826](https://github.com/WordPress/wordpress-playground/pull/1826)) -- Docs: Playground PR previews through GitHub actions. ([#1825](https://github.com/WordPress/wordpress-playground/pull/1825)) +- Docs: Disable localeDropdown until more pages are translated. ([#1824](https://github.com/WordPress/wordpress-playground/pull/1824)) +- Docs: Review playground documentation translations page. ([#1826](https://github.com/WordPress/wordpress-playground/pull/1826)) +- Docs: Playground PR previews through GitHub actions. ([#1825](https://github.com/WordPress/wordpress-playground/pull/1825)) ### Website -- Use site slug as a stable scope. ([#1839](https://github.com/WordPress/wordpress-playground/pull/1839)) -- Close Playground Manager by default. ([#1831](https://github.com/WordPress/wordpress-playground/pull/1831)) -- Fix go-to-site menu items to reveal site view. ([#1833](https://github.com/WordPress/wordpress-playground/pull/1833)) +- Use site slug as a stable scope. ([#1839](https://github.com/WordPress/wordpress-playground/pull/1839)) +- Close Playground Manager by default. ([#1831](https://github.com/WordPress/wordpress-playground/pull/1831)) +- Fix go-to-site menu items to reveal site view. ([#1833](https://github.com/WordPress/wordpress-playground/pull/1833)) ### Various -- Add Install instructions to the Playwright README. ([#1837](https://github.com/WordPress/wordpress-playground/pull/1837)) -- Resolve end-to-end failures. ([#1844](https://github.com/WordPress/wordpress-playground/pull/1844)) +- Add Install instructions to the Playwright README. ([#1837](https://github.com/WordPress/wordpress-playground/pull/1837)) +- Resolve end-to-end failures. ([#1844](https://github.com/WordPress/wordpress-playground/pull/1844)) ### Contributors @@ -2210,29 +2210,29 @@ The following contributors merged PRs in this release: ### Blueprints -- Translate GitHub.com file URLs into CORS-accessible raw.githubusercontent.com. ([#1810](https://github.com/WordPress/wordpress-playground/pull/1810)) +- Translate GitHub.com file URLs into CORS-accessible raw.githubusercontent.com. ([#1810](https://github.com/WordPress/wordpress-playground/pull/1810)) ### Tools -- [UX] Stored Playgrounds (no more data loss), multiple Playgrounds, UI WebApp Redesign. ([#1731](https://github.com/WordPress/wordpress-playground/pull/1731)) +- [UX] Stored Playgrounds (no more data loss), multiple Playgrounds, UI WebApp Redesign. ([#1731](https://github.com/WordPress/wordpress-playground/pull/1731)) ### Documentation -- Docs: Translation i18n messages - JSON files. ([#1807](https://github.com/WordPress/wordpress-playground/pull/1807)) +- Docs: Translation i18n messages - JSON files. ([#1807](https://github.com/WordPress/wordpress-playground/pull/1807)) ### Website -- Prevent creation of two temporary sites. ([#1817](https://github.com/WordPress/wordpress-playground/pull/1817)) -- Stop address bar from adding trailing slash to query params. ([#1820](https://github.com/WordPress/wordpress-playground/pull/1820)) +- Prevent creation of two temporary sites. ([#1817](https://github.com/WordPress/wordpress-playground/pull/1817)) +- Stop address bar from adding trailing slash to query params. ([#1820](https://github.com/WordPress/wordpress-playground/pull/1820)) ### Bug Fixes -- Fix broken Playwright tests. ([#1819](https://github.com/WordPress/wordpress-playground/pull/1819)) +- Fix broken Playwright tests. ([#1819](https://github.com/WordPress/wordpress-playground/pull/1819)) ### Various -- Add Playwright tests for UI redesign changes. ([#1769](https://github.com/WordPress/wordpress-playground/pull/1769)) -- Docs: Contributions to translations. ([#1808](https://github.com/WordPress/wordpress-playground/pull/1808)) +- Add Playwright tests for UI redesign changes. ([#1769](https://github.com/WordPress/wordpress-playground/pull/1769)) +- Docs: Contributions to translations. ([#1808](https://github.com/WordPress/wordpress-playground/pull/1808)) ### Contributors @@ -2244,11 +2244,11 @@ The following contributors merged PRs in this release: ### Bug Fixes -- Docs: Fix links intro fr. ([#1795](https://github.com/WordPress/wordpress-playground/pull/1795)) +- Docs: Fix links intro fr. ([#1795](https://github.com/WordPress/wordpress-playground/pull/1795)) ### Various -- Add missing functions required to succesfully connect with MySQL DB. ([#1752](https://github.com/WordPress/wordpress-playground/pull/1752)) +- Add missing functions required to succesfully connect with MySQL DB. ([#1752](https://github.com/WordPress/wordpress-playground/pull/1752)) ### Contributors @@ -2260,17 +2260,17 @@ The following contributors merged PRs in this release: ### Documentation -- Docs: Better paths for links. ([#1765](https://github.com/WordPress/wordpress-playground/pull/1765)) -- Docs: I18n setup. ([#1766](https://github.com/WordPress/wordpress-playground/pull/1766)) -- Docs: Remove the outdated "data rependencies" page. ([#1785](https://github.com/WordPress/wordpress-playground/pull/1785)) +- Docs: Better paths for links. ([#1765](https://github.com/WordPress/wordpress-playground/pull/1765)) +- Docs: I18n setup. ([#1766](https://github.com/WordPress/wordpress-playground/pull/1766)) +- Docs: Remove the outdated "data rependencies" page. ([#1785](https://github.com/WordPress/wordpress-playground/pull/1785)) ### Website -- Fix troubleshoot-and-debug link. ([#1782](https://github.com/WordPress/wordpress-playground/pull/1782)) +- Fix troubleshoot-and-debug link. ([#1782](https://github.com/WordPress/wordpress-playground/pull/1782)) ### Various -- Update link for contributor day. ([#1775](https://github.com/WordPress/wordpress-playground/pull/1775)) +- Update link for contributor day. ([#1775](https://github.com/WordPress/wordpress-playground/pull/1775)) ### Contributors @@ -2282,7 +2282,7 @@ The following contributors merged PRs in this release: ### PHP WebAssembly -- FS: Use the correct rm/rmdir method when moving files between mounts. ([#1770](https://github.com/WordPress/wordpress-playground/pull/1770)) +- FS: Use the correct rm/rmdir method when moving files between mounts. ([#1770](https://github.com/WordPress/wordpress-playground/pull/1770)) ### Contributors @@ -2296,40 +2296,40 @@ The following contributors merged PRs in this release: ### Enhancements -- Extend allowable resources available via WordPress/WordPress. ([#1721](https://github.com/WordPress/wordpress-playground/pull/1721)) +- Extend allowable resources available via WordPress/WordPress. ([#1721](https://github.com/WordPress/wordpress-playground/pull/1721)) ### Tools -- Update actions/upload-artifact version to 4. ([#1748](https://github.com/WordPress/wordpress-playground/pull/1748)) +- Update actions/upload-artifact version to 4. ([#1748](https://github.com/WordPress/wordpress-playground/pull/1748)) ### Documentation -- Docs/Blueprints resources: Grammar and typo fixes. ([#1741](https://github.com/WordPress/wordpress-playground/pull/1741)) +- Docs/Blueprints resources: Grammar and typo fixes. ([#1741](https://github.com/WordPress/wordpress-playground/pull/1741)) ### PHP WebAssembly -- @php-wasm/universal : Add Phar support in php-wasm. ([#1716](https://github.com/WordPress/wordpress-playground/pull/1716)) +- @php-wasm/universal : Add Phar support in php-wasm. ([#1716](https://github.com/WordPress/wordpress-playground/pull/1716)) ### Website -- Add the `components` package with PathMappingControl. ([#1608](https://github.com/WordPress/wordpress-playground/pull/1608)) +- Add the `components` package with PathMappingControl. ([#1608](https://github.com/WordPress/wordpress-playground/pull/1608)) ### Bug Fixes -- Fix CLI --skipWordPressSetup option. ([#1760](https://github.com/WordPress/wordpress-playground/pull/1760)) +- Fix CLI --skipWordPressSetup option. ([#1760](https://github.com/WordPress/wordpress-playground/pull/1760)) ### Reliability -- Improve Playground CLI logging and fix quiet mode. ([#1751](https://github.com/WordPress/wordpress-playground/pull/1751)) +- Improve Playground CLI logging and fix quiet mode. ([#1751](https://github.com/WordPress/wordpress-playground/pull/1751)) ### Various -- Docs/Guides: Guides introductions and some minor adjustments. ([#1754](https://github.com/WordPress/wordpress-playground/pull/1754)) -- Docs/Guides: Normalized and fixed guides links. ([#1756](https://github.com/WordPress/wordpress-playground/pull/1756)) -- Docs/Guides: Providing content for your demo. ([#1747](https://github.com/WordPress/wordpress-playground/pull/1747)) -- Docs/Guides: WordPress Playground for plugin developers. ([#1750](https://github.com/WordPress/wordpress-playground/pull/1750)) -- Docs/Guides: WordPress Playground for theme developers. ([#1732](https://github.com/WordPress/wordpress-playground/pull/1732)) -- Docs: Links redirections. ([#1758](https://github.com/WordPress/wordpress-playground/pull/1758)) +- Docs/Guides: Guides introductions and some minor adjustments. ([#1754](https://github.com/WordPress/wordpress-playground/pull/1754)) +- Docs/Guides: Normalized and fixed guides links. ([#1756](https://github.com/WordPress/wordpress-playground/pull/1756)) +- Docs/Guides: Providing content for your demo. ([#1747](https://github.com/WordPress/wordpress-playground/pull/1747)) +- Docs/Guides: WordPress Playground for plugin developers. ([#1750](https://github.com/WordPress/wordpress-playground/pull/1750)) +- Docs/Guides: WordPress Playground for theme developers. ([#1732](https://github.com/WordPress/wordpress-playground/pull/1732)) +- Docs: Links redirections. ([#1758](https://github.com/WordPress/wordpress-playground/pull/1758)) ### Contributors @@ -2341,7 +2341,7 @@ The following contributors merged PRs in this release: ### Bug Fixes -- Use the correct imports in the generated .d.ts files. ([#1742](https://github.com/WordPress/wordpress-playground/pull/1742)) +- Use the correct imports in the generated .d.ts files. ([#1742](https://github.com/WordPress/wordpress-playground/pull/1742)) ### Contributors @@ -2353,13 +2353,13 @@ The following contributors merged PRs in this release: ### Internal -- Fix changelog updates for latest doc structure. ([#1734](https://github.com/WordPress/wordpress-playground/pull/1734)) +- Fix changelog updates for latest doc structure. ([#1734](https://github.com/WordPress/wordpress-playground/pull/1734)) ### Various -- Add support for handling symlinks in the request handler. ([#1724](https://github.com/WordPress/wordpress-playground/pull/1724)) -- Docs: Playground block in launch section. ([#1722](https://github.com/WordPress/wordpress-playground/pull/1722)) -- documentation - Blueprints - Resources: Highlight installPlugin and installTheme steps and most common resouces for them. ([#1733](https://github.com/WordPress/wordpress-playground/pull/1733)) +- Add support for handling symlinks in the request handler. ([#1724](https://github.com/WordPress/wordpress-playground/pull/1724)) +- Docs: Playground block in launch section. ([#1722](https://github.com/WordPress/wordpress-playground/pull/1722)) +- documentation - Blueprints - Resources: Highlight installPlugin and installTheme steps and most common resouces for them. ([#1733](https://github.com/WordPress/wordpress-playground/pull/1733)) ### Contributors @@ -2371,11 +2371,11 @@ The following contributors merged PRs in this release: ### PHP WebAssembly -- Add more asyncify-listed PHP functions to fix Studio crash. ([#1729](https://github.com/WordPress/wordpress-playground/pull/1729)) +- Add more asyncify-listed PHP functions to fix Studio crash. ([#1729](https://github.com/WordPress/wordpress-playground/pull/1729)) ### Website -- Add initial site info view. ([#1701](https://github.com/WordPress/wordpress-playground/pull/1701)) +- Add initial site info view. ([#1701](https://github.com/WordPress/wordpress-playground/pull/1701)) ### Contributors @@ -2387,11 +2387,11 @@ The following contributors merged PRs in this release: ### Bug Fixes -- Fix logger test for inconsistent short month. ([#1727](https://github.com/WordPress/wordpress-playground/pull/1727)) +- Fix logger test for inconsistent short month. ([#1727](https://github.com/WordPress/wordpress-playground/pull/1727)) ### Reliability -- Avoid errors due to log message formatting. ([#1726](https://github.com/WordPress/wordpress-playground/pull/1726)) +- Avoid errors due to log message formatting. ([#1726](https://github.com/WordPress/wordpress-playground/pull/1726)) ### Contributors @@ -2403,15 +2403,15 @@ The following contributors merged PRs in this release: ### Enhancements -- Allow specifying a WordPres/WordPress branch and pulling from GitHub. ([#1705](https://github.com/WordPress/wordpress-playground/pull/1705)) +- Allow specifying a WordPres/WordPress branch and pulling from GitHub. ([#1705](https://github.com/WordPress/wordpress-playground/pull/1705)) ### PHP WebAssembly -- Fix: Exit http server on php exit. ([#1714](https://github.com/WordPress/wordpress-playground/pull/1714)) +- Fix: Exit http server on php exit. ([#1714](https://github.com/WordPress/wordpress-playground/pull/1714)) ### Various -- Enable networking for WordPress and Gutenberg PR viewers. ([#1715](https://github.com/WordPress/wordpress-playground/pull/1715)) +- Enable networking for WordPress and Gutenberg PR viewers. ([#1715](https://github.com/WordPress/wordpress-playground/pull/1715)) ### Contributors @@ -2423,7 +2423,7 @@ The following contributors merged PRs in this release: ### PHP WebAssembly -- @php-wasm/node: Publish index.d.ts. ([#1713](https://github.com/WordPress/wordpress-playground/pull/1713)) +- @php-wasm/node: Publish index.d.ts. ([#1713](https://github.com/WordPress/wordpress-playground/pull/1713)) ### Contributors @@ -2435,7 +2435,7 @@ The following contributors merged PRs in this release: ### Internal -- @php-wasm/util: Publish TypeScript types. ([#1711](https://github.com/WordPress/wordpress-playground/pull/1711)) +- @php-wasm/util: Publish TypeScript types. ([#1711](https://github.com/WordPress/wordpress-playground/pull/1711)) ### Contributors @@ -2447,15 +2447,15 @@ The following contributors merged PRs in this release: ### Website -- Make the site switcher work again. ([#1698](https://github.com/WordPress/wordpress-playground/pull/1698)) -- WebApp Redesign: Interact with sites list via redux. ([#1679](https://github.com/WordPress/wordpress-playground/pull/1679)) -- deployment: Fix builder redirect. ([#1696](https://github.com/WordPress/wordpress-playground/pull/1696)) +- Make the site switcher work again. ([#1698](https://github.com/WordPress/wordpress-playground/pull/1698)) +- WebApp Redesign: Interact with sites list via redux. ([#1679](https://github.com/WordPress/wordpress-playground/pull/1679)) +- deployment: Fix builder redirect. ([#1696](https://github.com/WordPress/wordpress-playground/pull/1696)) ### Bug Fixes -- Docs: Fix typo and replace en dash with hyphen for consistency. ([#1702](https://github.com/WordPress/wordpress-playground/pull/1702)) -- Fix broken documentation links. ([#1694](https://github.com/WordPress/wordpress-playground/pull/1694)) -- Remove Playground branding from site list. ([#1700](https://github.com/WordPress/wordpress-playground/pull/1700)) +- Docs: Fix typo and replace en dash with hyphen for consistency. ([#1702](https://github.com/WordPress/wordpress-playground/pull/1702)) +- Fix broken documentation links. ([#1694](https://github.com/WordPress/wordpress-playground/pull/1694)) +- Remove Playground branding from site list. ([#1700](https://github.com/WordPress/wordpress-playground/pull/1700)) ### Contributors @@ -2469,30 +2469,30 @@ The following contributors merged PRs in this release: #### Boot Flow -- A boot() method to explicitly initialize the PHP worker. ([#1669](https://github.com/WordPress/wordpress-playground/pull/1669)) +- A boot() method to explicitly initialize the PHP worker. ([#1669](https://github.com/WordPress/wordpress-playground/pull/1669)) ### Website -- Fix builder redirect. ([#1693](https://github.com/WordPress/wordpress-playground/pull/1693)) +- Fix builder redirect. ([#1693](https://github.com/WordPress/wordpress-playground/pull/1693)) ### Internal -- Avoid GH board automation permissions error. ([#1691](https://github.com/WordPress/wordpress-playground/pull/1691)) -- Refresh sqlite-database-integration from develop branch. ([#1692](https://github.com/WordPress/wordpress-playground/pull/1692)) +- Avoid GH board automation permissions error. ([#1691](https://github.com/WordPress/wordpress-playground/pull/1691)) +- Refresh sqlite-database-integration from develop branch. ([#1692](https://github.com/WordPress/wordpress-playground/pull/1692)) ### Bug Fixes #### Boot Flow -- Fix sqlite-database-integration rename fatal. ([#1695](https://github.com/WordPress/wordpress-playground/pull/1695)) +- Fix sqlite-database-integration rename fatal. ([#1695](https://github.com/WordPress/wordpress-playground/pull/1695)) #### Documentation -- Docs: Fix links to proper pages. ([#1690](https://github.com/WordPress/wordpress-playground/pull/1690)) +- Docs: Fix links to proper pages. ([#1690](https://github.com/WordPress/wordpress-playground/pull/1690)) ### Various -- Documentation structure overhaul. ([#1602](https://github.com/WordPress/wordpress-playground/pull/1602)) +- Documentation structure overhaul. ([#1602](https://github.com/WordPress/wordpress-playground/pull/1602)) ### Contributors @@ -2504,15 +2504,15 @@ The following contributors merged PRs in this release: ### Website -- Ask users to report errors if Playground load fails. ([#1686](https://github.com/WordPress/wordpress-playground/pull/1686)) +- Ask users to report errors if Playground load fails. ([#1686](https://github.com/WordPress/wordpress-playground/pull/1686)) ### Bug Fixes -- Avoid Blueprint schema formatting changes by build. ([#1685](https://github.com/WordPress/wordpress-playground/pull/1685)) +- Avoid Blueprint schema formatting changes by build. ([#1685](https://github.com/WordPress/wordpress-playground/pull/1685)) ### Various -- [Website] Improves the messaging around exporting a zip if needed, when connecting to GitHub. ([#1689](https://github.com/WordPress/wordpress-playground/pull/1689)) +- [Website] Improves the messaging around exporting a zip if needed, when connecting to GitHub. ([#1689](https://github.com/WordPress/wordpress-playground/pull/1689)) ### Contributors @@ -2524,27 +2524,27 @@ The following contributors merged PRs in this release: ### Tools -- Add max-len rule. ([#1613](https://github.com/WordPress/wordpress-playground/pull/1613)) +- Add max-len rule. ([#1613](https://github.com/WordPress/wordpress-playground/pull/1613)) ### Experiments #### GitHub integration -- Add site manager view and sidebar. ([#1661](https://github.com/WordPress/wordpress-playground/pull/1661)) -- Add sites from the site manager. ([#1680](https://github.com/WordPress/wordpress-playground/pull/1680)) +- Add site manager view and sidebar. ([#1661](https://github.com/WordPress/wordpress-playground/pull/1661)) +- Add sites from the site manager. ([#1680](https://github.com/WordPress/wordpress-playground/pull/1680)) ### PHP WebAssembly -- Offline mode end-to-end tests. ([#1648](https://github.com/WordPress/wordpress-playground/pull/1648)) +- Offline mode end-to-end tests. ([#1648](https://github.com/WordPress/wordpress-playground/pull/1648)) ### Website -- Add nice redirects for the new documentation site. ([#1681](https://github.com/WordPress/wordpress-playground/pull/1681)) -- Fix site manager button styles. ([#1676](https://github.com/WordPress/wordpress-playground/pull/1676)) +- Add nice redirects for the new documentation site. ([#1681](https://github.com/WordPress/wordpress-playground/pull/1681)) +- Fix site manager button styles. ([#1676](https://github.com/WordPress/wordpress-playground/pull/1676)) ### Bug Fixes -- Revert "Offline mode end-to-end tests". ([#1673](https://github.com/WordPress/wordpress-playground/pull/1673)) +- Revert "Offline mode end-to-end tests". ([#1673](https://github.com/WordPress/wordpress-playground/pull/1673)) ### Contributors @@ -2556,31 +2556,31 @@ The following contributors merged PRs in this release: ### Blueprints -- Add support for loading wpCli without running blueprint steps. ([#1629](https://github.com/WordPress/wordpress-playground/pull/1629)) +- Add support for loading wpCli without running blueprint steps. ([#1629](https://github.com/WordPress/wordpress-playground/pull/1629)) ### Documentation -- Blueprints: Add resetData step to documentation. ([#1658](https://github.com/WordPress/wordpress-playground/pull/1658)) -- Docs: Redirect from /docs to https://wordpress.github.io/wordpress-playground. ([#1671](https://github.com/WordPress/wordpress-playground/pull/1671)) +- Blueprints: Add resetData step to documentation. ([#1658](https://github.com/WordPress/wordpress-playground/pull/1658)) +- Docs: Redirect from /docs to https://wordpress.github.io/wordpress-playground. ([#1671](https://github.com/WordPress/wordpress-playground/pull/1671)) ### Website -- Suppress unavoidable Deprecated notices - Networking. ([#1660](https://github.com/WordPress/wordpress-playground/pull/1660)) -- UI: Explain the Logs modal. ([#1666](https://github.com/WordPress/wordpress-playground/pull/1666)) +- Suppress unavoidable Deprecated notices - Networking. ([#1660](https://github.com/WordPress/wordpress-playground/pull/1660)) +- UI: Explain the Logs modal. ([#1666](https://github.com/WordPress/wordpress-playground/pull/1666)) #### Blueprints -- Precompile Ajv Blueprint validator to avoid CSP issues. ([#1649](https://github.com/WordPress/wordpress-playground/pull/1649)) +- Precompile Ajv Blueprint validator to avoid CSP issues. ([#1649](https://github.com/WordPress/wordpress-playground/pull/1649)) ### Internal -- Reinstantiate Changelog generation in GitHub CI. ([#1657](https://github.com/WordPress/wordpress-playground/pull/1657)) +- Reinstantiate Changelog generation in GitHub CI. ([#1657](https://github.com/WordPress/wordpress-playground/pull/1657)) ### Various -- Rollback artifact creation to enable downloading a pre-built package …. ([#1624](https://github.com/WordPress/wordpress-playground/pull/1624)) -- Update WordPress packages. ([#1672](https://github.com/WordPress/wordpress-playground/pull/1672)) -- Update `ws` package version to fix DOS vulnerability. ([#1635](https://github.com/WordPress/wordpress-playground/pull/1635)) +- Rollback artifact creation to enable downloading a pre-built package …. ([#1624](https://github.com/WordPress/wordpress-playground/pull/1624)) +- Update WordPress packages. ([#1672](https://github.com/WordPress/wordpress-playground/pull/1672)) +- Update `ws` package version to fix DOS vulnerability. ([#1635](https://github.com/WordPress/wordpress-playground/pull/1635)) ### Contributors @@ -2592,17 +2592,17 @@ The following contributors merged PRs in this release: ### Enhancements -- Support offline mode after the first Playground page load. ([#1643](https://github.com/WordPress/wordpress-playground/pull/1643)) +- Support offline mode after the first Playground page load. ([#1643](https://github.com/WordPress/wordpress-playground/pull/1643)) ### Devrel -- Remove puzzle app package. ([#1642](https://github.com/WordPress/wordpress-playground/pull/1642)) +- Remove puzzle app package. ([#1642](https://github.com/WordPress/wordpress-playground/pull/1642)) ### PHP WebAssembly -- Cache Playground assets to enable offline support. ([#1535](https://github.com/WordPress/wordpress-playground/pull/1535)) -- Rotate PHP runtime after runtime crash. ([#1628](https://github.com/WordPress/wordpress-playground/pull/1628)) -- Throw error when PHP run() receives no code to run. ([#1646](https://github.com/WordPress/wordpress-playground/pull/1646)) +- Cache Playground assets to enable offline support. ([#1535](https://github.com/WordPress/wordpress-playground/pull/1535)) +- Rotate PHP runtime after runtime crash. ([#1628](https://github.com/WordPress/wordpress-playground/pull/1628)) +- Throw error when PHP run() receives no code to run. ([#1646](https://github.com/WordPress/wordpress-playground/pull/1646)) ### Contributors @@ -2614,7 +2614,7 @@ The following contributors merged PRs in this release: ### Blueprints -- Add missing blueprints library dep. ([#1640](https://github.com/WordPress/wordpress-playground/pull/1640)) +- Add missing blueprints library dep. ([#1640](https://github.com/WordPress/wordpress-playground/pull/1640)) ### Contributors @@ -2626,7 +2626,7 @@ The following contributors merged PRs in this release: ### Tools -- Make sure NPM packages declare dependencies. ([#1639](https://github.com/WordPress/wordpress-playground/pull/1639)) +- Make sure NPM packages declare dependencies. ([#1639](https://github.com/WordPress/wordpress-playground/pull/1639)) ### Contributors @@ -2638,8 +2638,8 @@ The following contributors merged PRs in this release: ### Bug Fixes -- Fix plugin-proxy response codes. ([#1636](https://github.com/WordPress/wordpress-playground/pull/1636)) -- Stop publishing @wp-playground/wordpress-builds package. ([#1637](https://github.com/WordPress/wordpress-playground/pull/1637)) +- Fix plugin-proxy response codes. ([#1636](https://github.com/WordPress/wordpress-playground/pull/1636)) +- Stop publishing @wp-playground/wordpress-builds package. ([#1637](https://github.com/WordPress/wordpress-playground/pull/1637)) ### Contributors @@ -2651,11 +2651,11 @@ The following contributors merged PRs in this release: ### PHP WebAssembly -- Route requests more like a normal web server. ([#1539](https://github.com/WordPress/wordpress-playground/pull/1539)) +- Route requests more like a normal web server. ([#1539](https://github.com/WordPress/wordpress-playground/pull/1539)) ### Website -- Remove old, unused website deployment workflow. ([#1633](https://github.com/WordPress/wordpress-playground/pull/1633)) +- Remove old, unused website deployment workflow. ([#1633](https://github.com/WordPress/wordpress-playground/pull/1633)) ### Contributors @@ -2667,7 +2667,7 @@ The following contributors merged PRs in this release: ### Bug Fixes -- Remove WP 6.2 support after WP 6.6 release. ([#1632](https://github.com/WordPress/wordpress-playground/pull/1632)) +- Remove WP 6.2 support after WP 6.6 release. ([#1632](https://github.com/WordPress/wordpress-playground/pull/1632)) ### Contributors @@ -2679,15 +2679,15 @@ The following contributors merged PRs in this release: ### Website -- Fix manifest.json URLs. ([#1615](https://github.com/WordPress/wordpress-playground/pull/1615)) +- Fix manifest.json URLs. ([#1615](https://github.com/WordPress/wordpress-playground/pull/1615)) ### Internal -- Fix joinPaths root edge case. ([#1620](https://github.com/WordPress/wordpress-playground/pull/1620)) +- Fix joinPaths root edge case. ([#1620](https://github.com/WordPress/wordpress-playground/pull/1620)) ### Various -- Disable PHP 7.0 and 7.1 version switcher end-to-end tests. ([#1626](https://github.com/WordPress/wordpress-playground/pull/1626)) +- Disable PHP 7.0 and 7.1 version switcher end-to-end tests. ([#1626](https://github.com/WordPress/wordpress-playground/pull/1626)) ### Contributors @@ -2701,27 +2701,27 @@ The following contributors merged PRs in this release: #### Boot Flow -- Backfill the assets removed from minified WordPress bundles. ([#1604](https://github.com/WordPress/wordpress-playground/pull/1604)) -- Register service worker before spawning the worker thread. ([#1606](https://github.com/WordPress/wordpress-playground/pull/1606)) +- Backfill the assets removed from minified WordPress bundles. ([#1604](https://github.com/WordPress/wordpress-playground/pull/1604)) +- Register service worker before spawning the worker thread. ([#1606](https://github.com/WordPress/wordpress-playground/pull/1606)) ### Website -- Disable website features that don't work while offline. ([#1607](https://github.com/WordPress/wordpress-playground/pull/1607)) -- Generate a list of assets to cache for offline support. ([#1573](https://github.com/WordPress/wordpress-playground/pull/1573)) +- Disable website features that don't work while offline. ([#1607](https://github.com/WordPress/wordpress-playground/pull/1607)) +- Generate a list of assets to cache for offline support. ([#1573](https://github.com/WordPress/wordpress-playground/pull/1573)) ### Internal -- Build: Ship the default TypeScript .d.ts declaration files, not rollups. ([#1593](https://github.com/WordPress/wordpress-playground/pull/1593)) +- Build: Ship the default TypeScript .d.ts declaration files, not rollups. ([#1593](https://github.com/WordPress/wordpress-playground/pull/1593)) ### Bug Fixes #### Boot Flow -- Fix recursive calls to backfillStaticFilesRemovedFromMinifiedBuild. ([#1614](https://github.com/WordPress/wordpress-playground/pull/1614)) +- Fix recursive calls to backfillStaticFilesRemovedFromMinifiedBuild. ([#1614](https://github.com/WordPress/wordpress-playground/pull/1614)) ### Various -- Add/allow import site gutenberg pr. ([#1610](https://github.com/WordPress/wordpress-playground/pull/1610)) +- Add/allow import site gutenberg pr. ([#1610](https://github.com/WordPress/wordpress-playground/pull/1610)) ### Contributors @@ -2733,31 +2733,31 @@ The following contributors merged PRs in this release: ### **Breaking Changes** -- Set web worker startup options with messages instead of query strings. ([#1574](https://github.com/WordPress/wordpress-playground/pull/1574)) +- Set web worker startup options with messages instead of query strings. ([#1574](https://github.com/WordPress/wordpress-playground/pull/1574)) ### Blueprints -- Add an Import Theme Starter Content step. ([#1521](https://github.com/WordPress/wordpress-playground/pull/1521)) -- Add setSiteLanguage step to change the language. ([#1538](https://github.com/WordPress/wordpress-playground/pull/1538)) -- Mark shorthand properties as stable, not deprecated. ([#1594](https://github.com/WordPress/wordpress-playground/pull/1594)) +- Add an Import Theme Starter Content step. ([#1521](https://github.com/WordPress/wordpress-playground/pull/1521)) +- Add setSiteLanguage step to change the language. ([#1538](https://github.com/WordPress/wordpress-playground/pull/1538)) +- Mark shorthand properties as stable, not deprecated. ([#1594](https://github.com/WordPress/wordpress-playground/pull/1594)) ### Documentation -- Add Blueprint 101 to Documentation. ([#1556](https://github.com/WordPress/wordpress-playground/pull/1556)) +- Add Blueprint 101 to Documentation. ([#1556](https://github.com/WordPress/wordpress-playground/pull/1556)) ### PHP WebAssembly #### Website -- Download all WordPress assets on boot. ([#1532](https://github.com/WordPress/wordpress-playground/pull/1532)) +- Download all WordPress assets on boot. ([#1532](https://github.com/WordPress/wordpress-playground/pull/1532)) ### Website -- PHP CORS Proxy. ([#1546](https://github.com/WordPress/wordpress-playground/pull/1546)) +- PHP CORS Proxy. ([#1546](https://github.com/WordPress/wordpress-playground/pull/1546)) ### Various -- Revert "Set web worker startup options with messages instead of query strings". ([#1605](https://github.com/WordPress/wordpress-playground/pull/1605)) +- Revert "Set web worker startup options with messages instead of query strings". ([#1605](https://github.com/WordPress/wordpress-playground/pull/1605)) ### Contributors @@ -2769,11 +2769,11 @@ The following contributors merged PRs in this release: ### Website -- Remove the unused isSupportedWordPressVersion export. ([#1592](https://github.com/WordPress/wordpress-playground/pull/1592)) +- Remove the unused isSupportedWordPressVersion export. ([#1592](https://github.com/WordPress/wordpress-playground/pull/1592)) ### Internal -- Build: Polyfill \_\_dirname in php-wam/node ESM via banner option. ([#1591](https://github.com/WordPress/wordpress-playground/pull/1591)) +- Build: Polyfill \_\_dirname in php-wam/node ESM via banner option. ([#1591](https://github.com/WordPress/wordpress-playground/pull/1591)) ### Contributors @@ -2785,7 +2785,7 @@ The following contributors merged PRs in this release: ### Internal -- Build: Source external deps from package.json. ([#1590](https://github.com/WordPress/wordpress-playground/pull/1590)) +- Build: Source external deps from package.json. ([#1590](https://github.com/WordPress/wordpress-playground/pull/1590)) ### Contributors @@ -2797,7 +2797,7 @@ The following contributors merged PRs in this release: ### Internal -- Build: Use regular expressions to mark packages as external. ([#1589](https://github.com/WordPress/wordpress-playground/pull/1589)) +- Build: Use regular expressions to mark packages as external. ([#1589](https://github.com/WordPress/wordpress-playground/pull/1589)) ### Contributors @@ -2809,11 +2809,11 @@ The following contributors merged PRs in this release: ### Devrel -- Remove Puzzle app from the Playground website. ([#1588](https://github.com/WordPress/wordpress-playground/pull/1588)) +- Remove Puzzle app from the Playground website. ([#1588](https://github.com/WordPress/wordpress-playground/pull/1588)) ### Internal -- Vite build: Mark all imported modules as external to avoid bundling them with released packages. ([#1586](https://github.com/WordPress/wordpress-playground/pull/1586)) +- Vite build: Mark all imported modules as external to avoid bundling them with released packages. ([#1586](https://github.com/WordPress/wordpress-playground/pull/1586)) ### Contributors @@ -2825,7 +2825,7 @@ The following contributors merged PRs in this release: ### PHP WebAssembly -- php-wasm/node: Ship as ESM and CJS. ([#1585](https://github.com/WordPress/wordpress-playground/pull/1585)) +- php-wasm/node: Ship as ESM and CJS. ([#1585](https://github.com/WordPress/wordpress-playground/pull/1585)) ### Contributors @@ -2839,11 +2839,11 @@ The following contributors merged PRs in this release: ### PHP WebAssembly -- Build: Treat all dependencies of php-wasm/node as external. ([#1584](https://github.com/WordPress/wordpress-playground/pull/1584)) +- Build: Treat all dependencies of php-wasm/node as external. ([#1584](https://github.com/WordPress/wordpress-playground/pull/1584)) ### Various -- Autopublish npm packages every week. ([#1542](https://github.com/WordPress/wordpress-playground/pull/1542)) +- Autopublish npm packages every week. ([#1542](https://github.com/WordPress/wordpress-playground/pull/1542)) ### Contributors @@ -2855,7 +2855,7 @@ The following contributors merged PRs in this release: ### Internal -- Revert "Use NPM for publishing packages instead of Lerna ". ([#1582](https://github.com/WordPress/wordpress-playground/pull/1582)) +- Revert "Use NPM for publishing packages instead of Lerna ". ([#1582](https://github.com/WordPress/wordpress-playground/pull/1582)) ### Contributors @@ -2867,7 +2867,7 @@ The following contributors merged PRs in this release: ### Internal -- Use NPM for publishing packages instead of Lerna. ([#1581](https://github.com/WordPress/wordpress-playground/pull/1581)) +- Use NPM for publishing packages instead of Lerna. ([#1581](https://github.com/WordPress/wordpress-playground/pull/1581)) ### Contributors @@ -2879,7 +2879,7 @@ The following contributors merged PRs in this release: ### Documentation -- Update the Blueprint data format doc. ([#1510](https://github.com/WordPress/wordpress-playground/pull/1510)) +- Update the Blueprint data format doc. ([#1510](https://github.com/WordPress/wordpress-playground/pull/1510)) ### Contributors @@ -2893,20 +2893,20 @@ The following contributors merged PRs in this release: #### Blueprints -- Importing regression fix – support old exported Playground ZIPs. ([#1569](https://github.com/WordPress/wordpress-playground/pull/1569)) +- Importing regression fix – support old exported Playground ZIPs. ([#1569](https://github.com/WordPress/wordpress-playground/pull/1569)) ### Documentation -- Add GitHub development instructions. ([#1551](https://github.com/WordPress/wordpress-playground/pull/1551)) +- Add GitHub development instructions. ([#1551](https://github.com/WordPress/wordpress-playground/pull/1551)) ### Internal -- Meta: GitHub Boards Automation. ([#1549](https://github.com/WordPress/wordpress-playground/pull/1549)) -- Meta: GitHub-sourced Mindmap. ([#1559](https://github.com/WordPress/wordpress-playground/pull/1559)) +- Meta: GitHub Boards Automation. ([#1549](https://github.com/WordPress/wordpress-playground/pull/1549)) +- Meta: GitHub-sourced Mindmap. ([#1559](https://github.com/WordPress/wordpress-playground/pull/1559)) ### -- Add cache version number. ([#1541](https://github.com/WordPress/wordpress-playground/pull/1541)) +- Add cache version number. ([#1541](https://github.com/WordPress/wordpress-playground/pull/1541)) ### Contributors @@ -2918,19 +2918,19 @@ The following contributors merged PRs in this release: ### PHP WebAssembly -- Networking access: Fix wp_http_supports() to work without the kitchen-sink extension bundle. ([#1504](https://github.com/WordPress/wordpress-playground/pull/1504)) -- Networking: Remove CORS workarounds for WordPress.org API. ([#1511](https://github.com/WordPress/wordpress-playground/pull/1511)) -- Backfill remote asset listing when needed. ([#1531](https://github.com/WordPress/wordpress-playground/pull/1531)) +- Networking access: Fix wp_http_supports() to work without the kitchen-sink extension bundle. ([#1504](https://github.com/WordPress/wordpress-playground/pull/1504)) +- Networking: Remove CORS workarounds for WordPress.org API. ([#1511](https://github.com/WordPress/wordpress-playground/pull/1511)) +- Backfill remote asset listing when needed. ([#1531](https://github.com/WordPress/wordpress-playground/pull/1531)) ### Website -- Remove "small window mode". ([#1540](https://github.com/WordPress/wordpress-playground/pull/1540)) -- Detect actual, loaded WP version. ([#1503](https://github.com/WordPress/wordpress-playground/pull/1503)) +- Remove "small window mode". ([#1540](https://github.com/WordPress/wordpress-playground/pull/1540)) +- Detect actual, loaded WP version. ([#1503](https://github.com/WordPress/wordpress-playground/pull/1503)) ### Various -- Remove deprecation note from shorthand steps. ([#1507](https://github.com/WordPress/wordpress-playground/pull/1507)) -- Remove trailing semicolon from example URL for loading playground with network access. ([#1520](https://github.com/WordPress/wordpress-playground/pull/1520)) +- Remove deprecation note from shorthand steps. ([#1507](https://github.com/WordPress/wordpress-playground/pull/1507)) +- Remove trailing semicolon from example URL for loading playground with network access. ([#1520](https://github.com/WordPress/wordpress-playground/pull/1520)) ### Contributors @@ -2942,113 +2942,113 @@ The following contributors merged PRs in this release: ### **Breaking Changes** -- [Breaking] Refactor PHP.ini management, remove php.setPhpIniPath() and php.setPhpIniEntry(). ([#1423](https://github.com/WordPress/wordpress-playground/pull/1423)) +- [Breaking] Refactor PHP.ini management, remove php.setPhpIniPath() and php.setPhpIniEntry(). ([#1423](https://github.com/WordPress/wordpress-playground/pull/1423)) ### Enhancements -- CLI: Distinguish between mount and mountBeforeInstall options. ([#1410](https://github.com/WordPress/wordpress-playground/pull/1410)) -- CLI: Support fetching WordPress zips from custom URLs. ([#1415](https://github.com/WordPress/wordpress-playground/pull/1415)) -- Introduce a new @wp-playground/common package to avoid circular depencies. ([#1387](https://github.com/WordPress/wordpress-playground/pull/1387)) -- Website: Ship the SQLite database integration plugin. ([#1418](https://github.com/WordPress/wordpress-playground/pull/1418)) +- CLI: Distinguish between mount and mountBeforeInstall options. ([#1410](https://github.com/WordPress/wordpress-playground/pull/1410)) +- CLI: Support fetching WordPress zips from custom URLs. ([#1415](https://github.com/WordPress/wordpress-playground/pull/1415)) +- Introduce a new @wp-playground/common package to avoid circular depencies. ([#1387](https://github.com/WordPress/wordpress-playground/pull/1387)) +- Website: Ship the SQLite database integration plugin. ([#1418](https://github.com/WordPress/wordpress-playground/pull/1418)) #### Boot Flow -- Playground CLI: Don't create /wordpress/wp-config.php on boot. ([#1407](https://github.com/WordPress/wordpress-playground/pull/1407)) +- Playground CLI: Don't create /wordpress/wp-config.php on boot. ([#1407](https://github.com/WordPress/wordpress-playground/pull/1407)) ### Blueprints -- Define constants in auto_prepend_file, silence warnings related to redefining those constants. ([#1400](https://github.com/WordPress/wordpress-playground/pull/1400)) -- Detect silent failures when activating plugins and theme. ([#1436](https://github.com/WordPress/wordpress-playground/pull/1436)) -- Re-activate single-file plugins when enabling a multisite. ([#1435](https://github.com/WordPress/wordpress-playground/pull/1435)) -- Throw an error when activating a theme or plugin that doesn't exist. ([#1391](https://github.com/WordPress/wordpress-playground/pull/1391)) -- Write sunrise.php to /internal in enableMultisite step. ([#1401](https://github.com/WordPress/wordpress-playground/pull/1401)) +- Define constants in auto_prepend_file, silence warnings related to redefining those constants. ([#1400](https://github.com/WordPress/wordpress-playground/pull/1400)) +- Detect silent failures when activating plugins and theme. ([#1436](https://github.com/WordPress/wordpress-playground/pull/1436)) +- Re-activate single-file plugins when enabling a multisite. ([#1435](https://github.com/WordPress/wordpress-playground/pull/1435)) +- Throw an error when activating a theme or plugin that doesn't exist. ([#1391](https://github.com/WordPress/wordpress-playground/pull/1391)) +- Write sunrise.php to /internal in enableMultisite step. ([#1401](https://github.com/WordPress/wordpress-playground/pull/1401)) ### Tools -- Add VSCode branch protection. ([#1408](https://github.com/WordPress/wordpress-playground/pull/1408)) -- Show error log if Playground fails to start. ([#1336](https://github.com/WordPress/wordpress-playground/pull/1336)) +- Add VSCode branch protection. ([#1408](https://github.com/WordPress/wordpress-playground/pull/1408)) +- Show error log if Playground fails to start. ([#1336](https://github.com/WordPress/wordpress-playground/pull/1336)) #### Blueprints -- Unzip: Only delete a temporary zip file after unzipping, do not delete the original zip. ([#1412](https://github.com/WordPress/wordpress-playground/pull/1412)) +- Unzip: Only delete a temporary zip file after unzipping, do not delete the original zip. ([#1412](https://github.com/WordPress/wordpress-playground/pull/1412)) #### GitHub integration -- GitHub export: Create new commits in your fork when writing to the upstream repo isn't allowed. ([#1392](https://github.com/WordPress/wordpress-playground/pull/1392)) +- GitHub export: Create new commits in your fork when writing to the upstream repo isn't allowed. ([#1392](https://github.com/WordPress/wordpress-playground/pull/1392)) #### Import/Export -- Support wp_crop_image in import wxr. ([#1357](https://github.com/WordPress/wordpress-playground/pull/1357)) +- Support wp_crop_image in import wxr. ([#1357](https://github.com/WordPress/wordpress-playground/pull/1357)) ### Devrel -- Add puzzle API. ([#1372](https://github.com/WordPress/wordpress-playground/pull/1372)) +- Add puzzle API. ([#1372](https://github.com/WordPress/wordpress-playground/pull/1372)) ### Documentation -- Docs: Use step function names instead of TypeScript type names. ([#1373](https://github.com/WordPress/wordpress-playground/pull/1373)) -- Updated the GitHub issue link to open in a new tab. ([#1353](https://github.com/WordPress/wordpress-playground/pull/1353)) -- Use step id name. ([#1377](https://github.com/WordPress/wordpress-playground/pull/1377)) +- Docs: Use step function names instead of TypeScript type names. ([#1373](https://github.com/WordPress/wordpress-playground/pull/1373)) +- Updated the GitHub issue link to open in a new tab. ([#1353](https://github.com/WordPress/wordpress-playground/pull/1353)) +- Use step id name. ([#1377](https://github.com/WordPress/wordpress-playground/pull/1377)) ### Experiments -- Explore: Setup SQLite database integration without creating wp-content/db.php. ([#1382](https://github.com/WordPress/wordpress-playground/pull/1382)) +- Explore: Setup SQLite database integration without creating wp-content/db.php. ([#1382](https://github.com/WordPress/wordpress-playground/pull/1382)) ### PHP WebAssembly -- Add shareable extension-to-MIME-type mapping. ([#1355](https://github.com/WordPress/wordpress-playground/pull/1355)) -- Document php ini functions. ([#1430](https://github.com/WordPress/wordpress-playground/pull/1430)) -- JSPI: Enable the origin trial on Chrome. ([#1346](https://github.com/WordPress/wordpress-playground/pull/1346)) -- PHP: Add libjpeg and libwebp support. ([#1393](https://github.com/WordPress/wordpress-playground/pull/1393)) -- PHP: Always set the auto_prepend_file php.ini entry, even when the auto_prepend_file.php file exists. ([#1388](https://github.com/WordPress/wordpress-playground/pull/1388)) -- PHP: Move internal shared directories to /internal/shared. ([#1386](https://github.com/WordPress/wordpress-playground/pull/1386)) -- PHP: Remove mentions of a custom PHP extension. ([#1422](https://github.com/WordPress/wordpress-playground/pull/1422)) -- PHP: Remove the MODE_EVAL_CODE execution mode. ([#1433](https://github.com/WordPress/wordpress-playground/pull/1433)) -- PHP: Support php.mv() between devices via recursive copy. ([#1411](https://github.com/WordPress/wordpress-playground/pull/1411)) -- PHP: Use /internal/shared/php.ini by default. ([#1419](https://github.com/WordPress/wordpress-playground/pull/1419)) -- PHP: Use auto_prepend_file to preload mu-plugins (instead of creating them in wp-content/mu-plugins). ([#1366](https://github.com/WordPress/wordpress-playground/pull/1366)) - -### Website - -- Improve log modal styles, a11y, error message wording. ([#1369](https://github.com/WordPress/wordpress-playground/pull/1369)) -- Move puzzle app to a Playground package. ([#1385](https://github.com/WordPress/wordpress-playground/pull/1385)) -- Add secrets on-demand for more endpoints. ([#1362](https://github.com/WordPress/wordpress-playground/pull/1362)) -- Boot: Move WordPress zip extraction logic to a common unzipWordPress() utility. ([#1427](https://github.com/WordPress/wordpress-playground/pull/1427)) -- Derive MIME types for PHP served files from shared JSON. ([#1360](https://github.com/WordPress/wordpress-playground/pull/1360)) -- Fix constant names for GH export oauth. ([#1378](https://github.com/WordPress/wordpress-playground/pull/1378)) -- Playground Boot: Align the boot process between remote.html and CLI. ([#1389](https://github.com/WordPress/wordpress-playground/pull/1389)) -- Remote.html: Install WordPress if it isn't installed yet. ([#1425](https://github.com/WordPress/wordpress-playground/pull/1425)) -- Remote.html: Preload the SQLite database plugin, but only execute it if there's no custom db.php inside wp-content. ([#1424](https://github.com/WordPress/wordpress-playground/pull/1424)) -- Simplify website deployment workflows. ([#1404](https://github.com/WordPress/wordpress-playground/pull/1404)) -- Update rsync command to clean up more completely. ([#1361](https://github.com/WordPress/wordpress-playground/pull/1361)) +- Add shareable extension-to-MIME-type mapping. ([#1355](https://github.com/WordPress/wordpress-playground/pull/1355)) +- Document php ini functions. ([#1430](https://github.com/WordPress/wordpress-playground/pull/1430)) +- JSPI: Enable the origin trial on Chrome. ([#1346](https://github.com/WordPress/wordpress-playground/pull/1346)) +- PHP: Add libjpeg and libwebp support. ([#1393](https://github.com/WordPress/wordpress-playground/pull/1393)) +- PHP: Always set the auto_prepend_file php.ini entry, even when the auto_prepend_file.php file exists. ([#1388](https://github.com/WordPress/wordpress-playground/pull/1388)) +- PHP: Move internal shared directories to /internal/shared. ([#1386](https://github.com/WordPress/wordpress-playground/pull/1386)) +- PHP: Remove mentions of a custom PHP extension. ([#1422](https://github.com/WordPress/wordpress-playground/pull/1422)) +- PHP: Remove the MODE_EVAL_CODE execution mode. ([#1433](https://github.com/WordPress/wordpress-playground/pull/1433)) +- PHP: Support php.mv() between devices via recursive copy. ([#1411](https://github.com/WordPress/wordpress-playground/pull/1411)) +- PHP: Use /internal/shared/php.ini by default. ([#1419](https://github.com/WordPress/wordpress-playground/pull/1419)) +- PHP: Use auto_prepend_file to preload mu-plugins (instead of creating them in wp-content/mu-plugins). ([#1366](https://github.com/WordPress/wordpress-playground/pull/1366)) + +### Website + +- Improve log modal styles, a11y, error message wording. ([#1369](https://github.com/WordPress/wordpress-playground/pull/1369)) +- Move puzzle app to a Playground package. ([#1385](https://github.com/WordPress/wordpress-playground/pull/1385)) +- Add secrets on-demand for more endpoints. ([#1362](https://github.com/WordPress/wordpress-playground/pull/1362)) +- Boot: Move WordPress zip extraction logic to a common unzipWordPress() utility. ([#1427](https://github.com/WordPress/wordpress-playground/pull/1427)) +- Derive MIME types for PHP served files from shared JSON. ([#1360](https://github.com/WordPress/wordpress-playground/pull/1360)) +- Fix constant names for GH export oauth. ([#1378](https://github.com/WordPress/wordpress-playground/pull/1378)) +- Playground Boot: Align the boot process between remote.html and CLI. ([#1389](https://github.com/WordPress/wordpress-playground/pull/1389)) +- Remote.html: Install WordPress if it isn't installed yet. ([#1425](https://github.com/WordPress/wordpress-playground/pull/1425)) +- Remote.html: Preload the SQLite database plugin, but only execute it if there's no custom db.php inside wp-content. ([#1424](https://github.com/WordPress/wordpress-playground/pull/1424)) +- Simplify website deployment workflows. ([#1404](https://github.com/WordPress/wordpress-playground/pull/1404)) +- Update rsync command to clean up more completely. ([#1361](https://github.com/WordPress/wordpress-playground/pull/1361)) #### Blueprints -- Provide non-gzipped wp-cli.phar file with website build. ([#1406](https://github.com/WordPress/wordpress-playground/pull/1406)) -- Simplify runPhpWithZipFunctions() setup. ([#1434](https://github.com/WordPress/wordpress-playground/pull/1434)) +- Provide non-gzipped wp-cli.phar file with website build. ([#1406](https://github.com/WordPress/wordpress-playground/pull/1406)) +- Simplify runPhpWithZipFunctions() setup. ([#1434](https://github.com/WordPress/wordpress-playground/pull/1434)) ### Internal -- Fix changelog automation. ([#1413](https://github.com/WordPress/wordpress-playground/pull/1413)) +- Fix changelog automation. ([#1413](https://github.com/WordPress/wordpress-playground/pull/1413)) ### Bug Fixes -- Add name to Puzzle package. ([#1443](https://github.com/WordPress/wordpress-playground/pull/1443)) -- Fixed images not loading on the page. ([#1352](https://github.com/WordPress/wordpress-playground/pull/1352)) -- Restore nightly wordpress build. ([#1437](https://github.com/WordPress/wordpress-playground/pull/1437)) +- Add name to Puzzle package. ([#1443](https://github.com/WordPress/wordpress-playground/pull/1443)) +- Fixed images not loading on the page. ([#1352](https://github.com/WordPress/wordpress-playground/pull/1352)) +- Restore nightly wordpress build. ([#1437](https://github.com/WordPress/wordpress-playground/pull/1437)) ### Reliability -- Disable console logging when running tests. ([#1368](https://github.com/WordPress/wordpress-playground/pull/1368)) +- Disable console logging when running tests. ([#1368](https://github.com/WordPress/wordpress-playground/pull/1368)) ### -- Lint: Disable console warnings for paths where they're not useful. ([#1421](https://github.com/WordPress/wordpress-playground/pull/1421)) +- Lint: Disable console warnings for paths where they're not useful. ([#1421](https://github.com/WordPress/wordpress-playground/pull/1421)) ### Various -- Add links to kitchen sink (PHP extensions), networking. ([#1363](https://github.com/WordPress/wordpress-playground/pull/1363)) -- Reorganize and update documentation. ([#1354](https://github.com/WordPress/wordpress-playground/pull/1354)) +- Add links to kitchen sink (PHP extensions), networking. ([#1363](https://github.com/WordPress/wordpress-playground/pull/1363)) +- Reorganize and update documentation. ([#1354](https://github.com/WordPress/wordpress-playground/pull/1354)) ### Contributors @@ -3060,8 +3060,8 @@ The following contributors merged PRs in this release: ### Website -- Avoid edge-caching conditionally redirected resources. ([#1351](https://github.com/WordPress/wordpress-playground/pull/1351)) -- Fix deploy-time check for file with PHP-handled redirect. ([#1350](https://github.com/WordPress/wordpress-playground/pull/1350)) +- Avoid edge-caching conditionally redirected resources. ([#1351](https://github.com/WordPress/wordpress-playground/pull/1351)) +- Fix deploy-time check for file with PHP-handled redirect. ([#1350](https://github.com/WordPress/wordpress-playground/pull/1350)) ### Contributors @@ -3073,7 +3073,7 @@ The following contributors merged PRs in this release: ### PHP WebAssembly -- PHP.wasm Node: Revert a part of #1289, do not import a .wasm file. ([#1348](https://github.com/WordPress/wordpress-playground/pull/1348)) +- PHP.wasm Node: Revert a part of #1289, do not import a .wasm file. ([#1348](https://github.com/WordPress/wordpress-playground/pull/1348)) ### Contributors @@ -3085,7 +3085,7 @@ The following contributors merged PRs in this release: ### Internal -- Meta: Move the minified WordPress to the new `@wp-playground/wordpress-builds` package. ([#1343](https://github.com/WordPress/wordpress-playground/pull/1343)) +- Meta: Move the minified WordPress to the new `@wp-playground/wordpress-builds` package. ([#1343](https://github.com/WordPress/wordpress-playground/pull/1343)) ### Contributors @@ -3097,7 +3097,7 @@ The following contributors merged PRs in this release: ### PHP WebAssembly -- Playground CLI. ([#1289](https://github.com/WordPress/wordpress-playground/pull/1289)) +- Playground CLI. ([#1289](https://github.com/WordPress/wordpress-playground/pull/1289)) ### Contributors @@ -3109,46 +3109,46 @@ The following contributors merged PRs in this release: ### **Breaking Changes** -- PHP: Remove setSapiName, setPhpIniEntry, setPhpIniPath methods from the remote PHP API client. ([#1321](https://github.com/WordPress/wordpress-playground/pull/1321)) -- Remove the wp-playground/node package. ([#1323](https://github.com/WordPress/wordpress-playground/pull/1323)) +- PHP: Remove setSapiName, setPhpIniEntry, setPhpIniPath methods from the remote PHP API client. ([#1321](https://github.com/WordPress/wordpress-playground/pull/1321)) +- Remove the wp-playground/node package. ([#1323](https://github.com/WordPress/wordpress-playground/pull/1323)) #### PHP WebAssembly -- Breaking: Loopback Request Support. ([#1287](https://github.com/WordPress/wordpress-playground/pull/1287)) +- Breaking: Loopback Request Support. ([#1287](https://github.com/WordPress/wordpress-playground/pull/1287)) ### Tools -- Centralize log storage. ([#1315](https://github.com/WordPress/wordpress-playground/pull/1315)) +- Centralize log storage. ([#1315](https://github.com/WordPress/wordpress-playground/pull/1315)) ### Documentation -- Link to Installing Nx Globally in the README. ([#1325](https://github.com/WordPress/wordpress-playground/pull/1325)) +- Link to Installing Nx Globally in the README. ([#1325](https://github.com/WordPress/wordpress-playground/pull/1325)) ### PHP WebAssembly -- Add PHPResponse.forHttpCode() shorthand. ([#1322](https://github.com/WordPress/wordpress-playground/pull/1322)) -- Asyncify: List ZEND_FETCH_OBJ_R_SPEC_CV_CV_HANDLER. ([#1342](https://github.com/WordPress/wordpress-playground/pull/1342)) -- Curl extension for the Node.js build of PHP.wasm. ([#1273](https://github.com/WordPress/wordpress-playground/pull/1273)) -- Explore curl support. ([#1133](https://github.com/WordPress/wordpress-playground/pull/1133)) -- PHP Process Manager. ([#1301](https://github.com/WordPress/wordpress-playground/pull/1301)) -- PHPProcessManager: Clear nextInstance when the concurrency limit is exhausted. ([#1324](https://github.com/WordPress/wordpress-playground/pull/1324)) -- Spawn handler: Wrap the program call with try/catch, exit gracefully on error. ([#1320](https://github.com/WordPress/wordpress-playground/pull/1320)) +- Add PHPResponse.forHttpCode() shorthand. ([#1322](https://github.com/WordPress/wordpress-playground/pull/1322)) +- Asyncify: List ZEND_FETCH_OBJ_R_SPEC_CV_CV_HANDLER. ([#1342](https://github.com/WordPress/wordpress-playground/pull/1342)) +- Curl extension for the Node.js build of PHP.wasm. ([#1273](https://github.com/WordPress/wordpress-playground/pull/1273)) +- Explore curl support. ([#1133](https://github.com/WordPress/wordpress-playground/pull/1133)) +- PHP Process Manager. ([#1301](https://github.com/WordPress/wordpress-playground/pull/1301)) +- PHPProcessManager: Clear nextInstance when the concurrency limit is exhausted. ([#1324](https://github.com/WordPress/wordpress-playground/pull/1324)) +- Spawn handler: Wrap the program call with try/catch, exit gracefully on error. ([#1320](https://github.com/WordPress/wordpress-playground/pull/1320)) ### Website -- Add initial workflow for deploying the website to WP Cloud. ([#1293](https://github.com/WordPress/wordpress-playground/pull/1293)) -- Eliminate 404s due to nested files-to-serve-via-php dir. ([#1333](https://github.com/WordPress/wordpress-playground/pull/1333)) -- Stop WP rewrite rules from matching files like wp-admin.css. ([#1317](https://github.com/WordPress/wordpress-playground/pull/1317)) -- Stop using PHP to serve most static files on WP Cloud. ([#1331](https://github.com/WordPress/wordpress-playground/pull/1331)) -- WP Cloud: Relay secrets for error logger. ([#1337](https://github.com/WordPress/wordpress-playground/pull/1337)) +- Add initial workflow for deploying the website to WP Cloud. ([#1293](https://github.com/WordPress/wordpress-playground/pull/1293)) +- Eliminate 404s due to nested files-to-serve-via-php dir. ([#1333](https://github.com/WordPress/wordpress-playground/pull/1333)) +- Stop WP rewrite rules from matching files like wp-admin.css. ([#1317](https://github.com/WordPress/wordpress-playground/pull/1317)) +- Stop using PHP to serve most static files on WP Cloud. ([#1331](https://github.com/WordPress/wordpress-playground/pull/1331)) +- WP Cloud: Relay secrets for error logger. ([#1337](https://github.com/WordPress/wordpress-playground/pull/1337)) #### Documentation -- Document WP Cloud website setup. ([#1338](https://github.com/WordPress/wordpress-playground/pull/1338)) +- Document WP Cloud website setup. ([#1338](https://github.com/WordPress/wordpress-playground/pull/1338)) ### Reliability -- Add log methods, log handlers, and separate log collection. ([#1264](https://github.com/WordPress/wordpress-playground/pull/1264)) +- Add log methods, log handlers, and separate log collection. ([#1264](https://github.com/WordPress/wordpress-playground/pull/1264)) ### Contributors @@ -3164,68 +3164,68 @@ The following contributors merged PRs in this release: #### PHP WebAssembly -- Breaking: Remove PHPBrowser. ([#1302](https://github.com/WordPress/wordpress-playground/pull/1302)) +- Breaking: Remove PHPBrowser. ([#1302](https://github.com/WordPress/wordpress-playground/pull/1302)) ### Enhancements -- Bump TypeScript to 5.4.5. ([#1299](https://github.com/WordPress/wordpress-playground/pull/1299)) -- Semaphore: Add timeout option. ([#1300](https://github.com/WordPress/wordpress-playground/pull/1300)) +- Bump TypeScript to 5.4.5. ([#1299](https://github.com/WordPress/wordpress-playground/pull/1299)) +- Semaphore: Add timeout option. ([#1300](https://github.com/WordPress/wordpress-playground/pull/1300)) ### Blueprints -- Builder: Fix stuck loader bar. ([#1284](https://github.com/WordPress/wordpress-playground/pull/1284)) -- Remove setPhpIniEntry step. ([#1288](https://github.com/WordPress/wordpress-playground/pull/1288)) +- Builder: Fix stuck loader bar. ([#1284](https://github.com/WordPress/wordpress-playground/pull/1284)) +- Remove setPhpIniEntry step. ([#1288](https://github.com/WordPress/wordpress-playground/pull/1288)) ### Tools #### GitHub integration -- GitHub: Don't delete all the files when exporting a theme. ([#1308](https://github.com/WordPress/wordpress-playground/pull/1308)) -- Urlencode branch name. ([#1275](https://github.com/WordPress/wordpress-playground/pull/1275)) +- GitHub: Don't delete all the files when exporting a theme. ([#1308](https://github.com/WordPress/wordpress-playground/pull/1308)) +- Urlencode branch name. ([#1275](https://github.com/WordPress/wordpress-playground/pull/1275)) #### Blueprints -- Blueprints builder: Support ?blueprint-url. ([#1309](https://github.com/WordPress/wordpress-playground/pull/1309)) +- Blueprints builder: Support ?blueprint-url. ([#1309](https://github.com/WordPress/wordpress-playground/pull/1309)) ### Documentation -- Use new learning resources in Playground documentation. ([#1276](https://github.com/WordPress/wordpress-playground/pull/1276)) +- Use new learning resources in Playground documentation. ([#1276](https://github.com/WordPress/wordpress-playground/pull/1276)) ### PHP WebAssembly -- Browser: Remove setSpawnHandler function from the public API. ([#1303](https://github.com/WordPress/wordpress-playground/pull/1303)) -- PHP: Add a cwd argument to hotSwapPHPRuntime(). ([#1304](https://github.com/WordPress/wordpress-playground/pull/1304)) -- PHP: Remove addServerGlobalEntry() method, accept $\_SERVER as php.run() property. ([#1286](https://github.com/WordPress/wordpress-playground/pull/1286)) -- PHPRequestHandler: Add a generic PHP argument. ([#1310](https://github.com/WordPress/wordpress-playground/pull/1310)) -- nit: Clean up after node PHP popen() test. ([#1280](https://github.com/WordPress/wordpress-playground/pull/1280)) +- Browser: Remove setSpawnHandler function from the public API. ([#1303](https://github.com/WordPress/wordpress-playground/pull/1303)) +- PHP: Add a cwd argument to hotSwapPHPRuntime(). ([#1304](https://github.com/WordPress/wordpress-playground/pull/1304)) +- PHP: Remove addServerGlobalEntry() method, accept $\_SERVER as php.run() property. ([#1286](https://github.com/WordPress/wordpress-playground/pull/1286)) +- PHPRequestHandler: Add a generic PHP argument. ([#1310](https://github.com/WordPress/wordpress-playground/pull/1310)) +- nit: Clean up after node PHP popen() test. ([#1280](https://github.com/WordPress/wordpress-playground/pull/1280)) ### Website -- Add more info to crash reports. ([#1253](https://github.com/WordPress/wordpress-playground/pull/1253)) -- Memoize fetch() responses when requesting php.wasm. ([#1306](https://github.com/WordPress/wordpress-playground/pull/1306)) -- Progress monitoring: Use a custom instantiateWasm handler to avoid monkey-patching WebAssembly.instantiateStreaming. ([#1305](https://github.com/WordPress/wordpress-playground/pull/1305)) -- Remove sandbox attribute from iframe. ([#1313](https://github.com/WordPress/wordpress-playground/pull/1313)) -- Service Worker: Fetch credentialless to play more nicely with server caches (#1311). ([#1311](https://github.com/WordPress/wordpress-playground/pull/1311)) +- Add more info to crash reports. ([#1253](https://github.com/WordPress/wordpress-playground/pull/1253)) +- Memoize fetch() responses when requesting php.wasm. ([#1306](https://github.com/WordPress/wordpress-playground/pull/1306)) +- Progress monitoring: Use a custom instantiateWasm handler to avoid monkey-patching WebAssembly.instantiateStreaming. ([#1305](https://github.com/WordPress/wordpress-playground/pull/1305)) +- Remove sandbox attribute from iframe. ([#1313](https://github.com/WordPress/wordpress-playground/pull/1313)) +- Service Worker: Fetch credentialless to play more nicely with server caches (#1311). ([#1311](https://github.com/WordPress/wordpress-playground/pull/1311)) ### Internal -- Automate Changelog generation after each npm release. ([#1312](https://github.com/WordPress/wordpress-playground/pull/1312)) -- CI: Fix intermittent documentation build failures. ([#1307](https://github.com/WordPress/wordpress-playground/pull/1307)) +- Automate Changelog generation after each npm release. ([#1312](https://github.com/WordPress/wordpress-playground/pull/1312)) +- CI: Fix intermittent documentation build failures. ([#1307](https://github.com/WordPress/wordpress-playground/pull/1307)) ### Bug Fixes -- Add styles to ensure `iframes` are responsive. ([#1267](https://github.com/WordPress/wordpress-playground/pull/1267)) -- Docs: Fix the Blueprint example of the Gutenberg PR preview. ([#1268](https://github.com/WordPress/wordpress-playground/pull/1268)) -- Docs: Move Steps Shorthands to a separate page to fix Steps TOC. ([#1265](https://github.com/WordPress/wordpress-playground/pull/1265)) +- Add styles to ensure `iframes` are responsive. ([#1267](https://github.com/WordPress/wordpress-playground/pull/1267)) +- Docs: Fix the Blueprint example of the Gutenberg PR preview. ([#1268](https://github.com/WordPress/wordpress-playground/pull/1268)) +- Docs: Move Steps Shorthands to a separate page to fix Steps TOC. ([#1265](https://github.com/WordPress/wordpress-playground/pull/1265)) ### Reliability -- Add network error message. ([#1281](https://github.com/WordPress/wordpress-playground/pull/1281)) -- Explore logging to a file. ([#1292](https://github.com/WordPress/wordpress-playground/pull/1292)) +- Add network error message. ([#1281](https://github.com/WordPress/wordpress-playground/pull/1281)) +- Explore logging to a file. ([#1292](https://github.com/WordPress/wordpress-playground/pull/1292)) ### Various -- Add PDF to infer mime type list. ([#1298](https://github.com/WordPress/wordpress-playground/pull/1298)) +- Add PDF to infer mime type list. ([#1298](https://github.com/WordPress/wordpress-playground/pull/1298)) ### Contributors @@ -3237,26 +3237,26 @@ The following contributors merged PRs in this release: ### Blueprints -- Replace set_current_user call with wp_set_current_user to fix a PHP notice. ([#1262](https://github.com/WordPress/playground/pull/1262)) +- Replace set_current_user call with wp_set_current_user to fix a PHP notice. ([#1262](https://github.com/WordPress/playground/pull/1262)) ### Tools -- Install themes and plugins using the ReadableStream API. ([#919](https://github.com/WordPress/playground/pull/919)) +- Install themes and plugins using the ReadableStream API. ([#919](https://github.com/WordPress/playground/pull/919)) ### Documentation -- Docs: Update WordPress versions used in the documentation, document using older releases. ([#1235](https://github.com/WordPress/playground/pull/1235)) +- Docs: Update WordPress versions used in the documentation, document using older releases. ([#1235](https://github.com/WordPress/playground/pull/1235)) ### PHP WebAssembly -- Filter Requests library to use the Fetch handler. ([#1048](https://github.com/WordPress/playground/pull/1048)) +- Filter Requests library to use the Fetch handler. ([#1048](https://github.com/WordPress/playground/pull/1048)) -- PHP: Handle request errors in PHPRequestHandler, return response code 500. ([#1249](https://github.com/WordPress/playground/pull/1249)) -- PHP: Reset exit code before dispatching a request. ([#1251](https://github.com/WordPress/playground/pull/1251)) +- PHP: Handle request errors in PHPRequestHandler, return response code 500. ([#1249](https://github.com/WordPress/playground/pull/1249)) +- PHP: Reset exit code before dispatching a request. ([#1251](https://github.com/WordPress/playground/pull/1251)) ### Various -- Add documentation for `shorthand` alternatives of Blueprint steps. ([#1261](https://github.com/WordPress/playground/pull/1261)) +- Add documentation for `shorthand` alternatives of Blueprint steps. ([#1261](https://github.com/WordPress/playground/pull/1261)) ### Contributors @@ -3268,33 +3268,33 @@ The following contributors merged PRs in this release: ### Blueprints -- Add ifAlreadyInstalled to installPlugin and installTheme steps. ([#1244](https://github.com/WordPress/playground/pull/1244)) -- Support a landingPage value without the initial slash. ([#1227](https://github.com/WordPress/playground/pull/1227)) +- Add ifAlreadyInstalled to installPlugin and installTheme steps. ([#1244](https://github.com/WordPress/playground/pull/1244)) +- Support a landingPage value without the initial slash. ([#1227](https://github.com/WordPress/playground/pull/1227)) ### PHP WebAssembly -- Investigate OOB: Run unit tests with instrumented PHP 8.0 code. ([#1220](https://github.com/WordPress/playground/pull/1220)) -- Unit tests: Restore site-data.spec.ts. ([#1194](https://github.com/WordPress/playground/pull/1194)) -- Web PHP: Increase memory limit to 256 M. ([#1232](https://github.com/WordPress/playground/pull/1232)) +- Investigate OOB: Run unit tests with instrumented PHP 8.0 code. ([#1220](https://github.com/WordPress/playground/pull/1220)) +- Unit tests: Restore site-data.spec.ts. ([#1194](https://github.com/WordPress/playground/pull/1194)) +- Web PHP: Increase memory limit to 256 M. ([#1232](https://github.com/WordPress/playground/pull/1232)) ### Website -- Browser: Display PHP output when Fatal Error is trigerred. ([#1234](https://github.com/WordPress/playground/pull/1234)) -- Fix accessibility issues found by Axe. ([#1246](https://github.com/WordPress/playground/pull/1246)) -- Request Handler: Urldecode the requested path. ([#1228](https://github.com/WordPress/playground/pull/1228)) +- Browser: Display PHP output when Fatal Error is trigerred. ([#1234](https://github.com/WordPress/playground/pull/1234)) +- Fix accessibility issues found by Axe. ([#1246](https://github.com/WordPress/playground/pull/1246)) +- Request Handler: Urldecode the requested path. ([#1228](https://github.com/WordPress/playground/pull/1228)) ### Bug Fixes -- fix: Set required engine version to 18.18.0. ([#1214](https://github.com/WordPress/playground/pull/1214)) +- fix: Set required engine version to 18.18.0. ([#1214](https://github.com/WordPress/playground/pull/1214)) ### Various -- Blueprints/json example. ([#1188](https://github.com/WordPress/playground/pull/1188)) -- Doc: Update 01-index.md. ([#1216](https://github.com/WordPress/playground/pull/1216)) -- Move DefineSiteUrlStep doc warning so it displays in documentation. ([#1245](https://github.com/WordPress/playground/pull/1245)) -- Updated link to native WordPress importer. ([#1243](https://github.com/WordPress/playground/pull/1243)) -- documentation update proposal: Provide more info on features, extensions?. ([#1208](https://github.com/WordPress/playground/pull/1208)) -- php-wasm/node: Update express to newest version, and move it to devDependencies. ([#1218](https://github.com/WordPress/playground/pull/1218)) +- Blueprints/json example. ([#1188](https://github.com/WordPress/playground/pull/1188)) +- Doc: Update 01-index.md. ([#1216](https://github.com/WordPress/playground/pull/1216)) +- Move DefineSiteUrlStep doc warning so it displays in documentation. ([#1245](https://github.com/WordPress/playground/pull/1245)) +- Updated link to native WordPress importer. ([#1243](https://github.com/WordPress/playground/pull/1243)) +- documentation update proposal: Provide more info on features, extensions?. ([#1208](https://github.com/WordPress/playground/pull/1208)) +- php-wasm/node: Update express to newest version, and move it to devDependencies. ([#1218](https://github.com/WordPress/playground/pull/1218)) ### Contributors @@ -3306,15 +3306,15 @@ The following contributors merged PRs in this release: ### Bug Fixes -- Revert changes to the documentation build. ([#1226](https://github.com/WordPress/playground/pull/1226)) +- Revert changes to the documentation build. ([#1226](https://github.com/WordPress/playground/pull/1226)) ### Reliability -- Update error modal description label. ([#1224](https://github.com/WordPress/playground/pull/1224)) +- Update error modal description label. ([#1224](https://github.com/WordPress/playground/pull/1224)) ### Various -- Try memory leak workaround with zeroed mem. ([#1229](https://github.com/WordPress/playground/pull/1229)) +- Try memory leak workaround with zeroed mem. ([#1229](https://github.com/WordPress/playground/pull/1229)) ### Contributors @@ -3326,11 +3326,11 @@ The following contributors merged PRs in this release: ### PHP WebAssembly -- Try to repro memory out of bounds errors in CI. ([#1199](https://github.com/WordPress/playground/pull/1199)) +- Try to repro memory out of bounds errors in CI. ([#1199](https://github.com/WordPress/playground/pull/1199)) ### Bug Fixes -- Fix docs-site build. ([#1222](https://github.com/WordPress/playground/pull/1222)) +- Fix docs-site build. ([#1222](https://github.com/WordPress/playground/pull/1222)) ### Contributors @@ -3342,23 +3342,23 @@ The following contributors merged PRs in this release: ### Tools -- Avoid Service Worker update issues on localhost. ([#1209](https://github.com/WordPress/playground/pull/1209)) +- Avoid Service Worker update issues on localhost. ([#1209](https://github.com/WordPress/playground/pull/1209)) #### Import/Export -- importWxr: Preserve backslashes in the imported content. ([#1213](https://github.com/WordPress/playground/pull/1213)) +- importWxr: Preserve backslashes in the imported content. ([#1213](https://github.com/WordPress/playground/pull/1213)) ### PHP WebAssembly -- Catch DNS errors to avoid unhandled exceptions. ([#1215](https://github.com/WordPress/playground/pull/1215)) +- Catch DNS errors to avoid unhandled exceptions. ([#1215](https://github.com/WordPress/playground/pull/1215)) -- Revert "Avoid partial munmap memory leak". ([#1195](https://github.com/WordPress/playground/pull/1195)) -- Try to repro memory out of bounds errors in CI. ([#1198](https://github.com/WordPress/playground/pull/1198)) +- Revert "Avoid partial munmap memory leak". ([#1195](https://github.com/WordPress/playground/pull/1195)) +- Try to repro memory out of bounds errors in CI. ([#1198](https://github.com/WordPress/playground/pull/1198)) ### Various -- Adjust link to LICENSE file. ([#1210](https://github.com/WordPress/playground/pull/1210)) -- Try to reproduce the memory access error with files from 096a017. ([#1212](https://github.com/WordPress/playground/pull/1212)) +- Adjust link to LICENSE file. ([#1210](https://github.com/WordPress/playground/pull/1210)) +- Try to reproduce the memory access error with files from 096a017. ([#1212](https://github.com/WordPress/playground/pull/1212)) ### Contributors @@ -3370,25 +3370,25 @@ The following contributors merged PRs in this release: ### Blueprints -- Rename importFile to importWxr, switch to humanmade/WordPress importer. ([#1192](https://github.com/WordPress/playground/pull/1192)) +- Rename importFile to importWxr, switch to humanmade/WordPress importer. ([#1192](https://github.com/WordPress/playground/pull/1192)) ### Tools #### Blueprints -- Explorations: Stream API. ([#851](https://github.com/WordPress/playground/pull/851)) +- Explorations: Stream API. ([#851](https://github.com/WordPress/playground/pull/851)) ### PHP WebAssembly -- Avoid partial munmap memory leak. ([#1189](https://github.com/WordPress/playground/pull/1189)) +- Avoid partial munmap memory leak. ([#1189](https://github.com/WordPress/playground/pull/1189)) ### Website -- Make kitchen sink extension bundle the default. ([#1191](https://github.com/WordPress/playground/pull/1191)) +- Make kitchen sink extension bundle the default. ([#1191](https://github.com/WordPress/playground/pull/1191)) ### Bug Fixes -- Fix cross-device mv by switching to copy. ([#846](https://github.com/WordPress/playground/pull/846)) +- Fix cross-device mv by switching to copy. ([#846](https://github.com/WordPress/playground/pull/846)) ### Contributors @@ -3400,49 +3400,49 @@ The following contributors merged PRs in this release: ### Tools -- Devex: Expose window.playground for quick testing and debugging. ([#1125](https://github.com/WordPress/playground/pull/1125)) +- Devex: Expose window.playground for quick testing and debugging. ([#1125](https://github.com/WordPress/playground/pull/1125)) #### GitHub integration -- Website: Query API options to preconfigure the GitHub export form. ([#1174](https://github.com/WordPress/playground/pull/1174)) +- Website: Query API options to preconfigure the GitHub export form. ([#1174](https://github.com/WordPress/playground/pull/1174)) ### Documentation -- Update the wp-cli step code example. ([#1140](https://github.com/WordPress/playground/pull/1140)) +- Update the wp-cli step code example. ([#1140](https://github.com/WordPress/playground/pull/1140)) ### PHP WebAssembly -- Add PHP iterator and yield support. ([#1181](https://github.com/WordPress/playground/pull/1181)) -- Fix fileinfo support. ([#1179](https://github.com/WordPress/playground/pull/1179)) -- Fix mbregex support. ([#1155](https://github.com/WordPress/playground/pull/1155)) -- PHP.run(): Throw JS exception on runtime error, remove throwOnError flag. ([#1137](https://github.com/WordPress/playground/pull/1137)) +- Add PHP iterator and yield support. ([#1181](https://github.com/WordPress/playground/pull/1181)) +- Fix fileinfo support. ([#1179](https://github.com/WordPress/playground/pull/1179)) +- Fix mbregex support. ([#1155](https://github.com/WordPress/playground/pull/1155)) +- PHP.run(): Throw JS exception on runtime error, remove throwOnError flag. ([#1137](https://github.com/WordPress/playground/pull/1137)) ### Website -- Add error report modal. ([#1102](https://github.com/WordPress/playground/pull/1102)) -- Ensure PromiseRejectionEvent has reason before logging it. ([#1150](https://github.com/WordPress/playground/pull/1150)) -- Request handler: Remove everything after # from the URL. ([#1126](https://github.com/WordPress/playground/pull/1126)) -- Web: Make the "Apply changes" button work in Playground settings form. ([#1122](https://github.com/WordPress/playground/pull/1122)) +- Add error report modal. ([#1102](https://github.com/WordPress/playground/pull/1102)) +- Ensure PromiseRejectionEvent has reason before logging it. ([#1150](https://github.com/WordPress/playground/pull/1150)) +- Request handler: Remove everything after # from the URL. ([#1126](https://github.com/WordPress/playground/pull/1126)) +- Web: Make the "Apply changes" button work in Playground settings form. ([#1122](https://github.com/WordPress/playground/pull/1122)) #### Plugin proxy -- Allow requests to WordPress.org. ([#1154](https://github.com/WordPress/playground/pull/1154)) +- Allow requests to WordPress.org. ([#1154](https://github.com/WordPress/playground/pull/1154)) ### Internal -- Refresh WordPress with the latest SQLite integration plugin. ([#1151](https://github.com/WordPress/playground/pull/1151)) +- Refresh WordPress with the latest SQLite integration plugin. ([#1151](https://github.com/WordPress/playground/pull/1151)) ### Bug Fixes -- Fix typo in blueprints/public/schema-readme.md. ([#1134](https://github.com/WordPress/playground/pull/1134)) -- Priority: Fix broken link to VS Code extension. ([#1141](https://github.com/WordPress/playground/pull/1141)) +- Fix typo in blueprints/public/schema-readme.md. ([#1134](https://github.com/WordPress/playground/pull/1134)) +- Priority: Fix broken link to VS Code extension. ([#1141](https://github.com/WordPress/playground/pull/1141)) ### Various -- Docs/update - Add implied step. ([#1144](https://github.com/WordPress/playground/pull/1144)) -- Give brandonpayton permission to run Playground GH workflows. ([#1139](https://github.com/WordPress/playground/pull/1139)) -- Logger API: Add rate limiting. ([#1142](https://github.com/WordPress/playground/pull/1142)) -- Remove `--disable-all` configuration option in PHP compile process. ([#1132](https://github.com/WordPress/playground/pull/1132)) +- Docs/update - Add implied step. ([#1144](https://github.com/WordPress/playground/pull/1144)) +- Give brandonpayton permission to run Playground GH workflows. ([#1139](https://github.com/WordPress/playground/pull/1139)) +- Logger API: Add rate limiting. ([#1142](https://github.com/WordPress/playground/pull/1142)) +- Remove `--disable-all` configuration option in PHP compile process. ([#1132](https://github.com/WordPress/playground/pull/1132)) ### Contributors @@ -3454,45 +3454,45 @@ The following contributors merged PRs in this release: ### Blueprints -- Allow optional metadata. ([#1103](https://github.com/WordPress/playground/pull/1103)) +- Allow optional metadata. ([#1103](https://github.com/WordPress/playground/pull/1103)) ### Tools -- Add VSCode Chrome debugging support. ([#1088](https://github.com/WordPress/playground/pull/1088)) -- Website: Support Base64-encoding Blueprints passed in the URL. ([#1091](https://github.com/WordPress/playground/pull/1091)) +- Add VSCode Chrome debugging support. ([#1088](https://github.com/WordPress/playground/pull/1088)) +- Website: Support Base64-encoding Blueprints passed in the URL. ([#1091](https://github.com/WordPress/playground/pull/1091)) ### Documentation -- Docs: Expand Details section. ([#1109](https://github.com/WordPress/playground/pull/1109)) -- Update activate-theme.ts to use `themeFolderName`. ([#1119](https://github.com/WordPress/playground/pull/1119)) +- Docs: Expand Details section. ([#1109](https://github.com/WordPress/playground/pull/1109)) +- Update activate-theme.ts to use `themeFolderName`. ([#1119](https://github.com/WordPress/playground/pull/1119)) ### PHP WebAssembly -- Blueprints: Explore switching to the PHP implementation. ([#1051](https://github.com/WordPress/playground/pull/1051)) -- Explore weird register_shutdown_function behavior. ([#1099](https://github.com/WordPress/playground/pull/1099)) -- Fix post_message_to_js memory out of bounds. ([#1114](https://github.com/WordPress/playground/pull/1114)) -- Fix shutdown errors. ([#1104](https://github.com/WordPress/playground/pull/1104)) -- Fixing build regression [BISON COMPILE]. ([#871](https://github.com/WordPress/playground/pull/871)) -- PHP : Set appropriate SCRIPT variables in $\_SERVER superglobal. ([#1092](https://github.com/WordPress/playground/pull/1092)) +- Blueprints: Explore switching to the PHP implementation. ([#1051](https://github.com/WordPress/playground/pull/1051)) +- Explore weird register_shutdown_function behavior. ([#1099](https://github.com/WordPress/playground/pull/1099)) +- Fix post_message_to_js memory out of bounds. ([#1114](https://github.com/WordPress/playground/pull/1114)) +- Fix shutdown errors. ([#1104](https://github.com/WordPress/playground/pull/1104)) +- Fixing build regression [BISON COMPILE]. ([#871](https://github.com/WordPress/playground/pull/871)) +- PHP : Set appropriate SCRIPT variables in $\_SERVER superglobal. ([#1092](https://github.com/WordPress/playground/pull/1092)) ### Website -- Add logger API. ([#1113](https://github.com/WordPress/playground/pull/1113)) -- Add multisite rewrite rules. ([#1083](https://github.com/WordPress/playground/pull/1083)) -- Service worker: Improve error reporting in non-secure contexts. ([#1098](https://github.com/WordPress/playground/pull/1098)) +- Add logger API. ([#1113](https://github.com/WordPress/playground/pull/1113)) +- Add multisite rewrite rules. ([#1083](https://github.com/WordPress/playground/pull/1083)) +- Service worker: Improve error reporting in non-secure contexts. ([#1098](https://github.com/WordPress/playground/pull/1098)) ### Bug Fixes -- Fix experimental notice in FF ESR. ([#1117](https://github.com/WordPress/playground/pull/1117)) -- Fix php bison dep for building on non-arm64 architectures. ([#1115](https://github.com/WordPress/playground/pull/1115)) +- Fix experimental notice in FF ESR. ([#1117](https://github.com/WordPress/playground/pull/1117)) +- Fix php bison dep for building on non-arm64 architectures. ([#1115](https://github.com/WordPress/playground/pull/1115)) ### Reliability -- Add fatal errror listener. ([#1095](https://github.com/WordPress/playground/pull/1095)) +- Add fatal errror listener. ([#1095](https://github.com/WordPress/playground/pull/1095)) ### Various -- Update examples and demos in the documentation. ([#1107](https://github.com/WordPress/playground/pull/1107)) +- Update examples and demos in the documentation. ([#1107](https://github.com/WordPress/playground/pull/1107)) ### Contributors @@ -3504,7 +3504,7 @@ The following contributors merged PRs in this release: ### Website -- Node polyfills: Only apply them in Node.js, not in web browsers. ([#1089](https://github.com/WordPress/playground/pull/1089)) +- Node polyfills: Only apply them in Node.js, not in web browsers. ([#1089](https://github.com/WordPress/playground/pull/1089)) ### Contributors @@ -3516,10 +3516,10 @@ The following contributors merged PRs in this release: ### Website -- Comlink API: Pass the context argument to windowEndpoint, not wrap. ([#1087](https://github.com/WordPress/playground/pull/1087)) -- Fix: Playground not starting due to a race condition. ([#1084](https://github.com/WordPress/playground/pull/1084)) -- Hide the "This is experimental WordPress" notice on click. ([#1082](https://github.com/WordPress/playground/pull/1082)) -- Set the API context when using Comlink.wrap(). ([#1085](https://github.com/WordPress/playground/pull/1085)) +- Comlink API: Pass the context argument to windowEndpoint, not wrap. ([#1087](https://github.com/WordPress/playground/pull/1087)) +- Fix: Playground not starting due to a race condition. ([#1084](https://github.com/WordPress/playground/pull/1084)) +- Hide the "This is experimental WordPress" notice on click. ([#1082](https://github.com/WordPress/playground/pull/1082)) +- Set the API context when using Comlink.wrap(). ([#1085](https://github.com/WordPress/playground/pull/1085)) ### Contributors @@ -3533,25 +3533,25 @@ The following contributors merged PRs in this release: #### Plugin proxy -- Add Sensei to the allowed repositories for plugin proxy. ([#1079](https://github.com/WordPress/playground/pull/1079)) +- Add Sensei to the allowed repositories for plugin proxy. ([#1079](https://github.com/WordPress/playground/pull/1079)) #### Blueprints -- Snapshot Import Protocol v1. ([#1007](https://github.com/WordPress/playground/pull/1007)) +- Snapshot Import Protocol v1. ([#1007](https://github.com/WordPress/playground/pull/1007)) ### Internal -- Build the php-wasm/util package as both ESM and CJS. ([#1081](https://github.com/WordPress/playground/pull/1081)) +- Build the php-wasm/util package as both ESM and CJS. ([#1081](https://github.com/WordPress/playground/pull/1081)) ### Reliability #### Blueprints -- Add unit tests to the mkdir step. ([#1029](https://github.com/WordPress/playground/pull/1029)) +- Add unit tests to the mkdir step. ([#1029](https://github.com/WordPress/playground/pull/1029)) ### Various -- Website query API: Continue plugin installs on error. ([#605](https://github.com/WordPress/playground/pull/605)) +- Website query API: Continue plugin installs on error. ([#605](https://github.com/WordPress/playground/pull/605)) ### Contributors @@ -3563,52 +3563,52 @@ The following contributors merged PRs in this release: ### Enhancements -- Add logging support to Playground. ([#1035](https://github.com/WordPress/playground/pull/1035)) +- Add logging support to Playground. ([#1035](https://github.com/WordPress/playground/pull/1035)) ### Blueprints -- PHP Blueprints: Display progress. ([#1077](https://github.com/WordPress/playground/pull/1077)) -- Set progress caption and communicate failures in the import file step. ([#1034](https://github.com/WordPress/playground/pull/1034)) +- PHP Blueprints: Display progress. ([#1077](https://github.com/WordPress/playground/pull/1077)) +- Set progress caption and communicate failures in the import file step. ([#1034](https://github.com/WordPress/playground/pull/1034)) ### Tools #### Blueprints -- PHP Blueprints demo page. ([#1070](https://github.com/WordPress/playground/pull/1070)) -- PHP: Do not prepend a whitespace when encoding body as multipart form data. ([#1033](https://github.com/WordPress/playground/pull/1033)) +- PHP Blueprints demo page. ([#1070](https://github.com/WordPress/playground/pull/1070)) +- PHP: Do not prepend a whitespace when encoding body as multipart form data. ([#1033](https://github.com/WordPress/playground/pull/1033)) ### PHP WebAssembly -- Fix response header escaping. ([#1050](https://github.com/WordPress/playground/pull/1050)) -- Fix: Networking broken when extra PHP extensions are enabled. ([#1045](https://github.com/WordPress/playground/pull/1045)) -- PHP.wasm: Yield 0 bytes read on fd_read failure to improve PHP's fread() and feof() behavior. ([#1053](https://github.com/WordPress/playground/pull/1053)) -- PHP: Support $env and $cwd proc_open arguments. ([#1064](https://github.com/WordPress/playground/pull/1064)) -- Parse shell commands in createSpawnHandler. ([#1065](https://github.com/WordPress/playground/pull/1065)) -- Prototype: Spawning PHP sub-processes in Web Workers. ([#1031](https://github.com/WordPress/playground/pull/1031)) -- Spawning PHP sub-processes in Web Workers. ([#1069](https://github.com/WordPress/playground/pull/1069)) +- Fix response header escaping. ([#1050](https://github.com/WordPress/playground/pull/1050)) +- Fix: Networking broken when extra PHP extensions are enabled. ([#1045](https://github.com/WordPress/playground/pull/1045)) +- PHP.wasm: Yield 0 bytes read on fd_read failure to improve PHP's fread() and feof() behavior. ([#1053](https://github.com/WordPress/playground/pull/1053)) +- PHP: Support $env and $cwd proc_open arguments. ([#1064](https://github.com/WordPress/playground/pull/1064)) +- Parse shell commands in createSpawnHandler. ([#1065](https://github.com/WordPress/playground/pull/1065)) +- Prototype: Spawning PHP sub-processes in Web Workers. ([#1031](https://github.com/WordPress/playground/pull/1031)) +- Spawning PHP sub-processes in Web Workers. ([#1069](https://github.com/WordPress/playground/pull/1069)) ### Website -- Add Google Analytics events to Playground. ([#1040](https://github.com/WordPress/playground/pull/1040)) -- Fix error on reload site click. ([#1041](https://github.com/WordPress/playground/pull/1041)) +- Add Google Analytics events to Playground. ([#1040](https://github.com/WordPress/playground/pull/1040)) +- Fix error on reload site click. ([#1041](https://github.com/WordPress/playground/pull/1041)) ### Internal -- Rebuild WordPress every 20 minutes, short-circuit if no new version is found. ([#1061](https://github.com/WordPress/playground/pull/1061)) -- Rebuild WordPress within an hour of a beta release. ([#1059](https://github.com/WordPress/playground/pull/1059)) +- Rebuild WordPress every 20 minutes, short-circuit if no new version is found. ([#1061](https://github.com/WordPress/playground/pull/1061)) +- Rebuild WordPress within an hour of a beta release. ([#1059](https://github.com/WordPress/playground/pull/1059)) ### Bug Fixes -- Fix the login message so it doesn't override another. ([#1044](https://github.com/WordPress/playground/pull/1044)) +- Fix the login message so it doesn't override another. ([#1044](https://github.com/WordPress/playground/pull/1044)) ### Various -- Add arguments to default node spawn method. ([#1037](https://github.com/WordPress/playground/pull/1037)) -- Add bgrgicak to deployment allowlists. ([#1057](https://github.com/WordPress/playground/pull/1057)) -- Allow for CORS requests to api.wordpress.org to pass. ([#1009](https://github.com/WordPress/playground/pull/1009)) -- Default URL rewrites to /index.php. ([#1072](https://github.com/WordPress/playground/pull/1072)) -- Remove repository specific Code of Conduct. ([#1038](https://github.com/WordPress/playground/pull/1038)) -- Ship WordPress 6.5 beta 1. ([#1036](https://github.com/WordPress/playground/pull/1036)) +- Add arguments to default node spawn method. ([#1037](https://github.com/WordPress/playground/pull/1037)) +- Add bgrgicak to deployment allowlists. ([#1057](https://github.com/WordPress/playground/pull/1057)) +- Allow for CORS requests to api.wordpress.org to pass. ([#1009](https://github.com/WordPress/playground/pull/1009)) +- Default URL rewrites to /index.php. ([#1072](https://github.com/WordPress/playground/pull/1072)) +- Remove repository specific Code of Conduct. ([#1038](https://github.com/WordPress/playground/pull/1038)) +- Ship WordPress 6.5 beta 1. ([#1036](https://github.com/WordPress/playground/pull/1036)) ### Contributors @@ -3620,13 +3620,13 @@ The following contributors merged PRs in this release: ### Blueprints -- Wp-cli step. ([#1017](https://github.com/WordPress/playground/pull/1017)) +- Wp-cli step. ([#1017](https://github.com/WordPress/playground/pull/1017)) ### PHP WebAssembly -- Calls proc_open two times in a row. ([#1012](https://github.com/WordPress/playground/pull/1012)) -- Experiment: Build PHP with OPFS support. ([#1030](https://github.com/WordPress/playground/pull/1030)) -- PHP: Pass request body as UInt8Array. ([#1018](https://github.com/WordPress/playground/pull/1018)) +- Calls proc_open two times in a row. ([#1012](https://github.com/WordPress/playground/pull/1012)) +- Experiment: Build PHP with OPFS support. ([#1030](https://github.com/WordPress/playground/pull/1030)) +- PHP: Pass request body as UInt8Array. ([#1018](https://github.com/WordPress/playground/pull/1018)) ### Contributors @@ -3638,19 +3638,19 @@ The following contributors merged PRs in this release: ### PHP WebAssembly -- Networking: Swap Requests transports using the http_api_transports instead of patching the Requests library. ([#1004](https://github.com/WordPress/playground/pull/1004)) -- Remove `crypto.randomUUID` dependency in favor of a custom function. ([#1016](https://github.com/WordPress/playground/pull/1016)) -- Remove x-request-issuer header on cross-origin requests. ([#1010](https://github.com/WordPress/playground/pull/1010)) -- Update wp_http_fetch.php. ([#1002](https://github.com/WordPress/playground/pull/1002)) +- Networking: Swap Requests transports using the http_api_transports instead of patching the Requests library. ([#1004](https://github.com/WordPress/playground/pull/1004)) +- Remove `crypto.randomUUID` dependency in favor of a custom function. ([#1016](https://github.com/WordPress/playground/pull/1016)) +- Remove x-request-issuer header on cross-origin requests. ([#1010](https://github.com/WordPress/playground/pull/1010)) +- Update wp_http_fetch.php. ([#1002](https://github.com/WordPress/playground/pull/1002)) ### Website -- Remote.html: Always install the playground mu-plugin. ([#1005](https://github.com/WordPress/playground/pull/1005)) +- Remote.html: Always install the playground mu-plugin. ([#1005](https://github.com/WordPress/playground/pull/1005)) ### Various -- 32bit integer workaround. ([#1014](https://github.com/WordPress/playground/pull/1014)) -- Test/hello world blueprint. ([#908](https://github.com/WordPress/playground/pull/908)) +- 32bit integer workaround. ([#1014](https://github.com/WordPress/playground/pull/1014)) +- Test/hello world blueprint. ([#908](https://github.com/WordPress/playground/pull/908)) ### Contributors @@ -3664,11 +3664,11 @@ The following contributors merged PRs in this release: #### Blueprints -- Remove the applyWordPressPatches step, enable the Site Health Plugin. ([#1001](https://github.com/WordPress/playground/pull/1001)) +- Remove the applyWordPressPatches step, enable the Site Health Plugin. ([#1001](https://github.com/WordPress/playground/pull/1001)) ### Various -- Add `crypto` to Polyfills improving Blueprint compatibility for Node. ([#1000](https://github.com/WordPress/playground/pull/1000)) +- Add `crypto` to Polyfills improving Blueprint compatibility for Node. ([#1000](https://github.com/WordPress/playground/pull/1000)) ### Contributors @@ -3680,59 +3680,59 @@ The following contributors merged PRs in this release: ### Enhancements -- Add wp-cli and code editor examples to the demos page. ([#965](https://github.com/WordPress/playground/pull/965)) -- WordPress: Preserve PHP attributes and wp-config.php whitespace. ([#964](https://github.com/WordPress/playground/pull/964)) +- Add wp-cli and code editor examples to the demos page. ([#965](https://github.com/WordPress/playground/pull/965)) +- WordPress: Preserve PHP attributes and wp-config.php whitespace. ([#964](https://github.com/WordPress/playground/pull/964)) ### Blueprints -- Add enableMultisite step. ([#888](https://github.com/WordPress/playground/pull/888)) -- Set_current_user to admin before activating plugins and themes. ([#984](https://github.com/WordPress/playground/pull/984)) +- Add enableMultisite step. ([#888](https://github.com/WordPress/playground/pull/888)) +- Set_current_user to admin before activating plugins and themes. ([#984](https://github.com/WordPress/playground/pull/984)) ### Tools -- Use .zip files instead of .data files for loading WordPress. ([#978](https://github.com/WordPress/playground/pull/978)) +- Use .zip files instead of .data files for loading WordPress. ([#978](https://github.com/WordPress/playground/pull/978)) #### Blueprints -- Throw on failure. ([#982](https://github.com/WordPress/playground/pull/982)) +- Throw on failure. ([#982](https://github.com/WordPress/playground/pull/982)) #### PHP WebAssembly -- Support wp-cli in the browser. ([#957](https://github.com/WordPress/playground/pull/957)) +- Support wp-cli in the browser. ([#957](https://github.com/WordPress/playground/pull/957)) ### PHP WebAssembly -- Correcting OOB & Prevent Crash on Saving Large Post. ([#870](https://github.com/WordPress/playground/pull/870)) -- Memory leak: Add rotatedPHP to kill and recreate PHP instances after a certain number of requests. ([#990](https://github.com/WordPress/playground/pull/990)) -- PHP : Add args and descriptors dynamic arrays in proc open function. ([#969](https://github.com/WordPress/playground/pull/969)) -- PHP.wasm: Fix stack overflow in wasm_set_request_body. ([#993](https://github.com/WordPress/playground/pull/993)) +- Correcting OOB & Prevent Crash on Saving Large Post. ([#870](https://github.com/WordPress/playground/pull/870)) +- Memory leak: Add rotatedPHP to kill and recreate PHP instances after a certain number of requests. ([#990](https://github.com/WordPress/playground/pull/990)) +- PHP : Add args and descriptors dynamic arrays in proc open function. ([#969](https://github.com/WordPress/playground/pull/969)) +- PHP.wasm: Fix stack overflow in wasm_set_request_body. ([#993](https://github.com/WordPress/playground/pull/993)) ### Website -- Add .htaccess file to prevent caching of index.html and enable importing the client.js library. ([#989](https://github.com/WordPress/playground/pull/989)) -- Add og meta tags and meta description. ([#980](https://github.com/WordPress/playground/pull/980)) -- CORS headers for client/index.js. ([#893](https://github.com/WordPress/playground/pull/893)) -- wp-cli: Respect quotes when parsing shell commands. ([#966](https://github.com/WordPress/playground/pull/966)) +- Add .htaccess file to prevent caching of index.html and enable importing the client.js library. ([#989](https://github.com/WordPress/playground/pull/989)) +- Add og meta tags and meta description. ([#980](https://github.com/WordPress/playground/pull/980)) +- CORS headers for client/index.js. ([#893](https://github.com/WordPress/playground/pull/893)) +- wp-cli: Respect quotes when parsing shell commands. ([#966](https://github.com/WordPress/playground/pull/966)) ### Internal -- Remove the interactive block playground. ([#988](https://github.com/WordPress/playground/pull/988)) +- Remove the interactive block playground. ([#988](https://github.com/WordPress/playground/pull/988)) ### Bug Fixes -- Fix "WP-CLI" typos. ([#971](https://github.com/WordPress/playground/pull/971)) -- Fix footer styling issue in the "Code is Poetry" in wordpress.github.io/wordpress-playground. ([#959](https://github.com/WordPress/playground/pull/959)) -- WordPress build: Add newlines after PHP annotations. ([#986](https://github.com/WordPress/playground/pull/986)) +- Fix "WP-CLI" typos. ([#971](https://github.com/WordPress/playground/pull/971)) +- Fix footer styling issue in the "Code is Poetry" in wordpress.github.io/wordpress-playground. ([#959](https://github.com/WordPress/playground/pull/959)) +- WordPress build: Add newlines after PHP annotations. ([#986](https://github.com/WordPress/playground/pull/986)) ### Various -- Add a blueprint example. ([#946](https://github.com/WordPress/playground/pull/946)) -- Add terminal to playground site. ([#161](https://github.com/WordPress/playground/pull/161)) -- Match the .nvmrc node version to the changes made in commit ec2605b. ([#972](https://github.com/WordPress/playground/pull/972)) -- PHP : Dispatch available descriptor specs in js_open_process function. ([#963](https://github.com/WordPress/playground/pull/963)) -- PHP : Give access to command arguments if array type is given in php ^7.4 proc_open function. ([#944](https://github.com/WordPress/playground/pull/944)) -- Rebuild WordPress. ([#987](https://github.com/WordPress/playground/pull/987)) -- Update the networking disabled error messages in wp-admin for plugins and themes. ([#936](https://github.com/WordPress/playground/pull/936)) +- Add a blueprint example. ([#946](https://github.com/WordPress/playground/pull/946)) +- Add terminal to playground site. ([#161](https://github.com/WordPress/playground/pull/161)) +- Match the .nvmrc node version to the changes made in commit ec2605b. ([#972](https://github.com/WordPress/playground/pull/972)) +- PHP : Dispatch available descriptor specs in js_open_process function. ([#963](https://github.com/WordPress/playground/pull/963)) +- PHP : Give access to command arguments if array type is given in php ^7.4 proc_open function. ([#944](https://github.com/WordPress/playground/pull/944)) +- Rebuild WordPress. ([#987](https://github.com/WordPress/playground/pull/987)) +- Update the networking disabled error messages in wp-admin for plugins and themes. ([#936](https://github.com/WordPress/playground/pull/936)) ### Contributors diff --git a/packages/docs/site/docs/developers/03-build-an-app/01-index.md b/packages/docs/site/docs/developers/03-build-an-app/01-index.md index d232cb80ba..654f1608de 100644 --- a/packages/docs/site/docs/developers/03-build-an-app/01-index.md +++ b/packages/docs/site/docs/developers/03-build-an-app/01-index.md @@ -119,8 +119,8 @@ Loading a `.zip` file is another alternative for previewing your project. See th To use Playground as a PR previewer, you need: -- A CI pipeline that bundles your plugin or theme -- Public access to the generated `.zip` file +- A CI pipeline that bundles your plugin or theme +- Public access to the generated `.zip` file Those zip bundles aren't any different from regular WordPress Plugins, which means you can install them in Playground using the [JSON Blueprints](/blueprints) API. Once you expose an endpoint like https://your-site.com/pull-request-1234.zip, the following Blueprint will do the rest: @@ -187,9 +187,9 @@ blueprint={{ You can preview specific pull requests from WordPress Core and Gutenberg repositories using Query API parameters. Gutenberg branches also have an alternative to preview them with the parameter `gutenberg-branch`. This is useful for testing the latest trunk changes or specific feature branches without creating a PR. -- Preview a specific WordPress Core PR: `https://playground.wordpress.net/?core-pr=9500` -- Preview a specific Gutenberg PR: `https://playground.wordpress.net/?gutenberg-pr=73010` -- Preview the Gutenberg trunk branch: `https://playground.wordpress.net/?gutenberg-branch=trunk` +- Preview a specific WordPress Core PR: `https://playground.wordpress.net/?core-pr=9500` +- Preview a specific Gutenberg PR: `https://playground.wordpress.net/?gutenberg-pr=73010` +- Preview the Gutenberg trunk branch: `https://playground.wordpress.net/?gutenberg-branch=trunk` ## Build a compatibility testing environment diff --git a/packages/docs/site/i18n/es/docusaurus-plugin-content-docs/current/developers/03-build-an-app/01-index.md b/packages/docs/site/i18n/es/docusaurus-plugin-content-docs/current/developers/03-build-an-app/01-index.md index 4107659fec..99cb8a637f 100644 --- a/packages/docs/site/i18n/es/docusaurus-plugin-content-docs/current/developers/03-build-an-app/01-index.md +++ b/packages/docs/site/i18n/es/docusaurus-plugin-content-docs/current/developers/03-build-an-app/01-index.md @@ -197,8 +197,8 @@ Para usar Playground como un previsualizador de PR, necesitas: - Public access to the generated `.zip` file --> -- Un pipeline de CI que empaquete tu plugin o tema -- Acceso público al archivo `.zip` generado +- Un pipeline de CI que empaquete tu plugin o tema +- Acceso público al archivo `.zip` generado -- Previsualizar un PR específico de WordPress Core: `https://playground.wordpress.net/?core-pr=9500` -- Previsualizar un PR específico de Gutenberg: `https://playground.wordpress.net/?gutenberg-pr=73010` -- Previsualizar la rama trunk de Gutenberg: `https://playground.wordpress.net/?gutenberg-branch=trunk` +- Previsualizar un PR específico de WordPress Core: `https://playground.wordpress.net/?core-pr=9500` +- Previsualizar un PR específico de Gutenberg: `https://playground.wordpress.net/?gutenberg-pr=73010` +- Previsualizar la rama trunk de Gutenberg: `https://playground.wordpress.net/?gutenberg-branch=trunk` -- D'un pipeline CI qui empaquette votre plugin ou thème -- D'un accès public au fichier `.zip` généré +- D'un pipeline CI qui empaquette votre plugin ou thème +- D'un accès public au fichier `.zip` généré -- Prévisualiser un PR WordPress Core spécifique : `https://playground.wordpress.net/?core-pr=9500` -- Prévisualiser un PR Gutenberg spécifique : `https://playground.wordpress.net/?gutenberg-pr=73010` -- Prévisualiser la branche trunk de Gutenberg : `https://playground.wordpress.net/?gutenberg-branch=trunk` +- Prévisualiser un PR WordPress Core spécifique : `https://playground.wordpress.net/?core-pr=9500` +- Prévisualiser un PR Gutenberg spécifique : `https://playground.wordpress.net/?gutenberg-pr=73010` +- Prévisualiser la branche trunk de Gutenberg : `https://playground.wordpress.net/?gutenberg-branch=trunk` -- Um pipeline de CI que empacote seu plugin ou tema -- Acesso público ao arquivo `.zip` gerado +- Um pipeline de CI que empacote seu plugin ou tema +- Acesso público ao arquivo `.zip` gerado @@ -239,9 +239,9 @@ Você pode visualizar pull requests específicos dos repositórios WordPress Cor -- Visualizar um PR específico do WordPress Core: `https://playground.wordpress.net/?core-pr=9500` -- Visualizar um PR específico do Gutenberg: `https://playground.wordpress.net/?gutenberg-pr=73010` -- Visualizar o branch trunk do Gutenberg: `https://playground.wordpress.net/?gutenberg-branch=trunk` +- Visualizar um PR específico do WordPress Core: `https://playground.wordpress.net/?core-pr=9500` +- Visualizar um PR específico do Gutenberg: `https://playground.wordpress.net/?gutenberg-pr=73010` +- Visualizar o branch trunk do Gutenberg: `https://playground.wordpress.net/?gutenberg-branch=trunk` diff --git a/packages/php-wasm/compile/Makefile b/packages/php-wasm/compile/Makefile index f472a680a5..a78e88fa64 100644 --- a/packages/php-wasm/compile/Makefile +++ b/packages/php-wasm/compile/Makefile @@ -128,6 +128,22 @@ libavif/jspi/dist/root/lib/lib/libavif.a: base-image docker cp $$(docker create playground-php-wasm:libavif):/root/lib/lib ./libavif/jspi/dist/root/lib docker cp $$(docker create playground-php-wasm:libavif):/root/lib/include ./libavif/jspi/dist/root/lib +libgd_asyncify: libgd/asyncify/dist/root/lib/lib/libgd.a +libgd/asyncify/dist/root/lib/lib/libgd.a: base-image libz_asyncify libpng16_asyncify libjpeg_asyncify libwebp_asyncify libavif_asyncify + mkdir -p ./libgd/asyncify/dist/root/lib + docker build -f ./libgd/Dockerfile -t playground-php-wasm:libgd . + docker cp $$(docker create playground-php-wasm:libgd):/root/install/lib ./libgd/asyncify/dist/root/lib + docker cp $$(docker create playground-php-wasm:libgd):/root/install/include ./libgd/asyncify/dist/root/lib + docker cp $$(docker create playground-php-wasm:libgd):/root/install/bin ./libgd/asyncify/dist/root/lib + +libgd_jspi: libgd/jspi/dist/root/lib/lib/libgd.a +libgd/jspi/dist/root/lib/lib/libgd.a: base-image libz_jspi libpng16_jspi libjpeg_jspi libwebp_jspi libavif_jspi + mkdir -p ./libgd/jspi/dist/root/lib + docker build -f ./libgd/Dockerfile -t playground-php-wasm:libgd . --build-arg JSPI=1 + docker cp $$(docker create playground-php-wasm:libgd):/root/install/lib ./libgd/jspi/dist/root/lib + docker cp $$(docker create playground-php-wasm:libgd):/root/install/include ./libgd/jspi/dist/root/lib + docker cp $$(docker create playground-php-wasm:libgd):/root/install/bin ./libgd/jspi/dist/root/lib + libxml2_asyncify: libxml2/asyncify/dist/root/lib/lib/libxml2.a libxml2/asyncify/dist/root/lib/lib/libxml2.a: base-image libz_asyncify mkdir -p ./libxml2/asyncify/dist/root/lib @@ -317,8 +333,8 @@ libImageMagick/jspi/dist/root/lib/lib/libMagickCore-7.Q16HDRI.a: base-image libz docker cp $$(docker create playground-php-wasm:libImageMagick):/root/install/bin ./libImageMagick/jspi/dist/root/lib all: all_jspi all_asyncify -all_jspi: libz_jspi libzip_jspi libpng16_jspi libjpeg_jspi libwebp_jspi libaom_jspi libavif_jspi libxml2_jspi libopenssl_jspi libsqlite3_jspi libiconv_jspi bison2.7 oniguruma_jspi libcurl_jspi libintl_jspi libImageMagick_jspi -all_asyncify: libz_asyncify libzip_asyncify libpng16_asyncify libjpeg_asyncify libwebp_asyncify libaom_asyncify libavif_asyncify libxml2_asyncify libopenssl_asyncify libsqlite3_asyncify libiconv_asyncify bison2.7 oniguruma_asyncify libcurl_asyncify libintl_asyncify libImageMagick_asyncify +all_jspi: libz_jspi libzip_jspi libpng16_jspi libjpeg_jspi libwebp_jspi libaom_jspi libavif_jspi libgd_jspi libxml2_jspi libopenssl_jspi libsqlite3_jspi libiconv_jspi bison2.7 oniguruma_jspi libcurl_jspi libintl_jspi libImageMagick_jspi +all_asyncify: libz_asyncify libzip_asyncify libpng16_asyncify libjpeg_asyncify libwebp_asyncify libaom_asyncify libavif_asyncify libgd_asyncify libxml2_asyncify libopenssl_asyncify libsqlite3_asyncify libiconv_asyncify bison2.7 oniguruma_asyncify libcurl_asyncify libintl_asyncify libImageMagick_asyncify clean: rm -rf ./libz/jspi/dist diff --git a/packages/php-wasm/compile/libavif/asyncify/dist/root/lib/lib/libavif.a b/packages/php-wasm/compile/libavif/asyncify/dist/root/lib/lib/libavif.a index be74e57ffa..81ff5af441 100644 Binary files a/packages/php-wasm/compile/libavif/asyncify/dist/root/lib/lib/libavif.a and b/packages/php-wasm/compile/libavif/asyncify/dist/root/lib/lib/libavif.a differ diff --git a/packages/php-wasm/compile/libavif/jspi/dist/root/lib/lib/libavif.a b/packages/php-wasm/compile/libavif/jspi/dist/root/lib/lib/libavif.a index 6f1237e196..c3e42765f5 100644 Binary files a/packages/php-wasm/compile/libavif/jspi/dist/root/lib/lib/libavif.a and b/packages/php-wasm/compile/libavif/jspi/dist/root/lib/lib/libavif.a differ diff --git a/packages/php-wasm/compile/libgd/Dockerfile b/packages/php-wasm/compile/libgd/Dockerfile new file mode 100644 index 0000000000..469a0712be --- /dev/null +++ b/packages/php-wasm/compile/libgd/Dockerfile @@ -0,0 +1,144 @@ +FROM playground-php-wasm:base + +ARG JSPI +ARG GD_VERSION="2.3.3" + +RUN mkdir -p /root/lib/include /root/lib/lib +COPY ./libz/ /root/libz +COPY ./libpng16/ /root/libpng16 +COPY ./libjpeg/ /root/libjpeg +COPY ./libwebp/ /root/libwebp +COPY ./libavif/ /root/libavif +COPY ./libgd/libavifConfig.cmake /tmp/libavifConfig.cmake +COPY ./libgd/libavifConfigVersion.cmake /tmp/libavifConfigVersion.cmake + +RUN if [ "$JSPI" = "1" ]; then \ + cp -r /root/libz/jspi/dist/root/lib/* /root/lib; \ + cp -r /root/libpng16/jspi/dist/root/lib/* /root/lib; \ + cp -r /root/libjpeg/jspi/dist/root/lib/* /root/lib; \ + cp -r /root/libwebp/jspi/dist/root/lib/* /root/lib; \ + cp -r /root/libavif/jspi/dist/root/lib/* /root/lib; \ + else \ + cp -r /root/libz/asyncify/dist/root/lib/* /root/lib; \ + cp -r /root/libpng16/asyncify/dist/root/lib/* /root/lib; \ + cp -r /root/libjpeg/asyncify/dist/root/lib/* /root/lib; \ + cp -r /root/libwebp/asyncify/dist/root/lib/* /root/lib; \ + cp -r /root/libavif/asyncify/dist/root/lib/* /root/lib; \ + fi +RUN mkdir -p /root/lib/lib/cmake/libavif && \ + cp /tmp/libavifConfig.cmake /root/lib/lib/cmake/libavif/libavifConfig.cmake && \ + cp /tmp/libavifConfigVersion.cmake /root/lib/lib/cmake/libavif/libavifConfigVersion.cmake + +RUN wget https://github.com/libgd/libgd/releases/download/gd-$GD_VERSION/libgd-$GD_VERSION.tar.gz -O libgd.tar.gz +RUN tar -xzf libgd.tar.gz +WORKDIR /root/libgd-$GD_VERSION + +# Patch gd_security.c to make overflow2 static (avoids duplicate symbol with PHP's gd_compat.o) +RUN sed -i 's/^int overflow2/static int overflow2/' /root/libgd-$GD_VERSION/src/gd_security.c + +# Patch gdkanji.c to make iconv stubs static (avoids duplicate symbol with emscripten libc) +# Need to update both forward declarations and definitions +RUN sed -i 's/^iconv_t iconv_open (const char/static iconv_t iconv_open (const char/' /root/libgd-$GD_VERSION/src/gdkanji.c && \ + sed -i 's/^size_t iconv (iconv_t/static size_t iconv (iconv_t/' /root/libgd-$GD_VERSION/src/gdkanji.c && \ + sed -i 's/^int iconv_close (iconv_t/static int iconv_close (iconv_t/' /root/libgd-$GD_VERSION/src/gdkanji.c && \ + sed -i 's/^iconv_open (/static iconv_open (/' /root/libgd-$GD_VERSION/src/gdkanji.c && \ + sed -i 's/^iconv (/static iconv (/' /root/libgd-$GD_VERSION/src/gdkanji.c && \ + sed -i 's/^iconv_close (/static iconv_close (/' /root/libgd-$GD_VERSION/src/gdkanji.c + +# Add stub implementations for FreeType functions when FreeType is disabled +# These are needed because PHP's GD extension expects them +RUN echo '' >> /root/libgd-$GD_VERSION/src/gd.c && \ + echo '/* Stub implementations for when FreeType is disabled */' >> /root/libgd-$GD_VERSION/src/gd.c && \ + echo '#ifndef HAVE_LIBFREETYPE' >> /root/libgd-$GD_VERSION/src/gd.c && \ + echo '#include "gd.h"' >> /root/libgd-$GD_VERSION/src/gd.c && \ + echo 'BGD_DECLARE(void) gdFontCacheShutdown(void) {}' >> /root/libgd-$GD_VERSION/src/gd.c && \ + echo 'BGD_DECLARE(void) gdFreeFontCache(void) {}' >> /root/libgd-$GD_VERSION/src/gd.c && \ + echo '#endif' >> /root/libgd-$GD_VERSION/src/gd.c + +RUN set -euxo pipefail; \ + source /root/emsdk/emsdk_env.sh; \ + export PKG_CONFIG_PATH=/root/lib/lib/pkgconfig:$PKG_CONFIG_PATH; \ + emcmake cmake -G"Unix Makefiles" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/root/install \ + -DCMAKE_PREFIX_PATH=/root/lib \ + -DZLIB_LIBRARY=/root/lib/lib/libz.a \ + -DZLIB_INCLUDE_DIR=/root/lib/include \ + -DPNG_LIBRARY=/root/lib/lib/libpng16.a \ + -DPNG_PNG_INCLUDE_DIR=/root/lib/include \ + -DJPEG_LIBRARY=/root/lib/lib/libjpeg.a \ + -DJPEG_INCLUDE_DIR=/root/lib/include \ + -DWEBP_LIBRARY=/root/lib/lib/libwebp.a \ + -DWEBP_LIBRARIES="/root/lib/lib/libwebp.a;/root/lib/lib/libsharpyuv.a" \ + -DWEBP_INCLUDE_DIR=/root/lib/include \ + -DAVIF_LIBRARY=/root/lib/lib/libavif.a \ + -DAVIF_INCLUDE_DIR=/root/lib/include \ + -Dlibavif_DIR=/root/lib/lib/cmake/libavif \ + -DBUILD_STATIC_LIBS=ON \ + -DBUILD_SHARED_LIBS=OFF \ + -DBUILD_TEST=OFF \ + -DBUILD_PROGRAMS=OFF \ + -DENABLE_CPP=OFF \ + -DENABLE_GD_FORMATS=ON \ + -DENABLE_PNG=ON \ + -DENABLE_JPEG=ON \ + -DENABLE_WEBP=ON \ + -DENABLE_AVIF=ON \ + -DENABLE_LIQ=OFF \ + -DENABLE_TIFF=OFF \ + -DENABLE_ICONV=OFF \ + -DENABLE_XPM=OFF \ + -DENABLE_FREETYPE=OFF \ + -DENABLE_FONTCONFIG=OFF \ + -DENABLE_HEIF=OFF \ + -DENABLE_RAQM=OFF + +# Build as side module, skipping all dependency libraries (they'll be linked with PHP later) +RUN source /root/emsdk/emsdk_env.sh && \ + export JSPI_FLAGS=$(if [ "$JSPI" = "1" ]; then echo "-sSUPPORT_LONGJMP=wasm -fwasm-exceptions"; else echo ""; fi) && \ + EMCC_SKIP="-lc -lz -lpng -lpng16 -ljpeg -lwebp -lavif -liconv" \ + EMCC_FLAGS=" -D__x86_64__ -sSIDE_MODULE $JSPI_FLAGS" \ + emmake make gd_static -j"$(nproc)" + +# Manually stage the static lib and headers (skip installing programs) +RUN set -euxo pipefail && \ + mkdir -p /root/install/lib /root/install/include /root/install/lib/pkgconfig /root/install/bin && \ + LIBFILE=$(find /root/libgd-2.3.3 -maxdepth 4 -name "libgd*.a" | head -n1) && \ + if [ -z "$LIBFILE" ]; then echo "libgd static archive not found"; exit 1; fi && \ + cp "$LIBFILE" /root/install/lib/libgd.a && \ + (cp /root/libgd-2.3.3/src/gd_config.h /root/install/include/ || true) && \ + (cp /root/libgd-2.3.3/gd_config.h /root/install/include/ || true) && \ + cp /root/libgd-2.3.3/src/*.h /root/install/include/ && \ + (cp /root/libgd-2.3.3/gd.h /root/install/include/ || true) && \ + (cp /root/libgd-2.3.3/gd_errors.h /root/install/include/ || true) + +RUN cat > /root/install/lib/pkgconfig/gdlib.pc <<'EOF' +prefix=/root/lib +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: gdlib +Description: GD graphics library +Version: 2.3.3 +Requires.private: libpng libjpeg libwebp libavif zlib +Libs: -L${libdir} -lgd -lpng16 -lz -ljpeg -lwebp -lsharpyuv -lavif +Cflags: -I${includedir} +EOF + +RUN cat > /root/install/bin/gdlib-config <<'EOF' +#!/bin/sh +case "$1" in + --version) echo 2.3.3 ;; + --features) echo "PNG JPEG WEBP AVIF GIF XBM WBMP FREETYPE" ;; + --libs) echo "-L/root/lib/lib -lgd -lpng16 -lz -ljpeg -lwebp -lsharpyuv -lavif" ;; + --cflags|--includes) echo "-I/root/lib/include" ;; + --libdir) echo "/root/lib/lib" ;; + --includedir) echo "/root/lib/include" ;; + *) echo "--version --features --libs --cflags --includedir --libdir" ;; +esac +EOF + +RUN chmod +x /root/install/bin/gdlib-config + +RUN rm -rf /root/libgd-$GD_VERSION libgd.tar.gz diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/bin/gdlib-config b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/bin/gdlib-config new file mode 100755 index 0000000000..86978d7d0a --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/bin/gdlib-config @@ -0,0 +1,10 @@ +#!/bin/sh +case "$1" in + --version) echo 2.3.3 ;; + --features) echo "PNG JPEG WEBP AVIF GIF XBM WBMP FREETYPE" ;; + --libs) echo "-L/root/lib/lib -lgd -lpng16 -lz -ljpeg -lwebp -lsharpyuv -lavif" ;; + --cflags|--includes) echo "-I/root/lib/include" ;; + --libdir) echo "/root/lib/lib" ;; + --includedir) echo "/root/lib/include" ;; + *) echo "--version --features --libs --cflags --includedir --libdir" ;; +esac diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/.gitkeep b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/.gitkeep new file mode 100644 index 0000000000..48cdce8528 --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/.gitkeep @@ -0,0 +1 @@ +placeholder diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/bmp.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/bmp.h new file mode 100644 index 0000000000..5644fab982 --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/bmp.h @@ -0,0 +1,111 @@ +#ifndef BMP_H +#define BMP_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + + /* + gd_bmp.c + + Bitmap format support for libgd + + * Written 2007, Scott MacVicar + --------------------------------------------------------------------------- + + Todo: + + RLE4, RLE8 and Bitfield encoding + Add full support for Windows v4 and Windows v5 header formats + + ---------------------------------------------------------------------------- + */ + +#define BMP_PALETTE_3 1 +#define BMP_PALETTE_4 2 + +#define BMP_WINDOWS_V3 40 +#define BMP_OS2_V1 12 +#define BMP_OS2_V2 64 +#define BMP_WINDOWS_V4 108 +#define BMP_WINDOWS_V5 124 + +#define BMP_BI_RGB 0 +#define BMP_BI_RLE8 1 +#define BMP_BI_RLE4 2 +#define BMP_BI_BITFIELDS 3 +#define BMP_BI_JPEG 4 +#define BMP_BI_PNG 5 + +#define BMP_RLE_COMMAND 0 +#define BMP_RLE_ENDOFLINE 0 +#define BMP_RLE_ENDOFBITMAP 1 +#define BMP_RLE_DELTA 2 + +#define BMP_RLE_TYPE_RAW 0 +#define BMP_RLE_TYPE_RLE 1 + + /* BMP header. */ + typedef struct { + /* 16 bit - header identifying the type */ + signed short int magic; + + /* 32bit - size of the file */ + int size; + + /* 16bit - these two are in the spec but "reserved" */ + signed short int reserved1; + signed short int reserved2; + + /* 32 bit - offset of the bitmap header from data in bytes */ + signed int off; + + } bmp_hdr_t; + + /* BMP info. */ + typedef struct { + /* 16bit - Type, ie Windows or OS/2 for the palette info */ + signed short int type; + /* 32bit - The length of the bitmap information header in bytes. */ + signed int len; + + /* 32bit - The width of the bitmap in pixels. */ + signed int width; + + /* 32bit - The height of the bitmap in pixels. */ + signed int height; + + /* 8 bit - The bitmap data is specified in top-down order. */ + signed char topdown; + + /* 16 bit - The number of planes. This must be set to a value of one. */ + signed short int numplanes; + + /* 16 bit - The number of bits per pixel. */ + signed short int depth; + + /* 32bit - The type of compression used. */ + signed int enctype; + + /* 32bit - The size of the image in bytes. */ + signed int size; + + /* 32bit - The horizontal resolution in pixels/metre. */ + signed int hres; + + /* 32bit - The vertical resolution in pixels/metre. */ + signed int vres; + + /* 32bit - The number of color indices used by the bitmap. */ + signed int numcolors; + + /* 32bit - The number of color indices important for displaying the bitmap. */ + signed int mincolors; + + } bmp_info_t; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/config.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/config.h new file mode 100644 index 0000000000..cd143c72c0 --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/config.h @@ -0,0 +1,141 @@ +/* Generated from config.hin via autoheader for cmake; see bootstrap.sh. */ + +/* Define is you are building for Win32 API */ +/* #undef BGDWIN32 */ + +/* Whether to support gd image formats */ +#define ENABLE_GD_FORMATS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DIRENT_H + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DLFCN_H */ + +/* Define if you have the ft2build.h header. */ +/* #undef HAVE_FT2BUILD_H */ + +/* Define if you have the iconv() function and it works. */ +/* #undef HAVE_ICONV */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ICONV_H */ + +/* Define if defines iconv_t. */ +/* #undef HAVE_ICONV_T_DEF */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H + +/* Define if you have avif */ +#define HAVE_LIBAVIF + +/* Define if you have fontconfig */ +/* #undef HAVE_LIBFONTCONFIG */ + +/* Define if you have freetype */ +/* #undef HAVE_LIBFREETYPE */ + +/* Define if you have heif */ +/* #undef HAVE_LIBHEIF */ + +/* Define if you have liq */ +/* #undef HAVE_LIBIMAGEQUANT */ + +/* Define if you have jpeg */ +#define HAVE_LIBJPEG + +/* Define to 1 if you have the `m' library (-lm). */ +#define HAVE_LIBM + +/* Define if you have png */ +#define HAVE_LIBPNG + +/* Define if you have raqm */ +/* #undef HAVE_LIBRAQM */ + +/* Define if you have tiff */ +/* #undef HAVE_LIBTIFF */ + +/* Define if you have webp */ +#define HAVE_LIBWEBP + +/* Define if you have xpm */ +/* #undef HAVE_LIBXPM */ + +/* Define if you have zlib */ +#define HAVE_LIBZ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MEMORY_H */ + +/* Define if OpenMP is enabled */ +/* #undef HAVE_OPENMP */ + +/* Define if you have POSIX threads libraries and header files. */ +/* #undef HAVE_PTHREAD */ + +/* Have PTHREAD_PRIO_INHERIT. */ +/* #undef HAVE_PTHREAD_PRIO_INHERIT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STDLIB_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STRING_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H + +/* Define to 1 or 0, depending whether the compiler supports simple visibility + declarations. */ +/* #undef HAVE_VISIBILITY */ + +/* Define as const if the declaration of iconv() needs const. */ +/* #undef ICONV_CONST */ + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +/* #undef LT_OBJDIR */ + +/* Name of package */ +#define PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +/* #undef PACKAGE_BUGREPORT */ + +/* Define to the full name of this package. */ +#define PACKAGE_NAME + +/* Define to the full name and version of this package. */ +/* #undef PACKAGE_STRING */ + +/* Define to the one symbol short name of this package. */ +/* #undef PACKAGE_TARNAME */ + +/* Define to the home page for this package. */ +/* #undef PACKAGE_URL */ + +/* Define to the version of this package. */ +#define PACKAGE_VERSION + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +/* #undef PTHREAD_CREATE_JOINABLE */ + +/* Define to 1 if you have the ANSI C header files. */ +/* #undef STDC_HEADERS */ + +/* Version number of package */ +/* #undef VERSION */ diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/entities.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/entities.h new file mode 100644 index 0000000000..cf24cb63e3 --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/entities.h @@ -0,0 +1,277 @@ +/* + * Generated file - do not edit directly. + * + * This file was generated from: + * http://www.w3.org/TR/REC-html40/sgml/entities.html + * by means of the script: + * entities.tcl + */ + +#ifdef __cplusplus +extern "C" { +#endif + + static struct entities_s { + char *name; + int value; + } entities[] = { + {"AElig", 198}, + {"Aacute", 193}, + {"Acirc", 194}, + {"Agrave", 192}, + {"Alpha", 913}, + {"Aring", 197}, + {"Atilde", 195}, + {"Auml", 196}, + {"Beta", 914}, + {"Ccedil", 199}, + {"Chi", 935}, + {"Dagger", 8225}, + {"Delta", 916}, + {"ETH", 208}, + {"Eacute", 201}, + {"Ecirc", 202}, + {"Egrave", 200}, + {"Epsilon", 917}, + {"Eta", 919}, + {"Euml", 203}, + {"Gamma", 915}, + {"Iacute", 205}, + {"Icirc", 206}, + {"Igrave", 204}, + {"Iota", 921}, + {"Iuml", 207}, + {"Kappa", 922}, + {"Lambda", 923}, + {"Mu", 924}, + {"Ntilde", 209}, + {"Nu", 925}, + {"OElig", 338}, + {"Oacute", 211}, + {"Ocirc", 212}, + {"Ograve", 210}, + {"Omega", 937}, + {"Omicron", 927}, + {"Oslash", 216}, + {"Otilde", 213}, + {"Ouml", 214}, + {"Phi", 934}, + {"Pi", 928}, + {"Prime", 8243}, + {"Psi", 936}, + {"Rho", 929}, + {"Scaron", 352}, + {"Sigma", 931}, + {"THORN", 222}, + {"Tau", 932}, + {"Theta", 920}, + {"Uacute", 218}, + {"Ucirc", 219}, + {"Ugrave", 217}, + {"Upsilon", 933}, + {"Uuml", 220}, + {"Xi", 926}, + {"Yacute", 221}, + {"Yuml", 376}, + {"Zeta", 918}, + {"aacute", 225}, + {"acirc", 226}, + {"acute", 180}, + {"aelig", 230}, + {"agrave", 224}, + {"alefsym", 8501}, + {"alpha", 945}, + {"amp", 38}, + {"and", 8743}, + {"ang", 8736}, + {"aring", 229}, + {"asymp", 8776}, + {"atilde", 227}, + {"auml", 228}, + {"bdquo", 8222}, + {"beta", 946}, + {"brvbar", 166}, + {"bull", 8226}, + {"cap", 8745}, + {"ccedil", 231}, + {"cedil", 184}, + {"cent", 162}, + {"chi", 967}, + {"circ", 710}, + {"clubs", 9827}, + {"cong", 8773}, + {"copy", 169}, + {"crarr", 8629}, + {"cup", 8746}, + {"curren", 164}, + {"dArr", 8659}, + {"dagger", 8224}, + {"darr", 8595}, + {"deg", 176}, + {"delta", 948}, + {"diams", 9830}, + {"divide", 247}, + {"eacute", 233}, + {"ecirc", 234}, + {"egrave", 232}, + {"empty", 8709}, + {"emsp", 8195}, + {"ensp", 8194}, + {"epsilon", 949}, + {"equiv", 8801}, + {"eta", 951}, + {"eth", 240}, + {"euml", 235}, + {"euro", 8364}, + {"exist", 8707}, + {"fnof", 402}, + {"forall", 8704}, + {"frac12", 189}, + {"frac14", 188}, + {"frac34", 190}, + {"frasl", 8260}, + {"gamma", 947}, + {"ge", 8805}, + {"gt", 62}, + {"hArr", 8660}, + {"harr", 8596}, + {"hearts", 9829}, + {"hellip", 8230}, + {"iacute", 237}, + {"icirc", 238}, + {"iexcl", 161}, + {"igrave", 236}, + {"image", 8465}, + {"infin", 8734}, + {"int", 8747}, + {"iota", 953}, + {"iquest", 191}, + {"isin", 8712}, + {"iuml", 239}, + {"kappa", 954}, + {"lArr", 8656}, + {"lambda", 955}, + {"lang", 9001}, + {"laquo", 171}, + {"larr", 8592}, + {"lceil", 8968}, + {"ldquo", 8220}, + {"le", 8804}, + {"lfloor", 8970}, + {"lowast", 8727}, + {"loz", 9674}, + {"lrm", 8206}, + {"lsaquo", 8249}, + {"lsquo", 8216}, + {"lt", 60}, + {"macr", 175}, + {"mdash", 8212}, + {"micro", 181}, + {"middot", 183}, + {"minus", 8722}, + {"mu", 956}, + {"nabla", 8711}, + {"nbsp", 160}, + {"ndash", 8211}, + {"ne", 8800}, + {"ni", 8715}, + {"not", 172}, + {"notin", 8713}, + {"nsub", 8836}, + {"ntilde", 241}, + {"nu", 957}, + {"oacute", 243}, + {"ocirc", 244}, + {"oelig", 339}, + {"ograve", 242}, + {"oline", 8254}, + {"omega", 969}, + {"omicron", 959}, + {"oplus", 8853}, + {"or", 8744}, + {"ordf", 170}, + {"ordm", 186}, + {"oslash", 248}, + {"otilde", 245}, + {"otimes", 8855}, + {"ouml", 246}, + {"para", 182}, + {"part", 8706}, + {"permil", 8240}, + {"perp", 8869}, + {"phi", 966}, + {"pi", 960}, + {"piv", 982}, + {"plusmn", 177}, + {"pound", 163}, + {"prime", 8242}, + {"prod", 8719}, + {"prop", 8733}, + {"psi", 968}, + {"quot", 34}, + {"rArr", 8658}, + {"radic", 8730}, + {"rang", 9002}, + {"raquo", 187}, + {"rarr", 8594}, + {"rceil", 8969}, + {"rdquo", 8221}, + {"real", 8476}, + {"reg", 174}, + {"rfloor", 8971}, + {"rho", 961}, + {"rlm", 8207}, + {"rsaquo", 8250}, + {"rsquo", 8217}, + {"sbquo", 8218}, + {"scaron", 353}, + {"sdot", 8901}, + {"sect", 167}, + {"shy", 173}, + {"sigma", 963}, + {"sigmaf", 962}, + {"sim", 8764}, + {"spades", 9824}, + {"sub", 8834}, + {"sube", 8838}, + {"sum", 8721}, + {"sup", 8835}, + {"sup1", 185}, + {"sup2", 178}, + {"sup3", 179}, + {"supe", 8839}, + {"szlig", 223}, + {"tau", 964}, + {"there4", 8756}, + {"theta", 952}, + {"thetasym", 977}, + {"thinsp", 8201}, + {"thorn", 254}, + {"tilde", 732}, + {"times", 215}, + {"trade", 8482}, + {"uArr", 8657}, + {"uacute", 250}, + {"uarr", 8593}, + {"ucirc", 251}, + {"ugrave", 249}, + {"uml", 168}, + {"upsih", 978}, + {"upsilon", 965}, + {"uuml", 252}, + {"weierp", 8472}, + {"xi", 958}, + {"yacute", 253}, + {"yen", 165}, + {"yuml", 255}, + {"zeta", 950}, + {"zwj", 8205}, + {"zwnj", 8204}, + }; + +#define ENTITY_NAME_LENGTH_MAX 8 +#define NR_OF_ENTITIES 252 + +#ifdef __cplusplus +} +#endif diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd.h new file mode 100644 index 0000000000..3056039529 --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd.h @@ -0,0 +1,1716 @@ +#ifndef GD_H +#define GD_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Version information. This gets parsed by build scripts as well as + * gcc so each #define line in this group must also be splittable on + * whitespace, take the form GD_*_VERSION and contain the magical + * trailing comment. */ +#define GD_MAJOR_VERSION 2 /*version605b5d1778*/ +#define GD_MINOR_VERSION 3 /*version605b5d1778*/ +#define GD_RELEASE_VERSION 3 /*version605b5d1778*/ +#define GD_EXTRA_VERSION "" /*version605b5d1778*/ +/* End parsable section. */ + +/* The version string. This is constructed from the version number + * parts above via macro abuse^Wtrickery. */ +#define GDXXX_VERSION_STR(mjr, mnr, rev, ext) mjr "." mnr "." rev ext +#define GDXXX_STR(s) GDXXX_SSTR(s) /* Two levels needed to expand args. */ +#define GDXXX_SSTR(s) #s + +#define GD_VERSION_STRING \ + GDXXX_VERSION_STR(GDXXX_STR(GD_MAJOR_VERSION), \ + GDXXX_STR(GD_MINOR_VERSION), \ + GDXXX_STR(GD_RELEASE_VERSION), \ + GD_EXTRA_VERSION) + + +/* Do the DLL dance: dllexport when building the DLL, + dllimport when importing from it, nothing when + not on Silly Silly Windows (tm Aardman Productions). */ + +/* 2.0.20: for headers */ + +/* 2.0.24: __stdcall also needed for Visual BASIC + and other languages. This breaks ABI compatibility + with previous DLL revs, but it's necessary. */ + +/* 2.0.29: WIN32 programmers can declare the NONDLL macro if they + wish to build gd as a static library or by directly including + the gd sources in a project. */ + +/* http://gcc.gnu.org/wiki/Visibility */ +#if defined(_WIN32) || defined(CYGWIN) || defined(_WIN32_WCE) +# ifdef BGDWIN32 +# ifdef NONDLL +# define BGD_EXPORT_DATA_PROT +# else +# ifdef __GNUC__ +# define BGD_EXPORT_DATA_PROT __attribute__ ((__dllexport__)) +# else +# define BGD_EXPORT_DATA_PROT __declspec(dllexport) +# endif +# endif +# else +# ifdef __GNUC__ +# define BGD_EXPORT_DATA_PROT __attribute__ ((__dllimport__)) +# else +# define BGD_EXPORT_DATA_PROT __declspec(dllimport) +# endif +# endif +# define BGD_STDCALL __stdcall +# define BGD_EXPORT_DATA_IMPL +# define BGD_MALLOC +#else +# if defined(__GNUC__) || defined(__clang__) +# define BGD_EXPORT_DATA_PROT __attribute__ ((__visibility__ ("default"))) +# define BGD_EXPORT_DATA_IMPL __attribute__ ((__visibility__ ("hidden"))) +# else +# define BGD_EXPORT_DATA_PROT +# define BGD_EXPORT_DATA_IMPL +# endif +# define BGD_STDCALL +# define BGD_MALLOC __attribute__ ((__malloc__)) +#endif + +#define BGD_DECLARE(rt) BGD_EXPORT_DATA_PROT rt BGD_STDCALL + +/* VS2012+ disable keyword macroizing unless _ALLOW_KEYWORD_MACROS is set + We define inline, and strcasecmp if they're missing +*/ +#ifdef _MSC_VER +# define _ALLOW_KEYWORD_MACROS +# ifndef inline +# define inline __inline +# endif +# ifndef strcasecmp +# define strcasecmp _stricmp +# endif +#endif + +#undef ARG_NOT_USED +#define ARG_NOT_USED(arg) (void) arg + +/* gd.h: declarations file for the graphic-draw module. + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "AS IS." Thomas Boutell and + * Boutell.Com, Inc. disclaim all warranties, either express or implied, + * including but not limited to implied warranties of merchantability and + * fitness for a particular purpose, with respect to this code and accompanying + * documentation. */ + +/* stdio is needed for file I/O. */ +#include +#include +#include "gd_io.h" + +/* The maximum number of palette entries in palette-based images. + In the wonderful new world of gd 2.0, you can of course have + many more colors when using truecolor mode. */ + +#define gdMaxColors 256 + +/* Image type. See functions below; you will not need to change + the elements directly. Use the provided macros to + access sx, sy, the color table, and colorsTotal for + read-only purposes. */ + +/* If 'truecolor' is set true, the image is truecolor; + pixels are represented by integers, which + must be 32 bits wide or more. + + True colors are repsented as follows: + + ARGB + + Where 'A' (alpha channel) occupies only the + LOWER 7 BITS of the MSB. This very small + loss of alpha channel resolution allows gd 2.x + to keep backwards compatibility by allowing + signed integers to be used to represent colors, + and negative numbers to represent special cases, + just as in gd 1.x. */ + +#define gdAlphaMax 127 +#define gdAlphaOpaque 0 +#define gdAlphaTransparent 127 +#define gdRedMax 255 +#define gdGreenMax 255 +#define gdBlueMax 255 + +/** + * Group: Color Decomposition + */ + +/** + * Macro: gdTrueColorGetAlpha + * + * Gets the alpha channel value + * + * Parameters: + * c - The color + * + * See also: + * - + */ +#define gdTrueColorGetAlpha(c) (((c) & 0x7F000000) >> 24) + +/** + * Macro: gdTrueColorGetRed + * + * Gets the red channel value + * + * Parameters: + * c - The color + * + * See also: + * - + */ +#define gdTrueColorGetRed(c) (((c) & 0xFF0000) >> 16) + +/** + * Macro: gdTrueColorGetGreen + * + * Gets the green channel value + * + * Parameters: + * c - The color + * + * See also: + * - + */ +#define gdTrueColorGetGreen(c) (((c) & 0x00FF00) >> 8) + +/** + * Macro: gdTrueColorGetBlue + * + * Gets the blue channel value + * + * Parameters: + * c - The color + * + * See also: + * - + */ +#define gdTrueColorGetBlue(c) ((c) & 0x0000FF) + +/** + * Group: Effects + * + * The layering effect + * + * When pixels are drawn the new colors are "mixed" with the background + * depending on the effect. + * + * Note that the effect does not apply to palette images, where pixels + * are always replaced. + * + * Modes: + * gdEffectReplace - replace pixels + * gdEffectAlphaBlend - blend pixels, see + * gdEffectNormal - default mode; same as gdEffectAlphaBlend + * gdEffectOverlay - overlay pixels, see + * gdEffectMultiply - overlay pixels with multiply effect, see + * + * + * See also: + * - + */ +#define gdEffectReplace 0 +#define gdEffectAlphaBlend 1 +#define gdEffectNormal 2 +#define gdEffectOverlay 3 +#define gdEffectMultiply 4 + +#define GD_TRUE 1 +#define GD_FALSE 0 + +#define GD_EPSILON 1e-6 +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +/* This function accepts truecolor pixel values only. The + source color is composited with the destination color + based on the alpha channel value of the source color. + The resulting color is opaque. */ + +BGD_DECLARE(int) gdAlphaBlend (int dest, int src); +BGD_DECLARE(int) gdLayerOverlay (int dest, int src); +BGD_DECLARE(int) gdLayerMultiply (int dest, int src); + + +/** + * Group: Color Quantization + * + * Enum: gdPaletteQuantizationMethod + * + * Constants: + * GD_QUANT_DEFAULT - GD_QUANT_LIQ if libimagequant is available, + * GD_QUANT_JQUANT otherwise. + * GD_QUANT_JQUANT - libjpeg's old median cut. Fast, but only uses 16-bit + * color. + * GD_QUANT_NEUQUANT - NeuQuant - approximation using Kohonen neural network. + * GD_QUANT_LIQ - A combination of algorithms used in libimagequant + * aiming for the highest quality at cost of speed. + * + * Note that GD_QUANT_JQUANT does not retain the alpha channel, and + * GD_QUANT_NEUQUANT does not support dithering. + * + * See also: + * - + */ +enum gdPaletteQuantizationMethod { + GD_QUANT_DEFAULT = 0, + GD_QUANT_JQUANT = 1, + GD_QUANT_NEUQUANT = 2, + GD_QUANT_LIQ = 3 +}; + +/** + * Group: Transform + * + * Constants: gdInterpolationMethod + * + * GD_BELL - Bell + * GD_BESSEL - Bessel + * GD_BILINEAR_FIXED - fixed point bilinear + * GD_BICUBIC - Bicubic + * GD_BICUBIC_FIXED - fixed point bicubic integer + * GD_BLACKMAN - Blackman + * GD_BOX - Box + * GD_BSPLINE - BSpline + * GD_CATMULLROM - Catmullrom + * GD_GAUSSIAN - Gaussian + * GD_GENERALIZED_CUBIC - Generalized cubic + * GD_HERMITE - Hermite + * GD_HAMMING - Hamming + * GD_HANNING - Hannig + * GD_MITCHELL - Mitchell + * GD_NEAREST_NEIGHBOUR - Nearest neighbour interpolation + * GD_POWER - Power + * GD_QUADRATIC - Quadratic + * GD_SINC - Sinc + * GD_TRIANGLE - Triangle + * GD_WEIGHTED4 - 4 pixels weighted bilinear interpolation + * GD_LINEAR - bilinear interpolation + * + * See also: + * - + * - + */ +typedef enum { + GD_DEFAULT = 0, + GD_BELL, + GD_BESSEL, + GD_BILINEAR_FIXED, + GD_BICUBIC, + GD_BICUBIC_FIXED, + GD_BLACKMAN, + GD_BOX, + GD_BSPLINE, + GD_CATMULLROM, + GD_GAUSSIAN, + GD_GENERALIZED_CUBIC, + GD_HERMITE, + GD_HAMMING, + GD_HANNING, + GD_MITCHELL, + GD_NEAREST_NEIGHBOUR, + GD_POWER, + GD_QUADRATIC, + GD_SINC, + GD_TRIANGLE, + GD_WEIGHTED4, + GD_LINEAR, + GD_LANCZOS3, + GD_LANCZOS8, + GD_BLACKMAN_BESSEL, + GD_BLACKMAN_SINC, + GD_QUADRATIC_BSPLINE, + GD_CUBIC_SPLINE, + GD_COSINE, + GD_WELSH, + GD_METHOD_COUNT = 30 +} gdInterpolationMethod; + +/** + * Group: HEIF Coding Format + * + * Values that select the HEIF coding format. + * + * Constants: gdHeifCodec + * + * GD_HEIF_CODEC_UNKNOWN + * GD_HEIF_CODEC_HEVC + * GD_HEIF_CODEC_AV1 + * + * See also: + * - + */ +typedef enum { + GD_HEIF_CODEC_UNKNOWN = 0, + GD_HEIF_CODEC_HEVC, + GD_HEIF_CODEC_AV1 = 4, +} gdHeifCodec; + +/** + * Group: HEIF Chroma Subsampling + * + * Values that select the HEIF chroma subsampling. + * + * Constants: gdHeifCompression + * + * GD_HEIF_CHROMA_420 + * GD_HEIF_CHROMA_422 + * GD_HEIF_CHROMA_444 + * + * See also: + * - + */ +typedef const char *gdHeifChroma; + +#define GD_HEIF_CHROMA_420 "420" +#define GD_HEIF_CHROMA_422 "422" +#define GD_HEIF_CHROMA_444 "444" + +/* define struct with name and func ptr and add it to gdImageStruct gdInterpolationMethod interpolation; */ + +/* Interpolation function ptr */ +typedef double (* interpolation_method )(double, double); + + +/* + Group: Types + + typedef: gdImage + + typedef: gdImagePtr + + The data structure in which gd stores images. , + and the various image file-loading functions + return a pointer to this type, and the other functions expect to + receive a pointer to this type as their first argument. + + *gdImagePtr* is a pointer to *gdImage*. + + See also: + + + (Previous versions of this library encouraged directly manipulating + the contents ofthe struct but we are attempting to move away from + this practice so the fields are no longer documented here. If you + need to poke at the internals of this struct, feel free to look at + *gd.h*.) +*/ +typedef struct gdImageStruct { + /* Palette-based image pixels */ + unsigned char **pixels; + int sx; + int sy; + /* These are valid in palette images only. See also + 'alpha', which appears later in the structure to + preserve binary backwards compatibility */ + int colorsTotal; + int red[gdMaxColors]; + int green[gdMaxColors]; + int blue[gdMaxColors]; + int open[gdMaxColors]; + /* For backwards compatibility, this is set to the + first palette entry with 100% transparency, + and is also set and reset by the + gdImageColorTransparent function. Newer + applications can allocate palette entries + with any desired level of transparency; however, + bear in mind that many viewers, notably + many web browsers, fail to implement + full alpha channel for PNG and provide + support for full opacity or transparency only. */ + int transparent; + int *polyInts; + int polyAllocated; + struct gdImageStruct *brush; + struct gdImageStruct *tile; + int brushColorMap[gdMaxColors]; + int tileColorMap[gdMaxColors]; + int styleLength; + int stylePos; + int *style; + int interlace; + /* New in 2.0: thickness of line. Initialized to 1. */ + int thick; + /* New in 2.0: alpha channel for palettes. Note that only + Macintosh Internet Explorer and (possibly) Netscape 6 + really support multiple levels of transparency in + palettes, to my knowledge, as of 2/15/01. Most + common browsers will display 100% opaque and + 100% transparent correctly, and do something + unpredictable and/or undesirable for levels + in between. TBB */ + int alpha[gdMaxColors]; + /* Truecolor flag and pixels. New 2.0 fields appear here at the + end to minimize breakage of existing object code. */ + int trueColor; + int **tpixels; + /* Should alpha channel be copied, or applied, each time a + pixel is drawn? This applies to truecolor images only. + No attempt is made to alpha-blend in palette images, + even if semitransparent palette entries exist. + To do that, build your image as a truecolor image, + then quantize down to 8 bits. */ + int alphaBlendingFlag; + /* Should the alpha channel of the image be saved? This affects + PNG at the moment; other future formats may also + have that capability. JPEG doesn't. */ + int saveAlphaFlag; + + /* There should NEVER BE ACCESSOR MACROS FOR ITEMS BELOW HERE, so this + part of the structure can be safely changed in new releases. */ + + /* 2.0.12: anti-aliased globals. 2.0.26: just a few vestiges after + switching to the fast, memory-cheap implementation from PHP-gd. */ + int AA; + int AA_color; + int AA_dont_blend; + + /* 2.0.12: simple clipping rectangle. These values + must be checked for safety when set; please use + gdImageSetClip */ + int cx1; + int cy1; + int cx2; + int cy2; + + /* 2.1.0: allows to specify resolution in dpi */ + unsigned int res_x; + unsigned int res_y; + + /* Selects quantization method, see gdImageTrueColorToPaletteSetMethod() and gdPaletteQuantizationMethod enum. */ + int paletteQuantizationMethod; + /* speed/quality trade-off. 1 = best quality, 10 = best speed. 0 = method-specific default. + Applicable to GD_QUANT_LIQ and GD_QUANT_NEUQUANT. */ + int paletteQuantizationSpeed; + /* Image will remain true-color if conversion to palette cannot achieve given quality. + Value from 1 to 100, 1 = ugly, 100 = perfect. Applicable to GD_QUANT_LIQ.*/ + int paletteQuantizationMinQuality; + /* Image will use minimum number of palette colors needed to achieve given quality. Must be higher than paletteQuantizationMinQuality + Value from 1 to 100, 1 = ugly, 100 = perfect. Applicable to GD_QUANT_LIQ.*/ + int paletteQuantizationMaxQuality; + gdInterpolationMethod interpolation_id; + interpolation_method interpolation; +} +gdImage; + +typedef gdImage *gdImagePtr; + + +/* Point type for use in polygon drawing. */ + +/** + * Group: Types + * + * typedef: gdPointF + * Defines a point in a 2D coordinate system using floating point + * values. + * x - Floating point position (increase from left to right) + * y - Floating point Row position (increase from top to bottom) + * + * typedef: gdPointFPtr + * Pointer to a + * + * See also: + * , , + **/ +typedef struct +{ + double x, y; +} +gdPointF, *gdPointFPtr; + + +/* + Group: Types + + typedef: gdFont + + typedef: gdFontPtr + + A font structure, containing the bitmaps of all characters in a + font. Used to declare the characteristics of a font. Text-output + functions expect these as their second argument, following the + argument. and both + return one. + + You can provide your own font data by providing such a structure and + the associated pixel array. You can determine the width and height + of a single character in a font by examining the w and h members of + the structure. If you will not be creating your own fonts, you will + not need to concern yourself with the rest of the components of this + structure. + + Please see the files gdfontl.c and gdfontl.h for an example of + the proper declaration of this structure. + + > typedef struct { + > // # of characters in font + > int nchars; + > // First character is numbered... (usually 32 = space) + > int offset; + > // Character width and height + > int w; + > int h; + > // Font data; array of characters, one row after another. + > // Easily included in code, also easily loaded from + > // data files. + > char *data; + > } gdFont; + + gdFontPtr is a pointer to gdFont. + +*/ +typedef struct { + /* # of characters in font */ + int nchars; + /* First character is numbered... (usually 32 = space) */ + int offset; + /* Character width and height */ + int w; + int h; + /* Font data; array of characters, one row after another. + Easily included in code, also easily loaded from + data files. */ + char *data; +} +gdFont; + +/* Text functions take these. */ +typedef gdFont *gdFontPtr; + +typedef void(*gdErrorMethod)(int, const char *, va_list); + +BGD_DECLARE(void) gdSetErrorMethod(gdErrorMethod); +BGD_DECLARE(void) gdClearErrorMethod(void); + +/* For backwards compatibility only. Use gdImageSetStyle() + for MUCH more flexible line drawing. Also see + gdImageSetBrush(). */ +#define gdDashSize 4 + +/** + * Group: Colors + * + * Colors are always of type int which is supposed to be at least 32 bit large. + * + * Kinds of colors: + * true colors - ARGB values where the alpha channel is stored as most + * significant, and the blue channel as least significant + * byte. Note that the alpha channel only uses the 7 least + * significant bits. + * Don't rely on the internal representation, though, and + * use to compose a truecolor value, and + * , , + * and to access + * the respective channels. + * palette indexes - The index of a color palette entry (0-255). + * special colors - As listed in the following section. + * + * Constants: Special Colors + * gdStyled - use the current style, see + * gdBrushed - use the current brush, see + * gdStyledBrushed - use the current style and brush + * gdTiled - use the current tile, see + * gdTransparent - indicate transparency, what is not the same as the + * transparent color index; used for lines only + * gdAntiAliased - draw anti aliased + */ + +#define gdStyled (-2) +#define gdBrushed (-3) +#define gdStyledBrushed (-4) +#define gdTiled (-5) +#define gdTransparent (-6) +#define gdAntiAliased (-7) + +/* Functions to manipulate images. */ + +/* Creates a palette-based image (up to 256 colors). */ +BGD_DECLARE(gdImagePtr) gdImageCreate (int sx, int sy); + +/* An alternate name for the above (2.0). */ +#define gdImageCreatePalette gdImageCreate + +/* Creates a truecolor image (millions of colors). */ +BGD_DECLARE(gdImagePtr) gdImageCreateTrueColor (int sx, int sy); + +/* Creates an image from various file types. These functions + return a palette or truecolor image based on the + nature of the file being loaded. Truecolor PNG + stays truecolor; palette PNG stays palette-based; + JPEG is always truecolor. */ +BGD_DECLARE(gdImagePtr) gdImageCreateFromPng (FILE * fd); +BGD_DECLARE(gdImagePtr) gdImageCreateFromPngCtx(gdIOCtxPtr in); +BGD_DECLARE(gdImagePtr) gdImageCreateFromPngPtr (int size, void *data); + +/* These read the first frame only */ +BGD_DECLARE(gdImagePtr) gdImageCreateFromGif (FILE * fd); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGifCtx(gdIOCtxPtr in); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGifPtr (int size, void *data); +BGD_DECLARE(gdImagePtr) gdImageCreateFromWBMP (FILE * inFile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromWBMPCtx(gdIOCtxPtr infile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromWBMPPtr (int size, void *data); +BGD_DECLARE(gdImagePtr) gdImageCreateFromJpeg (FILE * infile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegEx (FILE * infile, int ignore_warning); +BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegCtx(gdIOCtxPtr infile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegCtxEx(gdIOCtxPtr infile, int ignore_warning); +BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegPtr (int size, void *data); +BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegPtrEx (int size, void *data, int ignore_warning); +BGD_DECLARE(gdImagePtr) gdImageCreateFromWebp (FILE * inFile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromWebpPtr (int size, void *data); +BGD_DECLARE(gdImagePtr) gdImageCreateFromWebpCtx(gdIOCtxPtr infile); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromHeif(FILE *inFile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromHeifPtr(int size, void *data); +BGD_DECLARE(gdImagePtr) gdImageCreateFromHeifCtx(gdIOCtxPtr infile); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromAvif(FILE *inFile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromAvifPtr(int size, void *data); +BGD_DECLARE(gdImagePtr) gdImageCreateFromAvifCtx(gdIOCtxPtr infile); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromTiff(FILE *inFile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromTiffCtx(gdIOCtxPtr infile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromTiffPtr(int size, void *data); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromTga( FILE * fp ); +BGD_DECLARE(gdImagePtr) gdImageCreateFromTgaCtx(gdIOCtxPtr ctx); +BGD_DECLARE(gdImagePtr) gdImageCreateFromTgaPtr(int size, void *data); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromBmp (FILE * inFile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpPtr (int size, void *data); +BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpCtx(gdIOCtxPtr infile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromFile(const char *filename); + + +/* + Group: Types + + typedef: gdSource + + typedef: gdSourcePtr + + *Note:* This interface is *obsolete* and kept only for + *compatibility. Use instead. + + Represents a source from which a PNG can be read. Programmers who + do not wish to read PNGs from a file can provide their own + alternate input mechanism, using the + function. See the documentation of that function for an example of + the proper use of this type. + + > typedef struct { + > int (*source) (void *context, char *buffer, int len); + > void *context; + > } gdSource, *gdSourcePtr; + + The source function must return -1 on error, otherwise the number + of bytes fetched. 0 is EOF, not an error! + + 'context' will be passed to your source function. + +*/ +typedef struct { + int (*source) (void *context, char *buffer, int len); + void *context; +} +gdSource, *gdSourcePtr; + +/* Deprecated in favor of gdImageCreateFromPngCtx */ +BGD_DECLARE(gdImagePtr) gdImageCreateFromPngSource (gdSourcePtr in); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd (FILE * in); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGdCtx(gdIOCtxPtr in); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGdPtr (int size, void *data); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2 (FILE * in); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Ctx(gdIOCtxPtr in); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Ptr (int size, void *data); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Part (FILE * in, int srcx, int srcy, int w, + int h); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2PartCtx(gdIOCtxPtr in, int srcx, int srcy, + int w, int h); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2PartPtr (int size, void *data, int srcx, int srcy, + int w, int h); +/* 2.0.10: prototype was missing */ +BGD_DECLARE(gdImagePtr) gdImageCreateFromXbm (FILE * in); +BGD_DECLARE(void) gdImageXbmCtx(gdImagePtr image, char* file_name, int fg, gdIOCtxPtr out); + +/* NOTE: filename, not FILE */ +BGD_DECLARE(gdImagePtr) gdImageCreateFromXpm (char *filename); + +BGD_DECLARE(void) gdImageDestroy (gdImagePtr im); + +/* Replaces or blends with the background depending on the + most recent call to gdImageAlphaBlending and the + alpha channel value of 'color'; default is to overwrite. + Tiling and line styling are also implemented + here. All other gd drawing functions pass through this call, + allowing for many useful effects. + Overlay and multiply effects are used when gdImageAlphaBlending + is passed gdEffectOverlay and gdEffectMultiply */ + +BGD_DECLARE(void) gdImageSetPixel (gdImagePtr im, int x, int y, int color); +/* FreeType 2 text output with hook to extra flags */ + +BGD_DECLARE(int) gdImageGetPixel (gdImagePtr im, int x, int y); +BGD_DECLARE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y); + +BGD_DECLARE(void) gdImageAABlend (gdImagePtr im); + +BGD_DECLARE(void) gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color); + +/* For backwards compatibility only. Use gdImageSetStyle() + for much more flexible line drawing. */ +BGD_DECLARE(void) gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2, + int color); +/* Corners specified (not width and height). Upper left first, lower right + second. */ +BGD_DECLARE(void) gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, + int color); +/* Solid bar. Upper left corner first, lower right corner second. */ +BGD_DECLARE(void) gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, + int color); +BGD_DECLARE(void) gdImageSetClip(gdImagePtr im, int x1, int y1, int x2, int y2); +BGD_DECLARE(void) gdImageGetClip(gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P); +BGD_DECLARE(void) gdImageSetResolution(gdImagePtr im, const unsigned int res_x, const unsigned int res_y); +BGD_DECLARE(int) gdImageBoundsSafe (gdImagePtr im, int x, int y); +BGD_DECLARE(void) gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y, int c, + int color); +BGD_DECLARE(void) gdImageCharUp (gdImagePtr im, gdFontPtr f, int x, int y, int c, + int color); +BGD_DECLARE(void) gdImageString (gdImagePtr im, gdFontPtr f, int x, int y, + unsigned char *s, int color); +BGD_DECLARE(void) gdImageStringUp (gdImagePtr im, gdFontPtr f, int x, int y, + unsigned char *s, int color); +BGD_DECLARE(void) gdImageString16 (gdImagePtr im, gdFontPtr f, int x, int y, + unsigned short *s, int color); +BGD_DECLARE(void) gdImageStringUp16 (gdImagePtr im, gdFontPtr f, int x, int y, + unsigned short *s, int color); + +/* 2.0.16: for thread-safe use of gdImageStringFT and friends, + call this before allowing any thread to call gdImageStringFT. + Otherwise it is invoked by the first thread to invoke + gdImageStringFT, with a very small but real risk of a race condition. + Return 0 on success, nonzero on failure to initialize freetype. */ +BGD_DECLARE(int) gdFontCacheSetup (void); + +/* Optional: clean up after application is done using fonts in + gdImageStringFT(). */ +BGD_DECLARE(void) gdFontCacheShutdown (void); +/* 2.0.20: for backwards compatibility. A few applications did start calling + this function when it first appeared although it was never documented. + Simply invokes gdFontCacheShutdown. */ +BGD_DECLARE(void) gdFreeFontCache (void); + +/* Calls gdImageStringFT. Provided for backwards compatibility only. */ +BGD_DECLARE(char *) gdImageStringTTF (gdImagePtr im, int *brect, int fg, const char *fontlist, + double ptsize, double angle, int x, int y, + const char *string); + +/* FreeType 2 text output */ +BGD_DECLARE(char *) gdImageStringFT (gdImagePtr im, int *brect, int fg, const char *fontlist, + double ptsize, double angle, int x, int y, + const char *string); + + +/* + Group: Types + + typedef: gdFTStringExtra + + typedef: gdFTStringExtraPtr + + A structure and associated pointer type used to pass additional + parameters to the function. See + for the structure definition. + + Thanks to Wez Furlong. +*/ + +/* 2.0.5: provides an extensible way to pass additional parameters. + Thanks to Wez Furlong, sorry for the delay. */ +typedef struct { + int flags; /* Logical OR of gdFTEX_ values */ + double linespacing; /* fine tune line spacing for '\n' */ + int charmap; /* TBB: 2.0.12: may be gdFTEX_Unicode, + gdFTEX_Shift_JIS, gdFTEX_Big5, + or gdFTEX_Adobe_Custom; + when not specified, maps are searched + for in the above order. */ + int hdpi; /* if (flags & gdFTEX_RESOLUTION) */ + int vdpi; /* if (flags & gdFTEX_RESOLUTION) */ + char *xshow; /* if (flags & gdFTEX_XSHOW) + then, on return, xshow is a malloc'ed + string containing xshow position data for + the last string. + + NB. The caller is responsible for gdFree'ing + the xshow string. + */ + char *fontpath; /* if (flags & gdFTEX_RETURNFONTPATHNAME) + then, on return, fontpath is a malloc'ed + string containing the actual font file path name + used, which can be interesting when fontconfig + is in use. + + The caller is responsible for gdFree'ing the + fontpath string. + */ + +} +gdFTStringExtra, *gdFTStringExtraPtr; + +#define gdFTEX_LINESPACE 1 +#define gdFTEX_CHARMAP 2 +#define gdFTEX_RESOLUTION 4 +#define gdFTEX_DISABLE_KERNING 8 +#define gdFTEX_XSHOW 16 +/* The default unless gdFTUseFontConfig(1); has been called: + fontlist is a full or partial font file pathname or list thereof + (i.e. just like before 2.0.29) */ +#define gdFTEX_FONTPATHNAME 32 +/* Necessary to use fontconfig patterns instead of font pathnames + as the fontlist argument, unless gdFTUseFontConfig(1); has + been called. New in 2.0.29 */ +#define gdFTEX_FONTCONFIG 64 +/* Sometimes interesting when fontconfig is used: the fontpath + element of the structure above will contain a gdMalloc'd string + copy of the actual font file pathname used, if this flag is set + when the call is made */ +#define gdFTEX_RETURNFONTPATHNAME 128 + +/* If flag is nonzero, the fontlist parameter to gdImageStringFT + and gdImageStringFTEx shall be assumed to be a fontconfig font pattern + if fontconfig was compiled into gd. This function returns zero + if fontconfig is not available, nonzero otherwise. */ +BGD_DECLARE(int) gdFTUseFontConfig(int flag); + +/* These are NOT flags; set one in 'charmap' if you set the + gdFTEX_CHARMAP bit in 'flags'. */ +#define gdFTEX_Unicode 0 +#define gdFTEX_Shift_JIS 1 +#define gdFTEX_Big5 2 +#define gdFTEX_Adobe_Custom 3 + +BGD_DECLARE(char *) gdImageStringFTEx (gdImagePtr im, int *brect, int fg, const char *fontlist, + double ptsize, double angle, int x, int y, + const char *string, gdFTStringExtraPtr strex); + + +/* + Group: Types + + typedef: gdPoint + + typedef: gdPointPtr + + Represents a point in the coordinate space of the image; used by + , and + for polygon drawing. + + > typedef struct { + > int x, y; + > } gdPoint, *gdPointPtr; + +*/ +typedef struct { + int x, y; +} +gdPoint, *gdPointPtr; + +/** + * Typedef: gdRect + * + * A rectangle in the coordinate space of the image + * + * Members: + * x - The x-coordinate of the upper left corner. + * y - The y-coordinate of the upper left corner. + * width - The width. + * height - The height. + * + * Typedef: gdRectPtr + * + * A pointer to a + */ +typedef struct { + int x, y; + int width, height; +} +gdRect, *gdRectPtr; + + +BGD_DECLARE(void) gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c); +BGD_DECLARE(void) gdImageOpenPolygon (gdImagePtr im, gdPointPtr p, int n, int c); +BGD_DECLARE(void) gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c); + +/* These functions still work with truecolor images, + for which they never return error. */ +BGD_DECLARE(int) gdImageColorAllocate (gdImagePtr im, int r, int g, int b); +/* gd 2.0: palette entries with non-opaque transparency are permitted. */ +BGD_DECLARE(int) gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a); +/* Assumes opaque is the preferred alpha channel value */ +BGD_DECLARE(int) gdImageColorClosest (gdImagePtr im, int r, int g, int b); +/* Closest match taking all four parameters into account. + A slightly different color with the same transparency + beats the exact same color with radically different + transparency */ +BGD_DECLARE(int) gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a); +/* An alternate method */ +BGD_DECLARE(int) gdImageColorClosestHWB (gdImagePtr im, int r, int g, int b); +/* Returns exact, 100% opaque matches only */ +BGD_DECLARE(int) gdImageColorExact (gdImagePtr im, int r, int g, int b); +/* Returns an exact match only, including alpha */ +BGD_DECLARE(int) gdImageColorExactAlpha (gdImagePtr im, int r, int g, int b, int a); +/* Opaque only */ +BGD_DECLARE(int) gdImageColorResolve (gdImagePtr im, int r, int g, int b); +/* Based on gdImageColorExactAlpha and gdImageColorClosestAlpha */ +BGD_DECLARE(int) gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a); + +/* A simpler way to obtain an opaque truecolor value for drawing on a + truecolor image. Not for use with palette images! */ + +#define gdTrueColor(r, g, b) (((r) << 16) + \ + ((g) << 8) + \ + (b)) + +/** + * Group: Color Composition + * + * Macro: gdTrueColorAlpha + * + * Compose a truecolor value from its components + * + * Parameters: + * r - The red channel (0-255) + * g - The green channel (0-255) + * b - The blue channel (0-255) + * a - The alpha channel (0-127, where 127 is fully transparent, and 0 is + * completely opaque). + * + * See also: + * - + * - + * - + * - + * - + */ +#define gdTrueColorAlpha(r, g, b, a) (((a) << 24) + \ + ((r) << 16) + \ + ((g) << 8) + \ + (b)) + +BGD_DECLARE(void) gdImageColorDeallocate (gdImagePtr im, int color); + +/* Converts a truecolor image to a palette-based image, + using a high-quality two-pass quantization routine + which attempts to preserve alpha channel information + as well as R/G/B color information when creating + a palette. If ditherFlag is set, the image will be + dithered to approximate colors better, at the expense + of some obvious "speckling." colorsWanted can be + anything up to 256. If the original source image + includes photographic information or anything that + came out of a JPEG, 256 is strongly recommended. + + Better yet, don't use these function -- write real + truecolor PNGs and JPEGs. The disk space gain of + conversion to palette is not great (for small images + it can be negative) and the quality loss is ugly. + + DIFFERENCES: gdImageCreatePaletteFromTrueColor creates and + returns a new image. gdImageTrueColorToPalette modifies + an existing image, and the truecolor pixels are discarded. + + gdImageTrueColorToPalette() returns TRUE on success, FALSE on failure. +*/ + +BGD_DECLARE(gdImagePtr) gdImageCreatePaletteFromTrueColor (gdImagePtr im, int ditherFlag, + int colorsWanted); + +BGD_DECLARE(int) gdImageTrueColorToPalette (gdImagePtr im, int ditherFlag, + int colorsWanted); + +BGD_DECLARE(int) gdImagePaletteToTrueColor(gdImagePtr src); + +/* An attempt at getting the results of gdImageTrueColorToPalette to + * look a bit more like the original (im1 is the original and im2 is + * the palette version */ + +BGD_DECLARE(int) gdImageColorMatch(gdImagePtr im1, gdImagePtr im2); + +/* Selects quantization method used for subsequent gdImageTrueColorToPalette calls. + See gdPaletteQuantizationMethod enum (e.g. GD_QUANT_NEUQUANT, GD_QUANT_LIQ). + Speed is from 1 (highest quality) to 10 (fastest). + Speed 0 selects method-specific default (recommended). + + Returns FALSE if the given method is invalid or not available. +*/ +BGD_DECLARE(int) gdImageTrueColorToPaletteSetMethod (gdImagePtr im, int method, int speed); + +/* + Chooses quality range that subsequent call to gdImageTrueColorToPalette will aim for. + Min and max quality is in range 1-100 (1 = ugly, 100 = perfect). Max must be higher than min. + If palette cannot represent image with at least min_quality, then image will remain true-color. + If palette can represent image with quality better than max_quality, then lower number of colors will be used. + This function has effect only when GD_QUANT_LIQ method has been selected and the source image is true-color. +*/ +BGD_DECLARE(void) gdImageTrueColorToPaletteSetQuality (gdImagePtr im, int min_quality, int max_quality); + +/* Specifies a color index (if a palette image) or an + RGB color (if a truecolor image) which should be + considered 100% transparent. FOR TRUECOLOR IMAGES, + THIS IS IGNORED IF AN ALPHA CHANNEL IS BEING + SAVED. Use gdImageSaveAlpha(im, 0); to + turn off the saving of a full alpha channel in + a truecolor image. Note that gdImageColorTransparent + is usually compatible with older browsers that + do not understand full alpha channels well. TBB */ +BGD_DECLARE(void) gdImageColorTransparent (gdImagePtr im, int color); + +BGD_DECLARE(void) gdImagePaletteCopy (gdImagePtr dst, gdImagePtr src); + +typedef int (*gdCallbackImageColor)(gdImagePtr im, int src); + +BGD_DECLARE(int) gdImageColorReplace(gdImagePtr im, int src, int dst); +BGD_DECLARE(int) gdImageColorReplaceThreshold(gdImagePtr im, int src, int dst, float threshold); +BGD_DECLARE(int) gdImageColorReplaceArray(gdImagePtr im, int len, int *src, int *dst); +BGD_DECLARE(int) gdImageColorReplaceCallback(gdImagePtr im, gdCallbackImageColor callback); + +BGD_DECLARE(void) gdImageGif (gdImagePtr im, FILE * out); +BGD_DECLARE(void) gdImagePng (gdImagePtr im, FILE * out); +BGD_DECLARE(void) gdImagePngCtx(gdImagePtr im, gdIOCtxPtr out); +BGD_DECLARE(void) gdImageGifCtx(gdImagePtr im, gdIOCtxPtr out); +BGD_DECLARE(void) gdImageTiff(gdImagePtr im, FILE *outFile); +BGD_DECLARE(void *) gdImageTiffPtr(gdImagePtr im, int *size); +BGD_DECLARE(void) gdImageTiffCtx(gdImagePtr image, gdIOCtxPtr out); + +BGD_DECLARE(void *) gdImageBmpPtr(gdImagePtr im, int *size, int compression); +BGD_DECLARE(void) gdImageBmp(gdImagePtr im, FILE *outFile, int compression); +BGD_DECLARE(void) gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression); + +/* 2.0.12: Compression level: 0-9 or -1, where 0 is NO COMPRESSION at all, + 1 is FASTEST but produces larger files, 9 provides the best + compression (smallest files) but takes a long time to compress, and + -1 selects the default compiled into the zlib library. */ +BGD_DECLARE(void) gdImagePngEx (gdImagePtr im, FILE * out, int level); +BGD_DECLARE(void) gdImagePngCtxEx(gdImagePtr im, gdIOCtxPtr out, int level); + +BGD_DECLARE(void) gdImageWBMP (gdImagePtr image, int fg, FILE * out); +BGD_DECLARE(void) gdImageWBMPCtx(gdImagePtr image, int fg, gdIOCtxPtr out); + +BGD_DECLARE(int) gdImageFile(gdImagePtr im, const char *filename); +BGD_DECLARE(int) gdSupportsFileType(const char *filename, int writing); + + +/* Guaranteed to correctly free memory returned by the gdImage*Ptr + functions */ +BGD_DECLARE(void) gdFree (void *m); + +/* Best to free this memory with gdFree(), not free() */ +BGD_DECLARE(void *) gdImageWBMPPtr (gdImagePtr im, int *size, int fg); + +/* 100 is highest quality (there is always a little loss with JPEG). + 0 is lowest. 10 is about the lowest useful setting. */ +BGD_DECLARE(void) gdImageJpeg (gdImagePtr im, FILE * out, int quality); +BGD_DECLARE(void) gdImageJpegCtx(gdImagePtr im, gdIOCtxPtr out, int quality); + +/* Best to free this memory with gdFree(), not free() */ +BGD_DECLARE(void *) gdImageJpegPtr (gdImagePtr im, int *size, int quality); + +/** + * Group: WebP + * + * Constant: gdWebpLossless + * + * Lossless quality threshold. When image quality is greater than or equal to + * , the image will be written in the lossless WebP format. + * + * See also: + * - + */ +#define gdWebpLossless 101 + +BGD_DECLARE(void) gdImageWebpEx (gdImagePtr im, FILE * outFile, int quantization); +BGD_DECLARE(void) gdImageWebp (gdImagePtr im, FILE * outFile); +BGD_DECLARE(void *) gdImageWebpPtr (gdImagePtr im, int *size); +BGD_DECLARE(void *) gdImageWebpPtrEx (gdImagePtr im, int *size, int quantization); +BGD_DECLARE(void) gdImageWebpCtx(gdImagePtr im, gdIOCtxPtr outfile, int quantization); + +BGD_DECLARE(void) gdImageHeifEx(gdImagePtr im, FILE *outFile, int quality, gdHeifCodec codec, gdHeifChroma chroma); +BGD_DECLARE(void) gdImageHeif(gdImagePtr im, FILE *outFile); +BGD_DECLARE(void *) gdImageHeifPtr(gdImagePtr im, int *size); +BGD_DECLARE(void *) gdImageHeifPtrEx(gdImagePtr im, int *size, int quality, gdHeifCodec codec, gdHeifChroma chroma); +BGD_DECLARE(void) gdImageHeifCtx(gdImagePtr im, gdIOCtxPtr outfile, int quality, gdHeifCodec codec, gdHeifChroma chroma); + +BGD_DECLARE(void) gdImageAvif(gdImagePtr im, FILE *outFile); +BGD_DECLARE(void) gdImageAvifEx(gdImagePtr im, FILE *outFile, int quality, int speed); +BGD_DECLARE(void *) gdImageAvifPtr(gdImagePtr im, int *size); +BGD_DECLARE(void *) gdImageAvifPtrEx(gdImagePtr im, int *size, int quality, int speed); +BGD_DECLARE(void) gdImageAvifCtx(gdImagePtr im, gdIOCtxPtr outfile, int quality, int speed); + +/** + * Group: GifAnim + * + * Legal values for Disposal. gdDisposalNone is always used by + * the built-in optimizer if previm is passed. + * + * Constants: gdImageGifAnim + * + * gdDisposalUnknown - Not recommended + * gdDisposalNone - Preserve previous frame + * gdDisposalRestoreBackground - First allocated color of palette + * gdDisposalRestorePrevious - Restore to before start of frame + * + * See also: + * - + */ +enum { + gdDisposalUnknown, + gdDisposalNone, + gdDisposalRestoreBackground, + gdDisposalRestorePrevious +}; + +BGD_DECLARE(void) gdImageGifAnimBegin(gdImagePtr im, FILE *outFile, int GlobalCM, int Loops); +BGD_DECLARE(void) gdImageGifAnimAdd(gdImagePtr im, FILE *outFile, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm); +BGD_DECLARE(void) gdImageGifAnimEnd(FILE *outFile); +BGD_DECLARE(void) gdImageGifAnimBeginCtx(gdImagePtr im, gdIOCtxPtr out, int GlobalCM, int Loops); +BGD_DECLARE(void) gdImageGifAnimAddCtx(gdImagePtr im, gdIOCtxPtr out, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm); +BGD_DECLARE(void) gdImageGifAnimEndCtx(gdIOCtxPtr out); +BGD_DECLARE(void *) gdImageGifAnimBeginPtr(gdImagePtr im, int *size, int GlobalCM, int Loops); +BGD_DECLARE(void *) gdImageGifAnimAddPtr(gdImagePtr im, int *size, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm); +BGD_DECLARE(void *) gdImageGifAnimEndPtr(int *size); + + + +/* + Group: Types + + typedef: gdSink + + typedef: gdSinkPtr + + *Note:* This interface is *obsolete* and kept only for + *compatibility*. Use instead. + + Represents a "sink" (destination) to which a PNG can be + written. Programmers who do not wish to write PNGs to a file can + provide their own alternate output mechanism, using the + function. See the documentation of that + function for an example of the proper use of this type. + + > typedef struct { + > int (*sink) (void *context, char *buffer, int len); + > void *context; + > } gdSink, *gdSinkPtr; + + The _sink_ function must return -1 on error, otherwise the number of + bytes written, which must be equal to len. + + _context_ will be passed to your sink function. + +*/ + +typedef struct { + int (*sink) (void *context, const char *buffer, int len); + void *context; +} +gdSink, *gdSinkPtr; + +BGD_DECLARE(void) gdImagePngToSink (gdImagePtr im, gdSinkPtr out); + +BGD_DECLARE(void) gdImageGd (gdImagePtr im, FILE * out); +BGD_DECLARE(void) gdImageGd2 (gdImagePtr im, FILE * out, int cs, int fmt); + +/* Best to free this memory with gdFree(), not free() */ +BGD_DECLARE(void *) gdImageGifPtr (gdImagePtr im, int *size); + +/* Best to free this memory with gdFree(), not free() */ +BGD_DECLARE(void *) gdImagePngPtr (gdImagePtr im, int *size); +BGD_DECLARE(void *) gdImagePngPtrEx (gdImagePtr im, int *size, int level); + +/* Best to free this memory with gdFree(), not free() */ +BGD_DECLARE(void *) gdImageGdPtr (gdImagePtr im, int *size); + +/* Best to free this memory with gdFree(), not free() */ +BGD_DECLARE(void *) gdImageGd2Ptr (gdImagePtr im, int cs, int fmt, int *size); + +/* Style is a bitwise OR ( | operator ) of these. + gdArc and gdChord are mutually exclusive; + gdChord just connects the starting and ending + angles with a straight line, while gdArc produces + a rounded edge. gdPie is a synonym for gdArc. + gdNoFill indicates that the arc or chord should be + outlined, not filled. gdEdged, used together with + gdNoFill, indicates that the beginning and ending + angles should be connected to the center; this is + a good way to outline (rather than fill) a + 'pie slice'. */ +#define gdArc 0 +#define gdPie gdArc +#define gdChord 1 +#define gdNoFill 2 +#define gdEdged 4 + +BGD_DECLARE(void) gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, + int e, int color, int style); +BGD_DECLARE(void) gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, + int color); +BGD_DECLARE(void) gdImageEllipse(gdImagePtr im, int cx, int cy, int w, int h, int color); +BGD_DECLARE(void) gdImageFilledEllipse (gdImagePtr im, int cx, int cy, int w, int h, + int color); +BGD_DECLARE(void) gdImageFillToBorder (gdImagePtr im, int x, int y, int border, + int color); +BGD_DECLARE(void) gdImageFill (gdImagePtr im, int x, int y, int color); +BGD_DECLARE(void) gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, + int srcX, int srcY, int w, int h); +BGD_DECLARE(void) gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, + int srcX, int srcY, int w, int h, int pct); +BGD_DECLARE(void) gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, + int dstY, int srcX, int srcY, int w, int h, + int pct); + +/* Stretches or shrinks to fit, as needed. Does NOT attempt + to average the entire set of source pixels that scale down onto the + destination pixel. */ +BGD_DECLARE(void) gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, + int srcX, int srcY, int dstW, int dstH, int srcW, + int srcH); + +/* gd 2.0: stretches or shrinks to fit, as needed. When called with a + truecolor destination image, this function averages the + entire set of source pixels that scale down onto the + destination pixel, taking into account what portion of the + destination pixel each source pixel represents. This is a + floating point operation, but this is not a performance issue + on modern hardware, except for some embedded devices. If the + destination is a palette image, gdImageCopyResized is + substituted automatically. */ +BGD_DECLARE(void) gdImageCopyResampled (gdImagePtr dst, gdImagePtr src, int dstX, + int dstY, int srcX, int srcY, int dstW, int dstH, + int srcW, int srcH); + +/* gd 2.0.8: gdImageCopyRotated is added. Source + is a rectangle, with its upper left corner at + srcX and srcY. Destination is the *center* of + the rotated copy. Angle is in degrees, same as + gdImageArc. Floating point destination center + coordinates allow accurate rotation of + objects of odd-numbered width or height. */ +BGD_DECLARE(void) gdImageCopyRotated (gdImagePtr dst, + gdImagePtr src, + double dstX, double dstY, + int srcX, int srcY, + int srcWidth, int srcHeight, int angle); + +BGD_DECLARE(gdImagePtr) gdImageClone (gdImagePtr src); + +BGD_DECLARE(void) gdImageSetBrush (gdImagePtr im, gdImagePtr brush); +BGD_DECLARE(void) gdImageSetTile (gdImagePtr im, gdImagePtr tile); +BGD_DECLARE(void) gdImageSetAntiAliased (gdImagePtr im, int c); +BGD_DECLARE(void) gdImageSetAntiAliasedDontBlend (gdImagePtr im, int c, int dont_blend); +BGD_DECLARE(void) gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels); +/* Line thickness (defaults to 1). Affects lines, ellipses, + rectangles, polygons and so forth. */ +BGD_DECLARE(void) gdImageSetThickness (gdImagePtr im, int thickness); +/* On or off (1 or 0) for all three of these. */ +BGD_DECLARE(void) gdImageInterlace (gdImagePtr im, int interlaceArg); +BGD_DECLARE(void) gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg); +BGD_DECLARE(void) gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg); + +BGD_DECLARE(gdImagePtr) gdImageNeuQuant(gdImagePtr im, const int max_color, int sample_factor); + +enum gdPixelateMode { + GD_PIXELATE_UPPERLEFT, + GD_PIXELATE_AVERAGE +}; + +BGD_DECLARE(int) gdImagePixelate(gdImagePtr im, int block_size, const unsigned int mode); + +typedef struct { + int sub; + int plus; + unsigned int num_colors; + int *colors; + unsigned int seed; +} gdScatter, *gdScatterPtr; + +BGD_DECLARE(int) gdImageScatter(gdImagePtr im, int sub, int plus); +BGD_DECLARE(int) gdImageScatterColor(gdImagePtr im, int sub, int plus, int colors[], unsigned int num_colors); +BGD_DECLARE(int) gdImageScatterEx(gdImagePtr im, gdScatterPtr s); +BGD_DECLARE(int) gdImageSmooth(gdImagePtr im, float weight); +BGD_DECLARE(int) gdImageMeanRemoval(gdImagePtr im); +BGD_DECLARE(int) gdImageEmboss(gdImagePtr im); +BGD_DECLARE(int) gdImageGaussianBlur(gdImagePtr im); +BGD_DECLARE(int) gdImageEdgeDetectQuick(gdImagePtr src); +BGD_DECLARE(int) gdImageSelectiveBlur( gdImagePtr src); +BGD_DECLARE(int) gdImageConvolution(gdImagePtr src, float filter[3][3], float filter_div, float offset); +BGD_DECLARE(int) gdImageColor(gdImagePtr src, const int red, const int green, const int blue, const int alpha); +BGD_DECLARE(int) gdImageContrast(gdImagePtr src, double contrast); +BGD_DECLARE(int) gdImageBrightness(gdImagePtr src, int brightness); +BGD_DECLARE(int) gdImageGrayScale(gdImagePtr src); +BGD_DECLARE(int) gdImageNegate(gdImagePtr src); + +BGD_DECLARE(gdImagePtr) gdImageCopyGaussianBlurred(gdImagePtr src, int radius, + double sigma); + + +/** + * Group: Accessor Macros + */ + +/** + * Macro: gdImageTrueColor + * + * Whether an image is a truecolor image. + * + * Parameters: + * im - The image. + * + * Returns: + * Non-zero if the image is a truecolor image, zero for palette images. + */ +#define gdImageTrueColor(im) ((im)->trueColor) + +/** + * Macro: gdImageSX + * + * Gets the width (in pixels) of an image. + * + * Parameters: + * im - The image. + */ +#define gdImageSX(im) ((im)->sx) + +/** + * Macro: gdImageSY + * + * Gets the height (in pixels) of an image. + * + * Parameters: + * im - The image. + */ +#define gdImageSY(im) ((im)->sy) + +/** + * Macro: gdImageColorsTotal + * + * Gets the number of colors in the palette. + * + * This macro is only valid for palette images. + * + * Parameters: + * im - The image + */ +#define gdImageColorsTotal(im) ((im)->colorsTotal) + +/** + * Macro: gdImageRed + * + * Gets the red component value of a given color. + * + * Parameters: + * im - The image. + * c - The color. + */ +#define gdImageRed(im, c) ((im)->trueColor ? gdTrueColorGetRed(c) : \ + (im)->red[(c)]) + +/** + * Macro: gdImageGreen + * + * Gets the green component value of a given color. + * + * Parameters: + * im - The image. + * c - The color. + */ +#define gdImageGreen(im, c) ((im)->trueColor ? gdTrueColorGetGreen(c) : \ + (im)->green[(c)]) + +/** + * Macro: gdImageBlue + * + * Gets the blue component value of a given color. + * + * Parameters: + * im - The image. + * c - The color. + */ +#define gdImageBlue(im, c) ((im)->trueColor ? gdTrueColorGetBlue(c) : \ + (im)->blue[(c)]) + +/** + * Macro: gdImageAlpha + * + * Gets the alpha component value of a given color. + * + * Parameters: + * im - The image. + * c - The color. + */ +#define gdImageAlpha(im, c) ((im)->trueColor ? gdTrueColorGetAlpha(c) : \ + (im)->alpha[(c)]) + +/** + * Macro: gdImageGetTransparent + * + * Gets the transparent color of the image. + * + * Parameters: + * im - The image. + * + * See also: + * - + */ +#define gdImageGetTransparent(im) ((im)->transparent) + +/** + * Macro: gdImageGetInterlaced + * + * Whether an image is interlaced. + * + * Parameters: + * im - The image. + * + * Returns: + * Non-zero for interlaced images, zero otherwise. + * + * See also: + * - + */ +#define gdImageGetInterlaced(im) ((im)->interlace) + +/** + * Macro: gdImagePalettePixel + * + * Gets the color of a pixel. + * + * Calling this macro is only valid for palette images. + * No bounds checking is done for the coordinates. + * + * Parameters: + * im - The image. + * x - The x-coordinate. + * y - The y-coordinate. + * + * See also: + * - + * - + */ +#define gdImagePalettePixel(im, x, y) (im)->pixels[(y)][(x)] + +/** + * Macro: gdImageTrueColorPixel + * + * Gets the color of a pixel. + * + * Calling this macro is only valid for truecolor images. + * No bounds checking is done for the coordinates. + * + * Parameters: + * im - The image. + * x - The x-coordinate. + * y - The y-coordinate. + * + * See also: + * - + * - + */ +#define gdImageTrueColorPixel(im, x, y) (im)->tpixels[(y)][(x)] + +/** + * Macro: gdImageResolutionX + * + * Gets the horizontal resolution in DPI. + * + * Parameters: + * im - The image. + * + * See also: + * - + * - + */ +#define gdImageResolutionX(im) (im)->res_x + +/** + * Macro: gdImageResolutionY + * + * Gets the vertical resolution in DPI. + * + * Parameters: + * im - The image. + * + * See also: + * - + * - + */ +#define gdImageResolutionY(im) (im)->res_y + +/* I/O Support routines. */ + +BGD_DECLARE(gdIOCtxPtr) gdNewFileCtx(FILE *); +/* If data is null, size is ignored and an initial data buffer is + allocated automatically. NOTE: this function assumes gd has the right + to free or reallocate "data" at will! Also note that gd will free + "data" when the IO context is freed. If data is not null, it must point + to memory allocated with gdMalloc, or by a call to gdImage[something]Ptr. + If not, see gdNewDynamicCtxEx for an alternative. */ +BGD_DECLARE(gdIOCtxPtr) gdNewDynamicCtx(int size, void *data); +/* 2.0.21: if freeFlag is nonzero, gd will free and/or reallocate "data" as + needed as described above. If freeFlag is zero, gd will never free + or reallocate "data", which means that the context should only be used + for *reading* an image from a memory buffer, or writing an image to a + memory buffer which is already large enough. If the memory buffer is + not large enough and an image write is attempted, the write operation + will fail. Those wishing to write an image to a buffer in memory have + a much simpler alternative in the gdImage[something]Ptr functions. */ +BGD_DECLARE(gdIOCtxPtr) gdNewDynamicCtxEx(int size, void *data, int freeFlag); +BGD_DECLARE(gdIOCtxPtr) gdNewSSCtx(gdSourcePtr in, gdSinkPtr out); +BGD_DECLARE(void *) gdDPExtractData(gdIOCtxPtr ctx, int *size); + +#define GD2_CHUNKSIZE 128 +#define GD2_CHUNKSIZE_MIN 64 +#define GD2_CHUNKSIZE_MAX 4096 + +#define GD2_VERS 2 +#define GD2_ID "gd2" + +#define GD2_FMT_RAW 1 +#define GD2_FMT_COMPRESSED 2 + +/* Image comparison definitions */ +BGD_DECLARE(int) gdImageCompare (gdImagePtr im1, gdImagePtr im2); + +BGD_DECLARE(void) gdImageFlipHorizontal(gdImagePtr im); +BGD_DECLARE(void) gdImageFlipVertical(gdImagePtr im); +BGD_DECLARE(void) gdImageFlipBoth(gdImagePtr im); + +/** + * Group: Crop + * + * Constants: gdCropMode + * GD_CROP_DEFAULT - Same as GD_CROP_TRANSPARENT + * GD_CROP_TRANSPARENT - Crop using the transparent color + * GD_CROP_BLACK - Crop black borders + * GD_CROP_WHITE - Crop white borders + * GD_CROP_SIDES - Crop using colors of the 4 corners + * + * See also: + * - + **/ +enum gdCropMode { + GD_CROP_DEFAULT = 0, + GD_CROP_TRANSPARENT, + GD_CROP_BLACK, + GD_CROP_WHITE, + GD_CROP_SIDES, + GD_CROP_THRESHOLD +}; + +BGD_DECLARE(gdImagePtr) gdImageCrop(gdImagePtr src, const gdRect *crop); +BGD_DECLARE(gdImagePtr) gdImageCropAuto(gdImagePtr im, const unsigned int mode); +BGD_DECLARE(gdImagePtr) gdImageCropThreshold(gdImagePtr im, const unsigned int color, const float threshold); + +BGD_DECLARE(int) gdImageSetInterpolationMethod(gdImagePtr im, gdInterpolationMethod id); +BGD_DECLARE(gdInterpolationMethod) gdImageGetInterpolationMethod(gdImagePtr im); + +BGD_DECLARE(gdImagePtr) gdImageScale(const gdImagePtr src, const unsigned int new_width, const unsigned int new_height); + +BGD_DECLARE(gdImagePtr) gdImageRotateInterpolated(const gdImagePtr src, const float angle, int bgcolor); + +typedef enum { + GD_AFFINE_TRANSLATE = 0, + GD_AFFINE_SCALE, + GD_AFFINE_ROTATE, + GD_AFFINE_SHEAR_HORIZONTAL, + GD_AFFINE_SHEAR_VERTICAL +} gdAffineStandardMatrix; + +BGD_DECLARE(int) gdAffineApplyToPointF (gdPointFPtr dst, const gdPointFPtr src, const double affine[6]); +BGD_DECLARE(int) gdAffineInvert (double dst[6], const double src[6]); +BGD_DECLARE(int) gdAffineFlip (double dst_affine[6], const double src_affine[6], const int flip_h, const int flip_v); +BGD_DECLARE(int) gdAffineConcat (double dst[6], const double m1[6], const double m2[6]); + +BGD_DECLARE(int) gdAffineIdentity (double dst[6]); +BGD_DECLARE(int) gdAffineScale (double dst[6], const double scale_x, const double scale_y); +BGD_DECLARE(int) gdAffineRotate (double dst[6], const double angle); +BGD_DECLARE(int) gdAffineShearHorizontal (double dst[6], const double angle); +BGD_DECLARE(int) gdAffineShearVertical(double dst[6], const double angle); +BGD_DECLARE(int) gdAffineTranslate (double dst[6], const double offset_x, const double offset_y); +BGD_DECLARE(double) gdAffineExpansion (const double src[6]); +BGD_DECLARE(int) gdAffineRectilinear (const double src[6]); +BGD_DECLARE(int) gdAffineEqual (const double matrix1[6], const double matrix2[6]); +BGD_DECLARE(int) gdTransformAffineGetImage(gdImagePtr *dst, const gdImagePtr src, gdRectPtr src_area, const double affine[6]); +BGD_DECLARE(int) gdTransformAffineCopy(gdImagePtr dst, int dst_x, int dst_y, const gdImagePtr src, gdRectPtr src_region, const double affine[6]); +/* +gdTransformAffineCopy(gdImagePtr dst, int x0, int y0, int x1, int y1, + const gdImagePtr src, int src_width, int src_height, + const double affine[6]); +*/ +BGD_DECLARE(int) gdTransformAffineBoundingBox(gdRectPtr src, const double affine[6], gdRectPtr bbox); + +/** + * Group: Image Comparison + * + * Constants: + * GD_CMP_IMAGE - Actual image IS different + * GD_CMP_NUM_COLORS - Number of colors in pallette differ + * GD_CMP_COLOR - Image colors differ + * GD_CMP_SIZE_X - Image width differs + * GD_CMP_SIZE_Y - Image heights differ + * GD_CMP_TRANSPARENT - Transparent color differs + * GD_CMP_BACKGROUND - Background color differs + * GD_CMP_INTERLACE - Interlaced setting differs + * GD_CMP_TRUECOLOR - Truecolor vs palette differs + * + * See also: + * - + */ +#define GD_CMP_IMAGE 1 +#define GD_CMP_NUM_COLORS 2 +#define GD_CMP_COLOR 4 +#define GD_CMP_SIZE_X 8 +#define GD_CMP_SIZE_Y 16 +#define GD_CMP_TRANSPARENT 32 +#define GD_CMP_BACKGROUND 64 +#define GD_CMP_INTERLACE 128 +#define GD_CMP_TRUECOLOR 256 + +/* resolution affects ttf font rendering, particularly hinting */ +#define GD_RESOLUTION 96 /* pixels per inch */ + + +/* Version information functions */ +BGD_DECLARE(int) gdMajorVersion(void); +BGD_DECLARE(int) gdMinorVersion(void); +BGD_DECLARE(int) gdReleaseVersion(void); +BGD_DECLARE(const char *) gdExtraVersion(void); +BGD_DECLARE(const char *) gdVersionString(void); + +/* newfangled special effects */ +#include "gdfx.h" + +#ifdef __cplusplus +} +#endif + +#endif /* GD_H */ diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_color.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_color.h new file mode 100644 index 0000000000..08b06cee09 --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_color.h @@ -0,0 +1,14 @@ +#ifndef GD_COLOR_H +#define GD_COLOR_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + + int gdColorMatch(gdImagePtr im, int col1, int col2, float threshold); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_color_map.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_color_map.h new file mode 100644 index 0000000000..6d2275e564 --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_color_map.h @@ -0,0 +1,30 @@ +#ifndef GD_COLOR_MAP_H +#define GD_COLOR_MAP_H 1 + +#include "gd.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + char *color_name; + int red; + int green; + int blue; +} gdColorMapEntry; + +typedef struct { + int num_entries; + gdColorMapEntry *entries; +} gdColorMap; + +extern BGD_EXPORT_DATA_PROT gdColorMap GD_COLOR_MAP_X11; + +BGD_DECLARE(int) gdColorMapLookup(const gdColorMap color_map, const char *color_name, int *r, int *g, int *b); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_errors.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_errors.h new file mode 100644 index 0000000000..4ecee94b38 --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_errors.h @@ -0,0 +1,46 @@ +#ifndef GD_ERRORS_H +#define GD_ERRORS_H + +#ifndef _WIN32 +# include +#else +/* + * priorities/facilities are encoded into a single 32-bit quantity, where the + * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility + * (0-big number). Both the priorities and the facilities map roughly + * one-to-one to strings in the syslogd(8) source code. This mapping is + * included in this file. + * + * priorities (these are ordered) + */ +# define LOG_EMERG 0 /* system is unusable */ +# define LOG_ALERT 1 /* action must be taken immediately */ +# define LOG_CRIT 2 /* critical conditions */ +# define LOG_ERR 3 /* error conditions */ +# define LOG_WARNING 4 /* warning conditions */ +# define LOG_NOTICE 5 /* normal but significant condition */ +# define LOG_INFO 6 /* informational */ +# define LOG_DEBUG 7 /* debug-level messages */ +#endif + +/* +LOG_EMERG system is unusable +LOG_ALERT action must be taken immediately +LOG_CRIT critical conditions +LOG_ERR error conditions +LOG_WARNING warning conditions +LOG_NOTICE normal, but significant, condition +LOG_INFO informational message +LOG_DEBUG debug-level message +*/ + +#define GD_ERROR LOG_ERR +#define GD_WARNING LOG_WARNING +#define GD_NOTICE LOG_NOTICE +#define GD_INFO LOG_INFO +#define GD_DEBUG LOG_DEBUG + +void gd_error(const char *format, ...); +void gd_error_ex(int priority, const char *format, ...); + +#endif diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_intern.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_intern.h new file mode 100644 index 0000000000..380f4db2c2 --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_intern.h @@ -0,0 +1,92 @@ +/* Internal header for random common utility functions. */ + +#ifndef GD_INTERN_H +#define GD_INTERN_H + +#include + +#ifndef MAXPATHLEN +# ifdef PATH_MAX +# define MAXPATHLEN PATH_MAX +# elif defined(MAX_PATH) +# define MAXPATHLEN MAX_PATH +# else +# if defined(__GNU__) +# define MAXPATHLEN 4096 +# else +# define MAXPATHLEN 256 /* Should be safe for any weird systems that do not define it */ +# endif +# endif +#endif + +#ifdef HAVE_STDINT_H +# include +#else +# if defined(HAVE_INTTYPES_H) +# include +# else +# include "msinttypes/inttypes.h" +# endif +#endif + +#ifdef _MSC_VER +#define ssize_t SSIZE_T +#define MAXSIZE_T ((SIZE_T)~ ((SIZE_T)0)) +#define MAXSSIZE_T ((SSIZE_T) (MAXSIZE_T >> 1)) +#define MINSSIZE_T ((SSIZE_T)~MAXSSIZE_T) +#define SSIZE_MAX MAXSSIZE_T +#endif + +#include "gd.h" + +#define MIN(a,b) ((a)<(b)?(a):(b)) +#define MIN3(a,b,c) ((a)<(b)?(MIN(a,c)):(MIN(b,c))) +#define MAX(a,b) ((a)<(b)?(b):(a)) +#define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c))) +#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) + +typedef enum { + HORIZONTAL, + VERTICAL, +} gdAxis; + +/* Convert a double to an unsigned char, rounding to the nearest + * integer and clamping the result between 0 and max. The absolute + * value of clr must be less than the maximum value of an unsigned + * short. */ +static inline unsigned char +uchar_clamp(double clr, unsigned char max) { + unsigned short result; + + //assert(fabs(clr) <= SHRT_MAX); + + /* Casting a negative float to an unsigned short is undefined. + * However, casting a float to a signed truncates toward zero and + * casting a negative signed value to an unsigned of the same size + * results in a bit-identical value (assuming twos-complement + * arithmetic). This is what we want: all legal negative values + * for clr will be greater than 255. */ + + /* Convert and clamp. */ + result = (unsigned short)(short)(clr + 0.5); + if (result > max) { + result = (clr < 0) ? 0 : max; + }/* if */ + + return result; +}/* uchar_clamp*/ + + +/* Internal prototypes: */ + +/* gd_rotate.c */ +gdImagePtr gdImageRotate90(gdImagePtr src, int ignoretransparent); +gdImagePtr gdImageRotate180(gdImagePtr src, int ignoretransparent); +gdImagePtr gdImageRotate270(gdImagePtr src, int ignoretransparent); + + + + + + +#endif diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_io.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_io.h new file mode 100644 index 0000000000..f6bd4d6ea2 --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_io.h @@ -0,0 +1,89 @@ +#ifndef GD_IO_H +#define GD_IO_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + Group: Types + + typedef: gdIOCtx + + gdIOCtx structures hold function pointers for doing image IO. + + Most of the gd functions that read and write files, such as + also have variants that accept a structure; + see and . + + Those who wish to provide their own custom routines to read and + write images can populate a gdIOCtx structure with functions of + their own devising to to read and write data. For image reading, the + only mandatory functions are getC and getBuf, which must return the + number of characters actually read, or a negative value on error or + EOF. These functions must read the number of characters requested + unless at the end of the file. + + For image writing, the only mandatory functions are putC and putBuf, + which return the number of characters written; these functions must + write the number of characters requested except in the event of an + error. The seek and tell functions are only required in conjunction + with the gd2 file format, which supports quick loading of partial + images. The gd_free function will not be invoked when calling the + standard Ctx functions; it is an implementation convenience when + adding new data types to gd. For examples, see gd_png.c, gd_gd2.c, + gd_jpeg.c, etc., all of which rely on gdIOCtx to implement the + standard image read and write functions. + + > typedef struct gdIOCtx + > { + > int (*getC)(gdIOCtxPtr); + > int (*getBuf)(gdIOCtxPtr, void *, int wanted); + > + > void (*putC)(gdIOCtxPtr, int); + > int (*putBuf)(gdIOCtxPtr, const void *, int wanted); + > + > // seek must return 1 on SUCCESS, 0 on FAILURE. Unlike fseek! + > int (*seek)(gdIOCtxPtr, const int); + > long (*tell)(gdIOCtxPtr); + > + > void (*gd_free)(gdIOCtxPtr); + > } gdIOCtx; + */ +typedef struct gdIOCtx *gdIOCtxPtr; + +typedef struct gdIOCtx { + int (*getC)(gdIOCtxPtr); + int (*getBuf)(gdIOCtxPtr, void *, int); + void (*putC)(gdIOCtxPtr, int); + int (*putBuf)(gdIOCtxPtr, const void *, int); + /* seek must return 1 on SUCCESS, 0 on FAILURE. Unlike fseek! */ + int (*seek)(gdIOCtxPtr, const int); + long (*tell)(gdIOCtxPtr); + void (*gd_free)(gdIOCtxPtr); + void *data; +} gdIOCtx; + +void gdPutC(const unsigned char c, gdIOCtxPtr ctx); +int gdPutBuf(const void *, int, gdIOCtxPtr); +void gdPutWord(int w, gdIOCtxPtr ctx); +void gdPutInt(int w, gdIOCtxPtr ctx); + +int gdGetC(gdIOCtxPtr ctx); +int gdGetBuf(void *, int, gdIOCtxPtr); +int gdGetByte(int *result, gdIOCtxPtr ctx); +int gdGetWord(int *result, gdIOCtxPtr ctx); +int gdGetWordLSB(signed short int *result, gdIOCtxPtr ctx); +int gdGetInt(int *result, gdIOCtxPtr ctx); +int gdGetIntLSB(signed int *result, gdIOCtxPtr ctx); + +int gdSeek(gdIOCtxPtr ctx, const int offset); +long gdTell(gdIOCtxPtr ctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_io_stream.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_io_stream.h new file mode 100644 index 0000000000..d682c2fd9d --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_io_stream.h @@ -0,0 +1,125 @@ +/* ***************************************************************************** +** Initial file written and documented by: +** Kevin Shepherd December 2007 +** of Scarlet Line http://www.scarletline.com/ +*******************************************************************************/ +/** \file gd_io_stream.h + \brief C++ standard library iostream specializations of gdIOCtx. + + Note that all of the methods defined in this header are internal to the + libgd library, except for the constructors. + Only the constructors are needed by a user of the libgd API. + This file does not use or need gdpp.h, but if GD::Image is + used, then C++ coding becomes even simpler, and the classes below + become entirely hidden implementation details. + Example usage, convert png to gif: + #include + #include "gd_io_stream.h" + std::ifstream in("image.png", std::ios_base::in | std::ios_base::binary ); + if (in.good()) + { + istreamIOCtx _in_ctx(in); + gdImagePtr im_in = gdImageCreateFromPngCtx ( & _in_ctx); + std::ofstream out("image.gif", std::ios_base::out | std::ios_base::binary ); + ostreamIOCtx _out_ctx(out); + gdImageGifCtx(im_in, & _out_ctx); + } + gdImageDestroy(im_in); +*/ +#ifndef _gd_io_stream_h +#define _gd_io_stream_h +#ifdef __cplusplus + +#include "gd.h" +#include + +/** Standard library input stream specialization of gdIOCtx +*/ +class BGD_EXPORT_DATA_IMPL istreamIOCtx : public gdIOCtx +{ +public: + typedef std::istream stream_type; + /** Construct an instance of this input stream specialization, + given an input stream. + For example: + std::ifstream in("image.png", std::ios_base::in | std::ios_base::binary ); + istreamIOCtx in_ctx(in); + */ + istreamIOCtx(stream_type & __stream) { + init( & __stream); + } + + static int Getbuf(gdIOCtxPtr ctx, void *buf, int size); + static int Putbuf(gdIOCtxPtr, const void *, int); + static void Putchar(gdIOCtxPtr, int); + static int Getchar(gdIOCtxPtr ctx); + static int Seek(gdIOCtxPtr ctx, const int pos); + static long Tell(gdIOCtxPtr ctx); + static void FreeCtx(gdIOCtxPtr ctx); + + void init(stream_type * __stream) { + getC = Getchar; + putC = Putchar; + getBuf = Getbuf; + putBuf = Putbuf; + tell = Tell; + seek = Seek; + gd_free = FreeCtx; + _M_stream = __stream; + } +private: + stream_type * _M_stream; +}; +/** Allocate a new instance of the class +*/ +inline gdIOCtxPtr gdNewIstreamCtx(std::istream *__stream) +{ + return new istreamIOCtx(* __stream); +} + +/** Standard library output stream specialization of gdIOCtx +*/ +class BGD_EXPORT_DATA_IMPL ostreamIOCtx : public gdIOCtx +{ +public: + typedef std::ostream stream_type; + /** Construct an instance of this output stream specialization, + given an output stream. + For example: + std::ofstream out("image.gif", std::ios_base::out | std::ios_base::binary ); + ostreamIOCtx out_ctx(out); + */ + ostreamIOCtx(stream_type & __stream) { + init( & __stream); + } + + static int Getbuf(gdIOCtxPtr, void *, int); + static int Putbuf(gdIOCtxPtr ctx, const void *buf, int size); + static int Getchar(gdIOCtxPtr); + static void Putchar(gdIOCtxPtr ctx, int a); + static int Seek(gdIOCtxPtr ctx, const int pos); + static long Tell(gdIOCtxPtr ctx); + static void FreeCtx(gdIOCtxPtr ctx); + + void init(stream_type * __stream) { + getC = Getchar; + putC = Putchar; + getBuf = Getbuf; + putBuf = Putbuf; + tell = Tell; + seek = Seek; + gd_free = FreeCtx; + _M_stream = __stream; + } +private: + stream_type * _M_stream; +}; +/** Allocate a new instance of the class +*/ +inline gdIOCtxPtr gdNewOstreamCtx(std::ostream *__stream) +{ + return new ostreamIOCtx(* __stream); +} + +#endif /* __cplusplus */ +#endif /* _gd_io_stream_h */ diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_nnquant.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_nnquant.h new file mode 100644 index 0000000000..11643b7d62 --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_nnquant.h @@ -0,0 +1,16 @@ +/* maximum number of colours that can be used. + actual number is now passed to initcolors */ +#define MAXNETSIZE 256 + +/* For 256 colours, fixed arrays need 8kb, plus space for the image + ---------------------------------------------------------------- */ + + +/* four primes near 500 - assume no image has a length so large */ +/* that it is divisible by all four primes */ +#define prime1 499 +#define prime2 491 +#define prime3 487 +#define prime4 503 + +#define minpicturebytes (4*prime4) /* minimum size for input image */ diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_tga.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_tga.h new file mode 100644 index 0000000000..b56e2e41f9 --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gd_tga.h @@ -0,0 +1,52 @@ +#ifndef __TGA_H +#define __TGA_H 1 + +#include "gd.h" +#include "gdhelpers.h" + +#include "gd_intern.h" + +typedef struct oTga_ { + uint8_t identsize; // size of ID field that follows 18 uint8_t header (0 usually) + uint8_t colormaptype; // type of colour map 0=none, 1=has palette [IGNORED] Adrian requested no support + uint8_t imagetype; // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed + + int colormapstart; // first colour map entry in palette [IGNORED] Adrian requested no support + int colormaplength; // number of colours in palette [IGNORED] Adrian requested no support + uint8_t colormapbits; // number of bits per palette entry 15,16,24,32 [IGNORED] Adrian requested no support + + int xstart; // image x origin + int ystart; // image y origin + int width; // image width in pixels + int height; // image height in pixels + uint8_t bits; // image bits per pixel 8,16,24,32 + uint8_t alphabits; // alpha bits (low 4bits of header 17) + uint8_t fliph; // horizontal or vertical + uint8_t flipv; // flip + char *ident; // identifcation tag string + int *bitmap; // bitmap data + +} oTga; + +#define TGA_TYPE_NO_IMAGE 0 +#define TGA_TYPE_INDEXED 1 +#define TGA_TYPE_RGB 2 +#define TGA_TYPE_GREYSCALE 3 +#define TGA_TYPE_INDEXED_RLE 9 +#define TGA_TYPE_RGB_RLE 10 +#define TGA_TYPE_GREYSCALE_RLE 11 +#define TGA_TYPE_INDEXED_HUFFMAN_DELTA_RLE 32 +#define TGA_TYPE_RGB_HUFFMAN_DELTA_QUADTREE_RLE 33 + +#define TGA_BPP_8 8 +#define TGA_BPP_16 16 +#define TGA_BPP_24 24 +#define TGA_BPP_32 32 + +#define TGA_RLE_FLAG 128 + +int read_header_tga(gdIOCtxPtr ctx, oTga *tga); +int read_image_tga(gdIOCtxPtr ctx, oTga *tga); +void free_tga(oTga *tga); + +#endif //__TGA_H diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdcache.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdcache.h new file mode 100644 index 0000000000..751a842154 --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdcache.h @@ -0,0 +1,90 @@ +#ifdef __cplusplus +extern "C" { +#endif + + /* + * gdcache.h + * + * Caches of pointers to user structs in which the least-recently-used + * element is replaced in the event of a cache miss after the cache has + * reached a given size. + * + * John Ellson (ellson@graphviz.org) Oct 31, 1997 + * + * Test this with: + * gcc -o gdcache -g -Wall -DTEST -DNEED_CACHE gdcache.c -lgd + * or + * gcc -o gdcache -g -Wall -DTEST -DNEED_CACHE gdcache.c libgd.a + * + * The cache is implemented by a singly-linked list of elements + * each containing a pointer to a user struct that is being managed by + * the cache. + * + * The head structure has a pointer to the most-recently-used + * element, and elements are moved to this position in the list each + * time they are used. The head also contains pointers to three + * user defined functions: + * - a function to test if a cached userdata matches some keydata + * - a function to provide a new userdata struct to the cache + * if there has been a cache miss. + * - a function to release a userdata struct when it is + * no longer being managed by the cache + * + * In the event of a cache miss the cache is allowed to grow up to + * a specified maximum size. After the maximum size is reached then + * the least-recently-used element is discarded to make room for the + * new. The most-recently-returned value is always left at the + * beginning of the list after retrieval. + * + * In the current implementation the cache is traversed by a linear + * search from most-recent to least-recent. This linear search + * probably limits the usefulness of this implementation to cache + * sizes of a few tens of elements. + */ + + /*********************************************************/ + /* header */ + /*********************************************************/ + +#include +#ifndef NULL +# define NULL (void *)0 +#endif + + /* user defined function templates */ + typedef int (*gdCacheTestFn_t)(void *userdata, void *keydata); + typedef void *(*gdCacheFetchFn_t)(char **error, void *keydata); + typedef void (*gdCacheReleaseFn_t)(void *userdata); + + /* element structure */ + typedef struct gdCache_element_s gdCache_element_t; + struct gdCache_element_s { + gdCache_element_t *next; + void *userdata; + }; + + /* head structure */ + typedef struct gdCache_head_s gdCache_head_t; + struct gdCache_head_s { + gdCache_element_t *mru; + int size; + char *error; + gdCacheTestFn_t gdCacheTest; + gdCacheFetchFn_t gdCacheFetch; + gdCacheReleaseFn_t gdCacheRelease; + }; + + /* function templates */ + gdCache_head_t *gdCacheCreate(int size, + gdCacheTestFn_t gdCacheTest, + gdCacheFetchFn_t gdCacheFetch, + gdCacheReleaseFn_t gdCacheRelease + ); + + void gdCacheDelete(gdCache_head_t *head); + + void *gdCacheGet(gdCache_head_t *head, void *keydata); + +#ifdef __cplusplus +} +#endif diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdfontg.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdfontg.h new file mode 100644 index 0000000000..5d85812cf4 --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdfontg.h @@ -0,0 +1,28 @@ +#ifndef _GDFONTG_H_ +#define _GDFONTG_H_ 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + This is a header file for gd font, generated using + bdftogd version 0.51 by Jan Pazdziora, adelton@fi.muni.cz + from bdf font + -Misc-Fixed-Bold-R-Normal-Sans-15-140-75-75-C-90-ISO8859-2 + at Mon Jan 26 14:45:58 1998. + The original bdf was holding following copyright: + "Libor Skarvada, libor@informatics.muni.cz" + */ + +#include "gd.h" + +extern BGD_EXPORT_DATA_PROT gdFontPtr gdFontGiant; +BGD_DECLARE(gdFontPtr) gdFontGetGiant(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdfontl.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdfontl.h new file mode 100644 index 0000000000..2fc91ca6bf --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdfontl.h @@ -0,0 +1,29 @@ +#ifndef _GDFONTL_H_ +#define _GDFONTL_H_ 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + This is a header file for gd font, generated using + bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz + from bdf font + -misc-fixed-medium-r-normal--16-140-75-75-c-80-iso8859-2 + at Tue Jan 6 19:39:27 1998. + + The original bdf was holding following copyright: + "Libor Skarvada, libor@informatics.muni.cz" + */ + +#include "gd.h" + +extern BGD_EXPORT_DATA_PROT gdFontPtr gdFontLarge; +BGD_DECLARE(gdFontPtr) gdFontGetLarge(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdfontmb.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdfontmb.h new file mode 100644 index 0000000000..e6807db4eb --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdfontmb.h @@ -0,0 +1,27 @@ +#ifndef _GDFONTMB_H_ +#define _GDFONTMB_H_ 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + This is a header file for gd font, generated using + bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz + from bdf font + -misc-fixed-bold-r-normal-sans-13-94-100-100-c-70-iso8859-2 + at Thu Jan 8 13:54:57 1998. + No copyright info was found in the original bdf. + */ + +#include "gd.h" + +extern BGD_EXPORT_DATA_PROT gdFontPtr gdFontMediumBold; +BGD_DECLARE(gdFontPtr) gdFontGetMediumBold(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdfonts.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdfonts.h new file mode 100644 index 0000000000..b5127e971a --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdfonts.h @@ -0,0 +1,27 @@ +#ifndef _GDFONTS_H_ +#define _GDFONTS_H_ 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + This is a header file for gd font, generated using + bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz + from bdf font + -misc-fixed-medium-r-semicondensed-sans-12-116-75-75-c-60-iso8859-2 + at Thu Jan 8 14:13:20 1998. + No copyright info was found in the original bdf. + */ + +#include "gd.h" + +extern BGD_EXPORT_DATA_PROT gdFontPtr gdFontSmall; +BGD_DECLARE(gdFontPtr) gdFontGetSmall(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdfontt.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdfontt.h new file mode 100644 index 0000000000..d61b01ff4a --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdfontt.h @@ -0,0 +1,28 @@ +#ifndef _GDFONTT_H_ +#define _GDFONTT_H_ 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + This is a header file for gd font, generated using + bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz + from bdf font + -Misc-Fixed-Medium-R-Normal--8-80-75-75-C-50-ISO8859-2 + at Thu Jan 8 13:49:54 1998. + The original bdf was holding following copyright: + "Libor Skarvada, libor@informatics.muni.cz" + */ + +#include "gd.h" + +extern BGD_EXPORT_DATA_PROT gdFontPtr gdFontTiny; +BGD_DECLARE(gdFontPtr) gdFontGetTiny(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdfx.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdfx.h new file mode 100644 index 0000000000..b00f573a60 --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdfx.h @@ -0,0 +1,29 @@ +#ifndef GDFX_H +#define GDFX_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +BGD_DECLARE(gdImagePtr) gdImageSquareToCircle(gdImagePtr im, int radius); + +BGD_DECLARE(char *) gdImageStringFTCircle( + gdImagePtr im, + int cx, + int cy, + double radius, + double textRadius, + double fillPortion, + char *font, + double points, + char *top, + char *bottom, + int fgcolor); + +BGD_DECLARE(void) gdImageSharpen (gdImagePtr im, int pct); + +#ifdef __cplusplus +} +#endif + +#endif /* GDFX_H */ diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdhelpers.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdhelpers.h new file mode 100644 index 0000000000..9b187af7fa --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdhelpers.h @@ -0,0 +1,76 @@ +#ifndef GDHELPERS_H +#define GDHELPERS_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + + /* sys/types.h is needed for size_t on Sparc-SunOS-4.1 */ +#ifndef _WIN32_WCE +#include +#else +#include +#endif /* _WIN32_WCE */ + + /* TBB: strtok_r is not universal; provide an implementation of it. */ + + char *gd_strtok_r(char *s, const char *sep, char **state); + + /* These functions wrap memory management. gdFree is + in gd.h, where callers can utilize it to correctly + free memory allocated by these functions with the + right version of free(). */ + void *gdCalloc(size_t nmemb, size_t size) BGD_MALLOC; + void *gdMalloc(size_t size) BGD_MALLOC; + void *gdRealloc (void *ptr, size_t size); + /* The extended version of gdReallocEx will free *ptr if the + * realloc fails */ + void *gdReallocEx (void *ptr, size_t size); + + /* Returns nonzero if multiplying the two quantities will + result in integer overflow. Also returns nonzero if + either quantity is negative. By Phil Knirsch based on + netpbm fixes by Alan Cox. */ + + int overflow2(int a, int b); + + /* 2.0.16: portable mutex support for thread safety. */ +#if defined(CPP_SHARP) +# define gdMutexDeclare(x) +# define gdMutexSetup(x) +# define gdMutexShutdown(x) +# define gdMutexLock(x) +# define gdMutexUnlock(x) +#elif defined(_WIN32) + /* 2.0.18: must include windows.h to get CRITICAL_SECTION. */ +# include +# define gdMutexDeclare(x) CRITICAL_SECTION x +# define gdMutexSetup(x) InitializeCriticalSection(&x) +# define gdMutexShutdown(x) DeleteCriticalSection(&x) +# define gdMutexLock(x) EnterCriticalSection(&x) +# define gdMutexUnlock(x) LeaveCriticalSection(&x) +#elif defined(HAVE_PTHREAD) +# include +# define gdMutexDeclare(x) pthread_mutex_t x +# define gdMutexSetup(x) pthread_mutex_init(&x, 0) +# define gdMutexShutdown(x) pthread_mutex_destroy(&x) +# define gdMutexLock(x) pthread_mutex_lock(&x) +# define gdMutexUnlock(x) pthread_mutex_unlock(&x) +#else +# define gdMutexDeclare(x) +# define gdMutexSetup(x) +# define gdMutexShutdown(x) +# define gdMutexLock(x) +# define gdMutexUnlock(x) +#endif /* _WIN32 || HAVE_PTHREAD */ + +#define DPCM2DPI(dpcm) (unsigned int)((dpcm)*2.54 + 0.5) +#define DPM2DPI(dpm) (unsigned int)((dpm)*0.0254 + 0.5) +#define DPI2DPCM(dpi) (unsigned int)((dpi)/2.54 + 0.5) +#define DPI2DPM(dpi) (unsigned int)((dpi)/0.0254 + 0.5) + +#ifdef __cplusplus +} +#endif + +#endif /* GDHELPERS_H */ diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdpp.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdpp.h new file mode 100644 index 0000000000..635f2c402d --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/gdpp.h @@ -0,0 +1,1530 @@ +/* ***************************************************************************** +** Initial file written and documented by: +** Kevin Shepherd December 2007 +** of Scarlet Line http://www.scarletline.com/ +** with contributions from Torben Nielsen. +*******************************************************************************/ +/** \file gdpp.h + \brief Object Oriented C++ wrappers around libgd functionality. + + Example usage, convert png to gif: + #include + #include + + std::ifstream in("image.png", std::ios_base::in | std::ios_base::binary ); + GD::Image im(in, GD::Png_tag()); + if (im.good()) + { + std::ofstream out("image.gif", std::ios_base::out | std::ios_base::binary ); + im.Gif(out); + } +*/ +#ifndef _gdpp_h +#define _gdpp_h +#ifdef __cplusplus + +#include "gd_io_stream.h" +#include + +/// namespace GD:: contains the C++ wrapper classes for libgd +/** This namespace is primarily to avoid name clashes, and to + contain all of the gd classes within one namespace. + It is not recommended to use the "using namespace" directive with this namespace. + Example usage: + GD::Image im(64, 32, true); // Create a truecolor image 64 pixels wide by 32 pixels high + GD::Point pt(10, 8); // The point at x=10, y=8. + GD::Size sz(16, 8); // The size width=16, height=8. + GD::TrueColor col(0xFF, 0, 0); // The colour red; R=255, G=0, B=0. + im.Rectangle(pt, sz, col.Int()); // Draw a red rectangle with top left corner at pt, of size sz. +*/ +namespace GD +{ +/** This class GD::Point stores a point in two dimensions, somewhere + on the plane of an image. +*/ +class BGD_EXPORT_DATA_PROT Point +{ +public: + // Constructors + Point(int x, int y) + :_x(x), _y(y) {} + Point(const Point & p) + :_x(p._x), _y(p._y) {} + Point() + :_x(0), _y(0) {} + Point & operator=(const Point & p) { + _x = p._x; + _y = p._y; + return (* this); + } + // Accessors + int X() const { + return _x; + } + int Y() const { + return _y; + } + // Updaters + void X(int x) { + _x = x; + } + void Y(int y) { + _y = y; + } + void set(int x, int y) { + _x = x; + _y = y; + } + int & lhsX() { + return _x; + } + int & lhsY() { + return _y; + } + + gdPointPtr as_gdPointPtr() { + return (gdPointPtr) this; + } +protected: + int _x, _y; +}; +typedef Point * PointPtr; +/** This class GD::Size stores length in two dimensions. + Giving the size of an area as width and height. +*/ +class BGD_EXPORT_DATA_PROT Size +{ +public: + // Constructors + Size(int w, int h) + :_w(w), _h(h) {} + Size(const Size & p) + :_w(p._w), _h(p._h) {} + Size() + :_w(0), _h(0) {} + Size & operator=(const Size & p) { + _w = p._w; + _h = p._h; + return (* this); + } + // Accessors + int W() const { + return _w; + } + int H() const { + return _h; + } + // Updaters + void W(int w) { + _w = w; + } + void H(int h) { + _h = h; + } + void set(int w, int h) { + _w = w; + _h = h; + } + int & lhsW() { + return _w; + } + int & lhsH() { + return _h; + } +protected: + int _w, _h; +}; +typedef Size * SizePtr; + +/** This class GD::TrueColor stores a colour as an RGBA quadruplet. + It can also be read as an integer, and in other colour formats. +*/ +class BGD_EXPORT_DATA_PROT TrueColor +{ +public: + union as_types { + int as_int; + struct uchars { + unsigned char blue, green, red, alpha; + } as_uchar; + }; + TrueColor() { + internal.as_int = 0; + } + TrueColor(int c) { + internal.as_int = c; + } + TrueColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 0) { + internal.as_uchar.alpha = a; + internal.as_uchar.red = r; + internal.as_uchar.green = g; + internal.as_uchar.blue = b; + } + // Accessors + int Int() const { + return internal.as_int; + } + unsigned char Red() const { + return internal.as_uchar.red; + } + unsigned char Green() const { + return internal.as_uchar.green; + } + unsigned char Blue() const { + return internal.as_uchar.blue; + } + unsigned char Alpha() const { + return internal.as_uchar.alpha; + } + // Updaters + void set(int c) { + internal.as_int = c; + } + void set(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 0) { + internal.as_uchar.alpha = a; + internal.as_uchar.red = r; + internal.as_uchar.green = g; + internal.as_uchar.blue = b; + } + void Red(unsigned char c) { + internal.as_uchar.red = c; + } + void Green(unsigned char c) { + internal.as_uchar.green = c; + } + void Blue(unsigned char c) { + internal.as_uchar.blue = c; + } + void Alpha(unsigned char c) { + internal.as_uchar.alpha = c; + } +protected: + as_types internal; +}; +/* The following tags are simply empty structures which are used + to tell the compiler which constructor we want when we know + the image file format. +*/ +struct BGD_EXPORT_DATA_PROT Png_tag {}; +struct BGD_EXPORT_DATA_PROT Gif_tag {}; +struct BGD_EXPORT_DATA_PROT WBMP_tag {}; +struct BGD_EXPORT_DATA_PROT Jpeg_tag {}; +struct BGD_EXPORT_DATA_PROT Gd_tag {}; +struct BGD_EXPORT_DATA_PROT Gd2_tag {}; +struct BGD_EXPORT_DATA_PROT Xbm_tag {}; + +/** This class GD::Image wraps all of the 'C' libgd functionality + for the convenience of C++ users. An instance of this class + corresponds to a single image. +*/ +class BGD_EXPORT_DATA_PROT Image +{ +public: + /** Construct a null image + */ + Image() + :im(0) + {} + /** Construct a blank image, of the given size and colour format type. + \param[in] sx Width of the image + \param[in] sy Height of the image + \param[in] istruecolor Create a true colour image, defaults to false, i.e. create an indexed palette image. + */ + Image(int sx, int sy, bool istruecolor = false) + :im(0) { + if (istruecolor) + CreateTrueColor(sx, sy); + else + Create(sx, sy); + } + /** Construct a blank image, of the given size and colour format type. + \param[in] s Width and height of the image + \param[in] istruecolor Create a true colour image, defaults to false, i.e. create an indexed palette image. + */ + Image(const Size & s, bool istruecolor = false) + :im(0) { + if (istruecolor) + CreateTrueColor(s); + else + Create(s); + } + /** Construct an instance of the GD::Image class, given the internal gdImage poimter. + Note that gdImageDestroy will be called on the image pointer in the destructor. + \param[in] i Pointer to the internal gdImage + */ + Image(gdImagePtr i) + :im(i) {} + /** Copy constructor. Construct an instance of the GD::Image class, + by making a copy of the GD::Image provided. + \param[in] i Reference to the image to be copied + */ + Image(const GD::Image & i) + :im(0) { + Copy(i); + } + /** Construct an image by reading from \p in. This constructor + will first attempt to determine the file format. + \param[in] in The stream containing the image data + */ + Image(std::istream & in) + :im(0) { + CreateFrom(in); + } + /** Construct an image by reading from \p in. This constructor + will first attempt to determine the file format. + \param[in] in An opened FILE * handle to a file containing the image data + */ + Image(FILE * in) + :im(0) { + CreateFrom(in); + } + /** Construct an image by reading from memory block \p data. This constructor + will first attempt to determine the image formatting. + \param[in] size The byte count of the memory block + \param[in] data Pointer to the memory block + */ + Image(int size, void * data) + :im(0) { + CreateFrom(size, data); + } + + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Png_tag()); // read a png file from input + \param[in] in The stream containing the image data + */ + Image(std::istream & in, Png_tag) + :im(0) { + CreateFromPng(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Png_tag()); // read a png file from input + \param[in] in An opened FILE * handle to a file containing the image data + */ + Image(FILE * in, Png_tag) + :im(0) { + CreateFromPng(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Png_tag()); // read a png file from input + \param[in] in The io context from which to read the image data + */ + Image(gdIOCtxPtr in, Png_tag) + :im(0) { + CreateFromPng(in); + } + /** Construct an image by reading from memory block \p data. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(sz, dat, GD::Png_tag()); // read a png file from dat + \param[in] size The byte count of the memory block + \param[in] data Pointer to the memory block + */ + Image(int size, void * data, Png_tag) + :im(0) { + CreateFromPng(size, data); + } + + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Gif_tag()); // read a gif file from input + \param[in] in The stream containing the image data + */ + Image(std::istream & in, Gif_tag) + :im(0) { + CreateFromGif(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Gif_tag()); // read a gif file from input + \param[in] in An opened FILE * handle to a file containing the image data + */ + Image(FILE * in, Gif_tag) + :im(0) { + CreateFromGif(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Gif_tag()); // read a gif file from input + \param[in] in The io context from which to read the image data + */ + Image(gdIOCtxPtr in, Gif_tag) + :im(0) { + CreateFromGif(in); + } + /** Construct an image by reading from memory block \p data. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(sz, dat, GD::Gif_tag()); // read a gif file from dat + \param[in] size The byte count of the memory block + \param[in] data Pointer to the memory block + */ + Image(int size, void * data, Gif_tag) + :im(0) { + CreateFromGif(size, data); + } + + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::WBMP_tag()); // read a monchrome WBMP file from input + \param[in] in The stream containing the image data + */ + Image(std::istream & in, WBMP_tag) + :im(0) { + CreateFromWBMP(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::WBMP_tag()); // read a monchrome WBMP file from input + \param[in] in An opened FILE * handle to a file containing the image data + */ + Image(FILE * in, WBMP_tag) + :im(0) { + CreateFromWBMP(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::WBMP_tag()); // read a monchrome WBMP file from input + \param[in] in The io context from which to read the image data + */ + Image(gdIOCtxPtr in, WBMP_tag) + :im(0) { + CreateFromWBMP(in); + } + /** Construct an image by reading from memory block \p data. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(sz, dat, GD::WBMP_tag()); // read a monchrome WBMP file from dat + \param[in] size The byte count of the memory block + \param[in] data Pointer to the memory block + */ + Image(int size, void * data, WBMP_tag) + :im(0) { + CreateFromWBMP(size, data); + } + + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Jpeg_tag()); // read a jpeg file from input + \param[in] in The stream containing the image data + */ + Image(std::istream & in, Jpeg_tag) + :im(0) { + CreateFromJpeg(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Jpeg_tag()); // read a jpeg file from input + \param[in] in An opened FILE * handle to a file containing the image data + */ + Image(FILE * in, Jpeg_tag) + :im(0) { + CreateFromJpeg(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Jpeg_tag()); // read a jpeg file from input + \param[in] in The io context from which to read the image data + */ + Image(gdIOCtxPtr in, Jpeg_tag) + :im(0) { + CreateFromJpeg(in); + } + /** Construct an image by reading from memory block \p data. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(sz, dat, GD::Jpeg_tag()); // read a jpeg file from dat + \param[in] size The byte count of the memory block + \param[in] data Pointer to the memory block + */ + Image(int size, void * data, Jpeg_tag) + :im(0) { + CreateFromJpeg(size, data); + } + + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Gd_tag()); // read a gd file from input + \param[in] in The stream containing the image data + */ + Image(std::istream & in, Gd_tag) + :im(0) { + CreateFromGd(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Gd_tag()); // read a gd file from input + \param[in] in An opened FILE * handle to a file containing the image data + */ + Image(FILE * in, Gd_tag) + :im(0) { + CreateFromGd(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Gd_tag()); // read a gd file from input + \param[in] in The io context from which to read the image data + */ + Image(gdIOCtxPtr in, Gd_tag) + :im(0) { + CreateFromGd(in); + } + /** Construct an image by reading from memory block \p data. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(sz, dat, GD::Gd_tag()); // read a gd file from dat + \param[in] size The byte count of the memory block + \param[in] data Pointer to the memory block + */ + Image(int size, void * data, Gd_tag) + :im(0) { + CreateFromGd(size, data); + } + + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Gd2_tag()); // read a gd2 file from input + \param[in] in The stream containing the image data + */ + Image(std::istream & in, Gd2_tag) + :im(0) { + CreateFromGd2(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Png_tag()); // read a png file from input + \param[in] in An opened FILE * handle to a file containing the image data + */ + Image(FILE * in, Gd2_tag) + :im(0) { + CreateFromGd2(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Gd2_tag()); // read a gd2 file from input + \param[in] in The io context from which to read the image data + */ + Image(gdIOCtxPtr in, Gd2_tag) + :im(0) { + CreateFromGd2(in); + } + /** Construct an image by reading from memory block \p data. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(sz, dat, GD::Gd2_tag()); // read a gd2 file from dat + \param[in] size The byte count of the memory block + \param[in] data Pointer to the memory block + */ + Image(int size, void * data, Gd2_tag) + :im(0) { + CreateFromGd2(size, data); + } + + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Xbm_tag()); // read an xbm file from input + \param[in] in An opened FILE * handle to a file containing the image data + */ + Image(FILE * in, Xbm_tag) + :im(0) { + CreateFromXbm(in); + } + + ~Image() { + clear(); + } + + /** Assignment Operator. Make this a copy of the GD::Image provided. + \param[in] src Reference to the image to be copied + */ + GD::Image & operator=(const GD::Image & src) { + Copy(src); + return (* this); + } + /** Make this an exact copy of the GD::Image provided. Any existing iamge data is discarded. + \param[in] src Reference to the image to be copied + */ + void Copy(const GD::Image & src) { + int w = src.Width(), h = src.Height(); + if (src.IsTrueColor()) + CreateTrueColor(w, h); + else { + Create(w, h); + PaletteCopy(src); + } + Copy(src, 0, 0, 0, 0, w, h); + } + /** Check to see if this appears to be a valid image + */ + bool good() const { + return (im != 0); + } + // Creation: + /** + Create a palette-based image, with no more than 256 colors. + \param sx Width of the desired image + \param sy Height of the desired image + \return true if it worked, else false + */ + bool Create(int sx, int sy) { + clear(); + return ((im = gdImageCreate(sx, sy)) != 0); + } + /** + Create a truecolor image. + \param sx Width of the desired image + \param sy Height of the desired image + \return true if it worked, else false + */ + bool CreateTrueColor(int sx, int sy) { + clear(); + return ((im = gdImageCreateTrueColor(sx, sy)) != 0); + } + /** + Create a palette-based image, with no more than 256 colors. + \param s Width and height of the desired image + \return true if it worked, else false + */ + bool Create(const Size & s) { + return Create(s.W(), s.H()); + } + /** + Create a truecolor image. + \param s Width and height of the desired image + \return true if it worked, else false + */ + bool CreateTrueColor(const Size & s) { + return CreateTrueColor(s.W(), s.H()); + } + // Create, determining the image format from the data + /// Read an image from an open FILE * handle, after determining the image format + bool CreateFrom(FILE * in); + /// Read an image from an open standard library input stream, after determining the image format + bool CreateFrom(std::istream & in); + /// Read an image from a memory block, after determining the image format + bool CreateFrom(int size, void * data); + + // Png + bool CreateFromPng(FILE * in) { + clear(); + return ((im = gdImageCreateFromPng(in)) != 0); + } + bool CreateFromPng(gdIOCtxPtr in) { + clear(); + return ((im = gdImageCreateFromPngCtx(in)) != 0); + } + bool CreateFromPng(int size, void * data) { + clear(); + return ((im = gdImageCreateFromPngPtr(size, data)) != 0); + } + bool CreateFromPng(std::istream & in) { + clear(); + istreamIOCtx _in_ctx(in); + return ((im = gdImageCreateFromPngCtx( & _in_ctx)) != 0); + } + + // Gif + bool CreateFromGif(FILE * in) { + clear(); + return ((im = gdImageCreateFromGif(in)) != 0); + } + bool CreateFromGif(gdIOCtxPtr in) { + clear(); + return ((im = gdImageCreateFromGifCtx(in)) != 0); + } + bool CreateFromGif(int size, void * data) { + clear(); + return ((im = gdImageCreateFromGifPtr(size, data)) != 0); + } + bool CreateFromGif(std::istream & in) { + clear(); + istreamIOCtx _in_ctx(in); + return ((im = gdImageCreateFromGifCtx( & _in_ctx)) != 0); + } + // WBMP + bool CreateFromWBMP(FILE * in) { + clear(); + return ((im = gdImageCreateFromWBMP(in)) != 0); + } + bool CreateFromWBMP(gdIOCtxPtr in) { + clear(); + return ((im = gdImageCreateFromWBMPCtx(in)) != 0); + } + bool CreateFromWBMP(int size, void * data) { + clear(); + return ((im = gdImageCreateFromWBMPPtr(size, data)) != 0); + } + bool CreateFromWBMP(std::istream & in) { + clear(); + istreamIOCtx _in_ctx(in); + return ((im = gdImageCreateFromWBMPCtx( & _in_ctx)) != 0); + } + + // Jpeg + /** + Load a truecolor image from a JPEG format file. + Invoke CreateFromJpeg with an already opened + pointer to a file containing the desired image. + CreateFromJpeg does not close the file. + \return true for success, or false if unable to load the image (most often because + the file is corrupt or does not contain a JPEG image). + You can call Width() and Height() member functions of the image to determine its + size. The returned image is always a truecolor image. + */ + bool CreateFromJpeg(FILE * in) { + clear(); + return ((im = gdImageCreateFromJpeg(in)) != 0); + } + /** + Load a truecolor image from a JPEG format file. + Invoke CreateFromJpeg with an already opened + pointer to a file containing the desired image. + CreateFromJpeg does not close the file. + \return true for success, or false if unable to load the image (most often because the file is corrupt or does not contain a JPEG image). + You can call Width() and Height() member functions of the image to determine its + size. The returned image is always a truecolor image. + */ + bool CreateFromJpeg(gdIOCtxPtr in) { + clear(); + return ((im = gdImageCreateFromJpegCtx(in)) != 0); + } + /** + Load a truecolor image from a JPEG format file. + Invoke CreateFromJpeg with an already opened + pointer to a file containing the desired image. + CreateFromJpeg does not close the file. + \return true for success, or false if unable to load the image (most often because the file is corrupt or does not contain a JPEG image). + You can call Width() and Height() member functions of the image to determine its + size. The returned image is always a truecolor image. + */ + bool CreateFromJpeg(int size, void * data) { + clear(); + return ((im = gdImageCreateFromJpegPtr(size, data)) != 0); + } + /** + Load a truecolor image from a JPEG format file. + Invoke CreateFromJpeg with an image file in memory. + \return true for success, or false if unable to load the image (most often because the format is corrupt or does not contain a JPEG image). + You can call Width() and Height() member functions of the image to determine its + size. The returned image is always a truecolor image. + */ + bool CreateFromJpeg(std::istream & in) { + clear(); + istreamIOCtx _in_ctx(in); + return ((im = gdImageCreateFromJpegCtx( & _in_ctx)) != 0); + } + + // Gd + bool CreateFromGd(FILE * in) { + clear(); + return ((im = gdImageCreateFromGd(in)) != 0); + } + bool CreateFromGd(gdIOCtxPtr in) { + clear(); + return ((im = gdImageCreateFromGdCtx(in)) != 0); + } + bool CreateFromGd(int size, void * data) { + clear(); + return ((im = gdImageCreateFromGdPtr(size, data)) != 0); + } + bool CreateFromGd(std::istream & in) { + clear(); + istreamIOCtx _in_ctx(in); + return ((im = gdImageCreateFromGdCtx( & _in_ctx)) != 0); + } + // Gd2 + bool CreateFromGd2(FILE * in) { + clear(); + return ((im = gdImageCreateFromGd2(in)) != 0); + } + bool CreateFromGd2(gdIOCtxPtr in) { + clear(); + return ((im = gdImageCreateFromGd2Ctx(in)) != 0); + } + bool CreateFromGd2(int size, void * data) { + clear(); + return ((im = gdImageCreateFromGd2Ptr(size, data)) != 0); + } + bool CreateFromGd2(std::istream & in) { + clear(); + istreamIOCtx _in_ctx(in); + return ((im = gdImageCreateFromGd2Ctx( & _in_ctx)) != 0); + } + // Gd2 Part + bool CreateFromGd2Part(FILE * in, int srcx, int srcy, int w, int h) { + clear(); + return ((im = gdImageCreateFromGd2Part(in, srcx, srcy, w, h)) != 0); + } + bool CreateFromGd2Part(gdIOCtxPtr in, int srcx, int srcy, int w, int h) { + clear(); + return ((im = gdImageCreateFromGd2PartCtx(in, srcx, srcy, w, h)) != 0); + } + bool CreateFromGd2Part(int size, void * data, int srcx, int srcy, int w, int h) { + clear(); + return ((im = gdImageCreateFromGd2PartPtr(size, data, srcx, srcy, w, h)) != 0); + } + bool CreateFromGd2Part(std::istream & in, int srcx, int srcy, int w, int h) { + clear(); + istreamIOCtx _in_ctx(in); + return ((im = gdImageCreateFromGd2PartCtx( & _in_ctx, srcx, srcy, w, h)) != 0); + } + bool CreateFromGd2Part(FILE * in, const Point & src, const Size & s) { + return CreateFromGd2Part(in, src.X(), src.Y(), s.W(), s.H()); + } + bool CreateFromGd2Part(gdIOCtxPtr in, const Point & src, const Size & s) { + return CreateFromGd2Part(in, src.X(), src.Y(), s.W(), s.H()); + } + bool CreateFromGd2Part(int size, void * data, const Point & src, const Size & s) { + return CreateFromGd2Part(size, data, src.X(), src.Y(), s.W(), s.H()); + } + bool CreateFromGd2Part(std::istream & in, const Point & src, const Size & s) { + return CreateFromGd2Part(in, src.X(), src.Y(), s.W(), s.H()); + } + // Xbm + bool CreateFromXbm(FILE * in) { + clear(); + return ((im = gdImageCreateFromXbm(in)) != 0); + } + // Xpm + bool CreateFromXpm(char * filename) { + clear(); + return ((im = gdImageCreateFromXpm(filename)) != 0); + } + bool CreateFromXpm(std::string & filename) { + return CreateFromXpm((char *)(filename.c_str())); + } + + // Accessors, Updaters & Methods: + void SetPixel(int x, int y, int color) { + gdImageSetPixel(im, x, y, color); + } + void SetPixel(const Point & p, int color) { + SetPixel(p.X(), p.Y(), color); + } + int GetPixel(int x, int y) const { + return gdImageGetPixel(im, x, y); + } + int GetPixel(const Point & p) const { + return GetPixel(p.X(), p.Y()); + } + int GetTrueColorPixel(int x, int y) const { + return gdImageGetTrueColorPixel(im, x, y); + } + int GetTrueColorPixel(const Point & p) const { + return GetTrueColorPixel(p.X(), p.Y()); + } + + void SetPixel(int x, int y, TrueColor c) { + SetPixel(x, y, c.Int()); + } + void SetPixel(const Point & p, TrueColor c) { + SetPixel(p.X(), p.Y(), c.Int()); + } + void GetTrueColorPixel(TrueColor & c, int x, int y) const { + c.set(GetTrueColorPixel(x, y)); + } + void GetTrueColorPixel(TrueColor & c, const Point & p) const { + c.set(GetTrueColorPixel(p.X(), p.Y())); + } + + void AABlend() { + gdImageAABlend(im); + } + + void Line(int x1, int y1, int x2, int y2, int color) { + gdImageLine(im, x1, y1, x2, y2, color); + } + void Line(const Point & p1, const Point & p2, int color) { + Line(p1.X(), p1.Y(), p2.X(), p2.Y(), color); + } + void Rectangle(int x1, int y1, int x2, int y2, int color) { + gdImageRectangle(im, x1, y1, x2, y2, color); + } + void Rectangle(const Point & p1, const Point & p2, int color) { + Rectangle(p1.X(), p1.Y(), p2.X(), p2.Y(), color); + } + void Rectangle(const Point & p, const Size & s, int color) { + Rectangle(p.X(), p.Y(), p.X() + s.W(), p.Y() + s.H(), color); + } + void FilledRectangle(int x1, int y1, int x2, int y2, int color) { + gdImageFilledRectangle(im, x1, y1, x2, y2, color); + } + void FilledRectangle(const Point & p1, const Point & p2, int color) { + FilledRectangle(p1.X(), p1.Y(), p2.X(), p2.Y(), color); + } + void FilledRectangle(const Point & p, const Size & s, int color) { + FilledRectangle(p.X(), p.Y(), p.X() + s.W(), p.Y() + s.H(), color); + } + + void SetClip(int x1, int y1, int x2, int y2) { + gdImageSetClip(im, x1, y1, x2, y2); + } + void SetClip(const Point & p1, const Point & p2) { + SetClip(p1.X(), p1.Y(), p2.X(), p2.Y()); + } + void SetClip(const Point & p, const Size & s) { + SetClip(p.X(), p.Y(), p.X() + s.W(), p.Y() + s.H()); + } + void GetClip(int & x1, int & y1, int & x2, int & y2) const { + gdImageGetClip(im, & x1, & y1, & x2, & y2); + } + void GetClip(Point & p1, Point & p2) const { + GetClip(p1.lhsX(), p1.lhsY(), p2.lhsX(), p2.lhsY()); + } + void GetClip(Point & p, Size & s) const { + Point p2; + GetClip(p.lhsX(), p.lhsY(), p2.lhsX(), p2.lhsY()); + s.set(p2.X() - p.X(), p2.Y() - p.Y()); + } + + bool BoundsSafe(int x, int y) const { + return (gdImageBoundsSafe(im, x, y)?true:false); + } + bool BoundsSafe(const Point & p) const { + return BoundsSafe(p.X(), p.Y()); + } + + void Char(gdFontPtr f, int x, int y, int c, int color) { + gdImageChar(im, f, x, y, c, color); + } + void CharUp(gdFontPtr f, int x, int y, int c, int color) { + gdImageCharUp(im, f, x, y, c, color); + } + + void Char(gdFontPtr f, const Point & p, int c, int color) { + Char(f, p.X(), p.Y(), c, color); + } + void CharUp(gdFontPtr f, const Point & p, int c, int color) { + CharUp(f, p.X(), p.Y(), c, color); + } + + void String(gdFontPtr f, int x, int y, unsigned char * s, int color) { + gdImageString(im, f, x, y, (unsigned char *)s, color); + } + void StringUp(gdFontPtr f, int x, int y, unsigned char * s, int color) { + gdImageStringUp(im, f, x, y, (unsigned char *)s, color); + } + void String(gdFontPtr f, int x, int y, unsigned short * s, int color) { + gdImageString16(im, f, x, y, (unsigned short *)s, color); + } + void StringUp(gdFontPtr f, int x, int y, unsigned short * s, int color) { + gdImageStringUp16(im, f, x, y, (unsigned short *)s, color); + } + void String(gdFontPtr f, int x, int y, char * s, int color) { + gdImageString(im, f, x, y, (unsigned char *)s, color); + } + void StringUp(gdFontPtr f, int x, int y, char * s, int color) { + gdImageStringUp(im, f, x, y, (unsigned char *)s, color); + } + void String(gdFontPtr f, int x, int y, const std::string & s, int color) { + String(f, x, y, (char *)s.c_str(), color); + } + void StringUp(gdFontPtr f, int x, int y, const std::string & s, int color) { + StringUp(f, x, y, (char *)s.c_str(), color); + } + + void String(gdFontPtr f, const Point & p, unsigned char * s, int color) { + String(f, p.X(), p.Y(), (unsigned char *)s, color); + } + void StringUp(gdFontPtr f, const Point & p, unsigned char * s, int color) { + StringUp(f, p.X(), p.Y(), (unsigned char *)s, color); + } + void String(gdFontPtr f, const Point & p, unsigned short * s, int color) { + String(f, p.X(), p.Y(), (unsigned short *)s, color); + } + void StringUp(gdFontPtr f, const Point & p, unsigned short * s, int color) { + StringUp(f, p.X(), p.Y(), (unsigned short *)s, color); + } + void String(gdFontPtr f, const Point & p, char * s, int color) { + String(f, p.X(), p.Y(), (unsigned char *)s, color); + } + void StringUp(gdFontPtr f, const Point & p, char * s, int color) { + StringUp(f, p.X(), p.Y(), (unsigned char *)s, color); + } + void String(gdFontPtr f, const Point & p, const std::string & s, int color) { + String(f, p, (char *)s.c_str(), color); + } + void StringUp(gdFontPtr f, const Point & p, const std::string & s, int color) { + StringUp(f, p, (char *)s.c_str(), color); + } + + char * StringFT(int * brect, int fg, char * fontlist, double ptsize, double angle, + int x, int y, char * string) { + return gdImageStringFT(im, brect, fg, fontlist, ptsize, angle, x, y, string); + } + char * StringFT(int * brect, int fg, char * fontlist, double ptsize, double angle, + int x, int y, char * string, gdFTStringExtraPtr strex) { + return gdImageStringFTEx(im, brect, fg, fontlist, ptsize, angle, x, y, string, strex); + } + char * StringFT(int * brect, int fg, char * fontlist, double ptsize, double angle, + int x, int y, const std::string & string) { + return StringFT(brect, fg, fontlist, ptsize, angle, x, y, (char *)string.c_str()); + } + char * StringFT(int * brect, int fg, char * fontlist, double ptsize, double angle, + int x, int y, const std::string & string, gdFTStringExtraPtr strex) { + return StringFT(brect, fg, fontlist, ptsize, angle, x, y, (char *)string.c_str(), strex); + } + + char * StringFT(int * brect, int fg, char * fontlist, double ptsize, double angle, + const Point & p, char * string) { + return StringFT(brect, fg, fontlist, ptsize, angle, p.X(), p.Y(), string); + } + char * StringFT(int * brect, int fg, char * fontlist, double ptsize, double angle, + const Point & p, char * string, gdFTStringExtraPtr strex) { + return StringFT(brect, fg, fontlist, ptsize, angle, p.X(), p.Y(), string, strex); + } + char * StringFT(int * brect, int fg, char * fontlist, double ptsize, double angle, + const Point & p, const std::string & string) { + return StringFT(brect, fg, fontlist, ptsize, angle, p, (char *)string.c_str()); + } + char * StringFT(int * brect, int fg, char * fontlist, double ptsize, double angle, + const Point & p, const std::string & string, gdFTStringExtraPtr strex) { + return StringFT(brect, fg, fontlist, ptsize, angle, p, (char *)string.c_str(), strex); + } + + void Polygon(gdPointPtr p, int n, int c) { + gdImagePolygon(im, p, n, c); + } + void OpenPolygon(gdPointPtr p, int n, int c) { + gdImageOpenPolygon(im, p, n, c); + } + void FilledPolygon(gdPointPtr p, int n, int c) { + gdImageFilledPolygon(im, p, n, c); + } + + void Polygon(PointPtr p, int n, int c) { + Polygon(p->as_gdPointPtr(), n, c); + } + void OpenPolygon(PointPtr p, int n, int c) { + OpenPolygon(p->as_gdPointPtr(), n, c); + } + void FilledPolygon(PointPtr p, int n, int c) { + FilledPolygon(p->as_gdPointPtr(), n, c); + } + + int ColorAllocate(int r, int g, int b) { + return gdImageColorAllocate(im, r, g, b); + } + int ColorAllocate(int r, int g, int b, int a) { + return gdImageColorAllocateAlpha(im, r, g, b, a); + } + + int ColorClosest(int r, int g, int b) const { + return gdImageColorClosest(im, r, g, b); + } + int ColorClosest(int r, int g, int b, int a) const { + return gdImageColorClosestAlpha(im, r, g, b, a); + } + int ColorClosestHWB(int r, int g, int b) const { + return gdImageColorClosestHWB(im, r, g, b); + } + int ColorExact(int r, int g, int b) const { + return gdImageColorExact(im, r, g, b); + } + int ColorExact(int r, int g, int b, int a) const { + return gdImageColorExactAlpha(im, r, g, b, a); + } + int ColorResolve(int r, int g, int b) { + return gdImageColorResolve(im, r, g, b); + } + int ColorResolve(int r, int g, int b, int a) { + return gdImageColorResolveAlpha(im, r, g, b, a); + } + + void ColorDeallocate(int color) { + gdImageColorDeallocate(im, color); + } + + void TrueColorToPalette(int ditherFlag, int colorsWanted) { + gdImageTrueColorToPalette(im, ditherFlag, colorsWanted); + } + + void ColorTransparent(int color) { + gdImageColorTransparent(im, color); + } + + void PaletteCopy(gdImagePtr src) { + gdImagePaletteCopy(im, src); + } + void PaletteCopy(const GD::Image & src) { + PaletteCopy(src.im); + } + + /** + Write out this image in GIF file format to \p out. + \param out A FILE * handle + */ + void Gif(FILE * out) const { + gdImageGif(im, out); + } + /** + Write out this image in GIF file format to \p out. + \param out A gdIOCtxPtr handle + */ + void Gif(gdIOCtxPtr out) const { + gdImageGifCtx(im, out); + } + /** + Allocate sufficient memory, and write this image, in GIF file format, to that memory. + \param size A pointer for the allocated memory + \return A pointer to the allocated memory, containing the image GIF file formatted. Caller is responsible for freeing with gdFree(). + */ + void * Gif(int * size) const { + return gdImageGifPtr(im, size); + } + /** + Write out this image in GIF file format to \p out. + \param out An output stream, already opened. + */ + void Gif(std::ostream & out) const { + ostreamIOCtx _out_ctx(out); + gdImageGifCtx(im, & _out_ctx); + } + + /** + Write out this image in PNG file format to \p out. + \param out A FILE * handle + */ + void Png(FILE * out) const { + gdImagePng(im, out); + } + /** + Write out this image in PNG file format to \p out. + \param out A gdIOCtxPtr handle + */ + void Png(gdIOCtxPtr out) const { + gdImagePngCtx(im, out); + } + /** + Allocate sufficient memory, and write this image, in PNG file format, to that memory. + \param size A pointer for the allocated memory + \return A pointer to the allocated memory, containing the image PNG file formatted. Caller is responsible for freeing with gdFree(). + */ + void * Png(int * size) const { + return gdImagePngPtr(im, size); + } + /** + Write out this image in PNG file format to \p out. + \param out An output stream, already opened. + */ + void Png(std::ostream & out) const { + ostreamIOCtx _out_ctx(out); + gdImagePngCtx(im, & _out_ctx); + } + /** + Write out this image in PNG file format to \p out. + \param out A FILE * handle + \param level The level of compression: 0 == "no compression", 1 == "compressed as quickly as possible" --> 9 == "compressed as much as possible", -1 == zlib default compression level + */ + void Png(FILE * out, int level) const { + gdImagePngEx(im, out, level); + } + /** + Write out this image in PNG file format to \p out. + \param out A gdIOCtxPtr handle + \param level The level of compression: 0 == "no compression", 1 == "compressed as quickly as possible" --> 9 == "compressed as much as possible", -1 == zlib default compression level + */ + void Png(gdIOCtxPtr out, int level) const { + gdImagePngCtxEx(im, out, level); + } + /** + Allocate sufficient memory, and write this image, in PNG file format, to that memory. + \param size A pointer for the allocated memory + \param level The level of compression: 0 == "no compression", 1 == "compressed as quickly as possible" --> 9 == "compressed as much as possible", -1 == zlib default compression level + \return A pointer to the allocated memory, containing the image PNG file formatted. Caller is responsible for freeing with gdFree(). + */ + void * Png(int * size, int level) const { + return gdImagePngPtrEx(im, size, level); + } + /** + Write out this image in PNG file format to \p out. + \param out An output stream, already opened. + \param level The level of compression: 0 == "no compression", 1 == "compressed as quickly as possible" --> 9 == "compressed as much as possible", -1 == zlib default compression level + */ + void Png(std::ostream & out, int level) const { + ostreamIOCtx _out_ctx(out); + gdImagePngCtxEx(im, & _out_ctx, level); + } + + /** + Write out this image in WBMP file format ( black and white only ) to \p out. + \param fg The color index of the foreground. All other pixels considered background. + \param out A FILE * handle + */ + void WBMP(int fg, FILE * out) const { + gdImageWBMP(im, fg, out); + } + /** + Write out this image in WBMP file format ( black and white only ) to \p out. + \param fg The color index of the foreground. All other pixels considered background. + \param out A gdIOCtxPtr handle + */ + void WBMP(int fg, gdIOCtxPtr out) const { + gdImageWBMPCtx(im, fg, out); + } + /** + Allocate sufficient memory, and write this image, in WBMP file format ( black and white only ), to that memory. + \param size A pointer for the allocated memory + \param fg The color index of the foreground. All other pixels considered background. + \return A pointer to the allocated memory, containing the image WBMP file formatted. Caller is responsible for freeing with gdFree(). + */ + void * WBMP(int * size, int fg) const { + return gdImageWBMPPtr(im, size, fg); + } + /** + Write out this image in WBMP file format ( black and white only ) to \p out. + \param fg The color index of the foreground. All other pixels considered background. + \param out An output stream, already opened. + */ + void WBMP(int fg, std::ostream & out) const { + ostreamIOCtx _out_ctx(out); + gdImageWBMPCtx(im, fg, & _out_ctx); + } + + /** + Write out this image in JPEG file format to \p out. + \param out A FILE * handle + \param quality Should be a value in the range 0-95, higher numbers imply both higher quality and larger image size. Default value is -1, indicating "use a sensible default value". + */ + void Jpeg(FILE * out, int quality = -1) const { + gdImageJpeg(im, out, quality); + } + /** + Write out this image in JPEG file format to \p out. + \param out A gdIOCtxPtr handle + \param quality Should be a value in the range 0-95, higher numbers imply both higher quality and larger image size. Default value is -1, indicating "use a sensible default value". + */ + void Jpeg(gdIOCtxPtr out, int quality = -1) const { + gdImageJpegCtx(im, out, quality); + } + /** + Allocate sufficient memory, and write this image, in JPEG file format, to that memory. + \param size A pointer for the allocated memory + \param quality Should be a value in the range 0-95, higher numbers imply both higher quality and larger image size. Default value is -1, indicating "use a sensible default value". + \return A pointer to the allocated memory, containing the image JPEG file formatted. Caller is responsible for freeing with gdFree(). + */ + void * Jpeg(int * size, int quality = -1) const { + return gdImageJpegPtr(im, size, quality); + } + /** + Write out this image in JPEG file format to \p out. + \param out An output stream, already opened. + \param quality Should be a value in the range 0-95, higher numbers imply both higher quality and larger image size. Default value is -1, indicating "use a sensible default value". + */ + void Jpeg(std::ostream & out, int quality = -1) const { + ostreamIOCtx _out_ctx(out); + gdImageJpegCtx(im, & _out_ctx, quality); + } + + void GifAnimBegin(FILE * out, int GlobalCM, int Loops) const { + gdImageGifAnimBegin(im, out, GlobalCM, Loops); + } + void GifAnimAdd(FILE * out, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm) const { + gdImageGifAnimAdd(im, out, LocalCM, LeftOfs, TopOfs, Delay, Disposal, previm); + } + void GifAnimAdd(FILE * out, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, const GD::Image & previm) const { + GifAnimAdd(out, LocalCM, LeftOfs, TopOfs, Delay, Disposal, previm.im); + } + inline static void GifAnimEnd(FILE * out) { + gdImageGifAnimEnd(out); + } + void GifAnimBegin(gdIOCtxPtr out, int GlobalCM, int Loops) const { + gdImageGifAnimBeginCtx(im, out, GlobalCM, Loops); + } + void GifAnimAdd(gdIOCtxPtr out, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm) const { + gdImageGifAnimAddCtx(im, out, LocalCM, LeftOfs, TopOfs, Delay, Disposal, previm); + } + void GifAnimAdd(gdIOCtxPtr out, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, const GD::Image & previm) const { + GifAnimAdd(out, LocalCM, LeftOfs, TopOfs, Delay, Disposal, previm.im); + } + inline static void GifAnimEnd(gdIOCtxPtr out) { + gdImageGifAnimEndCtx(out); + } + void * GifAnimBegin(int * size, int GlobalCM, int Loops) const { + return gdImageGifAnimBeginPtr(im, size, GlobalCM, Loops); + } + void * GifAnimAdd(int * size, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm) const { + return gdImageGifAnimAddPtr(im, size, LocalCM, LeftOfs, TopOfs, Delay, Disposal, previm); + } + void * GifAnimAdd(int * size, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, const GD::Image & previm) const { + return GifAnimAdd(size, LocalCM, LeftOfs, TopOfs, Delay, Disposal, previm.im); + } + inline static void * GifAnimEnd(int * size) { + return gdImageGifAnimEndPtr(size); + } + + void Gd(FILE * out) const { + gdImageGd(im, out); + } + void* Gd(int * size) const { + return gdImageGdPtr(im, size); + } + void Gd2(FILE * out, int cs, int fmt) const { + gdImageGd2(im, out, cs, fmt); + } + void* Gd2(int cs, int fmt, int * size) const { + return gdImageGd2Ptr(im, cs, fmt, size); + } + + void Ellipse(int cx, int cy, int w, int h, int color) { + gdImageEllipse(im, cx, cy, w, h, color); + } + /** + Draw a partial ellipse centered at the given point, with the specified width and height in pixels. + */ + void FilledArc(int cx, int cy, int w, int h, int s, int e, int color, int style) { + gdImageFilledArc(im, cx, cy, w, h, s, e, color, style); + } + void Arc(int cx, int cy, int w, int h, int s, int e, int color) { + gdImageArc(im, cx, cy, w, h, s, e, color); + } + void FilledEllipse(int cx, int cy, int w, int h, int color) { + gdImageFilledEllipse(im, cx, cy, w, h, color); + } + void FillToBorder(int x, int y, int border, int color) { + gdImageFillToBorder(im, x, y, border, color); + } + void Fill(int x, int y, int color) { + gdImageFill(im, x, y, color); + } + + void Ellipse(const Point & c, const Size & s, int color) { + Ellipse(c.X(), c.Y(), s.W(), s.H(), color); + } + void FilledArc(const Point & c, const Size & si, int s, int e, int color, int style) { + FilledArc(c.X(), c.Y(), si.W(), si.H(), s, e, color, style); + } + void Arc(const Point & c, const Size & si, int s, int e, int color) { + Arc(c.X(), c.Y(), si.W(), si.H(), s, e, color); + } + void FilledEllipse(const Point & c, const Size & s, int color) { + FilledEllipse(c.X(), c.Y(), s.W(), s.H(), color); + } + void FillToBorder(const Point & p, int border, int color) { + FillToBorder(p.X(), p.Y(), border, color); + } + void Fill(const Point & p, int color) { + Fill(p.X(), p.Y(), color); + } + + void Copy(const gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h) { + gdImageCopy(im, src, dstX, dstY, srcX, srcY, w, h); + } + void CopyMerge(const gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct) { + gdImageCopyMerge(im, src, dstX, dstY, srcX, srcY, w, h, pct); + } + void CopyMergeGray(const gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct) { + gdImageCopyMergeGray(im, src, dstX, dstY, srcX, srcY, w, h, pct); + } + + void CopyResized(const gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH) { + gdImageCopyResized(im, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH); + } + void CopyResampled(const gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH) { + gdImageCopyResampled(im, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH); + } + void CopyRotated(const gdImagePtr src, double dstX, double dstY, int srcX, int srcY, int srcWidth, int srcHeight, int angle) { + gdImageCopyRotated(im, src, dstX, dstY, srcX, srcY, srcWidth, srcHeight, angle); + } + + Image * CopyGaussianBlurred(int radius, double sigma) { + return new Image(gdImageCopyGaussianBlurred(im, radius, sigma)); + } + + void Copy(const gdImagePtr src, const Point & dstP, const Point & srcP, const Size & s) { + Copy(src, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), s.W(), s.H()); + } + void CopyMerge(const gdImagePtr src, const Point & dstP, const Point & srcP, const Size & s, int pct) { + CopyMerge(src, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), s.W(), s.H(), pct); + } + void CopyMergeGray(const gdImagePtr src, const Point & dstP, const Point & srcP, const Size & s, int pct) { + CopyMergeGray(src, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), s.W(), s.H(), pct); + } + + void CopyResized(const gdImagePtr src, const Point & dstP, const Point & srcP, const Size & dstS, const Size & srcS) { + CopyResized(src, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), dstS.W(), dstS.H(), srcS.W(), srcS.H()); + } + void CopyResampled(const gdImagePtr src, const Point & dstP, const Point & srcP, const Size & dstS, const Size & srcS) { + CopyResampled(src, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), dstS.W(), dstS.H(), srcS.W(), srcS.H()); + } + void CopyRotated(const gdImagePtr src, double dstX, double dstY, const Point & srcP, const Size & srcS, int angle) { + CopyRotated(src, dstX, dstY, srcP.X(), srcP.Y(), srcS.W(), srcS.H(), angle); + } + + void Copy(const GD::Image & src, int dstX, int dstY, int srcX, int srcY, int w, int h) { + Copy(src.im, dstX, dstY, srcX, srcY, w, h); + } + void CopyMerge(const GD::Image & src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct) { + CopyMerge(src.im, dstX, dstY, srcX, srcY, w, h, pct); + } + void CopyMergeGray(const GD::Image & src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct) { + CopyMergeGray(src.im, dstX, dstY, srcX, srcY, w, h, pct); + } + + void CopyResized(const GD::Image & src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH) { + CopyResized(src.im, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH); + } + void CopyResampled(const GD::Image & src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH) { + CopyResampled(src.im, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH); + } + void CopyRotated(const GD::Image & src, double dstX, double dstY, int srcX, int srcY, int srcWidth, int srcHeight, int angle) { + CopyRotated(src.im, dstX, dstY, srcX, srcY, srcWidth, srcHeight, angle); + } + + void Copy(const GD::Image & src, const Point & dstP, const Point & srcP, const Size & s) { + Copy(src.im, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), s.W(), s.H()); + } + void CopyMerge(const GD::Image & src, const Point & dstP, const Point & srcP, const Size & s, int pct) { + CopyMerge(src.im, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), s.W(), s.H(), pct); + } + void CopyMergeGray(const GD::Image & src, const Point & dstP, const Point & srcP, const Size & s, int pct) { + CopyMergeGray(src.im, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), s.W(), s.H(), pct); + } + + void CopyResized(const GD::Image & src, const Point & dstP, const Point & srcP, const Size & dstS, const Size & srcS) { + CopyResized(src.im, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), dstS.W(), dstS.H(), srcS.W(), srcS.H()); + } + void CopyResampled(const GD::Image & src, const Point & dstP, const Point & srcP, const Size & dstS, const Size & srcS) { + CopyResampled(src.im, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), dstS.W(), dstS.H(), srcS.W(), srcS.H()); + } + void CopyRotated(const GD::Image & src, double dstX, double dstY, const Point & srcP, const Size & srcS, int angle) { + CopyRotated(src.im, dstX, dstY, srcP.X(), srcP.Y(), srcS.W(), srcS.H(), angle); + } + + Image * Clone() { + return new Image(gdImageClone(im)); + } + + void SetBrush(gdImagePtr brush) { + gdImageSetBrush(im, brush); + } + void SetBrush(const GD::Image & brush) { + SetBrush(brush.im); + } + void SetTile(gdImagePtr tile) { + gdImageSetTile(im, tile); + } + void SetTile(const GD::Image & tile) { + SetTile(tile.im); + } + void SetAntiAliased(int c) { + gdImageSetAntiAliased(im, c); + } + void SetAntiAliasedDontBlend(int c, int dont_blend) { + gdImageSetAntiAliasedDontBlend(im, c, dont_blend); + } + void SetStyle(int * style, int noOfPixels) { + gdImageSetStyle(im, style, noOfPixels); + } + void SetThickness(int thickness) { + gdImageSetThickness(im, thickness); + } + void SetResolution(int res_x, int res_y) { + gdImageSetResolution(im, res_x, res_y); + } + void SetInterpolationMethod(gdInterpolationMethod interpolation_method) { + gdImageSetInterpolationMethod(im, interpolation_method); + } + + Image * RotateInterpolated(const float angle, int bgcolor) { + return new Image(gdImageRotateInterpolated(im, angle, bgcolor)); + } + + void Interlace(bool interlaceArg) { + gdImageInterlace(im, interlaceArg?1:0); + } + void AlphaBlending(bool alphaBlendingArg) { + gdImageAlphaBlending(im, alphaBlendingArg?1:0); + } + void SaveAlpha(bool saveAlphaArg) { + gdImageSaveAlpha(im, saveAlphaArg?1:0); + } + + int ColorReplace(int src, int dst) { + return gdImageColorReplace(im, src, dst); + } + int ColorReplaceArray(int len, int * src, int * dst) { + return gdImageColorReplaceArray(im, len, src, dst); + } + int ColorReplaceCallback(gdCallbackImageColor callback) { + return gdImageColorReplaceCallback(im, callback); + } + int ColorReplaceThreshold(int src, int dst, float threshold) { + return gdImageColorReplaceThreshold(im, src, dst, threshold); + } + + bool Pixelate(int block_size, gdPixelateMode mode) { + return gdImagePixelate(im, block_size, mode) == 0 ? false : true; + } + + Image * Scale(int new_width, int new_height) { + return new Image(gdImageScale(im, new_width, new_height)); + } + + bool IsTrueColor() const { + return (gdImageTrueColor(im)?true:false); + } + int SX() const { + return gdImageSX(im); + } + int SY() const { + return gdImageSY(im); + } + int Width() const { + return SX(); + } + int Height() const { + return SY(); + } + int ResX() const { + return gdImageResolutionX(im); + } + int ResY() const { + return gdImageResolutionY(im); + } + void GetSize(Size & s) const { + s.set(SX(), SY()); + } + int ColorsTotal() const { + return gdImageColorsTotal(im); + } + int Red(int color) const { + return gdImageRed(im, color); + } + int Green(int color) const { + return gdImageGreen(im, color); + } + int Blue(int color) const { + return gdImageBlue(im, color); + } + int Alpha(int color) const { + return gdImageAlpha(im, color); + } + int GetTransparent() const { + return gdImageGetTransparent(im); + } + int GetInterlaced() const { + return gdImageGetInterlaced(im); + } + int PalettePixel(int x, int y) const { + return gdImagePalettePixel(im, x, y); + } + int TrueColorPixel(int x, int y) const { + return gdImageTrueColorPixel(im, x, y); + } + + const gdImagePtr GetPtr() const { + return im; + } + +protected: + /// Free the internal image pointer + void clear() { + if (im) + gdImageDestroy(im); + im = 0; + } + gdImagePtr im; +}; +} // namespace GD +/// Read in an image from a standard library input stream +std::istream & operator>> (std::istream & in, GD::Image & img); + +#endif /* __cplusplus */ +#endif /* _gdpp_h */ diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/jisx0208.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/jisx0208.h new file mode 100644 index 0000000000..118c23e0aa --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/jisx0208.h @@ -0,0 +1,1306 @@ +#ifndef JISX0208_H +#define JISX0208_H +#ifdef __cplusplus +extern "C" { +#endif + + /* This file was derived from "src/VF_Ftype.c" in VFlib2-2.24.2 + by Dr. Kakugawa */ + + /* JIS -> Unicode mapping table */ + static const unsigned short UnicodeTbl[][94] = { + { /* category 01 */ + 0x0000, 0x3001, 0x3002, 0xFF0C, 0xFF0E, 0x30FB, 0xFF1A, 0xFF1B, + 0xFF1F, 0xFF01, 0x309B, 0x309C, 0x00B4, 0xFF40, 0x00A8, 0xFF3E, + 0xFFE3, 0xFF3F, 0x30FD, 0x30FE, 0x309D, 0x309E, 0x3003, 0x4EDD, + 0x3005, 0x3006, 0x3007, 0x30FC, 0x2015, 0x2010, 0xFF0F, 0xFF3C, + 0xFF5E, 0x2225, 0xFF5C, 0x2026, 0x2025, 0x2018, 0x2019, 0x201C, + 0x201D, 0xFF08, 0xFF09, 0x3014, 0x3015, 0xFF3B, 0xFF3D, 0xFF5B, + 0xFF5D, 0x3008, 0x3009, 0x300A, 0x300B, 0x300C, 0x300D, 0x300E, + 0x300F, 0x3010, 0x3011, 0xFF0B, 0xFF0D, 0x00B1, 0x00D7, 0x00F7, + 0xFF1D, 0x2260, 0xFF1C, 0xFF1E, 0x2266, 0x2267, 0x221E, 0x2234, + 0x2642, 0x2640, 0x00B0, 0x2032, 0x2033, 0x2103, 0xFFE5, 0xFF04, + 0xFFE0, 0xFFE1, 0xFF05, 0xFF03, 0xFF06, 0xFF0A, 0xFF20, 0x00A7, + 0x2606, 0x2605, 0x25CB, 0x25CF, 0x25CE, 0x25C7 + }, + { /* category 02 */ + 0x25C6, 0x25A1, 0x25A0, 0x25B3, 0x25B2, 0x25BD, 0x25BC, 0x203B, + 0x3012, 0x2192, 0x2190, 0x2191, 0x2193, 0x3013, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2208, 0x220B, 0x2286, 0x2287, 0x2282, 0x2283, 0x222A, + 0x2229, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2227, 0x2228, 0xFFE2, 0x21D2, 0x21D4, 0x2200, 0x2203, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x2220, 0x22A5, 0x2312, 0x2202, 0x2207, + 0x2261, 0x2252, 0x226A, 0x226B, 0x221A, 0x223D, 0x221D, 0x2235, + 0x222B, 0x222C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x212B, 0x2030, 0x266F, 0x266D, 0x266A, 0x2020, 0x2021, /**/ + 0x00B6, 0x0000, 0x0000, 0x0000, 0x0000, 0x25EF + }, + { /* category 03 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFF10, + 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17, 0xFF18, + 0xFF19, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28, + 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F, 0xFF30, + 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, + 0xFF39, 0xFF3A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, + 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, 0xFF50, + 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, + 0xFF59, 0xFF5A, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 04 */ + 0x3041, 0x3042, 0x3043, 0x3044, 0x3045, 0x3046, 0x3047, 0x3048, + 0x3049, 0x304A, 0x304B, 0x304C, 0x304D, 0x304E, 0x304F, 0x3050, + 0x3051, 0x3052, 0x3053, 0x3054, 0x3055, 0x3056, 0x3057, 0x3058, + 0x3059, 0x305A, 0x305B, 0x305C, 0x305D, 0x305E, 0x305F, 0x3060, + 0x3061, 0x3062, 0x3063, 0x3064, 0x3065, 0x3066, 0x3067, 0x3068, + 0x3069, 0x306A, 0x306B, 0x306C, 0x306D, 0x306E, 0x306F, 0x3070, + 0x3071, 0x3072, 0x3073, 0x3074, 0x3075, 0x3076, 0x3077, 0x3078, + 0x3079, 0x307A, 0x307B, 0x307C, 0x307D, 0x307E, 0x307F, 0x3080, + 0x3081, 0x3082, 0x3083, 0x3084, 0x3085, 0x3086, 0x3087, 0x3088, + 0x3089, 0x308A, 0x308B, 0x308C, 0x308D, 0x308E, 0x308F, 0x3090, + 0x3091, 0x3092, 0x3093, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 05 */ + 0x30A1, 0x30A2, 0x30A3, 0x30A4, 0x30A5, 0x30A6, 0x30A7, 0x30A8, + 0x30A9, 0x30AA, 0x30AB, 0x30AC, 0x30AD, 0x30AE, 0x30AF, 0x30B0, + 0x30B1, 0x30B2, 0x30B3, 0x30B4, 0x30B5, 0x30B6, 0x30B7, 0x30B8, + 0x30B9, 0x30BA, 0x30BB, 0x30BC, 0x30BD, 0x30BE, 0x30BF, 0x30C0, + 0x30C1, 0x30C2, 0x30C3, 0x30C4, 0x30C5, 0x30C6, 0x30C7, 0x30C8, + 0x30C9, 0x30CA, 0x30CB, 0x30CC, 0x30CD, 0x30CE, 0x30CF, 0x30D0, + 0x30D1, 0x30D2, 0x30D3, 0x30D4, 0x30D5, 0x30D6, 0x30D7, 0x30D8, + 0x30D9, 0x30DA, 0x30DB, 0x30DC, 0x30DD, 0x30DE, 0x30DF, 0x30E0, + 0x30E1, 0x30E2, 0x30E3, 0x30E4, 0x30E5, 0x30E6, 0x30E7, 0x30E8, + 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EE, 0x30EF, 0x30F0, + 0x30F1, 0x30F2, 0x30F3, 0x30F4, 0x30F5, 0x30F6, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 06 */ + 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, + 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, + 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, + 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, + 0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 07 */ + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0401, 0x0416, + 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, + 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, + 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, + 0x042F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0451, 0x0436, + 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, + 0x043F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, + 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, + 0x044F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 08 */ + 0x2500, 0x2502, 0x250C, 0x2510, 0x2518, 0x2514, 0x251C, 0x252C, + 0x2524, 0x2534, 0x253C, 0x2501, 0x2503, 0x250F, 0x2513, 0x251B, + 0x2517, 0x2523, 0x2533, 0x252B, 0x253B, 0x254B, 0x2520, 0x252F, + 0x2528, 0x2537, 0x253F, 0x251D, 0x2530, 0x2525, 0x2538, 0x2542, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 09 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 10 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 11 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 12 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 13 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 14 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 15 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 16 */ + 0x4E9C, 0x5516, 0x5A03, 0x963F, 0x54C0, 0x611B, 0x6328, 0x59F6, + 0x9022, 0x8475, 0x831C, 0x7A50, 0x60AA, 0x63E1, 0x6E25, 0x65ED, + 0x8466, 0x82A6, 0x9BF5, 0x6893, 0x5727, 0x65A1, 0x6271, 0x5B9B, + 0x59D0, 0x867B, 0x98F4, 0x7D62, 0x7DBE, 0x9B8E, 0x6216, 0x7C9F, + 0x88B7, 0x5B89, 0x5EB5, 0x6309, 0x6697, 0x6848, 0x95C7, 0x978D, + 0x674F, 0x4EE5, 0x4F0A, 0x4F4D, 0x4F9D, 0x5049, 0x56F2, 0x5937, + 0x59D4, 0x5A01, 0x5C09, 0x60DF, 0x610F, 0x6170, 0x6613, 0x6905, + 0x70BA, 0x754F, 0x7570, 0x79FB, 0x7DAD, 0x7DEF, 0x80C3, 0x840E, + 0x8863, 0x8B02, 0x9055, 0x907A, 0x533B, 0x4E95, 0x4EA5, 0x57DF, + 0x80B2, 0x90C1, 0x78EF, 0x4E00, 0x58F1, 0x6EA2, 0x9038, 0x7A32, + 0x8328, 0x828B, 0x9C2F, 0x5141, 0x5370, 0x54BD, 0x54E1, 0x56E0, + 0x59FB, 0x5F15, 0x98F2, 0x6DEB, 0x80E4, 0x852D + }, + { /* category 17 */ + 0x9662, 0x9670, 0x96A0, 0x97FB, 0x540B, 0x53F3, 0x5B87, 0x70CF, + 0x7FBD, 0x8FC2, 0x96E8, 0x536F, 0x9D5C, 0x7ABA, 0x4E11, 0x7893, + 0x81FC, 0x6E26, 0x5618, 0x5504, 0x6B1D, 0x851A, 0x9C3B, 0x59E5, + 0x53A9, 0x6D66, 0x74DC, 0x958F, 0x5642, 0x4E91, 0x904B, 0x96F2, + 0x834F, 0x990C, 0x53E1, 0x55B6, 0x5B30, 0x5F71, 0x6620, 0x66F3, + 0x6804, 0x6C38, 0x6CF3, 0x6D29, 0x745B, 0x76C8, 0x7A4E, 0x9834, + 0x82F1, 0x885B, 0x8A60, 0x92ED, 0x6DB2, 0x75AB, 0x76CA, 0x99C5, + 0x60A6, 0x8B01, 0x8D8A, 0x95B2, 0x698E, 0x53AD, 0x5186, 0x5712, + 0x5830, 0x5944, 0x5BB4, 0x5EF6, 0x6028, 0x63A9, 0x63F4, 0x6CBF, + 0x6F14, 0x708E, 0x7114, 0x7159, 0x71D5, 0x733F, 0x7E01, 0x8276, + 0x82D1, 0x8597, 0x9060, 0x925B, 0x9D1B, 0x5869, 0x65BC, 0x6C5A, + 0x7525, 0x51F9, 0x592E, 0x5965, 0x5F80, 0x5FDC + }, + { /* category 18 */ + 0x62BC, 0x65FA, 0x6A2A, 0x6B27, 0x6BB4, 0x738B, 0x7FC1, 0x8956, + 0x9D2C, 0x9D0E, 0x9EC4, 0x5CA1, 0x6C96, 0x837B, 0x5104, 0x5C4B, + 0x61B6, 0x81C6, 0x6876, 0x7261, 0x4E59, 0x4FFA, 0x5378, 0x6069, + 0x6E29, 0x7A4F, 0x97F3, 0x4E0B, 0x5316, 0x4EEE, 0x4F55, 0x4F3D, + 0x4FA1, 0x4F73, 0x52A0, 0x53EF, 0x5609, 0x590F, 0x5AC1, 0x5BB6, + 0x5BE1, 0x79D1, 0x6687, 0x679C, 0x67B6, 0x6B4C, 0x6CB3, 0x706B, + 0x73C2, 0x798D, 0x79BE, 0x7A3C, 0x7B87, 0x82B1, 0x82DB, 0x8304, + 0x8377, 0x83EF, 0x83D3, 0x8766, 0x8AB2, 0x5629, 0x8CA8, 0x8FE6, + 0x904E, 0x971E, 0x868A, 0x4FC4, 0x5CE8, 0x6211, 0x7259, 0x753B, + 0x81E5, 0x82BD, 0x86FE, 0x8CC0, 0x96C5, 0x9913, 0x99D5, 0x4ECB, + 0x4F1A, 0x89E3, 0x56DE, 0x584A, 0x58CA, 0x5EFB, 0x5FEB, 0x602A, + 0x6094, 0x6062, 0x61D0, 0x6212, 0x62D0, 0x6539 + }, + { /* category 19 */ + 0x9B41, 0x6666, 0x68B0, 0x6D77, 0x7070, 0x754C, 0x7686, 0x7D75, + 0x82A5, 0x87F9, 0x958B, 0x968E, 0x8C9D, 0x51F1, 0x52BE, 0x5916, + 0x54B3, 0x5BB3, 0x5D16, 0x6168, 0x6982, 0x6DAF, 0x788D, 0x84CB, + 0x8857, 0x8A72, 0x93A7, 0x9AB8, 0x6D6C, 0x99A8, 0x86D9, 0x57A3, + 0x67FF, 0x86CE, 0x920E, 0x5283, 0x5687, 0x5404, 0x5ED3, 0x62E1, + 0x64B9, 0x683C, 0x6838, 0x6BBB, 0x7372, 0x78BA, 0x7A6B, 0x899A, + 0x89D2, 0x8D6B, 0x8F03, 0x90ED, 0x95A3, 0x9694, 0x9769, 0x5B66, + 0x5CB3, 0x697D, 0x984D, 0x984E, 0x639B, 0x7B20, 0x6A2B, 0x6A7F, + 0x68B6, 0x9C0D, 0x6F5F, 0x5272, 0x559D, 0x6070, 0x62EC, 0x6D3B, + 0x6E07, 0x6ED1, 0x845B, 0x8910, 0x8F44, 0x4E14, 0x9C39, 0x53F6, + 0x691B, 0x6A3A, 0x9784, 0x682A, 0x515C, 0x7AC3, 0x84B2, 0x91DC, + 0x938C, 0x565B, 0x9D28, 0x6822, 0x8305, 0x8431 + }, + { /* category 20 */ + 0x7CA5, 0x5208, 0x82C5, 0x74E6, 0x4E7E, 0x4F83, 0x51A0, 0x5BD2, + 0x520A, 0x52D8, 0x52E7, 0x5DFB, 0x559A, 0x582A, 0x59E6, 0x5B8C, + 0x5B98, 0x5BDB, 0x5E72, 0x5E79, 0x60A3, 0x611F, 0x6163, 0x61BE, + 0x63DB, 0x6562, 0x67D1, 0x6853, 0x68FA, 0x6B3E, 0x6B53, 0x6C57, + 0x6F22, 0x6F97, 0x6F45, 0x74B0, 0x7518, 0x76E3, 0x770B, 0x7AFF, + 0x7BA1, 0x7C21, 0x7DE9, 0x7F36, 0x7FF0, 0x809D, 0x8266, 0x839E, + 0x89B3, 0x8ACC, 0x8CAB, 0x9084, 0x9451, 0x9593, 0x9591, 0x95A2, + 0x9665, 0x97D3, 0x9928, 0x8218, 0x4E38, 0x542B, 0x5CB8, 0x5DCC, + 0x73A9, 0x764C, 0x773C, 0x5CA9, 0x7FEB, 0x8D0B, 0x96C1, 0x9811, + 0x9854, 0x9858, 0x4F01, 0x4F0E, 0x5371, 0x559C, 0x5668, 0x57FA, + 0x5947, 0x5B09, 0x5BC4, 0x5C90, 0x5E0C, 0x5E7E, 0x5FCC, 0x63EE, + 0x673A, 0x65D7, 0x65E2, 0x671F, 0x68CB, 0x68C4 + }, + { /* category 21 */ + 0x6A5F, 0x5E30, 0x6BC5, 0x6C17, 0x6C7D, 0x757F, 0x7948, 0x5B63, + 0x7A00, 0x7D00, 0x5FBD, 0x898F, 0x8A18, 0x8CB4, 0x8D77, 0x8ECC, + 0x8F1D, 0x98E2, 0x9A0E, 0x9B3C, 0x4E80, 0x507D, 0x5100, 0x5993, + 0x5B9C, 0x622F, 0x6280, 0x64EC, 0x6B3A, 0x72A0, 0x7591, 0x7947, + 0x7FA9, 0x87FB, 0x8ABC, 0x8B70, 0x63AC, 0x83CA, 0x97A0, 0x5409, + 0x5403, 0x55AB, 0x6854, 0x6A58, 0x8A70, 0x7827, 0x6775, 0x9ECD, + 0x5374, 0x5BA2, 0x811A, 0x8650, 0x9006, 0x4E18, 0x4E45, 0x4EC7, + 0x4F11, 0x53CA, 0x5438, 0x5BAE, 0x5F13, 0x6025, 0x6551, 0x673D, + 0x6C42, 0x6C72, 0x6CE3, 0x7078, 0x7403, 0x7A76, 0x7AAE, 0x7B08, + 0x7D1A, 0x7CFE, 0x7D66, 0x65E7, 0x725B, 0x53BB, 0x5C45, 0x5DE8, + 0x62D2, 0x62E0, 0x6319, 0x6E20, 0x865A, 0x8A31, 0x8DDD, 0x92F8, + 0x6F01, 0x79A6, 0x9B5A, 0x4EA8, 0x4EAB, 0x4EAC + }, + { /* category 22 */ + 0x4F9B, 0x4FA0, 0x50D1, 0x5147, 0x7AF6, 0x5171, 0x51F6, 0x5354, + 0x5321, 0x537F, 0x53EB, 0x55AC, 0x5883, 0x5CE1, 0x5F37, 0x5F4A, + 0x602F, 0x6050, 0x606D, 0x631F, 0x6559, 0x6A4B, 0x6CC1, 0x72C2, + 0x72ED, 0x77EF, 0x80F8, 0x8105, 0x8208, 0x854E, 0x90F7, 0x93E1, + 0x97FF, 0x9957, 0x9A5A, 0x4EF0, 0x51DD, 0x5C2D, 0x6681, 0x696D, + 0x5C40, 0x66F2, 0x6975, 0x7389, 0x6850, 0x7C81, 0x50C5, 0x52E4, + 0x5747, 0x5DFE, 0x9326, 0x65A4, 0x6B23, 0x6B3D, 0x7434, 0x7981, + 0x79BD, 0x7B4B, 0x7DCA, 0x82B9, 0x83CC, 0x887F, 0x895F, 0x8B39, + 0x8FD1, 0x91D1, 0x541F, 0x9280, 0x4E5D, 0x5036, 0x53E5, 0x533A, + 0x72D7, 0x7396, 0x77E9, 0x82E6, 0x8EAF, 0x99C6, 0x99C8, 0x99D2, + 0x5177, 0x611A, 0x865E, 0x55B0, 0x7A7A, 0x5076, 0x5BD3, 0x9047, + 0x9685, 0x4E32, 0x6ADB, 0x91E7, 0x5C51, 0x5C48 + }, + { /* category 23 */ + 0x6398, 0x7A9F, 0x6C93, 0x9774, 0x8F61, 0x7AAA, 0x718A, 0x9688, + 0x7C82, 0x6817, 0x7E70, 0x6851, 0x936C, 0x52F2, 0x541B, 0x85AB, + 0x8A13, 0x7FA4, 0x8ECD, 0x90E1, 0x5366, 0x8888, 0x7941, 0x4FC2, + 0x50BE, 0x5211, 0x5144, 0x5553, 0x572D, 0x73EA, 0x578B, 0x5951, + 0x5F62, 0x5F84, 0x6075, 0x6176, 0x6167, 0x61A9, 0x63B2, 0x643A, + 0x656C, 0x666F, 0x6842, 0x6E13, 0x7566, 0x7A3D, 0x7CFB, 0x7D4C, + 0x7D99, 0x7E4B, 0x7F6B, 0x830E, 0x834A, 0x86CD, 0x8A08, 0x8A63, + 0x8B66, 0x8EFD, 0x981A, 0x9D8F, 0x82B8, 0x8FCE, 0x9BE8, 0x5287, + 0x621F, 0x6483, 0x6FC0, 0x9699, 0x6841, 0x5091, 0x6B20, 0x6C7A, + 0x6F54, 0x7A74, 0x7D50, 0x8840, 0x8A23, 0x6708, 0x4EF6, 0x5039, + 0x5026, 0x5065, 0x517C, 0x5238, 0x5263, 0x55A7, 0x570F, 0x5805, + 0x5ACC, 0x5EFA, 0x61B2, 0x61F8, 0x62F3, 0x6372 + }, + { /* category 24 */ + 0x691C, 0x6A29, 0x727D, 0x72AC, 0x732E, 0x7814, 0x786F, 0x7D79, + 0x770C, 0x80A9, 0x898B, 0x8B19, 0x8CE2, 0x8ED2, 0x9063, 0x9375, + 0x967A, 0x9855, 0x9A13, 0x9E78, 0x5143, 0x539F, 0x53B3, 0x5E7B, + 0x5F26, 0x6E1B, 0x6E90, 0x7384, 0x73FE, 0x7D43, 0x8237, 0x8A00, + 0x8AFA, 0x9650, 0x4E4E, 0x500B, 0x53E4, 0x547C, 0x56FA, 0x59D1, + 0x5B64, 0x5DF1, 0x5EAB, 0x5F27, 0x6238, 0x6545, 0x67AF, 0x6E56, + 0x72D0, 0x7CCA, 0x88B4, 0x80A1, 0x80E1, 0x83F0, 0x864E, 0x8A87, + 0x8DE8, 0x9237, 0x96C7, 0x9867, 0x9F13, 0x4E94, 0x4E92, 0x4F0D, + 0x5348, 0x5449, 0x543E, 0x5A2F, 0x5F8C, 0x5FA1, 0x609F, 0x68A7, + 0x6A8E, 0x745A, 0x7881, 0x8A9E, 0x8AA4, 0x8B77, 0x9190, 0x4E5E, + 0x9BC9, 0x4EA4, 0x4F7C, 0x4FAF, 0x5019, 0x5016, 0x5149, 0x516C, + 0x529F, 0x52B9, 0x52FE, 0x539A, 0x53E3, 0x5411 + }, + { /* category 25 */ + 0x540E, 0x5589, 0x5751, 0x57A2, 0x597D, 0x5B54, 0x5B5D, 0x5B8F, + 0x5DE5, 0x5DE7, 0x5DF7, 0x5E78, 0x5E83, 0x5E9A, 0x5EB7, 0x5F18, + 0x6052, 0x614C, 0x6297, 0x62D8, 0x63A7, 0x653B, 0x6602, 0x6643, + 0x66F4, 0x676D, 0x6821, 0x6897, 0x69CB, 0x6C5F, 0x6D2A, 0x6D69, + 0x6E2F, 0x6E9D, 0x7532, 0x7687, 0x786C, 0x7A3F, 0x7CE0, 0x7D05, + 0x7D18, 0x7D5E, 0x7DB1, 0x8015, 0x8003, 0x80AF, 0x80B1, 0x8154, + 0x818F, 0x822A, 0x8352, 0x884C, 0x8861, 0x8B1B, 0x8CA2, 0x8CFC, + 0x90CA, 0x9175, 0x9271, 0x783F, 0x92FC, 0x95A4, 0x964D, 0x9805, + 0x9999, 0x9AD8, 0x9D3B, 0x525B, 0x52AB, 0x53F7, 0x5408, 0x58D5, + 0x62F7, 0x6FE0, 0x8C6A, 0x8F5F, 0x9EB9, 0x514B, 0x523B, 0x544A, + 0x56FD, 0x7A40, 0x9177, 0x9D60, 0x9ED2, 0x7344, 0x6F09, 0x8170, + 0x7511, 0x5FFD, 0x60DA, 0x9AA8, 0x72DB, 0x8FBC + }, + { /* category 26 */ + 0x6B64, 0x9803, 0x4ECA, 0x56F0, 0x5764, 0x58BE, 0x5A5A, 0x6068, + 0x61C7, 0x660F, 0x6606, 0x6839, 0x68B1, 0x6DF7, 0x75D5, 0x7D3A, + 0x826E, 0x9B42, 0x4E9B, 0x4F50, 0x53C9, 0x5506, 0x5D6F, 0x5DE6, + 0x5DEE, 0x67FB, 0x6C99, 0x7473, 0x7802, 0x8A50, 0x9396, 0x88DF, + 0x5750, 0x5EA7, 0x632B, 0x50B5, 0x50AC, 0x518D, 0x6700, 0x54C9, + 0x585E, 0x59BB, 0x5BB0, 0x5F69, 0x624D, 0x63A1, 0x683D, 0x6B73, + 0x6E08, 0x707D, 0x91C7, 0x7280, 0x7815, 0x7826, 0x796D, 0x658E, + 0x7D30, 0x83DC, 0x88C1, 0x8F09, 0x969B, 0x5264, 0x5728, 0x6750, + 0x7F6A, 0x8CA1, 0x51B4, 0x5742, 0x962A, 0x583A, 0x698A, 0x80B4, + 0x54B2, 0x5D0E, 0x57FC, 0x7895, 0x9DFA, 0x4F5C, 0x524A, 0x548B, + 0x643E, 0x6628, 0x6714, 0x67F5, 0x7A84, 0x7B56, 0x7D22, 0x932F, + 0x685C, 0x9BAD, 0x7B39, 0x5319, 0x518A, 0x5237 + }, + { /* category 27 */ + 0x5BDF, 0x62F6, 0x64AE, 0x64E6, 0x672D, 0x6BBA, 0x85A9, 0x96D1, + 0x7690, 0x9BD6, 0x634C, 0x9306, 0x9BAB, 0x76BF, 0x6652, 0x4E09, + 0x5098, 0x53C2, 0x5C71, 0x60E8, 0x6492, 0x6563, 0x685F, 0x71E6, + 0x73CA, 0x7523, 0x7B97, 0x7E82, 0x8695, 0x8B83, 0x8CDB, 0x9178, + 0x9910, 0x65AC, 0x66AB, 0x6B8B, 0x4ED5, 0x4ED4, 0x4F3A, 0x4F7F, + 0x523A, 0x53F8, 0x53F2, 0x55E3, 0x56DB, 0x58EB, 0x59CB, 0x59C9, + 0x59FF, 0x5B50, 0x5C4D, 0x5E02, 0x5E2B, 0x5FD7, 0x601D, 0x6307, + 0x652F, 0x5B5C, 0x65AF, 0x65BD, 0x65E8, 0x679D, 0x6B62, 0x6B7B, + 0x6C0F, 0x7345, 0x7949, 0x79C1, 0x7CF8, 0x7D19, 0x7D2B, 0x80A2, + 0x8102, 0x81F3, 0x8996, 0x8A5E, 0x8A69, 0x8A66, 0x8A8C, 0x8AEE, + 0x8CC7, 0x8CDC, 0x96CC, 0x98FC, 0x6B6F, 0x4E8B, 0x4F3C, 0x4F8D, + 0x5150, 0x5B57, 0x5BFA, 0x6148, 0x6301, 0x6642 + }, + { /* category 28 */ + 0x6B21, 0x6ECB, 0x6CBB, 0x723E, 0x74BD, 0x75D4, 0x78C1, 0x793A, + 0x800C, 0x8033, 0x81EA, 0x8494, 0x8F9E, 0x6C50, 0x9E7F, 0x5F0F, + 0x8B58, 0x9D2B, 0x7AFA, 0x8EF8, 0x5B8D, 0x96EB, 0x4E03, 0x53F1, + 0x57F7, 0x5931, 0x5AC9, 0x5BA4, 0x6089, 0x6E7F, 0x6F06, 0x75BE, + 0x8CEA, 0x5B9F, 0x8500, 0x7BE0, 0x5072, 0x67F4, 0x829D, 0x5C61, + 0x854A, 0x7E1E, 0x820E, 0x5199, 0x5C04, 0x6368, 0x8D66, 0x659C, + 0x716E, 0x793E, 0x7D17, 0x8005, 0x8B1D, 0x8ECA, 0x906E, 0x86C7, + 0x90AA, 0x501F, 0x52FA, 0x5C3A, 0x6753, 0x707C, 0x7235, 0x914C, + 0x91C8, 0x932B, 0x82E5, 0x5BC2, 0x5F31, 0x60F9, 0x4E3B, 0x53D6, + 0x5B88, 0x624B, 0x6731, 0x6B8A, 0x72E9, 0x73E0, 0x7A2E, 0x816B, + 0x8DA3, 0x9152, 0x9996, 0x5112, 0x53D7, 0x546A, 0x5BFF, 0x6388, + 0x6A39, 0x7DAC, 0x9700, 0x56DA, 0x53CE, 0x5468 + }, + { /* category 29 */ + 0x5B97, 0x5C31, 0x5DDE, 0x4FEE, 0x6101, 0x62FE, 0x6D32, 0x79C0, + 0x79CB, 0x7D42, 0x7E4D, 0x7FD2, 0x81ED, 0x821F, 0x8490, 0x8846, + 0x8972, 0x8B90, 0x8E74, 0x8F2F, 0x9031, 0x914B, 0x916C, 0x96C6, + 0x919C, 0x4EC0, 0x4F4F, 0x5145, 0x5341, 0x5F93, 0x620E, 0x67D4, + 0x6C41, 0x6E0B, 0x7363, 0x7E26, 0x91CD, 0x9283, 0x53D4, 0x5919, + 0x5BBF, 0x6DD1, 0x795D, 0x7E2E, 0x7C9B, 0x587E, 0x719F, 0x51FA, + 0x8853, 0x8FF0, 0x4FCA, 0x5CFB, 0x6625, 0x77AC, 0x7AE3, 0x821C, + 0x99FF, 0x51C6, 0x5FAA, 0x65EC, 0x696F, 0x6B89, 0x6DF3, 0x6E96, + 0x6F64, 0x76FE, 0x7D14, 0x5DE1, 0x9075, 0x9187, 0x9806, 0x51E6, + 0x521D, 0x6240, 0x6691, 0x66D9, 0x6E1A, 0x5EB6, 0x7DD2, 0x7F72, + 0x66F8, 0x85AF, 0x85F7, 0x8AF8, 0x52A9, 0x53D9, 0x5973, 0x5E8F, + 0x5F90, 0x6055, 0x92E4, 0x9664, 0x50B7, 0x511F + }, + { /* category 30 */ + 0x52DD, 0x5320, 0x5347, 0x53EC, 0x54E8, 0x5546, 0x5531, 0x5617, + 0x5968, 0x59BE, 0x5A3C, 0x5BB5, 0x5C06, 0x5C0F, 0x5C11, 0x5C1A, + 0x5E84, 0x5E8A, 0x5EE0, 0x5F70, 0x627F, 0x6284, 0x62DB, 0x638C, + 0x6377, 0x6607, 0x660C, 0x662D, 0x6676, 0x677E, 0x68A2, 0x6A1F, + 0x6A35, 0x6CBC, 0x6D88, 0x6E09, 0x6E58, 0x713C, 0x7126, 0x7167, + 0x75C7, 0x7701, 0x785D, 0x7901, 0x7965, 0x79F0, 0x7AE0, 0x7B11, + 0x7CA7, 0x7D39, 0x8096, 0x83D6, 0x848B, 0x8549, 0x885D, 0x88F3, + 0x8A1F, 0x8A3C, 0x8A54, 0x8A73, 0x8C61, 0x8CDE, 0x91A4, 0x9266, + 0x937E, 0x9418, 0x969C, 0x9798, 0x4E0A, 0x4E08, 0x4E1E, 0x4E57, + 0x5197, 0x5270, 0x57CE, 0x5834, 0x58CC, 0x5B22, 0x5E38, 0x60C5, + 0x64FE, 0x6761, 0x6756, 0x6D44, 0x72B6, 0x7573, 0x7A63, 0x84B8, + 0x8B72, 0x91B8, 0x9320, 0x5631, 0x57F4, 0x98FE + }, + { /* category 31 */ + 0x62ED, 0x690D, 0x6B96, 0x71ED, 0x7E54, 0x8077, 0x8272, 0x89E6, + 0x98DF, 0x8755, 0x8FB1, 0x5C3B, 0x4F38, 0x4FE1, 0x4FB5, 0x5507, + 0x5A20, 0x5BDD, 0x5BE9, 0x5FC3, 0x614E, 0x632F, 0x65B0, 0x664B, + 0x68EE, 0x699B, 0x6D78, 0x6DF1, 0x7533, 0x75B9, 0x771F, 0x795E, + 0x79E6, 0x7D33, 0x81E3, 0x82AF, 0x85AA, 0x89AA, 0x8A3A, 0x8EAB, + 0x8F9B, 0x9032, 0x91DD, 0x9707, 0x4EBA, 0x4EC1, 0x5203, 0x5875, + 0x58EC, 0x5C0B, 0x751A, 0x5C3D, 0x814E, 0x8A0A, 0x8FC5, 0x9663, + 0x976D, 0x7B25, 0x8ACF, 0x9808, 0x9162, 0x56F3, 0x53A8, 0x9017, + 0x5439, 0x5782, 0x5E25, 0x63A8, 0x6C34, 0x708A, 0x7761, 0x7C8B, + 0x7FE0, 0x8870, 0x9042, 0x9154, 0x9310, 0x9318, 0x968F, 0x745E, + 0x9AC4, 0x5D07, 0x5D69, 0x6570, 0x67A2, 0x8DA8, 0x96DB, 0x636E, + 0x6749, 0x6919, 0x83C5, 0x9817, 0x96C0, 0x88FE + }, + { /* category 32 */ + 0x6F84, 0x647A, 0x5BF8, 0x4E16, 0x702C, 0x755D, 0x662F, 0x51C4, + 0x5236, 0x52E2, 0x59D3, 0x5F81, 0x6027, 0x6210, 0x653F, 0x6574, + 0x661F, 0x6674, 0x68F2, 0x6816, 0x6B63, 0x6E05, 0x7272, 0x751F, + 0x76DB, 0x7CBE, 0x8056, 0x58F0, 0x88FD, 0x897F, 0x8AA0, 0x8A93, + 0x8ACB, 0x901D, 0x9192, 0x9752, 0x9759, 0x6589, 0x7A0E, 0x8106, + 0x96BB, 0x5E2D, 0x60DC, 0x621A, 0x65A5, 0x6614, 0x6790, 0x77F3, + 0x7A4D, 0x7C4D, 0x7E3E, 0x810A, 0x8CAC, 0x8D64, 0x8DE1, 0x8E5F, + 0x78A9, 0x5207, 0x62D9, 0x63A5, 0x6442, 0x6298, 0x8A2D, 0x7A83, + 0x7BC0, 0x8AAC, 0x96EA, 0x7D76, 0x820C, 0x8749, 0x4ED9, 0x5148, + 0x5343, 0x5360, 0x5BA3, 0x5C02, 0x5C16, 0x5DDD, 0x6226, 0x6247, + 0x64B0, 0x6813, 0x6834, 0x6CC9, 0x6D45, 0x6D17, 0x67D3, 0x6F5C, + 0x714E, 0x717D, 0x65CB, 0x7A7F, 0x7BAD, 0x7DDA + }, + { /* category 33 */ + 0x7E4A, 0x7FA8, 0x817A, 0x821B, 0x8239, 0x85A6, 0x8A6E, 0x8CCE, + 0x8DF5, 0x9078, 0x9077, 0x92AD, 0x9291, 0x9583, 0x9BAE, 0x524D, + 0x5584, 0x6F38, 0x7136, 0x5168, 0x7985, 0x7E55, 0x81B3, 0x7CCE, + 0x564C, 0x5851, 0x5CA8, 0x63AA, 0x66FE, 0x66FD, 0x695A, 0x72D9, + 0x758F, 0x758E, 0x790E, 0x7956, 0x79DF, 0x7C97, 0x7D20, 0x7D44, + 0x8607, 0x8A34, 0x963B, 0x9061, 0x9F20, 0x50E7, 0x5275, 0x53CC, + 0x53E2, 0x5009, 0x55AA, 0x58EE, 0x594F, 0x723D, 0x5B8B, 0x5C64, + 0x531D, 0x60E3, 0x60F3, 0x635C, 0x6383, 0x633F, 0x63BB, 0x64CD, + 0x65E9, 0x66F9, 0x5DE3, 0x69CD, 0x69FD, 0x6F15, 0x71E5, 0x4E89, + 0x75E9, 0x76F8, 0x7A93, 0x7CDF, 0x7DCF, 0x7D9C, 0x8061, 0x8349, + 0x8358, 0x846C, 0x84BC, 0x85FB, 0x88C5, 0x8D70, 0x9001, 0x906D, + 0x9397, 0x971C, 0x9A12, 0x50CF, 0x5897, 0x618E + }, + { /* category 34 */ + 0x81D3, 0x8535, 0x8D08, 0x9020, 0x4FC3, 0x5074, 0x5247, 0x5373, + 0x606F, 0x6349, 0x675F, 0x6E2C, 0x8DB3, 0x901F, 0x4FD7, 0x5C5E, + 0x8CCA, 0x65CF, 0x7D9A, 0x5352, 0x8896, 0x5176, 0x63C3, 0x5B58, + 0x5B6B, 0x5C0A, 0x640D, 0x6751, 0x905C, 0x4ED6, 0x591A, 0x592A, + 0x6C70, 0x8A51, 0x553E, 0x5815, 0x59A5, 0x60F0, 0x6253, 0x67C1, + 0x8235, 0x6955, 0x9640, 0x99C4, 0x9A28, 0x4F53, 0x5806, 0x5BFE, + 0x8010, 0x5CB1, 0x5E2F, 0x5F85, 0x6020, 0x614B, 0x6234, 0x66FF, + 0x6CF0, 0x6EDE, 0x80CE, 0x817F, 0x82D4, 0x888B, 0x8CB8, 0x9000, + 0x902E, 0x968A, 0x9EDB, 0x9BDB, 0x4EE3, 0x53F0, 0x5927, 0x7B2C, + 0x918D, 0x984C, 0x9DF9, 0x6EDD, 0x7027, 0x5353, 0x5544, 0x5B85, + 0x6258, 0x629E, 0x62D3, 0x6CA2, 0x6FEF, 0x7422, 0x8A17, 0x9438, + 0x6FC1, 0x8AFE, 0x8338, 0x51E7, 0x86F8, 0x53EA + }, + { /* category 35 */ + 0x53E9, 0x4F46, 0x9054, 0x8FB0, 0x596A, 0x8131, 0x5DFD, 0x7AEA, + 0x8FBF, 0x68DA, 0x8C37, 0x72F8, 0x9C48, 0x6A3D, 0x8AB0, 0x4E39, + 0x5358, 0x5606, 0x5766, 0x62C5, 0x63A2, 0x65E6, 0x6B4E, 0x6DE1, + 0x6E5B, 0x70AD, 0x77ED, 0x7AEF, 0x7BAA, 0x7DBB, 0x803D, 0x80C6, + 0x86CB, 0x8A95, 0x935B, 0x56E3, 0x58C7, 0x5F3E, 0x65AD, 0x6696, + 0x6A80, 0x6BB5, 0x7537, 0x8AC7, 0x5024, 0x77E5, 0x5730, 0x5F1B, + 0x6065, 0x667A, 0x6C60, 0x75F4, 0x7A1A, 0x7F6E, 0x81F4, 0x8718, + 0x9045, 0x99B3, 0x7BC9, 0x755C, 0x7AF9, 0x7B51, 0x84C4, 0x9010, + 0x79E9, 0x7A92, 0x8336, 0x5AE1, 0x7740, 0x4E2D, 0x4EF2, 0x5B99, + 0x5FE0, 0x62BD, 0x663C, 0x67F1, 0x6CE8, 0x866B, 0x8877, 0x8A3B, + 0x914E, 0x92F3, 0x99D0, 0x6A17, 0x7026, 0x732A, 0x82E7, 0x8457, + 0x8CAF, 0x4E01, 0x5146, 0x51CB, 0x558B, 0x5BF5 + }, + { /* category 36 */ + 0x5E16, 0x5E33, 0x5E81, 0x5F14, 0x5F35, 0x5F6B, 0x5FB4, 0x61F2, + 0x6311, 0x66A2, 0x671D, 0x6F6E, 0x7252, 0x753A, 0x773A, 0x8074, + 0x8139, 0x8178, 0x8776, 0x8ABF, 0x8ADC, 0x8D85, 0x8DF3, 0x929A, + 0x9577, 0x9802, 0x9CE5, 0x52C5, 0x6357, 0x76F4, 0x6715, 0x6C88, + 0x73CD, 0x8CC3, 0x93AE, 0x9673, 0x6D25, 0x589C, 0x690E, 0x69CC, + 0x8FFD, 0x939A, 0x75DB, 0x901A, 0x585A, 0x6802, 0x63B4, 0x69FB, + 0x4F43, 0x6F2C, 0x67D8, 0x8FBB, 0x8526, 0x7DB4, 0x9354, 0x693F, + 0x6F70, 0x576A, 0x58F7, 0x5B2C, 0x7D2C, 0x722A, 0x540A, 0x91E3, + 0x9DB4, 0x4EAD, 0x4F4E, 0x505C, 0x5075, 0x5243, 0x8C9E, 0x5448, + 0x5824, 0x5B9A, 0x5E1D, 0x5E95, 0x5EAD, 0x5EF7, 0x5F1F, 0x608C, + 0x62B5, 0x633A, 0x63D0, 0x68AF, 0x6C40, 0x7887, 0x798E, 0x7A0B, + 0x7DE0, 0x8247, 0x8A02, 0x8AE6, 0x8E44, 0x9013 + }, + { /* category 37 */ + 0x90B8, 0x912D, 0x91D8, 0x9F0E, 0x6CE5, 0x6458, 0x64E2, 0x6575, + 0x6EF4, 0x7684, 0x7B1B, 0x9069, 0x93D1, 0x6EBA, 0x54F2, 0x5FB9, + 0x64A4, 0x8F4D, 0x8FED, 0x9244, 0x5178, 0x586B, 0x5929, 0x5C55, + 0x5E97, 0x6DFB, 0x7E8F, 0x751C, 0x8CBC, 0x8EE2, 0x985B, 0x70B9, + 0x4F1D, 0x6BBF, 0x6FB1, 0x7530, 0x96FB, 0x514E, 0x5410, 0x5835, + 0x5857, 0x59AC, 0x5C60, 0x5F92, 0x6597, 0x675C, 0x6E21, 0x767B, + 0x83DF, 0x8CED, 0x9014, 0x90FD, 0x934D, 0x7825, 0x783A, 0x52AA, + 0x5EA6, 0x571F, 0x5974, 0x6012, 0x5012, 0x515A, 0x51AC, 0x51CD, + 0x5200, 0x5510, 0x5854, 0x5858, 0x5957, 0x5B95, 0x5CF6, 0x5D8B, + 0x60BC, 0x6295, 0x642D, 0x6771, 0x6843, 0x68BC, 0x68DF, 0x76D7, + 0x6DD8, 0x6E6F, 0x6D9B, 0x706F, 0x71C8, 0x5F53, 0x75D8, 0x7977, + 0x7B49, 0x7B54, 0x7B52, 0x7CD6, 0x7D71, 0x5230 + }, + { /* category 38 */ + 0x8463, 0x8569, 0x85E4, 0x8A0E, 0x8B04, 0x8C46, 0x8E0F, 0x9003, + 0x900F, 0x9419, 0x9676, 0x982D, 0x9A30, 0x95D8, 0x50CD, 0x52D5, + 0x540C, 0x5802, 0x5C0E, 0x61A7, 0x649E, 0x6D1E, 0x77B3, 0x7AE5, + 0x80F4, 0x8404, 0x9053, 0x9285, 0x5CE0, 0x9D07, 0x533F, 0x5F97, + 0x5FB3, 0x6D9C, 0x7279, 0x7763, 0x79BF, 0x7BE4, 0x6BD2, 0x72EC, + 0x8AAD, 0x6803, 0x6A61, 0x51F8, 0x7A81, 0x6934, 0x5C4A, 0x9CF6, + 0x82EB, 0x5BC5, 0x9149, 0x701E, 0x5678, 0x5C6F, 0x60C7, 0x6566, + 0x6C8C, 0x8C5A, 0x9041, 0x9813, 0x5451, 0x66C7, 0x920D, 0x5948, + 0x90A3, 0x5185, 0x4E4D, 0x51EA, 0x8599, 0x8B0E, 0x7058, 0x637A, + 0x934B, 0x6962, 0x99B4, 0x7E04, 0x7577, 0x5357, 0x6960, 0x8EDF, + 0x96E3, 0x6C5D, 0x4E8C, 0x5C3C, 0x5F10, 0x8FE9, 0x5302, 0x8CD1, + 0x8089, 0x8679, 0x5EFF, 0x65E5, 0x4E73, 0x5165 + }, + { /* category 39 */ + 0x5982, 0x5C3F, 0x97EE, 0x4EFB, 0x598A, 0x5FCD, 0x8A8D, 0x6FE1, + 0x79B0, 0x7962, 0x5BE7, 0x8471, 0x732B, 0x71B1, 0x5E74, 0x5FF5, + 0x637B, 0x649A, 0x71C3, 0x7C98, 0x4E43, 0x5EFC, 0x4E4B, 0x57DC, + 0x56A2, 0x60A9, 0x6FC3, 0x7D0D, 0x80FD, 0x8133, 0x81BF, 0x8FB2, + 0x8997, 0x86A4, 0x5DF4, 0x628A, 0x64AD, 0x8987, 0x6777, 0x6CE2, + 0x6D3E, 0x7436, 0x7834, 0x5A46, 0x7F75, 0x82AD, 0x99AC, 0x4FF3, + 0x5EC3, 0x62DD, 0x6392, 0x6557, 0x676F, 0x76C3, 0x724C, 0x80CC, + 0x80BA, 0x8F29, 0x914D, 0x500D, 0x57F9, 0x5A92, 0x6885, 0x6973, + 0x7164, 0x72FD, 0x8CB7, 0x58F2, 0x8CE0, 0x966A, 0x9019, 0x877F, + 0x79E4, 0x77E7, 0x8429, 0x4F2F, 0x5265, 0x535A, 0x62CD, 0x67CF, + 0x6CCA, 0x767D, 0x7B94, 0x7C95, 0x8236, 0x8584, 0x8FEB, 0x66DD, + 0x6F20, 0x7206, 0x7E1B, 0x83AB, 0x99C1, 0x9EA6 + }, + { /* category 40 */ + 0x51FD, 0x7BB1, 0x7872, 0x7BB8, 0x8087, 0x7B48, 0x6AE8, 0x5E61, + 0x808C, 0x7551, 0x7560, 0x516B, 0x9262, 0x6E8C, 0x767A, 0x9197, + 0x9AEA, 0x4F10, 0x7F70, 0x629C, 0x7B4F, 0x95A5, 0x9CE9, 0x567A, + 0x5859, 0x86E4, 0x96BC, 0x4F34, 0x5224, 0x534A, 0x53CD, 0x53DB, + 0x5E06, 0x642C, 0x6591, 0x677F, 0x6C3E, 0x6C4E, 0x7248, 0x72AF, + 0x73ED, 0x7554, 0x7E41, 0x822C, 0x85E9, 0x8CA9, 0x7BC4, 0x91C6, + 0x7169, 0x9812, 0x98EF, 0x633D, 0x6669, 0x756A, 0x76E4, 0x78D0, + 0x8543, 0x86EE, 0x532A, 0x5351, 0x5426, 0x5983, 0x5E87, 0x5F7C, + 0x60B2, 0x6249, 0x6279, 0x62AB, 0x6590, 0x6BD4, 0x6CCC, 0x75B2, + 0x76AE, 0x7891, 0x79D8, 0x7DCB, 0x7F77, 0x80A5, 0x88AB, 0x8AB9, + 0x8CBB, 0x907F, 0x975E, 0x98DB, 0x6A0B, 0x7C38, 0x5099, 0x5C3E, + 0x5FAE, 0x6787, 0x6BD8, 0x7435, 0x7709, 0x7F8E + }, + { /* category 41 */ + 0x9F3B, 0x67CA, 0x7A17, 0x5339, 0x758B, 0x9AED, 0x5F66, 0x819D, + 0x83F1, 0x8098, 0x5F3C, 0x5FC5, 0x7562, 0x7B46, 0x903C, 0x6867, + 0x59EB, 0x5A9B, 0x7D10, 0x767E, 0x8B2C, 0x4FF5, 0x5F6A, 0x6A19, + 0x6C37, 0x6F02, 0x74E2, 0x7968, 0x8868, 0x8A55, 0x8C79, 0x5EDF, + 0x63CF, 0x75C5, 0x79D2, 0x82D7, 0x9328, 0x92F2, 0x849C, 0x86ED, + 0x9C2D, 0x54C1, 0x5F6C, 0x658C, 0x6D5C, 0x7015, 0x8CA7, 0x8CD3, + 0x983B, 0x654F, 0x74F6, 0x4E0D, 0x4ED8, 0x57E0, 0x592B, 0x5A66, + 0x5BCC, 0x51A8, 0x5E03, 0x5E9C, 0x6016, 0x6276, 0x6577, 0x65A7, + 0x666E, 0x6D6E, 0x7236, 0x7B26, 0x8150, 0x819A, 0x8299, 0x8B5C, + 0x8CA0, 0x8CE6, 0x8D74, 0x961C, 0x9644, 0x4FAE, 0x64AB, 0x6B66, + 0x821E, 0x8461, 0x856A, 0x90E8, 0x5C01, 0x6953, 0x98A8, 0x847A, + 0x8557, 0x4F0F, 0x526F, 0x5FA9, 0x5E45, 0x670D + }, + { /* category 42 */ + 0x798F, 0x8179, 0x8907, 0x8986, 0x6DF5, 0x5F17, 0x6255, 0x6CB8, + 0x4ECF, 0x7269, 0x9B92, 0x5206, 0x543B, 0x5674, 0x58B3, 0x61A4, + 0x626E, 0x711A, 0x596E, 0x7C89, 0x7CDE, 0x7D1B, 0x96F0, 0x6587, + 0x805E, 0x4E19, 0x4F75, 0x5175, 0x5840, 0x5E63, 0x5E73, 0x5F0A, + 0x67C4, 0x4E26, 0x853D, 0x9589, 0x965B, 0x7C73, 0x9801, 0x50FB, + 0x58C1, 0x7656, 0x78A7, 0x5225, 0x77A5, 0x8511, 0x7B86, 0x504F, + 0x5909, 0x7247, 0x7BC7, 0x7DE8, 0x8FBA, 0x8FD4, 0x904D, 0x4FBF, + 0x52C9, 0x5A29, 0x5F01, 0x97AD, 0x4FDD, 0x8217, 0x92EA, 0x5703, + 0x6355, 0x6B69, 0x752B, 0x88DC, 0x8F14, 0x7A42, 0x52DF, 0x5893, + 0x6155, 0x620A, 0x66AE, 0x6BCD, 0x7C3F, 0x83E9, 0x5023, 0x4FF8, + 0x5305, 0x5446, 0x5831, 0x5949, 0x5B9D, 0x5CF0, 0x5CEF, 0x5D29, + 0x5E96, 0x62B1, 0x6367, 0x653E, 0x65B9, 0x670B + }, + { /* category 43 */ + 0x6CD5, 0x6CE1, 0x70F9, 0x7832, 0x7E2B, 0x80DE, 0x82B3, 0x840C, + 0x84EC, 0x8702, 0x8912, 0x8A2A, 0x8C4A, 0x90A6, 0x92D2, 0x98FD, + 0x9CF3, 0x9D6C, 0x4E4F, 0x4EA1, 0x508D, 0x5256, 0x574A, 0x59A8, + 0x5E3D, 0x5FD8, 0x5FD9, 0x623F, 0x66B4, 0x671B, 0x67D0, 0x68D2, + 0x5192, 0x7D21, 0x80AA, 0x81A8, 0x8B00, 0x8C8C, 0x8CBF, 0x927E, + 0x9632, 0x5420, 0x982C, 0x5317, 0x50D5, 0x535C, 0x58A8, 0x64B2, + 0x6734, 0x7267, 0x7766, 0x7A46, 0x91E6, 0x52C3, 0x6CA1, 0x6B86, + 0x5800, 0x5E4C, 0x5954, 0x672C, 0x7FFB, 0x51E1, 0x76C6, 0x6469, + 0x78E8, 0x9B54, 0x9EBB, 0x57CB, 0x59B9, 0x6627, 0x679A, 0x6BCE, + 0x54E9, 0x69D9, 0x5E55, 0x819C, 0x6795, 0x9BAA, 0x67FE, 0x9C52, + 0x685D, 0x4EA6, 0x4FE3, 0x53C8, 0x62B9, 0x672B, 0x6CAB, 0x8FC4, + 0x4FAD, 0x7E6D, 0x9EBF, 0x4E07, 0x6162, 0x6E80 + }, + { /* category 44 */ + 0x6F2B, 0x8513, 0x5473, 0x672A, 0x9B45, 0x5DF3, 0x7B95, 0x5CAC, + 0x5BC6, 0x871C, 0x6E4A, 0x84D1, 0x7A14, 0x8108, 0x5999, 0x7C8D, + 0x6C11, 0x7720, 0x52D9, 0x5922, 0x7121, 0x725F, 0x77DB, 0x9727, + 0x9D61, 0x690B, 0x5A7F, 0x5A18, 0x51A5, 0x540D, 0x547D, 0x660E, + 0x76DF, 0x8FF7, 0x9298, 0x9CF4, 0x59EA, 0x725D, 0x6EC5, 0x514D, + 0x68C9, 0x7DBF, 0x7DEC, 0x9762, 0x9EBA, 0x6478, 0x6A21, 0x8302, + 0x5984, 0x5B5F, 0x6BDB, 0x731B, 0x76F2, 0x7DB2, 0x8017, 0x8499, + 0x5132, 0x6728, 0x9ED9, 0x76EE, 0x6762, 0x52FF, 0x9905, 0x5C24, + 0x623B, 0x7C7E, 0x8CB0, 0x554F, 0x60B6, 0x7D0B, 0x9580, 0x5301, + 0x4E5F, 0x51B6, 0x591C, 0x723A, 0x8036, 0x91CE, 0x5F25, 0x77E2, + 0x5384, 0x5F79, 0x7D04, 0x85AC, 0x8A33, 0x8E8D, 0x9756, 0x67F3, + 0x85AE, 0x9453, 0x6109, 0x6108, 0x6CB9, 0x7652 + }, + { /* category 45 */ + 0x8AED, 0x8F38, 0x552F, 0x4F51, 0x512A, 0x52C7, 0x53CB, 0x5BA5, + 0x5E7D, 0x60A0, 0x6182, 0x63D6, 0x6709, 0x67DA, 0x6E67, 0x6D8C, + 0x7336, 0x7337, 0x7531, 0x7950, 0x88D5, 0x8A98, 0x904A, 0x9091, + 0x90F5, 0x96C4, 0x878D, 0x5915, 0x4E88, 0x4F59, 0x4E0E, 0x8A89, + 0x8F3F, 0x9810, 0x50AD, 0x5E7C, 0x5996, 0x5BB9, 0x5EB8, 0x63DA, + 0x63FA, 0x64C1, 0x66DC, 0x694A, 0x69D8, 0x6D0B, 0x6EB6, 0x7194, + 0x7528, 0x7AAF, 0x7F8A, 0x8000, 0x8449, 0x84C9, 0x8981, 0x8B21, + 0x8E0A, 0x9065, 0x967D, 0x990A, 0x617E, 0x6291, 0x6B32, 0x6C83, + 0x6D74, 0x7FCC, 0x7FFC, 0x6DC0, 0x7F85, 0x87BA, 0x88F8, 0x6765, + 0x83B1, 0x983C, 0x96F7, 0x6D1B, 0x7D61, 0x843D, 0x916A, 0x4E71, + 0x5375, 0x5D50, 0x6B04, 0x6FEB, 0x85CD, 0x862D, 0x89A7, 0x5229, + 0x540F, 0x5C65, 0x674E, 0x68A8, 0x7406, 0x7483 + }, + { /* category 46 */ + 0x75E2, 0x88CF, 0x88E1, 0x91CC, 0x96E2, 0x9678, 0x5F8B, 0x7387, + 0x7ACB, 0x844E, 0x63A0, 0x7565, 0x5289, 0x6D41, 0x6E9C, 0x7409, + 0x7559, 0x786B, 0x7C92, 0x9686, 0x7ADC, 0x9F8D, 0x4FB6, 0x616E, + 0x65C5, 0x865C, 0x4E86, 0x4EAE, 0x50DA, 0x4E21, 0x51CC, 0x5BEE, + 0x6599, 0x6881, 0x6DBC, 0x731F, 0x7642, 0x77AD, 0x7A1C, 0x7CE7, + 0x826F, 0x8AD2, 0x907C, 0x91CF, 0x9675, 0x9818, 0x529B, 0x7DD1, + 0x502B, 0x5398, 0x6797, 0x6DCB, 0x71D0, 0x7433, 0x81E8, 0x8F2A, + 0x96A3, 0x9C57, 0x9E9F, 0x7460, 0x5841, 0x6D99, 0x7D2F, 0x985E, + 0x4EE4, 0x4F36, 0x4F8B, 0x51B7, 0x52B1, 0x5DBA, 0x601C, 0x73B2, + 0x793C, 0x82D3, 0x9234, 0x96B7, 0x96F6, 0x970A, 0x9E97, 0x9F62, + 0x66A6, 0x6B74, 0x5217, 0x52A3, 0x70C8, 0x88C2, 0x5EC9, 0x604B, + 0x6190, 0x6F23, 0x7149, 0x7C3E, 0x7DF4, 0x806F + }, + { /* category 47 */ + 0x84EE, 0x9023, 0x932C, 0x5442, 0x9B6F, 0x6AD3, 0x7089, 0x8CC2, + 0x8DEF, 0x9732, 0x52B4, 0x5A41, 0x5ECA, 0x5F04, 0x6717, 0x697C, + 0x6994, 0x6D6A, 0x6F0F, 0x7262, 0x72FC, 0x7BED, 0x8001, 0x807E, + 0x874B, 0x90CE, 0x516D, 0x9E93, 0x7984, 0x808B, 0x9332, 0x8AD6, + 0x502D, 0x548C, 0x8A71, 0x6B6A, 0x8CC4, 0x8107, 0x60D1, 0x67A0, + 0x9DF2, 0x4E99, 0x4E98, 0x9C10, 0x8A6B, 0x85C1, 0x8568, 0x6900, + 0x6E7E, 0x7897, 0x8155, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 48 */ + 0x5F0C, 0x4E10, 0x4E15, 0x4E2A, 0x4E31, 0x4E36, 0x4E3C, 0x4E3F, + 0x4E42, 0x4E56, 0x4E58, 0x4E82, 0x4E85, 0x8C6B, 0x4E8A, 0x8212, + 0x5F0D, 0x4E8E, 0x4E9E, 0x4E9F, 0x4EA0, 0x4EA2, 0x4EB0, 0x4EB3, + 0x4EB6, 0x4ECE, 0x4ECD, 0x4EC4, 0x4EC6, 0x4EC2, 0x4ED7, 0x4EDE, + 0x4EED, 0x4EDF, 0x4EF7, 0x4F09, 0x4F5A, 0x4F30, 0x4F5B, 0x4F5D, + 0x4F57, 0x4F47, 0x4F76, 0x4F88, 0x4F8F, 0x4F98, 0x4F7B, 0x4F69, + 0x4F70, 0x4F91, 0x4F6F, 0x4F86, 0x4F96, 0x5118, 0x4FD4, 0x4FDF, + 0x4FCE, 0x4FD8, 0x4FDB, 0x4FD1, 0x4FDA, 0x4FD0, 0x4FE4, 0x4FE5, + 0x501A, 0x5028, 0x5014, 0x502A, 0x5025, 0x5005, 0x4F1C, 0x4FF6, + 0x5021, 0x5029, 0x502C, 0x4FFE, 0x4FEF, 0x5011, 0x5006, 0x5043, + 0x5047, 0x6703, 0x5055, 0x5050, 0x5048, 0x505A, 0x5056, 0x506C, + 0x5078, 0x5080, 0x509A, 0x5085, 0x50B4, 0x50B2 + }, + { /* category 49 */ + 0x50C9, 0x50CA, 0x50B3, 0x50C2, 0x50D6, 0x50DE, 0x50E5, 0x50ED, + 0x50E3, 0x50EE, 0x50F9, 0x50F5, 0x5109, 0x5101, 0x5102, 0x5116, + 0x5115, 0x5114, 0x511A, 0x5121, 0x513A, 0x5137, 0x513C, 0x513B, + 0x513F, 0x5140, 0x5152, 0x514C, 0x5154, 0x5162, 0x7AF8, 0x5169, + 0x516A, 0x516E, 0x5180, 0x5182, 0x56D8, 0x518C, 0x5189, 0x518F, + 0x5191, 0x5193, 0x5195, 0x5196, 0x51A4, 0x51A6, 0x51A2, 0x51A9, + 0x51AA, 0x51AB, 0x51B3, 0x51B1, 0x51B2, 0x51B0, 0x51B5, 0x51BD, + 0x51C5, 0x51C9, 0x51DB, 0x51E0, 0x8655, 0x51E9, 0x51ED, 0x51F0, + 0x51F5, 0x51FE, 0x5204, 0x520B, 0x5214, 0x520E, 0x5227, 0x522A, + 0x522E, 0x5233, 0x5239, 0x524F, 0x5244, 0x524B, 0x524C, 0x525E, + 0x5254, 0x526A, 0x5274, 0x5269, 0x5273, 0x527F, 0x527D, 0x528D, + 0x5294, 0x5292, 0x5271, 0x5288, 0x5291, 0x8FA8 + }, + { /* category 50 */ + 0x8FA7, 0x52AC, 0x52AD, 0x52BC, 0x52B5, 0x52C1, 0x52CD, 0x52D7, + 0x52DE, 0x52E3, 0x52E6, 0x98ED, 0x52E0, 0x52F3, 0x52F5, 0x52F8, + 0x52F9, 0x5306, 0x5308, 0x7538, 0x530D, 0x5310, 0x530F, 0x5315, + 0x531A, 0x5323, 0x532F, 0x5331, 0x5333, 0x5338, 0x5340, 0x5346, + 0x5345, 0x4E17, 0x5349, 0x534D, 0x51D6, 0x535E, 0x5369, 0x536E, + 0x5918, 0x537B, 0x5377, 0x5382, 0x5396, 0x53A0, 0x53A6, 0x53A5, + 0x53AE, 0x53B0, 0x53B6, 0x53C3, 0x7C12, 0x96D9, 0x53DF, 0x66FC, + 0x71EE, 0x53EE, 0x53E8, 0x53ED, 0x53FA, 0x5401, 0x543D, 0x5440, + 0x542C, 0x542D, 0x543C, 0x542E, 0x5436, 0x5429, 0x541D, 0x544E, + 0x548F, 0x5475, 0x548E, 0x545F, 0x5471, 0x5477, 0x5470, 0x5492, + 0x547B, 0x5480, 0x5476, 0x5484, 0x5490, 0x5486, 0x54C7, 0x54A2, + 0x54B8, 0x54A5, 0x54AC, 0x54C4, 0x54C8, 0x54A8 + }, + { /* category 51 */ + 0x54AB, 0x54C2, 0x54A4, 0x54BE, 0x54BC, 0x54D8, 0x54E5, 0x54E6, + 0x550F, 0x5514, 0x54FD, 0x54EE, 0x54ED, 0x54FA, 0x54E2, 0x5539, + 0x5540, 0x5563, 0x554C, 0x552E, 0x555C, 0x5545, 0x5556, 0x5557, + 0x5538, 0x5533, 0x555D, 0x5599, 0x5580, 0x54AF, 0x558A, 0x559F, + 0x557B, 0x557E, 0x5598, 0x559E, 0x55AE, 0x557C, 0x5583, 0x55A9, + 0x5587, 0x55A8, 0x55DA, 0x55C5, 0x55DF, 0x55C4, 0x55DC, 0x55E4, + 0x55D4, 0x5614, 0x55F7, 0x5616, 0x55FE, 0x55FD, 0x561B, 0x55F9, + 0x564E, 0x5650, 0x71DF, 0x5634, 0x5636, 0x5632, 0x5638, 0x566B, + 0x5664, 0x562F, 0x566C, 0x566A, 0x5686, 0x5680, 0x568A, 0x56A0, + 0x5694, 0x568F, 0x56A5, 0x56AE, 0x56B6, 0x56B4, 0x56C2, 0x56BC, + 0x56C1, 0x56C3, 0x56C0, 0x56C8, 0x56CE, 0x56D1, 0x56D3, 0x56D7, + 0x56EE, 0x56F9, 0x5700, 0x56FF, 0x5704, 0x5709 + }, + { /* category 52 */ + 0x5708, 0x570B, 0x570D, 0x5713, 0x5718, 0x5716, 0x55C7, 0x571C, + 0x5726, 0x5737, 0x5738, 0x574E, 0x573B, 0x5740, 0x574F, 0x5769, + 0x57C0, 0x5788, 0x5761, 0x577F, 0x5789, 0x5793, 0x57A0, 0x57B3, + 0x57A4, 0x57AA, 0x57B0, 0x57C3, 0x57C6, 0x57D4, 0x57D2, 0x57D3, + 0x580A, 0x57D6, 0x57E3, 0x580B, 0x5819, 0x581D, 0x5872, 0x5821, + 0x5862, 0x584B, 0x5870, 0x6BC0, 0x5852, 0x583D, 0x5879, 0x5885, + 0x58B9, 0x589F, 0x58AB, 0x58BA, 0x58DE, 0x58BB, 0x58B8, 0x58AE, + 0x58C5, 0x58D3, 0x58D1, 0x58D7, 0x58D9, 0x58D8, 0x58E5, 0x58DC, + 0x58E4, 0x58DF, 0x58EF, 0x58FA, 0x58F9, 0x58FB, 0x58FC, 0x58FD, + 0x5902, 0x590A, 0x5910, 0x591B, 0x68A6, 0x5925, 0x592C, 0x592D, + 0x5932, 0x5938, 0x593E, 0x7AD2, 0x5955, 0x5950, 0x594E, 0x595A, + 0x5958, 0x5962, 0x5960, 0x5967, 0x596C, 0x5969 + }, + { /* category 53 */ + 0x5978, 0x5981, 0x599D, 0x4F5E, 0x4FAB, 0x59A3, 0x59B2, 0x59C6, + 0x59E8, 0x59DC, 0x598D, 0x59D9, 0x59DA, 0x5A25, 0x5A1F, 0x5A11, + 0x5A1C, 0x5A09, 0x5A1A, 0x5A40, 0x5A6C, 0x5A49, 0x5A35, 0x5A36, + 0x5A62, 0x5A6A, 0x5A9A, 0x5ABC, 0x5ABE, 0x5ACB, 0x5AC2, 0x5ABD, + 0x5AE3, 0x5AD7, 0x5AE6, 0x5AE9, 0x5AD6, 0x5AFA, 0x5AFB, 0x5B0C, + 0x5B0B, 0x5B16, 0x5B32, 0x5AD0, 0x5B2A, 0x5B36, 0x5B3E, 0x5B43, + 0x5B45, 0x5B40, 0x5B51, 0x5B55, 0x5B5A, 0x5B5B, 0x5B65, 0x5B69, + 0x5B70, 0x5B73, 0x5B75, 0x5B78, 0x6588, 0x5B7A, 0x5B80, 0x5B83, + 0x5BA6, 0x5BB8, 0x5BC3, 0x5BC7, 0x5BC9, 0x5BD4, 0x5BD0, 0x5BE4, + 0x5BE6, 0x5BE2, 0x5BDE, 0x5BE5, 0x5BEB, 0x5BF0, 0x5BF6, 0x5BF3, + 0x5C05, 0x5C07, 0x5C08, 0x5C0D, 0x5C13, 0x5C20, 0x5C22, 0x5C28, + 0x5C38, 0x5C39, 0x5C41, 0x5C46, 0x5C4E, 0x5C53 + }, + { /* category 54 */ + 0x5C50, 0x5C4F, 0x5B71, 0x5C6C, 0x5C6E, 0x4E62, 0x5C76, 0x5C79, + 0x5C8C, 0x5C91, 0x5C94, 0x599B, 0x5CAB, 0x5CBB, 0x5CB6, 0x5CBC, + 0x5CB7, 0x5CC5, 0x5CBE, 0x5CC7, 0x5CD9, 0x5CE9, 0x5CFD, 0x5CFA, + 0x5CED, 0x5D8C, 0x5CEA, 0x5D0B, 0x5D15, 0x5D17, 0x5D5C, 0x5D1F, + 0x5D1B, 0x5D11, 0x5D14, 0x5D22, 0x5D1A, 0x5D19, 0x5D18, 0x5D4C, + 0x5D52, 0x5D4E, 0x5D4B, 0x5D6C, 0x5D73, 0x5D76, 0x5D87, 0x5D84, + 0x5D82, 0x5DA2, 0x5D9D, 0x5DAC, 0x5DAE, 0x5DBD, 0x5D90, 0x5DB7, + 0x5DBC, 0x5DC9, 0x5DCD, 0x5DD3, 0x5DD2, 0x5DD6, 0x5DDB, 0x5DEB, + 0x5DF2, 0x5DF5, 0x5E0B, 0x5E1A, 0x5E19, 0x5E11, 0x5E1B, 0x5E36, + 0x5E37, 0x5E44, 0x5E43, 0x5E40, 0x5E4E, 0x5E57, 0x5E54, 0x5E5F, + 0x5E62, 0x5E64, 0x5E47, 0x5E75, 0x5E76, 0x5E7A, 0x9EBC, 0x5E7F, + 0x5EA0, 0x5EC1, 0x5EC2, 0x5EC8, 0x5ED0, 0x5ECF + }, + { /* category 55 */ + 0x5ED6, 0x5EE3, 0x5EDD, 0x5EDA, 0x5EDB, 0x5EE2, 0x5EE1, 0x5EE8, + 0x5EE9, 0x5EEC, 0x5EF1, 0x5EF3, 0x5EF0, 0x5EF4, 0x5EF8, 0x5EFE, + 0x5F03, 0x5F09, 0x5F5D, 0x5F5C, 0x5F0B, 0x5F11, 0x5F16, 0x5F29, + 0x5F2D, 0x5F38, 0x5F41, 0x5F48, 0x5F4C, 0x5F4E, 0x5F2F, 0x5F51, + 0x5F56, 0x5F57, 0x5F59, 0x5F61, 0x5F6D, 0x5F73, 0x5F77, 0x5F83, + 0x5F82, 0x5F7F, 0x5F8A, 0x5F88, 0x5F91, 0x5F87, 0x5F9E, 0x5F99, + 0x5F98, 0x5FA0, 0x5FA8, 0x5FAD, 0x5FBC, 0x5FD6, 0x5FFB, 0x5FE4, + 0x5FF8, 0x5FF1, 0x5FDD, 0x60B3, 0x5FFF, 0x6021, 0x6060, 0x6019, + 0x6010, 0x6029, 0x600E, 0x6031, 0x601B, 0x6015, 0x602B, 0x6026, + 0x600F, 0x603A, 0x605A, 0x6041, 0x606A, 0x6077, 0x605F, 0x604A, + 0x6046, 0x604D, 0x6063, 0x6043, 0x6064, 0x6042, 0x606C, 0x606B, + 0x6059, 0x6081, 0x608D, 0x60E7, 0x6083, 0x609A + }, + { /* category 56 */ + 0x6084, 0x609B, 0x6096, 0x6097, 0x6092, 0x60A7, 0x608B, 0x60E1, + 0x60B8, 0x60E0, 0x60D3, 0x60B4, 0x5FF0, 0x60BD, 0x60C6, 0x60B5, + 0x60D8, 0x614D, 0x6115, 0x6106, 0x60F6, 0x60F7, 0x6100, 0x60F4, + 0x60FA, 0x6103, 0x6121, 0x60FB, 0x60F1, 0x610D, 0x610E, 0x6147, + 0x613E, 0x6128, 0x6127, 0x614A, 0x613F, 0x613C, 0x612C, 0x6134, + 0x613D, 0x6142, 0x6144, 0x6173, 0x6177, 0x6158, 0x6159, 0x615A, + 0x616B, 0x6174, 0x616F, 0x6165, 0x6171, 0x615F, 0x615D, 0x6153, + 0x6175, 0x6199, 0x6196, 0x6187, 0x61AC, 0x6194, 0x619A, 0x618A, + 0x6191, 0x61AB, 0x61AE, 0x61CC, 0x61CA, 0x61C9, 0x61F7, 0x61C8, + 0x61C3, 0x61C6, 0x61BA, 0x61CB, 0x7F79, 0x61CD, 0x61E6, 0x61E3, + 0x61F6, 0x61FA, 0x61F4, 0x61FF, 0x61FD, 0x61FC, 0x61FE, 0x6200, + 0x6208, 0x6209, 0x620D, 0x620C, 0x6214, 0x621B + }, + { /* category 57 */ + 0x621E, 0x6221, 0x622A, 0x622E, 0x6230, 0x6232, 0x6233, 0x6241, + 0x624E, 0x625E, 0x6263, 0x625B, 0x6260, 0x6268, 0x627C, 0x6282, + 0x6289, 0x627E, 0x6292, 0x6293, 0x6296, 0x62D4, 0x6283, 0x6294, + 0x62D7, 0x62D1, 0x62BB, 0x62CF, 0x62FF, 0x62C6, 0x64D4, 0x62C8, + 0x62DC, 0x62CC, 0x62CA, 0x62C2, 0x62C7, 0x629B, 0x62C9, 0x630C, + 0x62EE, 0x62F1, 0x6327, 0x6302, 0x6308, 0x62EF, 0x62F5, 0x6350, + 0x633E, 0x634D, 0x641C, 0x634F, 0x6396, 0x638E, 0x6380, 0x63AB, + 0x6376, 0x63A3, 0x638F, 0x6389, 0x639F, 0x63B5, 0x636B, 0x6369, + 0x63BE, 0x63E9, 0x63C0, 0x63C6, 0x63E3, 0x63C9, 0x63D2, 0x63F6, + 0x63C4, 0x6416, 0x6434, 0x6406, 0x6413, 0x6426, 0x6436, 0x651D, + 0x6417, 0x6428, 0x640F, 0x6467, 0x646F, 0x6476, 0x644E, 0x652A, + 0x6495, 0x6493, 0x64A5, 0x64A9, 0x6488, 0x64BC + }, + { /* category 58 */ + 0x64DA, 0x64D2, 0x64C5, 0x64C7, 0x64BB, 0x64D8, 0x64C2, 0x64F1, + 0x64E7, 0x8209, 0x64E0, 0x64E1, 0x62AC, 0x64E3, 0x64EF, 0x652C, + 0x64F6, 0x64F4, 0x64F2, 0x64FA, 0x6500, 0x64FD, 0x6518, 0x651C, + 0x6505, 0x6524, 0x6523, 0x652B, 0x6534, 0x6535, 0x6537, 0x6536, + 0x6538, 0x754B, 0x6548, 0x6556, 0x6555, 0x654D, 0x6558, 0x655E, + 0x655D, 0x6572, 0x6578, 0x6582, 0x6583, 0x8B8A, 0x659B, 0x659F, + 0x65AB, 0x65B7, 0x65C3, 0x65C6, 0x65C1, 0x65C4, 0x65CC, 0x65D2, + 0x65DB, 0x65D9, 0x65E0, 0x65E1, 0x65F1, 0x6772, 0x660A, 0x6603, + 0x65FB, 0x6773, 0x6635, 0x6636, 0x6634, 0x661C, 0x664F, 0x6644, + 0x6649, 0x6641, 0x665E, 0x665D, 0x6664, 0x6667, 0x6668, 0x665F, + 0x6662, 0x6670, 0x6683, 0x6688, 0x668E, 0x6689, 0x6684, 0x6698, + 0x669D, 0x66C1, 0x66B9, 0x66C9, 0x66BE, 0x66BC + }, + { /* category 59 */ + 0x66C4, 0x66B8, 0x66D6, 0x66DA, 0x66E0, 0x663F, 0x66E6, 0x66E9, + 0x66F0, 0x66F5, 0x66F7, 0x670F, 0x6716, 0x671E, 0x6726, 0x6727, + 0x9738, 0x672E, 0x673F, 0x6736, 0x6741, 0x6738, 0x6737, 0x6746, + 0x675E, 0x6760, 0x6759, 0x6763, 0x6764, 0x6789, 0x6770, 0x67A9, + 0x677C, 0x676A, 0x678C, 0x678B, 0x67A6, 0x67A1, 0x6785, 0x67B7, + 0x67EF, 0x67B4, 0x67EC, 0x67B3, 0x67E9, 0x67B8, 0x67E4, 0x67DE, + 0x67DD, 0x67E2, 0x67EE, 0x67B9, 0x67CE, 0x67C6, 0x67E7, 0x6A9C, + 0x681E, 0x6846, 0x6829, 0x6840, 0x684D, 0x6832, 0x684E, 0x68B3, + 0x682B, 0x6859, 0x6863, 0x6877, 0x687F, 0x689F, 0x688F, 0x68AD, + 0x6894, 0x689D, 0x689B, 0x6883, 0x6AAE, 0x68B9, 0x6874, 0x68B5, + 0x68A0, 0x68BA, 0x690F, 0x688D, 0x687E, 0x6901, 0x68CA, 0x6908, + 0x68D8, 0x6922, 0x6926, 0x68E1, 0x690C, 0x68CD + }, + { /* category 60 */ + 0x68D4, 0x68E7, 0x68D5, 0x6936, 0x6912, 0x6904, 0x68D7, 0x68E3, + 0x6925, 0x68F9, 0x68E0, 0x68EF, 0x6928, 0x692A, 0x691A, 0x6923, + 0x6921, 0x68C6, 0x6979, 0x6977, 0x695C, 0x6978, 0x696B, 0x6954, + 0x697E, 0x696E, 0x6939, 0x6974, 0x693D, 0x6959, 0x6930, 0x6961, + 0x695E, 0x695D, 0x6981, 0x696A, 0x69B2, 0x69AE, 0x69D0, 0x69BF, + 0x69C1, 0x69D3, 0x69BE, 0x69CE, 0x5BE8, 0x69CA, 0x69DD, 0x69BB, + 0x69C3, 0x69A7, 0x6A2E, 0x6991, 0x69A0, 0x699C, 0x6995, 0x69B4, + 0x69DE, 0x69E8, 0x6A02, 0x6A1B, 0x69FF, 0x6B0A, 0x69F9, 0x69F2, + 0x69E7, 0x6A05, 0x69B1, 0x6A1E, 0x69ED, 0x6A14, 0x69EB, 0x6A0A, + 0x6A12, 0x6AC1, 0x6A23, 0x6A13, 0x6A44, 0x6A0C, 0x6A72, 0x6A36, + 0x6A78, 0x6A47, 0x6A62, 0x6A59, 0x6A66, 0x6A48, 0x6A38, 0x6A22, + 0x6A90, 0x6A8D, 0x6AA0, 0x6A84, 0x6AA2, 0x6AA3 + }, + { /* category 61 */ + 0x6A97, 0x8617, 0x6ABB, 0x6AC3, 0x6AC2, 0x6AB8, 0x6AB3, 0x6AAC, + 0x6ADE, 0x6AD1, 0x6ADF, 0x6AAA, 0x6ADA, 0x6AEA, 0x6AFB, 0x6B05, + 0x8616, 0x6AFA, 0x6B12, 0x6B16, 0x9B31, 0x6B1F, 0x6B38, 0x6B37, + 0x76DC, 0x6B39, 0x98EE, 0x6B47, 0x6B43, 0x6B49, 0x6B50, 0x6B59, + 0x6B54, 0x6B5B, 0x6B5F, 0x6B61, 0x6B78, 0x6B79, 0x6B7F, 0x6B80, + 0x6B84, 0x6B83, 0x6B8D, 0x6B98, 0x6B95, 0x6B9E, 0x6BA4, 0x6BAA, + 0x6BAB, 0x6BAF, 0x6BB2, 0x6BB1, 0x6BB3, 0x6BB7, 0x6BBC, 0x6BC6, + 0x6BCB, 0x6BD3, 0x6BDF, 0x6BEC, 0x6BEB, 0x6BF3, 0x6BEF, 0x9EBE, + 0x6C08, 0x6C13, 0x6C14, 0x6C1B, 0x6C24, 0x6C23, 0x6C5E, 0x6C55, + 0x6C62, 0x6C6A, 0x6C82, 0x6C8D, 0x6C9A, 0x6C81, 0x6C9B, 0x6C7E, + 0x6C68, 0x6C73, 0x6C92, 0x6C90, 0x6CC4, 0x6CF1, 0x6CD3, 0x6CBD, + 0x6CD7, 0x6CC5, 0x6CDD, 0x6CAE, 0x6CB1, 0x6CBE + }, + { /* category 62 */ + 0x6CBA, 0x6CDB, 0x6CEF, 0x6CD9, 0x6CEA, 0x6D1F, 0x884D, 0x6D36, + 0x6D2B, 0x6D3D, 0x6D38, 0x6D19, 0x6D35, 0x6D33, 0x6D12, 0x6D0C, + 0x6D63, 0x6D93, 0x6D64, 0x6D5A, 0x6D79, 0x6D59, 0x6D8E, 0x6D95, + 0x6FE4, 0x6D85, 0x6DF9, 0x6E15, 0x6E0A, 0x6DB5, 0x6DC7, 0x6DE6, + 0x6DB8, 0x6DC6, 0x6DEC, 0x6DDE, 0x6DCC, 0x6DE8, 0x6DD2, 0x6DC5, + 0x6DFA, 0x6DD9, 0x6DE4, 0x6DD5, 0x6DEA, 0x6DEE, 0x6E2D, 0x6E6E, + 0x6E2E, 0x6E19, 0x6E72, 0x6E5F, 0x6E3E, 0x6E23, 0x6E6B, 0x6E2B, + 0x6E76, 0x6E4D, 0x6E1F, 0x6E43, 0x6E3A, 0x6E4E, 0x6E24, 0x6EFF, + 0x6E1D, 0x6E38, 0x6E82, 0x6EAA, 0x6E98, 0x6EC9, 0x6EB7, 0x6ED3, + 0x6EBD, 0x6EAF, 0x6EC4, 0x6EB2, 0x6ED4, 0x6ED5, 0x6E8F, 0x6EA5, + 0x6EC2, 0x6E9F, 0x6F41, 0x6F11, 0x704C, 0x6EEC, 0x6EF8, 0x6EFE, + 0x6F3F, 0x6EF2, 0x6F31, 0x6EEF, 0x6F32, 0x6ECC + }, + { /* category 63 */ + 0x6F3E, 0x6F13, 0x6EF7, 0x6F86, 0x6F7A, 0x6F78, 0x6F81, 0x6F80, + 0x6F6F, 0x6F5B, 0x6FF3, 0x6F6D, 0x6F82, 0x6F7C, 0x6F58, 0x6F8E, + 0x6F91, 0x6FC2, 0x6F66, 0x6FB3, 0x6FA3, 0x6FA1, 0x6FA4, 0x6FB9, + 0x6FC6, 0x6FAA, 0x6FDF, 0x6FD5, 0x6FEC, 0x6FD4, 0x6FD8, 0x6FF1, + 0x6FEE, 0x6FDB, 0x7009, 0x700B, 0x6FFA, 0x7011, 0x7001, 0x700F, + 0x6FFE, 0x701B, 0x701A, 0x6F74, 0x701D, 0x7018, 0x701F, 0x7030, + 0x703E, 0x7032, 0x7051, 0x7063, 0x7099, 0x7092, 0x70AF, 0x70F1, + 0x70AC, 0x70B8, 0x70B3, 0x70AE, 0x70DF, 0x70CB, 0x70DD, 0x70D9, + 0x7109, 0x70FD, 0x711C, 0x7119, 0x7165, 0x7155, 0x7188, 0x7166, + 0x7162, 0x714C, 0x7156, 0x716C, 0x718F, 0x71FB, 0x7184, 0x7195, + 0x71A8, 0x71AC, 0x71D7, 0x71B9, 0x71BE, 0x71D2, 0x71C9, 0x71D4, + 0x71CE, 0x71E0, 0x71EC, 0x71E7, 0x71F5, 0x71FC + }, + { /* category 64 */ + 0x71F9, 0x71FF, 0x720D, 0x7210, 0x721B, 0x7228, 0x722D, 0x722C, + 0x7230, 0x7232, 0x723B, 0x723C, 0x723F, 0x7240, 0x7246, 0x724B, + 0x7258, 0x7274, 0x727E, 0x7282, 0x7281, 0x7287, 0x7292, 0x7296, + 0x72A2, 0x72A7, 0x72B9, 0x72B2, 0x72C3, 0x72C6, 0x72C4, 0x72CE, + 0x72D2, 0x72E2, 0x72E0, 0x72E1, 0x72F9, 0x72F7, 0x500F, 0x7317, + 0x730A, 0x731C, 0x7316, 0x731D, 0x7334, 0x732F, 0x7329, 0x7325, + 0x733E, 0x734E, 0x734F, 0x9ED8, 0x7357, 0x736A, 0x7368, 0x7370, + 0x7378, 0x7375, 0x737B, 0x737A, 0x73C8, 0x73B3, 0x73CE, 0x73BB, + 0x73C0, 0x73E5, 0x73EE, 0x73DE, 0x74A2, 0x7405, 0x746F, 0x7425, + 0x73F8, 0x7432, 0x743A, 0x7455, 0x743F, 0x745F, 0x7459, 0x7441, + 0x745C, 0x7469, 0x7470, 0x7463, 0x746A, 0x7476, 0x747E, 0x748B, + 0x749E, 0x74A7, 0x74CA, 0x74CF, 0x74D4, 0x73F1 + }, + { /* category 65 */ + 0x74E0, 0x74E3, 0x74E7, 0x74E9, 0x74EE, 0x74F2, 0x74F0, 0x74F1, + 0x74F8, 0x74F7, 0x7504, 0x7503, 0x7505, 0x750C, 0x750E, 0x750D, + 0x7515, 0x7513, 0x751E, 0x7526, 0x752C, 0x753C, 0x7544, 0x754D, + 0x754A, 0x7549, 0x755B, 0x7546, 0x755A, 0x7569, 0x7564, 0x7567, + 0x756B, 0x756D, 0x7578, 0x7576, 0x7586, 0x7587, 0x7574, 0x758A, + 0x7589, 0x7582, 0x7594, 0x759A, 0x759D, 0x75A5, 0x75A3, 0x75C2, + 0x75B3, 0x75C3, 0x75B5, 0x75BD, 0x75B8, 0x75BC, 0x75B1, 0x75CD, + 0x75CA, 0x75D2, 0x75D9, 0x75E3, 0x75DE, 0x75FE, 0x75FF, 0x75FC, + 0x7601, 0x75F0, 0x75FA, 0x75F2, 0x75F3, 0x760B, 0x760D, 0x7609, + 0x761F, 0x7627, 0x7620, 0x7621, 0x7622, 0x7624, 0x7634, 0x7630, + 0x763B, 0x7647, 0x7648, 0x7646, 0x765C, 0x7658, 0x7661, 0x7662, + 0x7668, 0x7669, 0x766A, 0x7667, 0x766C, 0x7670 + }, + { /* category 66 */ + 0x7672, 0x7676, 0x7678, 0x767C, 0x7680, 0x7683, 0x7688, 0x768B, + 0x768E, 0x7696, 0x7693, 0x7699, 0x769A, 0x76B0, 0x76B4, 0x76B8, + 0x76B9, 0x76BA, 0x76C2, 0x76CD, 0x76D6, 0x76D2, 0x76DE, 0x76E1, + 0x76E5, 0x76E7, 0x76EA, 0x862F, 0x76FB, 0x7708, 0x7707, 0x7704, + 0x7729, 0x7724, 0x771E, 0x7725, 0x7726, 0x771B, 0x7737, 0x7738, + 0x7747, 0x775A, 0x7768, 0x776B, 0x775B, 0x7765, 0x777F, 0x777E, + 0x7779, 0x778E, 0x778B, 0x7791, 0x77A0, 0x779E, 0x77B0, 0x77B6, + 0x77B9, 0x77BF, 0x77BC, 0x77BD, 0x77BB, 0x77C7, 0x77CD, 0x77D7, + 0x77DA, 0x77DC, 0x77E3, 0x77EE, 0x77FC, 0x780C, 0x7812, 0x7926, + 0x7820, 0x792A, 0x7845, 0x788E, 0x7874, 0x7886, 0x787C, 0x789A, + 0x788C, 0x78A3, 0x78B5, 0x78AA, 0x78AF, 0x78D1, 0x78C6, 0x78CB, + 0x78D4, 0x78BE, 0x78BC, 0x78C5, 0x78CA, 0x78EC + }, + { /* category 67 */ + 0x78E7, 0x78DA, 0x78FD, 0x78F4, 0x7907, 0x7912, 0x7911, 0x7919, + 0x792C, 0x792B, 0x7940, 0x7960, 0x7957, 0x795F, 0x795A, 0x7955, + 0x7953, 0x797A, 0x797F, 0x798A, 0x799D, 0x79A7, 0x9F4B, 0x79AA, + 0x79AE, 0x79B3, 0x79B9, 0x79BA, 0x79C9, 0x79D5, 0x79E7, 0x79EC, + 0x79E1, 0x79E3, 0x7A08, 0x7A0D, 0x7A18, 0x7A19, 0x7A20, 0x7A1F, + 0x7980, 0x7A31, 0x7A3B, 0x7A3E, 0x7A37, 0x7A43, 0x7A57, 0x7A49, + 0x7A61, 0x7A62, 0x7A69, 0x9F9D, 0x7A70, 0x7A79, 0x7A7D, 0x7A88, + 0x7A97, 0x7A95, 0x7A98, 0x7A96, 0x7AA9, 0x7AC8, 0x7AB0, 0x7AB6, + 0x7AC5, 0x7AC4, 0x7ABF, 0x9083, 0x7AC7, 0x7ACA, 0x7ACD, 0x7ACF, + 0x7AD5, 0x7AD3, 0x7AD9, 0x7ADA, 0x7ADD, 0x7AE1, 0x7AE2, 0x7AE6, + 0x7AED, 0x7AF0, 0x7B02, 0x7B0F, 0x7B0A, 0x7B06, 0x7B33, 0x7B18, + 0x7B19, 0x7B1E, 0x7B35, 0x7B28, 0x7B36, 0x7B50 + }, + { /* category 68 */ + 0x7B7A, 0x7B04, 0x7B4D, 0x7B0B, 0x7B4C, 0x7B45, 0x7B75, 0x7B65, + 0x7B74, 0x7B67, 0x7B70, 0x7B71, 0x7B6C, 0x7B6E, 0x7B9D, 0x7B98, + 0x7B9F, 0x7B8D, 0x7B9C, 0x7B9A, 0x7B8B, 0x7B92, 0x7B8F, 0x7B5D, + 0x7B99, 0x7BCB, 0x7BC1, 0x7BCC, 0x7BCF, 0x7BB4, 0x7BC6, 0x7BDD, + 0x7BE9, 0x7C11, 0x7C14, 0x7BE6, 0x7BE5, 0x7C60, 0x7C00, 0x7C07, + 0x7C13, 0x7BF3, 0x7BF7, 0x7C17, 0x7C0D, 0x7BF6, 0x7C23, 0x7C27, + 0x7C2A, 0x7C1F, 0x7C37, 0x7C2B, 0x7C3D, 0x7C4C, 0x7C43, 0x7C54, + 0x7C4F, 0x7C40, 0x7C50, 0x7C58, 0x7C5F, 0x7C64, 0x7C56, 0x7C65, + 0x7C6C, 0x7C75, 0x7C83, 0x7C90, 0x7CA4, 0x7CAD, 0x7CA2, 0x7CAB, + 0x7CA1, 0x7CA8, 0x7CB3, 0x7CB2, 0x7CB1, 0x7CAE, 0x7CB9, 0x7CBD, + 0x7CC0, 0x7CC5, 0x7CC2, 0x7CD8, 0x7CD2, 0x7CDC, 0x7CE2, 0x9B3B, + 0x7CEF, 0x7CF2, 0x7CF4, 0x7CF6, 0x7CFA, 0x7D06 + }, + { /* category 69 */ + 0x7D02, 0x7D1C, 0x7D15, 0x7D0A, 0x7D45, 0x7D4B, 0x7D2E, 0x7D32, + 0x7D3F, 0x7D35, 0x7D46, 0x7D73, 0x7D56, 0x7D4E, 0x7D72, 0x7D68, + 0x7D6E, 0x7D4F, 0x7D63, 0x7D93, 0x7D89, 0x7D5B, 0x7D8F, 0x7D7D, + 0x7D9B, 0x7DBA, 0x7DAE, 0x7DA3, 0x7DB5, 0x7DC7, 0x7DBD, 0x7DAB, + 0x7E3D, 0x7DA2, 0x7DAF, 0x7DDC, 0x7DB8, 0x7D9F, 0x7DB0, 0x7DD8, + 0x7DDD, 0x7DE4, 0x7DDE, 0x7DFB, 0x7DF2, 0x7DE1, 0x7E05, 0x7E0A, + 0x7E23, 0x7E21, 0x7E12, 0x7E31, 0x7E1F, 0x7E09, 0x7E0B, 0x7E22, + 0x7E46, 0x7E66, 0x7E3B, 0x7E35, 0x7E39, 0x7E43, 0x7E37, 0x7E32, + 0x7E3A, 0x7E67, 0x7E5D, 0x7E56, 0x7E5E, 0x7E59, 0x7E5A, 0x7E79, + 0x7E6A, 0x7E69, 0x7E7C, 0x7E7B, 0x7E83, 0x7DD5, 0x7E7D, 0x8FAE, + 0x7E7F, 0x7E88, 0x7E89, 0x7E8C, 0x7E92, 0x7E90, 0x7E93, 0x7E94, + 0x7E96, 0x7E8E, 0x7E9B, 0x7E9C, 0x7F38, 0x7F3A + }, + { /* category 70 */ + 0x7F45, 0x7F4C, 0x7F4D, 0x7F4E, 0x7F50, 0x7F51, 0x7F55, 0x7F54, + 0x7F58, 0x7F5F, 0x7F60, 0x7F68, 0x7F69, 0x7F67, 0x7F78, 0x7F82, + 0x7F86, 0x7F83, 0x7F88, 0x7F87, 0x7F8C, 0x7F94, 0x7F9E, 0x7F9D, + 0x7F9A, 0x7FA3, 0x7FAF, 0x7FB2, 0x7FB9, 0x7FAE, 0x7FB6, 0x7FB8, + 0x8B71, 0x7FC5, 0x7FC6, 0x7FCA, 0x7FD5, 0x7FD4, 0x7FE1, 0x7FE6, + 0x7FE9, 0x7FF3, 0x7FF9, 0x98DC, 0x8006, 0x8004, 0x800B, 0x8012, + 0x8018, 0x8019, 0x801C, 0x8021, 0x8028, 0x803F, 0x803B, 0x804A, + 0x8046, 0x8052, 0x8058, 0x805A, 0x805F, 0x8062, 0x8068, 0x8073, + 0x8072, 0x8070, 0x8076, 0x8079, 0x807D, 0x807F, 0x8084, 0x8086, + 0x8085, 0x809B, 0x8093, 0x809A, 0x80AD, 0x5190, 0x80AC, 0x80DB, + 0x80E5, 0x80D9, 0x80DD, 0x80C4, 0x80DA, 0x80D6, 0x8109, 0x80EF, + 0x80F1, 0x811B, 0x8129, 0x8123, 0x812F, 0x814B + }, + { /* category 71 */ + 0x968B, 0x8146, 0x813E, 0x8153, 0x8151, 0x80FC, 0x8171, 0x816E, + 0x8165, 0x8166, 0x8174, 0x8183, 0x8188, 0x818A, 0x8180, 0x8182, + 0x81A0, 0x8195, 0x81A4, 0x81A3, 0x815F, 0x8193, 0x81A9, 0x81B0, + 0x81B5, 0x81BE, 0x81B8, 0x81BD, 0x81C0, 0x81C2, 0x81BA, 0x81C9, + 0x81CD, 0x81D1, 0x81D9, 0x81D8, 0x81C8, 0x81DA, 0x81DF, 0x81E0, + 0x81E7, 0x81FA, 0x81FB, 0x81FE, 0x8201, 0x8202, 0x8205, 0x8207, + 0x820A, 0x820D, 0x8210, 0x8216, 0x8229, 0x822B, 0x8238, 0x8233, + 0x8240, 0x8259, 0x8258, 0x825D, 0x825A, 0x825F, 0x8264, 0x8262, + 0x8268, 0x826A, 0x826B, 0x822E, 0x8271, 0x8277, 0x8278, 0x827E, + 0x828D, 0x8292, 0x82AB, 0x829F, 0x82BB, 0x82AC, 0x82E1, 0x82E3, + 0x82DF, 0x82D2, 0x82F4, 0x82F3, 0x82FA, 0x8393, 0x8303, 0x82FB, + 0x82F9, 0x82DE, 0x8306, 0x82DC, 0x8309, 0x82D9 + }, + { /* category 72 */ + 0x8335, 0x8334, 0x8316, 0x8332, 0x8331, 0x8340, 0x8339, 0x8350, + 0x8345, 0x832F, 0x832B, 0x8317, 0x8318, 0x8385, 0x839A, 0x83AA, + 0x839F, 0x83A2, 0x8396, 0x8323, 0x838E, 0x8387, 0x838A, 0x837C, + 0x83B5, 0x8373, 0x8375, 0x83A0, 0x8389, 0x83A8, 0x83F4, 0x8413, + 0x83EB, 0x83CE, 0x83FD, 0x8403, 0x83D8, 0x840B, 0x83C1, 0x83F7, + 0x8407, 0x83E0, 0x83F2, 0x840D, 0x8422, 0x8420, 0x83BD, 0x8438, + 0x8506, 0x83FB, 0x846D, 0x842A, 0x843C, 0x855A, 0x8484, 0x8477, + 0x846B, 0x84AD, 0x846E, 0x8482, 0x8469, 0x8446, 0x842C, 0x846F, + 0x8479, 0x8435, 0x84CA, 0x8462, 0x84B9, 0x84BF, 0x849F, 0x84D9, + 0x84CD, 0x84BB, 0x84DA, 0x84D0, 0x84C1, 0x84C6, 0x84D6, 0x84A1, + 0x8521, 0x84FF, 0x84F4, 0x8517, 0x8518, 0x852C, 0x851F, 0x8515, + 0x8514, 0x84FC, 0x8540, 0x8563, 0x8558, 0x8548 + }, + { /* category 73 */ + 0x8541, 0x8602, 0x854B, 0x8555, 0x8580, 0x85A4, 0x8588, 0x8591, + 0x858A, 0x85A8, 0x856D, 0x8594, 0x859B, 0x85EA, 0x8587, 0x859C, + 0x8577, 0x857E, 0x8590, 0x85C9, 0x85BA, 0x85CF, 0x85B9, 0x85D0, + 0x85D5, 0x85DD, 0x85E5, 0x85DC, 0x85F9, 0x860A, 0x8613, 0x860B, + 0x85FE, 0x85FA, 0x8606, 0x8622, 0x861A, 0x8630, 0x863F, 0x864D, + 0x4E55, 0x8654, 0x865F, 0x8667, 0x8671, 0x8693, 0x86A3, 0x86A9, + 0x86AA, 0x868B, 0x868C, 0x86B6, 0x86AF, 0x86C4, 0x86C6, 0x86B0, + 0x86C9, 0x8823, 0x86AB, 0x86D4, 0x86DE, 0x86E9, 0x86EC, 0x86DF, + 0x86DB, 0x86EF, 0x8712, 0x8706, 0x8708, 0x8700, 0x8703, 0x86FB, + 0x8711, 0x8709, 0x870D, 0x86F9, 0x870A, 0x8734, 0x873F, 0x8737, + 0x873B, 0x8725, 0x8729, 0x871A, 0x8760, 0x875F, 0x8778, 0x874C, + 0x874E, 0x8774, 0x8757, 0x8768, 0x876E, 0x8759 + }, + { /* category 74 */ + 0x8753, 0x8763, 0x876A, 0x8805, 0x87A2, 0x879F, 0x8782, 0x87AF, + 0x87CB, 0x87BD, 0x87C0, 0x87D0, 0x96D6, 0x87AB, 0x87C4, 0x87B3, + 0x87C7, 0x87C6, 0x87BB, 0x87EF, 0x87F2, 0x87E0, 0x880F, 0x880D, + 0x87FE, 0x87F6, 0x87F7, 0x880E, 0x87D2, 0x8811, 0x8816, 0x8815, + 0x8822, 0x8821, 0x8831, 0x8836, 0x8839, 0x8827, 0x883B, 0x8844, + 0x8842, 0x8852, 0x8859, 0x885E, 0x8862, 0x886B, 0x8881, 0x887E, + 0x889E, 0x8875, 0x887D, 0x88B5, 0x8872, 0x8882, 0x8897, 0x8892, + 0x88AE, 0x8899, 0x88A2, 0x888D, 0x88A4, 0x88B0, 0x88BF, 0x88B1, + 0x88C3, 0x88C4, 0x88D4, 0x88D8, 0x88D9, 0x88DD, 0x88F9, 0x8902, + 0x88FC, 0x88F4, 0x88E8, 0x88F2, 0x8904, 0x890C, 0x890A, 0x8913, + 0x8943, 0x891E, 0x8925, 0x892A, 0x892B, 0x8941, 0x8944, 0x893B, + 0x8936, 0x8938, 0x894C, 0x891D, 0x8960, 0x895E + }, + { /* category 75 */ + 0x8966, 0x8964, 0x896D, 0x896A, 0x896F, 0x8974, 0x8977, 0x897E, + 0x8983, 0x8988, 0x898A, 0x8993, 0x8998, 0x89A1, 0x89A9, 0x89A6, + 0x89AC, 0x89AF, 0x89B2, 0x89BA, 0x89BD, 0x89BF, 0x89C0, 0x89DA, + 0x89DC, 0x89DD, 0x89E7, 0x89F4, 0x89F8, 0x8A03, 0x8A16, 0x8A10, + 0x8A0C, 0x8A1B, 0x8A1D, 0x8A25, 0x8A36, 0x8A41, 0x8A5B, 0x8A52, + 0x8A46, 0x8A48, 0x8A7C, 0x8A6D, 0x8A6C, 0x8A62, 0x8A85, 0x8A82, + 0x8A84, 0x8AA8, 0x8AA1, 0x8A91, 0x8AA5, 0x8AA6, 0x8A9A, 0x8AA3, + 0x8AC4, 0x8ACD, 0x8AC2, 0x8ADA, 0x8AEB, 0x8AF3, 0x8AE7, 0x8AE4, + 0x8AF1, 0x8B14, 0x8AE0, 0x8AE2, 0x8AF7, 0x8ADE, 0x8ADB, 0x8B0C, + 0x8B07, 0x8B1A, 0x8AE1, 0x8B16, 0x8B10, 0x8B17, 0x8B20, 0x8B33, + 0x97AB, 0x8B26, 0x8B2B, 0x8B3E, 0x8B28, 0x8B41, 0x8B4C, 0x8B4F, + 0x8B4E, 0x8B49, 0x8B56, 0x8B5B, 0x8B5A, 0x8B6B + }, + { /* category 76 */ + 0x8B5F, 0x8B6C, 0x8B6F, 0x8B74, 0x8B7D, 0x8B80, 0x8B8C, 0x8B8E, + 0x8B92, 0x8B93, 0x8B96, 0x8B99, 0x8B9A, 0x8C3A, 0x8C41, 0x8C3F, + 0x8C48, 0x8C4C, 0x8C4E, 0x8C50, 0x8C55, 0x8C62, 0x8C6C, 0x8C78, + 0x8C7A, 0x8C82, 0x8C89, 0x8C85, 0x8C8A, 0x8C8D, 0x8C8E, 0x8C94, + 0x8C7C, 0x8C98, 0x621D, 0x8CAD, 0x8CAA, 0x8CBD, 0x8CB2, 0x8CB3, + 0x8CAE, 0x8CB6, 0x8CC8, 0x8CC1, 0x8CE4, 0x8CE3, 0x8CDA, 0x8CFD, + 0x8CFA, 0x8CFB, 0x8D04, 0x8D05, 0x8D0A, 0x8D07, 0x8D0F, 0x8D0D, + 0x8D10, 0x9F4E, 0x8D13, 0x8CCD, 0x8D14, 0x8D16, 0x8D67, 0x8D6D, + 0x8D71, 0x8D73, 0x8D81, 0x8D99, 0x8DC2, 0x8DBE, 0x8DBA, 0x8DCF, + 0x8DDA, 0x8DD6, 0x8DCC, 0x8DDB, 0x8DCB, 0x8DEA, 0x8DEB, 0x8DDF, + 0x8DE3, 0x8DFC, 0x8E08, 0x8E09, 0x8DFF, 0x8E1D, 0x8E1E, 0x8E10, + 0x8E1F, 0x8E42, 0x8E35, 0x8E30, 0x8E34, 0x8E4A + }, + { /* category 77 */ + 0x8E47, 0x8E49, 0x8E4C, 0x8E50, 0x8E48, 0x8E59, 0x8E64, 0x8E60, + 0x8E2A, 0x8E63, 0x8E55, 0x8E76, 0x8E72, 0x8E7C, 0x8E81, 0x8E87, + 0x8E85, 0x8E84, 0x8E8B, 0x8E8A, 0x8E93, 0x8E91, 0x8E94, 0x8E99, + 0x8EAA, 0x8EA1, 0x8EAC, 0x8EB0, 0x8EC6, 0x8EB1, 0x8EBE, 0x8EC5, + 0x8EC8, 0x8ECB, 0x8EDB, 0x8EE3, 0x8EFC, 0x8EFB, 0x8EEB, 0x8EFE, + 0x8F0A, 0x8F05, 0x8F15, 0x8F12, 0x8F19, 0x8F13, 0x8F1C, 0x8F1F, + 0x8F1B, 0x8F0C, 0x8F26, 0x8F33, 0x8F3B, 0x8F39, 0x8F45, 0x8F42, + 0x8F3E, 0x8F4C, 0x8F49, 0x8F46, 0x8F4E, 0x8F57, 0x8F5C, 0x8F62, + 0x8F63, 0x8F64, 0x8F9C, 0x8F9F, 0x8FA3, 0x8FAD, 0x8FAF, 0x8FB7, + 0x8FDA, 0x8FE5, 0x8FE2, 0x8FEA, 0x8FEF, 0x9087, 0x8FF4, 0x9005, + 0x8FF9, 0x8FFA, 0x9011, 0x9015, 0x9021, 0x900D, 0x901E, 0x9016, + 0x900B, 0x9027, 0x9036, 0x9035, 0x9039, 0x8FF8 + }, + { /* category 78 */ + 0x904F, 0x9050, 0x9051, 0x9052, 0x900E, 0x9049, 0x903E, 0x9056, + 0x9058, 0x905E, 0x9068, 0x906F, 0x9076, 0x96A8, 0x9072, 0x9082, + 0x907D, 0x9081, 0x9080, 0x908A, 0x9089, 0x908F, 0x90A8, 0x90AF, + 0x90B1, 0x90B5, 0x90E2, 0x90E4, 0x6248, 0x90DB, 0x9102, 0x9112, + 0x9119, 0x9132, 0x9130, 0x914A, 0x9156, 0x9158, 0x9163, 0x9165, + 0x9169, 0x9173, 0x9172, 0x918B, 0x9189, 0x9182, 0x91A2, 0x91AB, + 0x91AF, 0x91AA, 0x91B5, 0x91B4, 0x91BA, 0x91C0, 0x91C1, 0x91C9, + 0x91CB, 0x91D0, 0x91D6, 0x91DF, 0x91E1, 0x91DB, 0x91FC, 0x91F5, + 0x91F6, 0x921E, 0x91FF, 0x9214, 0x922C, 0x9215, 0x9211, 0x925E, + 0x9257, 0x9245, 0x9249, 0x9264, 0x9248, 0x9295, 0x923F, 0x924B, + 0x9250, 0x929C, 0x9296, 0x9293, 0x929B, 0x925A, 0x92CF, 0x92B9, + 0x92B7, 0x92E9, 0x930F, 0x92FA, 0x9344, 0x932E + }, + { /* category 79 */ + 0x9319, 0x9322, 0x931A, 0x9323, 0x933A, 0x9335, 0x933B, 0x935C, + 0x9360, 0x937C, 0x936E, 0x9356, 0x93B0, 0x93AC, 0x93AD, 0x9394, + 0x93B9, 0x93D6, 0x93D7, 0x93E8, 0x93E5, 0x93D8, 0x93C3, 0x93DD, + 0x93D0, 0x93C8, 0x93E4, 0x941A, 0x9414, 0x9413, 0x9403, 0x9407, + 0x9410, 0x9436, 0x942B, 0x9435, 0x9421, 0x943A, 0x9441, 0x9452, + 0x9444, 0x945B, 0x9460, 0x9462, 0x945E, 0x946A, 0x9229, 0x9470, + 0x9475, 0x9477, 0x947D, 0x945A, 0x947C, 0x947E, 0x9481, 0x947F, + 0x9582, 0x9587, 0x958A, 0x9594, 0x9596, 0x9598, 0x9599, 0x95A0, + 0x95A8, 0x95A7, 0x95AD, 0x95BC, 0x95BB, 0x95B9, 0x95BE, 0x95CA, + 0x6FF6, 0x95C3, 0x95CD, 0x95CC, 0x95D5, 0x95D4, 0x95D6, 0x95DC, + 0x95E1, 0x95E5, 0x95E2, 0x9621, 0x9628, 0x962E, 0x962F, 0x9642, + 0x964C, 0x964F, 0x964B, 0x9677, 0x965C, 0x965E + }, + { /* category 80 */ + 0x965D, 0x965F, 0x9666, 0x9672, 0x966C, 0x968D, 0x9698, 0x9695, + 0x9697, 0x96AA, 0x96A7, 0x96B1, 0x96B2, 0x96B0, 0x96B4, 0x96B6, + 0x96B8, 0x96B9, 0x96CE, 0x96CB, 0x96C9, 0x96CD, 0x894D, 0x96DC, + 0x970D, 0x96D5, 0x96F9, 0x9704, 0x9706, 0x9708, 0x9713, 0x970E, + 0x9711, 0x970F, 0x9716, 0x9719, 0x9724, 0x972A, 0x9730, 0x9739, + 0x973D, 0x973E, 0x9744, 0x9746, 0x9748, 0x9742, 0x9749, 0x975C, + 0x9760, 0x9764, 0x9766, 0x9768, 0x52D2, 0x976B, 0x9771, 0x9779, + 0x9785, 0x977C, 0x9781, 0x977A, 0x9786, 0x978B, 0x978F, 0x9790, + 0x979C, 0x97A8, 0x97A6, 0x97A3, 0x97B3, 0x97B4, 0x97C3, 0x97C6, + 0x97C8, 0x97CB, 0x97DC, 0x97ED, 0x9F4F, 0x97F2, 0x7ADF, 0x97F6, + 0x97F5, 0x980F, 0x980C, 0x9838, 0x9824, 0x9821, 0x9837, 0x983D, + 0x9846, 0x984F, 0x984B, 0x986B, 0x986F, 0x9870 + }, + { /* category 81 */ + 0x9871, 0x9874, 0x9873, 0x98AA, 0x98AF, 0x98B1, 0x98B6, 0x98C4, + 0x98C3, 0x98C6, 0x98E9, 0x98EB, 0x9903, 0x9909, 0x9912, 0x9914, + 0x9918, 0x9921, 0x991D, 0x991E, 0x9924, 0x9920, 0x992C, 0x992E, + 0x993D, 0x993E, 0x9942, 0x9949, 0x9945, 0x9950, 0x994B, 0x9951, + 0x9952, 0x994C, 0x9955, 0x9997, 0x9998, 0x99A5, 0x99AD, 0x99AE, + 0x99BC, 0x99DF, 0x99DB, 0x99DD, 0x99D8, 0x99D1, 0x99ED, 0x99EE, + 0x99F1, 0x99F2, 0x99FB, 0x99F8, 0x9A01, 0x9A0F, 0x9A05, 0x99E2, + 0x9A19, 0x9A2B, 0x9A37, 0x9A45, 0x9A42, 0x9A40, 0x9A43, 0x9A3E, + 0x9A55, 0x9A4D, 0x9A5B, 0x9A57, 0x9A5F, 0x9A62, 0x9A65, 0x9A64, + 0x9A69, 0x9A6B, 0x9A6A, 0x9AAD, 0x9AB0, 0x9ABC, 0x9AC0, 0x9ACF, + 0x9AD1, 0x9AD3, 0x9AD4, 0x9ADE, 0x9ADF, 0x9AE2, 0x9AE3, 0x9AE6, + 0x9AEF, 0x9AEB, 0x9AEE, 0x9AF4, 0x9AF1, 0x9AF7 + }, + { /* category 82 */ + 0x9AFB, 0x9B06, 0x9B18, 0x9B1A, 0x9B1F, 0x9B22, 0x9B23, 0x9B25, + 0x9B27, 0x9B28, 0x9B29, 0x9B2A, 0x9B2E, 0x9B2F, 0x9B32, 0x9B44, + 0x9B43, 0x9B4F, 0x9B4D, 0x9B4E, 0x9B51, 0x9B58, 0x9B74, 0x9B93, + 0x9B83, 0x9B91, 0x9B96, 0x9B97, 0x9B9F, 0x9BA0, 0x9BA8, 0x9BB4, + 0x9BC0, 0x9BCA, 0x9BB9, 0x9BC6, 0x9BCF, 0x9BD1, 0x9BD2, 0x9BE3, + 0x9BE2, 0x9BE4, 0x9BD4, 0x9BE1, 0x9C3A, 0x9BF2, 0x9BF1, 0x9BF0, + 0x9C15, 0x9C14, 0x9C09, 0x9C13, 0x9C0C, 0x9C06, 0x9C08, 0x9C12, + 0x9C0A, 0x9C04, 0x9C2E, 0x9C1B, 0x9C25, 0x9C24, 0x9C21, 0x9C30, + 0x9C47, 0x9C32, 0x9C46, 0x9C3E, 0x9C5A, 0x9C60, 0x9C67, 0x9C76, + 0x9C78, 0x9CE7, 0x9CEC, 0x9CF0, 0x9D09, 0x9D08, 0x9CEB, 0x9D03, + 0x9D06, 0x9D2A, 0x9D26, 0x9DAF, 0x9D23, 0x9D1F, 0x9D44, 0x9D15, + 0x9D12, 0x9D41, 0x9D3F, 0x9D3E, 0x9D46, 0x9D48 + }, + { /* category 83 */ + 0x9D5D, 0x9D5E, 0x9D64, 0x9D51, 0x9D50, 0x9D59, 0x9D72, 0x9D89, + 0x9D87, 0x9DAB, 0x9D6F, 0x9D7A, 0x9D9A, 0x9DA4, 0x9DA9, 0x9DB2, + 0x9DC4, 0x9DC1, 0x9DBB, 0x9DB8, 0x9DBA, 0x9DC6, 0x9DCF, 0x9DC2, + 0x9DD9, 0x9DD3, 0x9DF8, 0x9DE6, 0x9DED, 0x9DEF, 0x9DFD, 0x9E1A, + 0x9E1B, 0x9E1E, 0x9E75, 0x9E79, 0x9E7D, 0x9E81, 0x9E88, 0x9E8B, + 0x9E8C, 0x9E92, 0x9E95, 0x9E91, 0x9E9D, 0x9EA5, 0x9EA9, 0x9EB8, + 0x9EAA, 0x9EAD, 0x9761, 0x9ECC, 0x9ECE, 0x9ECF, 0x9ED0, 0x9ED4, + 0x9EDC, 0x9EDE, 0x9EDD, 0x9EE0, 0x9EE5, 0x9EE8, 0x9EEF, 0x9EF4, + 0x9EF6, 0x9EF7, 0x9EF9, 0x9EFB, 0x9EFC, 0x9EFD, 0x9F07, 0x9F08, + 0x76B7, 0x9F15, 0x9F21, 0x9F2C, 0x9F3E, 0x9F4A, 0x9F52, 0x9F54, + 0x9F63, 0x9F5F, 0x9F60, 0x9F61, 0x9F66, 0x9F67, 0x9F6C, 0x9F6A, + 0x9F77, 0x9F72, 0x9F76, 0x9F95, 0x9F9C, 0x9FA0 + }, + { /* category 84 */ + 0x582F, 0x69C7, 0x9059, 0x7464, 0x51DC, 0x7199, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 85 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 86 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 87 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 88 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 89 */ + 0x7E8A, 0x891C, 0x9348, 0x9288, 0x84DC, 0x4FC9, 0x70BB, 0x6631, + 0x68C8, 0x92F9, 0x66FB, 0x5F45, 0x4E28, 0x4EE1, 0x4EFC, 0x4F00, + 0x4F03, 0x4F39, 0x4F56, 0x4F92, 0x4F8A, 0x4F9A, 0x4F94, 0x4FCD, + 0x5040, 0x5022, 0x4FFF, 0x501E, 0x5046, 0x5070, 0x5042, 0x5094, + 0x50F4, 0x50D8, 0x514A, 0x5164, 0x519D, 0x51BE, 0x51EC, 0x5215, + 0x529C, 0x52A6, 0x52C0, 0x52DB, 0x5300, 0x5307, 0x5324, 0x5372, + 0x5393, 0x53B2, 0x53DD, 0xFA0E, 0x549C, 0x548A, 0x54A9, 0x54FF, + 0x5586, 0x5759, 0x5765, 0x57AC, 0x57C8, 0x57C7, 0xFA0F, 0xFA10, + 0x589E, 0x58B2, 0x590B, 0x5953, 0x595B, 0x595D, 0x5963, 0x59A4, + 0x59BA, 0x5B56, 0x5BC0, 0x752F, 0x5BD8, 0x5BEC, 0x5C1E, 0x5CA6, + 0x5CBA, 0x5CF5, 0x5D27, 0x5D53, 0xFA11, 0x5D42, 0x5D6D, 0x5DB8, + 0x5DB9, 0x5DD0, 0x5F21, 0x5F34, 0x5F67, 0x5FB7 + }, + { /* category 90 */ + 0x5FDE, 0x605D, 0x6085, 0x608A, 0x60DE, 0x60D5, 0x6120, 0x60F2, + 0x6111, 0x6137, 0x6130, 0x6198, 0x6213, 0x62A6, 0x63F5, 0x6460, + 0x649D, 0x64CE, 0x654E, 0x6600, 0x6615, 0x663B, 0x6609, 0x662E, + 0x661E, 0x6624, 0x6665, 0x6657, 0x6659, 0xFA12, 0x6673, 0x6699, + 0x66A0, 0x66B2, 0x66BF, 0x66FA, 0x670E, 0xF929, 0x6766, 0x67BB, + 0x6852, 0x67C0, 0x6801, 0x6844, 0x68CF, 0xFA13, 0x6968, 0xFA14, + 0x6998, 0x69E2, 0x6A30, 0x6A6B, 0x6A46, 0x6A73, 0x6A7E, 0x6AE2, + 0x6AE4, 0x6BD6, 0x6C3F, 0x6C5C, 0x6C86, 0x6C6F, 0x6CDA, 0x6D04, + 0x6D87, 0x6D6F, 0x6D96, 0x6DAC, 0x6DCF, 0x6DF8, 0x6DF2, 0x6DFC, + 0x6E39, 0x6E5C, 0x6E27, 0x6E3C, 0x6EBF, 0x6F88, 0x6FB5, 0x6FF5, + 0x7005, 0x7007, 0x7028, 0x7085, 0x70AB, 0x710F, 0x7104, 0x715C, + 0x7146, 0x7147, 0xFA15, 0x71C1, 0x71FE, 0x72B1 + }, + { /* category 91 */ + 0x72BE, 0x7324, 0xFA16, 0x7377, 0x73BD, 0x73C9, 0x73D6, 0x73E3, + 0x73D2, 0x7407, 0x73F5, 0x7426, 0x742A, 0x7429, 0x742E, 0x7462, + 0x7489, 0x749F, 0x7501, 0x756F, 0x7682, 0x769C, 0x769E, 0x769B, + 0x76A6, 0xFA17, 0x7746, 0x52AF, 0x7821, 0x784E, 0x7864, 0x787A, + 0x7930, 0xFA18, 0xFA19, 0xFA1A, 0x7994, 0xFA1B, 0x799B, 0x7AD1, + 0x7AE7, 0xFA1C, 0x7AEB, 0x7B9E, 0xFA1D, 0x7D48, 0x7D5C, 0x7DB7, + 0x7DA0, 0x7DD6, 0x7E52, 0x7F47, 0x7FA1, 0xFA1E, 0x8301, 0x8362, + 0x837F, 0x83C7, 0x83F6, 0x8448, 0x84B4, 0x8553, 0x8559, 0x856B, + 0xFA1F, 0x85B0, 0xFA20, 0xFA21, 0x8807, 0x88F5, 0x8A12, 0x8A37, + 0x8A79, 0x8AA7, 0x8ABE, 0x8ADF, 0xFA22, 0x8AF6, 0x8B53, 0x8B7F, + 0x8CF0, 0x8CF4, 0x8D12, 0x8D76, 0xFA23, 0x8ECF, 0xFA24, 0xFA25, + 0x9067, 0x90DE, 0xFA26, 0x9115, 0x9127, 0x91DA + }, + { /* category 92 */ + 0x91D7, 0x91DE, 0x91ED, 0x91EE, 0x91E4, 0x91E5, 0x9206, 0x9210, + 0x920A, 0x923A, 0x9240, 0x923C, 0x924E, 0x9259, 0x9251, 0x9239, + 0x9267, 0x92A7, 0x9277, 0x9278, 0x92E7, 0x92D7, 0x92D9, 0x92D0, + 0xFA27, 0x92D5, 0x92E0, 0x92D3, 0x9325, 0x9321, 0x92FB, 0xFA28, + 0x931E, 0x92FF, 0x931D, 0x9302, 0x9370, 0x9357, 0x93A4, 0x93C6, + 0x93DE, 0x93F8, 0x9431, 0x9445, 0x9448, 0x9592, 0xF9DC, 0xFA29, + 0x969D, 0x96AF, 0x9733, 0x973B, 0x9743, 0x974D, 0x974F, 0x9751, + 0x9755, 0x9857, 0x9865, 0xFA2A, 0xFA2B, 0x9927, 0xFA2C, 0x999E, + 0x9A4E, 0x9AD9, 0x9ADC, 0x9B75, 0x9B72, 0x9B8F, 0x9BB1, 0x9BBB, + 0x9C00, 0x9D70, 0x9D6B, 0xFA2D, 0x9E19, 0x9ED1, 0x0000, 0x0000, + 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, + 0x2178, 0x2179, 0xFFE2, 0xFFE4, 0xFF07, 0xFF02 + } + }; + +#ifdef __cplusplus +} +#endif + +#endif /* JISX0208_H */ diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/wbmp.h b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/wbmp.h new file mode 100644 index 0000000000..9a93d6ebf0 --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/include/wbmp.h @@ -0,0 +1,51 @@ + /* WBMP + * ---- + * WBMP Level 0: B/W, Uncompressed + * This implements the WBMP format as specified in WAPSpec 1.1 and 1.2. + * It does not support ExtHeaders as defined in the spec. The spec states + * that a WAP client does not need to implement ExtHeaders. + * + * (c) 2000 Johan Van den Brande + * + * Header file + */ +#ifndef __WBMP_H +#define __WBMP_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + + /* WBMP struct + * ----------- + * A Wireless bitmap structure + */ + + typedef struct Wbmp_ { + int type; /* type of the wbmp */ + int width; /* width of the image */ + int height; /* height of the image */ + int *bitmap;/* pointer to data: 0 = WHITE , 1 = BLACK */ + } + Wbmp; + +#define WBMP_WHITE 1 +#define WBMP_BLACK 0 + + /* Proto's + * ------- + */ + void putmbi(int i, void (*putout)(int c, void *out), void *out); + int getmbi(int (*getin)(void *in), void *in); + int skipheader(int (*getin)(void *in), void *in); + Wbmp *createwbmp(int width, int height, int color); + int readwbmp(int (*getin)(void *in), void *in, Wbmp **wbmp); + int writewbmp(Wbmp *wbmp, void (*putout)(int c, void *out), void *out); + void freewbmp(Wbmp *wbmp); + void printwbmp(Wbmp *wbmp); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/lib/.gitkeep b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/lib/.gitkeep new file mode 100644 index 0000000000..48cdce8528 --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/lib/.gitkeep @@ -0,0 +1 @@ +placeholder diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/lib/libgd.a b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/lib/libgd.a new file mode 100644 index 0000000000..bd60d8203b Binary files /dev/null and b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/lib/libgd.a differ diff --git a/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/lib/pkgconfig/gdlib.pc b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/lib/pkgconfig/gdlib.pc new file mode 100644 index 0000000000..6c81e37cd6 --- /dev/null +++ b/packages/php-wasm/compile/libgd/asyncify/dist/root/lib/lib/pkgconfig/gdlib.pc @@ -0,0 +1,11 @@ +prefix=/root/lib +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: gdlib +Description: GD graphics library +Version: 2.3.3 +Requires.private: libpng libjpeg libwebp libavif zlib +Libs: -L${libdir} -lgd -lpng16 -lz -ljpeg -lwebp -lsharpyuv -lavif +Cflags: -I${includedir} diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/bin/gdlib-config b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/bin/gdlib-config new file mode 100755 index 0000000000..86978d7d0a --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/bin/gdlib-config @@ -0,0 +1,10 @@ +#!/bin/sh +case "$1" in + --version) echo 2.3.3 ;; + --features) echo "PNG JPEG WEBP AVIF GIF XBM WBMP FREETYPE" ;; + --libs) echo "-L/root/lib/lib -lgd -lpng16 -lz -ljpeg -lwebp -lsharpyuv -lavif" ;; + --cflags|--includes) echo "-I/root/lib/include" ;; + --libdir) echo "/root/lib/lib" ;; + --includedir) echo "/root/lib/include" ;; + *) echo "--version --features --libs --cflags --includedir --libdir" ;; +esac diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/.gitkeep b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/.gitkeep new file mode 100644 index 0000000000..48cdce8528 --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/.gitkeep @@ -0,0 +1 @@ +placeholder diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/bmp.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/bmp.h new file mode 100644 index 0000000000..5644fab982 --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/bmp.h @@ -0,0 +1,111 @@ +#ifndef BMP_H +#define BMP_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + + /* + gd_bmp.c + + Bitmap format support for libgd + + * Written 2007, Scott MacVicar + --------------------------------------------------------------------------- + + Todo: + + RLE4, RLE8 and Bitfield encoding + Add full support for Windows v4 and Windows v5 header formats + + ---------------------------------------------------------------------------- + */ + +#define BMP_PALETTE_3 1 +#define BMP_PALETTE_4 2 + +#define BMP_WINDOWS_V3 40 +#define BMP_OS2_V1 12 +#define BMP_OS2_V2 64 +#define BMP_WINDOWS_V4 108 +#define BMP_WINDOWS_V5 124 + +#define BMP_BI_RGB 0 +#define BMP_BI_RLE8 1 +#define BMP_BI_RLE4 2 +#define BMP_BI_BITFIELDS 3 +#define BMP_BI_JPEG 4 +#define BMP_BI_PNG 5 + +#define BMP_RLE_COMMAND 0 +#define BMP_RLE_ENDOFLINE 0 +#define BMP_RLE_ENDOFBITMAP 1 +#define BMP_RLE_DELTA 2 + +#define BMP_RLE_TYPE_RAW 0 +#define BMP_RLE_TYPE_RLE 1 + + /* BMP header. */ + typedef struct { + /* 16 bit - header identifying the type */ + signed short int magic; + + /* 32bit - size of the file */ + int size; + + /* 16bit - these two are in the spec but "reserved" */ + signed short int reserved1; + signed short int reserved2; + + /* 32 bit - offset of the bitmap header from data in bytes */ + signed int off; + + } bmp_hdr_t; + + /* BMP info. */ + typedef struct { + /* 16bit - Type, ie Windows or OS/2 for the palette info */ + signed short int type; + /* 32bit - The length of the bitmap information header in bytes. */ + signed int len; + + /* 32bit - The width of the bitmap in pixels. */ + signed int width; + + /* 32bit - The height of the bitmap in pixels. */ + signed int height; + + /* 8 bit - The bitmap data is specified in top-down order. */ + signed char topdown; + + /* 16 bit - The number of planes. This must be set to a value of one. */ + signed short int numplanes; + + /* 16 bit - The number of bits per pixel. */ + signed short int depth; + + /* 32bit - The type of compression used. */ + signed int enctype; + + /* 32bit - The size of the image in bytes. */ + signed int size; + + /* 32bit - The horizontal resolution in pixels/metre. */ + signed int hres; + + /* 32bit - The vertical resolution in pixels/metre. */ + signed int vres; + + /* 32bit - The number of color indices used by the bitmap. */ + signed int numcolors; + + /* 32bit - The number of color indices important for displaying the bitmap. */ + signed int mincolors; + + } bmp_info_t; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/config.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/config.h new file mode 100644 index 0000000000..cd143c72c0 --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/config.h @@ -0,0 +1,141 @@ +/* Generated from config.hin via autoheader for cmake; see bootstrap.sh. */ + +/* Define is you are building for Win32 API */ +/* #undef BGDWIN32 */ + +/* Whether to support gd image formats */ +#define ENABLE_GD_FORMATS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_DIRENT_H + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_DLFCN_H */ + +/* Define if you have the ft2build.h header. */ +/* #undef HAVE_FT2BUILD_H */ + +/* Define if you have the iconv() function and it works. */ +/* #undef HAVE_ICONV */ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ICONV_H */ + +/* Define if defines iconv_t. */ +/* #undef HAVE_ICONV_T_DEF */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H + +/* Define if you have avif */ +#define HAVE_LIBAVIF + +/* Define if you have fontconfig */ +/* #undef HAVE_LIBFONTCONFIG */ + +/* Define if you have freetype */ +/* #undef HAVE_LIBFREETYPE */ + +/* Define if you have heif */ +/* #undef HAVE_LIBHEIF */ + +/* Define if you have liq */ +/* #undef HAVE_LIBIMAGEQUANT */ + +/* Define if you have jpeg */ +#define HAVE_LIBJPEG + +/* Define to 1 if you have the `m' library (-lm). */ +#define HAVE_LIBM + +/* Define if you have png */ +#define HAVE_LIBPNG + +/* Define if you have raqm */ +/* #undef HAVE_LIBRAQM */ + +/* Define if you have tiff */ +/* #undef HAVE_LIBTIFF */ + +/* Define if you have webp */ +#define HAVE_LIBWEBP + +/* Define if you have xpm */ +/* #undef HAVE_LIBXPM */ + +/* Define if you have zlib */ +#define HAVE_LIBZ + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_MEMORY_H */ + +/* Define if OpenMP is enabled */ +/* #undef HAVE_OPENMP */ + +/* Define if you have POSIX threads libraries and header files. */ +/* #undef HAVE_PTHREAD */ + +/* Have PTHREAD_PRIO_INHERIT. */ +/* #undef HAVE_PTHREAD_PRIO_INHERIT */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STDLIB_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_STRING_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H + +/* Define to 1 or 0, depending whether the compiler supports simple visibility + declarations. */ +/* #undef HAVE_VISIBILITY */ + +/* Define as const if the declaration of iconv() needs const. */ +/* #undef ICONV_CONST */ + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +/* #undef LT_OBJDIR */ + +/* Name of package */ +#define PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +/* #undef PACKAGE_BUGREPORT */ + +/* Define to the full name of this package. */ +#define PACKAGE_NAME + +/* Define to the full name and version of this package. */ +/* #undef PACKAGE_STRING */ + +/* Define to the one symbol short name of this package. */ +/* #undef PACKAGE_TARNAME */ + +/* Define to the home page for this package. */ +/* #undef PACKAGE_URL */ + +/* Define to the version of this package. */ +#define PACKAGE_VERSION + +/* Define to necessary symbol if this constant uses a non-standard name on + your system. */ +/* #undef PTHREAD_CREATE_JOINABLE */ + +/* Define to 1 if you have the ANSI C header files. */ +/* #undef STDC_HEADERS */ + +/* Version number of package */ +/* #undef VERSION */ diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/entities.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/entities.h new file mode 100644 index 0000000000..cf24cb63e3 --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/entities.h @@ -0,0 +1,277 @@ +/* + * Generated file - do not edit directly. + * + * This file was generated from: + * http://www.w3.org/TR/REC-html40/sgml/entities.html + * by means of the script: + * entities.tcl + */ + +#ifdef __cplusplus +extern "C" { +#endif + + static struct entities_s { + char *name; + int value; + } entities[] = { + {"AElig", 198}, + {"Aacute", 193}, + {"Acirc", 194}, + {"Agrave", 192}, + {"Alpha", 913}, + {"Aring", 197}, + {"Atilde", 195}, + {"Auml", 196}, + {"Beta", 914}, + {"Ccedil", 199}, + {"Chi", 935}, + {"Dagger", 8225}, + {"Delta", 916}, + {"ETH", 208}, + {"Eacute", 201}, + {"Ecirc", 202}, + {"Egrave", 200}, + {"Epsilon", 917}, + {"Eta", 919}, + {"Euml", 203}, + {"Gamma", 915}, + {"Iacute", 205}, + {"Icirc", 206}, + {"Igrave", 204}, + {"Iota", 921}, + {"Iuml", 207}, + {"Kappa", 922}, + {"Lambda", 923}, + {"Mu", 924}, + {"Ntilde", 209}, + {"Nu", 925}, + {"OElig", 338}, + {"Oacute", 211}, + {"Ocirc", 212}, + {"Ograve", 210}, + {"Omega", 937}, + {"Omicron", 927}, + {"Oslash", 216}, + {"Otilde", 213}, + {"Ouml", 214}, + {"Phi", 934}, + {"Pi", 928}, + {"Prime", 8243}, + {"Psi", 936}, + {"Rho", 929}, + {"Scaron", 352}, + {"Sigma", 931}, + {"THORN", 222}, + {"Tau", 932}, + {"Theta", 920}, + {"Uacute", 218}, + {"Ucirc", 219}, + {"Ugrave", 217}, + {"Upsilon", 933}, + {"Uuml", 220}, + {"Xi", 926}, + {"Yacute", 221}, + {"Yuml", 376}, + {"Zeta", 918}, + {"aacute", 225}, + {"acirc", 226}, + {"acute", 180}, + {"aelig", 230}, + {"agrave", 224}, + {"alefsym", 8501}, + {"alpha", 945}, + {"amp", 38}, + {"and", 8743}, + {"ang", 8736}, + {"aring", 229}, + {"asymp", 8776}, + {"atilde", 227}, + {"auml", 228}, + {"bdquo", 8222}, + {"beta", 946}, + {"brvbar", 166}, + {"bull", 8226}, + {"cap", 8745}, + {"ccedil", 231}, + {"cedil", 184}, + {"cent", 162}, + {"chi", 967}, + {"circ", 710}, + {"clubs", 9827}, + {"cong", 8773}, + {"copy", 169}, + {"crarr", 8629}, + {"cup", 8746}, + {"curren", 164}, + {"dArr", 8659}, + {"dagger", 8224}, + {"darr", 8595}, + {"deg", 176}, + {"delta", 948}, + {"diams", 9830}, + {"divide", 247}, + {"eacute", 233}, + {"ecirc", 234}, + {"egrave", 232}, + {"empty", 8709}, + {"emsp", 8195}, + {"ensp", 8194}, + {"epsilon", 949}, + {"equiv", 8801}, + {"eta", 951}, + {"eth", 240}, + {"euml", 235}, + {"euro", 8364}, + {"exist", 8707}, + {"fnof", 402}, + {"forall", 8704}, + {"frac12", 189}, + {"frac14", 188}, + {"frac34", 190}, + {"frasl", 8260}, + {"gamma", 947}, + {"ge", 8805}, + {"gt", 62}, + {"hArr", 8660}, + {"harr", 8596}, + {"hearts", 9829}, + {"hellip", 8230}, + {"iacute", 237}, + {"icirc", 238}, + {"iexcl", 161}, + {"igrave", 236}, + {"image", 8465}, + {"infin", 8734}, + {"int", 8747}, + {"iota", 953}, + {"iquest", 191}, + {"isin", 8712}, + {"iuml", 239}, + {"kappa", 954}, + {"lArr", 8656}, + {"lambda", 955}, + {"lang", 9001}, + {"laquo", 171}, + {"larr", 8592}, + {"lceil", 8968}, + {"ldquo", 8220}, + {"le", 8804}, + {"lfloor", 8970}, + {"lowast", 8727}, + {"loz", 9674}, + {"lrm", 8206}, + {"lsaquo", 8249}, + {"lsquo", 8216}, + {"lt", 60}, + {"macr", 175}, + {"mdash", 8212}, + {"micro", 181}, + {"middot", 183}, + {"minus", 8722}, + {"mu", 956}, + {"nabla", 8711}, + {"nbsp", 160}, + {"ndash", 8211}, + {"ne", 8800}, + {"ni", 8715}, + {"not", 172}, + {"notin", 8713}, + {"nsub", 8836}, + {"ntilde", 241}, + {"nu", 957}, + {"oacute", 243}, + {"ocirc", 244}, + {"oelig", 339}, + {"ograve", 242}, + {"oline", 8254}, + {"omega", 969}, + {"omicron", 959}, + {"oplus", 8853}, + {"or", 8744}, + {"ordf", 170}, + {"ordm", 186}, + {"oslash", 248}, + {"otilde", 245}, + {"otimes", 8855}, + {"ouml", 246}, + {"para", 182}, + {"part", 8706}, + {"permil", 8240}, + {"perp", 8869}, + {"phi", 966}, + {"pi", 960}, + {"piv", 982}, + {"plusmn", 177}, + {"pound", 163}, + {"prime", 8242}, + {"prod", 8719}, + {"prop", 8733}, + {"psi", 968}, + {"quot", 34}, + {"rArr", 8658}, + {"radic", 8730}, + {"rang", 9002}, + {"raquo", 187}, + {"rarr", 8594}, + {"rceil", 8969}, + {"rdquo", 8221}, + {"real", 8476}, + {"reg", 174}, + {"rfloor", 8971}, + {"rho", 961}, + {"rlm", 8207}, + {"rsaquo", 8250}, + {"rsquo", 8217}, + {"sbquo", 8218}, + {"scaron", 353}, + {"sdot", 8901}, + {"sect", 167}, + {"shy", 173}, + {"sigma", 963}, + {"sigmaf", 962}, + {"sim", 8764}, + {"spades", 9824}, + {"sub", 8834}, + {"sube", 8838}, + {"sum", 8721}, + {"sup", 8835}, + {"sup1", 185}, + {"sup2", 178}, + {"sup3", 179}, + {"supe", 8839}, + {"szlig", 223}, + {"tau", 964}, + {"there4", 8756}, + {"theta", 952}, + {"thetasym", 977}, + {"thinsp", 8201}, + {"thorn", 254}, + {"tilde", 732}, + {"times", 215}, + {"trade", 8482}, + {"uArr", 8657}, + {"uacute", 250}, + {"uarr", 8593}, + {"ucirc", 251}, + {"ugrave", 249}, + {"uml", 168}, + {"upsih", 978}, + {"upsilon", 965}, + {"uuml", 252}, + {"weierp", 8472}, + {"xi", 958}, + {"yacute", 253}, + {"yen", 165}, + {"yuml", 255}, + {"zeta", 950}, + {"zwj", 8205}, + {"zwnj", 8204}, + }; + +#define ENTITY_NAME_LENGTH_MAX 8 +#define NR_OF_ENTITIES 252 + +#ifdef __cplusplus +} +#endif diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd.h new file mode 100644 index 0000000000..3056039529 --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd.h @@ -0,0 +1,1716 @@ +#ifndef GD_H +#define GD_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Version information. This gets parsed by build scripts as well as + * gcc so each #define line in this group must also be splittable on + * whitespace, take the form GD_*_VERSION and contain the magical + * trailing comment. */ +#define GD_MAJOR_VERSION 2 /*version605b5d1778*/ +#define GD_MINOR_VERSION 3 /*version605b5d1778*/ +#define GD_RELEASE_VERSION 3 /*version605b5d1778*/ +#define GD_EXTRA_VERSION "" /*version605b5d1778*/ +/* End parsable section. */ + +/* The version string. This is constructed from the version number + * parts above via macro abuse^Wtrickery. */ +#define GDXXX_VERSION_STR(mjr, mnr, rev, ext) mjr "." mnr "." rev ext +#define GDXXX_STR(s) GDXXX_SSTR(s) /* Two levels needed to expand args. */ +#define GDXXX_SSTR(s) #s + +#define GD_VERSION_STRING \ + GDXXX_VERSION_STR(GDXXX_STR(GD_MAJOR_VERSION), \ + GDXXX_STR(GD_MINOR_VERSION), \ + GDXXX_STR(GD_RELEASE_VERSION), \ + GD_EXTRA_VERSION) + + +/* Do the DLL dance: dllexport when building the DLL, + dllimport when importing from it, nothing when + not on Silly Silly Windows (tm Aardman Productions). */ + +/* 2.0.20: for headers */ + +/* 2.0.24: __stdcall also needed for Visual BASIC + and other languages. This breaks ABI compatibility + with previous DLL revs, but it's necessary. */ + +/* 2.0.29: WIN32 programmers can declare the NONDLL macro if they + wish to build gd as a static library or by directly including + the gd sources in a project. */ + +/* http://gcc.gnu.org/wiki/Visibility */ +#if defined(_WIN32) || defined(CYGWIN) || defined(_WIN32_WCE) +# ifdef BGDWIN32 +# ifdef NONDLL +# define BGD_EXPORT_DATA_PROT +# else +# ifdef __GNUC__ +# define BGD_EXPORT_DATA_PROT __attribute__ ((__dllexport__)) +# else +# define BGD_EXPORT_DATA_PROT __declspec(dllexport) +# endif +# endif +# else +# ifdef __GNUC__ +# define BGD_EXPORT_DATA_PROT __attribute__ ((__dllimport__)) +# else +# define BGD_EXPORT_DATA_PROT __declspec(dllimport) +# endif +# endif +# define BGD_STDCALL __stdcall +# define BGD_EXPORT_DATA_IMPL +# define BGD_MALLOC +#else +# if defined(__GNUC__) || defined(__clang__) +# define BGD_EXPORT_DATA_PROT __attribute__ ((__visibility__ ("default"))) +# define BGD_EXPORT_DATA_IMPL __attribute__ ((__visibility__ ("hidden"))) +# else +# define BGD_EXPORT_DATA_PROT +# define BGD_EXPORT_DATA_IMPL +# endif +# define BGD_STDCALL +# define BGD_MALLOC __attribute__ ((__malloc__)) +#endif + +#define BGD_DECLARE(rt) BGD_EXPORT_DATA_PROT rt BGD_STDCALL + +/* VS2012+ disable keyword macroizing unless _ALLOW_KEYWORD_MACROS is set + We define inline, and strcasecmp if they're missing +*/ +#ifdef _MSC_VER +# define _ALLOW_KEYWORD_MACROS +# ifndef inline +# define inline __inline +# endif +# ifndef strcasecmp +# define strcasecmp _stricmp +# endif +#endif + +#undef ARG_NOT_USED +#define ARG_NOT_USED(arg) (void) arg + +/* gd.h: declarations file for the graphic-draw module. + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "AS IS." Thomas Boutell and + * Boutell.Com, Inc. disclaim all warranties, either express or implied, + * including but not limited to implied warranties of merchantability and + * fitness for a particular purpose, with respect to this code and accompanying + * documentation. */ + +/* stdio is needed for file I/O. */ +#include +#include +#include "gd_io.h" + +/* The maximum number of palette entries in palette-based images. + In the wonderful new world of gd 2.0, you can of course have + many more colors when using truecolor mode. */ + +#define gdMaxColors 256 + +/* Image type. See functions below; you will not need to change + the elements directly. Use the provided macros to + access sx, sy, the color table, and colorsTotal for + read-only purposes. */ + +/* If 'truecolor' is set true, the image is truecolor; + pixels are represented by integers, which + must be 32 bits wide or more. + + True colors are repsented as follows: + + ARGB + + Where 'A' (alpha channel) occupies only the + LOWER 7 BITS of the MSB. This very small + loss of alpha channel resolution allows gd 2.x + to keep backwards compatibility by allowing + signed integers to be used to represent colors, + and negative numbers to represent special cases, + just as in gd 1.x. */ + +#define gdAlphaMax 127 +#define gdAlphaOpaque 0 +#define gdAlphaTransparent 127 +#define gdRedMax 255 +#define gdGreenMax 255 +#define gdBlueMax 255 + +/** + * Group: Color Decomposition + */ + +/** + * Macro: gdTrueColorGetAlpha + * + * Gets the alpha channel value + * + * Parameters: + * c - The color + * + * See also: + * - + */ +#define gdTrueColorGetAlpha(c) (((c) & 0x7F000000) >> 24) + +/** + * Macro: gdTrueColorGetRed + * + * Gets the red channel value + * + * Parameters: + * c - The color + * + * See also: + * - + */ +#define gdTrueColorGetRed(c) (((c) & 0xFF0000) >> 16) + +/** + * Macro: gdTrueColorGetGreen + * + * Gets the green channel value + * + * Parameters: + * c - The color + * + * See also: + * - + */ +#define gdTrueColorGetGreen(c) (((c) & 0x00FF00) >> 8) + +/** + * Macro: gdTrueColorGetBlue + * + * Gets the blue channel value + * + * Parameters: + * c - The color + * + * See also: + * - + */ +#define gdTrueColorGetBlue(c) ((c) & 0x0000FF) + +/** + * Group: Effects + * + * The layering effect + * + * When pixels are drawn the new colors are "mixed" with the background + * depending on the effect. + * + * Note that the effect does not apply to palette images, where pixels + * are always replaced. + * + * Modes: + * gdEffectReplace - replace pixels + * gdEffectAlphaBlend - blend pixels, see + * gdEffectNormal - default mode; same as gdEffectAlphaBlend + * gdEffectOverlay - overlay pixels, see + * gdEffectMultiply - overlay pixels with multiply effect, see + * + * + * See also: + * - + */ +#define gdEffectReplace 0 +#define gdEffectAlphaBlend 1 +#define gdEffectNormal 2 +#define gdEffectOverlay 3 +#define gdEffectMultiply 4 + +#define GD_TRUE 1 +#define GD_FALSE 0 + +#define GD_EPSILON 1e-6 +#ifndef M_PI +# define M_PI 3.14159265358979323846 +#endif + +/* This function accepts truecolor pixel values only. The + source color is composited with the destination color + based on the alpha channel value of the source color. + The resulting color is opaque. */ + +BGD_DECLARE(int) gdAlphaBlend (int dest, int src); +BGD_DECLARE(int) gdLayerOverlay (int dest, int src); +BGD_DECLARE(int) gdLayerMultiply (int dest, int src); + + +/** + * Group: Color Quantization + * + * Enum: gdPaletteQuantizationMethod + * + * Constants: + * GD_QUANT_DEFAULT - GD_QUANT_LIQ if libimagequant is available, + * GD_QUANT_JQUANT otherwise. + * GD_QUANT_JQUANT - libjpeg's old median cut. Fast, but only uses 16-bit + * color. + * GD_QUANT_NEUQUANT - NeuQuant - approximation using Kohonen neural network. + * GD_QUANT_LIQ - A combination of algorithms used in libimagequant + * aiming for the highest quality at cost of speed. + * + * Note that GD_QUANT_JQUANT does not retain the alpha channel, and + * GD_QUANT_NEUQUANT does not support dithering. + * + * See also: + * - + */ +enum gdPaletteQuantizationMethod { + GD_QUANT_DEFAULT = 0, + GD_QUANT_JQUANT = 1, + GD_QUANT_NEUQUANT = 2, + GD_QUANT_LIQ = 3 +}; + +/** + * Group: Transform + * + * Constants: gdInterpolationMethod + * + * GD_BELL - Bell + * GD_BESSEL - Bessel + * GD_BILINEAR_FIXED - fixed point bilinear + * GD_BICUBIC - Bicubic + * GD_BICUBIC_FIXED - fixed point bicubic integer + * GD_BLACKMAN - Blackman + * GD_BOX - Box + * GD_BSPLINE - BSpline + * GD_CATMULLROM - Catmullrom + * GD_GAUSSIAN - Gaussian + * GD_GENERALIZED_CUBIC - Generalized cubic + * GD_HERMITE - Hermite + * GD_HAMMING - Hamming + * GD_HANNING - Hannig + * GD_MITCHELL - Mitchell + * GD_NEAREST_NEIGHBOUR - Nearest neighbour interpolation + * GD_POWER - Power + * GD_QUADRATIC - Quadratic + * GD_SINC - Sinc + * GD_TRIANGLE - Triangle + * GD_WEIGHTED4 - 4 pixels weighted bilinear interpolation + * GD_LINEAR - bilinear interpolation + * + * See also: + * - + * - + */ +typedef enum { + GD_DEFAULT = 0, + GD_BELL, + GD_BESSEL, + GD_BILINEAR_FIXED, + GD_BICUBIC, + GD_BICUBIC_FIXED, + GD_BLACKMAN, + GD_BOX, + GD_BSPLINE, + GD_CATMULLROM, + GD_GAUSSIAN, + GD_GENERALIZED_CUBIC, + GD_HERMITE, + GD_HAMMING, + GD_HANNING, + GD_MITCHELL, + GD_NEAREST_NEIGHBOUR, + GD_POWER, + GD_QUADRATIC, + GD_SINC, + GD_TRIANGLE, + GD_WEIGHTED4, + GD_LINEAR, + GD_LANCZOS3, + GD_LANCZOS8, + GD_BLACKMAN_BESSEL, + GD_BLACKMAN_SINC, + GD_QUADRATIC_BSPLINE, + GD_CUBIC_SPLINE, + GD_COSINE, + GD_WELSH, + GD_METHOD_COUNT = 30 +} gdInterpolationMethod; + +/** + * Group: HEIF Coding Format + * + * Values that select the HEIF coding format. + * + * Constants: gdHeifCodec + * + * GD_HEIF_CODEC_UNKNOWN + * GD_HEIF_CODEC_HEVC + * GD_HEIF_CODEC_AV1 + * + * See also: + * - + */ +typedef enum { + GD_HEIF_CODEC_UNKNOWN = 0, + GD_HEIF_CODEC_HEVC, + GD_HEIF_CODEC_AV1 = 4, +} gdHeifCodec; + +/** + * Group: HEIF Chroma Subsampling + * + * Values that select the HEIF chroma subsampling. + * + * Constants: gdHeifCompression + * + * GD_HEIF_CHROMA_420 + * GD_HEIF_CHROMA_422 + * GD_HEIF_CHROMA_444 + * + * See also: + * - + */ +typedef const char *gdHeifChroma; + +#define GD_HEIF_CHROMA_420 "420" +#define GD_HEIF_CHROMA_422 "422" +#define GD_HEIF_CHROMA_444 "444" + +/* define struct with name and func ptr and add it to gdImageStruct gdInterpolationMethod interpolation; */ + +/* Interpolation function ptr */ +typedef double (* interpolation_method )(double, double); + + +/* + Group: Types + + typedef: gdImage + + typedef: gdImagePtr + + The data structure in which gd stores images. , + and the various image file-loading functions + return a pointer to this type, and the other functions expect to + receive a pointer to this type as their first argument. + + *gdImagePtr* is a pointer to *gdImage*. + + See also: + + + (Previous versions of this library encouraged directly manipulating + the contents ofthe struct but we are attempting to move away from + this practice so the fields are no longer documented here. If you + need to poke at the internals of this struct, feel free to look at + *gd.h*.) +*/ +typedef struct gdImageStruct { + /* Palette-based image pixels */ + unsigned char **pixels; + int sx; + int sy; + /* These are valid in palette images only. See also + 'alpha', which appears later in the structure to + preserve binary backwards compatibility */ + int colorsTotal; + int red[gdMaxColors]; + int green[gdMaxColors]; + int blue[gdMaxColors]; + int open[gdMaxColors]; + /* For backwards compatibility, this is set to the + first palette entry with 100% transparency, + and is also set and reset by the + gdImageColorTransparent function. Newer + applications can allocate palette entries + with any desired level of transparency; however, + bear in mind that many viewers, notably + many web browsers, fail to implement + full alpha channel for PNG and provide + support for full opacity or transparency only. */ + int transparent; + int *polyInts; + int polyAllocated; + struct gdImageStruct *brush; + struct gdImageStruct *tile; + int brushColorMap[gdMaxColors]; + int tileColorMap[gdMaxColors]; + int styleLength; + int stylePos; + int *style; + int interlace; + /* New in 2.0: thickness of line. Initialized to 1. */ + int thick; + /* New in 2.0: alpha channel for palettes. Note that only + Macintosh Internet Explorer and (possibly) Netscape 6 + really support multiple levels of transparency in + palettes, to my knowledge, as of 2/15/01. Most + common browsers will display 100% opaque and + 100% transparent correctly, and do something + unpredictable and/or undesirable for levels + in between. TBB */ + int alpha[gdMaxColors]; + /* Truecolor flag and pixels. New 2.0 fields appear here at the + end to minimize breakage of existing object code. */ + int trueColor; + int **tpixels; + /* Should alpha channel be copied, or applied, each time a + pixel is drawn? This applies to truecolor images only. + No attempt is made to alpha-blend in palette images, + even if semitransparent palette entries exist. + To do that, build your image as a truecolor image, + then quantize down to 8 bits. */ + int alphaBlendingFlag; + /* Should the alpha channel of the image be saved? This affects + PNG at the moment; other future formats may also + have that capability. JPEG doesn't. */ + int saveAlphaFlag; + + /* There should NEVER BE ACCESSOR MACROS FOR ITEMS BELOW HERE, so this + part of the structure can be safely changed in new releases. */ + + /* 2.0.12: anti-aliased globals. 2.0.26: just a few vestiges after + switching to the fast, memory-cheap implementation from PHP-gd. */ + int AA; + int AA_color; + int AA_dont_blend; + + /* 2.0.12: simple clipping rectangle. These values + must be checked for safety when set; please use + gdImageSetClip */ + int cx1; + int cy1; + int cx2; + int cy2; + + /* 2.1.0: allows to specify resolution in dpi */ + unsigned int res_x; + unsigned int res_y; + + /* Selects quantization method, see gdImageTrueColorToPaletteSetMethod() and gdPaletteQuantizationMethod enum. */ + int paletteQuantizationMethod; + /* speed/quality trade-off. 1 = best quality, 10 = best speed. 0 = method-specific default. + Applicable to GD_QUANT_LIQ and GD_QUANT_NEUQUANT. */ + int paletteQuantizationSpeed; + /* Image will remain true-color if conversion to palette cannot achieve given quality. + Value from 1 to 100, 1 = ugly, 100 = perfect. Applicable to GD_QUANT_LIQ.*/ + int paletteQuantizationMinQuality; + /* Image will use minimum number of palette colors needed to achieve given quality. Must be higher than paletteQuantizationMinQuality + Value from 1 to 100, 1 = ugly, 100 = perfect. Applicable to GD_QUANT_LIQ.*/ + int paletteQuantizationMaxQuality; + gdInterpolationMethod interpolation_id; + interpolation_method interpolation; +} +gdImage; + +typedef gdImage *gdImagePtr; + + +/* Point type for use in polygon drawing. */ + +/** + * Group: Types + * + * typedef: gdPointF + * Defines a point in a 2D coordinate system using floating point + * values. + * x - Floating point position (increase from left to right) + * y - Floating point Row position (increase from top to bottom) + * + * typedef: gdPointFPtr + * Pointer to a + * + * See also: + * , , + **/ +typedef struct +{ + double x, y; +} +gdPointF, *gdPointFPtr; + + +/* + Group: Types + + typedef: gdFont + + typedef: gdFontPtr + + A font structure, containing the bitmaps of all characters in a + font. Used to declare the characteristics of a font. Text-output + functions expect these as their second argument, following the + argument. and both + return one. + + You can provide your own font data by providing such a structure and + the associated pixel array. You can determine the width and height + of a single character in a font by examining the w and h members of + the structure. If you will not be creating your own fonts, you will + not need to concern yourself with the rest of the components of this + structure. + + Please see the files gdfontl.c and gdfontl.h for an example of + the proper declaration of this structure. + + > typedef struct { + > // # of characters in font + > int nchars; + > // First character is numbered... (usually 32 = space) + > int offset; + > // Character width and height + > int w; + > int h; + > // Font data; array of characters, one row after another. + > // Easily included in code, also easily loaded from + > // data files. + > char *data; + > } gdFont; + + gdFontPtr is a pointer to gdFont. + +*/ +typedef struct { + /* # of characters in font */ + int nchars; + /* First character is numbered... (usually 32 = space) */ + int offset; + /* Character width and height */ + int w; + int h; + /* Font data; array of characters, one row after another. + Easily included in code, also easily loaded from + data files. */ + char *data; +} +gdFont; + +/* Text functions take these. */ +typedef gdFont *gdFontPtr; + +typedef void(*gdErrorMethod)(int, const char *, va_list); + +BGD_DECLARE(void) gdSetErrorMethod(gdErrorMethod); +BGD_DECLARE(void) gdClearErrorMethod(void); + +/* For backwards compatibility only. Use gdImageSetStyle() + for MUCH more flexible line drawing. Also see + gdImageSetBrush(). */ +#define gdDashSize 4 + +/** + * Group: Colors + * + * Colors are always of type int which is supposed to be at least 32 bit large. + * + * Kinds of colors: + * true colors - ARGB values where the alpha channel is stored as most + * significant, and the blue channel as least significant + * byte. Note that the alpha channel only uses the 7 least + * significant bits. + * Don't rely on the internal representation, though, and + * use to compose a truecolor value, and + * , , + * and to access + * the respective channels. + * palette indexes - The index of a color palette entry (0-255). + * special colors - As listed in the following section. + * + * Constants: Special Colors + * gdStyled - use the current style, see + * gdBrushed - use the current brush, see + * gdStyledBrushed - use the current style and brush + * gdTiled - use the current tile, see + * gdTransparent - indicate transparency, what is not the same as the + * transparent color index; used for lines only + * gdAntiAliased - draw anti aliased + */ + +#define gdStyled (-2) +#define gdBrushed (-3) +#define gdStyledBrushed (-4) +#define gdTiled (-5) +#define gdTransparent (-6) +#define gdAntiAliased (-7) + +/* Functions to manipulate images. */ + +/* Creates a palette-based image (up to 256 colors). */ +BGD_DECLARE(gdImagePtr) gdImageCreate (int sx, int sy); + +/* An alternate name for the above (2.0). */ +#define gdImageCreatePalette gdImageCreate + +/* Creates a truecolor image (millions of colors). */ +BGD_DECLARE(gdImagePtr) gdImageCreateTrueColor (int sx, int sy); + +/* Creates an image from various file types. These functions + return a palette or truecolor image based on the + nature of the file being loaded. Truecolor PNG + stays truecolor; palette PNG stays palette-based; + JPEG is always truecolor. */ +BGD_DECLARE(gdImagePtr) gdImageCreateFromPng (FILE * fd); +BGD_DECLARE(gdImagePtr) gdImageCreateFromPngCtx(gdIOCtxPtr in); +BGD_DECLARE(gdImagePtr) gdImageCreateFromPngPtr (int size, void *data); + +/* These read the first frame only */ +BGD_DECLARE(gdImagePtr) gdImageCreateFromGif (FILE * fd); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGifCtx(gdIOCtxPtr in); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGifPtr (int size, void *data); +BGD_DECLARE(gdImagePtr) gdImageCreateFromWBMP (FILE * inFile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromWBMPCtx(gdIOCtxPtr infile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromWBMPPtr (int size, void *data); +BGD_DECLARE(gdImagePtr) gdImageCreateFromJpeg (FILE * infile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegEx (FILE * infile, int ignore_warning); +BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegCtx(gdIOCtxPtr infile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegCtxEx(gdIOCtxPtr infile, int ignore_warning); +BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegPtr (int size, void *data); +BGD_DECLARE(gdImagePtr) gdImageCreateFromJpegPtrEx (int size, void *data, int ignore_warning); +BGD_DECLARE(gdImagePtr) gdImageCreateFromWebp (FILE * inFile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromWebpPtr (int size, void *data); +BGD_DECLARE(gdImagePtr) gdImageCreateFromWebpCtx(gdIOCtxPtr infile); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromHeif(FILE *inFile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromHeifPtr(int size, void *data); +BGD_DECLARE(gdImagePtr) gdImageCreateFromHeifCtx(gdIOCtxPtr infile); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromAvif(FILE *inFile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromAvifPtr(int size, void *data); +BGD_DECLARE(gdImagePtr) gdImageCreateFromAvifCtx(gdIOCtxPtr infile); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromTiff(FILE *inFile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromTiffCtx(gdIOCtxPtr infile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromTiffPtr(int size, void *data); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromTga( FILE * fp ); +BGD_DECLARE(gdImagePtr) gdImageCreateFromTgaCtx(gdIOCtxPtr ctx); +BGD_DECLARE(gdImagePtr) gdImageCreateFromTgaPtr(int size, void *data); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromBmp (FILE * inFile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpPtr (int size, void *data); +BGD_DECLARE(gdImagePtr) gdImageCreateFromBmpCtx(gdIOCtxPtr infile); +BGD_DECLARE(gdImagePtr) gdImageCreateFromFile(const char *filename); + + +/* + Group: Types + + typedef: gdSource + + typedef: gdSourcePtr + + *Note:* This interface is *obsolete* and kept only for + *compatibility. Use instead. + + Represents a source from which a PNG can be read. Programmers who + do not wish to read PNGs from a file can provide their own + alternate input mechanism, using the + function. See the documentation of that function for an example of + the proper use of this type. + + > typedef struct { + > int (*source) (void *context, char *buffer, int len); + > void *context; + > } gdSource, *gdSourcePtr; + + The source function must return -1 on error, otherwise the number + of bytes fetched. 0 is EOF, not an error! + + 'context' will be passed to your source function. + +*/ +typedef struct { + int (*source) (void *context, char *buffer, int len); + void *context; +} +gdSource, *gdSourcePtr; + +/* Deprecated in favor of gdImageCreateFromPngCtx */ +BGD_DECLARE(gdImagePtr) gdImageCreateFromPngSource (gdSourcePtr in); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd (FILE * in); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGdCtx(gdIOCtxPtr in); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGdPtr (int size, void *data); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2 (FILE * in); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Ctx(gdIOCtxPtr in); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Ptr (int size, void *data); + +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Part (FILE * in, int srcx, int srcy, int w, + int h); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2PartCtx(gdIOCtxPtr in, int srcx, int srcy, + int w, int h); +BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2PartPtr (int size, void *data, int srcx, int srcy, + int w, int h); +/* 2.0.10: prototype was missing */ +BGD_DECLARE(gdImagePtr) gdImageCreateFromXbm (FILE * in); +BGD_DECLARE(void) gdImageXbmCtx(gdImagePtr image, char* file_name, int fg, gdIOCtxPtr out); + +/* NOTE: filename, not FILE */ +BGD_DECLARE(gdImagePtr) gdImageCreateFromXpm (char *filename); + +BGD_DECLARE(void) gdImageDestroy (gdImagePtr im); + +/* Replaces or blends with the background depending on the + most recent call to gdImageAlphaBlending and the + alpha channel value of 'color'; default is to overwrite. + Tiling and line styling are also implemented + here. All other gd drawing functions pass through this call, + allowing for many useful effects. + Overlay and multiply effects are used when gdImageAlphaBlending + is passed gdEffectOverlay and gdEffectMultiply */ + +BGD_DECLARE(void) gdImageSetPixel (gdImagePtr im, int x, int y, int color); +/* FreeType 2 text output with hook to extra flags */ + +BGD_DECLARE(int) gdImageGetPixel (gdImagePtr im, int x, int y); +BGD_DECLARE(int) gdImageGetTrueColorPixel (gdImagePtr im, int x, int y); + +BGD_DECLARE(void) gdImageAABlend (gdImagePtr im); + +BGD_DECLARE(void) gdImageLine (gdImagePtr im, int x1, int y1, int x2, int y2, int color); + +/* For backwards compatibility only. Use gdImageSetStyle() + for much more flexible line drawing. */ +BGD_DECLARE(void) gdImageDashedLine (gdImagePtr im, int x1, int y1, int x2, int y2, + int color); +/* Corners specified (not width and height). Upper left first, lower right + second. */ +BGD_DECLARE(void) gdImageRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, + int color); +/* Solid bar. Upper left corner first, lower right corner second. */ +BGD_DECLARE(void) gdImageFilledRectangle (gdImagePtr im, int x1, int y1, int x2, int y2, + int color); +BGD_DECLARE(void) gdImageSetClip(gdImagePtr im, int x1, int y1, int x2, int y2); +BGD_DECLARE(void) gdImageGetClip(gdImagePtr im, int *x1P, int *y1P, int *x2P, int *y2P); +BGD_DECLARE(void) gdImageSetResolution(gdImagePtr im, const unsigned int res_x, const unsigned int res_y); +BGD_DECLARE(int) gdImageBoundsSafe (gdImagePtr im, int x, int y); +BGD_DECLARE(void) gdImageChar (gdImagePtr im, gdFontPtr f, int x, int y, int c, + int color); +BGD_DECLARE(void) gdImageCharUp (gdImagePtr im, gdFontPtr f, int x, int y, int c, + int color); +BGD_DECLARE(void) gdImageString (gdImagePtr im, gdFontPtr f, int x, int y, + unsigned char *s, int color); +BGD_DECLARE(void) gdImageStringUp (gdImagePtr im, gdFontPtr f, int x, int y, + unsigned char *s, int color); +BGD_DECLARE(void) gdImageString16 (gdImagePtr im, gdFontPtr f, int x, int y, + unsigned short *s, int color); +BGD_DECLARE(void) gdImageStringUp16 (gdImagePtr im, gdFontPtr f, int x, int y, + unsigned short *s, int color); + +/* 2.0.16: for thread-safe use of gdImageStringFT and friends, + call this before allowing any thread to call gdImageStringFT. + Otherwise it is invoked by the first thread to invoke + gdImageStringFT, with a very small but real risk of a race condition. + Return 0 on success, nonzero on failure to initialize freetype. */ +BGD_DECLARE(int) gdFontCacheSetup (void); + +/* Optional: clean up after application is done using fonts in + gdImageStringFT(). */ +BGD_DECLARE(void) gdFontCacheShutdown (void); +/* 2.0.20: for backwards compatibility. A few applications did start calling + this function when it first appeared although it was never documented. + Simply invokes gdFontCacheShutdown. */ +BGD_DECLARE(void) gdFreeFontCache (void); + +/* Calls gdImageStringFT. Provided for backwards compatibility only. */ +BGD_DECLARE(char *) gdImageStringTTF (gdImagePtr im, int *brect, int fg, const char *fontlist, + double ptsize, double angle, int x, int y, + const char *string); + +/* FreeType 2 text output */ +BGD_DECLARE(char *) gdImageStringFT (gdImagePtr im, int *brect, int fg, const char *fontlist, + double ptsize, double angle, int x, int y, + const char *string); + + +/* + Group: Types + + typedef: gdFTStringExtra + + typedef: gdFTStringExtraPtr + + A structure and associated pointer type used to pass additional + parameters to the function. See + for the structure definition. + + Thanks to Wez Furlong. +*/ + +/* 2.0.5: provides an extensible way to pass additional parameters. + Thanks to Wez Furlong, sorry for the delay. */ +typedef struct { + int flags; /* Logical OR of gdFTEX_ values */ + double linespacing; /* fine tune line spacing for '\n' */ + int charmap; /* TBB: 2.0.12: may be gdFTEX_Unicode, + gdFTEX_Shift_JIS, gdFTEX_Big5, + or gdFTEX_Adobe_Custom; + when not specified, maps are searched + for in the above order. */ + int hdpi; /* if (flags & gdFTEX_RESOLUTION) */ + int vdpi; /* if (flags & gdFTEX_RESOLUTION) */ + char *xshow; /* if (flags & gdFTEX_XSHOW) + then, on return, xshow is a malloc'ed + string containing xshow position data for + the last string. + + NB. The caller is responsible for gdFree'ing + the xshow string. + */ + char *fontpath; /* if (flags & gdFTEX_RETURNFONTPATHNAME) + then, on return, fontpath is a malloc'ed + string containing the actual font file path name + used, which can be interesting when fontconfig + is in use. + + The caller is responsible for gdFree'ing the + fontpath string. + */ + +} +gdFTStringExtra, *gdFTStringExtraPtr; + +#define gdFTEX_LINESPACE 1 +#define gdFTEX_CHARMAP 2 +#define gdFTEX_RESOLUTION 4 +#define gdFTEX_DISABLE_KERNING 8 +#define gdFTEX_XSHOW 16 +/* The default unless gdFTUseFontConfig(1); has been called: + fontlist is a full or partial font file pathname or list thereof + (i.e. just like before 2.0.29) */ +#define gdFTEX_FONTPATHNAME 32 +/* Necessary to use fontconfig patterns instead of font pathnames + as the fontlist argument, unless gdFTUseFontConfig(1); has + been called. New in 2.0.29 */ +#define gdFTEX_FONTCONFIG 64 +/* Sometimes interesting when fontconfig is used: the fontpath + element of the structure above will contain a gdMalloc'd string + copy of the actual font file pathname used, if this flag is set + when the call is made */ +#define gdFTEX_RETURNFONTPATHNAME 128 + +/* If flag is nonzero, the fontlist parameter to gdImageStringFT + and gdImageStringFTEx shall be assumed to be a fontconfig font pattern + if fontconfig was compiled into gd. This function returns zero + if fontconfig is not available, nonzero otherwise. */ +BGD_DECLARE(int) gdFTUseFontConfig(int flag); + +/* These are NOT flags; set one in 'charmap' if you set the + gdFTEX_CHARMAP bit in 'flags'. */ +#define gdFTEX_Unicode 0 +#define gdFTEX_Shift_JIS 1 +#define gdFTEX_Big5 2 +#define gdFTEX_Adobe_Custom 3 + +BGD_DECLARE(char *) gdImageStringFTEx (gdImagePtr im, int *brect, int fg, const char *fontlist, + double ptsize, double angle, int x, int y, + const char *string, gdFTStringExtraPtr strex); + + +/* + Group: Types + + typedef: gdPoint + + typedef: gdPointPtr + + Represents a point in the coordinate space of the image; used by + , and + for polygon drawing. + + > typedef struct { + > int x, y; + > } gdPoint, *gdPointPtr; + +*/ +typedef struct { + int x, y; +} +gdPoint, *gdPointPtr; + +/** + * Typedef: gdRect + * + * A rectangle in the coordinate space of the image + * + * Members: + * x - The x-coordinate of the upper left corner. + * y - The y-coordinate of the upper left corner. + * width - The width. + * height - The height. + * + * Typedef: gdRectPtr + * + * A pointer to a + */ +typedef struct { + int x, y; + int width, height; +} +gdRect, *gdRectPtr; + + +BGD_DECLARE(void) gdImagePolygon (gdImagePtr im, gdPointPtr p, int n, int c); +BGD_DECLARE(void) gdImageOpenPolygon (gdImagePtr im, gdPointPtr p, int n, int c); +BGD_DECLARE(void) gdImageFilledPolygon (gdImagePtr im, gdPointPtr p, int n, int c); + +/* These functions still work with truecolor images, + for which they never return error. */ +BGD_DECLARE(int) gdImageColorAllocate (gdImagePtr im, int r, int g, int b); +/* gd 2.0: palette entries with non-opaque transparency are permitted. */ +BGD_DECLARE(int) gdImageColorAllocateAlpha (gdImagePtr im, int r, int g, int b, int a); +/* Assumes opaque is the preferred alpha channel value */ +BGD_DECLARE(int) gdImageColorClosest (gdImagePtr im, int r, int g, int b); +/* Closest match taking all four parameters into account. + A slightly different color with the same transparency + beats the exact same color with radically different + transparency */ +BGD_DECLARE(int) gdImageColorClosestAlpha (gdImagePtr im, int r, int g, int b, int a); +/* An alternate method */ +BGD_DECLARE(int) gdImageColorClosestHWB (gdImagePtr im, int r, int g, int b); +/* Returns exact, 100% opaque matches only */ +BGD_DECLARE(int) gdImageColorExact (gdImagePtr im, int r, int g, int b); +/* Returns an exact match only, including alpha */ +BGD_DECLARE(int) gdImageColorExactAlpha (gdImagePtr im, int r, int g, int b, int a); +/* Opaque only */ +BGD_DECLARE(int) gdImageColorResolve (gdImagePtr im, int r, int g, int b); +/* Based on gdImageColorExactAlpha and gdImageColorClosestAlpha */ +BGD_DECLARE(int) gdImageColorResolveAlpha (gdImagePtr im, int r, int g, int b, int a); + +/* A simpler way to obtain an opaque truecolor value for drawing on a + truecolor image. Not for use with palette images! */ + +#define gdTrueColor(r, g, b) (((r) << 16) + \ + ((g) << 8) + \ + (b)) + +/** + * Group: Color Composition + * + * Macro: gdTrueColorAlpha + * + * Compose a truecolor value from its components + * + * Parameters: + * r - The red channel (0-255) + * g - The green channel (0-255) + * b - The blue channel (0-255) + * a - The alpha channel (0-127, where 127 is fully transparent, and 0 is + * completely opaque). + * + * See also: + * - + * - + * - + * - + * - + */ +#define gdTrueColorAlpha(r, g, b, a) (((a) << 24) + \ + ((r) << 16) + \ + ((g) << 8) + \ + (b)) + +BGD_DECLARE(void) gdImageColorDeallocate (gdImagePtr im, int color); + +/* Converts a truecolor image to a palette-based image, + using a high-quality two-pass quantization routine + which attempts to preserve alpha channel information + as well as R/G/B color information when creating + a palette. If ditherFlag is set, the image will be + dithered to approximate colors better, at the expense + of some obvious "speckling." colorsWanted can be + anything up to 256. If the original source image + includes photographic information or anything that + came out of a JPEG, 256 is strongly recommended. + + Better yet, don't use these function -- write real + truecolor PNGs and JPEGs. The disk space gain of + conversion to palette is not great (for small images + it can be negative) and the quality loss is ugly. + + DIFFERENCES: gdImageCreatePaletteFromTrueColor creates and + returns a new image. gdImageTrueColorToPalette modifies + an existing image, and the truecolor pixels are discarded. + + gdImageTrueColorToPalette() returns TRUE on success, FALSE on failure. +*/ + +BGD_DECLARE(gdImagePtr) gdImageCreatePaletteFromTrueColor (gdImagePtr im, int ditherFlag, + int colorsWanted); + +BGD_DECLARE(int) gdImageTrueColorToPalette (gdImagePtr im, int ditherFlag, + int colorsWanted); + +BGD_DECLARE(int) gdImagePaletteToTrueColor(gdImagePtr src); + +/* An attempt at getting the results of gdImageTrueColorToPalette to + * look a bit more like the original (im1 is the original and im2 is + * the palette version */ + +BGD_DECLARE(int) gdImageColorMatch(gdImagePtr im1, gdImagePtr im2); + +/* Selects quantization method used for subsequent gdImageTrueColorToPalette calls. + See gdPaletteQuantizationMethod enum (e.g. GD_QUANT_NEUQUANT, GD_QUANT_LIQ). + Speed is from 1 (highest quality) to 10 (fastest). + Speed 0 selects method-specific default (recommended). + + Returns FALSE if the given method is invalid or not available. +*/ +BGD_DECLARE(int) gdImageTrueColorToPaletteSetMethod (gdImagePtr im, int method, int speed); + +/* + Chooses quality range that subsequent call to gdImageTrueColorToPalette will aim for. + Min and max quality is in range 1-100 (1 = ugly, 100 = perfect). Max must be higher than min. + If palette cannot represent image with at least min_quality, then image will remain true-color. + If palette can represent image with quality better than max_quality, then lower number of colors will be used. + This function has effect only when GD_QUANT_LIQ method has been selected and the source image is true-color. +*/ +BGD_DECLARE(void) gdImageTrueColorToPaletteSetQuality (gdImagePtr im, int min_quality, int max_quality); + +/* Specifies a color index (if a palette image) or an + RGB color (if a truecolor image) which should be + considered 100% transparent. FOR TRUECOLOR IMAGES, + THIS IS IGNORED IF AN ALPHA CHANNEL IS BEING + SAVED. Use gdImageSaveAlpha(im, 0); to + turn off the saving of a full alpha channel in + a truecolor image. Note that gdImageColorTransparent + is usually compatible with older browsers that + do not understand full alpha channels well. TBB */ +BGD_DECLARE(void) gdImageColorTransparent (gdImagePtr im, int color); + +BGD_DECLARE(void) gdImagePaletteCopy (gdImagePtr dst, gdImagePtr src); + +typedef int (*gdCallbackImageColor)(gdImagePtr im, int src); + +BGD_DECLARE(int) gdImageColorReplace(gdImagePtr im, int src, int dst); +BGD_DECLARE(int) gdImageColorReplaceThreshold(gdImagePtr im, int src, int dst, float threshold); +BGD_DECLARE(int) gdImageColorReplaceArray(gdImagePtr im, int len, int *src, int *dst); +BGD_DECLARE(int) gdImageColorReplaceCallback(gdImagePtr im, gdCallbackImageColor callback); + +BGD_DECLARE(void) gdImageGif (gdImagePtr im, FILE * out); +BGD_DECLARE(void) gdImagePng (gdImagePtr im, FILE * out); +BGD_DECLARE(void) gdImagePngCtx(gdImagePtr im, gdIOCtxPtr out); +BGD_DECLARE(void) gdImageGifCtx(gdImagePtr im, gdIOCtxPtr out); +BGD_DECLARE(void) gdImageTiff(gdImagePtr im, FILE *outFile); +BGD_DECLARE(void *) gdImageTiffPtr(gdImagePtr im, int *size); +BGD_DECLARE(void) gdImageTiffCtx(gdImagePtr image, gdIOCtxPtr out); + +BGD_DECLARE(void *) gdImageBmpPtr(gdImagePtr im, int *size, int compression); +BGD_DECLARE(void) gdImageBmp(gdImagePtr im, FILE *outFile, int compression); +BGD_DECLARE(void) gdImageBmpCtx(gdImagePtr im, gdIOCtxPtr out, int compression); + +/* 2.0.12: Compression level: 0-9 or -1, where 0 is NO COMPRESSION at all, + 1 is FASTEST but produces larger files, 9 provides the best + compression (smallest files) but takes a long time to compress, and + -1 selects the default compiled into the zlib library. */ +BGD_DECLARE(void) gdImagePngEx (gdImagePtr im, FILE * out, int level); +BGD_DECLARE(void) gdImagePngCtxEx(gdImagePtr im, gdIOCtxPtr out, int level); + +BGD_DECLARE(void) gdImageWBMP (gdImagePtr image, int fg, FILE * out); +BGD_DECLARE(void) gdImageWBMPCtx(gdImagePtr image, int fg, gdIOCtxPtr out); + +BGD_DECLARE(int) gdImageFile(gdImagePtr im, const char *filename); +BGD_DECLARE(int) gdSupportsFileType(const char *filename, int writing); + + +/* Guaranteed to correctly free memory returned by the gdImage*Ptr + functions */ +BGD_DECLARE(void) gdFree (void *m); + +/* Best to free this memory with gdFree(), not free() */ +BGD_DECLARE(void *) gdImageWBMPPtr (gdImagePtr im, int *size, int fg); + +/* 100 is highest quality (there is always a little loss with JPEG). + 0 is lowest. 10 is about the lowest useful setting. */ +BGD_DECLARE(void) gdImageJpeg (gdImagePtr im, FILE * out, int quality); +BGD_DECLARE(void) gdImageJpegCtx(gdImagePtr im, gdIOCtxPtr out, int quality); + +/* Best to free this memory with gdFree(), not free() */ +BGD_DECLARE(void *) gdImageJpegPtr (gdImagePtr im, int *size, int quality); + +/** + * Group: WebP + * + * Constant: gdWebpLossless + * + * Lossless quality threshold. When image quality is greater than or equal to + * , the image will be written in the lossless WebP format. + * + * See also: + * - + */ +#define gdWebpLossless 101 + +BGD_DECLARE(void) gdImageWebpEx (gdImagePtr im, FILE * outFile, int quantization); +BGD_DECLARE(void) gdImageWebp (gdImagePtr im, FILE * outFile); +BGD_DECLARE(void *) gdImageWebpPtr (gdImagePtr im, int *size); +BGD_DECLARE(void *) gdImageWebpPtrEx (gdImagePtr im, int *size, int quantization); +BGD_DECLARE(void) gdImageWebpCtx(gdImagePtr im, gdIOCtxPtr outfile, int quantization); + +BGD_DECLARE(void) gdImageHeifEx(gdImagePtr im, FILE *outFile, int quality, gdHeifCodec codec, gdHeifChroma chroma); +BGD_DECLARE(void) gdImageHeif(gdImagePtr im, FILE *outFile); +BGD_DECLARE(void *) gdImageHeifPtr(gdImagePtr im, int *size); +BGD_DECLARE(void *) gdImageHeifPtrEx(gdImagePtr im, int *size, int quality, gdHeifCodec codec, gdHeifChroma chroma); +BGD_DECLARE(void) gdImageHeifCtx(gdImagePtr im, gdIOCtxPtr outfile, int quality, gdHeifCodec codec, gdHeifChroma chroma); + +BGD_DECLARE(void) gdImageAvif(gdImagePtr im, FILE *outFile); +BGD_DECLARE(void) gdImageAvifEx(gdImagePtr im, FILE *outFile, int quality, int speed); +BGD_DECLARE(void *) gdImageAvifPtr(gdImagePtr im, int *size); +BGD_DECLARE(void *) gdImageAvifPtrEx(gdImagePtr im, int *size, int quality, int speed); +BGD_DECLARE(void) gdImageAvifCtx(gdImagePtr im, gdIOCtxPtr outfile, int quality, int speed); + +/** + * Group: GifAnim + * + * Legal values for Disposal. gdDisposalNone is always used by + * the built-in optimizer if previm is passed. + * + * Constants: gdImageGifAnim + * + * gdDisposalUnknown - Not recommended + * gdDisposalNone - Preserve previous frame + * gdDisposalRestoreBackground - First allocated color of palette + * gdDisposalRestorePrevious - Restore to before start of frame + * + * See also: + * - + */ +enum { + gdDisposalUnknown, + gdDisposalNone, + gdDisposalRestoreBackground, + gdDisposalRestorePrevious +}; + +BGD_DECLARE(void) gdImageGifAnimBegin(gdImagePtr im, FILE *outFile, int GlobalCM, int Loops); +BGD_DECLARE(void) gdImageGifAnimAdd(gdImagePtr im, FILE *outFile, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm); +BGD_DECLARE(void) gdImageGifAnimEnd(FILE *outFile); +BGD_DECLARE(void) gdImageGifAnimBeginCtx(gdImagePtr im, gdIOCtxPtr out, int GlobalCM, int Loops); +BGD_DECLARE(void) gdImageGifAnimAddCtx(gdImagePtr im, gdIOCtxPtr out, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm); +BGD_DECLARE(void) gdImageGifAnimEndCtx(gdIOCtxPtr out); +BGD_DECLARE(void *) gdImageGifAnimBeginPtr(gdImagePtr im, int *size, int GlobalCM, int Loops); +BGD_DECLARE(void *) gdImageGifAnimAddPtr(gdImagePtr im, int *size, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm); +BGD_DECLARE(void *) gdImageGifAnimEndPtr(int *size); + + + +/* + Group: Types + + typedef: gdSink + + typedef: gdSinkPtr + + *Note:* This interface is *obsolete* and kept only for + *compatibility*. Use instead. + + Represents a "sink" (destination) to which a PNG can be + written. Programmers who do not wish to write PNGs to a file can + provide their own alternate output mechanism, using the + function. See the documentation of that + function for an example of the proper use of this type. + + > typedef struct { + > int (*sink) (void *context, char *buffer, int len); + > void *context; + > } gdSink, *gdSinkPtr; + + The _sink_ function must return -1 on error, otherwise the number of + bytes written, which must be equal to len. + + _context_ will be passed to your sink function. + +*/ + +typedef struct { + int (*sink) (void *context, const char *buffer, int len); + void *context; +} +gdSink, *gdSinkPtr; + +BGD_DECLARE(void) gdImagePngToSink (gdImagePtr im, gdSinkPtr out); + +BGD_DECLARE(void) gdImageGd (gdImagePtr im, FILE * out); +BGD_DECLARE(void) gdImageGd2 (gdImagePtr im, FILE * out, int cs, int fmt); + +/* Best to free this memory with gdFree(), not free() */ +BGD_DECLARE(void *) gdImageGifPtr (gdImagePtr im, int *size); + +/* Best to free this memory with gdFree(), not free() */ +BGD_DECLARE(void *) gdImagePngPtr (gdImagePtr im, int *size); +BGD_DECLARE(void *) gdImagePngPtrEx (gdImagePtr im, int *size, int level); + +/* Best to free this memory with gdFree(), not free() */ +BGD_DECLARE(void *) gdImageGdPtr (gdImagePtr im, int *size); + +/* Best to free this memory with gdFree(), not free() */ +BGD_DECLARE(void *) gdImageGd2Ptr (gdImagePtr im, int cs, int fmt, int *size); + +/* Style is a bitwise OR ( | operator ) of these. + gdArc and gdChord are mutually exclusive; + gdChord just connects the starting and ending + angles with a straight line, while gdArc produces + a rounded edge. gdPie is a synonym for gdArc. + gdNoFill indicates that the arc or chord should be + outlined, not filled. gdEdged, used together with + gdNoFill, indicates that the beginning and ending + angles should be connected to the center; this is + a good way to outline (rather than fill) a + 'pie slice'. */ +#define gdArc 0 +#define gdPie gdArc +#define gdChord 1 +#define gdNoFill 2 +#define gdEdged 4 + +BGD_DECLARE(void) gdImageFilledArc (gdImagePtr im, int cx, int cy, int w, int h, int s, + int e, int color, int style); +BGD_DECLARE(void) gdImageArc (gdImagePtr im, int cx, int cy, int w, int h, int s, int e, + int color); +BGD_DECLARE(void) gdImageEllipse(gdImagePtr im, int cx, int cy, int w, int h, int color); +BGD_DECLARE(void) gdImageFilledEllipse (gdImagePtr im, int cx, int cy, int w, int h, + int color); +BGD_DECLARE(void) gdImageFillToBorder (gdImagePtr im, int x, int y, int border, + int color); +BGD_DECLARE(void) gdImageFill (gdImagePtr im, int x, int y, int color); +BGD_DECLARE(void) gdImageCopy (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, + int srcX, int srcY, int w, int h); +BGD_DECLARE(void) gdImageCopyMerge (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, + int srcX, int srcY, int w, int h, int pct); +BGD_DECLARE(void) gdImageCopyMergeGray (gdImagePtr dst, gdImagePtr src, int dstX, + int dstY, int srcX, int srcY, int w, int h, + int pct); + +/* Stretches or shrinks to fit, as needed. Does NOT attempt + to average the entire set of source pixels that scale down onto the + destination pixel. */ +BGD_DECLARE(void) gdImageCopyResized (gdImagePtr dst, gdImagePtr src, int dstX, int dstY, + int srcX, int srcY, int dstW, int dstH, int srcW, + int srcH); + +/* gd 2.0: stretches or shrinks to fit, as needed. When called with a + truecolor destination image, this function averages the + entire set of source pixels that scale down onto the + destination pixel, taking into account what portion of the + destination pixel each source pixel represents. This is a + floating point operation, but this is not a performance issue + on modern hardware, except for some embedded devices. If the + destination is a palette image, gdImageCopyResized is + substituted automatically. */ +BGD_DECLARE(void) gdImageCopyResampled (gdImagePtr dst, gdImagePtr src, int dstX, + int dstY, int srcX, int srcY, int dstW, int dstH, + int srcW, int srcH); + +/* gd 2.0.8: gdImageCopyRotated is added. Source + is a rectangle, with its upper left corner at + srcX and srcY. Destination is the *center* of + the rotated copy. Angle is in degrees, same as + gdImageArc. Floating point destination center + coordinates allow accurate rotation of + objects of odd-numbered width or height. */ +BGD_DECLARE(void) gdImageCopyRotated (gdImagePtr dst, + gdImagePtr src, + double dstX, double dstY, + int srcX, int srcY, + int srcWidth, int srcHeight, int angle); + +BGD_DECLARE(gdImagePtr) gdImageClone (gdImagePtr src); + +BGD_DECLARE(void) gdImageSetBrush (gdImagePtr im, gdImagePtr brush); +BGD_DECLARE(void) gdImageSetTile (gdImagePtr im, gdImagePtr tile); +BGD_DECLARE(void) gdImageSetAntiAliased (gdImagePtr im, int c); +BGD_DECLARE(void) gdImageSetAntiAliasedDontBlend (gdImagePtr im, int c, int dont_blend); +BGD_DECLARE(void) gdImageSetStyle (gdImagePtr im, int *style, int noOfPixels); +/* Line thickness (defaults to 1). Affects lines, ellipses, + rectangles, polygons and so forth. */ +BGD_DECLARE(void) gdImageSetThickness (gdImagePtr im, int thickness); +/* On or off (1 or 0) for all three of these. */ +BGD_DECLARE(void) gdImageInterlace (gdImagePtr im, int interlaceArg); +BGD_DECLARE(void) gdImageAlphaBlending (gdImagePtr im, int alphaBlendingArg); +BGD_DECLARE(void) gdImageSaveAlpha (gdImagePtr im, int saveAlphaArg); + +BGD_DECLARE(gdImagePtr) gdImageNeuQuant(gdImagePtr im, const int max_color, int sample_factor); + +enum gdPixelateMode { + GD_PIXELATE_UPPERLEFT, + GD_PIXELATE_AVERAGE +}; + +BGD_DECLARE(int) gdImagePixelate(gdImagePtr im, int block_size, const unsigned int mode); + +typedef struct { + int sub; + int plus; + unsigned int num_colors; + int *colors; + unsigned int seed; +} gdScatter, *gdScatterPtr; + +BGD_DECLARE(int) gdImageScatter(gdImagePtr im, int sub, int plus); +BGD_DECLARE(int) gdImageScatterColor(gdImagePtr im, int sub, int plus, int colors[], unsigned int num_colors); +BGD_DECLARE(int) gdImageScatterEx(gdImagePtr im, gdScatterPtr s); +BGD_DECLARE(int) gdImageSmooth(gdImagePtr im, float weight); +BGD_DECLARE(int) gdImageMeanRemoval(gdImagePtr im); +BGD_DECLARE(int) gdImageEmboss(gdImagePtr im); +BGD_DECLARE(int) gdImageGaussianBlur(gdImagePtr im); +BGD_DECLARE(int) gdImageEdgeDetectQuick(gdImagePtr src); +BGD_DECLARE(int) gdImageSelectiveBlur( gdImagePtr src); +BGD_DECLARE(int) gdImageConvolution(gdImagePtr src, float filter[3][3], float filter_div, float offset); +BGD_DECLARE(int) gdImageColor(gdImagePtr src, const int red, const int green, const int blue, const int alpha); +BGD_DECLARE(int) gdImageContrast(gdImagePtr src, double contrast); +BGD_DECLARE(int) gdImageBrightness(gdImagePtr src, int brightness); +BGD_DECLARE(int) gdImageGrayScale(gdImagePtr src); +BGD_DECLARE(int) gdImageNegate(gdImagePtr src); + +BGD_DECLARE(gdImagePtr) gdImageCopyGaussianBlurred(gdImagePtr src, int radius, + double sigma); + + +/** + * Group: Accessor Macros + */ + +/** + * Macro: gdImageTrueColor + * + * Whether an image is a truecolor image. + * + * Parameters: + * im - The image. + * + * Returns: + * Non-zero if the image is a truecolor image, zero for palette images. + */ +#define gdImageTrueColor(im) ((im)->trueColor) + +/** + * Macro: gdImageSX + * + * Gets the width (in pixels) of an image. + * + * Parameters: + * im - The image. + */ +#define gdImageSX(im) ((im)->sx) + +/** + * Macro: gdImageSY + * + * Gets the height (in pixels) of an image. + * + * Parameters: + * im - The image. + */ +#define gdImageSY(im) ((im)->sy) + +/** + * Macro: gdImageColorsTotal + * + * Gets the number of colors in the palette. + * + * This macro is only valid for palette images. + * + * Parameters: + * im - The image + */ +#define gdImageColorsTotal(im) ((im)->colorsTotal) + +/** + * Macro: gdImageRed + * + * Gets the red component value of a given color. + * + * Parameters: + * im - The image. + * c - The color. + */ +#define gdImageRed(im, c) ((im)->trueColor ? gdTrueColorGetRed(c) : \ + (im)->red[(c)]) + +/** + * Macro: gdImageGreen + * + * Gets the green component value of a given color. + * + * Parameters: + * im - The image. + * c - The color. + */ +#define gdImageGreen(im, c) ((im)->trueColor ? gdTrueColorGetGreen(c) : \ + (im)->green[(c)]) + +/** + * Macro: gdImageBlue + * + * Gets the blue component value of a given color. + * + * Parameters: + * im - The image. + * c - The color. + */ +#define gdImageBlue(im, c) ((im)->trueColor ? gdTrueColorGetBlue(c) : \ + (im)->blue[(c)]) + +/** + * Macro: gdImageAlpha + * + * Gets the alpha component value of a given color. + * + * Parameters: + * im - The image. + * c - The color. + */ +#define gdImageAlpha(im, c) ((im)->trueColor ? gdTrueColorGetAlpha(c) : \ + (im)->alpha[(c)]) + +/** + * Macro: gdImageGetTransparent + * + * Gets the transparent color of the image. + * + * Parameters: + * im - The image. + * + * See also: + * - + */ +#define gdImageGetTransparent(im) ((im)->transparent) + +/** + * Macro: gdImageGetInterlaced + * + * Whether an image is interlaced. + * + * Parameters: + * im - The image. + * + * Returns: + * Non-zero for interlaced images, zero otherwise. + * + * See also: + * - + */ +#define gdImageGetInterlaced(im) ((im)->interlace) + +/** + * Macro: gdImagePalettePixel + * + * Gets the color of a pixel. + * + * Calling this macro is only valid for palette images. + * No bounds checking is done for the coordinates. + * + * Parameters: + * im - The image. + * x - The x-coordinate. + * y - The y-coordinate. + * + * See also: + * - + * - + */ +#define gdImagePalettePixel(im, x, y) (im)->pixels[(y)][(x)] + +/** + * Macro: gdImageTrueColorPixel + * + * Gets the color of a pixel. + * + * Calling this macro is only valid for truecolor images. + * No bounds checking is done for the coordinates. + * + * Parameters: + * im - The image. + * x - The x-coordinate. + * y - The y-coordinate. + * + * See also: + * - + * - + */ +#define gdImageTrueColorPixel(im, x, y) (im)->tpixels[(y)][(x)] + +/** + * Macro: gdImageResolutionX + * + * Gets the horizontal resolution in DPI. + * + * Parameters: + * im - The image. + * + * See also: + * - + * - + */ +#define gdImageResolutionX(im) (im)->res_x + +/** + * Macro: gdImageResolutionY + * + * Gets the vertical resolution in DPI. + * + * Parameters: + * im - The image. + * + * See also: + * - + * - + */ +#define gdImageResolutionY(im) (im)->res_y + +/* I/O Support routines. */ + +BGD_DECLARE(gdIOCtxPtr) gdNewFileCtx(FILE *); +/* If data is null, size is ignored and an initial data buffer is + allocated automatically. NOTE: this function assumes gd has the right + to free or reallocate "data" at will! Also note that gd will free + "data" when the IO context is freed. If data is not null, it must point + to memory allocated with gdMalloc, or by a call to gdImage[something]Ptr. + If not, see gdNewDynamicCtxEx for an alternative. */ +BGD_DECLARE(gdIOCtxPtr) gdNewDynamicCtx(int size, void *data); +/* 2.0.21: if freeFlag is nonzero, gd will free and/or reallocate "data" as + needed as described above. If freeFlag is zero, gd will never free + or reallocate "data", which means that the context should only be used + for *reading* an image from a memory buffer, or writing an image to a + memory buffer which is already large enough. If the memory buffer is + not large enough and an image write is attempted, the write operation + will fail. Those wishing to write an image to a buffer in memory have + a much simpler alternative in the gdImage[something]Ptr functions. */ +BGD_DECLARE(gdIOCtxPtr) gdNewDynamicCtxEx(int size, void *data, int freeFlag); +BGD_DECLARE(gdIOCtxPtr) gdNewSSCtx(gdSourcePtr in, gdSinkPtr out); +BGD_DECLARE(void *) gdDPExtractData(gdIOCtxPtr ctx, int *size); + +#define GD2_CHUNKSIZE 128 +#define GD2_CHUNKSIZE_MIN 64 +#define GD2_CHUNKSIZE_MAX 4096 + +#define GD2_VERS 2 +#define GD2_ID "gd2" + +#define GD2_FMT_RAW 1 +#define GD2_FMT_COMPRESSED 2 + +/* Image comparison definitions */ +BGD_DECLARE(int) gdImageCompare (gdImagePtr im1, gdImagePtr im2); + +BGD_DECLARE(void) gdImageFlipHorizontal(gdImagePtr im); +BGD_DECLARE(void) gdImageFlipVertical(gdImagePtr im); +BGD_DECLARE(void) gdImageFlipBoth(gdImagePtr im); + +/** + * Group: Crop + * + * Constants: gdCropMode + * GD_CROP_DEFAULT - Same as GD_CROP_TRANSPARENT + * GD_CROP_TRANSPARENT - Crop using the transparent color + * GD_CROP_BLACK - Crop black borders + * GD_CROP_WHITE - Crop white borders + * GD_CROP_SIDES - Crop using colors of the 4 corners + * + * See also: + * - + **/ +enum gdCropMode { + GD_CROP_DEFAULT = 0, + GD_CROP_TRANSPARENT, + GD_CROP_BLACK, + GD_CROP_WHITE, + GD_CROP_SIDES, + GD_CROP_THRESHOLD +}; + +BGD_DECLARE(gdImagePtr) gdImageCrop(gdImagePtr src, const gdRect *crop); +BGD_DECLARE(gdImagePtr) gdImageCropAuto(gdImagePtr im, const unsigned int mode); +BGD_DECLARE(gdImagePtr) gdImageCropThreshold(gdImagePtr im, const unsigned int color, const float threshold); + +BGD_DECLARE(int) gdImageSetInterpolationMethod(gdImagePtr im, gdInterpolationMethod id); +BGD_DECLARE(gdInterpolationMethod) gdImageGetInterpolationMethod(gdImagePtr im); + +BGD_DECLARE(gdImagePtr) gdImageScale(const gdImagePtr src, const unsigned int new_width, const unsigned int new_height); + +BGD_DECLARE(gdImagePtr) gdImageRotateInterpolated(const gdImagePtr src, const float angle, int bgcolor); + +typedef enum { + GD_AFFINE_TRANSLATE = 0, + GD_AFFINE_SCALE, + GD_AFFINE_ROTATE, + GD_AFFINE_SHEAR_HORIZONTAL, + GD_AFFINE_SHEAR_VERTICAL +} gdAffineStandardMatrix; + +BGD_DECLARE(int) gdAffineApplyToPointF (gdPointFPtr dst, const gdPointFPtr src, const double affine[6]); +BGD_DECLARE(int) gdAffineInvert (double dst[6], const double src[6]); +BGD_DECLARE(int) gdAffineFlip (double dst_affine[6], const double src_affine[6], const int flip_h, const int flip_v); +BGD_DECLARE(int) gdAffineConcat (double dst[6], const double m1[6], const double m2[6]); + +BGD_DECLARE(int) gdAffineIdentity (double dst[6]); +BGD_DECLARE(int) gdAffineScale (double dst[6], const double scale_x, const double scale_y); +BGD_DECLARE(int) gdAffineRotate (double dst[6], const double angle); +BGD_DECLARE(int) gdAffineShearHorizontal (double dst[6], const double angle); +BGD_DECLARE(int) gdAffineShearVertical(double dst[6], const double angle); +BGD_DECLARE(int) gdAffineTranslate (double dst[6], const double offset_x, const double offset_y); +BGD_DECLARE(double) gdAffineExpansion (const double src[6]); +BGD_DECLARE(int) gdAffineRectilinear (const double src[6]); +BGD_DECLARE(int) gdAffineEqual (const double matrix1[6], const double matrix2[6]); +BGD_DECLARE(int) gdTransformAffineGetImage(gdImagePtr *dst, const gdImagePtr src, gdRectPtr src_area, const double affine[6]); +BGD_DECLARE(int) gdTransformAffineCopy(gdImagePtr dst, int dst_x, int dst_y, const gdImagePtr src, gdRectPtr src_region, const double affine[6]); +/* +gdTransformAffineCopy(gdImagePtr dst, int x0, int y0, int x1, int y1, + const gdImagePtr src, int src_width, int src_height, + const double affine[6]); +*/ +BGD_DECLARE(int) gdTransformAffineBoundingBox(gdRectPtr src, const double affine[6], gdRectPtr bbox); + +/** + * Group: Image Comparison + * + * Constants: + * GD_CMP_IMAGE - Actual image IS different + * GD_CMP_NUM_COLORS - Number of colors in pallette differ + * GD_CMP_COLOR - Image colors differ + * GD_CMP_SIZE_X - Image width differs + * GD_CMP_SIZE_Y - Image heights differ + * GD_CMP_TRANSPARENT - Transparent color differs + * GD_CMP_BACKGROUND - Background color differs + * GD_CMP_INTERLACE - Interlaced setting differs + * GD_CMP_TRUECOLOR - Truecolor vs palette differs + * + * See also: + * - + */ +#define GD_CMP_IMAGE 1 +#define GD_CMP_NUM_COLORS 2 +#define GD_CMP_COLOR 4 +#define GD_CMP_SIZE_X 8 +#define GD_CMP_SIZE_Y 16 +#define GD_CMP_TRANSPARENT 32 +#define GD_CMP_BACKGROUND 64 +#define GD_CMP_INTERLACE 128 +#define GD_CMP_TRUECOLOR 256 + +/* resolution affects ttf font rendering, particularly hinting */ +#define GD_RESOLUTION 96 /* pixels per inch */ + + +/* Version information functions */ +BGD_DECLARE(int) gdMajorVersion(void); +BGD_DECLARE(int) gdMinorVersion(void); +BGD_DECLARE(int) gdReleaseVersion(void); +BGD_DECLARE(const char *) gdExtraVersion(void); +BGD_DECLARE(const char *) gdVersionString(void); + +/* newfangled special effects */ +#include "gdfx.h" + +#ifdef __cplusplus +} +#endif + +#endif /* GD_H */ diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_color.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_color.h new file mode 100644 index 0000000000..08b06cee09 --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_color.h @@ -0,0 +1,14 @@ +#ifndef GD_COLOR_H +#define GD_COLOR_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + + int gdColorMatch(gdImagePtr im, int col1, int col2, float threshold); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_color_map.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_color_map.h new file mode 100644 index 0000000000..6d2275e564 --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_color_map.h @@ -0,0 +1,30 @@ +#ifndef GD_COLOR_MAP_H +#define GD_COLOR_MAP_H 1 + +#include "gd.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + char *color_name; + int red; + int green; + int blue; +} gdColorMapEntry; + +typedef struct { + int num_entries; + gdColorMapEntry *entries; +} gdColorMap; + +extern BGD_EXPORT_DATA_PROT gdColorMap GD_COLOR_MAP_X11; + +BGD_DECLARE(int) gdColorMapLookup(const gdColorMap color_map, const char *color_name, int *r, int *g, int *b); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_errors.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_errors.h new file mode 100644 index 0000000000..4ecee94b38 --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_errors.h @@ -0,0 +1,46 @@ +#ifndef GD_ERRORS_H +#define GD_ERRORS_H + +#ifndef _WIN32 +# include +#else +/* + * priorities/facilities are encoded into a single 32-bit quantity, where the + * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility + * (0-big number). Both the priorities and the facilities map roughly + * one-to-one to strings in the syslogd(8) source code. This mapping is + * included in this file. + * + * priorities (these are ordered) + */ +# define LOG_EMERG 0 /* system is unusable */ +# define LOG_ALERT 1 /* action must be taken immediately */ +# define LOG_CRIT 2 /* critical conditions */ +# define LOG_ERR 3 /* error conditions */ +# define LOG_WARNING 4 /* warning conditions */ +# define LOG_NOTICE 5 /* normal but significant condition */ +# define LOG_INFO 6 /* informational */ +# define LOG_DEBUG 7 /* debug-level messages */ +#endif + +/* +LOG_EMERG system is unusable +LOG_ALERT action must be taken immediately +LOG_CRIT critical conditions +LOG_ERR error conditions +LOG_WARNING warning conditions +LOG_NOTICE normal, but significant, condition +LOG_INFO informational message +LOG_DEBUG debug-level message +*/ + +#define GD_ERROR LOG_ERR +#define GD_WARNING LOG_WARNING +#define GD_NOTICE LOG_NOTICE +#define GD_INFO LOG_INFO +#define GD_DEBUG LOG_DEBUG + +void gd_error(const char *format, ...); +void gd_error_ex(int priority, const char *format, ...); + +#endif diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_intern.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_intern.h new file mode 100644 index 0000000000..380f4db2c2 --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_intern.h @@ -0,0 +1,92 @@ +/* Internal header for random common utility functions. */ + +#ifndef GD_INTERN_H +#define GD_INTERN_H + +#include + +#ifndef MAXPATHLEN +# ifdef PATH_MAX +# define MAXPATHLEN PATH_MAX +# elif defined(MAX_PATH) +# define MAXPATHLEN MAX_PATH +# else +# if defined(__GNU__) +# define MAXPATHLEN 4096 +# else +# define MAXPATHLEN 256 /* Should be safe for any weird systems that do not define it */ +# endif +# endif +#endif + +#ifdef HAVE_STDINT_H +# include +#else +# if defined(HAVE_INTTYPES_H) +# include +# else +# include "msinttypes/inttypes.h" +# endif +#endif + +#ifdef _MSC_VER +#define ssize_t SSIZE_T +#define MAXSIZE_T ((SIZE_T)~ ((SIZE_T)0)) +#define MAXSSIZE_T ((SSIZE_T) (MAXSIZE_T >> 1)) +#define MINSSIZE_T ((SSIZE_T)~MAXSSIZE_T) +#define SSIZE_MAX MAXSSIZE_T +#endif + +#include "gd.h" + +#define MIN(a,b) ((a)<(b)?(a):(b)) +#define MIN3(a,b,c) ((a)<(b)?(MIN(a,c)):(MIN(b,c))) +#define MAX(a,b) ((a)<(b)?(b):(a)) +#define MAX3(a,b,c) ((a)<(b)?(MAX(b,c)):(MAX(a,c))) +#define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x))) + +typedef enum { + HORIZONTAL, + VERTICAL, +} gdAxis; + +/* Convert a double to an unsigned char, rounding to the nearest + * integer and clamping the result between 0 and max. The absolute + * value of clr must be less than the maximum value of an unsigned + * short. */ +static inline unsigned char +uchar_clamp(double clr, unsigned char max) { + unsigned short result; + + //assert(fabs(clr) <= SHRT_MAX); + + /* Casting a negative float to an unsigned short is undefined. + * However, casting a float to a signed truncates toward zero and + * casting a negative signed value to an unsigned of the same size + * results in a bit-identical value (assuming twos-complement + * arithmetic). This is what we want: all legal negative values + * for clr will be greater than 255. */ + + /* Convert and clamp. */ + result = (unsigned short)(short)(clr + 0.5); + if (result > max) { + result = (clr < 0) ? 0 : max; + }/* if */ + + return result; +}/* uchar_clamp*/ + + +/* Internal prototypes: */ + +/* gd_rotate.c */ +gdImagePtr gdImageRotate90(gdImagePtr src, int ignoretransparent); +gdImagePtr gdImageRotate180(gdImagePtr src, int ignoretransparent); +gdImagePtr gdImageRotate270(gdImagePtr src, int ignoretransparent); + + + + + + +#endif diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_io.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_io.h new file mode 100644 index 0000000000..f6bd4d6ea2 --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_io.h @@ -0,0 +1,89 @@ +#ifndef GD_IO_H +#define GD_IO_H 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + Group: Types + + typedef: gdIOCtx + + gdIOCtx structures hold function pointers for doing image IO. + + Most of the gd functions that read and write files, such as + also have variants that accept a structure; + see and . + + Those who wish to provide their own custom routines to read and + write images can populate a gdIOCtx structure with functions of + their own devising to to read and write data. For image reading, the + only mandatory functions are getC and getBuf, which must return the + number of characters actually read, or a negative value on error or + EOF. These functions must read the number of characters requested + unless at the end of the file. + + For image writing, the only mandatory functions are putC and putBuf, + which return the number of characters written; these functions must + write the number of characters requested except in the event of an + error. The seek and tell functions are only required in conjunction + with the gd2 file format, which supports quick loading of partial + images. The gd_free function will not be invoked when calling the + standard Ctx functions; it is an implementation convenience when + adding new data types to gd. For examples, see gd_png.c, gd_gd2.c, + gd_jpeg.c, etc., all of which rely on gdIOCtx to implement the + standard image read and write functions. + + > typedef struct gdIOCtx + > { + > int (*getC)(gdIOCtxPtr); + > int (*getBuf)(gdIOCtxPtr, void *, int wanted); + > + > void (*putC)(gdIOCtxPtr, int); + > int (*putBuf)(gdIOCtxPtr, const void *, int wanted); + > + > // seek must return 1 on SUCCESS, 0 on FAILURE. Unlike fseek! + > int (*seek)(gdIOCtxPtr, const int); + > long (*tell)(gdIOCtxPtr); + > + > void (*gd_free)(gdIOCtxPtr); + > } gdIOCtx; + */ +typedef struct gdIOCtx *gdIOCtxPtr; + +typedef struct gdIOCtx { + int (*getC)(gdIOCtxPtr); + int (*getBuf)(gdIOCtxPtr, void *, int); + void (*putC)(gdIOCtxPtr, int); + int (*putBuf)(gdIOCtxPtr, const void *, int); + /* seek must return 1 on SUCCESS, 0 on FAILURE. Unlike fseek! */ + int (*seek)(gdIOCtxPtr, const int); + long (*tell)(gdIOCtxPtr); + void (*gd_free)(gdIOCtxPtr); + void *data; +} gdIOCtx; + +void gdPutC(const unsigned char c, gdIOCtxPtr ctx); +int gdPutBuf(const void *, int, gdIOCtxPtr); +void gdPutWord(int w, gdIOCtxPtr ctx); +void gdPutInt(int w, gdIOCtxPtr ctx); + +int gdGetC(gdIOCtxPtr ctx); +int gdGetBuf(void *, int, gdIOCtxPtr); +int gdGetByte(int *result, gdIOCtxPtr ctx); +int gdGetWord(int *result, gdIOCtxPtr ctx); +int gdGetWordLSB(signed short int *result, gdIOCtxPtr ctx); +int gdGetInt(int *result, gdIOCtxPtr ctx); +int gdGetIntLSB(signed int *result, gdIOCtxPtr ctx); + +int gdSeek(gdIOCtxPtr ctx, const int offset); +long gdTell(gdIOCtxPtr ctx); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_io_stream.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_io_stream.h new file mode 100644 index 0000000000..d682c2fd9d --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_io_stream.h @@ -0,0 +1,125 @@ +/* ***************************************************************************** +** Initial file written and documented by: +** Kevin Shepherd December 2007 +** of Scarlet Line http://www.scarletline.com/ +*******************************************************************************/ +/** \file gd_io_stream.h + \brief C++ standard library iostream specializations of gdIOCtx. + + Note that all of the methods defined in this header are internal to the + libgd library, except for the constructors. + Only the constructors are needed by a user of the libgd API. + This file does not use or need gdpp.h, but if GD::Image is + used, then C++ coding becomes even simpler, and the classes below + become entirely hidden implementation details. + Example usage, convert png to gif: + #include + #include "gd_io_stream.h" + std::ifstream in("image.png", std::ios_base::in | std::ios_base::binary ); + if (in.good()) + { + istreamIOCtx _in_ctx(in); + gdImagePtr im_in = gdImageCreateFromPngCtx ( & _in_ctx); + std::ofstream out("image.gif", std::ios_base::out | std::ios_base::binary ); + ostreamIOCtx _out_ctx(out); + gdImageGifCtx(im_in, & _out_ctx); + } + gdImageDestroy(im_in); +*/ +#ifndef _gd_io_stream_h +#define _gd_io_stream_h +#ifdef __cplusplus + +#include "gd.h" +#include + +/** Standard library input stream specialization of gdIOCtx +*/ +class BGD_EXPORT_DATA_IMPL istreamIOCtx : public gdIOCtx +{ +public: + typedef std::istream stream_type; + /** Construct an instance of this input stream specialization, + given an input stream. + For example: + std::ifstream in("image.png", std::ios_base::in | std::ios_base::binary ); + istreamIOCtx in_ctx(in); + */ + istreamIOCtx(stream_type & __stream) { + init( & __stream); + } + + static int Getbuf(gdIOCtxPtr ctx, void *buf, int size); + static int Putbuf(gdIOCtxPtr, const void *, int); + static void Putchar(gdIOCtxPtr, int); + static int Getchar(gdIOCtxPtr ctx); + static int Seek(gdIOCtxPtr ctx, const int pos); + static long Tell(gdIOCtxPtr ctx); + static void FreeCtx(gdIOCtxPtr ctx); + + void init(stream_type * __stream) { + getC = Getchar; + putC = Putchar; + getBuf = Getbuf; + putBuf = Putbuf; + tell = Tell; + seek = Seek; + gd_free = FreeCtx; + _M_stream = __stream; + } +private: + stream_type * _M_stream; +}; +/** Allocate a new instance of the class +*/ +inline gdIOCtxPtr gdNewIstreamCtx(std::istream *__stream) +{ + return new istreamIOCtx(* __stream); +} + +/** Standard library output stream specialization of gdIOCtx +*/ +class BGD_EXPORT_DATA_IMPL ostreamIOCtx : public gdIOCtx +{ +public: + typedef std::ostream stream_type; + /** Construct an instance of this output stream specialization, + given an output stream. + For example: + std::ofstream out("image.gif", std::ios_base::out | std::ios_base::binary ); + ostreamIOCtx out_ctx(out); + */ + ostreamIOCtx(stream_type & __stream) { + init( & __stream); + } + + static int Getbuf(gdIOCtxPtr, void *, int); + static int Putbuf(gdIOCtxPtr ctx, const void *buf, int size); + static int Getchar(gdIOCtxPtr); + static void Putchar(gdIOCtxPtr ctx, int a); + static int Seek(gdIOCtxPtr ctx, const int pos); + static long Tell(gdIOCtxPtr ctx); + static void FreeCtx(gdIOCtxPtr ctx); + + void init(stream_type * __stream) { + getC = Getchar; + putC = Putchar; + getBuf = Getbuf; + putBuf = Putbuf; + tell = Tell; + seek = Seek; + gd_free = FreeCtx; + _M_stream = __stream; + } +private: + stream_type * _M_stream; +}; +/** Allocate a new instance of the class +*/ +inline gdIOCtxPtr gdNewOstreamCtx(std::ostream *__stream) +{ + return new ostreamIOCtx(* __stream); +} + +#endif /* __cplusplus */ +#endif /* _gd_io_stream_h */ diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_nnquant.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_nnquant.h new file mode 100644 index 0000000000..11643b7d62 --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_nnquant.h @@ -0,0 +1,16 @@ +/* maximum number of colours that can be used. + actual number is now passed to initcolors */ +#define MAXNETSIZE 256 + +/* For 256 colours, fixed arrays need 8kb, plus space for the image + ---------------------------------------------------------------- */ + + +/* four primes near 500 - assume no image has a length so large */ +/* that it is divisible by all four primes */ +#define prime1 499 +#define prime2 491 +#define prime3 487 +#define prime4 503 + +#define minpicturebytes (4*prime4) /* minimum size for input image */ diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_tga.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_tga.h new file mode 100644 index 0000000000..b56e2e41f9 --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gd_tga.h @@ -0,0 +1,52 @@ +#ifndef __TGA_H +#define __TGA_H 1 + +#include "gd.h" +#include "gdhelpers.h" + +#include "gd_intern.h" + +typedef struct oTga_ { + uint8_t identsize; // size of ID field that follows 18 uint8_t header (0 usually) + uint8_t colormaptype; // type of colour map 0=none, 1=has palette [IGNORED] Adrian requested no support + uint8_t imagetype; // type of image 0=none,1=indexed,2=rgb,3=grey,+8=rle packed + + int colormapstart; // first colour map entry in palette [IGNORED] Adrian requested no support + int colormaplength; // number of colours in palette [IGNORED] Adrian requested no support + uint8_t colormapbits; // number of bits per palette entry 15,16,24,32 [IGNORED] Adrian requested no support + + int xstart; // image x origin + int ystart; // image y origin + int width; // image width in pixels + int height; // image height in pixels + uint8_t bits; // image bits per pixel 8,16,24,32 + uint8_t alphabits; // alpha bits (low 4bits of header 17) + uint8_t fliph; // horizontal or vertical + uint8_t flipv; // flip + char *ident; // identifcation tag string + int *bitmap; // bitmap data + +} oTga; + +#define TGA_TYPE_NO_IMAGE 0 +#define TGA_TYPE_INDEXED 1 +#define TGA_TYPE_RGB 2 +#define TGA_TYPE_GREYSCALE 3 +#define TGA_TYPE_INDEXED_RLE 9 +#define TGA_TYPE_RGB_RLE 10 +#define TGA_TYPE_GREYSCALE_RLE 11 +#define TGA_TYPE_INDEXED_HUFFMAN_DELTA_RLE 32 +#define TGA_TYPE_RGB_HUFFMAN_DELTA_QUADTREE_RLE 33 + +#define TGA_BPP_8 8 +#define TGA_BPP_16 16 +#define TGA_BPP_24 24 +#define TGA_BPP_32 32 + +#define TGA_RLE_FLAG 128 + +int read_header_tga(gdIOCtxPtr ctx, oTga *tga); +int read_image_tga(gdIOCtxPtr ctx, oTga *tga); +void free_tga(oTga *tga); + +#endif //__TGA_H diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdcache.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdcache.h new file mode 100644 index 0000000000..751a842154 --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdcache.h @@ -0,0 +1,90 @@ +#ifdef __cplusplus +extern "C" { +#endif + + /* + * gdcache.h + * + * Caches of pointers to user structs in which the least-recently-used + * element is replaced in the event of a cache miss after the cache has + * reached a given size. + * + * John Ellson (ellson@graphviz.org) Oct 31, 1997 + * + * Test this with: + * gcc -o gdcache -g -Wall -DTEST -DNEED_CACHE gdcache.c -lgd + * or + * gcc -o gdcache -g -Wall -DTEST -DNEED_CACHE gdcache.c libgd.a + * + * The cache is implemented by a singly-linked list of elements + * each containing a pointer to a user struct that is being managed by + * the cache. + * + * The head structure has a pointer to the most-recently-used + * element, and elements are moved to this position in the list each + * time they are used. The head also contains pointers to three + * user defined functions: + * - a function to test if a cached userdata matches some keydata + * - a function to provide a new userdata struct to the cache + * if there has been a cache miss. + * - a function to release a userdata struct when it is + * no longer being managed by the cache + * + * In the event of a cache miss the cache is allowed to grow up to + * a specified maximum size. After the maximum size is reached then + * the least-recently-used element is discarded to make room for the + * new. The most-recently-returned value is always left at the + * beginning of the list after retrieval. + * + * In the current implementation the cache is traversed by a linear + * search from most-recent to least-recent. This linear search + * probably limits the usefulness of this implementation to cache + * sizes of a few tens of elements. + */ + + /*********************************************************/ + /* header */ + /*********************************************************/ + +#include +#ifndef NULL +# define NULL (void *)0 +#endif + + /* user defined function templates */ + typedef int (*gdCacheTestFn_t)(void *userdata, void *keydata); + typedef void *(*gdCacheFetchFn_t)(char **error, void *keydata); + typedef void (*gdCacheReleaseFn_t)(void *userdata); + + /* element structure */ + typedef struct gdCache_element_s gdCache_element_t; + struct gdCache_element_s { + gdCache_element_t *next; + void *userdata; + }; + + /* head structure */ + typedef struct gdCache_head_s gdCache_head_t; + struct gdCache_head_s { + gdCache_element_t *mru; + int size; + char *error; + gdCacheTestFn_t gdCacheTest; + gdCacheFetchFn_t gdCacheFetch; + gdCacheReleaseFn_t gdCacheRelease; + }; + + /* function templates */ + gdCache_head_t *gdCacheCreate(int size, + gdCacheTestFn_t gdCacheTest, + gdCacheFetchFn_t gdCacheFetch, + gdCacheReleaseFn_t gdCacheRelease + ); + + void gdCacheDelete(gdCache_head_t *head); + + void *gdCacheGet(gdCache_head_t *head, void *keydata); + +#ifdef __cplusplus +} +#endif diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdfontg.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdfontg.h new file mode 100644 index 0000000000..5d85812cf4 --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdfontg.h @@ -0,0 +1,28 @@ +#ifndef _GDFONTG_H_ +#define _GDFONTG_H_ 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + This is a header file for gd font, generated using + bdftogd version 0.51 by Jan Pazdziora, adelton@fi.muni.cz + from bdf font + -Misc-Fixed-Bold-R-Normal-Sans-15-140-75-75-C-90-ISO8859-2 + at Mon Jan 26 14:45:58 1998. + The original bdf was holding following copyright: + "Libor Skarvada, libor@informatics.muni.cz" + */ + +#include "gd.h" + +extern BGD_EXPORT_DATA_PROT gdFontPtr gdFontGiant; +BGD_DECLARE(gdFontPtr) gdFontGetGiant(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdfontl.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdfontl.h new file mode 100644 index 0000000000..2fc91ca6bf --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdfontl.h @@ -0,0 +1,29 @@ +#ifndef _GDFONTL_H_ +#define _GDFONTL_H_ 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + This is a header file for gd font, generated using + bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz + from bdf font + -misc-fixed-medium-r-normal--16-140-75-75-c-80-iso8859-2 + at Tue Jan 6 19:39:27 1998. + + The original bdf was holding following copyright: + "Libor Skarvada, libor@informatics.muni.cz" + */ + +#include "gd.h" + +extern BGD_EXPORT_DATA_PROT gdFontPtr gdFontLarge; +BGD_DECLARE(gdFontPtr) gdFontGetLarge(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdfontmb.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdfontmb.h new file mode 100644 index 0000000000..e6807db4eb --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdfontmb.h @@ -0,0 +1,27 @@ +#ifndef _GDFONTMB_H_ +#define _GDFONTMB_H_ 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + This is a header file for gd font, generated using + bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz + from bdf font + -misc-fixed-bold-r-normal-sans-13-94-100-100-c-70-iso8859-2 + at Thu Jan 8 13:54:57 1998. + No copyright info was found in the original bdf. + */ + +#include "gd.h" + +extern BGD_EXPORT_DATA_PROT gdFontPtr gdFontMediumBold; +BGD_DECLARE(gdFontPtr) gdFontGetMediumBold(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdfonts.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdfonts.h new file mode 100644 index 0000000000..b5127e971a --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdfonts.h @@ -0,0 +1,27 @@ +#ifndef _GDFONTS_H_ +#define _GDFONTS_H_ 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + This is a header file for gd font, generated using + bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz + from bdf font + -misc-fixed-medium-r-semicondensed-sans-12-116-75-75-c-60-iso8859-2 + at Thu Jan 8 14:13:20 1998. + No copyright info was found in the original bdf. + */ + +#include "gd.h" + +extern BGD_EXPORT_DATA_PROT gdFontPtr gdFontSmall; +BGD_DECLARE(gdFontPtr) gdFontGetSmall(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdfontt.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdfontt.h new file mode 100644 index 0000000000..d61b01ff4a --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdfontt.h @@ -0,0 +1,28 @@ +#ifndef _GDFONTT_H_ +#define _GDFONTT_H_ 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* + This is a header file for gd font, generated using + bdftogd version 0.5 by Jan Pazdziora, adelton@fi.muni.cz + from bdf font + -Misc-Fixed-Medium-R-Normal--8-80-75-75-C-50-ISO8859-2 + at Thu Jan 8 13:49:54 1998. + The original bdf was holding following copyright: + "Libor Skarvada, libor@informatics.muni.cz" + */ + +#include "gd.h" + +extern BGD_EXPORT_DATA_PROT gdFontPtr gdFontTiny; +BGD_DECLARE(gdFontPtr) gdFontGetTiny(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdfx.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdfx.h new file mode 100644 index 0000000000..b00f573a60 --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdfx.h @@ -0,0 +1,29 @@ +#ifndef GDFX_H +#define GDFX_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + +BGD_DECLARE(gdImagePtr) gdImageSquareToCircle(gdImagePtr im, int radius); + +BGD_DECLARE(char *) gdImageStringFTCircle( + gdImagePtr im, + int cx, + int cy, + double radius, + double textRadius, + double fillPortion, + char *font, + double points, + char *top, + char *bottom, + int fgcolor); + +BGD_DECLARE(void) gdImageSharpen (gdImagePtr im, int pct); + +#ifdef __cplusplus +} +#endif + +#endif /* GDFX_H */ diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdhelpers.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdhelpers.h new file mode 100644 index 0000000000..9b187af7fa --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdhelpers.h @@ -0,0 +1,76 @@ +#ifndef GDHELPERS_H +#define GDHELPERS_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + + /* sys/types.h is needed for size_t on Sparc-SunOS-4.1 */ +#ifndef _WIN32_WCE +#include +#else +#include +#endif /* _WIN32_WCE */ + + /* TBB: strtok_r is not universal; provide an implementation of it. */ + + char *gd_strtok_r(char *s, const char *sep, char **state); + + /* These functions wrap memory management. gdFree is + in gd.h, where callers can utilize it to correctly + free memory allocated by these functions with the + right version of free(). */ + void *gdCalloc(size_t nmemb, size_t size) BGD_MALLOC; + void *gdMalloc(size_t size) BGD_MALLOC; + void *gdRealloc (void *ptr, size_t size); + /* The extended version of gdReallocEx will free *ptr if the + * realloc fails */ + void *gdReallocEx (void *ptr, size_t size); + + /* Returns nonzero if multiplying the two quantities will + result in integer overflow. Also returns nonzero if + either quantity is negative. By Phil Knirsch based on + netpbm fixes by Alan Cox. */ + + int overflow2(int a, int b); + + /* 2.0.16: portable mutex support for thread safety. */ +#if defined(CPP_SHARP) +# define gdMutexDeclare(x) +# define gdMutexSetup(x) +# define gdMutexShutdown(x) +# define gdMutexLock(x) +# define gdMutexUnlock(x) +#elif defined(_WIN32) + /* 2.0.18: must include windows.h to get CRITICAL_SECTION. */ +# include +# define gdMutexDeclare(x) CRITICAL_SECTION x +# define gdMutexSetup(x) InitializeCriticalSection(&x) +# define gdMutexShutdown(x) DeleteCriticalSection(&x) +# define gdMutexLock(x) EnterCriticalSection(&x) +# define gdMutexUnlock(x) LeaveCriticalSection(&x) +#elif defined(HAVE_PTHREAD) +# include +# define gdMutexDeclare(x) pthread_mutex_t x +# define gdMutexSetup(x) pthread_mutex_init(&x, 0) +# define gdMutexShutdown(x) pthread_mutex_destroy(&x) +# define gdMutexLock(x) pthread_mutex_lock(&x) +# define gdMutexUnlock(x) pthread_mutex_unlock(&x) +#else +# define gdMutexDeclare(x) +# define gdMutexSetup(x) +# define gdMutexShutdown(x) +# define gdMutexLock(x) +# define gdMutexUnlock(x) +#endif /* _WIN32 || HAVE_PTHREAD */ + +#define DPCM2DPI(dpcm) (unsigned int)((dpcm)*2.54 + 0.5) +#define DPM2DPI(dpm) (unsigned int)((dpm)*0.0254 + 0.5) +#define DPI2DPCM(dpi) (unsigned int)((dpi)/2.54 + 0.5) +#define DPI2DPM(dpi) (unsigned int)((dpi)/0.0254 + 0.5) + +#ifdef __cplusplus +} +#endif + +#endif /* GDHELPERS_H */ diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdpp.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdpp.h new file mode 100644 index 0000000000..635f2c402d --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/gdpp.h @@ -0,0 +1,1530 @@ +/* ***************************************************************************** +** Initial file written and documented by: +** Kevin Shepherd December 2007 +** of Scarlet Line http://www.scarletline.com/ +** with contributions from Torben Nielsen. +*******************************************************************************/ +/** \file gdpp.h + \brief Object Oriented C++ wrappers around libgd functionality. + + Example usage, convert png to gif: + #include + #include + + std::ifstream in("image.png", std::ios_base::in | std::ios_base::binary ); + GD::Image im(in, GD::Png_tag()); + if (im.good()) + { + std::ofstream out("image.gif", std::ios_base::out | std::ios_base::binary ); + im.Gif(out); + } +*/ +#ifndef _gdpp_h +#define _gdpp_h +#ifdef __cplusplus + +#include "gd_io_stream.h" +#include + +/// namespace GD:: contains the C++ wrapper classes for libgd +/** This namespace is primarily to avoid name clashes, and to + contain all of the gd classes within one namespace. + It is not recommended to use the "using namespace" directive with this namespace. + Example usage: + GD::Image im(64, 32, true); // Create a truecolor image 64 pixels wide by 32 pixels high + GD::Point pt(10, 8); // The point at x=10, y=8. + GD::Size sz(16, 8); // The size width=16, height=8. + GD::TrueColor col(0xFF, 0, 0); // The colour red; R=255, G=0, B=0. + im.Rectangle(pt, sz, col.Int()); // Draw a red rectangle with top left corner at pt, of size sz. +*/ +namespace GD +{ +/** This class GD::Point stores a point in two dimensions, somewhere + on the plane of an image. +*/ +class BGD_EXPORT_DATA_PROT Point +{ +public: + // Constructors + Point(int x, int y) + :_x(x), _y(y) {} + Point(const Point & p) + :_x(p._x), _y(p._y) {} + Point() + :_x(0), _y(0) {} + Point & operator=(const Point & p) { + _x = p._x; + _y = p._y; + return (* this); + } + // Accessors + int X() const { + return _x; + } + int Y() const { + return _y; + } + // Updaters + void X(int x) { + _x = x; + } + void Y(int y) { + _y = y; + } + void set(int x, int y) { + _x = x; + _y = y; + } + int & lhsX() { + return _x; + } + int & lhsY() { + return _y; + } + + gdPointPtr as_gdPointPtr() { + return (gdPointPtr) this; + } +protected: + int _x, _y; +}; +typedef Point * PointPtr; +/** This class GD::Size stores length in two dimensions. + Giving the size of an area as width and height. +*/ +class BGD_EXPORT_DATA_PROT Size +{ +public: + // Constructors + Size(int w, int h) + :_w(w), _h(h) {} + Size(const Size & p) + :_w(p._w), _h(p._h) {} + Size() + :_w(0), _h(0) {} + Size & operator=(const Size & p) { + _w = p._w; + _h = p._h; + return (* this); + } + // Accessors + int W() const { + return _w; + } + int H() const { + return _h; + } + // Updaters + void W(int w) { + _w = w; + } + void H(int h) { + _h = h; + } + void set(int w, int h) { + _w = w; + _h = h; + } + int & lhsW() { + return _w; + } + int & lhsH() { + return _h; + } +protected: + int _w, _h; +}; +typedef Size * SizePtr; + +/** This class GD::TrueColor stores a colour as an RGBA quadruplet. + It can also be read as an integer, and in other colour formats. +*/ +class BGD_EXPORT_DATA_PROT TrueColor +{ +public: + union as_types { + int as_int; + struct uchars { + unsigned char blue, green, red, alpha; + } as_uchar; + }; + TrueColor() { + internal.as_int = 0; + } + TrueColor(int c) { + internal.as_int = c; + } + TrueColor(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 0) { + internal.as_uchar.alpha = a; + internal.as_uchar.red = r; + internal.as_uchar.green = g; + internal.as_uchar.blue = b; + } + // Accessors + int Int() const { + return internal.as_int; + } + unsigned char Red() const { + return internal.as_uchar.red; + } + unsigned char Green() const { + return internal.as_uchar.green; + } + unsigned char Blue() const { + return internal.as_uchar.blue; + } + unsigned char Alpha() const { + return internal.as_uchar.alpha; + } + // Updaters + void set(int c) { + internal.as_int = c; + } + void set(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 0) { + internal.as_uchar.alpha = a; + internal.as_uchar.red = r; + internal.as_uchar.green = g; + internal.as_uchar.blue = b; + } + void Red(unsigned char c) { + internal.as_uchar.red = c; + } + void Green(unsigned char c) { + internal.as_uchar.green = c; + } + void Blue(unsigned char c) { + internal.as_uchar.blue = c; + } + void Alpha(unsigned char c) { + internal.as_uchar.alpha = c; + } +protected: + as_types internal; +}; +/* The following tags are simply empty structures which are used + to tell the compiler which constructor we want when we know + the image file format. +*/ +struct BGD_EXPORT_DATA_PROT Png_tag {}; +struct BGD_EXPORT_DATA_PROT Gif_tag {}; +struct BGD_EXPORT_DATA_PROT WBMP_tag {}; +struct BGD_EXPORT_DATA_PROT Jpeg_tag {}; +struct BGD_EXPORT_DATA_PROT Gd_tag {}; +struct BGD_EXPORT_DATA_PROT Gd2_tag {}; +struct BGD_EXPORT_DATA_PROT Xbm_tag {}; + +/** This class GD::Image wraps all of the 'C' libgd functionality + for the convenience of C++ users. An instance of this class + corresponds to a single image. +*/ +class BGD_EXPORT_DATA_PROT Image +{ +public: + /** Construct a null image + */ + Image() + :im(0) + {} + /** Construct a blank image, of the given size and colour format type. + \param[in] sx Width of the image + \param[in] sy Height of the image + \param[in] istruecolor Create a true colour image, defaults to false, i.e. create an indexed palette image. + */ + Image(int sx, int sy, bool istruecolor = false) + :im(0) { + if (istruecolor) + CreateTrueColor(sx, sy); + else + Create(sx, sy); + } + /** Construct a blank image, of the given size and colour format type. + \param[in] s Width and height of the image + \param[in] istruecolor Create a true colour image, defaults to false, i.e. create an indexed palette image. + */ + Image(const Size & s, bool istruecolor = false) + :im(0) { + if (istruecolor) + CreateTrueColor(s); + else + Create(s); + } + /** Construct an instance of the GD::Image class, given the internal gdImage poimter. + Note that gdImageDestroy will be called on the image pointer in the destructor. + \param[in] i Pointer to the internal gdImage + */ + Image(gdImagePtr i) + :im(i) {} + /** Copy constructor. Construct an instance of the GD::Image class, + by making a copy of the GD::Image provided. + \param[in] i Reference to the image to be copied + */ + Image(const GD::Image & i) + :im(0) { + Copy(i); + } + /** Construct an image by reading from \p in. This constructor + will first attempt to determine the file format. + \param[in] in The stream containing the image data + */ + Image(std::istream & in) + :im(0) { + CreateFrom(in); + } + /** Construct an image by reading from \p in. This constructor + will first attempt to determine the file format. + \param[in] in An opened FILE * handle to a file containing the image data + */ + Image(FILE * in) + :im(0) { + CreateFrom(in); + } + /** Construct an image by reading from memory block \p data. This constructor + will first attempt to determine the image formatting. + \param[in] size The byte count of the memory block + \param[in] data Pointer to the memory block + */ + Image(int size, void * data) + :im(0) { + CreateFrom(size, data); + } + + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Png_tag()); // read a png file from input + \param[in] in The stream containing the image data + */ + Image(std::istream & in, Png_tag) + :im(0) { + CreateFromPng(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Png_tag()); // read a png file from input + \param[in] in An opened FILE * handle to a file containing the image data + */ + Image(FILE * in, Png_tag) + :im(0) { + CreateFromPng(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Png_tag()); // read a png file from input + \param[in] in The io context from which to read the image data + */ + Image(gdIOCtxPtr in, Png_tag) + :im(0) { + CreateFromPng(in); + } + /** Construct an image by reading from memory block \p data. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(sz, dat, GD::Png_tag()); // read a png file from dat + \param[in] size The byte count of the memory block + \param[in] data Pointer to the memory block + */ + Image(int size, void * data, Png_tag) + :im(0) { + CreateFromPng(size, data); + } + + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Gif_tag()); // read a gif file from input + \param[in] in The stream containing the image data + */ + Image(std::istream & in, Gif_tag) + :im(0) { + CreateFromGif(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Gif_tag()); // read a gif file from input + \param[in] in An opened FILE * handle to a file containing the image data + */ + Image(FILE * in, Gif_tag) + :im(0) { + CreateFromGif(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Gif_tag()); // read a gif file from input + \param[in] in The io context from which to read the image data + */ + Image(gdIOCtxPtr in, Gif_tag) + :im(0) { + CreateFromGif(in); + } + /** Construct an image by reading from memory block \p data. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(sz, dat, GD::Gif_tag()); // read a gif file from dat + \param[in] size The byte count of the memory block + \param[in] data Pointer to the memory block + */ + Image(int size, void * data, Gif_tag) + :im(0) { + CreateFromGif(size, data); + } + + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::WBMP_tag()); // read a monchrome WBMP file from input + \param[in] in The stream containing the image data + */ + Image(std::istream & in, WBMP_tag) + :im(0) { + CreateFromWBMP(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::WBMP_tag()); // read a monchrome WBMP file from input + \param[in] in An opened FILE * handle to a file containing the image data + */ + Image(FILE * in, WBMP_tag) + :im(0) { + CreateFromWBMP(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::WBMP_tag()); // read a monchrome WBMP file from input + \param[in] in The io context from which to read the image data + */ + Image(gdIOCtxPtr in, WBMP_tag) + :im(0) { + CreateFromWBMP(in); + } + /** Construct an image by reading from memory block \p data. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(sz, dat, GD::WBMP_tag()); // read a monchrome WBMP file from dat + \param[in] size The byte count of the memory block + \param[in] data Pointer to the memory block + */ + Image(int size, void * data, WBMP_tag) + :im(0) { + CreateFromWBMP(size, data); + } + + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Jpeg_tag()); // read a jpeg file from input + \param[in] in The stream containing the image data + */ + Image(std::istream & in, Jpeg_tag) + :im(0) { + CreateFromJpeg(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Jpeg_tag()); // read a jpeg file from input + \param[in] in An opened FILE * handle to a file containing the image data + */ + Image(FILE * in, Jpeg_tag) + :im(0) { + CreateFromJpeg(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Jpeg_tag()); // read a jpeg file from input + \param[in] in The io context from which to read the image data + */ + Image(gdIOCtxPtr in, Jpeg_tag) + :im(0) { + CreateFromJpeg(in); + } + /** Construct an image by reading from memory block \p data. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(sz, dat, GD::Jpeg_tag()); // read a jpeg file from dat + \param[in] size The byte count of the memory block + \param[in] data Pointer to the memory block + */ + Image(int size, void * data, Jpeg_tag) + :im(0) { + CreateFromJpeg(size, data); + } + + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Gd_tag()); // read a gd file from input + \param[in] in The stream containing the image data + */ + Image(std::istream & in, Gd_tag) + :im(0) { + CreateFromGd(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Gd_tag()); // read a gd file from input + \param[in] in An opened FILE * handle to a file containing the image data + */ + Image(FILE * in, Gd_tag) + :im(0) { + CreateFromGd(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Gd_tag()); // read a gd file from input + \param[in] in The io context from which to read the image data + */ + Image(gdIOCtxPtr in, Gd_tag) + :im(0) { + CreateFromGd(in); + } + /** Construct an image by reading from memory block \p data. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(sz, dat, GD::Gd_tag()); // read a gd file from dat + \param[in] size The byte count of the memory block + \param[in] data Pointer to the memory block + */ + Image(int size, void * data, Gd_tag) + :im(0) { + CreateFromGd(size, data); + } + + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Gd2_tag()); // read a gd2 file from input + \param[in] in The stream containing the image data + */ + Image(std::istream & in, Gd2_tag) + :im(0) { + CreateFromGd2(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Png_tag()); // read a png file from input + \param[in] in An opened FILE * handle to a file containing the image data + */ + Image(FILE * in, Gd2_tag) + :im(0) { + CreateFromGd2(in); + } + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Gd2_tag()); // read a gd2 file from input + \param[in] in The io context from which to read the image data + */ + Image(gdIOCtxPtr in, Gd2_tag) + :im(0) { + CreateFromGd2(in); + } + /** Construct an image by reading from memory block \p data. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(sz, dat, GD::Gd2_tag()); // read a gd2 file from dat + \param[in] size The byte count of the memory block + \param[in] data Pointer to the memory block + */ + Image(int size, void * data, Gd2_tag) + :im(0) { + CreateFromGd2(size, data); + } + + /** Construct an image by reading from \p in. + The tag is an empty struct which simply tells the compiler which image read function to use. + e.g. GD::Image img(input, GD::Xbm_tag()); // read an xbm file from input + \param[in] in An opened FILE * handle to a file containing the image data + */ + Image(FILE * in, Xbm_tag) + :im(0) { + CreateFromXbm(in); + } + + ~Image() { + clear(); + } + + /** Assignment Operator. Make this a copy of the GD::Image provided. + \param[in] src Reference to the image to be copied + */ + GD::Image & operator=(const GD::Image & src) { + Copy(src); + return (* this); + } + /** Make this an exact copy of the GD::Image provided. Any existing iamge data is discarded. + \param[in] src Reference to the image to be copied + */ + void Copy(const GD::Image & src) { + int w = src.Width(), h = src.Height(); + if (src.IsTrueColor()) + CreateTrueColor(w, h); + else { + Create(w, h); + PaletteCopy(src); + } + Copy(src, 0, 0, 0, 0, w, h); + } + /** Check to see if this appears to be a valid image + */ + bool good() const { + return (im != 0); + } + // Creation: + /** + Create a palette-based image, with no more than 256 colors. + \param sx Width of the desired image + \param sy Height of the desired image + \return true if it worked, else false + */ + bool Create(int sx, int sy) { + clear(); + return ((im = gdImageCreate(sx, sy)) != 0); + } + /** + Create a truecolor image. + \param sx Width of the desired image + \param sy Height of the desired image + \return true if it worked, else false + */ + bool CreateTrueColor(int sx, int sy) { + clear(); + return ((im = gdImageCreateTrueColor(sx, sy)) != 0); + } + /** + Create a palette-based image, with no more than 256 colors. + \param s Width and height of the desired image + \return true if it worked, else false + */ + bool Create(const Size & s) { + return Create(s.W(), s.H()); + } + /** + Create a truecolor image. + \param s Width and height of the desired image + \return true if it worked, else false + */ + bool CreateTrueColor(const Size & s) { + return CreateTrueColor(s.W(), s.H()); + } + // Create, determining the image format from the data + /// Read an image from an open FILE * handle, after determining the image format + bool CreateFrom(FILE * in); + /// Read an image from an open standard library input stream, after determining the image format + bool CreateFrom(std::istream & in); + /// Read an image from a memory block, after determining the image format + bool CreateFrom(int size, void * data); + + // Png + bool CreateFromPng(FILE * in) { + clear(); + return ((im = gdImageCreateFromPng(in)) != 0); + } + bool CreateFromPng(gdIOCtxPtr in) { + clear(); + return ((im = gdImageCreateFromPngCtx(in)) != 0); + } + bool CreateFromPng(int size, void * data) { + clear(); + return ((im = gdImageCreateFromPngPtr(size, data)) != 0); + } + bool CreateFromPng(std::istream & in) { + clear(); + istreamIOCtx _in_ctx(in); + return ((im = gdImageCreateFromPngCtx( & _in_ctx)) != 0); + } + + // Gif + bool CreateFromGif(FILE * in) { + clear(); + return ((im = gdImageCreateFromGif(in)) != 0); + } + bool CreateFromGif(gdIOCtxPtr in) { + clear(); + return ((im = gdImageCreateFromGifCtx(in)) != 0); + } + bool CreateFromGif(int size, void * data) { + clear(); + return ((im = gdImageCreateFromGifPtr(size, data)) != 0); + } + bool CreateFromGif(std::istream & in) { + clear(); + istreamIOCtx _in_ctx(in); + return ((im = gdImageCreateFromGifCtx( & _in_ctx)) != 0); + } + // WBMP + bool CreateFromWBMP(FILE * in) { + clear(); + return ((im = gdImageCreateFromWBMP(in)) != 0); + } + bool CreateFromWBMP(gdIOCtxPtr in) { + clear(); + return ((im = gdImageCreateFromWBMPCtx(in)) != 0); + } + bool CreateFromWBMP(int size, void * data) { + clear(); + return ((im = gdImageCreateFromWBMPPtr(size, data)) != 0); + } + bool CreateFromWBMP(std::istream & in) { + clear(); + istreamIOCtx _in_ctx(in); + return ((im = gdImageCreateFromWBMPCtx( & _in_ctx)) != 0); + } + + // Jpeg + /** + Load a truecolor image from a JPEG format file. + Invoke CreateFromJpeg with an already opened + pointer to a file containing the desired image. + CreateFromJpeg does not close the file. + \return true for success, or false if unable to load the image (most often because + the file is corrupt or does not contain a JPEG image). + You can call Width() and Height() member functions of the image to determine its + size. The returned image is always a truecolor image. + */ + bool CreateFromJpeg(FILE * in) { + clear(); + return ((im = gdImageCreateFromJpeg(in)) != 0); + } + /** + Load a truecolor image from a JPEG format file. + Invoke CreateFromJpeg with an already opened + pointer to a file containing the desired image. + CreateFromJpeg does not close the file. + \return true for success, or false if unable to load the image (most often because the file is corrupt or does not contain a JPEG image). + You can call Width() and Height() member functions of the image to determine its + size. The returned image is always a truecolor image. + */ + bool CreateFromJpeg(gdIOCtxPtr in) { + clear(); + return ((im = gdImageCreateFromJpegCtx(in)) != 0); + } + /** + Load a truecolor image from a JPEG format file. + Invoke CreateFromJpeg with an already opened + pointer to a file containing the desired image. + CreateFromJpeg does not close the file. + \return true for success, or false if unable to load the image (most often because the file is corrupt or does not contain a JPEG image). + You can call Width() and Height() member functions of the image to determine its + size. The returned image is always a truecolor image. + */ + bool CreateFromJpeg(int size, void * data) { + clear(); + return ((im = gdImageCreateFromJpegPtr(size, data)) != 0); + } + /** + Load a truecolor image from a JPEG format file. + Invoke CreateFromJpeg with an image file in memory. + \return true for success, or false if unable to load the image (most often because the format is corrupt or does not contain a JPEG image). + You can call Width() and Height() member functions of the image to determine its + size. The returned image is always a truecolor image. + */ + bool CreateFromJpeg(std::istream & in) { + clear(); + istreamIOCtx _in_ctx(in); + return ((im = gdImageCreateFromJpegCtx( & _in_ctx)) != 0); + } + + // Gd + bool CreateFromGd(FILE * in) { + clear(); + return ((im = gdImageCreateFromGd(in)) != 0); + } + bool CreateFromGd(gdIOCtxPtr in) { + clear(); + return ((im = gdImageCreateFromGdCtx(in)) != 0); + } + bool CreateFromGd(int size, void * data) { + clear(); + return ((im = gdImageCreateFromGdPtr(size, data)) != 0); + } + bool CreateFromGd(std::istream & in) { + clear(); + istreamIOCtx _in_ctx(in); + return ((im = gdImageCreateFromGdCtx( & _in_ctx)) != 0); + } + // Gd2 + bool CreateFromGd2(FILE * in) { + clear(); + return ((im = gdImageCreateFromGd2(in)) != 0); + } + bool CreateFromGd2(gdIOCtxPtr in) { + clear(); + return ((im = gdImageCreateFromGd2Ctx(in)) != 0); + } + bool CreateFromGd2(int size, void * data) { + clear(); + return ((im = gdImageCreateFromGd2Ptr(size, data)) != 0); + } + bool CreateFromGd2(std::istream & in) { + clear(); + istreamIOCtx _in_ctx(in); + return ((im = gdImageCreateFromGd2Ctx( & _in_ctx)) != 0); + } + // Gd2 Part + bool CreateFromGd2Part(FILE * in, int srcx, int srcy, int w, int h) { + clear(); + return ((im = gdImageCreateFromGd2Part(in, srcx, srcy, w, h)) != 0); + } + bool CreateFromGd2Part(gdIOCtxPtr in, int srcx, int srcy, int w, int h) { + clear(); + return ((im = gdImageCreateFromGd2PartCtx(in, srcx, srcy, w, h)) != 0); + } + bool CreateFromGd2Part(int size, void * data, int srcx, int srcy, int w, int h) { + clear(); + return ((im = gdImageCreateFromGd2PartPtr(size, data, srcx, srcy, w, h)) != 0); + } + bool CreateFromGd2Part(std::istream & in, int srcx, int srcy, int w, int h) { + clear(); + istreamIOCtx _in_ctx(in); + return ((im = gdImageCreateFromGd2PartCtx( & _in_ctx, srcx, srcy, w, h)) != 0); + } + bool CreateFromGd2Part(FILE * in, const Point & src, const Size & s) { + return CreateFromGd2Part(in, src.X(), src.Y(), s.W(), s.H()); + } + bool CreateFromGd2Part(gdIOCtxPtr in, const Point & src, const Size & s) { + return CreateFromGd2Part(in, src.X(), src.Y(), s.W(), s.H()); + } + bool CreateFromGd2Part(int size, void * data, const Point & src, const Size & s) { + return CreateFromGd2Part(size, data, src.X(), src.Y(), s.W(), s.H()); + } + bool CreateFromGd2Part(std::istream & in, const Point & src, const Size & s) { + return CreateFromGd2Part(in, src.X(), src.Y(), s.W(), s.H()); + } + // Xbm + bool CreateFromXbm(FILE * in) { + clear(); + return ((im = gdImageCreateFromXbm(in)) != 0); + } + // Xpm + bool CreateFromXpm(char * filename) { + clear(); + return ((im = gdImageCreateFromXpm(filename)) != 0); + } + bool CreateFromXpm(std::string & filename) { + return CreateFromXpm((char *)(filename.c_str())); + } + + // Accessors, Updaters & Methods: + void SetPixel(int x, int y, int color) { + gdImageSetPixel(im, x, y, color); + } + void SetPixel(const Point & p, int color) { + SetPixel(p.X(), p.Y(), color); + } + int GetPixel(int x, int y) const { + return gdImageGetPixel(im, x, y); + } + int GetPixel(const Point & p) const { + return GetPixel(p.X(), p.Y()); + } + int GetTrueColorPixel(int x, int y) const { + return gdImageGetTrueColorPixel(im, x, y); + } + int GetTrueColorPixel(const Point & p) const { + return GetTrueColorPixel(p.X(), p.Y()); + } + + void SetPixel(int x, int y, TrueColor c) { + SetPixel(x, y, c.Int()); + } + void SetPixel(const Point & p, TrueColor c) { + SetPixel(p.X(), p.Y(), c.Int()); + } + void GetTrueColorPixel(TrueColor & c, int x, int y) const { + c.set(GetTrueColorPixel(x, y)); + } + void GetTrueColorPixel(TrueColor & c, const Point & p) const { + c.set(GetTrueColorPixel(p.X(), p.Y())); + } + + void AABlend() { + gdImageAABlend(im); + } + + void Line(int x1, int y1, int x2, int y2, int color) { + gdImageLine(im, x1, y1, x2, y2, color); + } + void Line(const Point & p1, const Point & p2, int color) { + Line(p1.X(), p1.Y(), p2.X(), p2.Y(), color); + } + void Rectangle(int x1, int y1, int x2, int y2, int color) { + gdImageRectangle(im, x1, y1, x2, y2, color); + } + void Rectangle(const Point & p1, const Point & p2, int color) { + Rectangle(p1.X(), p1.Y(), p2.X(), p2.Y(), color); + } + void Rectangle(const Point & p, const Size & s, int color) { + Rectangle(p.X(), p.Y(), p.X() + s.W(), p.Y() + s.H(), color); + } + void FilledRectangle(int x1, int y1, int x2, int y2, int color) { + gdImageFilledRectangle(im, x1, y1, x2, y2, color); + } + void FilledRectangle(const Point & p1, const Point & p2, int color) { + FilledRectangle(p1.X(), p1.Y(), p2.X(), p2.Y(), color); + } + void FilledRectangle(const Point & p, const Size & s, int color) { + FilledRectangle(p.X(), p.Y(), p.X() + s.W(), p.Y() + s.H(), color); + } + + void SetClip(int x1, int y1, int x2, int y2) { + gdImageSetClip(im, x1, y1, x2, y2); + } + void SetClip(const Point & p1, const Point & p2) { + SetClip(p1.X(), p1.Y(), p2.X(), p2.Y()); + } + void SetClip(const Point & p, const Size & s) { + SetClip(p.X(), p.Y(), p.X() + s.W(), p.Y() + s.H()); + } + void GetClip(int & x1, int & y1, int & x2, int & y2) const { + gdImageGetClip(im, & x1, & y1, & x2, & y2); + } + void GetClip(Point & p1, Point & p2) const { + GetClip(p1.lhsX(), p1.lhsY(), p2.lhsX(), p2.lhsY()); + } + void GetClip(Point & p, Size & s) const { + Point p2; + GetClip(p.lhsX(), p.lhsY(), p2.lhsX(), p2.lhsY()); + s.set(p2.X() - p.X(), p2.Y() - p.Y()); + } + + bool BoundsSafe(int x, int y) const { + return (gdImageBoundsSafe(im, x, y)?true:false); + } + bool BoundsSafe(const Point & p) const { + return BoundsSafe(p.X(), p.Y()); + } + + void Char(gdFontPtr f, int x, int y, int c, int color) { + gdImageChar(im, f, x, y, c, color); + } + void CharUp(gdFontPtr f, int x, int y, int c, int color) { + gdImageCharUp(im, f, x, y, c, color); + } + + void Char(gdFontPtr f, const Point & p, int c, int color) { + Char(f, p.X(), p.Y(), c, color); + } + void CharUp(gdFontPtr f, const Point & p, int c, int color) { + CharUp(f, p.X(), p.Y(), c, color); + } + + void String(gdFontPtr f, int x, int y, unsigned char * s, int color) { + gdImageString(im, f, x, y, (unsigned char *)s, color); + } + void StringUp(gdFontPtr f, int x, int y, unsigned char * s, int color) { + gdImageStringUp(im, f, x, y, (unsigned char *)s, color); + } + void String(gdFontPtr f, int x, int y, unsigned short * s, int color) { + gdImageString16(im, f, x, y, (unsigned short *)s, color); + } + void StringUp(gdFontPtr f, int x, int y, unsigned short * s, int color) { + gdImageStringUp16(im, f, x, y, (unsigned short *)s, color); + } + void String(gdFontPtr f, int x, int y, char * s, int color) { + gdImageString(im, f, x, y, (unsigned char *)s, color); + } + void StringUp(gdFontPtr f, int x, int y, char * s, int color) { + gdImageStringUp(im, f, x, y, (unsigned char *)s, color); + } + void String(gdFontPtr f, int x, int y, const std::string & s, int color) { + String(f, x, y, (char *)s.c_str(), color); + } + void StringUp(gdFontPtr f, int x, int y, const std::string & s, int color) { + StringUp(f, x, y, (char *)s.c_str(), color); + } + + void String(gdFontPtr f, const Point & p, unsigned char * s, int color) { + String(f, p.X(), p.Y(), (unsigned char *)s, color); + } + void StringUp(gdFontPtr f, const Point & p, unsigned char * s, int color) { + StringUp(f, p.X(), p.Y(), (unsigned char *)s, color); + } + void String(gdFontPtr f, const Point & p, unsigned short * s, int color) { + String(f, p.X(), p.Y(), (unsigned short *)s, color); + } + void StringUp(gdFontPtr f, const Point & p, unsigned short * s, int color) { + StringUp(f, p.X(), p.Y(), (unsigned short *)s, color); + } + void String(gdFontPtr f, const Point & p, char * s, int color) { + String(f, p.X(), p.Y(), (unsigned char *)s, color); + } + void StringUp(gdFontPtr f, const Point & p, char * s, int color) { + StringUp(f, p.X(), p.Y(), (unsigned char *)s, color); + } + void String(gdFontPtr f, const Point & p, const std::string & s, int color) { + String(f, p, (char *)s.c_str(), color); + } + void StringUp(gdFontPtr f, const Point & p, const std::string & s, int color) { + StringUp(f, p, (char *)s.c_str(), color); + } + + char * StringFT(int * brect, int fg, char * fontlist, double ptsize, double angle, + int x, int y, char * string) { + return gdImageStringFT(im, brect, fg, fontlist, ptsize, angle, x, y, string); + } + char * StringFT(int * brect, int fg, char * fontlist, double ptsize, double angle, + int x, int y, char * string, gdFTStringExtraPtr strex) { + return gdImageStringFTEx(im, brect, fg, fontlist, ptsize, angle, x, y, string, strex); + } + char * StringFT(int * brect, int fg, char * fontlist, double ptsize, double angle, + int x, int y, const std::string & string) { + return StringFT(brect, fg, fontlist, ptsize, angle, x, y, (char *)string.c_str()); + } + char * StringFT(int * brect, int fg, char * fontlist, double ptsize, double angle, + int x, int y, const std::string & string, gdFTStringExtraPtr strex) { + return StringFT(brect, fg, fontlist, ptsize, angle, x, y, (char *)string.c_str(), strex); + } + + char * StringFT(int * brect, int fg, char * fontlist, double ptsize, double angle, + const Point & p, char * string) { + return StringFT(brect, fg, fontlist, ptsize, angle, p.X(), p.Y(), string); + } + char * StringFT(int * brect, int fg, char * fontlist, double ptsize, double angle, + const Point & p, char * string, gdFTStringExtraPtr strex) { + return StringFT(brect, fg, fontlist, ptsize, angle, p.X(), p.Y(), string, strex); + } + char * StringFT(int * brect, int fg, char * fontlist, double ptsize, double angle, + const Point & p, const std::string & string) { + return StringFT(brect, fg, fontlist, ptsize, angle, p, (char *)string.c_str()); + } + char * StringFT(int * brect, int fg, char * fontlist, double ptsize, double angle, + const Point & p, const std::string & string, gdFTStringExtraPtr strex) { + return StringFT(brect, fg, fontlist, ptsize, angle, p, (char *)string.c_str(), strex); + } + + void Polygon(gdPointPtr p, int n, int c) { + gdImagePolygon(im, p, n, c); + } + void OpenPolygon(gdPointPtr p, int n, int c) { + gdImageOpenPolygon(im, p, n, c); + } + void FilledPolygon(gdPointPtr p, int n, int c) { + gdImageFilledPolygon(im, p, n, c); + } + + void Polygon(PointPtr p, int n, int c) { + Polygon(p->as_gdPointPtr(), n, c); + } + void OpenPolygon(PointPtr p, int n, int c) { + OpenPolygon(p->as_gdPointPtr(), n, c); + } + void FilledPolygon(PointPtr p, int n, int c) { + FilledPolygon(p->as_gdPointPtr(), n, c); + } + + int ColorAllocate(int r, int g, int b) { + return gdImageColorAllocate(im, r, g, b); + } + int ColorAllocate(int r, int g, int b, int a) { + return gdImageColorAllocateAlpha(im, r, g, b, a); + } + + int ColorClosest(int r, int g, int b) const { + return gdImageColorClosest(im, r, g, b); + } + int ColorClosest(int r, int g, int b, int a) const { + return gdImageColorClosestAlpha(im, r, g, b, a); + } + int ColorClosestHWB(int r, int g, int b) const { + return gdImageColorClosestHWB(im, r, g, b); + } + int ColorExact(int r, int g, int b) const { + return gdImageColorExact(im, r, g, b); + } + int ColorExact(int r, int g, int b, int a) const { + return gdImageColorExactAlpha(im, r, g, b, a); + } + int ColorResolve(int r, int g, int b) { + return gdImageColorResolve(im, r, g, b); + } + int ColorResolve(int r, int g, int b, int a) { + return gdImageColorResolveAlpha(im, r, g, b, a); + } + + void ColorDeallocate(int color) { + gdImageColorDeallocate(im, color); + } + + void TrueColorToPalette(int ditherFlag, int colorsWanted) { + gdImageTrueColorToPalette(im, ditherFlag, colorsWanted); + } + + void ColorTransparent(int color) { + gdImageColorTransparent(im, color); + } + + void PaletteCopy(gdImagePtr src) { + gdImagePaletteCopy(im, src); + } + void PaletteCopy(const GD::Image & src) { + PaletteCopy(src.im); + } + + /** + Write out this image in GIF file format to \p out. + \param out A FILE * handle + */ + void Gif(FILE * out) const { + gdImageGif(im, out); + } + /** + Write out this image in GIF file format to \p out. + \param out A gdIOCtxPtr handle + */ + void Gif(gdIOCtxPtr out) const { + gdImageGifCtx(im, out); + } + /** + Allocate sufficient memory, and write this image, in GIF file format, to that memory. + \param size A pointer for the allocated memory + \return A pointer to the allocated memory, containing the image GIF file formatted. Caller is responsible for freeing with gdFree(). + */ + void * Gif(int * size) const { + return gdImageGifPtr(im, size); + } + /** + Write out this image in GIF file format to \p out. + \param out An output stream, already opened. + */ + void Gif(std::ostream & out) const { + ostreamIOCtx _out_ctx(out); + gdImageGifCtx(im, & _out_ctx); + } + + /** + Write out this image in PNG file format to \p out. + \param out A FILE * handle + */ + void Png(FILE * out) const { + gdImagePng(im, out); + } + /** + Write out this image in PNG file format to \p out. + \param out A gdIOCtxPtr handle + */ + void Png(gdIOCtxPtr out) const { + gdImagePngCtx(im, out); + } + /** + Allocate sufficient memory, and write this image, in PNG file format, to that memory. + \param size A pointer for the allocated memory + \return A pointer to the allocated memory, containing the image PNG file formatted. Caller is responsible for freeing with gdFree(). + */ + void * Png(int * size) const { + return gdImagePngPtr(im, size); + } + /** + Write out this image in PNG file format to \p out. + \param out An output stream, already opened. + */ + void Png(std::ostream & out) const { + ostreamIOCtx _out_ctx(out); + gdImagePngCtx(im, & _out_ctx); + } + /** + Write out this image in PNG file format to \p out. + \param out A FILE * handle + \param level The level of compression: 0 == "no compression", 1 == "compressed as quickly as possible" --> 9 == "compressed as much as possible", -1 == zlib default compression level + */ + void Png(FILE * out, int level) const { + gdImagePngEx(im, out, level); + } + /** + Write out this image in PNG file format to \p out. + \param out A gdIOCtxPtr handle + \param level The level of compression: 0 == "no compression", 1 == "compressed as quickly as possible" --> 9 == "compressed as much as possible", -1 == zlib default compression level + */ + void Png(gdIOCtxPtr out, int level) const { + gdImagePngCtxEx(im, out, level); + } + /** + Allocate sufficient memory, and write this image, in PNG file format, to that memory. + \param size A pointer for the allocated memory + \param level The level of compression: 0 == "no compression", 1 == "compressed as quickly as possible" --> 9 == "compressed as much as possible", -1 == zlib default compression level + \return A pointer to the allocated memory, containing the image PNG file formatted. Caller is responsible for freeing with gdFree(). + */ + void * Png(int * size, int level) const { + return gdImagePngPtrEx(im, size, level); + } + /** + Write out this image in PNG file format to \p out. + \param out An output stream, already opened. + \param level The level of compression: 0 == "no compression", 1 == "compressed as quickly as possible" --> 9 == "compressed as much as possible", -1 == zlib default compression level + */ + void Png(std::ostream & out, int level) const { + ostreamIOCtx _out_ctx(out); + gdImagePngCtxEx(im, & _out_ctx, level); + } + + /** + Write out this image in WBMP file format ( black and white only ) to \p out. + \param fg The color index of the foreground. All other pixels considered background. + \param out A FILE * handle + */ + void WBMP(int fg, FILE * out) const { + gdImageWBMP(im, fg, out); + } + /** + Write out this image in WBMP file format ( black and white only ) to \p out. + \param fg The color index of the foreground. All other pixels considered background. + \param out A gdIOCtxPtr handle + */ + void WBMP(int fg, gdIOCtxPtr out) const { + gdImageWBMPCtx(im, fg, out); + } + /** + Allocate sufficient memory, and write this image, in WBMP file format ( black and white only ), to that memory. + \param size A pointer for the allocated memory + \param fg The color index of the foreground. All other pixels considered background. + \return A pointer to the allocated memory, containing the image WBMP file formatted. Caller is responsible for freeing with gdFree(). + */ + void * WBMP(int * size, int fg) const { + return gdImageWBMPPtr(im, size, fg); + } + /** + Write out this image in WBMP file format ( black and white only ) to \p out. + \param fg The color index of the foreground. All other pixels considered background. + \param out An output stream, already opened. + */ + void WBMP(int fg, std::ostream & out) const { + ostreamIOCtx _out_ctx(out); + gdImageWBMPCtx(im, fg, & _out_ctx); + } + + /** + Write out this image in JPEG file format to \p out. + \param out A FILE * handle + \param quality Should be a value in the range 0-95, higher numbers imply both higher quality and larger image size. Default value is -1, indicating "use a sensible default value". + */ + void Jpeg(FILE * out, int quality = -1) const { + gdImageJpeg(im, out, quality); + } + /** + Write out this image in JPEG file format to \p out. + \param out A gdIOCtxPtr handle + \param quality Should be a value in the range 0-95, higher numbers imply both higher quality and larger image size. Default value is -1, indicating "use a sensible default value". + */ + void Jpeg(gdIOCtxPtr out, int quality = -1) const { + gdImageJpegCtx(im, out, quality); + } + /** + Allocate sufficient memory, and write this image, in JPEG file format, to that memory. + \param size A pointer for the allocated memory + \param quality Should be a value in the range 0-95, higher numbers imply both higher quality and larger image size. Default value is -1, indicating "use a sensible default value". + \return A pointer to the allocated memory, containing the image JPEG file formatted. Caller is responsible for freeing with gdFree(). + */ + void * Jpeg(int * size, int quality = -1) const { + return gdImageJpegPtr(im, size, quality); + } + /** + Write out this image in JPEG file format to \p out. + \param out An output stream, already opened. + \param quality Should be a value in the range 0-95, higher numbers imply both higher quality and larger image size. Default value is -1, indicating "use a sensible default value". + */ + void Jpeg(std::ostream & out, int quality = -1) const { + ostreamIOCtx _out_ctx(out); + gdImageJpegCtx(im, & _out_ctx, quality); + } + + void GifAnimBegin(FILE * out, int GlobalCM, int Loops) const { + gdImageGifAnimBegin(im, out, GlobalCM, Loops); + } + void GifAnimAdd(FILE * out, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm) const { + gdImageGifAnimAdd(im, out, LocalCM, LeftOfs, TopOfs, Delay, Disposal, previm); + } + void GifAnimAdd(FILE * out, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, const GD::Image & previm) const { + GifAnimAdd(out, LocalCM, LeftOfs, TopOfs, Delay, Disposal, previm.im); + } + inline static void GifAnimEnd(FILE * out) { + gdImageGifAnimEnd(out); + } + void GifAnimBegin(gdIOCtxPtr out, int GlobalCM, int Loops) const { + gdImageGifAnimBeginCtx(im, out, GlobalCM, Loops); + } + void GifAnimAdd(gdIOCtxPtr out, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm) const { + gdImageGifAnimAddCtx(im, out, LocalCM, LeftOfs, TopOfs, Delay, Disposal, previm); + } + void GifAnimAdd(gdIOCtxPtr out, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, const GD::Image & previm) const { + GifAnimAdd(out, LocalCM, LeftOfs, TopOfs, Delay, Disposal, previm.im); + } + inline static void GifAnimEnd(gdIOCtxPtr out) { + gdImageGifAnimEndCtx(out); + } + void * GifAnimBegin(int * size, int GlobalCM, int Loops) const { + return gdImageGifAnimBeginPtr(im, size, GlobalCM, Loops); + } + void * GifAnimAdd(int * size, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, gdImagePtr previm) const { + return gdImageGifAnimAddPtr(im, size, LocalCM, LeftOfs, TopOfs, Delay, Disposal, previm); + } + void * GifAnimAdd(int * size, int LocalCM, int LeftOfs, int TopOfs, int Delay, int Disposal, const GD::Image & previm) const { + return GifAnimAdd(size, LocalCM, LeftOfs, TopOfs, Delay, Disposal, previm.im); + } + inline static void * GifAnimEnd(int * size) { + return gdImageGifAnimEndPtr(size); + } + + void Gd(FILE * out) const { + gdImageGd(im, out); + } + void* Gd(int * size) const { + return gdImageGdPtr(im, size); + } + void Gd2(FILE * out, int cs, int fmt) const { + gdImageGd2(im, out, cs, fmt); + } + void* Gd2(int cs, int fmt, int * size) const { + return gdImageGd2Ptr(im, cs, fmt, size); + } + + void Ellipse(int cx, int cy, int w, int h, int color) { + gdImageEllipse(im, cx, cy, w, h, color); + } + /** + Draw a partial ellipse centered at the given point, with the specified width and height in pixels. + */ + void FilledArc(int cx, int cy, int w, int h, int s, int e, int color, int style) { + gdImageFilledArc(im, cx, cy, w, h, s, e, color, style); + } + void Arc(int cx, int cy, int w, int h, int s, int e, int color) { + gdImageArc(im, cx, cy, w, h, s, e, color); + } + void FilledEllipse(int cx, int cy, int w, int h, int color) { + gdImageFilledEllipse(im, cx, cy, w, h, color); + } + void FillToBorder(int x, int y, int border, int color) { + gdImageFillToBorder(im, x, y, border, color); + } + void Fill(int x, int y, int color) { + gdImageFill(im, x, y, color); + } + + void Ellipse(const Point & c, const Size & s, int color) { + Ellipse(c.X(), c.Y(), s.W(), s.H(), color); + } + void FilledArc(const Point & c, const Size & si, int s, int e, int color, int style) { + FilledArc(c.X(), c.Y(), si.W(), si.H(), s, e, color, style); + } + void Arc(const Point & c, const Size & si, int s, int e, int color) { + Arc(c.X(), c.Y(), si.W(), si.H(), s, e, color); + } + void FilledEllipse(const Point & c, const Size & s, int color) { + FilledEllipse(c.X(), c.Y(), s.W(), s.H(), color); + } + void FillToBorder(const Point & p, int border, int color) { + FillToBorder(p.X(), p.Y(), border, color); + } + void Fill(const Point & p, int color) { + Fill(p.X(), p.Y(), color); + } + + void Copy(const gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h) { + gdImageCopy(im, src, dstX, dstY, srcX, srcY, w, h); + } + void CopyMerge(const gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct) { + gdImageCopyMerge(im, src, dstX, dstY, srcX, srcY, w, h, pct); + } + void CopyMergeGray(const gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct) { + gdImageCopyMergeGray(im, src, dstX, dstY, srcX, srcY, w, h, pct); + } + + void CopyResized(const gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH) { + gdImageCopyResized(im, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH); + } + void CopyResampled(const gdImagePtr src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH) { + gdImageCopyResampled(im, src, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH); + } + void CopyRotated(const gdImagePtr src, double dstX, double dstY, int srcX, int srcY, int srcWidth, int srcHeight, int angle) { + gdImageCopyRotated(im, src, dstX, dstY, srcX, srcY, srcWidth, srcHeight, angle); + } + + Image * CopyGaussianBlurred(int radius, double sigma) { + return new Image(gdImageCopyGaussianBlurred(im, radius, sigma)); + } + + void Copy(const gdImagePtr src, const Point & dstP, const Point & srcP, const Size & s) { + Copy(src, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), s.W(), s.H()); + } + void CopyMerge(const gdImagePtr src, const Point & dstP, const Point & srcP, const Size & s, int pct) { + CopyMerge(src, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), s.W(), s.H(), pct); + } + void CopyMergeGray(const gdImagePtr src, const Point & dstP, const Point & srcP, const Size & s, int pct) { + CopyMergeGray(src, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), s.W(), s.H(), pct); + } + + void CopyResized(const gdImagePtr src, const Point & dstP, const Point & srcP, const Size & dstS, const Size & srcS) { + CopyResized(src, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), dstS.W(), dstS.H(), srcS.W(), srcS.H()); + } + void CopyResampled(const gdImagePtr src, const Point & dstP, const Point & srcP, const Size & dstS, const Size & srcS) { + CopyResampled(src, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), dstS.W(), dstS.H(), srcS.W(), srcS.H()); + } + void CopyRotated(const gdImagePtr src, double dstX, double dstY, const Point & srcP, const Size & srcS, int angle) { + CopyRotated(src, dstX, dstY, srcP.X(), srcP.Y(), srcS.W(), srcS.H(), angle); + } + + void Copy(const GD::Image & src, int dstX, int dstY, int srcX, int srcY, int w, int h) { + Copy(src.im, dstX, dstY, srcX, srcY, w, h); + } + void CopyMerge(const GD::Image & src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct) { + CopyMerge(src.im, dstX, dstY, srcX, srcY, w, h, pct); + } + void CopyMergeGray(const GD::Image & src, int dstX, int dstY, int srcX, int srcY, int w, int h, int pct) { + CopyMergeGray(src.im, dstX, dstY, srcX, srcY, w, h, pct); + } + + void CopyResized(const GD::Image & src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH) { + CopyResized(src.im, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH); + } + void CopyResampled(const GD::Image & src, int dstX, int dstY, int srcX, int srcY, int dstW, int dstH, int srcW, int srcH) { + CopyResampled(src.im, dstX, dstY, srcX, srcY, dstW, dstH, srcW, srcH); + } + void CopyRotated(const GD::Image & src, double dstX, double dstY, int srcX, int srcY, int srcWidth, int srcHeight, int angle) { + CopyRotated(src.im, dstX, dstY, srcX, srcY, srcWidth, srcHeight, angle); + } + + void Copy(const GD::Image & src, const Point & dstP, const Point & srcP, const Size & s) { + Copy(src.im, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), s.W(), s.H()); + } + void CopyMerge(const GD::Image & src, const Point & dstP, const Point & srcP, const Size & s, int pct) { + CopyMerge(src.im, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), s.W(), s.H(), pct); + } + void CopyMergeGray(const GD::Image & src, const Point & dstP, const Point & srcP, const Size & s, int pct) { + CopyMergeGray(src.im, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), s.W(), s.H(), pct); + } + + void CopyResized(const GD::Image & src, const Point & dstP, const Point & srcP, const Size & dstS, const Size & srcS) { + CopyResized(src.im, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), dstS.W(), dstS.H(), srcS.W(), srcS.H()); + } + void CopyResampled(const GD::Image & src, const Point & dstP, const Point & srcP, const Size & dstS, const Size & srcS) { + CopyResampled(src.im, dstP.X(), dstP.Y(), srcP.X(), srcP.Y(), dstS.W(), dstS.H(), srcS.W(), srcS.H()); + } + void CopyRotated(const GD::Image & src, double dstX, double dstY, const Point & srcP, const Size & srcS, int angle) { + CopyRotated(src.im, dstX, dstY, srcP.X(), srcP.Y(), srcS.W(), srcS.H(), angle); + } + + Image * Clone() { + return new Image(gdImageClone(im)); + } + + void SetBrush(gdImagePtr brush) { + gdImageSetBrush(im, brush); + } + void SetBrush(const GD::Image & brush) { + SetBrush(brush.im); + } + void SetTile(gdImagePtr tile) { + gdImageSetTile(im, tile); + } + void SetTile(const GD::Image & tile) { + SetTile(tile.im); + } + void SetAntiAliased(int c) { + gdImageSetAntiAliased(im, c); + } + void SetAntiAliasedDontBlend(int c, int dont_blend) { + gdImageSetAntiAliasedDontBlend(im, c, dont_blend); + } + void SetStyle(int * style, int noOfPixels) { + gdImageSetStyle(im, style, noOfPixels); + } + void SetThickness(int thickness) { + gdImageSetThickness(im, thickness); + } + void SetResolution(int res_x, int res_y) { + gdImageSetResolution(im, res_x, res_y); + } + void SetInterpolationMethod(gdInterpolationMethod interpolation_method) { + gdImageSetInterpolationMethod(im, interpolation_method); + } + + Image * RotateInterpolated(const float angle, int bgcolor) { + return new Image(gdImageRotateInterpolated(im, angle, bgcolor)); + } + + void Interlace(bool interlaceArg) { + gdImageInterlace(im, interlaceArg?1:0); + } + void AlphaBlending(bool alphaBlendingArg) { + gdImageAlphaBlending(im, alphaBlendingArg?1:0); + } + void SaveAlpha(bool saveAlphaArg) { + gdImageSaveAlpha(im, saveAlphaArg?1:0); + } + + int ColorReplace(int src, int dst) { + return gdImageColorReplace(im, src, dst); + } + int ColorReplaceArray(int len, int * src, int * dst) { + return gdImageColorReplaceArray(im, len, src, dst); + } + int ColorReplaceCallback(gdCallbackImageColor callback) { + return gdImageColorReplaceCallback(im, callback); + } + int ColorReplaceThreshold(int src, int dst, float threshold) { + return gdImageColorReplaceThreshold(im, src, dst, threshold); + } + + bool Pixelate(int block_size, gdPixelateMode mode) { + return gdImagePixelate(im, block_size, mode) == 0 ? false : true; + } + + Image * Scale(int new_width, int new_height) { + return new Image(gdImageScale(im, new_width, new_height)); + } + + bool IsTrueColor() const { + return (gdImageTrueColor(im)?true:false); + } + int SX() const { + return gdImageSX(im); + } + int SY() const { + return gdImageSY(im); + } + int Width() const { + return SX(); + } + int Height() const { + return SY(); + } + int ResX() const { + return gdImageResolutionX(im); + } + int ResY() const { + return gdImageResolutionY(im); + } + void GetSize(Size & s) const { + s.set(SX(), SY()); + } + int ColorsTotal() const { + return gdImageColorsTotal(im); + } + int Red(int color) const { + return gdImageRed(im, color); + } + int Green(int color) const { + return gdImageGreen(im, color); + } + int Blue(int color) const { + return gdImageBlue(im, color); + } + int Alpha(int color) const { + return gdImageAlpha(im, color); + } + int GetTransparent() const { + return gdImageGetTransparent(im); + } + int GetInterlaced() const { + return gdImageGetInterlaced(im); + } + int PalettePixel(int x, int y) const { + return gdImagePalettePixel(im, x, y); + } + int TrueColorPixel(int x, int y) const { + return gdImageTrueColorPixel(im, x, y); + } + + const gdImagePtr GetPtr() const { + return im; + } + +protected: + /// Free the internal image pointer + void clear() { + if (im) + gdImageDestroy(im); + im = 0; + } + gdImagePtr im; +}; +} // namespace GD +/// Read in an image from a standard library input stream +std::istream & operator>> (std::istream & in, GD::Image & img); + +#endif /* __cplusplus */ +#endif /* _gdpp_h */ diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/jisx0208.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/jisx0208.h new file mode 100644 index 0000000000..118c23e0aa --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/jisx0208.h @@ -0,0 +1,1306 @@ +#ifndef JISX0208_H +#define JISX0208_H +#ifdef __cplusplus +extern "C" { +#endif + + /* This file was derived from "src/VF_Ftype.c" in VFlib2-2.24.2 + by Dr. Kakugawa */ + + /* JIS -> Unicode mapping table */ + static const unsigned short UnicodeTbl[][94] = { + { /* category 01 */ + 0x0000, 0x3001, 0x3002, 0xFF0C, 0xFF0E, 0x30FB, 0xFF1A, 0xFF1B, + 0xFF1F, 0xFF01, 0x309B, 0x309C, 0x00B4, 0xFF40, 0x00A8, 0xFF3E, + 0xFFE3, 0xFF3F, 0x30FD, 0x30FE, 0x309D, 0x309E, 0x3003, 0x4EDD, + 0x3005, 0x3006, 0x3007, 0x30FC, 0x2015, 0x2010, 0xFF0F, 0xFF3C, + 0xFF5E, 0x2225, 0xFF5C, 0x2026, 0x2025, 0x2018, 0x2019, 0x201C, + 0x201D, 0xFF08, 0xFF09, 0x3014, 0x3015, 0xFF3B, 0xFF3D, 0xFF5B, + 0xFF5D, 0x3008, 0x3009, 0x300A, 0x300B, 0x300C, 0x300D, 0x300E, + 0x300F, 0x3010, 0x3011, 0xFF0B, 0xFF0D, 0x00B1, 0x00D7, 0x00F7, + 0xFF1D, 0x2260, 0xFF1C, 0xFF1E, 0x2266, 0x2267, 0x221E, 0x2234, + 0x2642, 0x2640, 0x00B0, 0x2032, 0x2033, 0x2103, 0xFFE5, 0xFF04, + 0xFFE0, 0xFFE1, 0xFF05, 0xFF03, 0xFF06, 0xFF0A, 0xFF20, 0x00A7, + 0x2606, 0x2605, 0x25CB, 0x25CF, 0x25CE, 0x25C7 + }, + { /* category 02 */ + 0x25C6, 0x25A1, 0x25A0, 0x25B3, 0x25B2, 0x25BD, 0x25BC, 0x203B, + 0x3012, 0x2192, 0x2190, 0x2191, 0x2193, 0x3013, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2208, 0x220B, 0x2286, 0x2287, 0x2282, 0x2283, 0x222A, + 0x2229, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2227, 0x2228, 0xFFE2, 0x21D2, 0x21D4, 0x2200, 0x2203, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x2220, 0x22A5, 0x2312, 0x2202, 0x2207, + 0x2261, 0x2252, 0x226A, 0x226B, 0x221A, 0x223D, 0x221D, 0x2235, + 0x222B, 0x222C, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x212B, 0x2030, 0x266F, 0x266D, 0x266A, 0x2020, 0x2021, /**/ + 0x00B6, 0x0000, 0x0000, 0x0000, 0x0000, 0x25EF + }, + { /* category 03 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFF10, + 0xFF11, 0xFF12, 0xFF13, 0xFF14, 0xFF15, 0xFF16, 0xFF17, 0xFF18, + 0xFF19, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xFF21, 0xFF22, 0xFF23, 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28, + 0xFF29, 0xFF2A, 0xFF2B, 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F, 0xFF30, + 0xFF31, 0xFF32, 0xFF33, 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, + 0xFF39, 0xFF3A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0xFF41, 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, + 0xFF49, 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, 0xFF50, + 0xFF51, 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, + 0xFF59, 0xFF5A, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 04 */ + 0x3041, 0x3042, 0x3043, 0x3044, 0x3045, 0x3046, 0x3047, 0x3048, + 0x3049, 0x304A, 0x304B, 0x304C, 0x304D, 0x304E, 0x304F, 0x3050, + 0x3051, 0x3052, 0x3053, 0x3054, 0x3055, 0x3056, 0x3057, 0x3058, + 0x3059, 0x305A, 0x305B, 0x305C, 0x305D, 0x305E, 0x305F, 0x3060, + 0x3061, 0x3062, 0x3063, 0x3064, 0x3065, 0x3066, 0x3067, 0x3068, + 0x3069, 0x306A, 0x306B, 0x306C, 0x306D, 0x306E, 0x306F, 0x3070, + 0x3071, 0x3072, 0x3073, 0x3074, 0x3075, 0x3076, 0x3077, 0x3078, + 0x3079, 0x307A, 0x307B, 0x307C, 0x307D, 0x307E, 0x307F, 0x3080, + 0x3081, 0x3082, 0x3083, 0x3084, 0x3085, 0x3086, 0x3087, 0x3088, + 0x3089, 0x308A, 0x308B, 0x308C, 0x308D, 0x308E, 0x308F, 0x3090, + 0x3091, 0x3092, 0x3093, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 05 */ + 0x30A1, 0x30A2, 0x30A3, 0x30A4, 0x30A5, 0x30A6, 0x30A7, 0x30A8, + 0x30A9, 0x30AA, 0x30AB, 0x30AC, 0x30AD, 0x30AE, 0x30AF, 0x30B0, + 0x30B1, 0x30B2, 0x30B3, 0x30B4, 0x30B5, 0x30B6, 0x30B7, 0x30B8, + 0x30B9, 0x30BA, 0x30BB, 0x30BC, 0x30BD, 0x30BE, 0x30BF, 0x30C0, + 0x30C1, 0x30C2, 0x30C3, 0x30C4, 0x30C5, 0x30C6, 0x30C7, 0x30C8, + 0x30C9, 0x30CA, 0x30CB, 0x30CC, 0x30CD, 0x30CE, 0x30CF, 0x30D0, + 0x30D1, 0x30D2, 0x30D3, 0x30D4, 0x30D5, 0x30D6, 0x30D7, 0x30D8, + 0x30D9, 0x30DA, 0x30DB, 0x30DC, 0x30DD, 0x30DE, 0x30DF, 0x30E0, + 0x30E1, 0x30E2, 0x30E3, 0x30E4, 0x30E5, 0x30E6, 0x30E7, 0x30E8, + 0x30E9, 0x30EA, 0x30EB, 0x30EC, 0x30ED, 0x30EE, 0x30EF, 0x30F0, + 0x30F1, 0x30F2, 0x30F3, 0x30F4, 0x30F5, 0x30F6, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 06 */ + 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, + 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0, + 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8, + 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, + 0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8, 0x03C9, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 07 */ + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0401, 0x0416, + 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, + 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, + 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, + 0x042F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0451, 0x0436, + 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, + 0x043F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, + 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, + 0x044F, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 08 */ + 0x2500, 0x2502, 0x250C, 0x2510, 0x2518, 0x2514, 0x251C, 0x252C, + 0x2524, 0x2534, 0x253C, 0x2501, 0x2503, 0x250F, 0x2513, 0x251B, + 0x2517, 0x2523, 0x2533, 0x252B, 0x253B, 0x254B, 0x2520, 0x252F, + 0x2528, 0x2537, 0x253F, 0x251D, 0x2530, 0x2525, 0x2538, 0x2542, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 09 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 10 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 11 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 12 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 13 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 14 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 15 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 16 */ + 0x4E9C, 0x5516, 0x5A03, 0x963F, 0x54C0, 0x611B, 0x6328, 0x59F6, + 0x9022, 0x8475, 0x831C, 0x7A50, 0x60AA, 0x63E1, 0x6E25, 0x65ED, + 0x8466, 0x82A6, 0x9BF5, 0x6893, 0x5727, 0x65A1, 0x6271, 0x5B9B, + 0x59D0, 0x867B, 0x98F4, 0x7D62, 0x7DBE, 0x9B8E, 0x6216, 0x7C9F, + 0x88B7, 0x5B89, 0x5EB5, 0x6309, 0x6697, 0x6848, 0x95C7, 0x978D, + 0x674F, 0x4EE5, 0x4F0A, 0x4F4D, 0x4F9D, 0x5049, 0x56F2, 0x5937, + 0x59D4, 0x5A01, 0x5C09, 0x60DF, 0x610F, 0x6170, 0x6613, 0x6905, + 0x70BA, 0x754F, 0x7570, 0x79FB, 0x7DAD, 0x7DEF, 0x80C3, 0x840E, + 0x8863, 0x8B02, 0x9055, 0x907A, 0x533B, 0x4E95, 0x4EA5, 0x57DF, + 0x80B2, 0x90C1, 0x78EF, 0x4E00, 0x58F1, 0x6EA2, 0x9038, 0x7A32, + 0x8328, 0x828B, 0x9C2F, 0x5141, 0x5370, 0x54BD, 0x54E1, 0x56E0, + 0x59FB, 0x5F15, 0x98F2, 0x6DEB, 0x80E4, 0x852D + }, + { /* category 17 */ + 0x9662, 0x9670, 0x96A0, 0x97FB, 0x540B, 0x53F3, 0x5B87, 0x70CF, + 0x7FBD, 0x8FC2, 0x96E8, 0x536F, 0x9D5C, 0x7ABA, 0x4E11, 0x7893, + 0x81FC, 0x6E26, 0x5618, 0x5504, 0x6B1D, 0x851A, 0x9C3B, 0x59E5, + 0x53A9, 0x6D66, 0x74DC, 0x958F, 0x5642, 0x4E91, 0x904B, 0x96F2, + 0x834F, 0x990C, 0x53E1, 0x55B6, 0x5B30, 0x5F71, 0x6620, 0x66F3, + 0x6804, 0x6C38, 0x6CF3, 0x6D29, 0x745B, 0x76C8, 0x7A4E, 0x9834, + 0x82F1, 0x885B, 0x8A60, 0x92ED, 0x6DB2, 0x75AB, 0x76CA, 0x99C5, + 0x60A6, 0x8B01, 0x8D8A, 0x95B2, 0x698E, 0x53AD, 0x5186, 0x5712, + 0x5830, 0x5944, 0x5BB4, 0x5EF6, 0x6028, 0x63A9, 0x63F4, 0x6CBF, + 0x6F14, 0x708E, 0x7114, 0x7159, 0x71D5, 0x733F, 0x7E01, 0x8276, + 0x82D1, 0x8597, 0x9060, 0x925B, 0x9D1B, 0x5869, 0x65BC, 0x6C5A, + 0x7525, 0x51F9, 0x592E, 0x5965, 0x5F80, 0x5FDC + }, + { /* category 18 */ + 0x62BC, 0x65FA, 0x6A2A, 0x6B27, 0x6BB4, 0x738B, 0x7FC1, 0x8956, + 0x9D2C, 0x9D0E, 0x9EC4, 0x5CA1, 0x6C96, 0x837B, 0x5104, 0x5C4B, + 0x61B6, 0x81C6, 0x6876, 0x7261, 0x4E59, 0x4FFA, 0x5378, 0x6069, + 0x6E29, 0x7A4F, 0x97F3, 0x4E0B, 0x5316, 0x4EEE, 0x4F55, 0x4F3D, + 0x4FA1, 0x4F73, 0x52A0, 0x53EF, 0x5609, 0x590F, 0x5AC1, 0x5BB6, + 0x5BE1, 0x79D1, 0x6687, 0x679C, 0x67B6, 0x6B4C, 0x6CB3, 0x706B, + 0x73C2, 0x798D, 0x79BE, 0x7A3C, 0x7B87, 0x82B1, 0x82DB, 0x8304, + 0x8377, 0x83EF, 0x83D3, 0x8766, 0x8AB2, 0x5629, 0x8CA8, 0x8FE6, + 0x904E, 0x971E, 0x868A, 0x4FC4, 0x5CE8, 0x6211, 0x7259, 0x753B, + 0x81E5, 0x82BD, 0x86FE, 0x8CC0, 0x96C5, 0x9913, 0x99D5, 0x4ECB, + 0x4F1A, 0x89E3, 0x56DE, 0x584A, 0x58CA, 0x5EFB, 0x5FEB, 0x602A, + 0x6094, 0x6062, 0x61D0, 0x6212, 0x62D0, 0x6539 + }, + { /* category 19 */ + 0x9B41, 0x6666, 0x68B0, 0x6D77, 0x7070, 0x754C, 0x7686, 0x7D75, + 0x82A5, 0x87F9, 0x958B, 0x968E, 0x8C9D, 0x51F1, 0x52BE, 0x5916, + 0x54B3, 0x5BB3, 0x5D16, 0x6168, 0x6982, 0x6DAF, 0x788D, 0x84CB, + 0x8857, 0x8A72, 0x93A7, 0x9AB8, 0x6D6C, 0x99A8, 0x86D9, 0x57A3, + 0x67FF, 0x86CE, 0x920E, 0x5283, 0x5687, 0x5404, 0x5ED3, 0x62E1, + 0x64B9, 0x683C, 0x6838, 0x6BBB, 0x7372, 0x78BA, 0x7A6B, 0x899A, + 0x89D2, 0x8D6B, 0x8F03, 0x90ED, 0x95A3, 0x9694, 0x9769, 0x5B66, + 0x5CB3, 0x697D, 0x984D, 0x984E, 0x639B, 0x7B20, 0x6A2B, 0x6A7F, + 0x68B6, 0x9C0D, 0x6F5F, 0x5272, 0x559D, 0x6070, 0x62EC, 0x6D3B, + 0x6E07, 0x6ED1, 0x845B, 0x8910, 0x8F44, 0x4E14, 0x9C39, 0x53F6, + 0x691B, 0x6A3A, 0x9784, 0x682A, 0x515C, 0x7AC3, 0x84B2, 0x91DC, + 0x938C, 0x565B, 0x9D28, 0x6822, 0x8305, 0x8431 + }, + { /* category 20 */ + 0x7CA5, 0x5208, 0x82C5, 0x74E6, 0x4E7E, 0x4F83, 0x51A0, 0x5BD2, + 0x520A, 0x52D8, 0x52E7, 0x5DFB, 0x559A, 0x582A, 0x59E6, 0x5B8C, + 0x5B98, 0x5BDB, 0x5E72, 0x5E79, 0x60A3, 0x611F, 0x6163, 0x61BE, + 0x63DB, 0x6562, 0x67D1, 0x6853, 0x68FA, 0x6B3E, 0x6B53, 0x6C57, + 0x6F22, 0x6F97, 0x6F45, 0x74B0, 0x7518, 0x76E3, 0x770B, 0x7AFF, + 0x7BA1, 0x7C21, 0x7DE9, 0x7F36, 0x7FF0, 0x809D, 0x8266, 0x839E, + 0x89B3, 0x8ACC, 0x8CAB, 0x9084, 0x9451, 0x9593, 0x9591, 0x95A2, + 0x9665, 0x97D3, 0x9928, 0x8218, 0x4E38, 0x542B, 0x5CB8, 0x5DCC, + 0x73A9, 0x764C, 0x773C, 0x5CA9, 0x7FEB, 0x8D0B, 0x96C1, 0x9811, + 0x9854, 0x9858, 0x4F01, 0x4F0E, 0x5371, 0x559C, 0x5668, 0x57FA, + 0x5947, 0x5B09, 0x5BC4, 0x5C90, 0x5E0C, 0x5E7E, 0x5FCC, 0x63EE, + 0x673A, 0x65D7, 0x65E2, 0x671F, 0x68CB, 0x68C4 + }, + { /* category 21 */ + 0x6A5F, 0x5E30, 0x6BC5, 0x6C17, 0x6C7D, 0x757F, 0x7948, 0x5B63, + 0x7A00, 0x7D00, 0x5FBD, 0x898F, 0x8A18, 0x8CB4, 0x8D77, 0x8ECC, + 0x8F1D, 0x98E2, 0x9A0E, 0x9B3C, 0x4E80, 0x507D, 0x5100, 0x5993, + 0x5B9C, 0x622F, 0x6280, 0x64EC, 0x6B3A, 0x72A0, 0x7591, 0x7947, + 0x7FA9, 0x87FB, 0x8ABC, 0x8B70, 0x63AC, 0x83CA, 0x97A0, 0x5409, + 0x5403, 0x55AB, 0x6854, 0x6A58, 0x8A70, 0x7827, 0x6775, 0x9ECD, + 0x5374, 0x5BA2, 0x811A, 0x8650, 0x9006, 0x4E18, 0x4E45, 0x4EC7, + 0x4F11, 0x53CA, 0x5438, 0x5BAE, 0x5F13, 0x6025, 0x6551, 0x673D, + 0x6C42, 0x6C72, 0x6CE3, 0x7078, 0x7403, 0x7A76, 0x7AAE, 0x7B08, + 0x7D1A, 0x7CFE, 0x7D66, 0x65E7, 0x725B, 0x53BB, 0x5C45, 0x5DE8, + 0x62D2, 0x62E0, 0x6319, 0x6E20, 0x865A, 0x8A31, 0x8DDD, 0x92F8, + 0x6F01, 0x79A6, 0x9B5A, 0x4EA8, 0x4EAB, 0x4EAC + }, + { /* category 22 */ + 0x4F9B, 0x4FA0, 0x50D1, 0x5147, 0x7AF6, 0x5171, 0x51F6, 0x5354, + 0x5321, 0x537F, 0x53EB, 0x55AC, 0x5883, 0x5CE1, 0x5F37, 0x5F4A, + 0x602F, 0x6050, 0x606D, 0x631F, 0x6559, 0x6A4B, 0x6CC1, 0x72C2, + 0x72ED, 0x77EF, 0x80F8, 0x8105, 0x8208, 0x854E, 0x90F7, 0x93E1, + 0x97FF, 0x9957, 0x9A5A, 0x4EF0, 0x51DD, 0x5C2D, 0x6681, 0x696D, + 0x5C40, 0x66F2, 0x6975, 0x7389, 0x6850, 0x7C81, 0x50C5, 0x52E4, + 0x5747, 0x5DFE, 0x9326, 0x65A4, 0x6B23, 0x6B3D, 0x7434, 0x7981, + 0x79BD, 0x7B4B, 0x7DCA, 0x82B9, 0x83CC, 0x887F, 0x895F, 0x8B39, + 0x8FD1, 0x91D1, 0x541F, 0x9280, 0x4E5D, 0x5036, 0x53E5, 0x533A, + 0x72D7, 0x7396, 0x77E9, 0x82E6, 0x8EAF, 0x99C6, 0x99C8, 0x99D2, + 0x5177, 0x611A, 0x865E, 0x55B0, 0x7A7A, 0x5076, 0x5BD3, 0x9047, + 0x9685, 0x4E32, 0x6ADB, 0x91E7, 0x5C51, 0x5C48 + }, + { /* category 23 */ + 0x6398, 0x7A9F, 0x6C93, 0x9774, 0x8F61, 0x7AAA, 0x718A, 0x9688, + 0x7C82, 0x6817, 0x7E70, 0x6851, 0x936C, 0x52F2, 0x541B, 0x85AB, + 0x8A13, 0x7FA4, 0x8ECD, 0x90E1, 0x5366, 0x8888, 0x7941, 0x4FC2, + 0x50BE, 0x5211, 0x5144, 0x5553, 0x572D, 0x73EA, 0x578B, 0x5951, + 0x5F62, 0x5F84, 0x6075, 0x6176, 0x6167, 0x61A9, 0x63B2, 0x643A, + 0x656C, 0x666F, 0x6842, 0x6E13, 0x7566, 0x7A3D, 0x7CFB, 0x7D4C, + 0x7D99, 0x7E4B, 0x7F6B, 0x830E, 0x834A, 0x86CD, 0x8A08, 0x8A63, + 0x8B66, 0x8EFD, 0x981A, 0x9D8F, 0x82B8, 0x8FCE, 0x9BE8, 0x5287, + 0x621F, 0x6483, 0x6FC0, 0x9699, 0x6841, 0x5091, 0x6B20, 0x6C7A, + 0x6F54, 0x7A74, 0x7D50, 0x8840, 0x8A23, 0x6708, 0x4EF6, 0x5039, + 0x5026, 0x5065, 0x517C, 0x5238, 0x5263, 0x55A7, 0x570F, 0x5805, + 0x5ACC, 0x5EFA, 0x61B2, 0x61F8, 0x62F3, 0x6372 + }, + { /* category 24 */ + 0x691C, 0x6A29, 0x727D, 0x72AC, 0x732E, 0x7814, 0x786F, 0x7D79, + 0x770C, 0x80A9, 0x898B, 0x8B19, 0x8CE2, 0x8ED2, 0x9063, 0x9375, + 0x967A, 0x9855, 0x9A13, 0x9E78, 0x5143, 0x539F, 0x53B3, 0x5E7B, + 0x5F26, 0x6E1B, 0x6E90, 0x7384, 0x73FE, 0x7D43, 0x8237, 0x8A00, + 0x8AFA, 0x9650, 0x4E4E, 0x500B, 0x53E4, 0x547C, 0x56FA, 0x59D1, + 0x5B64, 0x5DF1, 0x5EAB, 0x5F27, 0x6238, 0x6545, 0x67AF, 0x6E56, + 0x72D0, 0x7CCA, 0x88B4, 0x80A1, 0x80E1, 0x83F0, 0x864E, 0x8A87, + 0x8DE8, 0x9237, 0x96C7, 0x9867, 0x9F13, 0x4E94, 0x4E92, 0x4F0D, + 0x5348, 0x5449, 0x543E, 0x5A2F, 0x5F8C, 0x5FA1, 0x609F, 0x68A7, + 0x6A8E, 0x745A, 0x7881, 0x8A9E, 0x8AA4, 0x8B77, 0x9190, 0x4E5E, + 0x9BC9, 0x4EA4, 0x4F7C, 0x4FAF, 0x5019, 0x5016, 0x5149, 0x516C, + 0x529F, 0x52B9, 0x52FE, 0x539A, 0x53E3, 0x5411 + }, + { /* category 25 */ + 0x540E, 0x5589, 0x5751, 0x57A2, 0x597D, 0x5B54, 0x5B5D, 0x5B8F, + 0x5DE5, 0x5DE7, 0x5DF7, 0x5E78, 0x5E83, 0x5E9A, 0x5EB7, 0x5F18, + 0x6052, 0x614C, 0x6297, 0x62D8, 0x63A7, 0x653B, 0x6602, 0x6643, + 0x66F4, 0x676D, 0x6821, 0x6897, 0x69CB, 0x6C5F, 0x6D2A, 0x6D69, + 0x6E2F, 0x6E9D, 0x7532, 0x7687, 0x786C, 0x7A3F, 0x7CE0, 0x7D05, + 0x7D18, 0x7D5E, 0x7DB1, 0x8015, 0x8003, 0x80AF, 0x80B1, 0x8154, + 0x818F, 0x822A, 0x8352, 0x884C, 0x8861, 0x8B1B, 0x8CA2, 0x8CFC, + 0x90CA, 0x9175, 0x9271, 0x783F, 0x92FC, 0x95A4, 0x964D, 0x9805, + 0x9999, 0x9AD8, 0x9D3B, 0x525B, 0x52AB, 0x53F7, 0x5408, 0x58D5, + 0x62F7, 0x6FE0, 0x8C6A, 0x8F5F, 0x9EB9, 0x514B, 0x523B, 0x544A, + 0x56FD, 0x7A40, 0x9177, 0x9D60, 0x9ED2, 0x7344, 0x6F09, 0x8170, + 0x7511, 0x5FFD, 0x60DA, 0x9AA8, 0x72DB, 0x8FBC + }, + { /* category 26 */ + 0x6B64, 0x9803, 0x4ECA, 0x56F0, 0x5764, 0x58BE, 0x5A5A, 0x6068, + 0x61C7, 0x660F, 0x6606, 0x6839, 0x68B1, 0x6DF7, 0x75D5, 0x7D3A, + 0x826E, 0x9B42, 0x4E9B, 0x4F50, 0x53C9, 0x5506, 0x5D6F, 0x5DE6, + 0x5DEE, 0x67FB, 0x6C99, 0x7473, 0x7802, 0x8A50, 0x9396, 0x88DF, + 0x5750, 0x5EA7, 0x632B, 0x50B5, 0x50AC, 0x518D, 0x6700, 0x54C9, + 0x585E, 0x59BB, 0x5BB0, 0x5F69, 0x624D, 0x63A1, 0x683D, 0x6B73, + 0x6E08, 0x707D, 0x91C7, 0x7280, 0x7815, 0x7826, 0x796D, 0x658E, + 0x7D30, 0x83DC, 0x88C1, 0x8F09, 0x969B, 0x5264, 0x5728, 0x6750, + 0x7F6A, 0x8CA1, 0x51B4, 0x5742, 0x962A, 0x583A, 0x698A, 0x80B4, + 0x54B2, 0x5D0E, 0x57FC, 0x7895, 0x9DFA, 0x4F5C, 0x524A, 0x548B, + 0x643E, 0x6628, 0x6714, 0x67F5, 0x7A84, 0x7B56, 0x7D22, 0x932F, + 0x685C, 0x9BAD, 0x7B39, 0x5319, 0x518A, 0x5237 + }, + { /* category 27 */ + 0x5BDF, 0x62F6, 0x64AE, 0x64E6, 0x672D, 0x6BBA, 0x85A9, 0x96D1, + 0x7690, 0x9BD6, 0x634C, 0x9306, 0x9BAB, 0x76BF, 0x6652, 0x4E09, + 0x5098, 0x53C2, 0x5C71, 0x60E8, 0x6492, 0x6563, 0x685F, 0x71E6, + 0x73CA, 0x7523, 0x7B97, 0x7E82, 0x8695, 0x8B83, 0x8CDB, 0x9178, + 0x9910, 0x65AC, 0x66AB, 0x6B8B, 0x4ED5, 0x4ED4, 0x4F3A, 0x4F7F, + 0x523A, 0x53F8, 0x53F2, 0x55E3, 0x56DB, 0x58EB, 0x59CB, 0x59C9, + 0x59FF, 0x5B50, 0x5C4D, 0x5E02, 0x5E2B, 0x5FD7, 0x601D, 0x6307, + 0x652F, 0x5B5C, 0x65AF, 0x65BD, 0x65E8, 0x679D, 0x6B62, 0x6B7B, + 0x6C0F, 0x7345, 0x7949, 0x79C1, 0x7CF8, 0x7D19, 0x7D2B, 0x80A2, + 0x8102, 0x81F3, 0x8996, 0x8A5E, 0x8A69, 0x8A66, 0x8A8C, 0x8AEE, + 0x8CC7, 0x8CDC, 0x96CC, 0x98FC, 0x6B6F, 0x4E8B, 0x4F3C, 0x4F8D, + 0x5150, 0x5B57, 0x5BFA, 0x6148, 0x6301, 0x6642 + }, + { /* category 28 */ + 0x6B21, 0x6ECB, 0x6CBB, 0x723E, 0x74BD, 0x75D4, 0x78C1, 0x793A, + 0x800C, 0x8033, 0x81EA, 0x8494, 0x8F9E, 0x6C50, 0x9E7F, 0x5F0F, + 0x8B58, 0x9D2B, 0x7AFA, 0x8EF8, 0x5B8D, 0x96EB, 0x4E03, 0x53F1, + 0x57F7, 0x5931, 0x5AC9, 0x5BA4, 0x6089, 0x6E7F, 0x6F06, 0x75BE, + 0x8CEA, 0x5B9F, 0x8500, 0x7BE0, 0x5072, 0x67F4, 0x829D, 0x5C61, + 0x854A, 0x7E1E, 0x820E, 0x5199, 0x5C04, 0x6368, 0x8D66, 0x659C, + 0x716E, 0x793E, 0x7D17, 0x8005, 0x8B1D, 0x8ECA, 0x906E, 0x86C7, + 0x90AA, 0x501F, 0x52FA, 0x5C3A, 0x6753, 0x707C, 0x7235, 0x914C, + 0x91C8, 0x932B, 0x82E5, 0x5BC2, 0x5F31, 0x60F9, 0x4E3B, 0x53D6, + 0x5B88, 0x624B, 0x6731, 0x6B8A, 0x72E9, 0x73E0, 0x7A2E, 0x816B, + 0x8DA3, 0x9152, 0x9996, 0x5112, 0x53D7, 0x546A, 0x5BFF, 0x6388, + 0x6A39, 0x7DAC, 0x9700, 0x56DA, 0x53CE, 0x5468 + }, + { /* category 29 */ + 0x5B97, 0x5C31, 0x5DDE, 0x4FEE, 0x6101, 0x62FE, 0x6D32, 0x79C0, + 0x79CB, 0x7D42, 0x7E4D, 0x7FD2, 0x81ED, 0x821F, 0x8490, 0x8846, + 0x8972, 0x8B90, 0x8E74, 0x8F2F, 0x9031, 0x914B, 0x916C, 0x96C6, + 0x919C, 0x4EC0, 0x4F4F, 0x5145, 0x5341, 0x5F93, 0x620E, 0x67D4, + 0x6C41, 0x6E0B, 0x7363, 0x7E26, 0x91CD, 0x9283, 0x53D4, 0x5919, + 0x5BBF, 0x6DD1, 0x795D, 0x7E2E, 0x7C9B, 0x587E, 0x719F, 0x51FA, + 0x8853, 0x8FF0, 0x4FCA, 0x5CFB, 0x6625, 0x77AC, 0x7AE3, 0x821C, + 0x99FF, 0x51C6, 0x5FAA, 0x65EC, 0x696F, 0x6B89, 0x6DF3, 0x6E96, + 0x6F64, 0x76FE, 0x7D14, 0x5DE1, 0x9075, 0x9187, 0x9806, 0x51E6, + 0x521D, 0x6240, 0x6691, 0x66D9, 0x6E1A, 0x5EB6, 0x7DD2, 0x7F72, + 0x66F8, 0x85AF, 0x85F7, 0x8AF8, 0x52A9, 0x53D9, 0x5973, 0x5E8F, + 0x5F90, 0x6055, 0x92E4, 0x9664, 0x50B7, 0x511F + }, + { /* category 30 */ + 0x52DD, 0x5320, 0x5347, 0x53EC, 0x54E8, 0x5546, 0x5531, 0x5617, + 0x5968, 0x59BE, 0x5A3C, 0x5BB5, 0x5C06, 0x5C0F, 0x5C11, 0x5C1A, + 0x5E84, 0x5E8A, 0x5EE0, 0x5F70, 0x627F, 0x6284, 0x62DB, 0x638C, + 0x6377, 0x6607, 0x660C, 0x662D, 0x6676, 0x677E, 0x68A2, 0x6A1F, + 0x6A35, 0x6CBC, 0x6D88, 0x6E09, 0x6E58, 0x713C, 0x7126, 0x7167, + 0x75C7, 0x7701, 0x785D, 0x7901, 0x7965, 0x79F0, 0x7AE0, 0x7B11, + 0x7CA7, 0x7D39, 0x8096, 0x83D6, 0x848B, 0x8549, 0x885D, 0x88F3, + 0x8A1F, 0x8A3C, 0x8A54, 0x8A73, 0x8C61, 0x8CDE, 0x91A4, 0x9266, + 0x937E, 0x9418, 0x969C, 0x9798, 0x4E0A, 0x4E08, 0x4E1E, 0x4E57, + 0x5197, 0x5270, 0x57CE, 0x5834, 0x58CC, 0x5B22, 0x5E38, 0x60C5, + 0x64FE, 0x6761, 0x6756, 0x6D44, 0x72B6, 0x7573, 0x7A63, 0x84B8, + 0x8B72, 0x91B8, 0x9320, 0x5631, 0x57F4, 0x98FE + }, + { /* category 31 */ + 0x62ED, 0x690D, 0x6B96, 0x71ED, 0x7E54, 0x8077, 0x8272, 0x89E6, + 0x98DF, 0x8755, 0x8FB1, 0x5C3B, 0x4F38, 0x4FE1, 0x4FB5, 0x5507, + 0x5A20, 0x5BDD, 0x5BE9, 0x5FC3, 0x614E, 0x632F, 0x65B0, 0x664B, + 0x68EE, 0x699B, 0x6D78, 0x6DF1, 0x7533, 0x75B9, 0x771F, 0x795E, + 0x79E6, 0x7D33, 0x81E3, 0x82AF, 0x85AA, 0x89AA, 0x8A3A, 0x8EAB, + 0x8F9B, 0x9032, 0x91DD, 0x9707, 0x4EBA, 0x4EC1, 0x5203, 0x5875, + 0x58EC, 0x5C0B, 0x751A, 0x5C3D, 0x814E, 0x8A0A, 0x8FC5, 0x9663, + 0x976D, 0x7B25, 0x8ACF, 0x9808, 0x9162, 0x56F3, 0x53A8, 0x9017, + 0x5439, 0x5782, 0x5E25, 0x63A8, 0x6C34, 0x708A, 0x7761, 0x7C8B, + 0x7FE0, 0x8870, 0x9042, 0x9154, 0x9310, 0x9318, 0x968F, 0x745E, + 0x9AC4, 0x5D07, 0x5D69, 0x6570, 0x67A2, 0x8DA8, 0x96DB, 0x636E, + 0x6749, 0x6919, 0x83C5, 0x9817, 0x96C0, 0x88FE + }, + { /* category 32 */ + 0x6F84, 0x647A, 0x5BF8, 0x4E16, 0x702C, 0x755D, 0x662F, 0x51C4, + 0x5236, 0x52E2, 0x59D3, 0x5F81, 0x6027, 0x6210, 0x653F, 0x6574, + 0x661F, 0x6674, 0x68F2, 0x6816, 0x6B63, 0x6E05, 0x7272, 0x751F, + 0x76DB, 0x7CBE, 0x8056, 0x58F0, 0x88FD, 0x897F, 0x8AA0, 0x8A93, + 0x8ACB, 0x901D, 0x9192, 0x9752, 0x9759, 0x6589, 0x7A0E, 0x8106, + 0x96BB, 0x5E2D, 0x60DC, 0x621A, 0x65A5, 0x6614, 0x6790, 0x77F3, + 0x7A4D, 0x7C4D, 0x7E3E, 0x810A, 0x8CAC, 0x8D64, 0x8DE1, 0x8E5F, + 0x78A9, 0x5207, 0x62D9, 0x63A5, 0x6442, 0x6298, 0x8A2D, 0x7A83, + 0x7BC0, 0x8AAC, 0x96EA, 0x7D76, 0x820C, 0x8749, 0x4ED9, 0x5148, + 0x5343, 0x5360, 0x5BA3, 0x5C02, 0x5C16, 0x5DDD, 0x6226, 0x6247, + 0x64B0, 0x6813, 0x6834, 0x6CC9, 0x6D45, 0x6D17, 0x67D3, 0x6F5C, + 0x714E, 0x717D, 0x65CB, 0x7A7F, 0x7BAD, 0x7DDA + }, + { /* category 33 */ + 0x7E4A, 0x7FA8, 0x817A, 0x821B, 0x8239, 0x85A6, 0x8A6E, 0x8CCE, + 0x8DF5, 0x9078, 0x9077, 0x92AD, 0x9291, 0x9583, 0x9BAE, 0x524D, + 0x5584, 0x6F38, 0x7136, 0x5168, 0x7985, 0x7E55, 0x81B3, 0x7CCE, + 0x564C, 0x5851, 0x5CA8, 0x63AA, 0x66FE, 0x66FD, 0x695A, 0x72D9, + 0x758F, 0x758E, 0x790E, 0x7956, 0x79DF, 0x7C97, 0x7D20, 0x7D44, + 0x8607, 0x8A34, 0x963B, 0x9061, 0x9F20, 0x50E7, 0x5275, 0x53CC, + 0x53E2, 0x5009, 0x55AA, 0x58EE, 0x594F, 0x723D, 0x5B8B, 0x5C64, + 0x531D, 0x60E3, 0x60F3, 0x635C, 0x6383, 0x633F, 0x63BB, 0x64CD, + 0x65E9, 0x66F9, 0x5DE3, 0x69CD, 0x69FD, 0x6F15, 0x71E5, 0x4E89, + 0x75E9, 0x76F8, 0x7A93, 0x7CDF, 0x7DCF, 0x7D9C, 0x8061, 0x8349, + 0x8358, 0x846C, 0x84BC, 0x85FB, 0x88C5, 0x8D70, 0x9001, 0x906D, + 0x9397, 0x971C, 0x9A12, 0x50CF, 0x5897, 0x618E + }, + { /* category 34 */ + 0x81D3, 0x8535, 0x8D08, 0x9020, 0x4FC3, 0x5074, 0x5247, 0x5373, + 0x606F, 0x6349, 0x675F, 0x6E2C, 0x8DB3, 0x901F, 0x4FD7, 0x5C5E, + 0x8CCA, 0x65CF, 0x7D9A, 0x5352, 0x8896, 0x5176, 0x63C3, 0x5B58, + 0x5B6B, 0x5C0A, 0x640D, 0x6751, 0x905C, 0x4ED6, 0x591A, 0x592A, + 0x6C70, 0x8A51, 0x553E, 0x5815, 0x59A5, 0x60F0, 0x6253, 0x67C1, + 0x8235, 0x6955, 0x9640, 0x99C4, 0x9A28, 0x4F53, 0x5806, 0x5BFE, + 0x8010, 0x5CB1, 0x5E2F, 0x5F85, 0x6020, 0x614B, 0x6234, 0x66FF, + 0x6CF0, 0x6EDE, 0x80CE, 0x817F, 0x82D4, 0x888B, 0x8CB8, 0x9000, + 0x902E, 0x968A, 0x9EDB, 0x9BDB, 0x4EE3, 0x53F0, 0x5927, 0x7B2C, + 0x918D, 0x984C, 0x9DF9, 0x6EDD, 0x7027, 0x5353, 0x5544, 0x5B85, + 0x6258, 0x629E, 0x62D3, 0x6CA2, 0x6FEF, 0x7422, 0x8A17, 0x9438, + 0x6FC1, 0x8AFE, 0x8338, 0x51E7, 0x86F8, 0x53EA + }, + { /* category 35 */ + 0x53E9, 0x4F46, 0x9054, 0x8FB0, 0x596A, 0x8131, 0x5DFD, 0x7AEA, + 0x8FBF, 0x68DA, 0x8C37, 0x72F8, 0x9C48, 0x6A3D, 0x8AB0, 0x4E39, + 0x5358, 0x5606, 0x5766, 0x62C5, 0x63A2, 0x65E6, 0x6B4E, 0x6DE1, + 0x6E5B, 0x70AD, 0x77ED, 0x7AEF, 0x7BAA, 0x7DBB, 0x803D, 0x80C6, + 0x86CB, 0x8A95, 0x935B, 0x56E3, 0x58C7, 0x5F3E, 0x65AD, 0x6696, + 0x6A80, 0x6BB5, 0x7537, 0x8AC7, 0x5024, 0x77E5, 0x5730, 0x5F1B, + 0x6065, 0x667A, 0x6C60, 0x75F4, 0x7A1A, 0x7F6E, 0x81F4, 0x8718, + 0x9045, 0x99B3, 0x7BC9, 0x755C, 0x7AF9, 0x7B51, 0x84C4, 0x9010, + 0x79E9, 0x7A92, 0x8336, 0x5AE1, 0x7740, 0x4E2D, 0x4EF2, 0x5B99, + 0x5FE0, 0x62BD, 0x663C, 0x67F1, 0x6CE8, 0x866B, 0x8877, 0x8A3B, + 0x914E, 0x92F3, 0x99D0, 0x6A17, 0x7026, 0x732A, 0x82E7, 0x8457, + 0x8CAF, 0x4E01, 0x5146, 0x51CB, 0x558B, 0x5BF5 + }, + { /* category 36 */ + 0x5E16, 0x5E33, 0x5E81, 0x5F14, 0x5F35, 0x5F6B, 0x5FB4, 0x61F2, + 0x6311, 0x66A2, 0x671D, 0x6F6E, 0x7252, 0x753A, 0x773A, 0x8074, + 0x8139, 0x8178, 0x8776, 0x8ABF, 0x8ADC, 0x8D85, 0x8DF3, 0x929A, + 0x9577, 0x9802, 0x9CE5, 0x52C5, 0x6357, 0x76F4, 0x6715, 0x6C88, + 0x73CD, 0x8CC3, 0x93AE, 0x9673, 0x6D25, 0x589C, 0x690E, 0x69CC, + 0x8FFD, 0x939A, 0x75DB, 0x901A, 0x585A, 0x6802, 0x63B4, 0x69FB, + 0x4F43, 0x6F2C, 0x67D8, 0x8FBB, 0x8526, 0x7DB4, 0x9354, 0x693F, + 0x6F70, 0x576A, 0x58F7, 0x5B2C, 0x7D2C, 0x722A, 0x540A, 0x91E3, + 0x9DB4, 0x4EAD, 0x4F4E, 0x505C, 0x5075, 0x5243, 0x8C9E, 0x5448, + 0x5824, 0x5B9A, 0x5E1D, 0x5E95, 0x5EAD, 0x5EF7, 0x5F1F, 0x608C, + 0x62B5, 0x633A, 0x63D0, 0x68AF, 0x6C40, 0x7887, 0x798E, 0x7A0B, + 0x7DE0, 0x8247, 0x8A02, 0x8AE6, 0x8E44, 0x9013 + }, + { /* category 37 */ + 0x90B8, 0x912D, 0x91D8, 0x9F0E, 0x6CE5, 0x6458, 0x64E2, 0x6575, + 0x6EF4, 0x7684, 0x7B1B, 0x9069, 0x93D1, 0x6EBA, 0x54F2, 0x5FB9, + 0x64A4, 0x8F4D, 0x8FED, 0x9244, 0x5178, 0x586B, 0x5929, 0x5C55, + 0x5E97, 0x6DFB, 0x7E8F, 0x751C, 0x8CBC, 0x8EE2, 0x985B, 0x70B9, + 0x4F1D, 0x6BBF, 0x6FB1, 0x7530, 0x96FB, 0x514E, 0x5410, 0x5835, + 0x5857, 0x59AC, 0x5C60, 0x5F92, 0x6597, 0x675C, 0x6E21, 0x767B, + 0x83DF, 0x8CED, 0x9014, 0x90FD, 0x934D, 0x7825, 0x783A, 0x52AA, + 0x5EA6, 0x571F, 0x5974, 0x6012, 0x5012, 0x515A, 0x51AC, 0x51CD, + 0x5200, 0x5510, 0x5854, 0x5858, 0x5957, 0x5B95, 0x5CF6, 0x5D8B, + 0x60BC, 0x6295, 0x642D, 0x6771, 0x6843, 0x68BC, 0x68DF, 0x76D7, + 0x6DD8, 0x6E6F, 0x6D9B, 0x706F, 0x71C8, 0x5F53, 0x75D8, 0x7977, + 0x7B49, 0x7B54, 0x7B52, 0x7CD6, 0x7D71, 0x5230 + }, + { /* category 38 */ + 0x8463, 0x8569, 0x85E4, 0x8A0E, 0x8B04, 0x8C46, 0x8E0F, 0x9003, + 0x900F, 0x9419, 0x9676, 0x982D, 0x9A30, 0x95D8, 0x50CD, 0x52D5, + 0x540C, 0x5802, 0x5C0E, 0x61A7, 0x649E, 0x6D1E, 0x77B3, 0x7AE5, + 0x80F4, 0x8404, 0x9053, 0x9285, 0x5CE0, 0x9D07, 0x533F, 0x5F97, + 0x5FB3, 0x6D9C, 0x7279, 0x7763, 0x79BF, 0x7BE4, 0x6BD2, 0x72EC, + 0x8AAD, 0x6803, 0x6A61, 0x51F8, 0x7A81, 0x6934, 0x5C4A, 0x9CF6, + 0x82EB, 0x5BC5, 0x9149, 0x701E, 0x5678, 0x5C6F, 0x60C7, 0x6566, + 0x6C8C, 0x8C5A, 0x9041, 0x9813, 0x5451, 0x66C7, 0x920D, 0x5948, + 0x90A3, 0x5185, 0x4E4D, 0x51EA, 0x8599, 0x8B0E, 0x7058, 0x637A, + 0x934B, 0x6962, 0x99B4, 0x7E04, 0x7577, 0x5357, 0x6960, 0x8EDF, + 0x96E3, 0x6C5D, 0x4E8C, 0x5C3C, 0x5F10, 0x8FE9, 0x5302, 0x8CD1, + 0x8089, 0x8679, 0x5EFF, 0x65E5, 0x4E73, 0x5165 + }, + { /* category 39 */ + 0x5982, 0x5C3F, 0x97EE, 0x4EFB, 0x598A, 0x5FCD, 0x8A8D, 0x6FE1, + 0x79B0, 0x7962, 0x5BE7, 0x8471, 0x732B, 0x71B1, 0x5E74, 0x5FF5, + 0x637B, 0x649A, 0x71C3, 0x7C98, 0x4E43, 0x5EFC, 0x4E4B, 0x57DC, + 0x56A2, 0x60A9, 0x6FC3, 0x7D0D, 0x80FD, 0x8133, 0x81BF, 0x8FB2, + 0x8997, 0x86A4, 0x5DF4, 0x628A, 0x64AD, 0x8987, 0x6777, 0x6CE2, + 0x6D3E, 0x7436, 0x7834, 0x5A46, 0x7F75, 0x82AD, 0x99AC, 0x4FF3, + 0x5EC3, 0x62DD, 0x6392, 0x6557, 0x676F, 0x76C3, 0x724C, 0x80CC, + 0x80BA, 0x8F29, 0x914D, 0x500D, 0x57F9, 0x5A92, 0x6885, 0x6973, + 0x7164, 0x72FD, 0x8CB7, 0x58F2, 0x8CE0, 0x966A, 0x9019, 0x877F, + 0x79E4, 0x77E7, 0x8429, 0x4F2F, 0x5265, 0x535A, 0x62CD, 0x67CF, + 0x6CCA, 0x767D, 0x7B94, 0x7C95, 0x8236, 0x8584, 0x8FEB, 0x66DD, + 0x6F20, 0x7206, 0x7E1B, 0x83AB, 0x99C1, 0x9EA6 + }, + { /* category 40 */ + 0x51FD, 0x7BB1, 0x7872, 0x7BB8, 0x8087, 0x7B48, 0x6AE8, 0x5E61, + 0x808C, 0x7551, 0x7560, 0x516B, 0x9262, 0x6E8C, 0x767A, 0x9197, + 0x9AEA, 0x4F10, 0x7F70, 0x629C, 0x7B4F, 0x95A5, 0x9CE9, 0x567A, + 0x5859, 0x86E4, 0x96BC, 0x4F34, 0x5224, 0x534A, 0x53CD, 0x53DB, + 0x5E06, 0x642C, 0x6591, 0x677F, 0x6C3E, 0x6C4E, 0x7248, 0x72AF, + 0x73ED, 0x7554, 0x7E41, 0x822C, 0x85E9, 0x8CA9, 0x7BC4, 0x91C6, + 0x7169, 0x9812, 0x98EF, 0x633D, 0x6669, 0x756A, 0x76E4, 0x78D0, + 0x8543, 0x86EE, 0x532A, 0x5351, 0x5426, 0x5983, 0x5E87, 0x5F7C, + 0x60B2, 0x6249, 0x6279, 0x62AB, 0x6590, 0x6BD4, 0x6CCC, 0x75B2, + 0x76AE, 0x7891, 0x79D8, 0x7DCB, 0x7F77, 0x80A5, 0x88AB, 0x8AB9, + 0x8CBB, 0x907F, 0x975E, 0x98DB, 0x6A0B, 0x7C38, 0x5099, 0x5C3E, + 0x5FAE, 0x6787, 0x6BD8, 0x7435, 0x7709, 0x7F8E + }, + { /* category 41 */ + 0x9F3B, 0x67CA, 0x7A17, 0x5339, 0x758B, 0x9AED, 0x5F66, 0x819D, + 0x83F1, 0x8098, 0x5F3C, 0x5FC5, 0x7562, 0x7B46, 0x903C, 0x6867, + 0x59EB, 0x5A9B, 0x7D10, 0x767E, 0x8B2C, 0x4FF5, 0x5F6A, 0x6A19, + 0x6C37, 0x6F02, 0x74E2, 0x7968, 0x8868, 0x8A55, 0x8C79, 0x5EDF, + 0x63CF, 0x75C5, 0x79D2, 0x82D7, 0x9328, 0x92F2, 0x849C, 0x86ED, + 0x9C2D, 0x54C1, 0x5F6C, 0x658C, 0x6D5C, 0x7015, 0x8CA7, 0x8CD3, + 0x983B, 0x654F, 0x74F6, 0x4E0D, 0x4ED8, 0x57E0, 0x592B, 0x5A66, + 0x5BCC, 0x51A8, 0x5E03, 0x5E9C, 0x6016, 0x6276, 0x6577, 0x65A7, + 0x666E, 0x6D6E, 0x7236, 0x7B26, 0x8150, 0x819A, 0x8299, 0x8B5C, + 0x8CA0, 0x8CE6, 0x8D74, 0x961C, 0x9644, 0x4FAE, 0x64AB, 0x6B66, + 0x821E, 0x8461, 0x856A, 0x90E8, 0x5C01, 0x6953, 0x98A8, 0x847A, + 0x8557, 0x4F0F, 0x526F, 0x5FA9, 0x5E45, 0x670D + }, + { /* category 42 */ + 0x798F, 0x8179, 0x8907, 0x8986, 0x6DF5, 0x5F17, 0x6255, 0x6CB8, + 0x4ECF, 0x7269, 0x9B92, 0x5206, 0x543B, 0x5674, 0x58B3, 0x61A4, + 0x626E, 0x711A, 0x596E, 0x7C89, 0x7CDE, 0x7D1B, 0x96F0, 0x6587, + 0x805E, 0x4E19, 0x4F75, 0x5175, 0x5840, 0x5E63, 0x5E73, 0x5F0A, + 0x67C4, 0x4E26, 0x853D, 0x9589, 0x965B, 0x7C73, 0x9801, 0x50FB, + 0x58C1, 0x7656, 0x78A7, 0x5225, 0x77A5, 0x8511, 0x7B86, 0x504F, + 0x5909, 0x7247, 0x7BC7, 0x7DE8, 0x8FBA, 0x8FD4, 0x904D, 0x4FBF, + 0x52C9, 0x5A29, 0x5F01, 0x97AD, 0x4FDD, 0x8217, 0x92EA, 0x5703, + 0x6355, 0x6B69, 0x752B, 0x88DC, 0x8F14, 0x7A42, 0x52DF, 0x5893, + 0x6155, 0x620A, 0x66AE, 0x6BCD, 0x7C3F, 0x83E9, 0x5023, 0x4FF8, + 0x5305, 0x5446, 0x5831, 0x5949, 0x5B9D, 0x5CF0, 0x5CEF, 0x5D29, + 0x5E96, 0x62B1, 0x6367, 0x653E, 0x65B9, 0x670B + }, + { /* category 43 */ + 0x6CD5, 0x6CE1, 0x70F9, 0x7832, 0x7E2B, 0x80DE, 0x82B3, 0x840C, + 0x84EC, 0x8702, 0x8912, 0x8A2A, 0x8C4A, 0x90A6, 0x92D2, 0x98FD, + 0x9CF3, 0x9D6C, 0x4E4F, 0x4EA1, 0x508D, 0x5256, 0x574A, 0x59A8, + 0x5E3D, 0x5FD8, 0x5FD9, 0x623F, 0x66B4, 0x671B, 0x67D0, 0x68D2, + 0x5192, 0x7D21, 0x80AA, 0x81A8, 0x8B00, 0x8C8C, 0x8CBF, 0x927E, + 0x9632, 0x5420, 0x982C, 0x5317, 0x50D5, 0x535C, 0x58A8, 0x64B2, + 0x6734, 0x7267, 0x7766, 0x7A46, 0x91E6, 0x52C3, 0x6CA1, 0x6B86, + 0x5800, 0x5E4C, 0x5954, 0x672C, 0x7FFB, 0x51E1, 0x76C6, 0x6469, + 0x78E8, 0x9B54, 0x9EBB, 0x57CB, 0x59B9, 0x6627, 0x679A, 0x6BCE, + 0x54E9, 0x69D9, 0x5E55, 0x819C, 0x6795, 0x9BAA, 0x67FE, 0x9C52, + 0x685D, 0x4EA6, 0x4FE3, 0x53C8, 0x62B9, 0x672B, 0x6CAB, 0x8FC4, + 0x4FAD, 0x7E6D, 0x9EBF, 0x4E07, 0x6162, 0x6E80 + }, + { /* category 44 */ + 0x6F2B, 0x8513, 0x5473, 0x672A, 0x9B45, 0x5DF3, 0x7B95, 0x5CAC, + 0x5BC6, 0x871C, 0x6E4A, 0x84D1, 0x7A14, 0x8108, 0x5999, 0x7C8D, + 0x6C11, 0x7720, 0x52D9, 0x5922, 0x7121, 0x725F, 0x77DB, 0x9727, + 0x9D61, 0x690B, 0x5A7F, 0x5A18, 0x51A5, 0x540D, 0x547D, 0x660E, + 0x76DF, 0x8FF7, 0x9298, 0x9CF4, 0x59EA, 0x725D, 0x6EC5, 0x514D, + 0x68C9, 0x7DBF, 0x7DEC, 0x9762, 0x9EBA, 0x6478, 0x6A21, 0x8302, + 0x5984, 0x5B5F, 0x6BDB, 0x731B, 0x76F2, 0x7DB2, 0x8017, 0x8499, + 0x5132, 0x6728, 0x9ED9, 0x76EE, 0x6762, 0x52FF, 0x9905, 0x5C24, + 0x623B, 0x7C7E, 0x8CB0, 0x554F, 0x60B6, 0x7D0B, 0x9580, 0x5301, + 0x4E5F, 0x51B6, 0x591C, 0x723A, 0x8036, 0x91CE, 0x5F25, 0x77E2, + 0x5384, 0x5F79, 0x7D04, 0x85AC, 0x8A33, 0x8E8D, 0x9756, 0x67F3, + 0x85AE, 0x9453, 0x6109, 0x6108, 0x6CB9, 0x7652 + }, + { /* category 45 */ + 0x8AED, 0x8F38, 0x552F, 0x4F51, 0x512A, 0x52C7, 0x53CB, 0x5BA5, + 0x5E7D, 0x60A0, 0x6182, 0x63D6, 0x6709, 0x67DA, 0x6E67, 0x6D8C, + 0x7336, 0x7337, 0x7531, 0x7950, 0x88D5, 0x8A98, 0x904A, 0x9091, + 0x90F5, 0x96C4, 0x878D, 0x5915, 0x4E88, 0x4F59, 0x4E0E, 0x8A89, + 0x8F3F, 0x9810, 0x50AD, 0x5E7C, 0x5996, 0x5BB9, 0x5EB8, 0x63DA, + 0x63FA, 0x64C1, 0x66DC, 0x694A, 0x69D8, 0x6D0B, 0x6EB6, 0x7194, + 0x7528, 0x7AAF, 0x7F8A, 0x8000, 0x8449, 0x84C9, 0x8981, 0x8B21, + 0x8E0A, 0x9065, 0x967D, 0x990A, 0x617E, 0x6291, 0x6B32, 0x6C83, + 0x6D74, 0x7FCC, 0x7FFC, 0x6DC0, 0x7F85, 0x87BA, 0x88F8, 0x6765, + 0x83B1, 0x983C, 0x96F7, 0x6D1B, 0x7D61, 0x843D, 0x916A, 0x4E71, + 0x5375, 0x5D50, 0x6B04, 0x6FEB, 0x85CD, 0x862D, 0x89A7, 0x5229, + 0x540F, 0x5C65, 0x674E, 0x68A8, 0x7406, 0x7483 + }, + { /* category 46 */ + 0x75E2, 0x88CF, 0x88E1, 0x91CC, 0x96E2, 0x9678, 0x5F8B, 0x7387, + 0x7ACB, 0x844E, 0x63A0, 0x7565, 0x5289, 0x6D41, 0x6E9C, 0x7409, + 0x7559, 0x786B, 0x7C92, 0x9686, 0x7ADC, 0x9F8D, 0x4FB6, 0x616E, + 0x65C5, 0x865C, 0x4E86, 0x4EAE, 0x50DA, 0x4E21, 0x51CC, 0x5BEE, + 0x6599, 0x6881, 0x6DBC, 0x731F, 0x7642, 0x77AD, 0x7A1C, 0x7CE7, + 0x826F, 0x8AD2, 0x907C, 0x91CF, 0x9675, 0x9818, 0x529B, 0x7DD1, + 0x502B, 0x5398, 0x6797, 0x6DCB, 0x71D0, 0x7433, 0x81E8, 0x8F2A, + 0x96A3, 0x9C57, 0x9E9F, 0x7460, 0x5841, 0x6D99, 0x7D2F, 0x985E, + 0x4EE4, 0x4F36, 0x4F8B, 0x51B7, 0x52B1, 0x5DBA, 0x601C, 0x73B2, + 0x793C, 0x82D3, 0x9234, 0x96B7, 0x96F6, 0x970A, 0x9E97, 0x9F62, + 0x66A6, 0x6B74, 0x5217, 0x52A3, 0x70C8, 0x88C2, 0x5EC9, 0x604B, + 0x6190, 0x6F23, 0x7149, 0x7C3E, 0x7DF4, 0x806F + }, + { /* category 47 */ + 0x84EE, 0x9023, 0x932C, 0x5442, 0x9B6F, 0x6AD3, 0x7089, 0x8CC2, + 0x8DEF, 0x9732, 0x52B4, 0x5A41, 0x5ECA, 0x5F04, 0x6717, 0x697C, + 0x6994, 0x6D6A, 0x6F0F, 0x7262, 0x72FC, 0x7BED, 0x8001, 0x807E, + 0x874B, 0x90CE, 0x516D, 0x9E93, 0x7984, 0x808B, 0x9332, 0x8AD6, + 0x502D, 0x548C, 0x8A71, 0x6B6A, 0x8CC4, 0x8107, 0x60D1, 0x67A0, + 0x9DF2, 0x4E99, 0x4E98, 0x9C10, 0x8A6B, 0x85C1, 0x8568, 0x6900, + 0x6E7E, 0x7897, 0x8155, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 48 */ + 0x5F0C, 0x4E10, 0x4E15, 0x4E2A, 0x4E31, 0x4E36, 0x4E3C, 0x4E3F, + 0x4E42, 0x4E56, 0x4E58, 0x4E82, 0x4E85, 0x8C6B, 0x4E8A, 0x8212, + 0x5F0D, 0x4E8E, 0x4E9E, 0x4E9F, 0x4EA0, 0x4EA2, 0x4EB0, 0x4EB3, + 0x4EB6, 0x4ECE, 0x4ECD, 0x4EC4, 0x4EC6, 0x4EC2, 0x4ED7, 0x4EDE, + 0x4EED, 0x4EDF, 0x4EF7, 0x4F09, 0x4F5A, 0x4F30, 0x4F5B, 0x4F5D, + 0x4F57, 0x4F47, 0x4F76, 0x4F88, 0x4F8F, 0x4F98, 0x4F7B, 0x4F69, + 0x4F70, 0x4F91, 0x4F6F, 0x4F86, 0x4F96, 0x5118, 0x4FD4, 0x4FDF, + 0x4FCE, 0x4FD8, 0x4FDB, 0x4FD1, 0x4FDA, 0x4FD0, 0x4FE4, 0x4FE5, + 0x501A, 0x5028, 0x5014, 0x502A, 0x5025, 0x5005, 0x4F1C, 0x4FF6, + 0x5021, 0x5029, 0x502C, 0x4FFE, 0x4FEF, 0x5011, 0x5006, 0x5043, + 0x5047, 0x6703, 0x5055, 0x5050, 0x5048, 0x505A, 0x5056, 0x506C, + 0x5078, 0x5080, 0x509A, 0x5085, 0x50B4, 0x50B2 + }, + { /* category 49 */ + 0x50C9, 0x50CA, 0x50B3, 0x50C2, 0x50D6, 0x50DE, 0x50E5, 0x50ED, + 0x50E3, 0x50EE, 0x50F9, 0x50F5, 0x5109, 0x5101, 0x5102, 0x5116, + 0x5115, 0x5114, 0x511A, 0x5121, 0x513A, 0x5137, 0x513C, 0x513B, + 0x513F, 0x5140, 0x5152, 0x514C, 0x5154, 0x5162, 0x7AF8, 0x5169, + 0x516A, 0x516E, 0x5180, 0x5182, 0x56D8, 0x518C, 0x5189, 0x518F, + 0x5191, 0x5193, 0x5195, 0x5196, 0x51A4, 0x51A6, 0x51A2, 0x51A9, + 0x51AA, 0x51AB, 0x51B3, 0x51B1, 0x51B2, 0x51B0, 0x51B5, 0x51BD, + 0x51C5, 0x51C9, 0x51DB, 0x51E0, 0x8655, 0x51E9, 0x51ED, 0x51F0, + 0x51F5, 0x51FE, 0x5204, 0x520B, 0x5214, 0x520E, 0x5227, 0x522A, + 0x522E, 0x5233, 0x5239, 0x524F, 0x5244, 0x524B, 0x524C, 0x525E, + 0x5254, 0x526A, 0x5274, 0x5269, 0x5273, 0x527F, 0x527D, 0x528D, + 0x5294, 0x5292, 0x5271, 0x5288, 0x5291, 0x8FA8 + }, + { /* category 50 */ + 0x8FA7, 0x52AC, 0x52AD, 0x52BC, 0x52B5, 0x52C1, 0x52CD, 0x52D7, + 0x52DE, 0x52E3, 0x52E6, 0x98ED, 0x52E0, 0x52F3, 0x52F5, 0x52F8, + 0x52F9, 0x5306, 0x5308, 0x7538, 0x530D, 0x5310, 0x530F, 0x5315, + 0x531A, 0x5323, 0x532F, 0x5331, 0x5333, 0x5338, 0x5340, 0x5346, + 0x5345, 0x4E17, 0x5349, 0x534D, 0x51D6, 0x535E, 0x5369, 0x536E, + 0x5918, 0x537B, 0x5377, 0x5382, 0x5396, 0x53A0, 0x53A6, 0x53A5, + 0x53AE, 0x53B0, 0x53B6, 0x53C3, 0x7C12, 0x96D9, 0x53DF, 0x66FC, + 0x71EE, 0x53EE, 0x53E8, 0x53ED, 0x53FA, 0x5401, 0x543D, 0x5440, + 0x542C, 0x542D, 0x543C, 0x542E, 0x5436, 0x5429, 0x541D, 0x544E, + 0x548F, 0x5475, 0x548E, 0x545F, 0x5471, 0x5477, 0x5470, 0x5492, + 0x547B, 0x5480, 0x5476, 0x5484, 0x5490, 0x5486, 0x54C7, 0x54A2, + 0x54B8, 0x54A5, 0x54AC, 0x54C4, 0x54C8, 0x54A8 + }, + { /* category 51 */ + 0x54AB, 0x54C2, 0x54A4, 0x54BE, 0x54BC, 0x54D8, 0x54E5, 0x54E6, + 0x550F, 0x5514, 0x54FD, 0x54EE, 0x54ED, 0x54FA, 0x54E2, 0x5539, + 0x5540, 0x5563, 0x554C, 0x552E, 0x555C, 0x5545, 0x5556, 0x5557, + 0x5538, 0x5533, 0x555D, 0x5599, 0x5580, 0x54AF, 0x558A, 0x559F, + 0x557B, 0x557E, 0x5598, 0x559E, 0x55AE, 0x557C, 0x5583, 0x55A9, + 0x5587, 0x55A8, 0x55DA, 0x55C5, 0x55DF, 0x55C4, 0x55DC, 0x55E4, + 0x55D4, 0x5614, 0x55F7, 0x5616, 0x55FE, 0x55FD, 0x561B, 0x55F9, + 0x564E, 0x5650, 0x71DF, 0x5634, 0x5636, 0x5632, 0x5638, 0x566B, + 0x5664, 0x562F, 0x566C, 0x566A, 0x5686, 0x5680, 0x568A, 0x56A0, + 0x5694, 0x568F, 0x56A5, 0x56AE, 0x56B6, 0x56B4, 0x56C2, 0x56BC, + 0x56C1, 0x56C3, 0x56C0, 0x56C8, 0x56CE, 0x56D1, 0x56D3, 0x56D7, + 0x56EE, 0x56F9, 0x5700, 0x56FF, 0x5704, 0x5709 + }, + { /* category 52 */ + 0x5708, 0x570B, 0x570D, 0x5713, 0x5718, 0x5716, 0x55C7, 0x571C, + 0x5726, 0x5737, 0x5738, 0x574E, 0x573B, 0x5740, 0x574F, 0x5769, + 0x57C0, 0x5788, 0x5761, 0x577F, 0x5789, 0x5793, 0x57A0, 0x57B3, + 0x57A4, 0x57AA, 0x57B0, 0x57C3, 0x57C6, 0x57D4, 0x57D2, 0x57D3, + 0x580A, 0x57D6, 0x57E3, 0x580B, 0x5819, 0x581D, 0x5872, 0x5821, + 0x5862, 0x584B, 0x5870, 0x6BC0, 0x5852, 0x583D, 0x5879, 0x5885, + 0x58B9, 0x589F, 0x58AB, 0x58BA, 0x58DE, 0x58BB, 0x58B8, 0x58AE, + 0x58C5, 0x58D3, 0x58D1, 0x58D7, 0x58D9, 0x58D8, 0x58E5, 0x58DC, + 0x58E4, 0x58DF, 0x58EF, 0x58FA, 0x58F9, 0x58FB, 0x58FC, 0x58FD, + 0x5902, 0x590A, 0x5910, 0x591B, 0x68A6, 0x5925, 0x592C, 0x592D, + 0x5932, 0x5938, 0x593E, 0x7AD2, 0x5955, 0x5950, 0x594E, 0x595A, + 0x5958, 0x5962, 0x5960, 0x5967, 0x596C, 0x5969 + }, + { /* category 53 */ + 0x5978, 0x5981, 0x599D, 0x4F5E, 0x4FAB, 0x59A3, 0x59B2, 0x59C6, + 0x59E8, 0x59DC, 0x598D, 0x59D9, 0x59DA, 0x5A25, 0x5A1F, 0x5A11, + 0x5A1C, 0x5A09, 0x5A1A, 0x5A40, 0x5A6C, 0x5A49, 0x5A35, 0x5A36, + 0x5A62, 0x5A6A, 0x5A9A, 0x5ABC, 0x5ABE, 0x5ACB, 0x5AC2, 0x5ABD, + 0x5AE3, 0x5AD7, 0x5AE6, 0x5AE9, 0x5AD6, 0x5AFA, 0x5AFB, 0x5B0C, + 0x5B0B, 0x5B16, 0x5B32, 0x5AD0, 0x5B2A, 0x5B36, 0x5B3E, 0x5B43, + 0x5B45, 0x5B40, 0x5B51, 0x5B55, 0x5B5A, 0x5B5B, 0x5B65, 0x5B69, + 0x5B70, 0x5B73, 0x5B75, 0x5B78, 0x6588, 0x5B7A, 0x5B80, 0x5B83, + 0x5BA6, 0x5BB8, 0x5BC3, 0x5BC7, 0x5BC9, 0x5BD4, 0x5BD0, 0x5BE4, + 0x5BE6, 0x5BE2, 0x5BDE, 0x5BE5, 0x5BEB, 0x5BF0, 0x5BF6, 0x5BF3, + 0x5C05, 0x5C07, 0x5C08, 0x5C0D, 0x5C13, 0x5C20, 0x5C22, 0x5C28, + 0x5C38, 0x5C39, 0x5C41, 0x5C46, 0x5C4E, 0x5C53 + }, + { /* category 54 */ + 0x5C50, 0x5C4F, 0x5B71, 0x5C6C, 0x5C6E, 0x4E62, 0x5C76, 0x5C79, + 0x5C8C, 0x5C91, 0x5C94, 0x599B, 0x5CAB, 0x5CBB, 0x5CB6, 0x5CBC, + 0x5CB7, 0x5CC5, 0x5CBE, 0x5CC7, 0x5CD9, 0x5CE9, 0x5CFD, 0x5CFA, + 0x5CED, 0x5D8C, 0x5CEA, 0x5D0B, 0x5D15, 0x5D17, 0x5D5C, 0x5D1F, + 0x5D1B, 0x5D11, 0x5D14, 0x5D22, 0x5D1A, 0x5D19, 0x5D18, 0x5D4C, + 0x5D52, 0x5D4E, 0x5D4B, 0x5D6C, 0x5D73, 0x5D76, 0x5D87, 0x5D84, + 0x5D82, 0x5DA2, 0x5D9D, 0x5DAC, 0x5DAE, 0x5DBD, 0x5D90, 0x5DB7, + 0x5DBC, 0x5DC9, 0x5DCD, 0x5DD3, 0x5DD2, 0x5DD6, 0x5DDB, 0x5DEB, + 0x5DF2, 0x5DF5, 0x5E0B, 0x5E1A, 0x5E19, 0x5E11, 0x5E1B, 0x5E36, + 0x5E37, 0x5E44, 0x5E43, 0x5E40, 0x5E4E, 0x5E57, 0x5E54, 0x5E5F, + 0x5E62, 0x5E64, 0x5E47, 0x5E75, 0x5E76, 0x5E7A, 0x9EBC, 0x5E7F, + 0x5EA0, 0x5EC1, 0x5EC2, 0x5EC8, 0x5ED0, 0x5ECF + }, + { /* category 55 */ + 0x5ED6, 0x5EE3, 0x5EDD, 0x5EDA, 0x5EDB, 0x5EE2, 0x5EE1, 0x5EE8, + 0x5EE9, 0x5EEC, 0x5EF1, 0x5EF3, 0x5EF0, 0x5EF4, 0x5EF8, 0x5EFE, + 0x5F03, 0x5F09, 0x5F5D, 0x5F5C, 0x5F0B, 0x5F11, 0x5F16, 0x5F29, + 0x5F2D, 0x5F38, 0x5F41, 0x5F48, 0x5F4C, 0x5F4E, 0x5F2F, 0x5F51, + 0x5F56, 0x5F57, 0x5F59, 0x5F61, 0x5F6D, 0x5F73, 0x5F77, 0x5F83, + 0x5F82, 0x5F7F, 0x5F8A, 0x5F88, 0x5F91, 0x5F87, 0x5F9E, 0x5F99, + 0x5F98, 0x5FA0, 0x5FA8, 0x5FAD, 0x5FBC, 0x5FD6, 0x5FFB, 0x5FE4, + 0x5FF8, 0x5FF1, 0x5FDD, 0x60B3, 0x5FFF, 0x6021, 0x6060, 0x6019, + 0x6010, 0x6029, 0x600E, 0x6031, 0x601B, 0x6015, 0x602B, 0x6026, + 0x600F, 0x603A, 0x605A, 0x6041, 0x606A, 0x6077, 0x605F, 0x604A, + 0x6046, 0x604D, 0x6063, 0x6043, 0x6064, 0x6042, 0x606C, 0x606B, + 0x6059, 0x6081, 0x608D, 0x60E7, 0x6083, 0x609A + }, + { /* category 56 */ + 0x6084, 0x609B, 0x6096, 0x6097, 0x6092, 0x60A7, 0x608B, 0x60E1, + 0x60B8, 0x60E0, 0x60D3, 0x60B4, 0x5FF0, 0x60BD, 0x60C6, 0x60B5, + 0x60D8, 0x614D, 0x6115, 0x6106, 0x60F6, 0x60F7, 0x6100, 0x60F4, + 0x60FA, 0x6103, 0x6121, 0x60FB, 0x60F1, 0x610D, 0x610E, 0x6147, + 0x613E, 0x6128, 0x6127, 0x614A, 0x613F, 0x613C, 0x612C, 0x6134, + 0x613D, 0x6142, 0x6144, 0x6173, 0x6177, 0x6158, 0x6159, 0x615A, + 0x616B, 0x6174, 0x616F, 0x6165, 0x6171, 0x615F, 0x615D, 0x6153, + 0x6175, 0x6199, 0x6196, 0x6187, 0x61AC, 0x6194, 0x619A, 0x618A, + 0x6191, 0x61AB, 0x61AE, 0x61CC, 0x61CA, 0x61C9, 0x61F7, 0x61C8, + 0x61C3, 0x61C6, 0x61BA, 0x61CB, 0x7F79, 0x61CD, 0x61E6, 0x61E3, + 0x61F6, 0x61FA, 0x61F4, 0x61FF, 0x61FD, 0x61FC, 0x61FE, 0x6200, + 0x6208, 0x6209, 0x620D, 0x620C, 0x6214, 0x621B + }, + { /* category 57 */ + 0x621E, 0x6221, 0x622A, 0x622E, 0x6230, 0x6232, 0x6233, 0x6241, + 0x624E, 0x625E, 0x6263, 0x625B, 0x6260, 0x6268, 0x627C, 0x6282, + 0x6289, 0x627E, 0x6292, 0x6293, 0x6296, 0x62D4, 0x6283, 0x6294, + 0x62D7, 0x62D1, 0x62BB, 0x62CF, 0x62FF, 0x62C6, 0x64D4, 0x62C8, + 0x62DC, 0x62CC, 0x62CA, 0x62C2, 0x62C7, 0x629B, 0x62C9, 0x630C, + 0x62EE, 0x62F1, 0x6327, 0x6302, 0x6308, 0x62EF, 0x62F5, 0x6350, + 0x633E, 0x634D, 0x641C, 0x634F, 0x6396, 0x638E, 0x6380, 0x63AB, + 0x6376, 0x63A3, 0x638F, 0x6389, 0x639F, 0x63B5, 0x636B, 0x6369, + 0x63BE, 0x63E9, 0x63C0, 0x63C6, 0x63E3, 0x63C9, 0x63D2, 0x63F6, + 0x63C4, 0x6416, 0x6434, 0x6406, 0x6413, 0x6426, 0x6436, 0x651D, + 0x6417, 0x6428, 0x640F, 0x6467, 0x646F, 0x6476, 0x644E, 0x652A, + 0x6495, 0x6493, 0x64A5, 0x64A9, 0x6488, 0x64BC + }, + { /* category 58 */ + 0x64DA, 0x64D2, 0x64C5, 0x64C7, 0x64BB, 0x64D8, 0x64C2, 0x64F1, + 0x64E7, 0x8209, 0x64E0, 0x64E1, 0x62AC, 0x64E3, 0x64EF, 0x652C, + 0x64F6, 0x64F4, 0x64F2, 0x64FA, 0x6500, 0x64FD, 0x6518, 0x651C, + 0x6505, 0x6524, 0x6523, 0x652B, 0x6534, 0x6535, 0x6537, 0x6536, + 0x6538, 0x754B, 0x6548, 0x6556, 0x6555, 0x654D, 0x6558, 0x655E, + 0x655D, 0x6572, 0x6578, 0x6582, 0x6583, 0x8B8A, 0x659B, 0x659F, + 0x65AB, 0x65B7, 0x65C3, 0x65C6, 0x65C1, 0x65C4, 0x65CC, 0x65D2, + 0x65DB, 0x65D9, 0x65E0, 0x65E1, 0x65F1, 0x6772, 0x660A, 0x6603, + 0x65FB, 0x6773, 0x6635, 0x6636, 0x6634, 0x661C, 0x664F, 0x6644, + 0x6649, 0x6641, 0x665E, 0x665D, 0x6664, 0x6667, 0x6668, 0x665F, + 0x6662, 0x6670, 0x6683, 0x6688, 0x668E, 0x6689, 0x6684, 0x6698, + 0x669D, 0x66C1, 0x66B9, 0x66C9, 0x66BE, 0x66BC + }, + { /* category 59 */ + 0x66C4, 0x66B8, 0x66D6, 0x66DA, 0x66E0, 0x663F, 0x66E6, 0x66E9, + 0x66F0, 0x66F5, 0x66F7, 0x670F, 0x6716, 0x671E, 0x6726, 0x6727, + 0x9738, 0x672E, 0x673F, 0x6736, 0x6741, 0x6738, 0x6737, 0x6746, + 0x675E, 0x6760, 0x6759, 0x6763, 0x6764, 0x6789, 0x6770, 0x67A9, + 0x677C, 0x676A, 0x678C, 0x678B, 0x67A6, 0x67A1, 0x6785, 0x67B7, + 0x67EF, 0x67B4, 0x67EC, 0x67B3, 0x67E9, 0x67B8, 0x67E4, 0x67DE, + 0x67DD, 0x67E2, 0x67EE, 0x67B9, 0x67CE, 0x67C6, 0x67E7, 0x6A9C, + 0x681E, 0x6846, 0x6829, 0x6840, 0x684D, 0x6832, 0x684E, 0x68B3, + 0x682B, 0x6859, 0x6863, 0x6877, 0x687F, 0x689F, 0x688F, 0x68AD, + 0x6894, 0x689D, 0x689B, 0x6883, 0x6AAE, 0x68B9, 0x6874, 0x68B5, + 0x68A0, 0x68BA, 0x690F, 0x688D, 0x687E, 0x6901, 0x68CA, 0x6908, + 0x68D8, 0x6922, 0x6926, 0x68E1, 0x690C, 0x68CD + }, + { /* category 60 */ + 0x68D4, 0x68E7, 0x68D5, 0x6936, 0x6912, 0x6904, 0x68D7, 0x68E3, + 0x6925, 0x68F9, 0x68E0, 0x68EF, 0x6928, 0x692A, 0x691A, 0x6923, + 0x6921, 0x68C6, 0x6979, 0x6977, 0x695C, 0x6978, 0x696B, 0x6954, + 0x697E, 0x696E, 0x6939, 0x6974, 0x693D, 0x6959, 0x6930, 0x6961, + 0x695E, 0x695D, 0x6981, 0x696A, 0x69B2, 0x69AE, 0x69D0, 0x69BF, + 0x69C1, 0x69D3, 0x69BE, 0x69CE, 0x5BE8, 0x69CA, 0x69DD, 0x69BB, + 0x69C3, 0x69A7, 0x6A2E, 0x6991, 0x69A0, 0x699C, 0x6995, 0x69B4, + 0x69DE, 0x69E8, 0x6A02, 0x6A1B, 0x69FF, 0x6B0A, 0x69F9, 0x69F2, + 0x69E7, 0x6A05, 0x69B1, 0x6A1E, 0x69ED, 0x6A14, 0x69EB, 0x6A0A, + 0x6A12, 0x6AC1, 0x6A23, 0x6A13, 0x6A44, 0x6A0C, 0x6A72, 0x6A36, + 0x6A78, 0x6A47, 0x6A62, 0x6A59, 0x6A66, 0x6A48, 0x6A38, 0x6A22, + 0x6A90, 0x6A8D, 0x6AA0, 0x6A84, 0x6AA2, 0x6AA3 + }, + { /* category 61 */ + 0x6A97, 0x8617, 0x6ABB, 0x6AC3, 0x6AC2, 0x6AB8, 0x6AB3, 0x6AAC, + 0x6ADE, 0x6AD1, 0x6ADF, 0x6AAA, 0x6ADA, 0x6AEA, 0x6AFB, 0x6B05, + 0x8616, 0x6AFA, 0x6B12, 0x6B16, 0x9B31, 0x6B1F, 0x6B38, 0x6B37, + 0x76DC, 0x6B39, 0x98EE, 0x6B47, 0x6B43, 0x6B49, 0x6B50, 0x6B59, + 0x6B54, 0x6B5B, 0x6B5F, 0x6B61, 0x6B78, 0x6B79, 0x6B7F, 0x6B80, + 0x6B84, 0x6B83, 0x6B8D, 0x6B98, 0x6B95, 0x6B9E, 0x6BA4, 0x6BAA, + 0x6BAB, 0x6BAF, 0x6BB2, 0x6BB1, 0x6BB3, 0x6BB7, 0x6BBC, 0x6BC6, + 0x6BCB, 0x6BD3, 0x6BDF, 0x6BEC, 0x6BEB, 0x6BF3, 0x6BEF, 0x9EBE, + 0x6C08, 0x6C13, 0x6C14, 0x6C1B, 0x6C24, 0x6C23, 0x6C5E, 0x6C55, + 0x6C62, 0x6C6A, 0x6C82, 0x6C8D, 0x6C9A, 0x6C81, 0x6C9B, 0x6C7E, + 0x6C68, 0x6C73, 0x6C92, 0x6C90, 0x6CC4, 0x6CF1, 0x6CD3, 0x6CBD, + 0x6CD7, 0x6CC5, 0x6CDD, 0x6CAE, 0x6CB1, 0x6CBE + }, + { /* category 62 */ + 0x6CBA, 0x6CDB, 0x6CEF, 0x6CD9, 0x6CEA, 0x6D1F, 0x884D, 0x6D36, + 0x6D2B, 0x6D3D, 0x6D38, 0x6D19, 0x6D35, 0x6D33, 0x6D12, 0x6D0C, + 0x6D63, 0x6D93, 0x6D64, 0x6D5A, 0x6D79, 0x6D59, 0x6D8E, 0x6D95, + 0x6FE4, 0x6D85, 0x6DF9, 0x6E15, 0x6E0A, 0x6DB5, 0x6DC7, 0x6DE6, + 0x6DB8, 0x6DC6, 0x6DEC, 0x6DDE, 0x6DCC, 0x6DE8, 0x6DD2, 0x6DC5, + 0x6DFA, 0x6DD9, 0x6DE4, 0x6DD5, 0x6DEA, 0x6DEE, 0x6E2D, 0x6E6E, + 0x6E2E, 0x6E19, 0x6E72, 0x6E5F, 0x6E3E, 0x6E23, 0x6E6B, 0x6E2B, + 0x6E76, 0x6E4D, 0x6E1F, 0x6E43, 0x6E3A, 0x6E4E, 0x6E24, 0x6EFF, + 0x6E1D, 0x6E38, 0x6E82, 0x6EAA, 0x6E98, 0x6EC9, 0x6EB7, 0x6ED3, + 0x6EBD, 0x6EAF, 0x6EC4, 0x6EB2, 0x6ED4, 0x6ED5, 0x6E8F, 0x6EA5, + 0x6EC2, 0x6E9F, 0x6F41, 0x6F11, 0x704C, 0x6EEC, 0x6EF8, 0x6EFE, + 0x6F3F, 0x6EF2, 0x6F31, 0x6EEF, 0x6F32, 0x6ECC + }, + { /* category 63 */ + 0x6F3E, 0x6F13, 0x6EF7, 0x6F86, 0x6F7A, 0x6F78, 0x6F81, 0x6F80, + 0x6F6F, 0x6F5B, 0x6FF3, 0x6F6D, 0x6F82, 0x6F7C, 0x6F58, 0x6F8E, + 0x6F91, 0x6FC2, 0x6F66, 0x6FB3, 0x6FA3, 0x6FA1, 0x6FA4, 0x6FB9, + 0x6FC6, 0x6FAA, 0x6FDF, 0x6FD5, 0x6FEC, 0x6FD4, 0x6FD8, 0x6FF1, + 0x6FEE, 0x6FDB, 0x7009, 0x700B, 0x6FFA, 0x7011, 0x7001, 0x700F, + 0x6FFE, 0x701B, 0x701A, 0x6F74, 0x701D, 0x7018, 0x701F, 0x7030, + 0x703E, 0x7032, 0x7051, 0x7063, 0x7099, 0x7092, 0x70AF, 0x70F1, + 0x70AC, 0x70B8, 0x70B3, 0x70AE, 0x70DF, 0x70CB, 0x70DD, 0x70D9, + 0x7109, 0x70FD, 0x711C, 0x7119, 0x7165, 0x7155, 0x7188, 0x7166, + 0x7162, 0x714C, 0x7156, 0x716C, 0x718F, 0x71FB, 0x7184, 0x7195, + 0x71A8, 0x71AC, 0x71D7, 0x71B9, 0x71BE, 0x71D2, 0x71C9, 0x71D4, + 0x71CE, 0x71E0, 0x71EC, 0x71E7, 0x71F5, 0x71FC + }, + { /* category 64 */ + 0x71F9, 0x71FF, 0x720D, 0x7210, 0x721B, 0x7228, 0x722D, 0x722C, + 0x7230, 0x7232, 0x723B, 0x723C, 0x723F, 0x7240, 0x7246, 0x724B, + 0x7258, 0x7274, 0x727E, 0x7282, 0x7281, 0x7287, 0x7292, 0x7296, + 0x72A2, 0x72A7, 0x72B9, 0x72B2, 0x72C3, 0x72C6, 0x72C4, 0x72CE, + 0x72D2, 0x72E2, 0x72E0, 0x72E1, 0x72F9, 0x72F7, 0x500F, 0x7317, + 0x730A, 0x731C, 0x7316, 0x731D, 0x7334, 0x732F, 0x7329, 0x7325, + 0x733E, 0x734E, 0x734F, 0x9ED8, 0x7357, 0x736A, 0x7368, 0x7370, + 0x7378, 0x7375, 0x737B, 0x737A, 0x73C8, 0x73B3, 0x73CE, 0x73BB, + 0x73C0, 0x73E5, 0x73EE, 0x73DE, 0x74A2, 0x7405, 0x746F, 0x7425, + 0x73F8, 0x7432, 0x743A, 0x7455, 0x743F, 0x745F, 0x7459, 0x7441, + 0x745C, 0x7469, 0x7470, 0x7463, 0x746A, 0x7476, 0x747E, 0x748B, + 0x749E, 0x74A7, 0x74CA, 0x74CF, 0x74D4, 0x73F1 + }, + { /* category 65 */ + 0x74E0, 0x74E3, 0x74E7, 0x74E9, 0x74EE, 0x74F2, 0x74F0, 0x74F1, + 0x74F8, 0x74F7, 0x7504, 0x7503, 0x7505, 0x750C, 0x750E, 0x750D, + 0x7515, 0x7513, 0x751E, 0x7526, 0x752C, 0x753C, 0x7544, 0x754D, + 0x754A, 0x7549, 0x755B, 0x7546, 0x755A, 0x7569, 0x7564, 0x7567, + 0x756B, 0x756D, 0x7578, 0x7576, 0x7586, 0x7587, 0x7574, 0x758A, + 0x7589, 0x7582, 0x7594, 0x759A, 0x759D, 0x75A5, 0x75A3, 0x75C2, + 0x75B3, 0x75C3, 0x75B5, 0x75BD, 0x75B8, 0x75BC, 0x75B1, 0x75CD, + 0x75CA, 0x75D2, 0x75D9, 0x75E3, 0x75DE, 0x75FE, 0x75FF, 0x75FC, + 0x7601, 0x75F0, 0x75FA, 0x75F2, 0x75F3, 0x760B, 0x760D, 0x7609, + 0x761F, 0x7627, 0x7620, 0x7621, 0x7622, 0x7624, 0x7634, 0x7630, + 0x763B, 0x7647, 0x7648, 0x7646, 0x765C, 0x7658, 0x7661, 0x7662, + 0x7668, 0x7669, 0x766A, 0x7667, 0x766C, 0x7670 + }, + { /* category 66 */ + 0x7672, 0x7676, 0x7678, 0x767C, 0x7680, 0x7683, 0x7688, 0x768B, + 0x768E, 0x7696, 0x7693, 0x7699, 0x769A, 0x76B0, 0x76B4, 0x76B8, + 0x76B9, 0x76BA, 0x76C2, 0x76CD, 0x76D6, 0x76D2, 0x76DE, 0x76E1, + 0x76E5, 0x76E7, 0x76EA, 0x862F, 0x76FB, 0x7708, 0x7707, 0x7704, + 0x7729, 0x7724, 0x771E, 0x7725, 0x7726, 0x771B, 0x7737, 0x7738, + 0x7747, 0x775A, 0x7768, 0x776B, 0x775B, 0x7765, 0x777F, 0x777E, + 0x7779, 0x778E, 0x778B, 0x7791, 0x77A0, 0x779E, 0x77B0, 0x77B6, + 0x77B9, 0x77BF, 0x77BC, 0x77BD, 0x77BB, 0x77C7, 0x77CD, 0x77D7, + 0x77DA, 0x77DC, 0x77E3, 0x77EE, 0x77FC, 0x780C, 0x7812, 0x7926, + 0x7820, 0x792A, 0x7845, 0x788E, 0x7874, 0x7886, 0x787C, 0x789A, + 0x788C, 0x78A3, 0x78B5, 0x78AA, 0x78AF, 0x78D1, 0x78C6, 0x78CB, + 0x78D4, 0x78BE, 0x78BC, 0x78C5, 0x78CA, 0x78EC + }, + { /* category 67 */ + 0x78E7, 0x78DA, 0x78FD, 0x78F4, 0x7907, 0x7912, 0x7911, 0x7919, + 0x792C, 0x792B, 0x7940, 0x7960, 0x7957, 0x795F, 0x795A, 0x7955, + 0x7953, 0x797A, 0x797F, 0x798A, 0x799D, 0x79A7, 0x9F4B, 0x79AA, + 0x79AE, 0x79B3, 0x79B9, 0x79BA, 0x79C9, 0x79D5, 0x79E7, 0x79EC, + 0x79E1, 0x79E3, 0x7A08, 0x7A0D, 0x7A18, 0x7A19, 0x7A20, 0x7A1F, + 0x7980, 0x7A31, 0x7A3B, 0x7A3E, 0x7A37, 0x7A43, 0x7A57, 0x7A49, + 0x7A61, 0x7A62, 0x7A69, 0x9F9D, 0x7A70, 0x7A79, 0x7A7D, 0x7A88, + 0x7A97, 0x7A95, 0x7A98, 0x7A96, 0x7AA9, 0x7AC8, 0x7AB0, 0x7AB6, + 0x7AC5, 0x7AC4, 0x7ABF, 0x9083, 0x7AC7, 0x7ACA, 0x7ACD, 0x7ACF, + 0x7AD5, 0x7AD3, 0x7AD9, 0x7ADA, 0x7ADD, 0x7AE1, 0x7AE2, 0x7AE6, + 0x7AED, 0x7AF0, 0x7B02, 0x7B0F, 0x7B0A, 0x7B06, 0x7B33, 0x7B18, + 0x7B19, 0x7B1E, 0x7B35, 0x7B28, 0x7B36, 0x7B50 + }, + { /* category 68 */ + 0x7B7A, 0x7B04, 0x7B4D, 0x7B0B, 0x7B4C, 0x7B45, 0x7B75, 0x7B65, + 0x7B74, 0x7B67, 0x7B70, 0x7B71, 0x7B6C, 0x7B6E, 0x7B9D, 0x7B98, + 0x7B9F, 0x7B8D, 0x7B9C, 0x7B9A, 0x7B8B, 0x7B92, 0x7B8F, 0x7B5D, + 0x7B99, 0x7BCB, 0x7BC1, 0x7BCC, 0x7BCF, 0x7BB4, 0x7BC6, 0x7BDD, + 0x7BE9, 0x7C11, 0x7C14, 0x7BE6, 0x7BE5, 0x7C60, 0x7C00, 0x7C07, + 0x7C13, 0x7BF3, 0x7BF7, 0x7C17, 0x7C0D, 0x7BF6, 0x7C23, 0x7C27, + 0x7C2A, 0x7C1F, 0x7C37, 0x7C2B, 0x7C3D, 0x7C4C, 0x7C43, 0x7C54, + 0x7C4F, 0x7C40, 0x7C50, 0x7C58, 0x7C5F, 0x7C64, 0x7C56, 0x7C65, + 0x7C6C, 0x7C75, 0x7C83, 0x7C90, 0x7CA4, 0x7CAD, 0x7CA2, 0x7CAB, + 0x7CA1, 0x7CA8, 0x7CB3, 0x7CB2, 0x7CB1, 0x7CAE, 0x7CB9, 0x7CBD, + 0x7CC0, 0x7CC5, 0x7CC2, 0x7CD8, 0x7CD2, 0x7CDC, 0x7CE2, 0x9B3B, + 0x7CEF, 0x7CF2, 0x7CF4, 0x7CF6, 0x7CFA, 0x7D06 + }, + { /* category 69 */ + 0x7D02, 0x7D1C, 0x7D15, 0x7D0A, 0x7D45, 0x7D4B, 0x7D2E, 0x7D32, + 0x7D3F, 0x7D35, 0x7D46, 0x7D73, 0x7D56, 0x7D4E, 0x7D72, 0x7D68, + 0x7D6E, 0x7D4F, 0x7D63, 0x7D93, 0x7D89, 0x7D5B, 0x7D8F, 0x7D7D, + 0x7D9B, 0x7DBA, 0x7DAE, 0x7DA3, 0x7DB5, 0x7DC7, 0x7DBD, 0x7DAB, + 0x7E3D, 0x7DA2, 0x7DAF, 0x7DDC, 0x7DB8, 0x7D9F, 0x7DB0, 0x7DD8, + 0x7DDD, 0x7DE4, 0x7DDE, 0x7DFB, 0x7DF2, 0x7DE1, 0x7E05, 0x7E0A, + 0x7E23, 0x7E21, 0x7E12, 0x7E31, 0x7E1F, 0x7E09, 0x7E0B, 0x7E22, + 0x7E46, 0x7E66, 0x7E3B, 0x7E35, 0x7E39, 0x7E43, 0x7E37, 0x7E32, + 0x7E3A, 0x7E67, 0x7E5D, 0x7E56, 0x7E5E, 0x7E59, 0x7E5A, 0x7E79, + 0x7E6A, 0x7E69, 0x7E7C, 0x7E7B, 0x7E83, 0x7DD5, 0x7E7D, 0x8FAE, + 0x7E7F, 0x7E88, 0x7E89, 0x7E8C, 0x7E92, 0x7E90, 0x7E93, 0x7E94, + 0x7E96, 0x7E8E, 0x7E9B, 0x7E9C, 0x7F38, 0x7F3A + }, + { /* category 70 */ + 0x7F45, 0x7F4C, 0x7F4D, 0x7F4E, 0x7F50, 0x7F51, 0x7F55, 0x7F54, + 0x7F58, 0x7F5F, 0x7F60, 0x7F68, 0x7F69, 0x7F67, 0x7F78, 0x7F82, + 0x7F86, 0x7F83, 0x7F88, 0x7F87, 0x7F8C, 0x7F94, 0x7F9E, 0x7F9D, + 0x7F9A, 0x7FA3, 0x7FAF, 0x7FB2, 0x7FB9, 0x7FAE, 0x7FB6, 0x7FB8, + 0x8B71, 0x7FC5, 0x7FC6, 0x7FCA, 0x7FD5, 0x7FD4, 0x7FE1, 0x7FE6, + 0x7FE9, 0x7FF3, 0x7FF9, 0x98DC, 0x8006, 0x8004, 0x800B, 0x8012, + 0x8018, 0x8019, 0x801C, 0x8021, 0x8028, 0x803F, 0x803B, 0x804A, + 0x8046, 0x8052, 0x8058, 0x805A, 0x805F, 0x8062, 0x8068, 0x8073, + 0x8072, 0x8070, 0x8076, 0x8079, 0x807D, 0x807F, 0x8084, 0x8086, + 0x8085, 0x809B, 0x8093, 0x809A, 0x80AD, 0x5190, 0x80AC, 0x80DB, + 0x80E5, 0x80D9, 0x80DD, 0x80C4, 0x80DA, 0x80D6, 0x8109, 0x80EF, + 0x80F1, 0x811B, 0x8129, 0x8123, 0x812F, 0x814B + }, + { /* category 71 */ + 0x968B, 0x8146, 0x813E, 0x8153, 0x8151, 0x80FC, 0x8171, 0x816E, + 0x8165, 0x8166, 0x8174, 0x8183, 0x8188, 0x818A, 0x8180, 0x8182, + 0x81A0, 0x8195, 0x81A4, 0x81A3, 0x815F, 0x8193, 0x81A9, 0x81B0, + 0x81B5, 0x81BE, 0x81B8, 0x81BD, 0x81C0, 0x81C2, 0x81BA, 0x81C9, + 0x81CD, 0x81D1, 0x81D9, 0x81D8, 0x81C8, 0x81DA, 0x81DF, 0x81E0, + 0x81E7, 0x81FA, 0x81FB, 0x81FE, 0x8201, 0x8202, 0x8205, 0x8207, + 0x820A, 0x820D, 0x8210, 0x8216, 0x8229, 0x822B, 0x8238, 0x8233, + 0x8240, 0x8259, 0x8258, 0x825D, 0x825A, 0x825F, 0x8264, 0x8262, + 0x8268, 0x826A, 0x826B, 0x822E, 0x8271, 0x8277, 0x8278, 0x827E, + 0x828D, 0x8292, 0x82AB, 0x829F, 0x82BB, 0x82AC, 0x82E1, 0x82E3, + 0x82DF, 0x82D2, 0x82F4, 0x82F3, 0x82FA, 0x8393, 0x8303, 0x82FB, + 0x82F9, 0x82DE, 0x8306, 0x82DC, 0x8309, 0x82D9 + }, + { /* category 72 */ + 0x8335, 0x8334, 0x8316, 0x8332, 0x8331, 0x8340, 0x8339, 0x8350, + 0x8345, 0x832F, 0x832B, 0x8317, 0x8318, 0x8385, 0x839A, 0x83AA, + 0x839F, 0x83A2, 0x8396, 0x8323, 0x838E, 0x8387, 0x838A, 0x837C, + 0x83B5, 0x8373, 0x8375, 0x83A0, 0x8389, 0x83A8, 0x83F4, 0x8413, + 0x83EB, 0x83CE, 0x83FD, 0x8403, 0x83D8, 0x840B, 0x83C1, 0x83F7, + 0x8407, 0x83E0, 0x83F2, 0x840D, 0x8422, 0x8420, 0x83BD, 0x8438, + 0x8506, 0x83FB, 0x846D, 0x842A, 0x843C, 0x855A, 0x8484, 0x8477, + 0x846B, 0x84AD, 0x846E, 0x8482, 0x8469, 0x8446, 0x842C, 0x846F, + 0x8479, 0x8435, 0x84CA, 0x8462, 0x84B9, 0x84BF, 0x849F, 0x84D9, + 0x84CD, 0x84BB, 0x84DA, 0x84D0, 0x84C1, 0x84C6, 0x84D6, 0x84A1, + 0x8521, 0x84FF, 0x84F4, 0x8517, 0x8518, 0x852C, 0x851F, 0x8515, + 0x8514, 0x84FC, 0x8540, 0x8563, 0x8558, 0x8548 + }, + { /* category 73 */ + 0x8541, 0x8602, 0x854B, 0x8555, 0x8580, 0x85A4, 0x8588, 0x8591, + 0x858A, 0x85A8, 0x856D, 0x8594, 0x859B, 0x85EA, 0x8587, 0x859C, + 0x8577, 0x857E, 0x8590, 0x85C9, 0x85BA, 0x85CF, 0x85B9, 0x85D0, + 0x85D5, 0x85DD, 0x85E5, 0x85DC, 0x85F9, 0x860A, 0x8613, 0x860B, + 0x85FE, 0x85FA, 0x8606, 0x8622, 0x861A, 0x8630, 0x863F, 0x864D, + 0x4E55, 0x8654, 0x865F, 0x8667, 0x8671, 0x8693, 0x86A3, 0x86A9, + 0x86AA, 0x868B, 0x868C, 0x86B6, 0x86AF, 0x86C4, 0x86C6, 0x86B0, + 0x86C9, 0x8823, 0x86AB, 0x86D4, 0x86DE, 0x86E9, 0x86EC, 0x86DF, + 0x86DB, 0x86EF, 0x8712, 0x8706, 0x8708, 0x8700, 0x8703, 0x86FB, + 0x8711, 0x8709, 0x870D, 0x86F9, 0x870A, 0x8734, 0x873F, 0x8737, + 0x873B, 0x8725, 0x8729, 0x871A, 0x8760, 0x875F, 0x8778, 0x874C, + 0x874E, 0x8774, 0x8757, 0x8768, 0x876E, 0x8759 + }, + { /* category 74 */ + 0x8753, 0x8763, 0x876A, 0x8805, 0x87A2, 0x879F, 0x8782, 0x87AF, + 0x87CB, 0x87BD, 0x87C0, 0x87D0, 0x96D6, 0x87AB, 0x87C4, 0x87B3, + 0x87C7, 0x87C6, 0x87BB, 0x87EF, 0x87F2, 0x87E0, 0x880F, 0x880D, + 0x87FE, 0x87F6, 0x87F7, 0x880E, 0x87D2, 0x8811, 0x8816, 0x8815, + 0x8822, 0x8821, 0x8831, 0x8836, 0x8839, 0x8827, 0x883B, 0x8844, + 0x8842, 0x8852, 0x8859, 0x885E, 0x8862, 0x886B, 0x8881, 0x887E, + 0x889E, 0x8875, 0x887D, 0x88B5, 0x8872, 0x8882, 0x8897, 0x8892, + 0x88AE, 0x8899, 0x88A2, 0x888D, 0x88A4, 0x88B0, 0x88BF, 0x88B1, + 0x88C3, 0x88C4, 0x88D4, 0x88D8, 0x88D9, 0x88DD, 0x88F9, 0x8902, + 0x88FC, 0x88F4, 0x88E8, 0x88F2, 0x8904, 0x890C, 0x890A, 0x8913, + 0x8943, 0x891E, 0x8925, 0x892A, 0x892B, 0x8941, 0x8944, 0x893B, + 0x8936, 0x8938, 0x894C, 0x891D, 0x8960, 0x895E + }, + { /* category 75 */ + 0x8966, 0x8964, 0x896D, 0x896A, 0x896F, 0x8974, 0x8977, 0x897E, + 0x8983, 0x8988, 0x898A, 0x8993, 0x8998, 0x89A1, 0x89A9, 0x89A6, + 0x89AC, 0x89AF, 0x89B2, 0x89BA, 0x89BD, 0x89BF, 0x89C0, 0x89DA, + 0x89DC, 0x89DD, 0x89E7, 0x89F4, 0x89F8, 0x8A03, 0x8A16, 0x8A10, + 0x8A0C, 0x8A1B, 0x8A1D, 0x8A25, 0x8A36, 0x8A41, 0x8A5B, 0x8A52, + 0x8A46, 0x8A48, 0x8A7C, 0x8A6D, 0x8A6C, 0x8A62, 0x8A85, 0x8A82, + 0x8A84, 0x8AA8, 0x8AA1, 0x8A91, 0x8AA5, 0x8AA6, 0x8A9A, 0x8AA3, + 0x8AC4, 0x8ACD, 0x8AC2, 0x8ADA, 0x8AEB, 0x8AF3, 0x8AE7, 0x8AE4, + 0x8AF1, 0x8B14, 0x8AE0, 0x8AE2, 0x8AF7, 0x8ADE, 0x8ADB, 0x8B0C, + 0x8B07, 0x8B1A, 0x8AE1, 0x8B16, 0x8B10, 0x8B17, 0x8B20, 0x8B33, + 0x97AB, 0x8B26, 0x8B2B, 0x8B3E, 0x8B28, 0x8B41, 0x8B4C, 0x8B4F, + 0x8B4E, 0x8B49, 0x8B56, 0x8B5B, 0x8B5A, 0x8B6B + }, + { /* category 76 */ + 0x8B5F, 0x8B6C, 0x8B6F, 0x8B74, 0x8B7D, 0x8B80, 0x8B8C, 0x8B8E, + 0x8B92, 0x8B93, 0x8B96, 0x8B99, 0x8B9A, 0x8C3A, 0x8C41, 0x8C3F, + 0x8C48, 0x8C4C, 0x8C4E, 0x8C50, 0x8C55, 0x8C62, 0x8C6C, 0x8C78, + 0x8C7A, 0x8C82, 0x8C89, 0x8C85, 0x8C8A, 0x8C8D, 0x8C8E, 0x8C94, + 0x8C7C, 0x8C98, 0x621D, 0x8CAD, 0x8CAA, 0x8CBD, 0x8CB2, 0x8CB3, + 0x8CAE, 0x8CB6, 0x8CC8, 0x8CC1, 0x8CE4, 0x8CE3, 0x8CDA, 0x8CFD, + 0x8CFA, 0x8CFB, 0x8D04, 0x8D05, 0x8D0A, 0x8D07, 0x8D0F, 0x8D0D, + 0x8D10, 0x9F4E, 0x8D13, 0x8CCD, 0x8D14, 0x8D16, 0x8D67, 0x8D6D, + 0x8D71, 0x8D73, 0x8D81, 0x8D99, 0x8DC2, 0x8DBE, 0x8DBA, 0x8DCF, + 0x8DDA, 0x8DD6, 0x8DCC, 0x8DDB, 0x8DCB, 0x8DEA, 0x8DEB, 0x8DDF, + 0x8DE3, 0x8DFC, 0x8E08, 0x8E09, 0x8DFF, 0x8E1D, 0x8E1E, 0x8E10, + 0x8E1F, 0x8E42, 0x8E35, 0x8E30, 0x8E34, 0x8E4A + }, + { /* category 77 */ + 0x8E47, 0x8E49, 0x8E4C, 0x8E50, 0x8E48, 0x8E59, 0x8E64, 0x8E60, + 0x8E2A, 0x8E63, 0x8E55, 0x8E76, 0x8E72, 0x8E7C, 0x8E81, 0x8E87, + 0x8E85, 0x8E84, 0x8E8B, 0x8E8A, 0x8E93, 0x8E91, 0x8E94, 0x8E99, + 0x8EAA, 0x8EA1, 0x8EAC, 0x8EB0, 0x8EC6, 0x8EB1, 0x8EBE, 0x8EC5, + 0x8EC8, 0x8ECB, 0x8EDB, 0x8EE3, 0x8EFC, 0x8EFB, 0x8EEB, 0x8EFE, + 0x8F0A, 0x8F05, 0x8F15, 0x8F12, 0x8F19, 0x8F13, 0x8F1C, 0x8F1F, + 0x8F1B, 0x8F0C, 0x8F26, 0x8F33, 0x8F3B, 0x8F39, 0x8F45, 0x8F42, + 0x8F3E, 0x8F4C, 0x8F49, 0x8F46, 0x8F4E, 0x8F57, 0x8F5C, 0x8F62, + 0x8F63, 0x8F64, 0x8F9C, 0x8F9F, 0x8FA3, 0x8FAD, 0x8FAF, 0x8FB7, + 0x8FDA, 0x8FE5, 0x8FE2, 0x8FEA, 0x8FEF, 0x9087, 0x8FF4, 0x9005, + 0x8FF9, 0x8FFA, 0x9011, 0x9015, 0x9021, 0x900D, 0x901E, 0x9016, + 0x900B, 0x9027, 0x9036, 0x9035, 0x9039, 0x8FF8 + }, + { /* category 78 */ + 0x904F, 0x9050, 0x9051, 0x9052, 0x900E, 0x9049, 0x903E, 0x9056, + 0x9058, 0x905E, 0x9068, 0x906F, 0x9076, 0x96A8, 0x9072, 0x9082, + 0x907D, 0x9081, 0x9080, 0x908A, 0x9089, 0x908F, 0x90A8, 0x90AF, + 0x90B1, 0x90B5, 0x90E2, 0x90E4, 0x6248, 0x90DB, 0x9102, 0x9112, + 0x9119, 0x9132, 0x9130, 0x914A, 0x9156, 0x9158, 0x9163, 0x9165, + 0x9169, 0x9173, 0x9172, 0x918B, 0x9189, 0x9182, 0x91A2, 0x91AB, + 0x91AF, 0x91AA, 0x91B5, 0x91B4, 0x91BA, 0x91C0, 0x91C1, 0x91C9, + 0x91CB, 0x91D0, 0x91D6, 0x91DF, 0x91E1, 0x91DB, 0x91FC, 0x91F5, + 0x91F6, 0x921E, 0x91FF, 0x9214, 0x922C, 0x9215, 0x9211, 0x925E, + 0x9257, 0x9245, 0x9249, 0x9264, 0x9248, 0x9295, 0x923F, 0x924B, + 0x9250, 0x929C, 0x9296, 0x9293, 0x929B, 0x925A, 0x92CF, 0x92B9, + 0x92B7, 0x92E9, 0x930F, 0x92FA, 0x9344, 0x932E + }, + { /* category 79 */ + 0x9319, 0x9322, 0x931A, 0x9323, 0x933A, 0x9335, 0x933B, 0x935C, + 0x9360, 0x937C, 0x936E, 0x9356, 0x93B0, 0x93AC, 0x93AD, 0x9394, + 0x93B9, 0x93D6, 0x93D7, 0x93E8, 0x93E5, 0x93D8, 0x93C3, 0x93DD, + 0x93D0, 0x93C8, 0x93E4, 0x941A, 0x9414, 0x9413, 0x9403, 0x9407, + 0x9410, 0x9436, 0x942B, 0x9435, 0x9421, 0x943A, 0x9441, 0x9452, + 0x9444, 0x945B, 0x9460, 0x9462, 0x945E, 0x946A, 0x9229, 0x9470, + 0x9475, 0x9477, 0x947D, 0x945A, 0x947C, 0x947E, 0x9481, 0x947F, + 0x9582, 0x9587, 0x958A, 0x9594, 0x9596, 0x9598, 0x9599, 0x95A0, + 0x95A8, 0x95A7, 0x95AD, 0x95BC, 0x95BB, 0x95B9, 0x95BE, 0x95CA, + 0x6FF6, 0x95C3, 0x95CD, 0x95CC, 0x95D5, 0x95D4, 0x95D6, 0x95DC, + 0x95E1, 0x95E5, 0x95E2, 0x9621, 0x9628, 0x962E, 0x962F, 0x9642, + 0x964C, 0x964F, 0x964B, 0x9677, 0x965C, 0x965E + }, + { /* category 80 */ + 0x965D, 0x965F, 0x9666, 0x9672, 0x966C, 0x968D, 0x9698, 0x9695, + 0x9697, 0x96AA, 0x96A7, 0x96B1, 0x96B2, 0x96B0, 0x96B4, 0x96B6, + 0x96B8, 0x96B9, 0x96CE, 0x96CB, 0x96C9, 0x96CD, 0x894D, 0x96DC, + 0x970D, 0x96D5, 0x96F9, 0x9704, 0x9706, 0x9708, 0x9713, 0x970E, + 0x9711, 0x970F, 0x9716, 0x9719, 0x9724, 0x972A, 0x9730, 0x9739, + 0x973D, 0x973E, 0x9744, 0x9746, 0x9748, 0x9742, 0x9749, 0x975C, + 0x9760, 0x9764, 0x9766, 0x9768, 0x52D2, 0x976B, 0x9771, 0x9779, + 0x9785, 0x977C, 0x9781, 0x977A, 0x9786, 0x978B, 0x978F, 0x9790, + 0x979C, 0x97A8, 0x97A6, 0x97A3, 0x97B3, 0x97B4, 0x97C3, 0x97C6, + 0x97C8, 0x97CB, 0x97DC, 0x97ED, 0x9F4F, 0x97F2, 0x7ADF, 0x97F6, + 0x97F5, 0x980F, 0x980C, 0x9838, 0x9824, 0x9821, 0x9837, 0x983D, + 0x9846, 0x984F, 0x984B, 0x986B, 0x986F, 0x9870 + }, + { /* category 81 */ + 0x9871, 0x9874, 0x9873, 0x98AA, 0x98AF, 0x98B1, 0x98B6, 0x98C4, + 0x98C3, 0x98C6, 0x98E9, 0x98EB, 0x9903, 0x9909, 0x9912, 0x9914, + 0x9918, 0x9921, 0x991D, 0x991E, 0x9924, 0x9920, 0x992C, 0x992E, + 0x993D, 0x993E, 0x9942, 0x9949, 0x9945, 0x9950, 0x994B, 0x9951, + 0x9952, 0x994C, 0x9955, 0x9997, 0x9998, 0x99A5, 0x99AD, 0x99AE, + 0x99BC, 0x99DF, 0x99DB, 0x99DD, 0x99D8, 0x99D1, 0x99ED, 0x99EE, + 0x99F1, 0x99F2, 0x99FB, 0x99F8, 0x9A01, 0x9A0F, 0x9A05, 0x99E2, + 0x9A19, 0x9A2B, 0x9A37, 0x9A45, 0x9A42, 0x9A40, 0x9A43, 0x9A3E, + 0x9A55, 0x9A4D, 0x9A5B, 0x9A57, 0x9A5F, 0x9A62, 0x9A65, 0x9A64, + 0x9A69, 0x9A6B, 0x9A6A, 0x9AAD, 0x9AB0, 0x9ABC, 0x9AC0, 0x9ACF, + 0x9AD1, 0x9AD3, 0x9AD4, 0x9ADE, 0x9ADF, 0x9AE2, 0x9AE3, 0x9AE6, + 0x9AEF, 0x9AEB, 0x9AEE, 0x9AF4, 0x9AF1, 0x9AF7 + }, + { /* category 82 */ + 0x9AFB, 0x9B06, 0x9B18, 0x9B1A, 0x9B1F, 0x9B22, 0x9B23, 0x9B25, + 0x9B27, 0x9B28, 0x9B29, 0x9B2A, 0x9B2E, 0x9B2F, 0x9B32, 0x9B44, + 0x9B43, 0x9B4F, 0x9B4D, 0x9B4E, 0x9B51, 0x9B58, 0x9B74, 0x9B93, + 0x9B83, 0x9B91, 0x9B96, 0x9B97, 0x9B9F, 0x9BA0, 0x9BA8, 0x9BB4, + 0x9BC0, 0x9BCA, 0x9BB9, 0x9BC6, 0x9BCF, 0x9BD1, 0x9BD2, 0x9BE3, + 0x9BE2, 0x9BE4, 0x9BD4, 0x9BE1, 0x9C3A, 0x9BF2, 0x9BF1, 0x9BF0, + 0x9C15, 0x9C14, 0x9C09, 0x9C13, 0x9C0C, 0x9C06, 0x9C08, 0x9C12, + 0x9C0A, 0x9C04, 0x9C2E, 0x9C1B, 0x9C25, 0x9C24, 0x9C21, 0x9C30, + 0x9C47, 0x9C32, 0x9C46, 0x9C3E, 0x9C5A, 0x9C60, 0x9C67, 0x9C76, + 0x9C78, 0x9CE7, 0x9CEC, 0x9CF0, 0x9D09, 0x9D08, 0x9CEB, 0x9D03, + 0x9D06, 0x9D2A, 0x9D26, 0x9DAF, 0x9D23, 0x9D1F, 0x9D44, 0x9D15, + 0x9D12, 0x9D41, 0x9D3F, 0x9D3E, 0x9D46, 0x9D48 + }, + { /* category 83 */ + 0x9D5D, 0x9D5E, 0x9D64, 0x9D51, 0x9D50, 0x9D59, 0x9D72, 0x9D89, + 0x9D87, 0x9DAB, 0x9D6F, 0x9D7A, 0x9D9A, 0x9DA4, 0x9DA9, 0x9DB2, + 0x9DC4, 0x9DC1, 0x9DBB, 0x9DB8, 0x9DBA, 0x9DC6, 0x9DCF, 0x9DC2, + 0x9DD9, 0x9DD3, 0x9DF8, 0x9DE6, 0x9DED, 0x9DEF, 0x9DFD, 0x9E1A, + 0x9E1B, 0x9E1E, 0x9E75, 0x9E79, 0x9E7D, 0x9E81, 0x9E88, 0x9E8B, + 0x9E8C, 0x9E92, 0x9E95, 0x9E91, 0x9E9D, 0x9EA5, 0x9EA9, 0x9EB8, + 0x9EAA, 0x9EAD, 0x9761, 0x9ECC, 0x9ECE, 0x9ECF, 0x9ED0, 0x9ED4, + 0x9EDC, 0x9EDE, 0x9EDD, 0x9EE0, 0x9EE5, 0x9EE8, 0x9EEF, 0x9EF4, + 0x9EF6, 0x9EF7, 0x9EF9, 0x9EFB, 0x9EFC, 0x9EFD, 0x9F07, 0x9F08, + 0x76B7, 0x9F15, 0x9F21, 0x9F2C, 0x9F3E, 0x9F4A, 0x9F52, 0x9F54, + 0x9F63, 0x9F5F, 0x9F60, 0x9F61, 0x9F66, 0x9F67, 0x9F6C, 0x9F6A, + 0x9F77, 0x9F72, 0x9F76, 0x9F95, 0x9F9C, 0x9FA0 + }, + { /* category 84 */ + 0x582F, 0x69C7, 0x9059, 0x7464, 0x51DC, 0x7199, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 85 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 86 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 87 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 88 */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }, + { /* category 89 */ + 0x7E8A, 0x891C, 0x9348, 0x9288, 0x84DC, 0x4FC9, 0x70BB, 0x6631, + 0x68C8, 0x92F9, 0x66FB, 0x5F45, 0x4E28, 0x4EE1, 0x4EFC, 0x4F00, + 0x4F03, 0x4F39, 0x4F56, 0x4F92, 0x4F8A, 0x4F9A, 0x4F94, 0x4FCD, + 0x5040, 0x5022, 0x4FFF, 0x501E, 0x5046, 0x5070, 0x5042, 0x5094, + 0x50F4, 0x50D8, 0x514A, 0x5164, 0x519D, 0x51BE, 0x51EC, 0x5215, + 0x529C, 0x52A6, 0x52C0, 0x52DB, 0x5300, 0x5307, 0x5324, 0x5372, + 0x5393, 0x53B2, 0x53DD, 0xFA0E, 0x549C, 0x548A, 0x54A9, 0x54FF, + 0x5586, 0x5759, 0x5765, 0x57AC, 0x57C8, 0x57C7, 0xFA0F, 0xFA10, + 0x589E, 0x58B2, 0x590B, 0x5953, 0x595B, 0x595D, 0x5963, 0x59A4, + 0x59BA, 0x5B56, 0x5BC0, 0x752F, 0x5BD8, 0x5BEC, 0x5C1E, 0x5CA6, + 0x5CBA, 0x5CF5, 0x5D27, 0x5D53, 0xFA11, 0x5D42, 0x5D6D, 0x5DB8, + 0x5DB9, 0x5DD0, 0x5F21, 0x5F34, 0x5F67, 0x5FB7 + }, + { /* category 90 */ + 0x5FDE, 0x605D, 0x6085, 0x608A, 0x60DE, 0x60D5, 0x6120, 0x60F2, + 0x6111, 0x6137, 0x6130, 0x6198, 0x6213, 0x62A6, 0x63F5, 0x6460, + 0x649D, 0x64CE, 0x654E, 0x6600, 0x6615, 0x663B, 0x6609, 0x662E, + 0x661E, 0x6624, 0x6665, 0x6657, 0x6659, 0xFA12, 0x6673, 0x6699, + 0x66A0, 0x66B2, 0x66BF, 0x66FA, 0x670E, 0xF929, 0x6766, 0x67BB, + 0x6852, 0x67C0, 0x6801, 0x6844, 0x68CF, 0xFA13, 0x6968, 0xFA14, + 0x6998, 0x69E2, 0x6A30, 0x6A6B, 0x6A46, 0x6A73, 0x6A7E, 0x6AE2, + 0x6AE4, 0x6BD6, 0x6C3F, 0x6C5C, 0x6C86, 0x6C6F, 0x6CDA, 0x6D04, + 0x6D87, 0x6D6F, 0x6D96, 0x6DAC, 0x6DCF, 0x6DF8, 0x6DF2, 0x6DFC, + 0x6E39, 0x6E5C, 0x6E27, 0x6E3C, 0x6EBF, 0x6F88, 0x6FB5, 0x6FF5, + 0x7005, 0x7007, 0x7028, 0x7085, 0x70AB, 0x710F, 0x7104, 0x715C, + 0x7146, 0x7147, 0xFA15, 0x71C1, 0x71FE, 0x72B1 + }, + { /* category 91 */ + 0x72BE, 0x7324, 0xFA16, 0x7377, 0x73BD, 0x73C9, 0x73D6, 0x73E3, + 0x73D2, 0x7407, 0x73F5, 0x7426, 0x742A, 0x7429, 0x742E, 0x7462, + 0x7489, 0x749F, 0x7501, 0x756F, 0x7682, 0x769C, 0x769E, 0x769B, + 0x76A6, 0xFA17, 0x7746, 0x52AF, 0x7821, 0x784E, 0x7864, 0x787A, + 0x7930, 0xFA18, 0xFA19, 0xFA1A, 0x7994, 0xFA1B, 0x799B, 0x7AD1, + 0x7AE7, 0xFA1C, 0x7AEB, 0x7B9E, 0xFA1D, 0x7D48, 0x7D5C, 0x7DB7, + 0x7DA0, 0x7DD6, 0x7E52, 0x7F47, 0x7FA1, 0xFA1E, 0x8301, 0x8362, + 0x837F, 0x83C7, 0x83F6, 0x8448, 0x84B4, 0x8553, 0x8559, 0x856B, + 0xFA1F, 0x85B0, 0xFA20, 0xFA21, 0x8807, 0x88F5, 0x8A12, 0x8A37, + 0x8A79, 0x8AA7, 0x8ABE, 0x8ADF, 0xFA22, 0x8AF6, 0x8B53, 0x8B7F, + 0x8CF0, 0x8CF4, 0x8D12, 0x8D76, 0xFA23, 0x8ECF, 0xFA24, 0xFA25, + 0x9067, 0x90DE, 0xFA26, 0x9115, 0x9127, 0x91DA + }, + { /* category 92 */ + 0x91D7, 0x91DE, 0x91ED, 0x91EE, 0x91E4, 0x91E5, 0x9206, 0x9210, + 0x920A, 0x923A, 0x9240, 0x923C, 0x924E, 0x9259, 0x9251, 0x9239, + 0x9267, 0x92A7, 0x9277, 0x9278, 0x92E7, 0x92D7, 0x92D9, 0x92D0, + 0xFA27, 0x92D5, 0x92E0, 0x92D3, 0x9325, 0x9321, 0x92FB, 0xFA28, + 0x931E, 0x92FF, 0x931D, 0x9302, 0x9370, 0x9357, 0x93A4, 0x93C6, + 0x93DE, 0x93F8, 0x9431, 0x9445, 0x9448, 0x9592, 0xF9DC, 0xFA29, + 0x969D, 0x96AF, 0x9733, 0x973B, 0x9743, 0x974D, 0x974F, 0x9751, + 0x9755, 0x9857, 0x9865, 0xFA2A, 0xFA2B, 0x9927, 0xFA2C, 0x999E, + 0x9A4E, 0x9AD9, 0x9ADC, 0x9B75, 0x9B72, 0x9B8F, 0x9BB1, 0x9BBB, + 0x9C00, 0x9D70, 0x9D6B, 0xFA2D, 0x9E19, 0x9ED1, 0x0000, 0x0000, + 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, + 0x2178, 0x2179, 0xFFE2, 0xFFE4, 0xFF07, 0xFF02 + } + }; + +#ifdef __cplusplus +} +#endif + +#endif /* JISX0208_H */ diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/wbmp.h b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/wbmp.h new file mode 100644 index 0000000000..9a93d6ebf0 --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/include/wbmp.h @@ -0,0 +1,51 @@ + /* WBMP + * ---- + * WBMP Level 0: B/W, Uncompressed + * This implements the WBMP format as specified in WAPSpec 1.1 and 1.2. + * It does not support ExtHeaders as defined in the spec. The spec states + * that a WAP client does not need to implement ExtHeaders. + * + * (c) 2000 Johan Van den Brande + * + * Header file + */ +#ifndef __WBMP_H +#define __WBMP_H 1 + +#ifdef __cplusplus +extern "C" { +#endif + + /* WBMP struct + * ----------- + * A Wireless bitmap structure + */ + + typedef struct Wbmp_ { + int type; /* type of the wbmp */ + int width; /* width of the image */ + int height; /* height of the image */ + int *bitmap;/* pointer to data: 0 = WHITE , 1 = BLACK */ + } + Wbmp; + +#define WBMP_WHITE 1 +#define WBMP_BLACK 0 + + /* Proto's + * ------- + */ + void putmbi(int i, void (*putout)(int c, void *out), void *out); + int getmbi(int (*getin)(void *in), void *in); + int skipheader(int (*getin)(void *in), void *in); + Wbmp *createwbmp(int width, int height, int color); + int readwbmp(int (*getin)(void *in), void *in, Wbmp **wbmp); + int writewbmp(Wbmp *wbmp, void (*putout)(int c, void *out), void *out); + void freewbmp(Wbmp *wbmp); + void printwbmp(Wbmp *wbmp); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/lib/.gitkeep b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/lib/.gitkeep new file mode 100644 index 0000000000..48cdce8528 --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/lib/.gitkeep @@ -0,0 +1 @@ +placeholder diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/lib/libgd.a b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/lib/libgd.a new file mode 100644 index 0000000000..7d6b62e32e Binary files /dev/null and b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/lib/libgd.a differ diff --git a/packages/php-wasm/compile/libgd/jspi/dist/root/lib/lib/pkgconfig/gdlib.pc b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/lib/pkgconfig/gdlib.pc new file mode 100644 index 0000000000..6c81e37cd6 --- /dev/null +++ b/packages/php-wasm/compile/libgd/jspi/dist/root/lib/lib/pkgconfig/gdlib.pc @@ -0,0 +1,11 @@ +prefix=/root/lib +exec_prefix=${prefix} +libdir=${exec_prefix}/lib +includedir=${prefix}/include + +Name: gdlib +Description: GD graphics library +Version: 2.3.3 +Requires.private: libpng libjpeg libwebp libavif zlib +Libs: -L${libdir} -lgd -lpng16 -lz -ljpeg -lwebp -lsharpyuv -lavif +Cflags: -I${includedir} diff --git a/packages/php-wasm/compile/libgd/libavifConfig.cmake b/packages/php-wasm/compile/libgd/libavifConfig.cmake new file mode 100644 index 0000000000..4579ca1547 --- /dev/null +++ b/packages/php-wasm/compile/libgd/libavifConfig.cmake @@ -0,0 +1,34 @@ +# Minimal libavif config file for static build in php-wasm +set(PACKAGE_VERSION "0.8.2") + +if(PACKAGE_FIND_VERSION) + if(PACKAGE_FIND_VERSION_EXACT) + if(PACKAGE_VERSION VERSION_EQUAL PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + else() + set(PACKAGE_VERSION_EXACT FALSE) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + endif() + else() + if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + set(PACKAGE_VERSION_EXACT FALSE) + endif() + endif() +endif() + +if(NOT TARGET avif) + add_library(avif STATIC IMPORTED) + set_target_properties(avif PROPERTIES + IMPORTED_LOCATION "/root/lib/lib/libavif.a" + INTERFACE_INCLUDE_DIRECTORIES "/root/lib/include" + ) +endif() +if(NOT TARGET avif::avif) + add_library(avif::avif ALIAS avif) +endif() +set(libavif_VERSION "${PACKAGE_VERSION}") +set(libavif_FOUND TRUE) diff --git a/packages/php-wasm/compile/libgd/libavifConfigVersion.cmake b/packages/php-wasm/compile/libgd/libavifConfigVersion.cmake new file mode 100644 index 0000000000..8c543de3cd --- /dev/null +++ b/packages/php-wasm/compile/libgd/libavifConfigVersion.cmake @@ -0,0 +1,20 @@ +set(PACKAGE_VERSION "0.8.2") + +# Determine compatibility +if(PACKAGE_FIND_VERSION) + if(PACKAGE_FIND_VERSION_EXACT) + if(PACKAGE_VERSION VERSION_EQUAL PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + else() + set(PACKAGE_VERSION_EXACT FALSE) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + endif() + else() + if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + endif() + endif() +endif() diff --git a/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/cmake/libjpeg-turbo/libjpeg-turboConfig.cmake b/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/cmake/libjpeg-turbo/libjpeg-turboConfig.cmake new file mode 100644 index 0000000000..b637f86f0d --- /dev/null +++ b/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/cmake/libjpeg-turbo/libjpeg-turboConfig.cmake @@ -0,0 +1,28 @@ + +####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() ####### +####### Any changes to this file will be overwritten by the next CMake run #### +####### The input file was Config.cmake.in ######## + +get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE) + +macro(set_and_check _var _file) + set(${_var} "${_file}") + if(NOT EXISTS "${_file}") + message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !") + endif() +endmacro() + +macro(check_required_components _NAME) + foreach(comp ${${_NAME}_FIND_COMPONENTS}) + if(NOT ${_NAME}_${comp}_FOUND) + if(${_NAME}_FIND_REQUIRED_${comp}) + set(${_NAME}_FOUND FALSE) + endif() + endif() + endforeach() +endmacro() + +#################################################################################### + +include("${CMAKE_CURRENT_LIST_DIR}/libjpeg-turboTargets.cmake") +check_required_components("libjpeg-turbo") diff --git a/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/cmake/libjpeg-turbo/libjpeg-turboConfigVersion.cmake b/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/cmake/libjpeg-turbo/libjpeg-turboConfigVersion.cmake new file mode 100644 index 0000000000..1a6966843f --- /dev/null +++ b/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/cmake/libjpeg-turbo/libjpeg-turboConfigVersion.cmake @@ -0,0 +1,43 @@ +# This is a basic version file for the Config-mode of find_package(). +# It is used by write_basic_package_version_file() as input file for configure_file() +# to create a version-file which can be installed along a config.cmake file. +# +# The created file sets PACKAGE_VERSION_EXACT if the current version string and +# the requested version string are exactly the same and it sets +# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version. +# The variable CVF_VERSION must be set before calling configure_file(). + +set(PACKAGE_VERSION "3.0.3") + +if (PACKAGE_FIND_VERSION_RANGE) + # Package version must be in the requested version range + if ((PACKAGE_FIND_VERSION_RANGE_MIN STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION_MIN) + OR ((PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "INCLUDE" AND PACKAGE_VERSION VERSION_GREATER PACKAGE_FIND_VERSION_MAX) + OR (PACKAGE_FIND_VERSION_RANGE_MAX STREQUAL "EXCLUDE" AND PACKAGE_VERSION VERSION_GREATER_EQUAL PACKAGE_FIND_VERSION_MAX))) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + endif() +else() + if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_COMPATIBLE FALSE) + else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + endif() + endif() +endif() + + +# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it: +if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "4" STREQUAL "") + return() +endif() + +# check that the installed version has the same 32/64bit-ness as the one which is currently searching: +if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "4") + math(EXPR installedBits "4 * 8") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) +endif() diff --git a/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/cmake/libjpeg-turbo/libjpeg-turboTargets-release.cmake b/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/cmake/libjpeg-turbo/libjpeg-turboTargets-release.cmake new file mode 100644 index 0000000000..1aa258ec86 --- /dev/null +++ b/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/cmake/libjpeg-turbo/libjpeg-turboTargets-release.cmake @@ -0,0 +1,49 @@ +#---------------------------------------------------------------- +# Generated CMake target import file for configuration "Release". +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "libjpeg-turbo::jpeg" for configuration "Release" +set_property(TARGET libjpeg-turbo::jpeg APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(libjpeg-turbo::jpeg PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib32/libjpeg.a" + ) + +list(APPEND _cmake_import_check_targets libjpeg-turbo::jpeg ) +list(APPEND _cmake_import_check_files_for_libjpeg-turbo::jpeg "${_IMPORT_PREFIX}/lib32/libjpeg.a" ) + +# Import target "libjpeg-turbo::turbojpeg" for configuration "Release" +set_property(TARGET libjpeg-turbo::turbojpeg APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(libjpeg-turbo::turbojpeg PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib32/libturbojpeg.a" + ) + +list(APPEND _cmake_import_check_targets libjpeg-turbo::turbojpeg ) +list(APPEND _cmake_import_check_files_for_libjpeg-turbo::turbojpeg "${_IMPORT_PREFIX}/lib32/libturbojpeg.a" ) + +# Import target "libjpeg-turbo::turbojpeg-static" for configuration "Release" +set_property(TARGET libjpeg-turbo::turbojpeg-static APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(libjpeg-turbo::turbojpeg-static PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib32/libturbojpeg.a" + ) + +list(APPEND _cmake_import_check_targets libjpeg-turbo::turbojpeg-static ) +list(APPEND _cmake_import_check_files_for_libjpeg-turbo::turbojpeg-static "${_IMPORT_PREFIX}/lib32/libturbojpeg.a" ) + +# Import target "libjpeg-turbo::jpeg-static" for configuration "Release" +set_property(TARGET libjpeg-turbo::jpeg-static APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) +set_target_properties(libjpeg-turbo::jpeg-static PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib32/libjpeg.a" + ) + +list(APPEND _cmake_import_check_targets libjpeg-turbo::jpeg-static ) +list(APPEND _cmake_import_check_files_for_libjpeg-turbo::jpeg-static "${_IMPORT_PREFIX}/lib32/libjpeg.a" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/cmake/libjpeg-turbo/libjpeg-turboTargets.cmake b/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/cmake/libjpeg-turbo/libjpeg-turboTargets.cmake new file mode 100644 index 0000000000..bff9dda653 --- /dev/null +++ b/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/cmake/libjpeg-turbo/libjpeg-turboTargets.cmake @@ -0,0 +1,123 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8) + message(FATAL_ERROR "CMake >= 2.8.0 required") +endif() +if(CMAKE_VERSION VERSION_LESS "2.8.3") + message(FATAL_ERROR "CMake >= 2.8.3 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.8.3...3.26) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_cmake_targets_defined "") +set(_cmake_targets_not_defined "") +set(_cmake_expected_targets "") +foreach(_cmake_expected_target IN ITEMS libjpeg-turbo::jpeg libjpeg-turbo::turbojpeg libjpeg-turbo::turbojpeg-static libjpeg-turbo::jpeg-static) + list(APPEND _cmake_expected_targets "${_cmake_expected_target}") + if(TARGET "${_cmake_expected_target}") + list(APPEND _cmake_targets_defined "${_cmake_expected_target}") + else() + list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}") + endif() +endforeach() +unset(_cmake_expected_target) +if(_cmake_targets_defined STREQUAL _cmake_expected_targets) + unset(_cmake_targets_defined) + unset(_cmake_targets_not_defined) + unset(_cmake_expected_targets) + unset(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT _cmake_targets_defined STREQUAL "") + string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}") + string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n") +endif() +unset(_cmake_targets_defined) +unset(_cmake_targets_not_defined) +unset(_cmake_expected_targets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target libjpeg-turbo::jpeg +add_library(libjpeg-turbo::jpeg STATIC IMPORTED) + +set_target_properties(libjpeg-turbo::jpeg PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include" +) + +# Create imported target libjpeg-turbo::turbojpeg +add_library(libjpeg-turbo::turbojpeg STATIC IMPORTED) + +set_target_properties(libjpeg-turbo::turbojpeg PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include" +) + +# Create imported target libjpeg-turbo::turbojpeg-static +add_library(libjpeg-turbo::turbojpeg-static STATIC IMPORTED) + +set_target_properties(libjpeg-turbo::turbojpeg-static PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include" +) + +# Create imported target libjpeg-turbo::jpeg-static +add_library(libjpeg-turbo::jpeg-static STATIC IMPORTED) + +set_target_properties(libjpeg-turbo::jpeg-static PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include" +) + +# Load information for each installed configuration. +file(GLOB _cmake_config_files "${CMAKE_CURRENT_LIST_DIR}/libjpeg-turboTargets-*.cmake") +foreach(_cmake_config_file IN LISTS _cmake_config_files) + include("${_cmake_config_file}") +endforeach() +unset(_cmake_config_file) +unset(_cmake_config_files) + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(_cmake_target IN LISTS _cmake_import_check_targets) + foreach(_cmake_file IN LISTS "_cmake_import_check_files_for_${_cmake_target}") + if(NOT EXISTS "${_cmake_file}") + message(FATAL_ERROR "The imported target \"${_cmake_target}\" references the file + \"${_cmake_file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + unset(_cmake_file) + unset("_cmake_import_check_files_for_${_cmake_target}") +endforeach() +unset(_cmake_target) +unset(_cmake_import_check_targets) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/libjpeg.a b/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/libjpeg.a new file mode 100644 index 0000000000..b214b0b020 Binary files /dev/null and b/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/libjpeg.a differ diff --git a/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/libturbojpeg.a b/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/libturbojpeg.a new file mode 100644 index 0000000000..6536063e03 Binary files /dev/null and b/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/libturbojpeg.a differ diff --git a/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/pkgconfig/libjpeg.pc b/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/pkgconfig/libjpeg.pc new file mode 100644 index 0000000000..80d68a829c --- /dev/null +++ b/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/pkgconfig/libjpeg.pc @@ -0,0 +1,10 @@ +prefix=/root/lib +exec_prefix=/root/lib +libdir=/root/lib/lib +includedir=/root/lib/include + +Name: libjpeg +Description: A SIMD-accelerated JPEG codec that provides the libjpeg API +Version: 3.0.3 +Libs: -L${libdir} -ljpeg +Cflags: -I${includedir} diff --git a/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/pkgconfig/libturbojpeg.pc b/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/pkgconfig/libturbojpeg.pc new file mode 100644 index 0000000000..d1a8161363 --- /dev/null +++ b/packages/php-wasm/compile/libjpeg/asyncify/dist/root/lib/lib32/pkgconfig/libturbojpeg.pc @@ -0,0 +1,10 @@ +prefix=/root/lib +exec_prefix=/root/lib +libdir=/root/lib/lib32 +includedir=/root/lib/include + +Name: libturbojpeg +Description: A SIMD-accelerated JPEG codec that provides the TurboJPEG API +Version: 3.0.3 +Libs: -L${libdir} -lturbojpeg +Cflags: -I${includedir} diff --git a/packages/php-wasm/compile/libjpeg/jspi/dist/root/lib/lib32/libjpeg.a b/packages/php-wasm/compile/libjpeg/jspi/dist/root/lib/lib32/libjpeg.a index 4653dc5f59..b624739d8a 100644 Binary files a/packages/php-wasm/compile/libjpeg/jspi/dist/root/lib/lib32/libjpeg.a and b/packages/php-wasm/compile/libjpeg/jspi/dist/root/lib/lib32/libjpeg.a differ diff --git a/packages/php-wasm/compile/libjpeg/jspi/dist/root/lib/lib32/libturbojpeg.a b/packages/php-wasm/compile/libjpeg/jspi/dist/root/lib/lib32/libturbojpeg.a index 5a908b8881..5f458873c4 100644 Binary files a/packages/php-wasm/compile/libjpeg/jspi/dist/root/lib/lib32/libturbojpeg.a and b/packages/php-wasm/compile/libjpeg/jspi/dist/root/lib/lib32/libturbojpeg.a differ diff --git a/packages/php-wasm/compile/libwebp/asyncify/dist/root/lib/lib/libz.so.1.2.13 b/packages/php-wasm/compile/libwebp/asyncify/dist/root/lib/lib/libz.so.1.2.13 index 4295fe1e2a..670cf38bca 100755 Binary files a/packages/php-wasm/compile/libwebp/asyncify/dist/root/lib/lib/libz.so.1.2.13 and b/packages/php-wasm/compile/libwebp/asyncify/dist/root/lib/lib/libz.so.1.2.13 differ diff --git a/packages/php-wasm/compile/libwebp/jspi/dist/root/lib/lib/libz.so.1.2.13 b/packages/php-wasm/compile/libwebp/jspi/dist/root/lib/lib/libz.so.1.2.13 index 5424b2742f..daa7b6fafd 100755 Binary files a/packages/php-wasm/compile/libwebp/jspi/dist/root/lib/lib/libz.so.1.2.13 and b/packages/php-wasm/compile/libwebp/jspi/dist/root/lib/lib/libz.so.1.2.13 differ diff --git a/packages/php-wasm/compile/libz/asyncify/dist/root/lib/lib/libz.a b/packages/php-wasm/compile/libz/asyncify/dist/root/lib/lib/libz.a index bc65cf2af4..e598f34306 100644 Binary files a/packages/php-wasm/compile/libz/asyncify/dist/root/lib/lib/libz.a and b/packages/php-wasm/compile/libz/asyncify/dist/root/lib/lib/libz.a differ diff --git a/packages/php-wasm/compile/libz/asyncify/dist/root/lib/lib/libz.so.1.2.13 b/packages/php-wasm/compile/libz/asyncify/dist/root/lib/lib/libz.so.1.2.13 index 4295fe1e2a..670cf38bca 100755 Binary files a/packages/php-wasm/compile/libz/asyncify/dist/root/lib/lib/libz.so.1.2.13 and b/packages/php-wasm/compile/libz/asyncify/dist/root/lib/lib/libz.so.1.2.13 differ diff --git a/packages/php-wasm/compile/libz/jspi/dist/root/lib/lib/libz.a b/packages/php-wasm/compile/libz/jspi/dist/root/lib/lib/libz.a index e91adcb798..fa8972f69e 100644 Binary files a/packages/php-wasm/compile/libz/jspi/dist/root/lib/lib/libz.a and b/packages/php-wasm/compile/libz/jspi/dist/root/lib/lib/libz.a differ diff --git a/packages/php-wasm/compile/libz/jspi/dist/root/lib/lib/libz.so.1.2.13 b/packages/php-wasm/compile/libz/jspi/dist/root/lib/lib/libz.so.1.2.13 index 5424b2742f..daa7b6fafd 100755 Binary files a/packages/php-wasm/compile/libz/jspi/dist/root/lib/lib/libz.so.1.2.13 and b/packages/php-wasm/compile/libz/jspi/dist/root/lib/lib/libz.so.1.2.13 differ diff --git a/packages/php-wasm/compile/php/Dockerfile b/packages/php-wasm/compile/php/Dockerfile index 41a363d390..9970c5fb49 100644 --- a/packages/php-wasm/compile/php/Dockerfile +++ b/packages/php-wasm/compile/php/Dockerfile @@ -1,6 +1,8 @@ FROM playground-php-wasm:base ARG WITH_JSPI="no" +ENV PKG_CONFIG_PATH=/root/lib/lib/pkgconfig +ENV PATH="/root/lib/bin:${PATH}" # The PHP version to build. # This value must point to an existing branch of the @@ -17,7 +19,7 @@ ARG WITH_OPCACHE # Clone PHP RUN git clone https://github.com/php/php-src.git php-src \ --branch PHP-$PHP_VERSION \ - --single-branch \ + --single-branch \ --depth 1; # Work around memory leak due to PHP using Emscripten's incomplete mmap/munmap support @@ -49,11 +51,12 @@ COPY ./libz/ /root/builds/libz COPY ./oniguruma/ /root/builds/oniguruma COPY ./libintl/ /root/builds/libintl COPY ./libImageMagick/ /root/builds/libImageMagick +COPY ./libgd/ /root/builds/libgd RUN if [ "$WITH_JSPI" = "yes" ]; then \ - cp -r /root/builds/*/jspi/dist/root/lib/* /root/lib; \ + find /root/builds -path '*/jspi/dist/root/lib' -type d -exec cp -r {}/. /root/lib \; ; \ else \ - cp -r /root/builds/*/asyncify/dist/root/lib/* /root/lib; \ + find /root/builds -path '*/asyncify/dist/root/lib' -type d -exec cp -r {}/. /root/lib \; ; \ fi COPY ./libzip/ /root/builds-libzip/ @@ -254,27 +257,28 @@ RUN if [ "$WITH_SQLITE" = "yes" ]; \ # Add GD if needed RUN if [ "$WITH_GD" = "yes" ]; \ then \ - if [[ "${PHP_VERSION:0:1}" -eq "7" ]] && [ "${PHP_VERSION:0:3}" != "7.4" ]; then \ - # @TODO support webp for PHP 7.0 – 7.3 - echo -n ' --with-png-dir=/root/lib --with-jpeg-dir=/root/lib --with-gd --enable-gd ' >> /root/.php-configure-flags; \ - else \ + # Use external libgd for PHP 8.1+; fall back to bundled gd for <= 8.0 (and 7.x) to avoid missing symbols + if [[ "${PHP_VERSION:0:1}" -gt "8" || ( "${PHP_VERSION:0:1}" -eq "8" && "${PHP_VERSION:2:1}" -ge "1" ) ]]; then \ + echo -n ' --with-external-gd=/root/lib --enable-gd ' >> /root/.php-configure-flags; \ + echo -n ' /root/lib/lib/libgd.a /root/lib/lib/libjpeg.a /root/lib/lib/libpng16.a /root/lib/lib/libwebp.a /root/lib/lib/libsharpyuv.a /root/lib/lib/libavif.a ' >> /root/.emcc-php-wasm-sources; \ if [[ "${PHP_VERSION:0:1}" -eq "8" && "${PHP_VERSION:2:1}" -ge "1" ]]; then \ echo -n ' --with-avif ' >> /root/.php-configure-flags; \ fi; \ - echo -n ' --with-png-dir=/root/lib --with-jpeg --with-webp --with-gd --enable-gd ' >> /root/.php-configure-flags; \ - fi; \ - - if [[ "${PHP_VERSION:0:1}" -le "7" && "${PHP_VERSION:2:1}" -le "4" ]]; then \ - /root/replace.sh 's/static long php_jpeg_emit_message/static void php_jpeg_emit_message/g' /root/php-src/ext/gd/libgd/gd_jpeg.c; \ - sed -i '84s/.*return 1;.*//' /root/php-src/ext/gd/libgd/gd_jpeg.c; \ - /root/replace.sh 's/cinfo.err->emit_message = \(void \(*\)\(j_common_ptr,int\)\) php_jpeg_emit_message;/cinfo.err->emit_message = php_jpeg_emit_message;/g' /root/php-src/ext/gd/libgd/gd_jpeg.c; \ - fi; \ - - if [[ "${PHP_VERSION:0:1}" -eq "8" && "${PHP_VERSION:2:1}" -ge "1" ]]; then \ - echo -n ' /root/lib/lib/libjpeg.a /root/lib/lib/libpng16.a /root/lib/lib/libwebp.a /root/lib/lib/libsharpyuv.a /root/lib/lib/libavif.a ' >> /root/.emcc-php-wasm-sources; \ else \ + # Bundled gd for PHP 7.x and 8.0 + echo -n ' --enable-gd ' >> /root/.php-configure-flags; \ + if [[ "${PHP_VERSION:0:1}" -eq "7" ]] && [ "${PHP_VERSION:0:3}" != "7.4" ]; then \ + # PHP 7.0 – 7.3 need older-style flags + echo -n ' --with-png-dir=/root/lib --with-jpeg-dir=/root/lib --with-gd ' >> /root/.php-configure-flags; \ + fi; \ + if [[ "${PHP_VERSION:0:1}" -le "7" && "${PHP_VERSION:2:1}" -le "4" ]]; then \ + /root/replace.sh 's/static long php_jpeg_emit_message/static void php_jpeg_emit_message/g' /root/php-src/ext/gd/libgd/gd_jpeg.c; \ + sed -i '84s/.*return 1;.*//' /root/php-src/ext/gd/libgd/gd_jpeg.c; \ + /root/replace.sh 's/cinfo.err->emit_message = \(void \(*\)\(j_common_ptr,int\)\) php_jpeg_emit_message;/cinfo.err->emit_message = php_jpeg_emit_message;/g' /root/php-src/ext/gd/libgd/gd_jpeg.c; \ + fi; \ echo -n ' /root/lib/lib/libjpeg.a /root/lib/lib/libpng16.a /root/lib/lib/libwebp.a /root/lib/lib/libsharpyuv.a ' >> /root/.emcc-php-wasm-sources; \ fi; \ + echo -n ' --with-png-dir=/root/lib --with-jpeg --with-webp ' >> /root/.php-configure-flags; \ fi; # Add openssl if needed @@ -379,6 +383,13 @@ COPY ./php/php*.patch /root/ COPY ./php/apply-mysqlnd-patch.sh /root/ RUN cd /root && \ git apply --no-index /root/php${PHP_VERSION:0:3}*.patch -v && \ + if [[ "${PHP_VERSION:0:3}" == "7.3" || "${PHP_VERSION:0:3}" == "7.2" ]]; then \ + # Emscripten >= 4.0.19 Does not tolerate implicit declarations of strcmp/strchr/memcpy with clang >= C99. + # Let's backfill the required includes. + sed -i '1i#include ' /root/php-src/ext/mbstring/libmbfl/filters/mbfilter_htmlent.c; \ + sed -i '1i#include ' /root/php-src/ext/mbstring/libmbfl/mbfl/mbfilter.c; \ + sed -i '1i#include ' /root/php-src/ext/mbstring/libmbfl/mbfl/mbfl_allocators.c; \ + fi && \ chmod +x /root/apply-mysqlnd-patch.sh && \ /root/apply-mysqlnd-patch.sh && \ ( [[ "${PHP_VERSION:0:3}" == '8.3' ]] && \ @@ -430,13 +441,22 @@ RUN /root/replace.sh 's/pharcmd=pharcmd/pharcmd=/g' /root/php-src/configure && \ # Build the patched PHP WORKDIR /root/php-src RUN source /root/emsdk/emsdk_env.sh && \ -ICU_CFLAGS="-D__x86_64__ -fPIC -I/root/lib/include" \ -CURL_CFLAGS="-I/root/lib/include" \ -WEBP_LIBS="-L/root/lib/lib" \ -WEBP_CFLAGS="-I/root/lib/include" \ -CURL_LIBS="-I/root/lib/lib -L/root/lib/lib" \ - emconfigure ./configure \ - PKG_CONFIG_PATH=$PKG_CONFIG_PATH \ + ICU_CFLAGS="-D__x86_64__ -fPIC -I/root/lib/include" \ + CURL_CFLAGS="-I/root/lib/include" \ + WEBP_LIBS="-L/root/lib/lib -lwebp -lsharpyuv" \ + WEBP_CFLAGS="-I/root/lib/include" \ + CURL_LIBS="-I/root/lib/lib -L/root/lib/lib" \ + JPEG_CFLAGS="-I/root/lib/include" \ + JPEG_LIBS="-L/root/lib/lib -ljpeg" \ + PNG_CFLAGS="-I/root/lib/include" \ + PNG_LIBS="-L/root/lib/lib -lpng16 -lz" \ + AVIF_CFLAGS="-I/root/lib/include" \ + AVIF_LIBS="-L/root/lib/lib -lavif" \ + GDLIB_CFLAGS="-I/root/lib/include" \ + GDLIB_LIBS="-L/root/lib/lib -lgd -lpng16 -lz -ljpeg -lwebp -lsharpyuv -lavif" \ + PKG_CONFIG_PATH="/root/lib/lib/pkgconfig:${PKG_CONFIG_PATH}" \ + emconfigure ./configure \ + PKG_CONFIG_PATH=$PKG_CONFIG_PATH \ # Fibers are a PHP 8.1+ feature. They are compiled as # a custom assembly implementation by default. However, # that implementation does not work with emscripten. @@ -478,6 +498,27 @@ CURL_LIBS="-I/root/lib/lib -L/root/lib/lib" \ # @TODO: Identify the root cause behind these errors and fix them properly RUN echo '#define ZEND_MM_ERROR 0' >> /root/php-src/main/php_config.h; +# Force GD JPEG/PNG/WebP/AVIF support for external GD builds (PHP 8.1+) +# Configure checks may fail during cross-compilation, so we explicitly enable them +# after verifying the external libgd was built with these features. +RUN if [ "$WITH_GD" = "yes" ]; then \ + if [[ "${PHP_VERSION:0:1}" -gt "8" || ( "${PHP_VERSION:0:1}" -eq "8" && "${PHP_VERSION:2:1}" -ge "1" ) ]]; then \ + echo '/* Force GD format support for external libgd */' >> /root/php-src/main/php_config.h; \ + echo '#ifndef HAVE_GD_JPG' >> /root/php-src/main/php_config.h; \ + echo '#define HAVE_GD_JPG 1' >> /root/php-src/main/php_config.h; \ + echo '#endif' >> /root/php-src/main/php_config.h; \ + echo '#ifndef HAVE_GD_PNG' >> /root/php-src/main/php_config.h; \ + echo '#define HAVE_GD_PNG 1' >> /root/php-src/main/php_config.h; \ + echo '#endif' >> /root/php-src/main/php_config.h; \ + echo '#ifndef HAVE_GD_WEBP' >> /root/php-src/main/php_config.h; \ + echo '#define HAVE_GD_WEBP 1' >> /root/php-src/main/php_config.h; \ + echo '#endif' >> /root/php-src/main/php_config.h; \ + echo '#ifndef HAVE_GD_AVIF' >> /root/php-src/main/php_config.h; \ + echo '#define HAVE_GD_AVIF 1' >> /root/php-src/main/php_config.h; \ + echo '#endif' >> /root/php-src/main/php_config.h; \ + fi; \ +fi; + # 64 bit long support {{{ # PHP uses custom typedefs for 64 bit integers in many places, e.g. # timelib_long is int64_t when __x86_64__ is defined and int32_t otherwise. @@ -581,7 +622,7 @@ RUN source /root/emsdk/emsdk_env.sh && \ -fdebug-compilation-dir=${DEBUG_DWARF_COMPILATION_DIR}/ \ -fdebug-prefix-map=/root/php-src/=${OUTPUT_DIR_ON_HOST}/${PHP_VERSION_ESCAPED}/php-src/ " \ # ...which means we must skip all the libraries - they will be provided in the final linking step. - emmake make -j1 + emmake make -j14 RUN cp -v /root/php-src/.libs/libphp*.la /root/lib/libphp.la RUN cp -v /root/php-src/.libs/libphp*.a /root/lib/libphp.a diff --git a/packages/php-wasm/node/asyncify/7_2_34/php_7_2.wasm b/packages/php-wasm/node/asyncify/7_2_34/php_7_2.wasm index 687fc0827a..9c220fa8a0 100755 Binary files a/packages/php-wasm/node/asyncify/7_2_34/php_7_2.wasm and b/packages/php-wasm/node/asyncify/7_2_34/php_7_2.wasm differ diff --git a/packages/php-wasm/node/asyncify/7_3_33/php_7_3.wasm b/packages/php-wasm/node/asyncify/7_3_33/php_7_3.wasm index f4d6257ae9..e1816ff588 100755 Binary files a/packages/php-wasm/node/asyncify/7_3_33/php_7_3.wasm and b/packages/php-wasm/node/asyncify/7_3_33/php_7_3.wasm differ diff --git a/packages/php-wasm/node/asyncify/7_4_33/php_7_4.wasm b/packages/php-wasm/node/asyncify/7_4_33/php_7_4.wasm index 4cd024454c..c90c8845b1 100755 Binary files a/packages/php-wasm/node/asyncify/7_4_33/php_7_4.wasm and b/packages/php-wasm/node/asyncify/7_4_33/php_7_4.wasm differ diff --git a/packages/php-wasm/node/asyncify/8_0_30/php_8_0.wasm b/packages/php-wasm/node/asyncify/8_0_30/php_8_0.wasm index ee178d3e2d..b0a781e1a2 100755 Binary files a/packages/php-wasm/node/asyncify/8_0_30/php_8_0.wasm and b/packages/php-wasm/node/asyncify/8_0_30/php_8_0.wasm differ diff --git a/packages/php-wasm/node/asyncify/8_1_33/php_8_1.wasm b/packages/php-wasm/node/asyncify/8_1_33/php_8_1.wasm index 78ed5c1330..5945b28f05 100755 Binary files a/packages/php-wasm/node/asyncify/8_1_33/php_8_1.wasm and b/packages/php-wasm/node/asyncify/8_1_33/php_8_1.wasm differ diff --git a/packages/php-wasm/node/asyncify/8_2_29/php_8_2.wasm b/packages/php-wasm/node/asyncify/8_2_29/php_8_2.wasm index a3cb5e465c..7dd2fcd711 100755 Binary files a/packages/php-wasm/node/asyncify/8_2_29/php_8_2.wasm and b/packages/php-wasm/node/asyncify/8_2_29/php_8_2.wasm differ diff --git a/packages/php-wasm/node/asyncify/8_3_28/php_8_3.wasm b/packages/php-wasm/node/asyncify/8_3_28/php_8_3.wasm index ff84927d5b..02eff4da2e 100755 Binary files a/packages/php-wasm/node/asyncify/8_3_28/php_8_3.wasm and b/packages/php-wasm/node/asyncify/8_3_28/php_8_3.wasm differ diff --git a/packages/php-wasm/node/asyncify/8_4_15/php_8_4.wasm b/packages/php-wasm/node/asyncify/8_4_15/php_8_4.wasm index 5e27b2f032..bdbadc2ee6 100755 Binary files a/packages/php-wasm/node/asyncify/8_4_15/php_8_4.wasm and b/packages/php-wasm/node/asyncify/8_4_15/php_8_4.wasm differ diff --git a/packages/php-wasm/node/asyncify/php_7_2.js b/packages/php-wasm/node/asyncify/php_7_2.js index 265cb579bf..bc0f927092 100644 --- a/packages/php-wasm/node/asyncify/php_7_2.js +++ b/packages/php-wasm/node/asyncify/php_7_2.js @@ -7,35435 +7,32019 @@ const require = createRequire(import.meta.url); import path from 'path'; const dependencyFilename = path.join(__dirname, '7_2_34', 'php_7_2.wasm'); -export { dependencyFilename }; -export const dependenciesTotalSize = 22632140; +export { dependencyFilename }; +export const dependenciesTotalSize = 22632172; const phpVersionString = '7.2.34'; export function init(RuntimeName, PHPLoader) { - // The rest of the code comes from the built php.js file and esm-suffix.js - // include: shell.js - // include: minimum_runtime_check.js - // end include: minimum_runtime_check.js - // The Module object: Our interface to the outside world. We import - // and export values on it. There are various ways Module can be used: - // 1. Not defined. We create it here - // 2. A function parameter, function(moduleArg) => Promise - // 3. pre-run appended it, var Module = {}; ..generated code.. - // 4. External script tag defines var Module. - // We need to check if Module already exists (e.g. case 3 above). - // Substitution will be replaced with actual code on later stage of the build, - // this way Closure Compiler will not mangle it (e.g. case 4. above). - // Note that if you want to run closure, and also to use Module - // after the generated code, you will need to define var Module = {}; - // before the code. Then that object will be used in the code, and you - // can continue to use Module afterwards as well. - var Module = typeof PHPLoader != 'undefined' ? PHPLoader : {}; - - // Determine the runtime environment we are in. You can customize this by - // setting the ENVIRONMENT setting at compile time (see settings.js). - - var ENVIRONMENT_IS_WEB = RuntimeName === 'WEB'; - var ENVIRONMENT_IS_WORKER = RuntimeName === 'WORKER'; - var ENVIRONMENT_IS_NODE = RuntimeName === 'NODE'; - var ENVIRONMENT_IS_SHELL = RuntimeName === 'SHELL'; - - // --pre-jses are emitted after the Module integration code, so that they can - // refer to Module (if they choose; they can also define Module) - - var arguments_ = []; - var thisProgram = './this.program'; - var quit_ = (status, toThrow) => { - throw toThrow; - }; - - var _scriptName; - - if (typeof __filename != 'undefined') { - // Node - _scriptName = __filename; - } else { - /*no-op*/ - } - - // `/` should be present at the end if `scriptDirectory` is not empty - var scriptDirectory = ''; - function locateFile(path) { - if (Module['locateFile']) { - return Module['locateFile'](path, scriptDirectory); - } - return scriptDirectory + path; - } - - // Hooks that are implemented differently in different runtime environments. - var readAsync, readBinary; - - if (ENVIRONMENT_IS_NODE) { - // These modules will usually be used on Node.js. Load them eagerly to avoid - // the complexity of lazy-loading. - var fs = require('fs'); - - scriptDirectory = __dirname + '/'; - - // include: node_shell_read.js - readBinary = (filename) => { - // We need to re-wrap `file://` strings to URLs. - filename = isFileURI(filename) ? new URL(filename) : filename; - var ret = fs.readFileSync(filename); - return ret; - }; - - readAsync = async (filename, binary = true) => { - // See the comment in the `readBinary` function. - filename = isFileURI(filename) ? new URL(filename) : filename; - var ret = fs.readFileSync(filename, binary ? undefined : 'utf8'); - return ret; - }; - // end include: node_shell_read.js - if (process.argv.length > 1) { - thisProgram = process.argv[1].replace(/\\/g, '/'); - } - - arguments_ = process.argv.slice(2); - - // MODULARIZE will export the module in the proper place outside, we don't need to export here - if (typeof module != 'undefined') { - module['exports'] = Module; - } - - quit_ = (status, toThrow) => { - process.exitCode = status; - throw toThrow; - }; - } + // The rest of the code comes from the built php.js file and esm-suffix.js +// include: shell.js +// include: minimum_runtime_check.js +// end include: minimum_runtime_check.js +// The Module object: Our interface to the outside world. We import +// and export values on it. There are various ways Module can be used: +// 1. Not defined. We create it here +// 2. A function parameter, function(moduleArg) => Promise +// 3. pre-run appended it, var Module = {}; ..generated code.. +// 4. External script tag defines var Module. +// We need to check if Module already exists (e.g. case 3 above). +// Substitution will be replaced with actual code on later stage of the build, +// this way Closure Compiler will not mangle it (e.g. case 4. above). +// Note that if you want to run closure, and also to use Module +// after the generated code, you will need to define var Module = {}; +// before the code. Then that object will be used in the code, and you +// can continue to use Module afterwards as well. +var Module = typeof PHPLoader != 'undefined' ? PHPLoader : {}; + +// Determine the runtime environment we are in. You can customize this by +// setting the ENVIRONMENT setting at compile time (see settings.js). + +var ENVIRONMENT_IS_WEB=RuntimeName==="WEB"; +var ENVIRONMENT_IS_WORKER=RuntimeName==="WORKER"; +var ENVIRONMENT_IS_NODE=RuntimeName==="NODE"; +var ENVIRONMENT_IS_SHELL=RuntimeName==="SHELL"; + +// --pre-jses are emitted after the Module integration code, so that they can +// refer to Module (if they choose; they can also define Module) + + +var arguments_ = []; +var thisProgram = './this.program'; +var quit_ = (status, toThrow) => { + throw toThrow; +}; + +var _scriptName; + +if (typeof __filename != 'undefined') { // Node + _scriptName = __filename; +} else + /*no-op*/{} + +// `/` should be present at the end if `scriptDirectory` is not empty +var scriptDirectory = ''; +function locateFile(path) { + if (Module['locateFile']) { + return Module['locateFile'](path, scriptDirectory); + } + return scriptDirectory + path; +} - // Note that this includes Node.js workers when relevant (pthreads is enabled). - // Node.js workers are detected as a combination of ENVIRONMENT_IS_WORKER and - // ENVIRONMENT_IS_NODE. - else { - } +// Hooks that are implemented differently in different runtime environments. +var readAsync, readBinary; + +if (ENVIRONMENT_IS_NODE) { + + // These modules will usually be used on Node.js. Load them eagerly to avoid + // the complexity of lazy-loading. + var fs = require('fs'); + + scriptDirectory = __dirname + '/'; + +// include: node_shell_read.js +readBinary = (filename) => { + // We need to re-wrap `file://` strings to URLs. + filename = isFileURI(filename) ? new URL(filename) : filename; + var ret = fs.readFileSync(filename); + return ret; +}; + +readAsync = async (filename, binary = true) => { + // See the comment in the `readBinary` function. + filename = isFileURI(filename) ? new URL(filename) : filename; + var ret = fs.readFileSync(filename, binary ? undefined : 'utf8'); + return ret; +}; +// end include: node_shell_read.js + if (process.argv.length > 1) { + thisProgram = process.argv[1].replace(/\\/g, '/'); + } + + arguments_ = process.argv.slice(2); + + // MODULARIZE will export the module in the proper place outside, we don't need to export here + if (typeof module != 'undefined') { + module['exports'] = Module; + } + + quit_ = (status, toThrow) => { + process.exitCode = status; + throw toThrow; + }; + +} else + +// Note that this includes Node.js workers when relevant (pthreads is enabled). +// Node.js workers are detected as a combination of ENVIRONMENT_IS_WORKER and +// ENVIRONMENT_IS_NODE. +{ +} - var out = console.log.bind(console); - var err = console.error.bind(console); - - // end include: shell.js - - // include: preamble.js - // === Preamble library stuff === - - // Documentation for the public APIs defined in this file must be updated in: - // site/source/docs/api_reference/preamble.js.rst - // A prebuilt local version of the documentation is available at: - // site/build/text/docs/api_reference/preamble.js.txt - // You can also build docs locally as HTML or other formats in site/ - // An online HTML version (which may be of a different version of Emscripten) - // is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html - - var dynamicLibraries = []; - - var wasmBinary; - - // Wasm globals - - //======================================== - // Runtime essentials - //======================================== - - // whether we are quitting the application. no code should run after this. - // set in exit() and abort() - var ABORT = false; - - // set by exit() and abort(). Passed to 'onExit' handler. - // NOTE: This is also used as the process return code code in shell environments - // but only when noExitRuntime is false. - var EXITSTATUS; - - // In STRICT mode, we only define assert() when ASSERTIONS is set. i.e. we - // don't define it at all in release modes. This matches the behaviour of - // MINIMAL_RUNTIME. - // TODO(sbc): Make this the default even without STRICT enabled. - /** @type {function(*, string=)} */ - function assert(condition, text) { - if (!condition) { - // This build was created without ASSERTIONS defined. `assert()` should not - // ever be called in this configuration but in case there are callers in - // the wild leave this simple abort() implementation here for now. - abort(text); - } - } +var out = console.log.bind(console); +var err = console.error.bind(console); + +// end include: shell.js + +// include: preamble.js +// === Preamble library stuff === + +// Documentation for the public APIs defined in this file must be updated in: +// site/source/docs/api_reference/preamble.js.rst +// A prebuilt local version of the documentation is available at: +// site/build/text/docs/api_reference/preamble.js.txt +// You can also build docs locally as HTML or other formats in site/ +// An online HTML version (which may be of a different version of Emscripten) +// is up at http://kripken.github.io/emscripten-site/docs/api_reference/preamble.js.html + +var dynamicLibraries = []; + +var wasmBinary; + +// Wasm globals + +//======================================== +// Runtime essentials +//======================================== + +// whether we are quitting the application. no code should run after this. +// set in exit() and abort() +var ABORT = false; + +// set by exit() and abort(). Passed to 'onExit' handler. +// NOTE: This is also used as the process return code code in shell environments +// but only when noExitRuntime is false. +var EXITSTATUS; + +// In STRICT mode, we only define assert() when ASSERTIONS is set. i.e. we +// don't define it at all in release modes. This matches the behaviour of +// MINIMAL_RUNTIME. +// TODO(sbc): Make this the default even without STRICT enabled. +/** @type {function(*, string=)} */ +function assert(condition, text) { + if (!condition) { + // This build was created without ASSERTIONS defined. `assert()` should not + // ever be called in this configuration but in case there are callers in + // the wild leave this simple abort() implementation here for now. + abort(text); + } +} - /** - * Indicates whether filename is delivered via file protocol (as opposed to http/https) - * @noinline - */ - var isFileURI = (filename) => filename.startsWith('file://'); - - // include: runtime_common.js - // include: runtime_stack_check.js - // end include: runtime_stack_check.js - // include: runtime_exceptions.js - // end include: runtime_exceptions.js - // include: runtime_debug.js - // end include: runtime_debug.js - // Memory management - var /** @type {!Int8Array} */ - HEAP8, - /** @type {!Uint8Array} */ - HEAPU8, - /** @type {!Int16Array} */ - HEAP16, - /** @type {!Uint16Array} */ - HEAPU16, - /** @type {!Int32Array} */ - HEAP32, - /** @type {!Uint32Array} */ - HEAPU32, - /** @type {!Float32Array} */ - HEAPF32, - /** @type {!Float64Array} */ - HEAPF64; - - // BigInt64Array type is not correctly defined in closure - var /** not-@type {!BigInt64Array} */ - HEAP64, - /* BigUint64Array type is not correctly defined in closure +/** + * Indicates whether filename is delivered via file protocol (as opposed to http/https) + * @noinline + */ +var isFileURI = (filename) => filename.startsWith('file://'); + +// include: runtime_common.js +// include: runtime_stack_check.js +// end include: runtime_stack_check.js +// include: runtime_exceptions.js +// end include: runtime_exceptions.js +// include: runtime_debug.js +// end include: runtime_debug.js +// Memory management +var +/** @type {!Int8Array} */ + HEAP8, +/** @type {!Uint8Array} */ + HEAPU8, +/** @type {!Int16Array} */ + HEAP16, +/** @type {!Uint16Array} */ + HEAPU16, +/** @type {!Int32Array} */ + HEAP32, +/** @type {!Uint32Array} */ + HEAPU32, +/** @type {!Float32Array} */ + HEAPF32, +/** @type {!Float64Array} */ + HEAPF64; + +// BigInt64Array type is not correctly defined in closure +var +/** not-@type {!BigInt64Array} */ + HEAP64, +/* BigUint64Array type is not correctly defined in closure /** not-@type {!BigUint64Array} */ - HEAPU64; - - var runtimeInitialized = false; - - var runtimeExited = false; - - function updateMemoryViews() { - var b = wasmMemory.buffer; - HEAP8 = new Int8Array(b); - HEAP16 = new Int16Array(b); - Module['HEAPU8'] = HEAPU8 = new Uint8Array(b); - HEAPU16 = new Uint16Array(b); - HEAP32 = new Int32Array(b); - Module['HEAPU32'] = HEAPU32 = new Uint32Array(b); - HEAPF32 = new Float32Array(b); - HEAPF64 = new Float64Array(b); - HEAP64 = new BigInt64Array(b); - HEAPU64 = new BigUint64Array(b); - } - - // include: memoryprofiler.js - // end include: memoryprofiler.js - // end include: runtime_common.js - var __RELOC_FUNCS__ = []; - - function preRun() { - if (Module['preRun']) { - if (typeof Module['preRun'] == 'function') - Module['preRun'] = [Module['preRun']]; - while (Module['preRun'].length) { - addOnPreRun(Module['preRun'].shift()); - } - } - // Begin ATPRERUNS hooks - callRuntimeCallbacks(onPreRuns); - // End ATPRERUNS hooks - } - - function initRuntime() { - runtimeInitialized = true; - - callRuntimeCallbacks(__RELOC_FUNCS__); - - // Begin ATINITS hooks - callRuntimeCallbacks(onInits); - if (!Module['noFSInit'] && !FS.initialized) FS.init(); - TTY.init(); - SOCKFS.root = FS.mount(SOCKFS, {}, null); - PIPEFS.root = FS.mount(PIPEFS, {}, null); - // End ATINITS hooks + HEAPU64; - wasmExports['__wasm_call_ctors'](); +var runtimeInitialized = false; - // Begin ATPOSTCTORS hooks - callRuntimeCallbacks(onPostCtors); - FS.ignorePermissions = false; - // End ATPOSTCTORS hooks - } - - function preMain() { - // Begin ATMAINS hooks - callRuntimeCallbacks(onMains); - // End ATMAINS hooks - } - - function exitRuntime() { - // PThreads reuse the runtime from the main thread. - ___funcs_on_exit(); // Native atexit() functions - // Begin ATEXITS hooks - callRuntimeCallbacks(onExits); - FS.quit(); - TTY.shutdown(); - // End ATEXITS hooks - runtimeExited = true; - } - - function postRun() { - // PThreads reuse the runtime from the main thread. +var runtimeExited = false; - if (Module['postRun']) { - if (typeof Module['postRun'] == 'function') - Module['postRun'] = [Module['postRun']]; - while (Module['postRun'].length) { - addOnPostRun(Module['postRun'].shift()); - } - } - - // Begin ATPOSTRUNS hooks - callRuntimeCallbacks(onPostRuns); - // End ATPOSTRUNS hooks - } - /** @param {string|number=} what */ - function abort(what) { - Module['onAbort']?.(what); - - what = 'Aborted(' + what + ')'; - // TODO(sbc): Should we remove printing and leave it up to whoever - // catches the exception? - err(what); - - ABORT = true; - - what += '. Build with -sASSERTIONS for more info.'; - - // Use a wasm runtime error, because a JS error might be seen as a foreign - // exception, which means we'd run destructors on it. We need the error to - // simply make the program stop. - // FIXME This approach does not work in Wasm EH because it currently does not assume - // all RuntimeErrors are from traps; it decides whether a RuntimeError is from - // a trap or not based on a hidden field within the object. So at the moment - // we don't have a way of throwing a wasm trap from JS. TODO Make a JS API that - // allows this in the wasm spec. - - // Suppress closure compiler warning here. Closure compiler's builtin extern - // definition for WebAssembly.RuntimeError claims it takes no arguments even - // though it can. - // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure gets fixed. - /** @suppress {checkTypes} */ - var e = new WebAssembly.RuntimeError(what); - - // Throw the error whether or not MODULARIZE is set because abort is used - // in code paths apart from instantiation where an exception is expected - // to be thrown when abort is called. - throw e; - } - var wasmBinaryFile; +function updateMemoryViews() { + var b = wasmMemory.buffer; + HEAP8 = new Int8Array(b); + HEAP16 = new Int16Array(b); + Module['HEAPU8'] = HEAPU8 = new Uint8Array(b); + HEAPU16 = new Uint16Array(b); + HEAP32 = new Int32Array(b); + Module['HEAPU32'] = HEAPU32 = new Uint32Array(b); + HEAPF32 = new Float32Array(b); + HEAPF64 = new Float64Array(b); + HEAP64 = new BigInt64Array(b); + HEAPU64 = new BigUint64Array(b); +} - function findWasmBinary() { - return locateFile(dependencyFilename); - } +// include: memoryprofiler.js +// end include: memoryprofiler.js +// end include: runtime_common.js +var __RELOC_FUNCS__ = []; - function getBinarySync(file) { - if (file == wasmBinaryFile && wasmBinary) { - return new Uint8Array(wasmBinary); - } - if (readBinary) { - return readBinary(file); - } - // Throwing a plain string here, even though it not normally adviables since - // this gets turning into an `abort` in instantiateArrayBuffer. - throw 'both async and sync fetching of the wasm failed'; - } +function preRun() { + if (Module['preRun']) { + if (typeof Module['preRun'] == 'function') Module['preRun'] = [Module['preRun']]; + while (Module['preRun'].length) { + addOnPreRun(Module['preRun'].shift()); + } + } + // Begin ATPRERUNS hooks + callRuntimeCallbacks(onPreRuns); + // End ATPRERUNS hooks +} - async function getWasmBinary(binaryFile) { - // If we don't have the binary yet, load it asynchronously using readAsync. - if (!wasmBinary) { - // Fetch the binary using readAsync - try { - var response = await readAsync(binaryFile); - return new Uint8Array(response); - } catch { - // Fall back to getBinarySync below; - } - } - - // Otherwise, getBinarySync should be able to get it synchronously - return getBinarySync(binaryFile); - } +function initRuntime() { + runtimeInitialized = true; - async function instantiateArrayBuffer(binaryFile, imports) { - try { - var binary = await getWasmBinary(binaryFile); - var instance = await WebAssembly.instantiate(binary, imports); - return instance; - } catch (reason) { - err(`failed to asynchronously prepare wasm: ${reason}`); + callRuntimeCallbacks(__RELOC_FUNCS__); - abort(reason); - } - } + // Begin ATINITS hooks + callRuntimeCallbacks(onInits); +if (!Module['noFSInit'] && !FS.initialized) FS.init(); +TTY.init(); +SOCKFS.root = FS.mount(SOCKFS, {}, null); +PIPEFS.root = FS.mount(PIPEFS, {}, null); + // End ATINITS hooks - async function instantiateAsync(binary, binaryFile, imports) { - if ( - !binary && - // Avoid instantiateStreaming() on Node.js environment for now, as while - // Node.js v18.1.0 implements it, it does not have a full fetch() - // implementation yet. - // - // Reference: - // https://github.com/emscripten-core/emscripten/pull/16917 - !ENVIRONMENT_IS_NODE - ) { - try { - var response = fetch(binaryFile, { - credentials: 'same-origin', - }); - var instantiationResult = - await WebAssembly.instantiateStreaming(response, imports); - return instantiationResult; - } catch (reason) { - // We expect the most common failure cause to be a bad MIME type for the binary, - // in which case falling back to ArrayBuffer instantiation should work. - err(`wasm streaming compile failed: ${reason}`); - err('falling back to ArrayBuffer instantiation'); - // fall back of instantiateArrayBuffer below - } - } - return instantiateArrayBuffer(binaryFile, imports); - } + wasmExports['__wasm_call_ctors'](); - function getWasmImports() { - // prepare imports - var imports = { - env: wasmImports, - wasi_snapshot_preview1: wasmImports, - 'GOT.mem': new Proxy(wasmImports, GOTHandler), - 'GOT.func': new Proxy(wasmImports, GOTHandler), - }; - return imports; - } + // Begin ATPOSTCTORS hooks + callRuntimeCallbacks(onPostCtors); +FS.ignorePermissions = false; + // End ATPOSTCTORS hooks +} - // Create the wasm instance. - // Receives the wasm imports, returns the exports. - async function createWasm() { - // Load the wasm module and create an instance of using native support in the JS engine. - // handle a generated wasm instance, receiving its exports and - // performing other necessary setup - /** @param {WebAssembly.Module=} module*/ - function receiveInstance(instance, module) { - wasmExports = instance.exports; - - // No relocation needed here.. but calling this just so that updateGOT is - // called. - var origExports = (wasmExports = relocateExports(wasmExports)); - - wasmExports = Asyncify.instrumentWasmExports(wasmExports); - - mergeLibSymbols(wasmExports, 'main'); - var metadata = getDylinkMetadata(module); - if (metadata.neededDynlibs) { - dynamicLibraries = - metadata.neededDynlibs.concat(dynamicLibraries); - } - - assignWasmExports(wasmExports); - - updateGOT(origExports); - - Module['wasmExports'] = wasmExports; - - LDSO.init(); - loadDylibs(); - - updateMemoryViews(); - - removeRunDependency('wasm-instantiate'); - return wasmExports; - } - addRunDependency('wasm-instantiate'); - - // Prefer streaming instantiation if available. - function receiveInstantiationResult(result) { - // 'result' is a ResultObject object which has both the module and instance. - // receiveInstance() will swap in the exports (to Module.asm) so they can be called - return receiveInstance(result['instance'], result['module']); - } - - var info = getWasmImports(); - - // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback - // to manually instantiate the Wasm module themselves. This allows pages to - // run the instantiation parallel to any other async startup actions they are - // performing. - // Also pthreads and wasm workers initialize the wasm instance through this - // path. - if (Module['instantiateWasm']) { - return new Promise((resolve, reject) => { - Module['instantiateWasm'](info, (inst, mod) => { - resolve(receiveInstance(inst, mod)); - }); - }); - } - - wasmBinaryFile ??= findWasmBinary(); - var result = await instantiateAsync(wasmBinary, wasmBinaryFile, info); - var exports = receiveInstantiationResult(result); - return exports; - } +function preMain() { + // Begin ATMAINS hooks + callRuntimeCallbacks(onMains); + // End ATMAINS hooks +} - // With MAIN_MODULE + ASYNCIFY the normal method of placing stub functions in - // wasmImports for as-yet-undefined symbols doesn't work since ASYNCIFY then - // wraps these stub functions and we can't then replace them directly. Instead - // the stub functions call into `asyncifyStubs` which gets populated by the - // dynamic linker as symbols are loaded. - var asyncifyStubs = {}; - // end include: preamble.js - - // Begin JS library code - - class ExitStatus { - name = 'ExitStatus'; - constructor(status) { - this.message = `Program terminated with exit(${status})`; - this.status = status; - } - } - ExitStatus = class PHPExitStatus extends Error { - constructor(status) { - super(status); - this.name = 'ExitStatus'; - this.message = 'Program terminated with exit(' + status + ')'; - this.status = status; - } - }; - - var GOT = {}; - - var currentModuleWeakSymbols = new Set([ - '__start___llvm_prf_data', - '__stop___llvm_prf_data', - '__start___llvm_prf_names', - '__stop___llvm_prf_names', - '__start___llvm_prf_vns', - '__stop___llvm_prf_vns', - '__start___llvm_prf_vtab', - '__stop___llvm_prf_vtab', - '__start___llvm_prf_cnts', - '__stop___llvm_prf_cnts', - '__start___llvm_prf_bits', - '__stop___llvm_prf_bits', - '__start___llvm_prf_vnds', - '__stop___llvm_prf_vnds', - ]); - var GOTHandler = { - get(obj, symName) { - var rtn = GOT[symName]; - if (!rtn) { - rtn = GOT[symName] = new WebAssembly.Global( - { value: 'i32', mutable: true }, - -1 - ); - } - if (!currentModuleWeakSymbols.has(symName)) { - // Any non-weak reference to a symbol marks it as `required`, which - // enabled `reportUndefinedSymbols` to report undefined symbol errors - // correctly. - rtn.required = true; - } - return rtn; - }, - }; - - var callRuntimeCallbacks = (callbacks) => { - while (callbacks.length > 0) { - // Pass the module as the first argument. - callbacks.shift()(Module); - } - }; - var onPostRuns = []; - var addOnPostRun = (cb) => onPostRuns.push(cb); - - var onPreRuns = []; - var addOnPreRun = (cb) => onPreRuns.push(cb); - - var runDependencies = 0; - - var dependenciesFulfilled = null; - var removeRunDependency = (id) => { - runDependencies--; - - Module['monitorRunDependencies']?.(runDependencies); - - if (runDependencies == 0) { - if (dependenciesFulfilled) { - var callback = dependenciesFulfilled; - dependenciesFulfilled = null; - callback(); // can add another dependenciesFulfilled - } - } - }; - var addRunDependency = (id) => { - runDependencies++; - - Module['monitorRunDependencies']?.(runDependencies); - }; - - var dynCalls = {}; - var dynCallLegacy = (sig, ptr, args) => { - sig = sig.replace(/p/g, 'i'); - var f = dynCalls[sig]; - return f(ptr, ...args); - }; - var dynCall = (sig, ptr, args = [], promising = false) => { - var rtn = dynCallLegacy(sig, ptr, args); - - function convert(rtn) { - return rtn; - } - - return convert(rtn); - }; - - var UTF8Decoder = globalThis.TextDecoder && new TextDecoder(); - - var findStringEnd = (heapOrArray, idx, maxBytesToRead, ignoreNul) => { - var maxIdx = idx + maxBytesToRead; - if (ignoreNul) return maxIdx; - // TextDecoder needs to know the byte length in advance, it doesn't stop on - // null terminator by itself. - // As a tiny code save trick, compare idx against maxIdx using a negation, - // so that maxBytesToRead=undefined/NaN means Infinity. - while (heapOrArray[idx] && !(idx >= maxIdx)) ++idx; - return idx; - }; - - /** - * Given a pointer 'idx' to a null-terminated UTF8-encoded string in the given - * array that contains uint8 values, returns a copy of that string as a - * Javascript String object. - * heapOrArray is either a regular array, or a JavaScript typed array view. - * @param {number=} idx - * @param {number=} maxBytesToRead - * @param {boolean=} ignoreNul - If true, the function will not stop on a NUL character. - * @return {string} - */ - var UTF8ArrayToString = ( - heapOrArray, - idx = 0, - maxBytesToRead, - ignoreNul - ) => { - var endPtr = findStringEnd(heapOrArray, idx, maxBytesToRead, ignoreNul); - - // When using conditional TextDecoder, skip it for short strings as the overhead of the native call is not worth it. - if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) { - return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr)); - } - var str = ''; - while (idx < endPtr) { - // For UTF8 byte structure, see: - // http://en.wikipedia.org/wiki/UTF-8#Description - // https://www.ietf.org/rfc/rfc2279.txt - // https://tools.ietf.org/html/rfc3629 - var u0 = heapOrArray[idx++]; - if (!(u0 & 0x80)) { - str += String.fromCharCode(u0); - continue; - } - var u1 = heapOrArray[idx++] & 63; - if ((u0 & 0xe0) == 0xc0) { - str += String.fromCharCode(((u0 & 31) << 6) | u1); - continue; - } - var u2 = heapOrArray[idx++] & 63; - if ((u0 & 0xf0) == 0xe0) { - u0 = ((u0 & 15) << 12) | (u1 << 6) | u2; - } else { - u0 = - ((u0 & 7) << 18) | - (u1 << 12) | - (u2 << 6) | - (heapOrArray[idx++] & 63); - } - - if (u0 < 0x10000) { - str += String.fromCharCode(u0); - } else { - var ch = u0 - 0x10000; - str += String.fromCharCode( - 0xd800 | (ch >> 10), - 0xdc00 | (ch & 0x3ff) - ); - } - } - return str; - }; - var getDylinkMetadata = (binary) => { - var offset = 0; - var end = 0; - - function getU8() { - return binary[offset++]; - } - - function getLEB() { - var ret = 0; - var mul = 1; - while (1) { - var byte = binary[offset++]; - ret += (byte & 0x7f) * mul; - mul *= 0x80; - if (!(byte & 0x80)) break; - } - return ret; - } - - function getString() { - var len = getLEB(); - offset += len; - return UTF8ArrayToString(binary, offset - len, len); - } - - function getStringList() { - var count = getLEB(); - var rtn = []; - while (count--) rtn.push(getString()); - return rtn; - } - - /** @param {string=} message */ - function failIf(condition, message) { - if (condition) throw new Error(message); - } - - if (binary instanceof WebAssembly.Module) { - var dylinkSection = WebAssembly.Module.customSections( - binary, - 'dylink.0' - ); - failIf(dylinkSection.length === 0, 'need dylink section'); - binary = new Uint8Array(dylinkSection[0]); - end = binary.length; - } else { - var int32View = new Uint32Array( - new Uint8Array(binary.subarray(0, 24)).buffer - ); - var magicNumberFound = int32View[0] == 0x6d736100; - failIf(!magicNumberFound, 'need to see wasm magic number'); // \0asm - // we should see the dylink custom section right after the magic number and wasm version - failIf(binary[8] !== 0, 'need the dylink section to be first'); - offset = 9; - var section_size = getLEB(); //section size - end = offset + section_size; - var name = getString(); - failIf(name !== 'dylink.0'); - } - - var customSection = { - neededDynlibs: [], - tlsExports: new Set(), - weakImports: new Set(), - runtimePaths: [], - }; - var WASM_DYLINK_MEM_INFO = 0x1; - var WASM_DYLINK_NEEDED = 0x2; - var WASM_DYLINK_EXPORT_INFO = 0x3; - var WASM_DYLINK_IMPORT_INFO = 0x4; - var WASM_DYLINK_RUNTIME_PATH = 0x5; - var WASM_SYMBOL_TLS = 0x100; - var WASM_SYMBOL_BINDING_MASK = 0x3; - var WASM_SYMBOL_BINDING_WEAK = 0x1; - while (offset < end) { - var subsectionType = getU8(); - var subsectionSize = getLEB(); - if (subsectionType === WASM_DYLINK_MEM_INFO) { - customSection.memorySize = getLEB(); - customSection.memoryAlign = getLEB(); - customSection.tableSize = getLEB(); - customSection.tableAlign = getLEB(); - } else if (subsectionType === WASM_DYLINK_NEEDED) { - customSection.neededDynlibs = getStringList(); - } else if (subsectionType === WASM_DYLINK_EXPORT_INFO) { - var count = getLEB(); - while (count--) { - var symname = getString(); - var flags = getLEB(); - if (flags & WASM_SYMBOL_TLS) { - customSection.tlsExports.add(symname); - } - } - } else if (subsectionType === WASM_DYLINK_IMPORT_INFO) { - var count = getLEB(); - while (count--) { - var modname = getString(); - var symname = getString(); - var flags = getLEB(); - if ( - (flags & WASM_SYMBOL_BINDING_MASK) == - WASM_SYMBOL_BINDING_WEAK - ) { - customSection.weakImports.add(symname); - } - } - } else if (subsectionType === WASM_DYLINK_RUNTIME_PATH) { - customSection.runtimePaths = getStringList(); - } else { - // unknown subsection - offset += subsectionSize; - } - } - - return customSection; - }; - - /** - * @param {number} ptr - * @param {string} type - */ - function getValue(ptr, type = 'i8') { - if (type.endsWith('*')) type = '*'; - switch (type) { - case 'i1': - return HEAP8[ptr]; - case 'i8': - return HEAP8[ptr]; - case 'i16': - return HEAP16[ptr >> 1]; - case 'i32': - return HEAP32[ptr >> 2]; - case 'i64': - return HEAP64[ptr >> 3]; - case 'float': - return HEAPF32[ptr >> 2]; - case 'double': - return HEAPF64[ptr >> 3]; - case '*': - return HEAPU32[ptr >> 2]; - default: - abort(`invalid type for getValue: ${type}`); - } - } +function exitRuntime() { + // PThreads reuse the runtime from the main thread. + ___funcs_on_exit(); // Native atexit() functions + // Begin ATEXITS hooks + callRuntimeCallbacks(onExits); +FS.quit(); +TTY.shutdown(); + // End ATEXITS hooks + runtimeExited = true; +} - var newDSO = (name, handle, syms) => { - var dso = { - refcount: Infinity, - name, - exports: syms, - global: true, - }; - LDSO.loadedLibsByName[name] = dso; - if (handle != undefined) { - LDSO.loadedLibsByHandle[handle] = dso; - } - return dso; - }; - var LDSO = { - loadedLibsByName: {}, - loadedLibsByHandle: {}, - init() { - newDSO('__main__', 0, wasmImports); - }, - }; - - var alignMemory = (size, alignment) => { - return Math.ceil(size / alignment) * alignment; - }; - - var getMemory = (size) => { - // After the runtime is initialized, we must only use sbrk() normally. - if (runtimeInitialized) { - // Currently we don't support freeing of static data when modules are - // unloaded via dlclose. This function is tagged as `noleakcheck` to - // avoid having this reported as leak. - return _calloc(size, 1); - } - var ret = ___heap_base; - // Keep __heap_base stack aligned. - var end = ret + alignMemory(size, 16); - ___heap_base = end; - - // After allocating the memory from the start of the heap we need to ensure - // that once the program starts it doesn't use this region. In relocatable - // mode we can just update the __heap_base symbol that we are exporting to - // the main module. - // When not relocatable `__heap_base` is fixed and exported by the main - // module, but we can update the `sbrk_ptr` value instead. We call - // `_emscripten_get_sbrk_ptr` knowing that it is safe to call prior to - // runtime initialization (unlike, the higher level sbrk function) - var sbrk_ptr = _emscripten_get_sbrk_ptr(); - HEAPU32[sbrk_ptr >> 2] = end; - return ret; - }; - - var isInternalSym = (symName) => { - // TODO: find a way to mark these in the binary or avoid exporting them. - return ( - [ - 'memory', - '__memory_base', - '__table_base', - '__stack_pointer', - '__indirect_function_table', - '__cpp_exception', - '__c_longjmp', - '__wasm_apply_data_relocs', - '__dso_handle', - '__tls_size', - '__tls_align', - '__set_stack_limits', - '_emscripten_tls_init', - '__wasm_init_tls', - '__wasm_call_ctors', - '__start_em_asm', - '__stop_em_asm', - '__start_em_js', - '__stop_em_js', - ].includes(symName) || symName.startsWith('__em_js__') - ); - }; - - var wasmTableMirror = []; - - var getWasmTableEntry = (funcPtr) => { - var func = wasmTableMirror[funcPtr]; - if (!func) { - /** @suppress {checkTypes} */ - wasmTableMirror[funcPtr] = func = wasmTable.get(funcPtr); - } - return func; - }; - - var updateTableMap = (offset, count) => { - if (functionsInTableMap) { - for (var i = offset; i < offset + count; i++) { - var item = getWasmTableEntry(i); - // Ignore null values. - if (item) { - functionsInTableMap.set(item, i); - } - } - } - }; - - var functionsInTableMap; - - var getFunctionAddress = (func) => { - // First, create the map if this is the first use. - if (!functionsInTableMap) { - functionsInTableMap = new WeakMap(); - updateTableMap(0, wasmTable.length); - } - return functionsInTableMap.get(func) || 0; - }; - - var freeTableIndexes = []; - - var getEmptyTableSlot = () => { - // Reuse a free index if there is one, otherwise grow. - if (freeTableIndexes.length) { - return freeTableIndexes.pop(); - } - // Grow the table - return wasmTable['grow'](1); - }; - - var setWasmTableEntry = (idx, func) => { - /** @suppress {checkTypes} */ - wasmTable.set(idx, func); - // With ABORT_ON_WASM_EXCEPTIONS wasmTable.get is overridden to return wrapped - // functions so we need to call it here to retrieve the potential wrapper correctly - // instead of just storing 'func' directly into wasmTableMirror - /** @suppress {checkTypes} */ - wasmTableMirror[idx] = wasmTable.get(idx); - }; - - var uleb128EncodeWithLen = (arr) => { - const n = arr.length; - // Note: this LEB128 length encoding produces extra byte for n < 128, - // but we don't care as it's only used in a temporary representation. - return [n % 128 | 128, n >> 7, ...arr]; - }; - - var wasmTypeCodes = { - i: 0x7f, // i32 - p: 0x7f, // i32 - j: 0x7e, // i64 - f: 0x7d, // f32 - d: 0x7c, // f64 - e: 0x6f, // externref - }; - var generateTypePack = (types) => - uleb128EncodeWithLen( - Array.from(types, (type) => { - var code = wasmTypeCodes[type]; - return code; - }) - ); - var convertJsFunctionToWasm = (func, sig) => { - // Rest of the module is static - var bytes = Uint8Array.of( - 0x00, - 0x61, - 0x73, - 0x6d, // magic ("\0asm") - 0x01, - 0x00, - 0x00, - 0x00, // version: 1 - 0x01, // Type section code - // The module is static, with the exception of the type section, which is - // generated based on the signature passed in. - ...uleb128EncodeWithLen([ - 0x01, // count: 1 - 0x60 /* form: func */, - // param types - ...generateTypePack(sig.slice(1)), - // return types (for now only supporting [] if `void` and single [T] otherwise) - ...generateTypePack(sig[0] === 'v' ? '' : sig[0]), - ]), - // The rest of the module is static - 0x02, - 0x07, // import section - // (import "e" "f" (func 0 (type 0))) - 0x01, - 0x01, - 0x65, - 0x01, - 0x66, - 0x00, - 0x00, - 0x07, - 0x05, // export section - // (export "f" (func 0 (type 0))) - 0x01, - 0x01, - 0x66, - 0x00, - 0x00 - ); - - // We can compile this wasm module synchronously because it is very small. - // This accepts an import (at "e.f"), that it reroutes to an export (at "f") - var module = new WebAssembly.Module(bytes); - var instance = new WebAssembly.Instance(module, { e: { f: func } }); - var wrappedFunc = instance.exports['f']; - return wrappedFunc; - }; - /** @param {string=} sig */ - var addFunction = (func, sig) => { - // Check if the function is already in the table, to ensure each function - // gets a unique index. - var rtn = getFunctionAddress(func); - if (rtn) { - return rtn; - } - - // It's not in the table, add it now. - - var ret = getEmptyTableSlot(); - - // Set the new value. - try { - // Attempting to call this with JS function will cause of table.set() to fail - setWasmTableEntry(ret, func); - } catch (err) { - if (!(err instanceof TypeError)) { - throw err; - } - var wrapped = convertJsFunctionToWasm(func, sig); - setWasmTableEntry(ret, wrapped); - } - - functionsInTableMap.set(func, ret); - - return ret; - }; - /** @param {boolean=} replace */ - var updateGOT = (exports, replace) => { - for (var symName in exports) { - if (isInternalSym(symName)) { - continue; - } - - var value = exports[symName]; - - var existingEntry = GOT[symName] && GOT[symName].value != -1; - if (replace || !existingEntry) { - var newValue; - if (typeof value == 'function') { - newValue = addFunction(value); - } else if (typeof value == 'number') { - newValue = value; - } else { - // The GOT can only contain addresses (i.e data addresses or function - // addresses so we currently ignore other types export here. - continue; - } - GOT[symName] ??= new WebAssembly.Global({ - value: 'i32', - mutable: true, - }); - GOT[symName].value = newValue; - } - } - }; - - var isImmutableGlobal = (val) => { - if (val instanceof WebAssembly.Global) { - try { - val.value = val.value; - } catch { - return true; - } - } - return false; - }; - var relocateExports = (exports, memoryBase = 0) => { - function relocateExport(name, value) { - // Detect immuable wasm global exports. These represent data addresses - // which are relative to `memoryBase` - if (isImmutableGlobal(value)) { - return value.value + memoryBase; - } - - // Return unmodified value (no relocation required). - return value; - } - - var relocated = {}; - for (var e in exports) { - relocated[e] = relocateExport(e, exports[e]); - } - return relocated; - }; - - var isSymbolDefined = (symName) => { - // Ignore 'stub' symbols that are auto-generated as part of the original - // `wasmImports` used to instantiate the main module. - var existing = wasmImports[symName]; - if (!existing || existing.stub) { - return false; - } - // Even if a symbol exists in wasmImports, and is not itself a stub, it - // could be an ASYNCIFY wrapper function that wraps a stub function. - if (symName in asyncifyStubs && !asyncifyStubs[symName]) { - return false; - } - return true; - }; - - var createNamedFunction = (name, func) => - Object.defineProperty(func, 'name', { value: name }); - - var stackSave = () => _emscripten_stack_get_current(); - - var stackRestore = (val) => __emscripten_stack_restore(val); - var createInvokeFunction = - (sig) => - (ptr, ...args) => { - var sp = stackSave(); - try { - return dynCall(sig, ptr, args); - } catch (e) { - stackRestore(sp); - // Create a try-catch guard that rethrows the Emscripten EH exception. - // Exceptions thrown from C++ will be a pointer (number) and longjmp - // will throw the number Infinity. Use the compact and fast "e !== e+0" - // test to check if e was not a Number. - if (e !== e + 0) throw e; - _setThrew(1, 0); - // In theory this if statement could be done on - // creating the function, but I just added this to - // save wasting code space as it only happens on exception. - if (sig[0] == 'j') return 0n; - } - }; - var resolveGlobalSymbol = (symName, direct = false) => { - var sym; - if (isSymbolDefined(symName)) { - sym = wasmImports[symName]; - } - // Asm.js-style exception handling: invoke wrapper generation - else if (symName.startsWith('invoke_')) { - // Create (and cache) new invoke_ functions on demand. - sym = wasmImports[symName] = createNamedFunction( - symName, - createInvokeFunction(symName.split('_')[1]) - ); - } - return { sym, name: symName }; - }; - - var onPostCtors = []; - var addOnPostCtor = (cb) => onPostCtors.push(cb); - - /** - * Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the - * emscripten HEAP, returns a copy of that string as a Javascript String object. - * - * @param {number} ptr - * @param {number=} maxBytesToRead - An optional length that specifies the - * maximum number of bytes to read. You can omit this parameter to scan the - * string until the first 0 byte. If maxBytesToRead is passed, and the string - * at [ptr, ptr+maxBytesToReadr[ contains a null byte in the middle, then the - * string will cut short at that byte index. - * @param {boolean=} ignoreNul - If true, the function will not stop on a NUL character. - * @return {string} - */ - var UTF8ToString = (ptr, maxBytesToRead, ignoreNul) => { - return ptr - ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead, ignoreNul) - : ''; - }; - - /** - * @param {string=} libName - * @param {Object=} localScope - * @param {number=} handle - */ - var loadWebAssemblyModule = ( - binary, - flags, - libName, - localScope, - handle - ) => { - var metadata = getDylinkMetadata(binary); - - // loadModule loads the wasm module after all its dependencies have been loaded. - // can be called both sync/async. - function loadModule() { - // alignments are powers of 2 - var memAlign = Math.pow(2, metadata.memoryAlign); - // prepare memory - var memoryBase = metadata.memorySize - ? alignMemory( - getMemory(metadata.memorySize + memAlign), - memAlign - ) - : 0; // TODO: add to cleanups - var tableBase = metadata.tableSize ? wasmTable.length : 0; - if (handle) { - HEAP8[handle + 8] = 1; - HEAPU32[(handle + 12) >> 2] = memoryBase; - HEAP32[(handle + 16) >> 2] = metadata.memorySize; - HEAPU32[(handle + 20) >> 2] = tableBase; - HEAP32[(handle + 24) >> 2] = metadata.tableSize; - } - - if (metadata.tableSize) { - wasmTable.grow(metadata.tableSize); - } - - // This is the export map that we ultimately return. We declare it here - // so it can be used within resolveSymbol. We resolve symbols against - // this local symbol map in the case there they are not present on the - // global Module object. We need this fallback because Modules sometime - // need to import their own symbols - var moduleExports; - - function resolveSymbol(sym) { - var resolved = resolveGlobalSymbol(sym).sym; - if (!resolved && localScope) { - resolved = localScope[sym]; - } - if (!resolved) { - resolved = moduleExports[sym]; - } - return resolved; - } - - // TODO kill ↓↓↓ (except "symbols local to this module", it will likely be - // not needed if we require that if A wants symbols from B it has to link - // to B explicitly: similarly to -Wl,--no-undefined) - // - // wasm dynamic libraries are pure wasm, so they cannot assist in - // their own loading. When side module A wants to import something - // provided by a side module B that is loaded later, we need to - // add a layer of indirection, but worse, we can't even tell what - // to add the indirection for, without inspecting what A's imports - // are. To do that here, we use a JS proxy (another option would - // be to inspect the binary directly). - var proxyHandler = { - get(stubs, prop) { - // symbols that should be local to this module - switch (prop) { - case '__memory_base': - return memoryBase; - case '__table_base': - return tableBase; - } - if (prop in wasmImports && !wasmImports[prop].stub) { - // No stub needed, symbol already exists in symbol table - var res = wasmImports[prop]; - // Asyncify wraps exports, and we need to look through those wrappers. - if (res.orig) { - res = res.orig; - } - return res; - } - // Return a stub function that will resolve the symbol - // when first called. - if (!(prop in stubs)) { - var resolved; - stubs[prop] = (...args) => { - resolved ||= resolveSymbol(prop); - return resolved(...args); - }; - } - return stubs[prop]; - }, - }; - var proxy = new Proxy({}, proxyHandler); - currentModuleWeakSymbols = metadata.weakImports; - var info = { - 'GOT.mem': new Proxy({}, GOTHandler), - 'GOT.func': new Proxy({}, GOTHandler), - env: proxy, - wasi_snapshot_preview1: proxy, - }; - - function postInstantiation(module, instance) { - // add new entries to functionsInTableMap - updateTableMap(tableBase, metadata.tableSize); - moduleExports = relocateExports(instance.exports, memoryBase); - updateGOT(moduleExports); - moduleExports = Asyncify.instrumentWasmExports(moduleExports); - if (!flags.allowUndefined) { - reportUndefinedSymbols(); - } - - function addEmAsm(addr, body) { - var args = []; - for (var arity = 0; ; arity++) { - var argName = '$' + arity; - if (!body.includes(argName)) break; - args.push(argName); - } - args = args.join(','); - var func = `(${args}) => { ${body} };`; - ASM_CONSTS[start] = eval(func); - } - - // Add any EM_ASM function that exist in the side module - if ('__start_em_asm' in moduleExports) { - var start = moduleExports['__start_em_asm']; - var stop = moduleExports['__stop_em_asm']; - - while (start < stop) { - var jsString = UTF8ToString(start); - addEmAsm(start, jsString); - start = HEAPU8.indexOf(0, start) + 1; - } - } - - function addEmJs(name, cSig, body) { - // The signature here is a C signature (e.g. "(int foo, char* bar)"). - // See `create_em_js` in emcc.py` for the build-time version of this - // code. - var jsArgs = []; - cSig = cSig.slice(1, -1); - if (cSig != 'void') { - cSig = cSig.split(','); - for (var arg of cSig) { - var jsArg = arg.split(' ').pop(); - jsArgs.push(jsArg.replace('*', '')); - } - } - var func = `(${jsArgs}) => ${body};`; - moduleExports[name] = eval(func); - } - - for (var name in moduleExports) { - if (name.startsWith('__em_js__')) { - var start = moduleExports[name]; - var jsString = UTF8ToString(start); - // EM_JS strings are stored in the data section in the form - // SIG<::>BODY. - var [sig, body] = jsString.split('<::>'); - addEmJs(name.replace('__em_js__', ''), sig, body); - delete moduleExports[name]; - } - } - - // initialize the module - var applyRelocs = moduleExports['__wasm_apply_data_relocs']; - if (applyRelocs) { - if (runtimeInitialized) { - applyRelocs(); - } else { - __RELOC_FUNCS__.push(applyRelocs); - } - } - var init = moduleExports['__wasm_call_ctors']; - if (init) { - if (runtimeInitialized) { - init(); - } else { - // we aren't ready to run compiled code yet - addOnPostCtor(init); - } - } - return moduleExports; - } - - if (flags.loadAsync) { - return (async () => { - var instance; - if (binary instanceof WebAssembly.Module) { - instance = new WebAssembly.Instance(binary, info); - } else { - // Destructuring assignment without declaration has to be wrapped - // with parens or parser will treat the l-value as an object - // literal instead. - ({ module: binary, instance } = - await WebAssembly.instantiate(binary, info)); - } - return postInstantiation(binary, instance); - })(); - } - - var module = - binary instanceof WebAssembly.Module - ? binary - : new WebAssembly.Module(binary); - var instance = new WebAssembly.Instance(module, info); - return postInstantiation(module, instance); - } - - // We need to set rpath in flags based on the current library's rpath. - // We can't mutate flags or else if a depends on b and c and b depends on d, - // then c will be loaded with b's rpath instead of a's. - flags = { - ...flags, - rpath: { parentLibPath: libName, paths: metadata.runtimePaths }, - }; - // now load needed libraries and the module itself. - if (flags.loadAsync) { - return metadata.neededDynlibs - .reduce( - (chain, dynNeeded) => - chain.then(() => - loadDynamicLibrary(dynNeeded, flags, localScope) - ), - Promise.resolve() - ) - .then(loadModule); - } - - for (var needed of metadata.neededDynlibs) { - loadDynamicLibrary(needed, flags, localScope); - } - return loadModule(); - }; - - var mergeLibSymbols = (exports, libName) => { - registerDynCallSymbols(exports); - // add symbols into global namespace TODO: weak linking etc. - for (var [sym, exp] of Object.entries(exports)) { - // When RTLD_GLOBAL is enabled, the symbols defined by this shared object - // will be made available for symbol resolution of subsequently loaded - // shared objects. - // - // We should copy the symbols (which include methods and variables) from - // SIDE_MODULE to MAIN_MODULE. - const setImport = (target) => { - if (target in asyncifyStubs) { - asyncifyStubs[target] = exp; - } - if (!isSymbolDefined(target)) { - wasmImports[target] = exp; - } - }; - setImport(sym); - - // Special case for handling of main symbol: If a side module exports - // `main` that also acts a definition for `__main_argc_argv` and vice - // versa. - const main_alias = '__main_argc_argv'; - if (sym == 'main') { - setImport(main_alias); - } - if (sym == main_alias) { - setImport('main'); - } - } - }; - - var asyncLoad = async (url) => { - var arrayBuffer = await readAsync(url); - return new Uint8Array(arrayBuffer); - }; - - var preloadPlugins = []; - var registerWasmPlugin = () => { - // Use string keys here for public methods to avoid minification since the - // plugin consumer also uses string keys. - var wasmPlugin = { - promiseChainEnd: Promise.resolve(), - canHandle: (name) => { - return !Module['noWasmDecoding'] && name.endsWith('.so'); - }, - handle: async (byteArray, name) => - // loadWebAssemblyModule can not load modules out-of-order, so rather - // than just running the promises in parallel, this makes a chain of - // promises to run in series. - (wasmPlugin.promiseChainEnd = wasmPlugin.promiseChainEnd.then( - async () => { - try { - var exports = await loadWebAssemblyModule( - byteArray, - { loadAsync: true, nodelete: true }, - name, - {} - ); - } catch (error) { - throw new Error( - `failed to instantiate wasm: ${name}: ${error}` - ); - } - preloadedWasm[name] = exports; - return byteArray; - } - )), - }; - preloadPlugins.push(wasmPlugin); - }; - var preloadedWasm = {}; - - var PATH = { - isAbs: (path) => path.charAt(0) === '/', - splitPath: (filename) => { - var splitPathRe = - /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; - return splitPathRe.exec(filename).slice(1); - }, - normalizeArray: (parts, allowAboveRoot) => { - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = parts.length - 1; i >= 0; i--) { - var last = parts[i]; - if (last === '.') { - parts.splice(i, 1); - } else if (last === '..') { - parts.splice(i, 1); - up++; - } else if (up) { - parts.splice(i, 1); - up--; - } - } - // if the path is allowed to go above the root, restore leading ..s - if (allowAboveRoot) { - for (; up; up--) { - parts.unshift('..'); - } - } - return parts; - }, - normalize: (path) => { - var isAbsolute = PATH.isAbs(path), - trailingSlash = path.slice(-1) === '/'; - // Normalize the path - path = PATH.normalizeArray( - path.split('/').filter((p) => !!p), - !isAbsolute - ).join('/'); - if (!path && !isAbsolute) { - path = '.'; - } - if (path && trailingSlash) { - path += '/'; - } - return (isAbsolute ? '/' : '') + path; - }, - dirname: (path) => { - var result = PATH.splitPath(path), - root = result[0], - dir = result[1]; - if (!root && !dir) { - // No dirname whatsoever - return '.'; - } - if (dir) { - // It has a dirname, strip trailing slash - dir = dir.slice(0, -1); - } - return root + dir; - }, - basename: (path) => path && path.match(/([^\/]+|\/)\/*$/)[1], - join: (...paths) => PATH.normalize(paths.join('/')), - join2: (l, r) => PATH.normalize(l + '/' + r), - }; - var replaceORIGIN = (parentLibName, rpath) => { - if (rpath.startsWith('$ORIGIN')) { - // TODO: what to do if we only know the relative path of the file? It will return "." here. - var origin = PATH.dirname(parentLibName); - return rpath.replace('$ORIGIN', origin); - } - - return rpath; - }; - - var withStackSave = (f) => { - var stack = stackSave(); - var ret = f(); - stackRestore(stack); - return ret; - }; - - var stackAlloc = (sz) => __emscripten_stack_alloc(sz); - - var lengthBytesUTF8 = (str) => { - var len = 0; - for (var i = 0; i < str.length; ++i) { - // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code - // unit, not a Unicode code point of the character! So decode - // UTF16->UTF32->UTF8. - // See http://unicode.org/faq/utf_bom.html#utf16-3 - var c = str.charCodeAt(i); // possibly a lead surrogate - if (c <= 0x7f) { - len++; - } else if (c <= 0x7ff) { - len += 2; - } else if (c >= 0xd800 && c <= 0xdfff) { - len += 4; - ++i; - } else { - len += 3; - } - } - return len; - }; - - var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => { - // Parameter maxBytesToWrite is not optional. Negative values, 0, null, - // undefined and false each don't write out any bytes. - if (!(maxBytesToWrite > 0)) return 0; - - var startIdx = outIdx; - var endIdx = outIdx + maxBytesToWrite - 1; // -1 for string null terminator. - for (var i = 0; i < str.length; ++i) { - // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description - // and https://www.ietf.org/rfc/rfc2279.txt - // and https://tools.ietf.org/html/rfc3629 - var u = str.codePointAt(i); - if (u <= 0x7f) { - if (outIdx >= endIdx) break; - heap[outIdx++] = u; - } else if (u <= 0x7ff) { - if (outIdx + 1 >= endIdx) break; - heap[outIdx++] = 0xc0 | (u >> 6); - heap[outIdx++] = 0x80 | (u & 63); - } else if (u <= 0xffff) { - if (outIdx + 2 >= endIdx) break; - heap[outIdx++] = 0xe0 | (u >> 12); - heap[outIdx++] = 0x80 | ((u >> 6) & 63); - heap[outIdx++] = 0x80 | (u & 63); - } else { - if (outIdx + 3 >= endIdx) break; - heap[outIdx++] = 0xf0 | (u >> 18); - heap[outIdx++] = 0x80 | ((u >> 12) & 63); - heap[outIdx++] = 0x80 | ((u >> 6) & 63); - heap[outIdx++] = 0x80 | (u & 63); - // Gotcha: if codePoint is over 0xFFFF, it is represented as a surrogate pair in UTF-16. - // We need to manually skip over the second code unit for correct iteration. - i++; - } - } - // Null-terminate the pointer to the buffer. - heap[outIdx] = 0; - return outIdx - startIdx; - }; - var stringToUTF8 = (str, outPtr, maxBytesToWrite) => { - return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite); - }; - - var stringToUTF8OnStack = (str) => { - var size = lengthBytesUTF8(str) + 1; - var ret = stackAlloc(size); - stringToUTF8(str, ret, size); - return ret; - }; - - var initRandomFill = () => { - return (view) => crypto.getRandomValues(view); - }; - var randomFill = (view) => { - // Lazily init on the first invocation. - (randomFill = initRandomFill())(view); - }; - - var PATH_FS = { - resolve: (...args) => { - var resolvedPath = '', - resolvedAbsolute = false; - for (var i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = i >= 0 ? args[i] : FS.cwd(); - // Skip empty and invalid entries - if (typeof path != 'string') { - throw new TypeError( - 'Arguments to path.resolve must be strings' - ); - } else if (!path) { - return ''; // an invalid portion invalidates the whole thing - } - resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = PATH.isAbs(path); - } - // At this point the path should be resolved to a full absolute path, but - // handle relative paths to be safe (might happen when process.cwd() fails) - resolvedPath = PATH.normalizeArray( - resolvedPath.split('/').filter((p) => !!p), - !resolvedAbsolute - ).join('/'); - return (resolvedAbsolute ? '/' : '') + resolvedPath || '.'; - }, - relative: (from, to) => { - from = PATH_FS.resolve(from).slice(1); - to = PATH_FS.resolve(to).slice(1); - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== '') break; - } - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== '') break; - } - if (start > end) return []; - return arr.slice(start, end - start + 1); - } - var fromParts = trim(from.split('/')); - var toParts = trim(to.split('/')); - var length = Math.min(fromParts.length, toParts.length); - var samePartsLength = length; - for (var i = 0; i < length; i++) { - if (fromParts[i] !== toParts[i]) { - samePartsLength = i; - break; - } - } - var outputParts = []; - for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push('..'); - } - outputParts = outputParts.concat(toParts.slice(samePartsLength)); - return outputParts.join('/'); - }, - }; - - var FS_stdin_getChar_buffer = []; - - /** @type {function(string, boolean=, number=)} */ - var intArrayFromString = (stringy, dontAddNull, length) => { - var len = length > 0 ? length : lengthBytesUTF8(stringy) + 1; - var u8array = new Array(len); - var numBytesWritten = stringToUTF8Array( - stringy, - u8array, - 0, - u8array.length - ); - if (dontAddNull) u8array.length = numBytesWritten; - return u8array; - }; - var FS_stdin_getChar = () => { - if (!FS_stdin_getChar_buffer.length) { - var result = null; - if (ENVIRONMENT_IS_NODE) { - // we will read data by chunks of BUFSIZE - var BUFSIZE = 256; - var buf = Buffer.alloc(BUFSIZE); - var bytesRead = 0; - - // For some reason we must suppress a closure warning here, even though - // fd definitely exists on process.stdin, and is even the proper way to - // get the fd of stdin, - // https://github.com/nodejs/help/issues/2136#issuecomment-523649904 - // This started to happen after moving this logic out of library_tty.js, - // so it is related to the surrounding code in some unclear manner. - /** @suppress {missingProperties} */ - var fd = process.stdin.fd; - - try { - bytesRead = fs.readSync(fd, buf, 0, BUFSIZE); - } catch (e) { - // Cross-platform differences: on Windows, reading EOF throws an - // exception, but on other OSes, reading EOF returns 0. Uniformize - // behavior by treating the EOF exception to return 0. - if (e.toString().includes('EOF')) bytesRead = 0; - else throw e; - } - - if (bytesRead > 0) { - result = buf.slice(0, bytesRead).toString('utf-8'); - } - } else { - } - if (!result) { - return null; - } - FS_stdin_getChar_buffer = intArrayFromString(result, true); - } - return FS_stdin_getChar_buffer.shift(); - }; - var TTY = { - ttys: [], - init() { - // https://github.com/emscripten-core/emscripten/pull/1555 - // if (ENVIRONMENT_IS_NODE) { - // // currently, FS.init does not distinguish if process.stdin is a file or TTY - // // device, it always assumes it's a TTY device. because of this, we're forcing - // // process.stdin to UTF8 encoding to at least make stdin reading compatible - // // with text files until FS.init can be refactored. - // process.stdin.setEncoding('utf8'); - // } - }, - shutdown() { - // https://github.com/emscripten-core/emscripten/pull/1555 - // if (ENVIRONMENT_IS_NODE) { - // // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)? - // // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation - // // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists? - // // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle - // // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call - // process.stdin.pause(); - // } - }, - register(dev, ops) { - TTY.ttys[dev] = { input: [], output: [], ops: ops }; - FS.registerDevice(dev, TTY.stream_ops); - }, - stream_ops: { - open(stream) { - var tty = TTY.ttys[stream.node.rdev]; - if (!tty) { - throw new FS.ErrnoError(43); - } - stream.tty = tty; - stream.seekable = false; - }, - close(stream) { - // flush any pending line data - stream.tty.ops.fsync(stream.tty); - }, - fsync(stream) { - stream.tty.ops.fsync(stream.tty); - }, - read(stream, buffer, offset, length, pos /* ignored */) { - if (!stream.tty || !stream.tty.ops.get_char) { - throw new FS.ErrnoError(60); - } - var bytesRead = 0; - for (var i = 0; i < length; i++) { - var result; - try { - result = stream.tty.ops.get_char(stream.tty); - } catch (e) { - throw new FS.ErrnoError(29); - } - if (result === undefined && bytesRead === 0) { - throw new FS.ErrnoError(6); - } - if (result === null || result === undefined) break; - bytesRead++; - buffer[offset + i] = result; - } - if (bytesRead) { - stream.node.atime = Date.now(); - } - return bytesRead; - }, - write(stream, buffer, offset, length, pos) { - if (!stream.tty || !stream.tty.ops.put_char) { - throw new FS.ErrnoError(60); - } - try { - for (var i = 0; i < length; i++) { - stream.tty.ops.put_char(stream.tty, buffer[offset + i]); - } - } catch (e) { - throw new FS.ErrnoError(29); - } - if (length) { - stream.node.mtime = stream.node.ctime = Date.now(); - } - return i; - }, - }, - default_tty_ops: { - get_char(tty) { - return FS_stdin_getChar(); - }, - put_char(tty, val) { - if (val === null || val === 10) { - out(UTF8ArrayToString(tty.output)); - tty.output = []; - } else { - if (val != 0) tty.output.push(val); // val == 0 would cut text output off in the middle. - } - }, - fsync(tty) { - if (tty.output?.length > 0) { - out(UTF8ArrayToString(tty.output)); - tty.output = []; - } - }, - ioctl_tcgets(tty) { - // typical setting - return { - c_iflag: 25856, - c_oflag: 5, - c_cflag: 191, - c_lflag: 35387, - c_cc: [ - 0x03, 0x1c, 0x7f, 0x15, 0x04, 0x00, 0x01, 0x00, 0x11, - 0x13, 0x1a, 0x00, 0x12, 0x0f, 0x17, 0x16, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, - ], - }; - }, - ioctl_tcsets(tty, optional_actions, data) { - // currently just ignore - return 0; - }, - ioctl_tiocgwinsz(tty) { - return [24, 80]; - }, - }, - default_tty1_ops: { - put_char(tty, val) { - if (val === null || val === 10) { - err(UTF8ArrayToString(tty.output)); - tty.output = []; - } else { - if (val != 0) tty.output.push(val); - } - }, - fsync(tty) { - if (tty.output?.length > 0) { - err(UTF8ArrayToString(tty.output)); - tty.output = []; - } - }, - }, - }; - - var zeroMemory = (ptr, size) => HEAPU8.fill(0, ptr, ptr + size); - - var mmapAlloc = (size) => { - size = alignMemory(size, 65536); - var ptr = _emscripten_builtin_memalign(65536, size); - if (ptr) zeroMemory(ptr, size); - return ptr; - }; - var MEMFS = { - ops_table: null, - mount(mount) { - return MEMFS.createNode(null, '/', 16895, 0); - }, - createNode(parent, name, mode, dev) { - if (FS.isBlkdev(mode) || FS.isFIFO(mode)) { - // no supported - throw new FS.ErrnoError(63); - } - MEMFS.ops_table ||= { - dir: { - node: { - getattr: MEMFS.node_ops.getattr, - setattr: MEMFS.node_ops.setattr, - lookup: MEMFS.node_ops.lookup, - mknod: MEMFS.node_ops.mknod, - rename: MEMFS.node_ops.rename, - unlink: MEMFS.node_ops.unlink, - rmdir: MEMFS.node_ops.rmdir, - readdir: MEMFS.node_ops.readdir, - symlink: MEMFS.node_ops.symlink, - }, - stream: { - llseek: MEMFS.stream_ops.llseek, - }, - }, - file: { - node: { - getattr: MEMFS.node_ops.getattr, - setattr: MEMFS.node_ops.setattr, - }, - stream: { - llseek: MEMFS.stream_ops.llseek, - read: MEMFS.stream_ops.read, - write: MEMFS.stream_ops.write, - mmap: MEMFS.stream_ops.mmap, - msync: MEMFS.stream_ops.msync, - }, - }, - link: { - node: { - getattr: MEMFS.node_ops.getattr, - setattr: MEMFS.node_ops.setattr, - readlink: MEMFS.node_ops.readlink, - }, - stream: {}, - }, - chrdev: { - node: { - getattr: MEMFS.node_ops.getattr, - setattr: MEMFS.node_ops.setattr, - }, - stream: FS.chrdev_stream_ops, - }, - }; - var node = FS.createNode(parent, name, mode, dev); - if (FS.isDir(node.mode)) { - node.node_ops = MEMFS.ops_table.dir.node; - node.stream_ops = MEMFS.ops_table.dir.stream; - node.contents = {}; - } else if (FS.isFile(node.mode)) { - node.node_ops = MEMFS.ops_table.file.node; - node.stream_ops = MEMFS.ops_table.file.stream; - node.usedBytes = 0; // The actual number of bytes used in the typed array, as opposed to contents.length which gives the whole capacity. - // When the byte data of the file is populated, this will point to either a typed array, or a normal JS array. Typed arrays are preferred - // for performance, and used by default. However, typed arrays are not resizable like normal JS arrays are, so there is a small disk size - // penalty involved for appending file writes that continuously grow a file similar to std::vector capacity vs used -scheme. - node.contents = null; - } else if (FS.isLink(node.mode)) { - node.node_ops = MEMFS.ops_table.link.node; - node.stream_ops = MEMFS.ops_table.link.stream; - } else if (FS.isChrdev(node.mode)) { - node.node_ops = MEMFS.ops_table.chrdev.node; - node.stream_ops = MEMFS.ops_table.chrdev.stream; - } - node.atime = node.mtime = node.ctime = Date.now(); - // add the new node to the parent - if (parent) { - parent.contents[name] = node; - parent.atime = parent.mtime = parent.ctime = node.atime; - } - return node; - }, - getFileDataAsTypedArray(node) { - if (!node.contents) return new Uint8Array(0); - if (node.contents.subarray) - return node.contents.subarray(0, node.usedBytes); // Make sure to not return excess unused bytes. - return new Uint8Array(node.contents); - }, - expandFileStorage(node, newCapacity) { - var prevCapacity = node.contents ? node.contents.length : 0; - if (prevCapacity >= newCapacity) return; // No need to expand, the storage was already large enough. - // Don't expand strictly to the given requested limit if it's only a very small increase, but instead geometrically grow capacity. - // For small filesizes (<1MB), perform size*2 geometric increase, but for large sizes, do a much more conservative size*1.125 increase to - // avoid overshooting the allocation cap by a very large margin. - var CAPACITY_DOUBLING_MAX = 1024 * 1024; - newCapacity = Math.max( - newCapacity, - (prevCapacity * - (prevCapacity < CAPACITY_DOUBLING_MAX ? 2.0 : 1.125)) >>> - 0 - ); - if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256); // At minimum allocate 256b for each file when expanding. - var oldContents = node.contents; - node.contents = new Uint8Array(newCapacity); // Allocate new storage. - if (node.usedBytes > 0) - node.contents.set(oldContents.subarray(0, node.usedBytes), 0); // Copy old data over to the new storage. - }, - resizeFileStorage(node, newSize) { - if (node.usedBytes == newSize) return; - if (newSize == 0) { - node.contents = null; // Fully decommit when requesting a resize to zero. - node.usedBytes = 0; - } else { - var oldContents = node.contents; - node.contents = new Uint8Array(newSize); // Allocate new storage. - if (oldContents) { - node.contents.set( - oldContents.subarray( - 0, - Math.min(newSize, node.usedBytes) - ) - ); // Copy old data over to the new storage. - } - node.usedBytes = newSize; - } - }, - node_ops: { - getattr(node) { - var attr = {}; - // device numbers reuse inode numbers. - attr.dev = FS.isChrdev(node.mode) ? node.id : 1; - attr.ino = node.id; - attr.mode = node.mode; - attr.nlink = 1; - attr.uid = 0; - attr.gid = 0; - attr.rdev = node.rdev; - if (FS.isDir(node.mode)) { - attr.size = 4096; - } else if (FS.isFile(node.mode)) { - attr.size = node.usedBytes; - } else if (FS.isLink(node.mode)) { - attr.size = node.link.length; - } else { - attr.size = 0; - } - attr.atime = new Date(node.atime); - attr.mtime = new Date(node.mtime); - attr.ctime = new Date(node.ctime); - // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize), - // but this is not required by the standard. - attr.blksize = 4096; - attr.blocks = Math.ceil(attr.size / attr.blksize); - return attr; - }, - setattr(node, attr) { - for (const key of ['mode', 'atime', 'mtime', 'ctime']) { - if (attr[key] != null) { - node[key] = attr[key]; - } - } - if (attr.size !== undefined) { - MEMFS.resizeFileStorage(node, attr.size); - } - }, - lookup(parent, name) { - // This error may happen quite a bit. To avoid overhead we reuse it (and - // suffer a lack of stack info). - if (!MEMFS.doesNotExistError) { - MEMFS.doesNotExistError = new FS.ErrnoError(44); - /** @suppress {checkTypes} */ - MEMFS.doesNotExistError.stack = ''; - } - throw MEMFS.doesNotExistError; - }, - mknod(parent, name, mode, dev) { - return MEMFS.createNode(parent, name, mode, dev); - }, - rename(old_node, new_dir, new_name) { - var new_node; - try { - new_node = FS.lookupNode(new_dir, new_name); - } catch (e) {} - if (new_node) { - if (FS.isDir(old_node.mode)) { - // if we're overwriting a directory at new_name, make sure it's empty. - for (var i in new_node.contents) { - throw new FS.ErrnoError(55); - } - } - FS.hashRemoveNode(new_node); - } - // do the internal rewiring - delete old_node.parent.contents[old_node.name]; - new_dir.contents[new_name] = old_node; - old_node.name = new_name; - new_dir.ctime = - new_dir.mtime = - old_node.parent.ctime = - old_node.parent.mtime = - Date.now(); - }, - unlink(parent, name) { - delete parent.contents[name]; - parent.ctime = parent.mtime = Date.now(); - }, - rmdir(parent, name) { - var node = FS.lookupNode(parent, name); - for (var i in node.contents) { - throw new FS.ErrnoError(55); - } - delete parent.contents[name]; - parent.ctime = parent.mtime = Date.now(); - }, - readdir(node) { - return ['.', '..', ...Object.keys(node.contents)]; - }, - symlink(parent, newname, oldpath) { - var node = MEMFS.createNode(parent, newname, 0o777 | 40960, 0); - node.link = oldpath; - return node; - }, - readlink(node) { - if (!FS.isLink(node.mode)) { - throw new FS.ErrnoError(28); - } - return node.link; - }, - }, - stream_ops: { - read(stream, buffer, offset, length, position) { - var contents = stream.node.contents; - if (position >= stream.node.usedBytes) return 0; - var size = Math.min(stream.node.usedBytes - position, length); - if (size > 8 && contents.subarray) { - // non-trivial, and typed array - buffer.set( - contents.subarray(position, position + size), - offset - ); - } else { - for (var i = 0; i < size; i++) - buffer[offset + i] = contents[position + i]; - } - return size; - }, - write(stream, buffer, offset, length, position, canOwn) { - // If the buffer is located in main memory (HEAP), and if - // memory can grow, we can't hold on to references of the - // memory buffer, as they may get invalidated. That means we - // need to do copy its contents. - if (buffer.buffer === HEAP8.buffer) { - canOwn = false; - } - - if (!length) return 0; - var node = stream.node; - node.mtime = node.ctime = Date.now(); - - if ( - buffer.subarray && - (!node.contents || node.contents.subarray) - ) { - // This write is from a typed array to a typed array? - if (canOwn) { - node.contents = buffer.subarray( - offset, - offset + length - ); - node.usedBytes = length; - return length; - } else if (node.usedBytes === 0 && position === 0) { - // If this is a simple first write to an empty file, do a fast set since we don't need to care about old data. - node.contents = buffer.slice(offset, offset + length); - node.usedBytes = length; - return length; - } else if (position + length <= node.usedBytes) { - // Writing to an already allocated and used subrange of the file? - node.contents.set( - buffer.subarray(offset, offset + length), - position - ); - return length; - } - } - - // Appending to an existing file and we need to reallocate, or source data did not come as a typed array. - MEMFS.expandFileStorage(node, position + length); - if (node.contents.subarray && buffer.subarray) { - // Use typed array write which is available. - node.contents.set( - buffer.subarray(offset, offset + length), - position - ); - } else { - for (var i = 0; i < length; i++) { - node.contents[position + i] = buffer[offset + i]; // Or fall back to manual write if not. - } - } - node.usedBytes = Math.max(node.usedBytes, position + length); - return length; - }, - llseek(stream, offset, whence) { - var position = offset; - if (whence === 1) { - position += stream.position; - } else if (whence === 2) { - if (FS.isFile(stream.node.mode)) { - position += stream.node.usedBytes; - } - } - if (position < 0) { - throw new FS.ErrnoError(28); - } - return position; - }, - mmap(stream, length, position, prot, flags) { - if (!FS.isFile(stream.node.mode)) { - throw new FS.ErrnoError(43); - } - var ptr; - var allocated; - var contents = stream.node.contents; - // Only make a new copy when MAP_PRIVATE is specified. - if ( - !(flags & 2) && - contents && - contents.buffer === HEAP8.buffer - ) { - // We can't emulate MAP_SHARED when the file is not backed by the - // buffer we're mapping to (e.g. the HEAP buffer). - allocated = false; - ptr = contents.byteOffset; - } else { - allocated = true; - ptr = mmapAlloc(length); - if (!ptr) { - throw new FS.ErrnoError(48); - } - if (contents) { - // Try to avoid unnecessary slices. - if ( - position > 0 || - position + length < contents.length - ) { - if (contents.subarray) { - contents = contents.subarray( - position, - position + length - ); - } else { - contents = Array.prototype.slice.call( - contents, - position, - position + length - ); - } - } - HEAP8.set(contents, ptr); - } - } - return { ptr, allocated }; - }, - msync(stream, buffer, offset, length, mmapFlags) { - MEMFS.stream_ops.write( - stream, - buffer, - 0, - length, - offset, - false - ); - // should we check if bytesWritten and length are the same? - return 0; - }, - }, - }; - - var FS_modeStringToFlags = (str) => { - var flagModes = { - r: 0, - 'r+': 2, - w: 512 | 64 | 1, - 'w+': 512 | 64 | 2, - a: 1024 | 64 | 1, - 'a+': 1024 | 64 | 2, - }; - var flags = flagModes[str]; - if (typeof flags == 'undefined') { - throw new Error(`Unknown file open mode: ${str}`); - } - return flags; - }; - - var FS_getMode = (canRead, canWrite) => { - var mode = 0; - if (canRead) mode |= 292 | 73; - if (canWrite) mode |= 146; - return mode; - }; - - var ERRNO_CODES = { - EPERM: 63, - ENOENT: 44, - ESRCH: 71, - EINTR: 27, - EIO: 29, - ENXIO: 60, - E2BIG: 1, - ENOEXEC: 45, - EBADF: 8, - ECHILD: 12, - EAGAIN: 6, - EWOULDBLOCK: 6, - ENOMEM: 48, - EACCES: 2, - EFAULT: 21, - ENOTBLK: 105, - EBUSY: 10, - EEXIST: 20, - EXDEV: 75, - ENODEV: 43, - ENOTDIR: 54, - EISDIR: 31, - EINVAL: 28, - ENFILE: 41, - EMFILE: 33, - ENOTTY: 59, - ETXTBSY: 74, - EFBIG: 22, - ENOSPC: 51, - ESPIPE: 70, - EROFS: 69, - EMLINK: 34, - EPIPE: 64, - EDOM: 18, - ERANGE: 68, - ENOMSG: 49, - EIDRM: 24, - ECHRNG: 106, - EL2NSYNC: 156, - EL3HLT: 107, - EL3RST: 108, - ELNRNG: 109, - EUNATCH: 110, - ENOCSI: 111, - EL2HLT: 112, - EDEADLK: 16, - ENOLCK: 46, - EBADE: 113, - EBADR: 114, - EXFULL: 115, - ENOANO: 104, - EBADRQC: 103, - EBADSLT: 102, - EDEADLOCK: 16, - EBFONT: 101, - ENOSTR: 100, - ENODATA: 116, - ETIME: 117, - ENOSR: 118, - ENONET: 119, - ENOPKG: 120, - EREMOTE: 121, - ENOLINK: 47, - EADV: 122, - ESRMNT: 123, - ECOMM: 124, - EPROTO: 65, - EMULTIHOP: 36, - EDOTDOT: 125, - EBADMSG: 9, - ENOTUNIQ: 126, - EBADFD: 127, - EREMCHG: 128, - ELIBACC: 129, - ELIBBAD: 130, - ELIBSCN: 131, - ELIBMAX: 132, - ELIBEXEC: 133, - ENOSYS: 52, - ENOTEMPTY: 55, - ENAMETOOLONG: 37, - ELOOP: 32, - EOPNOTSUPP: 138, - EPFNOSUPPORT: 139, - ECONNRESET: 15, - ENOBUFS: 42, - EAFNOSUPPORT: 5, - EPROTOTYPE: 67, - ENOTSOCK: 57, - ENOPROTOOPT: 50, - ESHUTDOWN: 140, - ECONNREFUSED: 14, - EADDRINUSE: 3, - ECONNABORTED: 13, - ENETUNREACH: 40, - ENETDOWN: 38, - ETIMEDOUT: 73, - EHOSTDOWN: 142, - EHOSTUNREACH: 23, - EINPROGRESS: 26, - EALREADY: 7, - EDESTADDRREQ: 17, - EMSGSIZE: 35, - EPROTONOSUPPORT: 66, - ESOCKTNOSUPPORT: 137, - EADDRNOTAVAIL: 4, - ENETRESET: 39, - EISCONN: 30, - ENOTCONN: 53, - ETOOMANYREFS: 141, - EUSERS: 136, - EDQUOT: 19, - ESTALE: 72, - ENOTSUP: 138, - ENOMEDIUM: 148, - EILSEQ: 25, - EOVERFLOW: 61, - ECANCELED: 11, - ENOTRECOVERABLE: 56, - EOWNERDEAD: 62, - ESTRPIPE: 135, - }; - - var NODEFS = { - isWindows: false, - staticInit() { - NODEFS.isWindows = !!process.platform.match(/^win/); - var flags = process.binding('constants')['fs']; - NODEFS.flagsForNodeMap = { - 1024: flags['O_APPEND'], - 64: flags['O_CREAT'], - 128: flags['O_EXCL'], - 256: flags['O_NOCTTY'], - 0: flags['O_RDONLY'], - 2: flags['O_RDWR'], - 4096: flags['O_SYNC'], - 512: flags['O_TRUNC'], - 1: flags['O_WRONLY'], - 131072: flags['O_NOFOLLOW'], - }; - }, - convertNodeCode(e) { - var code = e.code; - return ERRNO_CODES[code]; - }, - tryFSOperation(f) { - try { - return f(); - } catch (e) { - if (!e.code) throw e; - // node under windows can return code 'UNKNOWN' here: - // https://github.com/emscripten-core/emscripten/issues/15468 - if (e.code === 'UNKNOWN') throw new FS.ErrnoError(28); - throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); - } - }, - mount(mount) { - return NODEFS.createNode( - null, - '/', - NODEFS.getMode(mount.opts.root), - 0 - ); - }, - createNode(parent, name, mode, dev) { - if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) { - throw new FS.ErrnoError(28); - } - var node = FS.createNode(parent, name, mode); - node.node_ops = NODEFS.node_ops; - node.stream_ops = NODEFS.stream_ops; - return node; - }, - getMode(path) { - return NODEFS.tryFSOperation(() => { - var mode = fs.lstatSync(path).mode; - if (NODEFS.isWindows) { - // Windows does not report the 'x' permission bit, so propagate read - // bits to execute bits. - mode |= (mode & 292) >> 2; - } - return mode; - }); - }, - realPath(node) { - var parts = []; - while (node.parent !== node) { - parts.push(node.name); - node = node.parent; - } - parts.push(node.mount.opts.root); - parts.reverse(); - return PATH.join(...parts); - }, - flagsForNode(flags) { - flags &= ~2097152; // Ignore this flag from musl, otherwise node.js fails to open the file. - flags &= ~2048; // Ignore this flag from musl, otherwise node.js fails to open the file. - flags &= ~32768; // Ignore this flag from musl, otherwise node.js fails to open the file. - flags &= ~524288; // Some applications may pass it; it makes no sense for a single process. - flags &= ~65536; // Node.js doesn't need this passed in, it errors. - var newFlags = 0; - for (var k in NODEFS.flagsForNodeMap) { - if (flags & k) { - newFlags |= NODEFS.flagsForNodeMap[k]; - flags ^= k; - } - } - if (flags) { - throw new FS.ErrnoError(28); - } - return newFlags; - }, - getattr(func, node) { - var stat = NODEFS.tryFSOperation(func); - if (NODEFS.isWindows) { - // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake - // them with default blksize of 4096. - // See http://support.microsoft.com/kb/140365 - if (!stat.blksize) { - stat.blksize = 4096; - } - if (!stat.blocks) { - stat.blocks = - ((stat.size + stat.blksize - 1) / stat.blksize) | 0; - } - // Windows does not report the 'x' permission bit, so propagate read - // bits to execute bits. - stat.mode |= (stat.mode & 292) >> 2; - } - return { - dev: stat.dev, - ino: node.id, - mode: stat.mode, - nlink: stat.nlink, - uid: stat.uid, - gid: stat.gid, - rdev: stat.rdev, - size: stat.size, - atime: stat.atime, - mtime: stat.mtime, - ctime: stat.ctime, - blksize: stat.blksize, - blocks: stat.blocks, - }; - }, - setattr(arg, node, attr, chmod, utimes, truncate, stat) { - NODEFS.tryFSOperation(() => { - if (attr.mode !== undefined) { - var mode = attr.mode; - if (NODEFS.isWindows) { - // Windows only supports S_IREAD / S_IWRITE (S_IRUSR / S_IWUSR) - // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/chmod-wchmod - mode &= 384; - } - chmod(arg, mode); - // update the common node structure mode as well - node.mode = attr.mode; - } - if (typeof (attr.atime ?? attr.mtime) === 'number') { - // Unfortunately, we have to stat the current value if we don't want - // to change it. On top of that, since the times don't round trip - // this will only keep the value nearly unchanged not exactly - // unchanged. See: - // https://github.com/nodejs/node/issues/56492 - var atime = new Date(attr.atime ?? stat(arg).atime); - var mtime = new Date(attr.mtime ?? stat(arg).mtime); - utimes(arg, atime, mtime); - } - if (attr.size !== undefined) { - truncate(arg, attr.size); - } - }); - }, - node_ops: { - getattr(node) { - var path = NODEFS.realPath(node); - return NODEFS.getattr(() => fs.lstatSync(path), node); - }, - setattr(node, attr) { - var path = NODEFS.realPath(node); - if (attr.mode != null && attr.dontFollow) { - throw new FS.ErrnoError(52); - } - NODEFS.setattr( - path, - node, - attr, - fs.chmodSync, - fs.utimesSync, - fs.truncateSync, - fs.lstatSync - ); - }, - lookup(parent, name) { - var path = PATH.join2(NODEFS.realPath(parent), name); - var mode = NODEFS.getMode(path); - return NODEFS.createNode(parent, name, mode); - }, - mknod(parent, name, mode, dev) { - var node = NODEFS.createNode(parent, name, mode, dev); - // create the backing node for this in the fs root as well - var path = NODEFS.realPath(node); - NODEFS.tryFSOperation(() => { - if (FS.isDir(node.mode)) { - fs.mkdirSync(path, node.mode); - } else { - fs.writeFileSync(path, '', { mode: node.mode }); - } - }); - return node; - }, - rename(oldNode, newDir, newName) { - var oldPath = NODEFS.realPath(oldNode); - var newPath = PATH.join2(NODEFS.realPath(newDir), newName); - try { - FS.unlink(newPath); - } catch (e) {} - NODEFS.tryFSOperation(() => fs.renameSync(oldPath, newPath)); - oldNode.name = newName; - }, - unlink(parent, name) { - var path = PATH.join2(NODEFS.realPath(parent), name); - NODEFS.tryFSOperation(() => fs.unlinkSync(path)); - }, - rmdir(parent, name) { - var path = PATH.join2(NODEFS.realPath(parent), name); - NODEFS.tryFSOperation(() => fs.rmdirSync(path)); - }, - readdir(node) { - var path = NODEFS.realPath(node); - return NODEFS.tryFSOperation(() => fs.readdirSync(path)); - }, - symlink(parent, newName, oldPath) { - var newPath = PATH.join2(NODEFS.realPath(parent), newName); - NODEFS.tryFSOperation(() => fs.symlinkSync(oldPath, newPath)); - }, - readlink(node) { - var path = NODEFS.realPath(node); - return NODEFS.tryFSOperation(() => fs.readlinkSync(path)); - }, - statfs(path) { - var stats = NODEFS.tryFSOperation(() => fs.statfsSync(path)); - // Node.js doesn't provide frsize (fragment size). Set it to bsize (block size) - // as they're often the same in many file systems. May not be accurate for all. - stats.frsize = stats.bsize; - return stats; - }, - }, - stream_ops: { - getattr(stream) { - return NODEFS.getattr( - () => fs.fstatSync(stream.nfd), - stream.node - ); - }, - setattr(stream, attr) { - NODEFS.setattr( - stream.nfd, - stream.node, - attr, - fs.fchmodSync, - fs.futimesSync, - fs.ftruncateSync, - fs.fstatSync - ); - }, - open(stream) { - var path = NODEFS.realPath(stream.node); - NODEFS.tryFSOperation(() => { - stream.shared.refcount = 1; - stream.nfd = fs.openSync( - path, - NODEFS.flagsForNode(stream.flags) - ); - }); - }, - close(stream) { - NODEFS.tryFSOperation(() => { - if (stream.nfd && --stream.shared.refcount === 0) { - fs.closeSync(stream.nfd); - } - }); - }, - dup(stream) { - stream.shared.refcount++; - }, - read(stream, buffer, offset, length, position) { - return NODEFS.tryFSOperation(() => - fs.readSync( - stream.nfd, - new Int8Array(buffer.buffer, offset, length), - 0, - length, - position - ) - ); - }, - write(stream, buffer, offset, length, position) { - return NODEFS.tryFSOperation(() => - fs.writeSync( - stream.nfd, - new Int8Array(buffer.buffer, offset, length), - 0, - length, - position - ) - ); - }, - llseek(stream, offset, whence) { - var position = offset; - if (whence === 1) { - position += stream.position; - } else if (whence === 2) { - if (FS.isFile(stream.node.mode)) { - NODEFS.tryFSOperation(() => { - var stat = fs.fstatSync(stream.nfd); - position += stat.size; - }); - } - } - - if (position < 0) { - throw new FS.ErrnoError(28); - } - - return position; - }, - mmap(stream, length, position, prot, flags) { - if (!FS.isFile(stream.node.mode)) { - throw new FS.ErrnoError(43); - } - - var ptr = mmapAlloc(length); - - NODEFS.stream_ops.read(stream, HEAP8, ptr, length, position); - return { ptr, allocated: true }; - }, - msync(stream, buffer, offset, length, mmapFlags) { - NODEFS.stream_ops.write( - stream, - buffer, - 0, - length, - offset, - false - ); - // should we check if bytesWritten and length are the same? - return 0; - }, - }, - }; - - var PROXYFS = { - mount(mount) { - return PROXYFS.createNode( - null, - '/', - mount.opts.fs.lstat(mount.opts.root).mode, - 0 - ); - }, - createNode(parent, name, mode, dev) { - if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) { - throw new FS.ErrnoError(ERRNO_CODES.EINVAL); - } - var node = FS.createNode(parent, name, mode); - node.node_ops = PROXYFS.node_ops; - node.stream_ops = PROXYFS.stream_ops; - return node; - }, - realPath(node) { - var parts = []; - while (node.parent !== node) { - parts.push(node.name); - node = node.parent; - } - parts.push(node.mount.opts.root); - parts.reverse(); - return PATH.join(...parts); - }, - node_ops: { - getattr(node) { - var path = PROXYFS.realPath(node); - var stat; - try { - stat = node.mount.opts.fs.lstat(path); - } catch (e) { - if (!e.code) throw e; - throw new FS.ErrnoError(ERRNO_CODES[e.code]); - } - return { - dev: stat.dev, - ino: stat.ino, - mode: stat.mode, - nlink: stat.nlink, - uid: stat.uid, - gid: stat.gid, - rdev: stat.rdev, - size: stat.size, - atime: stat.atime, - mtime: stat.mtime, - ctime: stat.ctime, - blksize: stat.blksize, - blocks: stat.blocks, - }; - }, - setattr(node, attr) { - var path = PROXYFS.realPath(node); - try { - if (attr.mode !== undefined) { - node.mount.opts.fs.chmod(path, attr.mode); - // update the common node structure mode as well - node.mode = attr.mode; - } - if (attr.atime || attr.mtime) { - var atime = new Date(attr.atime || attr.mtime); - var mtime = new Date(attr.mtime || attr.atime); - node.mount.opts.fs.utime(path, atime, mtime); - } - if (attr.size !== undefined) { - node.mount.opts.fs.truncate(path, attr.size); - } - } catch (e) { - if (!e.code) throw e; - throw new FS.ErrnoError(ERRNO_CODES[e.code]); - } - }, - lookup(parent, name) { - try { - var path = PATH.join2(PROXYFS.realPath(parent), name); - var mode = parent.mount.opts.fs.lstat(path).mode; - var node = PROXYFS.createNode(parent, name, mode); - return node; - } catch (e) { - if (!e.code) throw e; - throw new FS.ErrnoError(ERRNO_CODES[e.code]); - } - }, - mknod(parent, name, mode, dev) { - var node = PROXYFS.createNode(parent, name, mode, dev); - // create the backing node for this in the fs root as well - var path = PROXYFS.realPath(node); - try { - if (FS.isDir(node.mode)) { - node.mount.opts.fs.mkdir(path, node.mode); - } else { - node.mount.opts.fs.writeFile(path, '', { - mode: node.mode, - }); - } - } catch (e) { - if (!e.code) throw e; - throw new FS.ErrnoError(ERRNO_CODES[e.code]); - } - return node; - }, - rename(oldNode, newDir, newName) { - var oldPath = PROXYFS.realPath(oldNode); - var newPath = PATH.join2(PROXYFS.realPath(newDir), newName); - try { - oldNode.mount.opts.fs.rename(oldPath, newPath); - oldNode.name = newName; - } catch (e) { - if (!e.code) throw e; - throw new FS.ErrnoError(ERRNO_CODES[e.code]); - } - }, - unlink(parent, name) { - var path = PATH.join2(PROXYFS.realPath(parent), name); - try { - parent.mount.opts.fs.unlink(path); - } catch (e) { - if (!e.code) throw e; - throw new FS.ErrnoError(ERRNO_CODES[e.code]); - } - }, - rmdir(parent, name) { - var path = PATH.join2(PROXYFS.realPath(parent), name); - try { - parent.mount.opts.fs.rmdir(path); - } catch (e) { - if (!e.code) throw e; - throw new FS.ErrnoError(ERRNO_CODES[e.code]); - } - }, - readdir(node) { - var path = PROXYFS.realPath(node); - try { - return node.mount.opts.fs.readdir(path); - } catch (e) { - if (!e.code) throw e; - throw new FS.ErrnoError(ERRNO_CODES[e.code]); - } - }, - symlink(parent, newName, oldPath) { - var newPath = PATH.join2(PROXYFS.realPath(parent), newName); - try { - parent.mount.opts.fs.symlink(oldPath, newPath); - } catch (e) { - if (!e.code) throw e; - throw new FS.ErrnoError(ERRNO_CODES[e.code]); - } - }, - readlink(node) { - var path = PROXYFS.realPath(node); - try { - return node.mount.opts.fs.readlink(path); - } catch (e) { - if (!e.code) throw e; - throw new FS.ErrnoError(ERRNO_CODES[e.code]); - } - }, - }, - stream_ops: { - open(stream) { - var path = PROXYFS.realPath(stream.node); - try { - stream.nfd = stream.node.mount.opts.fs.open( - path, - stream.flags - ); - } catch (e) { - if (!e.code) throw e; - throw new FS.ErrnoError(ERRNO_CODES[e.code]); - } - }, - close(stream) { - try { - stream.node.mount.opts.fs.close(stream.nfd); - } catch (e) { - if (!e.code) throw e; - throw new FS.ErrnoError(ERRNO_CODES[e.code]); - } - }, - read(stream, buffer, offset, length, position) { - try { - return stream.node.mount.opts.fs.read( - stream.nfd, - buffer, - offset, - length, - position - ); - } catch (e) { - if (!e.code) throw e; - throw new FS.ErrnoError(ERRNO_CODES[e.code]); - } - }, - write(stream, buffer, offset, length, position) { - try { - return stream.node.mount.opts.fs.write( - stream.nfd, - buffer, - offset, - length, - position - ); - } catch (e) { - if (!e.code) throw e; - throw new FS.ErrnoError(ERRNO_CODES[e.code]); - } - }, - llseek(stream, offset, whence) { - var position = offset; - if (whence === 1) { - position += stream.position; - } else if (whence === 2) { - if (FS.isFile(stream.node.mode)) { - try { - var stat = stream.node.node_ops.getattr( - stream.node - ); - position += stat.size; - } catch (e) { - throw new FS.ErrnoError(ERRNO_CODES[e.code]); - } - } - } - - if (position < 0) { - throw new FS.ErrnoError(ERRNO_CODES.EINVAL); - } - - return position; - }, - }, - }; - - var FS_createDataFile = (...args) => FS.createDataFile(...args); - - var getUniqueRunDependency = (id) => { - return id; - }; - - var FS_handledByPreloadPlugin = async (byteArray, fullname) => { - // Ensure plugins are ready. - if (typeof Browser != 'undefined') Browser.init(); - - for (var plugin of preloadPlugins) { - if (plugin['canHandle'](fullname)) { - return plugin['handle'](byteArray, fullname); - } - } - // In no plugin handled this file then return the original/unmodified - // byteArray. - return byteArray; - }; - var FS_preloadFile = async ( - parent, - name, - url, - canRead, - canWrite, - dontCreateFile, - canOwn, - preFinish - ) => { - // TODO we should allow people to just pass in a complete filename instead - // of parent and name being that we just join them anyways - var fullname = name - ? PATH_FS.resolve(PATH.join2(parent, name)) - : parent; - var dep = getUniqueRunDependency(`cp ${fullname}`); // might have several active requests for the same fullname - addRunDependency(dep); - - try { - var byteArray = url; - if (typeof url == 'string') { - byteArray = await asyncLoad(url); - } - - byteArray = await FS_handledByPreloadPlugin(byteArray, fullname); - preFinish?.(); - if (!dontCreateFile) { - FS_createDataFile( - parent, - name, - byteArray, - canRead, - canWrite, - canOwn - ); - } - } finally { - removeRunDependency(dep); - } - }; - var FS_createPreloadedFile = ( - parent, - name, - url, - canRead, - canWrite, - onload, - onerror, - dontCreateFile, - canOwn, - preFinish - ) => { - FS_preloadFile( - parent, - name, - url, - canRead, - canWrite, - dontCreateFile, - canOwn, - preFinish - ) - .then(onload) - .catch(onerror); - }; - var FS = { - root: null, - mounts: [], - devices: {}, - streams: [], - nextInode: 1, - nameTable: null, - currentPath: '/', - initialized: false, - ignorePermissions: true, - filesystems: null, - syncFSRequests: 0, - readFiles: {}, - ErrnoError: class { - name = 'ErrnoError'; - // We set the `name` property to be able to identify `FS.ErrnoError` - // - the `name` is a standard ECMA-262 property of error objects. Kind of good to have it anyway. - // - when using PROXYFS, an error can come from an underlying FS - // as different FS objects have their own FS.ErrnoError each, - // the test `err instanceof FS.ErrnoError` won't detect an error coming from another filesystem, causing bugs. - // we'll use the reliable test `err.name == "ErrnoError"` instead - constructor(errno) { - this.errno = errno; - } - }, - FSStream: class { - shared = {}; - get object() { - return this.node; - } - set object(val) { - this.node = val; - } - get isRead() { - return (this.flags & 2097155) !== 1; - } - get isWrite() { - return (this.flags & 2097155) !== 0; - } - get isAppend() { - return this.flags & 1024; - } - get flags() { - return this.shared.flags; - } - set flags(val) { - this.shared.flags = val; - } - get position() { - return this.shared.position; - } - set position(val) { - this.shared.position = val; - } - }, - FSNode: class { - node_ops = {}; - stream_ops = {}; - readMode = 292 | 73; - writeMode = 146; - mounted = null; - constructor(parent, name, mode, rdev) { - if (!parent) { - parent = this; // root node sets parent to itself - } - this.parent = parent; - this.mount = parent.mount; - this.id = FS.nextInode++; - this.name = name; - this.mode = mode; - this.rdev = rdev; - this.atime = this.mtime = this.ctime = Date.now(); - } - get read() { - return (this.mode & this.readMode) === this.readMode; - } - set read(val) { - val - ? (this.mode |= this.readMode) - : (this.mode &= ~this.readMode); - } - get write() { - return (this.mode & this.writeMode) === this.writeMode; - } - set write(val) { - val - ? (this.mode |= this.writeMode) - : (this.mode &= ~this.writeMode); - } - get isFolder() { - return FS.isDir(this.mode); - } - get isDevice() { - return FS.isChrdev(this.mode); - } - }, - lookupPath(path, opts = {}) { - if (!path) { - throw new FS.ErrnoError(44); - } - opts.follow_mount ??= true; - - if (!PATH.isAbs(path)) { - path = FS.cwd() + '/' + path; - } - - // limit max consecutive symlinks to 40 (SYMLOOP_MAX). - linkloop: for (var nlinks = 0; nlinks < 40; nlinks++) { - // split the absolute path - var parts = path.split('/').filter((p) => !!p); - - // start at the root - var current = FS.root; - var current_path = '/'; - - for (var i = 0; i < parts.length; i++) { - var islast = i === parts.length - 1; - if (islast && opts.parent) { - // stop resolving - break; - } - - if (parts[i] === '.') { - continue; - } - - if (parts[i] === '..') { - current_path = PATH.dirname(current_path); - if (FS.isRoot(current)) { - path = - current_path + - '/' + - parts.slice(i + 1).join('/'); - // We're making progress here, don't let many consecutive ..'s - // lead to ELOOP - nlinks--; - continue linkloop; - } else { - current = current.parent; - } - continue; - } - - current_path = PATH.join2(current_path, parts[i]); - try { - current = FS.lookupNode(current, parts[i]); - } catch (e) { - // if noent_okay is true, suppress a ENOENT in the last component - // and return an object with an undefined node. This is needed for - // resolving symlinks in the path when creating a file. - if (e?.errno === 44 && islast && opts.noent_okay) { - return { path: current_path }; - } - throw e; - } - - // jump to the mount's root node if this is a mountpoint - if ( - FS.isMountpoint(current) && - (!islast || opts.follow_mount) - ) { - current = current.mounted.root; - } - - // by default, lookupPath will not follow a symlink if it is the final path component. - // setting opts.follow = true will override this behavior. - if (FS.isLink(current.mode) && (!islast || opts.follow)) { - if (!current.node_ops.readlink) { - throw new FS.ErrnoError(52); - } - var link = current.node_ops.readlink(current); - if (!PATH.isAbs(link)) { - link = PATH.dirname(current_path) + '/' + link; - } - path = link + '/' + parts.slice(i + 1).join('/'); - continue linkloop; - } - } - return { path: current_path, node: current }; - } - throw new FS.ErrnoError(32); - }, - getPath(node) { - var path; - while (true) { - if (FS.isRoot(node)) { - var mount = node.mount.mountpoint; - if (!path) return mount; - return mount[mount.length - 1] !== '/' - ? `${mount}/${path}` - : mount + path; - } - path = path ? `${node.name}/${path}` : node.name; - node = node.parent; - } - }, - hashName(parentid, name) { - var hash = 0; - - for (var i = 0; i < name.length; i++) { - hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0; - } - return ((parentid + hash) >>> 0) % FS.nameTable.length; - }, - hashAddNode(node) { - var hash = FS.hashName(node.parent.id, node.name); - node.name_next = FS.nameTable[hash]; - FS.nameTable[hash] = node; - }, - hashRemoveNode(node) { - var hash = FS.hashName(node.parent.id, node.name); - if (FS.nameTable[hash] === node) { - FS.nameTable[hash] = node.name_next; - } else { - var current = FS.nameTable[hash]; - while (current) { - if (current.name_next === node) { - current.name_next = node.name_next; - break; - } - current = current.name_next; - } - } - }, - lookupNode(parent, name) { - var errCode = FS.mayLookup(parent); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - var hash = FS.hashName(parent.id, name); - for (var node = FS.nameTable[hash]; node; node = node.name_next) { - var nodeName = node.name; - if (node.parent.id === parent.id && nodeName === name) { - return node; - } - } - // if we failed to find it in the cache, call into the VFS - return FS.lookup(parent, name); - }, - createNode(parent, name, mode, rdev) { - var node = new FS.FSNode(parent, name, mode, rdev); - - FS.hashAddNode(node); - - return node; - }, - destroyNode(node) { - FS.hashRemoveNode(node); - }, - isRoot(node) { - return node === node.parent; - }, - isMountpoint(node) { - return !!node.mounted; - }, - isFile(mode) { - return (mode & 61440) === 32768; - }, - isDir(mode) { - return (mode & 61440) === 16384; - }, - isLink(mode) { - return (mode & 61440) === 40960; - }, - isChrdev(mode) { - return (mode & 61440) === 8192; - }, - isBlkdev(mode) { - return (mode & 61440) === 24576; - }, - isFIFO(mode) { - return (mode & 61440) === 4096; - }, - isSocket(mode) { - return (mode & 49152) === 49152; - }, - flagsToPermissionString(flag) { - var perms = ['r', 'w', 'rw'][flag & 3]; - if (flag & 512) { - perms += 'w'; - } - return perms; - }, - nodePermissions(node, perms) { - if (FS.ignorePermissions) { - return 0; - } - // return 0 if any user, group or owner bits are set. - if (perms.includes('r') && !(node.mode & 292)) { - return 2; - } else if (perms.includes('w') && !(node.mode & 146)) { - return 2; - } else if (perms.includes('x') && !(node.mode & 73)) { - return 2; - } - return 0; - }, - mayLookup(dir) { - if (!FS.isDir(dir.mode)) return 54; - var errCode = FS.nodePermissions(dir, 'x'); - if (errCode) return errCode; - if (!dir.node_ops.lookup) return 2; - return 0; - }, - mayCreate(dir, name) { - if (!FS.isDir(dir.mode)) { - return 54; - } - try { - var node = FS.lookupNode(dir, name); - return 20; - } catch (e) {} - return FS.nodePermissions(dir, 'wx'); - }, - mayDelete(dir, name, isdir) { - var node; - try { - node = FS.lookupNode(dir, name); - } catch (e) { - return e.errno; - } - var errCode = FS.nodePermissions(dir, 'wx'); - if (errCode) { - return errCode; - } - if (isdir) { - if (!FS.isDir(node.mode)) { - return 54; - } - if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) { - return 10; - } - } else { - if (FS.isDir(node.mode)) { - return 31; - } - } - return 0; - }, - mayOpen(node, flags) { - if (!node) { - return 44; - } - if (FS.isLink(node.mode)) { - return 32; - } else if (FS.isDir(node.mode)) { - if ( - FS.flagsToPermissionString(flags) !== 'r' || // opening for write - flags & (512 | 64) - ) { - // TODO: check for O_SEARCH? (== search for dir only) - return 31; - } - } - return FS.nodePermissions(node, FS.flagsToPermissionString(flags)); - }, - checkOpExists(op, err) { - if (!op) { - throw new FS.ErrnoError(err); - } - return op; - }, - MAX_OPEN_FDS: 4096, - nextfd() { - for (var fd = 0; fd <= FS.MAX_OPEN_FDS; fd++) { - if (!FS.streams[fd]) { - return fd; - } - } - throw new FS.ErrnoError(33); - }, - getStreamChecked(fd) { - var stream = FS.getStream(fd); - if (!stream) { - throw new FS.ErrnoError(8); - } - return stream; - }, - getStream: (fd) => FS.streams[fd], - createStream(stream, fd = -1) { - // clone it, so we can return an instance of FSStream - stream = Object.assign(new FS.FSStream(), stream); - if (fd == -1) { - fd = FS.nextfd(); - } - stream.fd = fd; - FS.streams[fd] = stream; - return stream; - }, - closeStream(fd) { - FS.streams[fd] = null; - }, - dupStream(origStream, fd = -1) { - var stream = FS.createStream(origStream, fd); - stream.stream_ops?.dup?.(stream); - return stream; - }, - doSetAttr(stream, node, attr) { - var setattr = stream?.stream_ops.setattr; - var arg = setattr ? stream : node; - setattr ??= node.node_ops.setattr; - FS.checkOpExists(setattr, 63); - setattr(arg, attr); - }, - chrdev_stream_ops: { - open(stream) { - var device = FS.getDevice(stream.node.rdev); - // override node's stream ops with the device's - stream.stream_ops = device.stream_ops; - // forward the open call - stream.stream_ops.open?.(stream); - }, - llseek() { - throw new FS.ErrnoError(70); - }, - }, - major: (dev) => dev >> 8, - minor: (dev) => dev & 0xff, - makedev: (ma, mi) => (ma << 8) | mi, - registerDevice(dev, ops) { - FS.devices[dev] = { stream_ops: ops }; - }, - getDevice: (dev) => FS.devices[dev], - getMounts(mount) { - var mounts = []; - var check = [mount]; - - while (check.length) { - var m = check.pop(); - - mounts.push(m); - - check.push(...m.mounts); - } - - return mounts; - }, - syncfs(populate, callback) { - if (typeof populate == 'function') { - callback = populate; - populate = false; - } - - FS.syncFSRequests++; - - if (FS.syncFSRequests > 1) { - err( - `warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work` - ); - } - - var mounts = FS.getMounts(FS.root.mount); - var completed = 0; - - function doCallback(errCode) { - FS.syncFSRequests--; - return callback(errCode); - } - - function done(errCode) { - if (errCode) { - if (!done.errored) { - done.errored = true; - return doCallback(errCode); - } - return; - } - if (++completed >= mounts.length) { - doCallback(null); - } - } - - // sync all mounts - for (var mount of mounts) { - if (mount.type.syncfs) { - mount.type.syncfs(mount, populate, done); - } else { - done(null); - } - } - }, - mount(type, opts, mountpoint) { - var root = mountpoint === '/'; - var pseudo = !mountpoint; - var node; - - if (root && FS.root) { - throw new FS.ErrnoError(10); - } else if (!root && !pseudo) { - var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); - - mountpoint = lookup.path; // use the absolute path - node = lookup.node; - - if (FS.isMountpoint(node)) { - throw new FS.ErrnoError(10); - } - } - - var mount = { - type, - opts, - mountpoint, - mounts: [], - }; - - // create a root node for the fs - var mountRoot = type.mount(mount); - mountRoot.mount = mount; - mount.root = mountRoot; - - if (root) { - FS.root = mountRoot; - } else if (node) { - // set as a mountpoint - node.mounted = mount; - - // add the new mount to the current mount's children - if (node.mount) { - node.mount.mounts.push(mount); - } - } - - return mountRoot; - }, - unmount(mountpoint) { - var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); - - if (!FS.isMountpoint(lookup.node)) { - throw new FS.ErrnoError(28); - } - - // destroy the nodes for this mount, and all its child mounts - var node = lookup.node; - var mount = node.mounted; - var mounts = FS.getMounts(mount); - - for (var [hash, current] of Object.entries(FS.nameTable)) { - while (current) { - var next = current.name_next; - - if (mounts.includes(current.mount)) { - FS.destroyNode(current); - } - - current = next; - } - } - - // no longer a mountpoint - node.mounted = null; - - // remove this mount from the child mounts - var idx = node.mount.mounts.indexOf(mount); - node.mount.mounts.splice(idx, 1); - }, - lookup(parent, name) { - return parent.node_ops.lookup(parent, name); - }, - mknod(path, mode, dev) { - var lookup = FS.lookupPath(path, { parent: true }); - var parent = lookup.node; - var name = PATH.basename(path); - if (!name) { - throw new FS.ErrnoError(28); - } - if (name === '.' || name === '..') { - throw new FS.ErrnoError(20); - } - var errCode = FS.mayCreate(parent, name); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!parent.node_ops.mknod) { - throw new FS.ErrnoError(63); - } - return parent.node_ops.mknod(parent, name, mode, dev); - }, - statfs(path) { - return FS.statfsNode(FS.lookupPath(path, { follow: true }).node); - }, - statfsStream(stream) { - // We keep a separate statfsStream function because noderawfs overrides - // it. In noderawfs, stream.node is sometimes null. Instead, we need to - // look at stream.path. - return FS.statfsNode(stream.node); - }, - statfsNode(node) { - // NOTE: None of the defaults here are true. We're just returning safe and - // sane values. Currently nodefs and rawfs replace these defaults, - // other file systems leave them alone. - var rtn = { - bsize: 4096, - frsize: 4096, - blocks: 1e6, - bfree: 5e5, - bavail: 5e5, - files: FS.nextInode, - ffree: FS.nextInode - 1, - fsid: 42, - flags: 2, - namelen: 255, - }; - - if (node.node_ops.statfs) { - Object.assign(rtn, node.node_ops.statfs(node.mount.opts.root)); - } - return rtn; - }, - create(path, mode = 0o666) { - mode &= 4095; - mode |= 32768; - return FS.mknod(path, mode, 0); - }, - mkdir(path, mode = 0o777) { - mode &= 511 | 512; - mode |= 16384; - return FS.mknod(path, mode, 0); - }, - mkdirTree(path, mode) { - var dirs = path.split('/'); - var d = ''; - for (var dir of dirs) { - if (!dir) continue; - if (d || PATH.isAbs(path)) d += '/'; - d += dir; - try { - FS.mkdir(d, mode); - } catch (e) { - if (e.errno != 20) throw e; - } - } - }, - mkdev(path, mode, dev) { - if (typeof dev == 'undefined') { - dev = mode; - mode = 0o666; - } - mode |= 8192; - return FS.mknod(path, mode, dev); - }, - symlink(oldpath, newpath) { - if (!PATH_FS.resolve(oldpath)) { - throw new FS.ErrnoError(44); - } - var lookup = FS.lookupPath(newpath, { parent: true }); - var parent = lookup.node; - if (!parent) { - throw new FS.ErrnoError(44); - } - var newname = PATH.basename(newpath); - var errCode = FS.mayCreate(parent, newname); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!parent.node_ops.symlink) { - throw new FS.ErrnoError(63); - } - return parent.node_ops.symlink(parent, newname, oldpath); - }, - rename(old_path, new_path) { - var old_dirname = PATH.dirname(old_path); - var new_dirname = PATH.dirname(new_path); - var old_name = PATH.basename(old_path); - var new_name = PATH.basename(new_path); - // parents must exist - var lookup, old_dir, new_dir; - - // let the errors from non existent directories percolate up - lookup = FS.lookupPath(old_path, { parent: true }); - old_dir = lookup.node; - lookup = FS.lookupPath(new_path, { parent: true }); - new_dir = lookup.node; - - if (!old_dir || !new_dir) throw new FS.ErrnoError(44); - // need to be part of the same mount - if (old_dir.mount !== new_dir.mount) { - throw new FS.ErrnoError(75); - } - // source must exist - var old_node = FS.lookupNode(old_dir, old_name); - // old path should not be an ancestor of the new path - var relative = PATH_FS.relative(old_path, new_dirname); - if (relative.charAt(0) !== '.') { - throw new FS.ErrnoError(28); - } - // new path should not be an ancestor of the old path - relative = PATH_FS.relative(new_path, old_dirname); - if (relative.charAt(0) !== '.') { - throw new FS.ErrnoError(55); - } - // see if the new path already exists - var new_node; - try { - new_node = FS.lookupNode(new_dir, new_name); - } catch (e) { - // not fatal - } - // early out if nothing needs to change - if (old_node === new_node) { - return; - } - // we'll need to delete the old entry - var isdir = FS.isDir(old_node.mode); - var errCode = FS.mayDelete(old_dir, old_name, isdir); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - // need delete permissions if we'll be overwriting. - // need create permissions if new doesn't already exist. - errCode = new_node - ? FS.mayDelete(new_dir, new_name, isdir) - : FS.mayCreate(new_dir, new_name); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!old_dir.node_ops.rename) { - throw new FS.ErrnoError(63); - } - if ( - FS.isMountpoint(old_node) || - (new_node && FS.isMountpoint(new_node)) - ) { - throw new FS.ErrnoError(10); - } - // if we are going to change the parent, check write permissions - if (new_dir !== old_dir) { - errCode = FS.nodePermissions(old_dir, 'w'); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - } - // remove the node from the lookup hash - FS.hashRemoveNode(old_node); - // do the underlying fs rename - try { - old_dir.node_ops.rename(old_node, new_dir, new_name); - // update old node (we do this here to avoid each backend - // needing to) - old_node.parent = new_dir; - } catch (e) { - throw e; - } finally { - // add the node back to the hash (in case node_ops.rename - // changed its name) - FS.hashAddNode(old_node); - } - }, - rmdir(path) { - var lookup = FS.lookupPath(path, { parent: true }); - var parent = lookup.node; - var name = PATH.basename(path); - var node = FS.lookupNode(parent, name); - var errCode = FS.mayDelete(parent, name, true); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - if (!parent.node_ops.rmdir) { - throw new FS.ErrnoError(63); - } - if (FS.isMountpoint(node)) { - throw new FS.ErrnoError(10); - } - parent.node_ops.rmdir(parent, name); - FS.destroyNode(node); - }, - readdir(path) { - var lookup = FS.lookupPath(path, { follow: true }); - var node = lookup.node; - var readdir = FS.checkOpExists(node.node_ops.readdir, 54); - return readdir(node); - }, - unlink(path) { - var lookup = FS.lookupPath(path, { parent: true }); - var parent = lookup.node; - if (!parent) { - throw new FS.ErrnoError(44); - } - var name = PATH.basename(path); - var node = FS.lookupNode(parent, name); - var errCode = FS.mayDelete(parent, name, false); - if (errCode) { - // According to POSIX, we should map EISDIR to EPERM, but - // we instead do what Linux does (and we must, as we use - // the musl linux libc). - throw new FS.ErrnoError(errCode); - } - if (!parent.node_ops.unlink) { - throw new FS.ErrnoError(63); - } - if (FS.isMountpoint(node)) { - throw new FS.ErrnoError(10); - } - parent.node_ops.unlink(parent, name); - FS.destroyNode(node); - }, - readlink(path) { - var lookup = FS.lookupPath(path); - var link = lookup.node; - if (!link) { - throw new FS.ErrnoError(44); - } - if (!link.node_ops.readlink) { - throw new FS.ErrnoError(28); - } - return link.node_ops.readlink(link); - }, - stat(path, dontFollow) { - var lookup = FS.lookupPath(path, { follow: !dontFollow }); - var node = lookup.node; - var getattr = FS.checkOpExists(node.node_ops.getattr, 63); - return getattr(node); - }, - fstat(fd) { - var stream = FS.getStreamChecked(fd); - var node = stream.node; - var getattr = stream.stream_ops.getattr; - var arg = getattr ? stream : node; - getattr ??= node.node_ops.getattr; - FS.checkOpExists(getattr, 63); - return getattr(arg); - }, - lstat(path) { - return FS.stat(path, true); - }, - doChmod(stream, node, mode, dontFollow) { - FS.doSetAttr(stream, node, { - mode: (mode & 4095) | (node.mode & ~4095), - ctime: Date.now(), - dontFollow, - }); - }, - chmod(path, mode, dontFollow) { - var node; - if (typeof path == 'string') { - var lookup = FS.lookupPath(path, { follow: !dontFollow }); - node = lookup.node; - } else { - node = path; - } - FS.doChmod(null, node, mode, dontFollow); - }, - lchmod(path, mode) { - FS.chmod(path, mode, true); - }, - fchmod(fd, mode) { - var stream = FS.getStreamChecked(fd); - FS.doChmod(stream, stream.node, mode, false); - }, - doChown(stream, node, dontFollow) { - FS.doSetAttr(stream, node, { - timestamp: Date.now(), - dontFollow, - // we ignore the uid / gid for now - }); - }, - chown(path, uid, gid, dontFollow) { - var node; - if (typeof path == 'string') { - var lookup = FS.lookupPath(path, { follow: !dontFollow }); - node = lookup.node; - } else { - node = path; - } - FS.doChown(null, node, dontFollow); - }, - lchown(path, uid, gid) { - FS.chown(path, uid, gid, true); - }, - fchown(fd, uid, gid) { - var stream = FS.getStreamChecked(fd); - FS.doChown(stream, stream.node, false); - }, - doTruncate(stream, node, len) { - if (FS.isDir(node.mode)) { - throw new FS.ErrnoError(31); - } - if (!FS.isFile(node.mode)) { - throw new FS.ErrnoError(28); - } - var errCode = FS.nodePermissions(node, 'w'); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - FS.doSetAttr(stream, node, { - size: len, - timestamp: Date.now(), - }); - }, - truncate(path, len) { - if (len < 0) { - throw new FS.ErrnoError(28); - } - var node; - if (typeof path == 'string') { - var lookup = FS.lookupPath(path, { follow: true }); - node = lookup.node; - } else { - node = path; - } - FS.doTruncate(null, node, len); - }, - ftruncate(fd, len) { - var stream = FS.getStreamChecked(fd); - if (len < 0 || (stream.flags & 2097155) === 0) { - throw new FS.ErrnoError(28); - } - FS.doTruncate(stream, stream.node, len); - }, - utime(path, atime, mtime) { - var lookup = FS.lookupPath(path, { follow: true }); - var node = lookup.node; - var setattr = FS.checkOpExists(node.node_ops.setattr, 63); - setattr(node, { - atime: atime, - mtime: mtime, - }); - }, - open(path, flags, mode = 0o666) { - if (path === '') { - throw new FS.ErrnoError(44); - } - flags = - typeof flags == 'string' ? FS_modeStringToFlags(flags) : flags; - if (flags & 64) { - mode = (mode & 4095) | 32768; - } else { - mode = 0; - } - var node; - var isDirPath; - if (typeof path == 'object') { - node = path; - } else { - isDirPath = path.endsWith('/'); - // noent_okay makes it so that if the final component of the path - // doesn't exist, lookupPath returns `node: undefined`. `path` will be - // updated to point to the target of all symlinks. - var lookup = FS.lookupPath(path, { - follow: !(flags & 131072), - noent_okay: true, - }); - node = lookup.node; - path = lookup.path; - } - // perhaps we need to create the node - var created = false; - if (flags & 64) { - if (node) { - // if O_CREAT and O_EXCL are set, error out if the node already exists - if (flags & 128) { - throw new FS.ErrnoError(20); - } - } else if (isDirPath) { - throw new FS.ErrnoError(31); - } else { - // node doesn't exist, try to create it - // Ignore the permission bits here to ensure we can `open` this new - // file below. We use chmod below the apply the permissions once the - // file is open. - node = FS.mknod(path, mode | 0o777, 0); - created = true; - } - } - if (!node) { - throw new FS.ErrnoError(44); - } - // can't truncate a device - if (FS.isChrdev(node.mode)) { - flags &= ~512; - } - // if asked only for a directory, then this must be one - if (flags & 65536 && !FS.isDir(node.mode)) { - throw new FS.ErrnoError(54); - } - // check permissions, if this is not a file we just created now (it is ok to - // create and write to a file with read-only permissions; it is read-only - // for later use) - if (!created) { - var errCode = FS.mayOpen(node, flags); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - } - // do truncation if necessary - if (flags & 512 && !created) { - FS.truncate(node, 0); - } - // we've already handled these, don't pass down to the underlying vfs - flags &= ~(128 | 512 | 131072); - - // register the stream with the filesystem - var stream = FS.createStream({ - node, - path: FS.getPath(node), // we want the absolute path to the node - flags, - seekable: true, - position: 0, - stream_ops: node.stream_ops, - // used by the file family libc calls (fopen, fwrite, ferror, etc.) - ungotten: [], - error: false, - }); - // call the new stream's open function - if (stream.stream_ops.open) { - stream.stream_ops.open(stream); - } - if (created) { - FS.chmod(node, mode & 0o777); - } - if (Module['logReadFiles'] && !(flags & 1)) { - if (!(path in FS.readFiles)) { - FS.readFiles[path] = 1; - } - } - return stream; - }, - close(stream) { - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if (stream.getdents) stream.getdents = null; // free readdir state - try { - if (stream.stream_ops.close) { - stream.stream_ops.close(stream); - } - } catch (e) { - throw e; - } finally { - FS.closeStream(stream.fd); - } - stream.fd = null; - }, - isClosed(stream) { - return stream.fd === null; - }, - llseek(stream, offset, whence) { - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if (!stream.seekable || !stream.stream_ops.llseek) { - throw new FS.ErrnoError(70); - } - if (whence != 0 && whence != 1 && whence != 2) { - throw new FS.ErrnoError(28); - } - stream.position = stream.stream_ops.llseek(stream, offset, whence); - stream.ungotten = []; - return stream.position; - }, - read(stream, buffer, offset, length, position) { - if (length < 0 || position < 0) { - throw new FS.ErrnoError(28); - } - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if ((stream.flags & 2097155) === 1) { - throw new FS.ErrnoError(8); - } - if (FS.isDir(stream.node.mode)) { - throw new FS.ErrnoError(31); - } - if (!stream.stream_ops.read) { - throw new FS.ErrnoError(28); - } - var seeking = typeof position != 'undefined'; - if (!seeking) { - position = stream.position; - } else if (!stream.seekable) { - throw new FS.ErrnoError(70); - } - var bytesRead = stream.stream_ops.read( - stream, - buffer, - offset, - length, - position - ); - if (!seeking) stream.position += bytesRead; - return bytesRead; - }, - write(stream, buffer, offset, length, position, canOwn) { - if (length < 0 || position < 0) { - throw new FS.ErrnoError(28); - } - if (FS.isClosed(stream)) { - throw new FS.ErrnoError(8); - } - if ((stream.flags & 2097155) === 0) { - throw new FS.ErrnoError(8); - } - if (FS.isDir(stream.node.mode)) { - throw new FS.ErrnoError(31); - } - if (!stream.stream_ops.write) { - throw new FS.ErrnoError(28); - } - if (stream.seekable && stream.flags & 1024) { - // seek to the end before writing in append mode - FS.llseek(stream, 0, 2); - } - var seeking = typeof position != 'undefined'; - if (!seeking) { - position = stream.position; - } else if (!stream.seekable) { - throw new FS.ErrnoError(70); - } - var bytesWritten = stream.stream_ops.write( - stream, - buffer, - offset, - length, - position, - canOwn - ); - if (!seeking) stream.position += bytesWritten; - return bytesWritten; - }, - mmap(stream, length, position, prot, flags) { - // User requests writing to file (prot & PROT_WRITE != 0). - // Checking if we have permissions to write to the file unless - // MAP_PRIVATE flag is set. According to POSIX spec it is possible - // to write to file opened in read-only mode with MAP_PRIVATE flag, - // as all modifications will be visible only in the memory of - // the current process. - if ( - (prot & 2) !== 0 && - (flags & 2) === 0 && - (stream.flags & 2097155) !== 2 - ) { - throw new FS.ErrnoError(2); - } - if ((stream.flags & 2097155) === 1) { - throw new FS.ErrnoError(2); - } - if (!stream.stream_ops.mmap) { - throw new FS.ErrnoError(43); - } - if (!length) { - throw new FS.ErrnoError(28); - } - return stream.stream_ops.mmap( - stream, - length, - position, - prot, - flags - ); - }, - msync(stream, buffer, offset, length, mmapFlags) { - if (!stream.stream_ops.msync) { - return 0; - } - return stream.stream_ops.msync( - stream, - buffer, - offset, - length, - mmapFlags - ); - }, - ioctl(stream, cmd, arg) { - if (!stream.stream_ops.ioctl) { - throw new FS.ErrnoError(59); - } - return stream.stream_ops.ioctl(stream, cmd, arg); - }, - readFile(path, opts = {}) { - opts.flags = opts.flags || 0; - opts.encoding = opts.encoding || 'binary'; - if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') { - abort(`Invalid encoding type "${opts.encoding}"`); - } - var stream = FS.open(path, opts.flags); - var stat = FS.stat(path); - var length = stat.size; - var buf = new Uint8Array(length); - FS.read(stream, buf, 0, length, 0); - if (opts.encoding === 'utf8') { - buf = UTF8ArrayToString(buf); - } - FS.close(stream); - return buf; - }, - writeFile(path, data, opts = {}) { - opts.flags = opts.flags || 577; - var stream = FS.open(path, opts.flags, opts.mode); - if (typeof data == 'string') { - data = new Uint8Array(intArrayFromString(data, true)); - } - if (ArrayBuffer.isView(data)) { - FS.write( - stream, - data, - 0, - data.byteLength, - undefined, - opts.canOwn - ); - } else { - abort('Unsupported data type'); - } - FS.close(stream); - }, - cwd: () => FS.currentPath, - chdir(path) { - var lookup = FS.lookupPath(path, { follow: true }); - if (lookup.node === null) { - throw new FS.ErrnoError(44); - } - if (!FS.isDir(lookup.node.mode)) { - throw new FS.ErrnoError(54); - } - var errCode = FS.nodePermissions(lookup.node, 'x'); - if (errCode) { - throw new FS.ErrnoError(errCode); - } - FS.currentPath = lookup.path; - }, - createDefaultDirectories() { - FS.mkdir('/tmp'); - FS.mkdir('/home'); - FS.mkdir('/home/web_user'); - }, - createDefaultDevices() { - // create /dev - FS.mkdir('/dev'); - // setup /dev/null - FS.registerDevice(FS.makedev(1, 3), { - read: () => 0, - write: (stream, buffer, offset, length, pos) => length, - llseek: () => 0, - }); - FS.mkdev('/dev/null', FS.makedev(1, 3)); - // setup /dev/tty and /dev/tty1 - // stderr needs to print output using err() rather than out() - // so we register a second tty just for it. - TTY.register(FS.makedev(5, 0), TTY.default_tty_ops); - TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops); - FS.mkdev('/dev/tty', FS.makedev(5, 0)); - FS.mkdev('/dev/tty1', FS.makedev(6, 0)); - // setup /dev/[u]random - // use a buffer to avoid overhead of individual crypto calls per byte - var randomBuffer = new Uint8Array(1024), - randomLeft = 0; - var randomByte = () => { - if (randomLeft === 0) { - randomFill(randomBuffer); - randomLeft = randomBuffer.byteLength; - } - return randomBuffer[--randomLeft]; - }; - FS.createDevice('/dev', 'random', randomByte); - FS.createDevice('/dev', 'urandom', randomByte); - // we're not going to emulate the actual shm device, - // just create the tmp dirs that reside in it commonly - FS.mkdir('/dev/shm'); - FS.mkdir('/dev/shm/tmp'); - }, - createSpecialDirectories() { - // create /proc/self/fd which allows /proc/self/fd/6 => readlink gives the - // name of the stream for fd 6 (see test_unistd_ttyname) - FS.mkdir('/proc'); - var proc_self = FS.mkdir('/proc/self'); - FS.mkdir('/proc/self/fd'); - FS.mount( - { - mount() { - var node = FS.createNode(proc_self, 'fd', 16895, 73); - node.stream_ops = { - llseek: MEMFS.stream_ops.llseek, - }; - node.node_ops = { - lookup(parent, name) { - var fd = +name; - var stream = FS.getStreamChecked(fd); - var ret = { - parent: null, - mount: { mountpoint: 'fake' }, - node_ops: { readlink: () => stream.path }, - id: fd + 1, - }; - ret.parent = ret; // make it look like a simple root node - return ret; - }, - readdir() { - return Array.from(FS.streams.entries()) - .filter(([k, v]) => v) - .map(([k, v]) => k.toString()); - }, - }; - return node; - }, - }, - {}, - '/proc/self/fd' - ); - }, - createStandardStreams(input, output, error) { - // TODO deprecate the old functionality of a single - // input / output callback and that utilizes FS.createDevice - // and instead require a unique set of stream ops - - // by default, we symlink the standard streams to the - // default tty devices. however, if the standard streams - // have been overwritten we create a unique device for - // them instead. - if (input) { - FS.createDevice('/dev', 'stdin', input); - } else { - FS.symlink('/dev/tty', '/dev/stdin'); - } - if (output) { - FS.createDevice('/dev', 'stdout', null, output); - } else { - FS.symlink('/dev/tty', '/dev/stdout'); - } - if (error) { - FS.createDevice('/dev', 'stderr', null, error); - } else { - FS.symlink('/dev/tty1', '/dev/stderr'); - } - - // open default streams for the stdin, stdout and stderr devices - var stdin = FS.open('/dev/stdin', 0); - var stdout = FS.open('/dev/stdout', 1); - var stderr = FS.open('/dev/stderr', 1); - }, - staticInit() { - FS.nameTable = new Array(4096); - - FS.mount(MEMFS, {}, '/'); - - FS.createDefaultDirectories(); - FS.createDefaultDevices(); - FS.createSpecialDirectories(); - - FS.filesystems = { - MEMFS: MEMFS, - NODEFS: NODEFS, - PROXYFS: PROXYFS, - }; - }, - init(input, output, error) { - FS.initialized = true; - - // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here - input ??= Module['stdin']; - output ??= Module['stdout']; - error ??= Module['stderr']; - - FS.createStandardStreams(input, output, error); - }, - quit() { - FS.initialized = false; - // force-flush all streams, so we get musl std streams printed out - _fflush(0); - // close all of our streams - for (var stream of FS.streams) { - if (stream) { - FS.close(stream); - } - } - }, - findObject(path, dontResolveLastLink) { - var ret = FS.analyzePath(path, dontResolveLastLink); - if (!ret.exists) { - return null; - } - return ret.object; - }, - analyzePath(path, dontResolveLastLink) { - // operate from within the context of the symlink's target - try { - var lookup = FS.lookupPath(path, { - follow: !dontResolveLastLink, - }); - path = lookup.path; - } catch (e) {} - var ret = { - isRoot: false, - exists: false, - error: 0, - name: null, - path: null, - object: null, - parentExists: false, - parentPath: null, - parentObject: null, - }; - try { - var lookup = FS.lookupPath(path, { parent: true }); - ret.parentExists = true; - ret.parentPath = lookup.path; - ret.parentObject = lookup.node; - ret.name = PATH.basename(path); - lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); - ret.exists = true; - ret.path = lookup.path; - ret.object = lookup.node; - ret.name = lookup.node.name; - ret.isRoot = lookup.path === '/'; - } catch (e) { - ret.error = e.errno; - } - return ret; - }, - createPath(parent, path, canRead, canWrite) { - parent = typeof parent == 'string' ? parent : FS.getPath(parent); - var parts = path.split('/').reverse(); - while (parts.length) { - var part = parts.pop(); - if (!part) continue; - var current = PATH.join2(parent, part); - try { - FS.mkdir(current); - } catch (e) { - if (e.errno != 20) throw e; - } - parent = current; - } - return current; - }, - createFile(parent, name, properties, canRead, canWrite) { - var path = PATH.join2( - typeof parent == 'string' ? parent : FS.getPath(parent), - name - ); - var mode = FS_getMode(canRead, canWrite); - return FS.create(path, mode); - }, - createDataFile(parent, name, data, canRead, canWrite, canOwn) { - var path = name; - if (parent) { - parent = - typeof parent == 'string' ? parent : FS.getPath(parent); - path = name ? PATH.join2(parent, name) : parent; - } - var mode = FS_getMode(canRead, canWrite); - var node = FS.create(path, mode); - if (data) { - if (typeof data == 'string') { - var arr = new Array(data.length); - for (var i = 0, len = data.length; i < len; ++i) - arr[i] = data.charCodeAt(i); - data = arr; - } - // make sure we can write to the file - FS.chmod(node, mode | 146); - var stream = FS.open(node, 577); - FS.write(stream, data, 0, data.length, 0, canOwn); - FS.close(stream); - FS.chmod(node, mode); - } - }, - createDevice(parent, name, input, output) { - var path = PATH.join2( - typeof parent == 'string' ? parent : FS.getPath(parent), - name - ); - var mode = FS_getMode(!!input, !!output); - FS.createDevice.major ??= 64; - var dev = FS.makedev(FS.createDevice.major++, 0); - // Create a fake device that a set of stream ops to emulate - // the old behavior. - FS.registerDevice(dev, { - open(stream) { - stream.seekable = false; - }, - close(stream) { - // flush any pending line data - if (output?.buffer?.length) { - output(10); - } - }, - read(stream, buffer, offset, length, pos /* ignored */) { - var bytesRead = 0; - for (var i = 0; i < length; i++) { - var result; - try { - result = input(); - } catch (e) { - throw new FS.ErrnoError(29); - } - if (result === undefined && bytesRead === 0) { - throw new FS.ErrnoError(6); - } - if (result === null || result === undefined) break; - bytesRead++; - buffer[offset + i] = result; - } - if (bytesRead) { - stream.node.atime = Date.now(); - } - return bytesRead; - }, - write(stream, buffer, offset, length, pos) { - for (var i = 0; i < length; i++) { - try { - output(buffer[offset + i]); - } catch (e) { - throw new FS.ErrnoError(29); - } - } - if (length) { - stream.node.mtime = stream.node.ctime = Date.now(); - } - return i; - }, - }); - return FS.mkdev(path, mode, dev); - }, - forceLoadFile(obj) { - if (obj.isDevice || obj.isFolder || obj.link || obj.contents) - return true; - if (globalThis.XMLHttpRequest) { - abort( - 'Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.' - ); - } else { - // Command-line. - try { - obj.contents = readBinary(obj.url); - } catch (e) { - throw new FS.ErrnoError(29); - } - } - }, - createLazyFile(parent, name, url, canRead, canWrite) { - // Lazy chunked Uint8Array (implements get and length from Uint8Array). - // Actual getting is abstracted away for eventual reuse. - class LazyUint8Array { - lengthKnown = false; - chunks = []; // Loaded chunks. Index is the chunk number - get(idx) { - if (idx > this.length - 1 || idx < 0) { - return undefined; - } - var chunkOffset = idx % this.chunkSize; - var chunkNum = (idx / this.chunkSize) | 0; - return this.getter(chunkNum)[chunkOffset]; - } - setDataGetter(getter) { - this.getter = getter; - } - cacheLength() { - // Find length - var xhr = new XMLHttpRequest(); - xhr.open('HEAD', url, false); - xhr.send(null); - if ( - !( - (xhr.status >= 200 && xhr.status < 300) || - xhr.status === 304 - ) - ) - abort( - "Couldn't load " + url + '. Status: ' + xhr.status - ); - var datalength = Number( - xhr.getResponseHeader('Content-length') - ); - var header; - var hasByteServing = - (header = xhr.getResponseHeader('Accept-Ranges')) && - header === 'bytes'; - var usesGzip = - (header = xhr.getResponseHeader('Content-Encoding')) && - header === 'gzip'; - - var chunkSize = 1024 * 1024; // Chunk size in bytes - - if (!hasByteServing) chunkSize = datalength; - - // Function to get a range from the remote URL. - var doXHR = (from, to) => { - if (from > to) - abort( - 'invalid range (' + - from + - ', ' + - to + - ') or no bytes requested!' - ); - if (to > datalength - 1) - abort( - 'only ' + - datalength + - ' bytes available! programmer error!' - ); - - // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available. - var xhr = new XMLHttpRequest(); - xhr.open('GET', url, false); - if (datalength !== chunkSize) - xhr.setRequestHeader( - 'Range', - 'bytes=' + from + '-' + to - ); - - // Some hints to the browser that we want binary data. - xhr.responseType = 'arraybuffer'; - if (xhr.overrideMimeType) { - xhr.overrideMimeType( - 'text/plain; charset=x-user-defined' - ); - } - - xhr.send(null); - if ( - !( - (xhr.status >= 200 && xhr.status < 300) || - xhr.status === 304 - ) - ) - abort( - "Couldn't load " + - url + - '. Status: ' + - xhr.status - ); - if (xhr.response !== undefined) { - return new Uint8Array( - /** @type{Array} */ (xhr.response || []) - ); - } - return intArrayFromString(xhr.responseText || '', true); - }; - var lazyArray = this; - lazyArray.setDataGetter((chunkNum) => { - var start = chunkNum * chunkSize; - var end = (chunkNum + 1) * chunkSize - 1; // including this byte - end = Math.min(end, datalength - 1); // if datalength-1 is selected, this is the last block - if (typeof lazyArray.chunks[chunkNum] == 'undefined') { - lazyArray.chunks[chunkNum] = doXHR(start, end); - } - if (typeof lazyArray.chunks[chunkNum] == 'undefined') - abort('doXHR failed!'); - return lazyArray.chunks[chunkNum]; - }); - - if (usesGzip || !datalength) { - // if the server uses gzip or doesn't supply the length, we have to download the whole file to get the (uncompressed) length - chunkSize = datalength = 1; // this will force getter(0)/doXHR do download the whole file - datalength = this.getter(0).length; - chunkSize = datalength; - out( - 'LazyFiles on gzip forces download of the whole file when length is accessed' - ); - } - - this._length = datalength; - this._chunkSize = chunkSize; - this.lengthKnown = true; - } - get length() { - if (!this.lengthKnown) { - this.cacheLength(); - } - return this._length; - } - get chunkSize() { - if (!this.lengthKnown) { - this.cacheLength(); - } - return this._chunkSize; - } - } - - if (globalThis.XMLHttpRequest) { - if (!ENVIRONMENT_IS_WORKER) - abort( - 'Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc' - ); - var lazyArray = new LazyUint8Array(); - var properties = { isDevice: false, contents: lazyArray }; - } else { - var properties = { isDevice: false, url: url }; - } - - var node = FS.createFile( - parent, - name, - properties, - canRead, - canWrite - ); - // This is a total hack, but I want to get this lazy file code out of the - // core of MEMFS. If we want to keep this lazy file concept I feel it should - // be its own thin LAZYFS proxying calls to MEMFS. - if (properties.contents) { - node.contents = properties.contents; - } else if (properties.url) { - node.contents = null; - node.url = properties.url; - } - // Add a function that defers querying the file size until it is asked the first time. - Object.defineProperties(node, { - usedBytes: { - get: function () { - return this.contents.length; - }, - }, - }); - // override each stream op with one that tries to force load the lazy file first - var stream_ops = {}; - for (const [key, fn] of Object.entries(node.stream_ops)) { - stream_ops[key] = (...args) => { - FS.forceLoadFile(node); - return fn(...args); - }; - } - function writeChunks(stream, buffer, offset, length, position) { - var contents = stream.node.contents; - if (position >= contents.length) return 0; - var size = Math.min(contents.length - position, length); - if (contents.slice) { - // normal array - for (var i = 0; i < size; i++) { - buffer[offset + i] = contents[position + i]; - } - } else { - for (var i = 0; i < size; i++) { - // LazyUint8Array from sync binary XHR - buffer[offset + i] = contents.get(position + i); - } - } - return size; - } - // use a custom read function - stream_ops.read = (stream, buffer, offset, length, position) => { - FS.forceLoadFile(node); - return writeChunks(stream, buffer, offset, length, position); - }; - // use a custom mmap function - stream_ops.mmap = (stream, length, position, prot, flags) => { - FS.forceLoadFile(node); - var ptr = mmapAlloc(length); - if (!ptr) { - throw new FS.ErrnoError(48); - } - writeChunks(stream, HEAP8, ptr, length, position); - return { ptr, allocated: true }; - }; - node.stream_ops = stream_ops; - return node; - }, - }; - - var findLibraryFS = (libName, rpath) => { - // If we're preloading a dynamic library, the runtime is not ready to call - // __wasmfs_identify or __emscripten_find_dylib. So just quit out. - // - // This means that DT_NEEDED for the main module and transitive dependencies - // of it won't work with this code path. Similarly, it means that calling - // loadDynamicLibrary in a preRun hook can't use this code path. - if (!runtimeInitialized) { - return undefined; - } - if (PATH.isAbs(libName)) { - try { - FS.lookupPath(libName); - return libName; - } catch (e) { - return undefined; - } - } - var rpathResolved = (rpath?.paths || []).map((p) => - replaceORIGIN(rpath?.parentLibPath, p) - ); - return withStackSave(() => { - // In dylink.c we use: `char buf[2*NAME_MAX+2];` and NAME_MAX is 255. - // So we use the same size here. - var bufSize = 2 * 255 + 2; - var buf = stackAlloc(bufSize); - var rpathC = stringToUTF8OnStack(rpathResolved.join(':')); - var libNameC = stringToUTF8OnStack(libName); - var resLibNameC = __emscripten_find_dylib( - buf, - rpathC, - libNameC, - bufSize - ); - return resLibNameC ? UTF8ToString(resLibNameC) : undefined; - }); - }; - - var registerDynCallSymbols = (exports) => { - for (var [sym, exp] of Object.entries(exports)) { - if (sym.startsWith('dynCall_')) { - var sig = sym.substring(8); - if (!dynCalls.hasOwnProperty(sig)) { - dynCalls[sig] = exp; - } - } - } - }; - - /** - * @param {number=} handle - * @param {Object=} localScope - */ - function loadDynamicLibrary( - libName, - flags = { global: true, nodelete: true }, - localScope, - handle - ) { - // when loadDynamicLibrary did not have flags, libraries were loaded - // globally & permanently - - var dso = LDSO.loadedLibsByName[libName]; - if (dso) { - // the library is being loaded or has been loaded already. - if (!flags.global) { - if (localScope) { - Object.assign(localScope, dso.exports); - } - registerDynCallSymbols(dso.exports); - } else if (!dso.global) { - // The library was previously loaded only locally but not - // we have a request with global=true. - dso.global = true; - mergeLibSymbols(dso.exports, libName); - } - // same for "nodelete" - if (flags.nodelete && dso.refcount !== Infinity) { - dso.refcount = Infinity; - } - dso.refcount++; - if (handle) { - LDSO.loadedLibsByHandle[handle] = dso; - } - return flags.loadAsync ? Promise.resolve(true) : true; - } - - // allocate new DSO - dso = newDSO(libName, handle, 'loading'); - dso.refcount = flags.nodelete ? Infinity : 1; - dso.global = flags.global; - - // libName -> libData - function loadLibData() { - // for wasm, we can use fetch for async, but for fs mode we can only imitate it - if (handle) { - var data = HEAPU32[(handle + 28) >> 2]; - var dataSize = HEAPU32[(handle + 32) >> 2]; - if (data && dataSize) { - var libData = HEAP8.slice(data, data + dataSize); - return flags.loadAsync ? Promise.resolve(libData) : libData; - } - } - - var f = findLibraryFS(libName, flags.rpath); - if (f) { - var libData = FS.readFile(f, { encoding: 'binary' }); - return flags.loadAsync ? Promise.resolve(libData) : libData; - } - - var libFile = locateFile(libName); - if (flags.loadAsync) { - return asyncLoad(libFile); - } - - // load the binary synchronously - if (!readBinary) { - throw new Error( - `${libFile}: file not found, and synchronous loading of external files is not available` - ); - } - return readBinary(libFile); - } - - // libName -> exports - function getExports() { - // lookup preloaded cache first - var preloaded = preloadedWasm[libName]; - if (preloaded) { - return flags.loadAsync ? Promise.resolve(preloaded) : preloaded; - } - - // module not preloaded - load lib data and create new module from it - if (flags.loadAsync) { - return loadLibData().then((libData) => - loadWebAssemblyModule( - libData, - flags, - libName, - localScope, - handle - ) - ); - } - - return loadWebAssemblyModule( - loadLibData(), - flags, - libName, - localScope, - handle - ); - } - - // module for lib is loaded - update the dso & global namespace - function moduleLoaded(exports) { - if (dso.global) { - mergeLibSymbols(exports, libName); - } else if (localScope) { - Object.assign(localScope, exports); - registerDynCallSymbols(exports); - } - dso.exports = exports; - } - - if (flags.loadAsync) { - return getExports().then((exports) => { - moduleLoaded(exports); - return true; - }); - } - - moduleLoaded(getExports()); - return true; - } +function postRun() { + // PThreads reuse the runtime from the main thread. - var reportUndefinedSymbols = () => { - for (var [symName, entry] of Object.entries(GOT)) { - if (entry.value == -1) { - var value = resolveGlobalSymbol(symName, true).sym; - if (!value && !entry.required) { - // Ignore undefined symbols that are imported as weak. - entry.value = 0; - continue; - } - if (typeof value == 'function') { - /** @suppress {checkTypes} */ - entry.value = addFunction(value, value.sig); - } else if (typeof value == 'number') { - entry.value = value; - } else { - throw new Error( - `bad export type for '${symName}': ${typeof value} (${value})` - ); - } - } - } - }; - - var loadDylibs = async () => { - if (!dynamicLibraries.length) { - reportUndefinedSymbols(); - return; - } - - addRunDependency('loadDylibs'); - - // Load binaries asynchronously - for (var lib of dynamicLibraries) { - await loadDynamicLibrary(lib, { - loadAsync: true, - global: true, - nodelete: true, - allowUndefined: true, - }); - } - // we got them all, wonderful - reportUndefinedSymbols(); - - removeRunDependency('loadDylibs'); - }; - - var noExitRuntime = false; - - /** - * @param {number} ptr - * @param {number} value - * @param {string} type - */ - function setValue(ptr, value, type = 'i8') { - if (type.endsWith('*')) type = '*'; - switch (type) { - case 'i1': - HEAP8[ptr] = value; - break; - case 'i8': - HEAP8[ptr] = value; - break; - case 'i16': - HEAP16[ptr >> 1] = value; - break; - case 'i32': - HEAP32[ptr >> 2] = value; - break; - case 'i64': - HEAP64[ptr >> 3] = BigInt(value); - break; - case 'float': - HEAPF32[ptr >> 2] = value; - break; - case 'double': - HEAPF64[ptr >> 3] = value; - break; - case '*': - HEAPU32[ptr >> 2] = value; - break; - default: - abort(`invalid type for setValue: ${type}`); - } - } + if (Module['postRun']) { + if (typeof Module['postRun'] == 'function') Module['postRun'] = [Module['postRun']]; + while (Module['postRun'].length) { + addOnPostRun(Module['postRun'].shift()); + } + } - var ___assert_fail = (condition, filename, line, func) => - abort( - `Assertion failed: ${UTF8ToString(condition)}, at: ` + - [ - filename ? UTF8ToString(filename) : 'unknown filename', - line, - func ? UTF8ToString(func) : 'unknown function', - ] - ); - ___assert_fail.sig = 'vppip'; - - var ___asyncify_data = new WebAssembly.Global( - { value: 'i32', mutable: true }, - 0 - ); - - var ___asyncify_state = new WebAssembly.Global( - { value: 'i32', mutable: true }, - 0 - ); - - var ___call_sighandler = (fp, sig) => - (( - a1 - ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - sig - ); - ___call_sighandler.sig = 'vpi'; - - var exceptionLast = 0; - - class ExceptionInfo { - // excPtr - Thrown object pointer to wrap. Metadata pointer is calculated from it. - constructor(excPtr) { - this.excPtr = excPtr; - this.ptr = excPtr - 24; - } - - set_type(type) { - HEAPU32[(this.ptr + 4) >> 2] = type; - } - - get_type() { - return HEAPU32[(this.ptr + 4) >> 2]; - } - - set_destructor(destructor) { - HEAPU32[(this.ptr + 8) >> 2] = destructor; - } - - get_destructor() { - return HEAPU32[(this.ptr + 8) >> 2]; - } - - set_caught(caught) { - caught = caught ? 1 : 0; - HEAP8[this.ptr + 12] = caught; - } - - get_caught() { - return HEAP8[this.ptr + 12] != 0; - } - - set_rethrown(rethrown) { - rethrown = rethrown ? 1 : 0; - HEAP8[this.ptr + 13] = rethrown; - } - - get_rethrown() { - return HEAP8[this.ptr + 13] != 0; - } - - // Initialize native structure fields. Should be called once after allocated. - init(type, destructor) { - this.set_adjusted_ptr(0); - this.set_type(type); - this.set_destructor(destructor); - } - - set_adjusted_ptr(adjustedPtr) { - HEAPU32[(this.ptr + 16) >> 2] = adjustedPtr; - } - - get_adjusted_ptr() { - return HEAPU32[(this.ptr + 16) >> 2]; - } - } + // Begin ATPOSTRUNS hooks + callRuntimeCallbacks(onPostRuns); + // End ATPOSTRUNS hooks +} - var setTempRet0 = (val) => __emscripten_tempret_set(val); - var findMatchingCatch = (args) => { - var thrown = exceptionLast; - if (!thrown) { - // just pass through the null ptr - setTempRet0(0); - return 0; - } - var info = new ExceptionInfo(thrown); - info.set_adjusted_ptr(thrown); - var thrownType = info.get_type(); - if (!thrownType) { - // just pass through the thrown ptr - setTempRet0(0); - return thrown; - } - - // can_catch receives a **, add indirection - // The different catch blocks are denoted by different types. - // Due to inheritance, those types may not precisely match the - // type of the thrown object. Find one which matches, and - // return the type of the catch block which should be called. - for (var caughtType of args) { - if (caughtType === 0 || caughtType === thrownType) { - // Catch all clause matched or exactly the same type is caught - break; - } - var adjusted_ptr_addr = info.ptr + 16; - if (___cxa_can_catch(caughtType, thrownType, adjusted_ptr_addr)) { - setTempRet0(caughtType); - return thrown; - } - } - setTempRet0(thrownType); - return thrown; - }; - var ___cxa_find_matching_catch_2 = () => findMatchingCatch([]); - ___cxa_find_matching_catch_2.sig = 'p'; - - var ___resumeException = (ptr) => { - if (!exceptionLast) { - exceptionLast = ptr; - } - throw exceptionLast; - }; - ___resumeException.sig = 'vp'; - - var SYSCALLS = { - DEFAULT_POLLMASK: 5, - calculateAt(dirfd, path, allowEmpty) { - if (PATH.isAbs(path)) { - return path; - } - // relative path - var dir; - if (dirfd === -100) { - dir = FS.cwd(); - } else { - var dirstream = SYSCALLS.getStreamFromFD(dirfd); - dir = dirstream.path; - } - if (path.length == 0) { - if (!allowEmpty) { - throw new FS.ErrnoError(44); - } - return dir; - } - return dir + '/' + path; - }, - writeStat(buf, stat) { - HEAPU32[buf >> 2] = stat.dev; - HEAPU32[(buf + 4) >> 2] = stat.mode; - HEAPU32[(buf + 8) >> 2] = stat.nlink; - HEAPU32[(buf + 12) >> 2] = stat.uid; - HEAPU32[(buf + 16) >> 2] = stat.gid; - HEAPU32[(buf + 20) >> 2] = stat.rdev; - HEAP64[(buf + 24) >> 3] = BigInt(stat.size); - HEAP32[(buf + 32) >> 2] = 4096; - HEAP32[(buf + 36) >> 2] = stat.blocks; - var atime = stat.atime.getTime(); - var mtime = stat.mtime.getTime(); - var ctime = stat.ctime.getTime(); - HEAP64[(buf + 40) >> 3] = BigInt(Math.floor(atime / 1000)); - HEAPU32[(buf + 48) >> 2] = (atime % 1000) * 1000 * 1000; - HEAP64[(buf + 56) >> 3] = BigInt(Math.floor(mtime / 1000)); - HEAPU32[(buf + 64) >> 2] = (mtime % 1000) * 1000 * 1000; - HEAP64[(buf + 72) >> 3] = BigInt(Math.floor(ctime / 1000)); - HEAPU32[(buf + 80) >> 2] = (ctime % 1000) * 1000 * 1000; - HEAP64[(buf + 88) >> 3] = BigInt(stat.ino); - return 0; - }, - writeStatFs(buf, stats) { - HEAPU32[(buf + 4) >> 2] = stats.bsize; - HEAPU32[(buf + 60) >> 2] = stats.bsize; - HEAP64[(buf + 8) >> 3] = BigInt(stats.blocks); - HEAP64[(buf + 16) >> 3] = BigInt(stats.bfree); - HEAP64[(buf + 24) >> 3] = BigInt(stats.bavail); - HEAP64[(buf + 32) >> 3] = BigInt(stats.files); - HEAP64[(buf + 40) >> 3] = BigInt(stats.ffree); - HEAPU32[(buf + 48) >> 2] = stats.fsid; - HEAPU32[(buf + 64) >> 2] = stats.flags; // ST_NOSUID - HEAPU32[(buf + 56) >> 2] = stats.namelen; - }, - doMsync(addr, stream, len, flags, offset) { - if (!FS.isFile(stream.node.mode)) { - throw new FS.ErrnoError(43); - } - if (flags & 2) { - // MAP_PRIVATE calls need not to be synced back to underlying fs - return 0; - } - var buffer = HEAPU8.slice(addr, addr + len); - FS.msync(stream, buffer, offset, len, flags); - }, - getStreamFromFD(fd) { - var stream = FS.getStreamChecked(fd); - return stream; - }, - varargs: undefined, - getStr(ptr) { - var ret = UTF8ToString(ptr); - return ret; - }, - }; - var ___syscall__newselect = function ( - nfds, - readfds, - writefds, - exceptfds, - timeout - ) { - try { - // readfds are supported, - // writefds checks socket open status - // exceptfds are supported, although on web, such exceptional conditions never arise in web sockets - // and so the exceptfds list will always return empty. - // timeout is supported, although on SOCKFS and PIPEFS these are ignored and always treated as 0 - fully async - - var total = 0; - - var srcReadLow = readfds ? HEAP32[readfds >> 2] : 0, - srcReadHigh = readfds ? HEAP32[(readfds + 4) >> 2] : 0; - var srcWriteLow = writefds ? HEAP32[writefds >> 2] : 0, - srcWriteHigh = writefds ? HEAP32[(writefds + 4) >> 2] : 0; - var srcExceptLow = exceptfds ? HEAP32[exceptfds >> 2] : 0, - srcExceptHigh = exceptfds ? HEAP32[(exceptfds + 4) >> 2] : 0; - - var dstReadLow = 0, - dstReadHigh = 0; - var dstWriteLow = 0, - dstWriteHigh = 0; - var dstExceptLow = 0, - dstExceptHigh = 0; - - var allLow = - (readfds ? HEAP32[readfds >> 2] : 0) | - (writefds ? HEAP32[writefds >> 2] : 0) | - (exceptfds ? HEAP32[exceptfds >> 2] : 0); - var allHigh = - (readfds ? HEAP32[(readfds + 4) >> 2] : 0) | - (writefds ? HEAP32[(writefds + 4) >> 2] : 0) | - (exceptfds ? HEAP32[(exceptfds + 4) >> 2] : 0); - - var check = (fd, low, high, val) => - fd < 32 ? low & val : high & val; - - for (var fd = 0; fd < nfds; fd++) { - var mask = 1 << fd % 32; - if (!check(fd, allLow, allHigh, mask)) { - continue; // index isn't in the set - } - - var stream = SYSCALLS.getStreamFromFD(fd); - - var flags = SYSCALLS.DEFAULT_POLLMASK; - - if (stream.stream_ops?.poll) { - var timeoutInMillis = -1; - if (timeout) { - // select(2) is declared to accept "struct timeval { time_t tv_sec; suseconds_t tv_usec; }". - // However, musl passes the two values to the syscall as an array of long values. - // Note that sizeof(time_t) != sizeof(long) in wasm32. The former is 8, while the latter is 4. - // This means using "C_STRUCTS.timeval.tv_usec" leads to a wrong offset. - // So, instead, we use POINTER_SIZE. - var tv_sec = readfds ? HEAP32[timeout >> 2] : 0, - tv_usec = readfds ? HEAP32[(timeout + 4) >> 2] : 0; - timeoutInMillis = (tv_sec + tv_usec / 1000000) * 1000; - } - flags = stream.stream_ops.poll(stream, timeoutInMillis); - } - - if (flags & 1 && check(fd, srcReadLow, srcReadHigh, mask)) { - fd < 32 - ? (dstReadLow = dstReadLow | mask) - : (dstReadHigh = dstReadHigh | mask); - total++; - } - if (flags & 4 && check(fd, srcWriteLow, srcWriteHigh, mask)) { - fd < 32 - ? (dstWriteLow = dstWriteLow | mask) - : (dstWriteHigh = dstWriteHigh | mask); - total++; - } - if (flags & 2 && check(fd, srcExceptLow, srcExceptHigh, mask)) { - fd < 32 - ? (dstExceptLow = dstExceptLow | mask) - : (dstExceptHigh = dstExceptHigh | mask); - total++; - } - } - - if (readfds) { - HEAP32[readfds >> 2] = dstReadLow; - HEAP32[(readfds + 4) >> 2] = dstReadHigh; - } - if (writefds) { - HEAP32[writefds >> 2] = dstWriteLow; - HEAP32[(writefds + 4) >> 2] = dstWriteHigh; - } - if (exceptfds) { - HEAP32[exceptfds >> 2] = dstExceptLow; - HEAP32[(exceptfds + 4) >> 2] = dstExceptHigh; - } - - return total; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - }; - ___syscall__newselect.sig = 'iipppp'; - - var SOCKFS = { - websocketArgs: {}, - callbacks: {}, - on(event, callback) { - SOCKFS.callbacks[event] = callback; - }, - emit(event, param) { - SOCKFS.callbacks[event]?.(param); - }, - mount(mount) { - // The incomming Module['websocket'] can be used for configuring - // configuring subprotocol/url, etc - SOCKFS.websocketArgs = Module['websocket'] || {}; - // Add the Event registration mechanism to the exported websocket configuration - // object so we can register network callbacks from native JavaScript too. - // For more documentation see system/include/emscripten/emscripten.h - (Module['websocket'] ??= {})['on'] = SOCKFS.on; - - return FS.createNode(null, '/', 16895, 0); - }, - createSocket(family, type, protocol) { - // Emscripten only supports AF_INET - if (family != 2) { - throw new FS.ErrnoError(5); - } - type &= ~526336; // Some applications may pass it; it makes no sense for a single process. - // Emscripten only supports SOCK_STREAM and SOCK_DGRAM - if (type != 1 && type != 2) { - throw new FS.ErrnoError(28); - } - var streaming = type == 1; - if (streaming && protocol && protocol != 6) { - throw new FS.ErrnoError(66); // if SOCK_STREAM, must be tcp or 0. - } - - // create our internal socket structure - var sock = { - family, - type, - protocol, - server: null, - error: null, // Used in getsockopt for SOL_SOCKET/SO_ERROR test - peers: {}, - pending: [], - recv_queue: [], - sock_ops: SOCKFS.websocket_sock_ops, - }; - - // create the filesystem node to store the socket structure - var name = SOCKFS.nextname(); - var node = FS.createNode(SOCKFS.root, name, 49152, 0); - node.sock = sock; - - // and the wrapping stream that enables library functions such - // as read and write to indirectly interact with the socket - var stream = FS.createStream({ - path: name, - node, - flags: 2, - seekable: false, - stream_ops: SOCKFS.stream_ops, - }); - - // map the new stream to the socket structure (sockets have a 1:1 - // relationship with a stream) - sock.stream = stream; - - return sock; - }, - getSocket(fd) { - var stream = FS.getStream(fd); - if (!stream || !FS.isSocket(stream.node.mode)) { - return null; - } - return stream.node.sock; - }, - stream_ops: { - poll(stream) { - var sock = stream.node.sock; - return sock.sock_ops.poll(sock); - }, - ioctl(stream, request, varargs) { - var sock = stream.node.sock; - return sock.sock_ops.ioctl(sock, request, varargs); - }, - read(stream, buffer, offset, length, position /* ignored */) { - var sock = stream.node.sock; - var msg = sock.sock_ops.recvmsg(sock, length); - if (!msg) { - // socket is closed - return 0; - } - buffer.set(msg.buffer, offset); - return msg.buffer.length; - }, - write(stream, buffer, offset, length, position /* ignored */) { - var sock = stream.node.sock; - return sock.sock_ops.sendmsg(sock, buffer, offset, length); - }, - close(stream) { - var sock = stream.node.sock; - sock.sock_ops.close(sock); - }, - }, - nextname() { - if (!SOCKFS.nextname.current) { - SOCKFS.nextname.current = 0; - } - return `socket[${SOCKFS.nextname.current++}]`; - }, - websocket_sock_ops: { - createPeer(sock, addr, port) { - var ws; - - if (typeof addr == 'object') { - ws = addr; - addr = null; - port = null; - } - - if (ws) { - // for sockets that've already connected (e.g. we're the server) - // we can inspect the _socket property for the address - if (ws._socket) { - addr = ws._socket.remoteAddress; - port = ws._socket.remotePort; - } - // if we're just now initializing a connection to the remote, - // inspect the url property - else { - var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url); - if (!result) { - throw new Error( - 'WebSocket URL must be in the format ws(s)://address:port' - ); - } - addr = result[1]; - port = parseInt(result[2], 10); - } - } else { - // create the actual websocket object and connect - try { - // The default value is 'ws://' the replace is needed because the compiler replaces '//' comments with '#' - // comments without checking context, so we'd end up with ws:#, the replace swaps the '#' for '//' again. - var url = 'ws://'.replace('#', '//'); - // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set. - var subProtocols = 'binary'; // The default value is 'binary' - // The default WebSocket options - var opts = undefined; - - // Fetch runtime WebSocket URL config. - if ('function' === typeof SOCKFS.websocketArgs['url']) { - url = SOCKFS.websocketArgs['url'](...arguments); - } else if ( - 'string' === typeof SOCKFS.websocketArgs['url'] - ) { - url = SOCKFS.websocketArgs['url']; - } - // Fetch runtime WebSocket subprotocol config. - if (SOCKFS.websocketArgs['subprotocol']) { - subProtocols = SOCKFS.websocketArgs['subprotocol']; - } else if ( - SOCKFS.websocketArgs['subprotocol'] === null - ) { - subProtocols = 'null'; - } - - if (url === 'ws://' || url === 'wss://') { - // Is the supplied URL config just a prefix, if so complete it. - var parts = addr.split('/'); - url = - url + - parts[0] + - ':' + - port + - '/' + - parts.slice(1).join('/'); - } - - if (subProtocols !== 'null') { - // The regex trims the string (removes spaces at the beginning and end, then splits the string by - // , into an Array. Whitespace removal is important for Websockify and ws. - subProtocols = subProtocols - .replace(/^ +| +$/g, '') - .split(/ *, */); - - opts = subProtocols; - } - - // If node we use the ws library. - var WebSocketConstructor; - if (ENVIRONMENT_IS_NODE) { - WebSocketConstructor = - /** @type{(typeof WebSocket)} */ ( - require('ws') - ); - } else { - WebSocketConstructor = WebSocket; - } - if (Module['websocket']['decorator']) { - WebSocketConstructor = - Module['websocket']['decorator']( - WebSocketConstructor - ); - } - ws = new WebSocketConstructor(url, opts); - ws.binaryType = 'arraybuffer'; - } catch (e) { - throw new FS.ErrnoError(23); - } - } - - var peer = { - addr, - port, - socket: ws, - msg_send_queue: [], - }; - - SOCKFS.websocket_sock_ops.addPeer(sock, peer); - SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer); - - // if this is a bound dgram socket, send the port number first to allow - // us to override the ephemeral port reported to us by remotePort on the - // remote end. - if (sock.type === 2 && typeof sock.sport != 'undefined') { - peer.msg_send_queue.push( - new Uint8Array([ - 255, - 255, - 255, - 255, - 'p'.charCodeAt(0), - 'o'.charCodeAt(0), - 'r'.charCodeAt(0), - 't'.charCodeAt(0), - (sock.sport & 0xff00) >> 8, - sock.sport & 0xff, - ]) - ); - } - - return peer; - }, - getPeer(sock, addr, port) { - return sock.peers[addr + ':' + port]; - }, - addPeer(sock, peer) { - sock.peers[peer.addr + ':' + peer.port] = peer; - }, - removePeer(sock, peer) { - delete sock.peers[peer.addr + ':' + peer.port]; - }, - handlePeerEvents(sock, peer) { - var first = true; - - var handleOpen = function () { - sock.connecting = false; - SOCKFS.emit('open', sock.stream.fd); - - try { - var queued = peer.msg_send_queue.shift(); - while (queued) { - peer.socket.send(queued); - queued = peer.msg_send_queue.shift(); - } - } catch (e) { - // not much we can do here in the way of proper error handling as we've already - // lied and said this data was sent. shut it down. - peer.socket.close(); - } - }; - - function handleMessage(data) { - if (typeof data == 'string') { - var encoder = new TextEncoder(); // should be utf-8 - data = encoder.encode(data); // make a typed array from the string - } else { - if (data.byteLength == 0) { - // An empty ArrayBuffer will emit a pseudo disconnect event - // as recv/recvmsg will return zero which indicates that a socket - // has performed a shutdown although the connection has not been disconnected yet. - return; - } - data = new Uint8Array(data); // make a typed array view on the array buffer - } - - // if this is the port message, override the peer's port with it - var wasfirst = first; - first = false; - if ( - wasfirst && - data.length === 10 && - data[0] === 255 && - data[1] === 255 && - data[2] === 255 && - data[3] === 255 && - data[4] === 'p'.charCodeAt(0) && - data[5] === 'o'.charCodeAt(0) && - data[6] === 'r'.charCodeAt(0) && - data[7] === 't'.charCodeAt(0) - ) { - // update the peer's port and it's key in the peer map - var newport = (data[8] << 8) | data[9]; - SOCKFS.websocket_sock_ops.removePeer(sock, peer); - peer.port = newport; - SOCKFS.websocket_sock_ops.addPeer(sock, peer); - return; - } - - sock.recv_queue.push({ - addr: peer.addr, - port: peer.port, - data: data, - }); - SOCKFS.emit('message', sock.stream.fd); - } - - if (ENVIRONMENT_IS_NODE) { - peer.socket.on('open', handleOpen); - peer.socket.on('message', function (data, isBinary) { - if (!isBinary) { - return; - } - handleMessage(new Uint8Array(data).buffer); // copy from node Buffer -> ArrayBuffer - }); - peer.socket.on('close', function () { - SOCKFS.emit('close', sock.stream.fd); - }); - peer.socket.on('error', function (error) { - // Although the ws library may pass errors that may be more descriptive than - // ECONNREFUSED they are not necessarily the expected error code e.g. - // ENOTFOUND on getaddrinfo seems to be node.js specific, so using ECONNREFUSED - // is still probably the most useful thing to do. - sock.error = 14; // Used in getsockopt for SOL_SOCKET/SO_ERROR test. - SOCKFS.emit('error', [ - sock.stream.fd, - sock.error, - 'ECONNREFUSED: Connection refused', - ]); - // don't throw - }); - } else { - peer.socket.onopen = handleOpen; - peer.socket.onclose = function () { - SOCKFS.emit('close', sock.stream.fd); - }; - peer.socket.onmessage = function peer_socket_onmessage( - event - ) { - handleMessage(event.data); - }; - peer.socket.onerror = function (error) { - // The WebSocket spec only allows a 'simple event' to be thrown on error, - // so we only really know as much as ECONNREFUSED. - sock.error = 14; // Used in getsockopt for SOL_SOCKET/SO_ERROR test. - SOCKFS.emit('error', [ - sock.stream.fd, - sock.error, - 'ECONNREFUSED: Connection refused', - ]); - }; - } - }, - poll(sock) { - if (sock.type === 1 && sock.server) { - // listen sockets should only say they're available for reading - // if there are pending clients. - return sock.pending.length ? 64 | 1 : 0; - } - - var mask = 0; - var dest = - sock.type === 1 // we only care about the socket state for connection-based sockets - ? SOCKFS.websocket_sock_ops.getPeer( - sock, - sock.daddr, - sock.dport - ) - : null; - - if ( - sock.recv_queue.length || - !dest || // connection-less sockets are always ready to read - (dest && dest.socket.readyState === dest.socket.CLOSING) || - (dest && dest.socket.readyState === dest.socket.CLOSED) - ) { - // let recv return 0 once closed - mask |= 64 | 1; - } - - if ( - !dest || // connection-less sockets are always ready to write - (dest && dest.socket.readyState === dest.socket.OPEN) - ) { - mask |= 4; - } - - if ( - (dest && dest.socket.readyState === dest.socket.CLOSING) || - (dest && dest.socket.readyState === dest.socket.CLOSED) - ) { - // When an non-blocking connect fails mark the socket as writable. - // Its up to the calling code to then use getsockopt with SO_ERROR to - // retrieve the error. - // See https://man7.org/linux/man-pages/man2/connect.2.html - if (sock.connecting) { - mask |= 4; - } else { - mask |= 16; - } - } - - return mask; - }, - ioctl(sock, request, arg) { - switch (request) { - case 21531: - var bytes = 0; - if (sock.recv_queue.length) { - bytes = sock.recv_queue[0].data.length; - } - HEAP32[arg >> 2] = bytes; - return 0; - case 21537: - var on = HEAP32[arg >> 2]; - if (on) { - sock.stream.flags |= 2048; - } else { - sock.stream.flags &= ~2048; - } - return 0; - default: - return 28; - } - }, - close(sock) { - // if we've spawned a listen server, close it - if (sock.server) { - try { - sock.server.close(); - } catch (e) {} - sock.server = null; - } - // close any peer connections - for (var peer of Object.values(sock.peers)) { - try { - peer.socket.close(); - } catch (e) {} - SOCKFS.websocket_sock_ops.removePeer(sock, peer); - } - return 0; - }, - bind(sock, addr, port) { - if ( - typeof sock.saddr != 'undefined' || - typeof sock.sport != 'undefined' - ) { - throw new FS.ErrnoError(28); // already bound - } - sock.saddr = addr; - sock.sport = port; - // in order to emulate dgram sockets, we need to launch a listen server when - // binding on a connection-less socket - // note: this is only required on the server side - if (sock.type === 2) { - // close the existing server if it exists - if (sock.server) { - sock.server.close(); - sock.server = null; - } - // swallow error operation not supported error that occurs when binding in the - // browser where this isn't supported - try { - sock.sock_ops.listen(sock, 0); - } catch (e) { - if (!(e.name === 'ErrnoError')) throw e; - if (e.errno !== 138) throw e; - } - } - }, - connect(sock, addr, port) { - if (sock.server) { - throw new FS.ErrnoError(138); - } - - // TODO autobind - // if (!sock.addr && sock.type == 2) { - // } - - // early out if we're already connected / in the middle of connecting - if ( - typeof sock.daddr != 'undefined' && - typeof sock.dport != 'undefined' - ) { - var dest = SOCKFS.websocket_sock_ops.getPeer( - sock, - sock.daddr, - sock.dport - ); - if (dest) { - if (dest.socket.readyState === dest.socket.CONNECTING) { - throw new FS.ErrnoError(7); - } else { - throw new FS.ErrnoError(30); - } - } - } - - // add the socket to our peer list and set our - // destination address / port to match - var peer = SOCKFS.websocket_sock_ops.createPeer( - sock, - addr, - port - ); - sock.daddr = peer.addr; - sock.dport = peer.port; - - // because we cannot synchronously block to wait for the WebSocket - // connection to complete, we return here pretending that the connection - // was a success. - sock.connecting = true; - }, - listen(sock, backlog) { - if (!ENVIRONMENT_IS_NODE) { - throw new FS.ErrnoError(138); - } - if (sock.server) { - throw new FS.ErrnoError(28); // already listening - } - var WebSocketServer = require('ws').Server; - var host = sock.saddr; - if (Module['websocket']['serverDecorator']) { - WebSocketServer = - Module['websocket']['serverDecorator'](WebSocketServer); - } - sock.server = new WebSocketServer({ - host, - port: sock.sport, - // TODO support backlog - }); - SOCKFS.emit('listen', sock.stream.fd); // Send Event with listen fd. - - sock.server.on('connection', function (ws) { - if (sock.type === 1) { - var newsock = SOCKFS.createSocket( - sock.family, - sock.type, - sock.protocol - ); - - // create a peer on the new socket - var peer = SOCKFS.websocket_sock_ops.createPeer( - newsock, - ws - ); - newsock.daddr = peer.addr; - newsock.dport = peer.port; - - // push to queue for accept to pick up - sock.pending.push(newsock); - SOCKFS.emit('connection', newsock.stream.fd); - } else { - // create a peer on the listen socket so calling sendto - // with the listen socket and an address will resolve - // to the correct client - SOCKFS.websocket_sock_ops.createPeer(sock, ws); - SOCKFS.emit('connection', sock.stream.fd); - } - }); - sock.server.on('close', function () { - SOCKFS.emit('close', sock.stream.fd); - sock.server = null; - }); - sock.server.on('error', function (error) { - // Although the ws library may pass errors that may be more descriptive than - // ECONNREFUSED they are not necessarily the expected error code e.g. - // ENOTFOUND on getaddrinfo seems to be node.js specific, so using EHOSTUNREACH - // is still probably the most useful thing to do. This error shouldn't - // occur in a well written app as errors should get trapped in the compiled - // app's own getaddrinfo call. - sock.error = 23; // Used in getsockopt for SOL_SOCKET/SO_ERROR test. - SOCKFS.emit('error', [ - sock.stream.fd, - sock.error, - 'EHOSTUNREACH: Host is unreachable', - ]); - // don't throw - }); - }, - accept(listensock) { - if (!listensock.server || !listensock.pending.length) { - throw new FS.ErrnoError(28); - } - var newsock = listensock.pending.shift(); - newsock.stream.flags = listensock.stream.flags; - return newsock; - }, - getname(sock, peer) { - var addr, port; - if (peer) { - if (sock.daddr === undefined || sock.dport === undefined) { - throw new FS.ErrnoError(53); - } - addr = sock.daddr; - port = sock.dport; - } else { - // TODO saddr and sport will be set for bind()'d UDP sockets, but what - // should we be returning for TCP sockets that've been connect()'d? - addr = sock.saddr || 0; - port = sock.sport || 0; - } - return { addr, port }; - }, - sendmsg(sock, buffer, offset, length, addr, port) { - if (sock.type === 2) { - // connection-less sockets will honor the message address, - // and otherwise fall back to the bound destination address - if (addr === undefined || port === undefined) { - addr = sock.daddr; - port = sock.dport; - } - // if there was no address to fall back to, error out - if (addr === undefined || port === undefined) { - throw new FS.ErrnoError(17); - } - } else { - // connection-based sockets will only use the bound - addr = sock.daddr; - port = sock.dport; - } - - // find the peer for the destination address - var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port); - - // early out if not connected with a connection-based socket - if (sock.type === 1) { - if ( - !dest || - dest.socket.readyState === dest.socket.CLOSING || - dest.socket.readyState === dest.socket.CLOSED - ) { - throw new FS.ErrnoError(53); - } - } - - // create a copy of the incoming data to send, as the WebSocket API - // doesn't work entirely with an ArrayBufferView, it'll just send - // the entire underlying buffer - if (ArrayBuffer.isView(buffer)) { - offset += buffer.byteOffset; - buffer = buffer.buffer; - } - - var data = buffer.slice(offset, offset + length); - - // if we don't have a cached connectionless UDP datagram connection, or - // the TCP socket is still connecting, queue the message to be sent upon - // connect, and lie, saying the data was sent now. - if (!dest || dest.socket.readyState !== dest.socket.OPEN) { - // if we're not connected, open a new connection - if (sock.type === 2) { - if ( - !dest || - dest.socket.readyState === dest.socket.CLOSING || - dest.socket.readyState === dest.socket.CLOSED - ) { - dest = SOCKFS.websocket_sock_ops.createPeer( - sock, - addr, - port - ); - } - } - dest.msg_send_queue.push(data); - return length; - } - - try { - // send the actual data - dest.socket.send(data); - return length; - } catch (e) { - throw new FS.ErrnoError(28); - } - }, - recvmsg(sock, length, flags) { - // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html - if (sock.type === 1 && sock.server) { - // tcp servers should not be recv()'ing on the listen socket - throw new FS.ErrnoError(53); - } - - var queued = sock.recv_queue.shift(); - if (!queued) { - if (sock.type === 1) { - var dest = SOCKFS.websocket_sock_ops.getPeer( - sock, - sock.daddr, - sock.dport - ); - - if (!dest) { - // if we have a destination address but are not connected, error out - throw new FS.ErrnoError(53); - } - if ( - dest.socket.readyState === dest.socket.CLOSING || - dest.socket.readyState === dest.socket.CLOSED - ) { - // return null if the socket has closed - return null; - } - // else, our socket is in a valid state but truly has nothing available - throw new FS.ErrnoError(6); - } - throw new FS.ErrnoError(6); - } - - // queued.data will be an ArrayBuffer if it's unadulterated, but if it's - // requeued TCP data it'll be an ArrayBufferView - var queuedLength = queued.data.byteLength || queued.data.length; - var queuedOffset = queued.data.byteOffset || 0; - var queuedBuffer = queued.data.buffer || queued.data; - var bytesRead = Math.min(length, queuedLength); - var res = { - buffer: new Uint8Array( - queuedBuffer, - queuedOffset, - bytesRead - ), - addr: queued.addr, - port: queued.port, - }; - - // push back any unread data for TCP connections - if (flags & 2) { - bytesRead = 0; - } - if (sock.type === 1 && bytesRead < queuedLength) { - var bytesRemaining = queuedLength - bytesRead; - queued.data = new Uint8Array( - queuedBuffer, - queuedOffset + bytesRead, - bytesRemaining - ); - sock.recv_queue.unshift(queued); - } - - return res; - }, - }, - }; - - var getSocketFromFD = (fd) => { - var socket = SOCKFS.getSocket(fd); - if (!socket) throw new FS.ErrnoError(8); - return socket; - }; - - var inetPton4 = (str) => { - var b = str.split('.'); - for (var i = 0; i < 4; i++) { - var tmp = Number(b[i]); - if (isNaN(tmp)) return null; - b[i] = tmp; - } - return (b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24)) >>> 0; - }; - - var inetPton6 = (str) => { - var words; - var w, offset, z, i; - /* http://home.deds.nl/~aeron/regex/ */ - var valid6regx = - /^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i; - var parts = []; - if (!valid6regx.test(str)) { - return null; - } - if (str === '::') { - return [0, 0, 0, 0, 0, 0, 0, 0]; - } - // Z placeholder to keep track of zeros when splitting the string on ":" - if (str.startsWith('::')) { - str = str.replace('::', 'Z:'); // leading zeros case - } else { - str = str.replace('::', ':Z:'); - } - - if (str.indexOf('.') > 0) { - // parse IPv4 embedded stress - str = str.replace(new RegExp('[.]', 'g'), ':'); - words = str.split(':'); - words[words.length - 4] = - Number(words[words.length - 4]) + - Number(words[words.length - 3]) * 256; - words[words.length - 3] = - Number(words[words.length - 2]) + - Number(words[words.length - 1]) * 256; - words = words.slice(0, words.length - 2); - } else { - words = str.split(':'); - } - - offset = 0; - z = 0; - for (w = 0; w < words.length; w++) { - if (typeof words[w] == 'string') { - if (words[w] === 'Z') { - // compressed zeros - write appropriate number of zero words - for (z = 0; z < 8 - words.length + 1; z++) { - parts[w + z] = 0; - } - offset = z - 1; - } else { - // parse hex to field to 16-bit value and write it in network byte-order - parts[w + offset] = _htons(parseInt(words[w], 16)); - } - } else { - // parsed IPv4 words - parts[w + offset] = words[w]; - } - } - return [ - (parts[1] << 16) | parts[0], - (parts[3] << 16) | parts[2], - (parts[5] << 16) | parts[4], - (parts[7] << 16) | parts[6], - ]; - }; - - /** @param {number=} addrlen */ - var writeSockaddr = (sa, family, addr, port, addrlen) => { - switch (family) { - case 2: - addr = inetPton4(addr); - zeroMemory(sa, 16); - if (addrlen) { - HEAP32[addrlen >> 2] = 16; - } - HEAP16[sa >> 1] = family; - HEAP32[(sa + 4) >> 2] = addr; - HEAP16[(sa + 2) >> 1] = _htons(port); - break; - case 10: - addr = inetPton6(addr); - zeroMemory(sa, 28); - if (addrlen) { - HEAP32[addrlen >> 2] = 28; - } - HEAP32[sa >> 2] = family; - HEAP32[(sa + 8) >> 2] = addr[0]; - HEAP32[(sa + 12) >> 2] = addr[1]; - HEAP32[(sa + 16) >> 2] = addr[2]; - HEAP32[(sa + 20) >> 2] = addr[3]; - HEAP16[(sa + 2) >> 1] = _htons(port); - break; - default: - return 5; - } - return 0; - }; - - var DNS = { - address_map: { - id: 1, - addrs: {}, - names: {}, - }, - lookup_name(name) { - // If the name is already a valid ipv4 / ipv6 address, don't generate a fake one. - var res = inetPton4(name); - if (res !== null) { - return name; - } - res = inetPton6(name); - if (res !== null) { - return name; - } - - // See if this name is already mapped. - var addr; - - if (DNS.address_map.addrs[name]) { - addr = DNS.address_map.addrs[name]; - } else { - var id = DNS.address_map.id++; - - addr = '172.29.' + (id & 0xff) + '.' + (id & 0xff00); - - DNS.address_map.names[addr] = name; - DNS.address_map.addrs[name] = addr; - } - - return addr; - }, - lookup_addr(addr) { - if (DNS.address_map.names[addr]) { - return DNS.address_map.names[addr]; - } - - return null; - }, - }; - function ___syscall_accept4(fd, addr, addrlen, flags, d1, d2) { - try { - var sock = getSocketFromFD(fd); - var newsock = sock.sock_ops.accept(sock); - if (addr) { - var errno = writeSockaddr( - addr, - newsock.family, - DNS.lookup_name(newsock.daddr), - newsock.dport, - addrlen - ); - } - return newsock.stream.fd; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_accept4.sig = 'iippiii'; - - var inetNtop4 = (addr) => - (addr & 0xff) + - '.' + - ((addr >> 8) & 0xff) + - '.' + - ((addr >> 16) & 0xff) + - '.' + - ((addr >> 24) & 0xff); - - var inetNtop6 = (ints) => { - // ref: http://www.ietf.org/rfc/rfc2373.txt - section 2.5.4 - // Format for IPv4 compatible and mapped 128-bit IPv6 Addresses - // 128-bits are split into eight 16-bit words - // stored in network byte order (big-endian) - // | 80 bits | 16 | 32 bits | - // +-----------------------------------------------------------------+ - // | 10 bytes | 2 | 4 bytes | - // +--------------------------------------+--------------------------+ - // + 5 words | 1 | 2 words | - // +--------------------------------------+--------------------------+ - // |0000..............................0000|0000| IPv4 ADDRESS | (compatible) - // +--------------------------------------+----+---------------------+ - // |0000..............................0000|FFFF| IPv4 ADDRESS | (mapped) - // +--------------------------------------+----+---------------------+ - var str = ''; - var word = 0; - var longest = 0; - var lastzero = 0; - var zstart = 0; - var len = 0; - var i = 0; - var parts = [ - ints[0] & 0xffff, - ints[0] >> 16, - ints[1] & 0xffff, - ints[1] >> 16, - ints[2] & 0xffff, - ints[2] >> 16, - ints[3] & 0xffff, - ints[3] >> 16, - ]; - - // Handle IPv4-compatible, IPv4-mapped, loopback and any/unspecified addresses - - var hasipv4 = true; - var v4part = ''; - // check if the 10 high-order bytes are all zeros (first 5 words) - for (i = 0; i < 5; i++) { - if (parts[i] !== 0) { - hasipv4 = false; - break; - } - } - - if (hasipv4) { - // low-order 32-bits store an IPv4 address (bytes 13 to 16) (last 2 words) - v4part = inetNtop4(parts[6] | (parts[7] << 16)); - // IPv4-mapped IPv6 address if 16-bit value (bytes 11 and 12) == 0xFFFF (6th word) - if (parts[5] === -1) { - str = '::ffff:'; - str += v4part; - return str; - } - // IPv4-compatible IPv6 address if 16-bit value (bytes 11 and 12) == 0x0000 (6th word) - if (parts[5] === 0) { - str = '::'; - //special case IPv6 addresses - if (v4part === '0.0.0.0') v4part = ''; // any/unspecified address - if (v4part === '0.0.0.1') v4part = '1'; // loopback address - str += v4part; - return str; - } - } - - // Handle all other IPv6 addresses - - // first run to find the longest contiguous zero words - for (word = 0; word < 8; word++) { - if (parts[word] === 0) { - if (word - lastzero > 1) { - len = 0; - } - lastzero = word; - len++; - } - if (len > longest) { - longest = len; - zstart = word - longest + 1; - } - } - - for (word = 0; word < 8; word++) { - if (longest > 1) { - // compress contiguous zeros - to produce "::" - if ( - parts[word] === 0 && - word >= zstart && - word < zstart + longest - ) { - if (word === zstart) { - str += ':'; - if (zstart === 0) str += ':'; //leading zeros case - } - continue; - } - } - // converts 16-bit words from big-endian to little-endian before converting to hex string - str += Number(_ntohs(parts[word] & 0xffff)).toString(16); - str += word < 7 ? ':' : ''; - } - return str; - }; - - var readSockaddr = (sa, salen) => { - // family / port offsets are common to both sockaddr_in and sockaddr_in6 - var family = HEAP16[sa >> 1]; - var port = _ntohs(HEAPU16[(sa + 2) >> 1]); - var addr; - - switch (family) { - case 2: - if (salen !== 16) { - return { errno: 28 }; - } - addr = HEAP32[(sa + 4) >> 2]; - addr = inetNtop4(addr); - break; - case 10: - if (salen !== 28) { - return { errno: 28 }; - } - addr = [ - HEAP32[(sa + 8) >> 2], - HEAP32[(sa + 12) >> 2], - HEAP32[(sa + 16) >> 2], - HEAP32[(sa + 20) >> 2], - ]; - addr = inetNtop6(addr); - break; - default: - return { errno: 5 }; - } - - return { family: family, addr: addr, port: port }; - }; - - var getSocketAddress = (addrp, addrlen) => { - var info = readSockaddr(addrp, addrlen); - if (info.errno) throw new FS.ErrnoError(info.errno); - info.addr = DNS.lookup_addr(info.addr) || info.addr; - return info; - }; - function ___syscall_bind(fd, addr, addrlen, d1, d2, d3) { - try { - var sock = getSocketFromFD(fd); - var info = getSocketAddress(addr, addrlen); - sock.sock_ops.bind(sock, info.addr, info.port); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_bind.sig = 'iippiii'; - - function ___syscall_chdir(path) { - try { - path = SYSCALLS.getStr(path); - FS.chdir(path); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_chdir.sig = 'ip'; - - function ___syscall_chmod(path, mode) { - try { - path = SYSCALLS.getStr(path); - FS.chmod(path, mode); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_chmod.sig = 'ipi'; - - function ___syscall_connect(fd, addr, addrlen, d1, d2, d3) { - try { - var sock = getSocketFromFD(fd); - var info = getSocketAddress(addr, addrlen); - sock.sock_ops.connect(sock, info.addr, info.port); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_connect.sig = 'iippiii'; - - function ___syscall_dup(fd) { - try { - var old = SYSCALLS.getStreamFromFD(fd); - return FS.dupStream(old).fd; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_dup.sig = 'ii'; - - function ___syscall_dup3(fd, newfd, flags) { - try { - var old = SYSCALLS.getStreamFromFD(fd); - if (old.fd === newfd) return -28; - // Check newfd is within range of valid open file descriptors. - if (newfd < 0 || newfd >= FS.MAX_OPEN_FDS) return -8; - var existing = FS.getStream(newfd); - if (existing) FS.close(existing); - return FS.dupStream(old, newfd).fd; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_dup3.sig = 'iiii'; - - function ___syscall_faccessat(dirfd, path, amode, flags) { - try { - path = SYSCALLS.getStr(path); - path = SYSCALLS.calculateAt(dirfd, path); - if (amode & ~7) { - // need a valid mode - return -28; - } - var lookup = FS.lookupPath(path, { follow: true }); - var node = lookup.node; - if (!node) { - return -44; - } - var perms = ''; - if (amode & 4) perms += 'r'; - if (amode & 2) perms += 'w'; - if (amode & 1) perms += 'x'; - if ( - perms /* otherwise, they've just passed F_OK */ && - FS.nodePermissions(node, perms) - ) { - return -2; - } - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_faccessat.sig = 'iipii'; - - var ___syscall_fadvise64 = (fd, offset, len, advice) => 0; - ___syscall_fadvise64.sig = 'iijji'; - - var INT53_MAX = 9007199254740992; - - var INT53_MIN = -9007199254740992; - var bigintToI53Checked = (num) => - num < INT53_MIN || num > INT53_MAX ? NaN : Number(num); - function ___syscall_fallocate(fd, mode, offset, len) { - offset = bigintToI53Checked(offset); - len = bigintToI53Checked(len); - - try { - if (isNaN(offset) || isNaN(len)) return -61; - if (mode != 0) { - return -138; - } - if (offset < 0 || len < 0) { - return -28; - } - // We only support mode == 0, which means we can implement fallocate - // in terms of ftruncate. - var oldSize = FS.fstat(fd).size; - var newSize = offset + len; - if (newSize > oldSize) { - FS.ftruncate(fd, newSize); - } - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_fallocate.sig = 'iiijj'; - - function ___syscall_fchdir(fd) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - FS.chdir(stream.path); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_fchdir.sig = 'ii'; - - function ___syscall_fchmod(fd, mode) { - try { - FS.fchmod(fd, mode); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_fchmod.sig = 'iii'; - - function ___syscall_fchmodat2(dirfd, path, mode, flags) { - try { - var nofollow = flags & 256; - path = SYSCALLS.getStr(path); - path = SYSCALLS.calculateAt(dirfd, path); - FS.chmod(path, mode, nofollow); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_fchmodat2.sig = 'iipii'; - - function ___syscall_fchown32(fd, owner, group) { - try { - FS.fchown(fd, owner, group); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_fchown32.sig = 'iiii'; - - function ___syscall_fchownat(dirfd, path, owner, group, flags) { - try { - path = SYSCALLS.getStr(path); - var nofollow = flags & 256; - flags = flags & ~256; - path = SYSCALLS.calculateAt(dirfd, path); - (nofollow ? FS.lchown : FS.chown)(path, owner, group); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_fchownat.sig = 'iipiii'; - - var syscallGetVarargI = () => { - // the `+` prepended here is necessary to convince the JSCompiler that varargs is indeed a number. - var ret = HEAP32[+SYSCALLS.varargs >> 2]; - SYSCALLS.varargs += 4; - return ret; - }; - var syscallGetVarargP = syscallGetVarargI; - - var allocateUTF8OnStack = (...args) => stringToUTF8OnStack(...args); - - var PHPWASM = { - O_APPEND: 1024, - O_NONBLOCK: 2048, - POLLHUP: 16, - SETFL_MASK: 3072, - init: function (phpWasmInitOptions) { - Module['ENV'] = Module['ENV'] || {}; - // Ensure a platform-level bin directory for a fallback `php` binary. - Module['ENV']['PATH'] = [ - Module['ENV']['PATH'], - '/internal/shared/bin', - ] - .filter(Boolean) - .join(':'); - - // The /request directory is required by the C module. It's where the - // stdout, stderr, and headers information are written for the JavaScript - // code to read later on. This is per-request state that is isolated to a - // single PHP process. - FS.mkdir('/request'); - // The /internal directory is shared amongst all PHP processes - // and contains the php.ini, constants definitions, etc. - FS.mkdir('/internal'); - - if (phpWasmInitOptions?.nativeInternalDirPath) { - FS.mount( - FS.filesystems.NODEFS, - { root: phpWasmInitOptions.nativeInternalDirPath }, - '/internal' - ); - } - - // The files from the shared directory are shared between all the - // PHP processes managed by PHPProcessManager. - FS.mkdirTree('/internal/shared'); - - // The files from the preload directory are preloaded using the - // auto_prepend_file php.ini directive. - FS.mkdirTree('/internal/shared/preload'); - // Platform-level bin directory for a fallback `php` binary. Without it, - // PHP may not populate the PHP_BINARY constant. - FS.mkdirTree('/internal/shared/bin'); - const originalOnRuntimeInitialized = Module['onRuntimeInitialized']; - Module['onRuntimeInitialized'] = () => { - const { node: phpBinaryNode } = FS.lookupPath( - '/internal/shared/bin/php', - { noent_okay: true } - ); - if (!phpBinaryNode) { - // Dummy PHP binary for PHP to populate the PHP_BINARY constant. - FS.writeFile( - '/internal/shared/bin/php', - new TextEncoder().encode('#!/bin/sh\nphp "$@"') - ); - // It must be executable to be used by PHP. - FS.chmod('/internal/shared/bin/php', 0o755); - } - originalOnRuntimeInitialized(); - }; - - // Create stdout and stderr devices. We can't just use Emscripten's - // default stdout and stderr devices because they stop processing data - // on the first null byte. However, when dealing with binary data, - // null bytes are valid and common. - FS.registerDevice(FS.makedev(64, 0), { - open: () => {}, - close: () => {}, - read: () => 0, - write: (stream, buffer, offset, length, pos) => { - const chunk = buffer.subarray(offset, offset + length); - PHPWASM.onStdout(chunk); - return length; - }, - }); - FS.mkdev('/request/stdout', FS.makedev(64, 0)); - - FS.registerDevice(FS.makedev(63, 0), { - open: () => {}, - close: () => {}, - read: () => 0, - write: (stream, buffer, offset, length, pos) => { - const chunk = buffer.subarray(offset, offset + length); - PHPWASM.onStderr(chunk); - return length; - }, - }); - FS.mkdev('/request/stderr', FS.makedev(63, 0)); - - FS.registerDevice(FS.makedev(62, 0), { - open: () => {}, - close: () => {}, - read: () => 0, - write: (stream, buffer, offset, length, pos) => { - const chunk = buffer.subarray(offset, offset + length); - PHPWASM.onHeaders(chunk); - return length; - }, - }); - FS.mkdev('/request/headers', FS.makedev(62, 0)); - - // Handle events. - PHPWASM.EventEmitter = ENVIRONMENT_IS_NODE - ? require('events').EventEmitter - : class EventEmitter { - constructor() { - this.listeners = {}; - } - emit(eventName, data) { - if (this.listeners[eventName]) { - this.listeners[eventName].forEach( - (callback) => { - callback(data); - } - ); - } - } - once(eventName, callback) { - const self = this; - function removedCallback() { - callback(...arguments); - self.removeListener(eventName, removedCallback); - } - this.on(eventName, removedCallback); - } - removeAllListeners(eventName) { - if (eventName) { - delete this.listeners[eventName]; - } else { - this.listeners = {}; - } - } - removeListener(eventName, callback) { - if (this.listeners[eventName]) { - const idx = - this.listeners[eventName].indexOf(callback); - if (idx !== -1) { - this.listeners[eventName].splice(idx, 1); - } - } - } - }; - - PHPWASM.processTable = {}; - - PHPWASM.input_devices = {}; - const originalWrite = TTY.stream_ops.write; - TTY.stream_ops.write = function (stream, ...rest) { - const retval = originalWrite(stream, ...rest); - // Implicit flush since PHP's fflush() doesn't seem to trigger the fsync event - // @TODO: Fix this at the wasm level - stream.tty.ops.fsync(stream.tty); - return retval; - }; - const originalPutChar = TTY.stream_ops.put_char; - TTY.stream_ops.put_char = function (tty, val) { - /** - * Buffer newlines that Emscripten normally ignores. - * - * Emscripten doesn't do it by default because its default - * print function is console.log that implicitly adds a newline. We are overwriting - * it with an environment-specific function that outputs exaclty what it was given, - * e.g. in Node.js it's process.stdout.write(). Therefore, we need to mak sure - * all the newlines make it to the output buffer. - */ - if (val === 10) tty.output.push(val); - return originalPutChar(tty, val); - }; - }, - onHeaders: function (chunk) { - if (Module['onHeaders']) { - Module['onHeaders'](chunk); - return; - } - console.log('headers', { chunk }); - }, - onStdout: function (chunk) { - if (Module['onStdout']) { - Module['onStdout'](chunk); - return; - } - if (ENVIRONMENT_IS_NODE) { - process.stdout.write(chunk); - } else { - console.log('stdout', { chunk }); - } - }, - onStderr: function (chunk) { - if (Module['onStderr']) { - Module['onStderr'](chunk); - return; - } - if (ENVIRONMENT_IS_NODE) { - process.stderr.write(chunk); - } else { - console.warn('stderr', { chunk }); - } - }, - getAllWebSockets: function (sock) { - const webSockets = /* @__PURE__ */ new Set(); - if (sock.server) { - sock.server.clients.forEach((ws) => { - webSockets.add(ws); - }); - } - for (const peer of PHPWASM.getAllPeers(sock)) { - webSockets.add(peer.socket); - } - return Array.from(webSockets); - }, - getAllPeers: function (sock) { - const peers = new Set(); - if (sock.server) { - sock.pending - .filter((pending) => pending.peers) - .forEach((pending) => { - for (const peer of Object.values(pending.peers)) { - peers.add(peer); - } - }); - } - if (sock.peers) { - for (const peer of Object.values(sock.peers)) { - peers.add(peer); - } - } - return Array.from(peers); - }, - awaitData: function (ws) { - return PHPWASM.awaitEvent(ws, 'message'); - }, - awaitConnection: function (ws) { - if (ws.OPEN === ws.readyState) { - return [Promise.resolve(), PHPWASM.noop]; - } - return PHPWASM.awaitEvent(ws, 'open'); - }, - awaitClose: function (ws) { - if ([ws.CLOSING, ws.CLOSED].includes(ws.readyState)) { - return [Promise.resolve(), PHPWASM.noop]; - } - return PHPWASM.awaitEvent(ws, 'close'); - }, - awaitError: function (ws) { - if ([ws.CLOSING, ws.CLOSED].includes(ws.readyState)) { - return [Promise.resolve(), PHPWASM.noop]; - } - return PHPWASM.awaitEvent(ws, 'error'); - }, - awaitEvent: function (ws, event) { - let resolve; - const listener = () => { - resolve(); - }; - const promise = new Promise(function (_resolve) { - resolve = _resolve; - ws.once(event, listener); - }); - const cancel = () => { - ws.removeListener(event, listener); - // Rejecting the promises bubbles up and kills the entire - // node process. Let's resolve them on the next tick instead - // to give the caller some space to unbind any handlers. - setTimeout(resolve); - }; - return [promise, cancel]; - }, - noop: function () {}, - spawnProcess: function (command, args, options) { - if (Module['spawnProcess']) { - const spawnedPromise = Module['spawnProcess']( - command, - args, - options - ); - return Promise.resolve(spawnedPromise).then(function (spawned) { - if (!spawned || !spawned.on) { - throw new Error( - 'spawnProcess() must return an EventEmitter but returned a different type.' - ); - } - return spawned; - }); - } - - if (ENVIRONMENT_IS_NODE) { - return require('child_process').spawn(command, args, { - ...options, - shell: true, - stdio: ['pipe', 'pipe', 'pipe'], - }); - } - const e = new Error( - 'popen(), proc_open() etc. are unsupported in the browser. Call php.setSpawnHandler() ' + - 'and provide a callback to handle spawning processes, or disable a popen(), proc_open() ' + - 'and similar functions via php.ini.' - ); - e.code = 'SPAWN_UNSUPPORTED'; - throw e; - }, - shutdownSocket: function (socketd, how) { - // This implementation only supports websockets at the moment - const sock = getSocketFromFD(socketd); - const peer = Object.values(sock.peers)[0]; - - if (!peer) { - return -1; - } - - try { - peer.socket.close(); - SOCKFS.websocket_sock_ops.removePeer(sock, peer); - return 0; - } catch (e) { - console.log('Socket shutdown error', e); - return -1; - } - }, - }; - - function _js_getpid() { - return PHPLoader.processId ?? 42; - } +/** @param {string|number=} what */ +function abort(what) { + Module['onAbort']?.(what); + + what = 'Aborted(' + what + ')'; + // TODO(sbc): Should we remove printing and leave it up to whoever + // catches the exception? + err(what); + + ABORT = true; + + what += '. Build with -sASSERTIONS for more info.'; + + // Use a wasm runtime error, because a JS error might be seen as a foreign + // exception, which means we'd run destructors on it. We need the error to + // simply make the program stop. + // FIXME This approach does not work in Wasm EH because it currently does not assume + // all RuntimeErrors are from traps; it decides whether a RuntimeError is from + // a trap or not based on a hidden field within the object. So at the moment + // we don't have a way of throwing a wasm trap from JS. TODO Make a JS API that + // allows this in the wasm spec. + + // Suppress closure compiler warning here. Closure compiler's builtin extern + // definition for WebAssembly.RuntimeError claims it takes no arguments even + // though it can. + // TODO(https://github.com/google/closure-compiler/pull/3913): Remove if/when upstream closure gets fixed. + /** @suppress {checkTypes} */ + var e = new WebAssembly.RuntimeError(what); + + // Throw the error whether or not MODULARIZE is set because abort is used + // in code paths apart from instantiation where an exception is expected + // to be thrown when abort is called. + throw e; +} - function _js_wasm_trace(format, ...args) { - if (PHPLoader.trace instanceof Function) { - PHPLoader.trace(_js_getpid(), format, ...args); - } - } +var wasmBinaryFile; - function _fd_close(fd) { - // We have to get the VFS path from the file descriptor - // before closing it. - const [vfsPath, vfsPathResolutionErrno] = - locking.get_vfs_path_from_fd(fd); - - const fdCloseResult = _builtin_fd_close(fd); - if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { - _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); - return fdCloseResult; - } - - if (vfsPathResolutionErrno !== 0) { - _js_wasm_trace( - 'fd_close(%d) get_vfs_path_from_fd error %d', - fd, - vfsPathResolutionErrno - ); - /* - * It looks like the file may have had an associated lock, - * but since we cannot look up the path, - * there is nothing more for us to do. - * - * NOTE: This seems possible for files that are locked and - * then unlinked before close. It is an opportunity for a - * lock to be orphaned in the lock manager. - * @TODO: Explore how to ensure cleanup in this case. - */ - return fdCloseResult; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - PHPLoader.fileLockManager.releaseLocksForProcessFd( - PHPLoader.processId, - fd, - nativeFilePath - ); - _js_wasm_trace('fd_close(%d) release locks success', fd); - } catch (e) { - _js_wasm_trace("fd_close(%d) error '%s'", fd, e); - } finally { - locking.maybeLockedFds.delete(fd); - } - return fdCloseResult; - } - _fd_close.sig = 'ii'; - function _builtin_fd_close(fd) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - FS.close(stream); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return e.errno; - } - } +function findWasmBinary() { + return locateFile(dependencyFilename); +} - function _builtin_fcntl64(fd, cmd, varargs) { - SYSCALLS.varargs = varargs; - try { - var stream = SYSCALLS.getStreamFromFD(fd); - switch (cmd) { - case 0: { - var arg = syscallGetVarargI(); - if (arg < 0) { - return -28; - } - while (FS.streams[arg]) { - arg++; - } - var newStream; - newStream = FS.dupStream(stream, arg); - return newStream.fd; - } - case 1: - case 2: - return 0; // FD_CLOEXEC makes no sense for a single process. - case 3: - return stream.flags; - case 4: { - var arg = syscallGetVarargI(); - stream.flags |= arg; - return 0; - } - case 12: { - var arg = syscallGetVarargP(); - var offset = 0; - // We're always unlocked. - HEAP16[(arg + offset) >> 1] = 2; - return 0; - } - case 13: - case 14: - // Pretend that the locking is successful. These are process-level locks, - // and Emscripten programs are a single process. If we supported linking a - // filesystem between programs, we'd need to do more here. - // See https://github.com/emscripten-core/emscripten/issues/23697 - return 0; - } - return -28; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } +function getBinarySync(file) { + if (file == wasmBinaryFile && wasmBinary) { + return new Uint8Array(wasmBinary); + } + if (readBinary) { + return readBinary(file); + } + // Throwing a plain string here, even though it not normally adviables since + // this gets turning into an `abort` in instantiateArrayBuffer. + throw 'both async and sync fetching of the wasm failed'; +} - var locking = { - maybeLockedFds: new Set(), - F_RDLCK: 0, - F_WRLCK: 1, - F_UNLCK: 2, - lockStateToFcntl: { - shared: 0, - exclusive: 1, - unlocked: 2, - }, - fcntlToLockState: { - 0: 'shared', - 1: 'exclusive', - 2: 'unlocked', - }, - is_path_to_shared_fs(path) { - _js_wasm_trace('is_path_to_shared_fs(%s)', path); - const { node } = FS.lookupPath(path, { noent_okay: true }); - if (node.mount.type !== PROXYFS) { - return !!node.isSharedFS; - } - - // This looks like a PROXYFS node. Let's try a lookup. - const nodePath = PROXYFS.realPath(node); - const backingFs = node?.mount?.opts?.fs; - if (backingFs) { - // Tolerate ENOENT because looking up a MEMFS node by path always fails. - const { node: backingNode } = backingFs.lookupPath(nodePath, { - noent_okay: true, - }); - return !!backingNode?.isSharedFS; - } - - return false; - }, - get_fd_access_mode(fd) { - const emscripten_F_GETFL = Number('3'); - const emscripten_O_ACCMODE = Number('2097155'); - - return ( - _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE - ); - }, - get_vfs_path_from_fd(fd) { - try { - return [FS.readlink(`/proc/self/fd/${fd}`), 0]; - } catch (error) { - return [null, ERRNO_CODES.EBADF]; - } - }, - get_native_path_from_vfs_path(vfsPath) { - const { node } = FS.lookupPath(vfsPath, { - noent_okay: true, - }); - if (!node) { - throw new Error(`No node found for VFS path ${vfsPath}`); - } - if (node.mount.type === NODEFS) { - return NODEFS.realPath(node); - } else if (node.mount.type === PROXYFS) { - // TODO: Tolerate ENOENT here? - const { node: backingNode, path: backingPath } = - node.mount.opts.fs.lookupPath(vfsPath); - _js_wasm_trace( - 'backingNode for %s: %s', - vfsPath, - backingPath, - backingNode - ); - return backingNode.mount.type.realPath(backingNode); - } else { - throw new Error( - `Unsupported filesystem type for path ${vfsPath}` - ); - } - }, - check_lock_params(fd, l_type) { - const emscripten_O_RDONLY = Number('0'); - const emscripten_O_WRONLY = Number('1'); - - const accessMode = locking.get_fd_access_mode(fd); - if ( - (l_type === locking.F_WRLCK && - accessMode === emscripten_O_RDONLY) || - (l_type === locking.F_RDLCK && - accessMode === emscripten_O_WRONLY) - ) { - return ERRNO_CODES.EBADF; - } - - return 0; - }, - }; - - function ___syscall_fcntl64(fd, cmd, varargs) { - if (!PHPLoader.fileLockManager) { - return _builtin_fcntl64(fd, cmd, varargs); - } - // Necessary to use varargs accessor - SYSCALLS.varargs = varargs; - - // These constants are replaced by Emscripten during the build process - const emscripten_F_SETFL = Number('4'); - const emscripten_F_GETLK = Number('12'); - const emscripten_F_SETLK = Number('13'); - const emscripten_F_SETLKW = Number('14'); - const emscripten_SEEK_SET = Number('0'); - - // NOTE: With the exception of l_type, these offsets are not exposed to - // JS by Emscripten, so we hardcode them here. - const emscripten_flock_l_type_offset = 0; - const emscripten_flock_l_whence_offset = 2; - const emscripten_flock_l_start_offset = 8; - const emscripten_flock_l_len_offset = 16; - const emscripten_flock_l_pid_offset = 24; - - /** - * Read the flock struct at the given address. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @returns the flock struct - */ - function read_flock_struct(flockStructAddress) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - return { - l_type: HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ], - l_whence: - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + - emscripten_flock_l_whence_offset) >> - 1 - ], - l_start: - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + - emscripten_flock_l_start_offset) >> - 3 - ], - l_len: HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ], - l_pid: HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ], - }; - } - - /** - * Update the flock struct at the given address with the given fields. - * - * @param {bigint} flockStructAddress - the address of the flock struct - * @param {object} fields - the fields to update - */ - function update_flock_struct(flockStructAddress, fields) { - /* - * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, - * we need to adjust offsets to address the word size of each HEAP. - * - * For example, an offset of 64 bytes is the following for each HEAP: - * - HEAP8: 64 (the 64th byte) - * - HEAP16: 32 (the 32nd 16-bit word) - * - HEAP32: 16 (the 16th 32-bit word) - * - HEAP64: 8 (the 8th 64-bit word) - * - * We get a word offset by dividing the byte offset by the word size. - */ - if (fields.l_type !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_type_offset) >> 1 - ] = fields.l_type; - } - if (fields.l_whence !== undefined) { - HEAP16[ - // Shift right by 1 to divide by 2^1. - (flockStructAddress + emscripten_flock_l_whence_offset) >> 1 - ] = fields.l_whence; - } - if (fields.l_start !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_start_offset) >> 3 - ] = fields.l_start; - } - if (fields.l_len !== undefined) { - HEAP64[ - // Shift right by 3 to divide by 2^3. - (flockStructAddress + emscripten_flock_l_len_offset) >> 3 - ] = fields.l_len; - } - if (fields.l_pid !== undefined) { - HEAP32[ - // Shift right by 2 to divide by 2^2. - (flockStructAddress + emscripten_flock_l_pid_offset) >> 2 - ] = fields.l_pid; - } - } - - /** - * Resolve the base address of the range depending on the whence and start offset. - * - * @param {number} fd - the file descriptor - * @param {number} whence - what the start offset is relative to - * @param {bigint} startOffset - the offset from the whence - * @returns The resolved offset and the errno. If there is an error, - * the resolved offset is null, and the errno is non-zero. - */ - function get_base_address(fd, whence, startOffset) { - let baseAddress; - switch (whence) { - case emscripten_SEEK_SET: - baseAddress = 0n; - break; - case emscripten_SEEK_CUR: - baseAddress = FS.lseek(fd, 0, whence); - break; - case emscripten_SEEK_END: - baseAddress = _wasm_get_end_offset(fd); - break; - default: - return [null, ERRNO_CODES.EINVAL]; - } - - if (baseAddress == -1) { - // We cannot resolve the offset within the file. - // Let's treat this as a problem with the file descriptor. - return [null, ERRNO_CODES.EBADF]; - } - - const resolvedOffset = baseAddress + startOffset; - if (resolvedOffset < 0) { - // This is not a valid offset. Report args as invalid. - return [null, ERRNO_CODES.EINVAL]; - } - - return [resolvedOffset, 0]; - } - - const pid = PHPLoader.processId; - switch (cmd) { - case emscripten_F_GETLK: { - _js_wasm_trace('fcntl(%d, F_GETLK)', fd); - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EBADF; - } - - const flockStructAddr = syscallGetVarargP(); - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - const flockStruct = read_flock_struct(flockStructAddr); - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const conflictingLock = - PHPLoader.fileLockManager.findFirstConflictingByteRangeLock( - nativeFilePath, - { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - } - ); - if (conflictingLock === undefined) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', - fd, - vfsPath, - absoluteStartOffset, - absoluteStartOffset + flockStruct.l_len - ); - - update_flock_struct(flockStructAddr, { - l_type: F_UNLCK, - }); - return 0; - } - - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', - fd, - vfsPath, - conflictingLock.type, - conflictingLock.start, - conflictingLock.end, - conflictingLock.pid - ); - - const fcntlLockState = - locking.lockStateToFcntl[conflictingLock.type]; - update_flock_struct(flockStructAddr, { - l_type: fcntlLockState, - l_whence: emscripten_SEEK_SET, - l_start: conflictingLock.start, - l_len: conflictingLock.end - conflictingLock.start, - l_pid: conflictingLock.pid, - }); - return 0; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', - fd, - vfsPath, - e - ); - return -ERRNO_CODES.EINVAL; - } - } - case emscripten_F_SETLK: { - _js_wasm_trace('fcntl(%d, F_SETLK)', fd); - let vfsPath; - let errno; - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', - fd, - vfsPath - ); - - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - var flockStructAddr = syscallGetVarargP(); - const flockStruct = read_flock_struct(flockStructAddr); - - let absoluteStartOffset; - [absoluteStartOffset, errno] = get_base_address( - fd, - flockStruct.l_whence, - flockStruct.l_start - ); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s get_base_address errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - if (!(flockStruct.l_type in locking.fcntlToLockState)) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s invalid lock type %d', - fd, - vfsPath, - flockStruct.l_type - ); - return -ERRNO_CODES.EINVAL; - } - - errno = locking.check_lock_params(fd, flockStruct.l_type); - if (errno !== 0) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', - fd, - vfsPath, - errno - ); - return -errno; - } - - locking.maybeLockedFds.add(fd); - - const requestedLockType = - locking.fcntlToLockState[flockStruct.l_type]; - const rangeLock = { - type: requestedLockType, - start: absoluteStartOffset, - end: absoluteStartOffset + flockStruct.l_len, - pid, - }; - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', - fd, - vfsPath, - rangeLock - ); - - const succeeded = - PHPLoader.fileLockManager.lockFileByteRange( - nativeFilePath, - rangeLock - ); - - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', - fd, - vfsPath, - succeeded, - rangeLock - ); - return succeeded ? 0 : -ERRNO_CODES.EAGAIN; - } catch (e) { - _js_wasm_trace( - 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', - fd, - vfsPath, - e, - rangeLock - ); - return -ERRNO_CODES.EINVAL; - } - } - // @TODO: Implement waiting for lock - case emscripten_F_SETLKW: { - // We do not yet support the blocking form of flock(). - // We respond with EDEADLK to indicate failure - // because it is a known errno for a failed F_SETLKW command. - return -ERRNO_CODES.EDEADLK; - } - case emscripten_F_SETFL: { - /** - * Overrides the core Emscripten implementation to reflect what - * fcntl does in linux kernel. This implementation is still missing - * a bunch of nuance, but, unlike the core Emscripten implementation, - * it overrides the stream flags while preserving non-stream flags. - * - * @see fcntl.c: - * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 - */ - const arg = varargs ? syscallGetVarargI() : 0; - const stream = SYSCALLS.getStreamFromFD(fd); - - // Update the stream flags - stream.flags = - (arg & PHPWASM.SETFL_MASK) | - (stream.flags & ~PHPWASM.SETFL_MASK); - - return 0; - } - default: - return _builtin_fcntl64(fd, cmd, varargs); - } - } - ___syscall_fcntl64.sig = 'iiip'; - - function ___syscall_fdatasync(fd) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - return 0; // we can't do anything synchronously; the in-memory FS is already synced to - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_fdatasync.sig = 'ii'; - - function ___syscall_fstat64(fd, buf) { - try { - return SYSCALLS.writeStat(buf, FS.fstat(fd)); - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_fstat64.sig = 'iip'; - - function ___syscall_fstatfs64(fd, size, buf) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - SYSCALLS.writeStatFs(buf, FS.statfsStream(stream)); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_fstatfs64.sig = 'iipp'; - - function ___syscall_ftruncate64(fd, length) { - length = bigintToI53Checked(length); - - try { - if (isNaN(length)) return -61; - FS.ftruncate(fd, length); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_ftruncate64.sig = 'iij'; - - function ___syscall_getcwd(buf, size) { - try { - if (size === 0) return -28; - var cwd = FS.cwd(); - var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1; - if (size < cwdLengthInBytes) return -68; - stringToUTF8(cwd, buf, size); - return cwdLengthInBytes; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_getcwd.sig = 'ipp'; - - function ___syscall_getdents64(fd, dirp, count) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - stream.getdents ||= FS.readdir(stream.path); - - var struct_size = 280; - var pos = 0; - var off = FS.llseek(stream, 0, 1); - - var startIdx = Math.floor(off / struct_size); - var endIdx = Math.min( - stream.getdents.length, - startIdx + Math.floor(count / struct_size) - ); - for (var idx = startIdx; idx < endIdx; idx++) { - var id; - var type; - var name = stream.getdents[idx]; - if (name === '.') { - id = stream.node.id; - type = 4; // DT_DIR - } else if (name === '..') { - var lookup = FS.lookupPath(stream.path, { parent: true }); - id = lookup.node.id; - type = 4; // DT_DIR - } else { - var child; - try { - child = FS.lookupNode(stream.node, name); - } catch (e) { - // If the entry is not a directory, file, or symlink, nodefs - // lookupNode will raise EINVAL. Skip these and continue. - if (e?.errno === 28) { - continue; - } - throw e; - } - id = child.id; - type = FS.isChrdev(child.mode) - ? 2 // DT_CHR, character device. - : FS.isDir(child.mode) - ? 4 // DT_DIR, directory. - : FS.isLink(child.mode) - ? 10 // DT_LNK, symbolic link. - : 8; // DT_REG, regular file. - } - HEAP64[(dirp + pos) >> 3] = BigInt(id); - HEAP64[(dirp + pos + 8) >> 3] = BigInt((idx + 1) * struct_size); - HEAP16[(dirp + pos + 16) >> 1] = 280; - HEAP8[dirp + pos + 18] = type; - stringToUTF8(name, dirp + pos + 19, 256); - pos += struct_size; - } - FS.llseek(stream, idx * struct_size, 0); - return pos; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_getdents64.sig = 'iipp'; - - function ___syscall_getpeername(fd, addr, addrlen, d1, d2, d3) { - try { - var sock = getSocketFromFD(fd); - if (!sock.daddr) { - return -53; // The socket is not connected. - } - var errno = writeSockaddr( - addr, - sock.family, - DNS.lookup_name(sock.daddr), - sock.dport, - addrlen - ); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_getpeername.sig = 'iippiii'; - - function ___syscall_getsockname(fd, addr, addrlen, d1, d2, d3) { - try { - var sock = getSocketFromFD(fd); - // TODO: sock.saddr should never be undefined, see TODO in websocket_sock_ops.getname - var errno = writeSockaddr( - addr, - sock.family, - DNS.lookup_name(sock.saddr || '0.0.0.0'), - sock.sport, - addrlen - ); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_getsockname.sig = 'iippiii'; - - function ___syscall_getsockopt(fd, level, optname, optval, optlen, d1) { - try { - var sock = getSocketFromFD(fd); - // Minimal getsockopt aimed at resolving https://github.com/emscripten-core/emscripten/issues/2211 - // so only supports SOL_SOCKET with SO_ERROR. - if (level === 1) { - if (optname === 4) { - HEAP32[optval >> 2] = sock.error; - HEAP32[optlen >> 2] = 4; - sock.error = null; // Clear the error (The SO_ERROR option obtains and then clears this field). - return 0; - } - } - return -50; // The option is unknown at the level indicated. - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_getsockopt.sig = 'iiiippi'; - - function ___syscall_ioctl(fd, op, varargs) { - SYSCALLS.varargs = varargs; - try { - var stream = SYSCALLS.getStreamFromFD(fd); - switch (op) { - case 21509: { - if (!stream.tty) return -59; - return 0; - } - case 21505: { - if (!stream.tty) return -59; - if (stream.tty.ops.ioctl_tcgets) { - var termios = stream.tty.ops.ioctl_tcgets(stream); - var argp = syscallGetVarargP(); - HEAP32[argp >> 2] = termios.c_iflag || 0; - HEAP32[(argp + 4) >> 2] = termios.c_oflag || 0; - HEAP32[(argp + 8) >> 2] = termios.c_cflag || 0; - HEAP32[(argp + 12) >> 2] = termios.c_lflag || 0; - for (var i = 0; i < 32; i++) { - HEAP8[argp + i + 17] = termios.c_cc[i] || 0; - } - return 0; - } - return 0; - } - case 21510: - case 21511: - case 21512: { - if (!stream.tty) return -59; - return 0; // no-op, not actually adjusting terminal settings - } - case 21506: - case 21507: - case 21508: { - if (!stream.tty) return -59; - if (stream.tty.ops.ioctl_tcsets) { - var argp = syscallGetVarargP(); - var c_iflag = HEAP32[argp >> 2]; - var c_oflag = HEAP32[(argp + 4) >> 2]; - var c_cflag = HEAP32[(argp + 8) >> 2]; - var c_lflag = HEAP32[(argp + 12) >> 2]; - var c_cc = []; - for (var i = 0; i < 32; i++) { - c_cc.push(HEAP8[argp + i + 17]); - } - return stream.tty.ops.ioctl_tcsets(stream.tty, op, { - c_iflag, - c_oflag, - c_cflag, - c_lflag, - c_cc, - }); - } - return 0; // no-op, not actually adjusting terminal settings - } - case 21519: { - if (!stream.tty) return -59; - var argp = syscallGetVarargP(); - HEAP32[argp >> 2] = 0; - return 0; - } - case 21520: { - if (!stream.tty) return -59; - return -28; // not supported - } - case 21537: - case 21531: { - var argp = syscallGetVarargP(); - return FS.ioctl(stream, op, argp); - } - case 21523: { - // TODO: in theory we should write to the winsize struct that gets - // passed in, but for now musl doesn't read anything on it - if (!stream.tty) return -59; - if (stream.tty.ops.ioctl_tiocgwinsz) { - var winsize = stream.tty.ops.ioctl_tiocgwinsz( - stream.tty - ); - var argp = syscallGetVarargP(); - HEAP16[argp >> 1] = winsize[0]; - HEAP16[(argp + 2) >> 1] = winsize[1]; - } - return 0; - } - case 21524: { - // TODO: technically, this ioctl call should change the window size. - // but, since emscripten doesn't have any concept of a terminal window - // yet, we'll just silently throw it away as we do TIOCGWINSZ - if (!stream.tty) return -59; - return 0; - } - case 21515: { - if (!stream.tty) return -59; - return 0; - } - default: - return -28; // not supported - } - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_ioctl.sig = 'iiip'; - - function ___syscall_listen(fd, backlog) { - try { - var sock = getSocketFromFD(fd); - sock.sock_ops.listen(sock, backlog); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_listen.sig = 'iiiiiii'; - - function ___syscall_lstat64(path, buf) { - try { - path = SYSCALLS.getStr(path); - return SYSCALLS.writeStat(buf, FS.lstat(path)); - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_lstat64.sig = 'ipp'; - - function ___syscall_mkdirat(dirfd, path, mode) { - try { - path = SYSCALLS.getStr(path); - path = SYSCALLS.calculateAt(dirfd, path); - FS.mkdir(path, mode, 0); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_mkdirat.sig = 'iipi'; - - function ___syscall_mknodat(dirfd, path, mode, dev) { - try { - path = SYSCALLS.getStr(path); - path = SYSCALLS.calculateAt(dirfd, path); - // we don't want this in the JS API as it uses mknod to create all nodes. - switch (mode & 61440) { - case 32768: - case 8192: - case 24576: - case 4096: - case 49152: - break; - default: - return -28; - } - FS.mknod(path, mode, dev); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_mknodat.sig = 'iipii'; - - function ___syscall_newfstatat(dirfd, path, buf, flags) { - try { - path = SYSCALLS.getStr(path); - var nofollow = flags & 256; - var allowEmpty = flags & 4096; - flags = flags & ~6400; - path = SYSCALLS.calculateAt(dirfd, path, allowEmpty); - return SYSCALLS.writeStat( - buf, - nofollow ? FS.lstat(path) : FS.stat(path) - ); - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_newfstatat.sig = 'iippi'; - - function ___syscall_openat(dirfd, path, flags, varargs) { - SYSCALLS.varargs = varargs; - try { - path = SYSCALLS.getStr(path); - path = SYSCALLS.calculateAt(dirfd, path); - var mode = varargs ? syscallGetVarargI() : 0; - return FS.open(path, flags, mode).fd; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_openat.sig = 'iipip'; - - var PIPEFS = { - BUCKET_BUFFER_SIZE: 8192, - mount(mount) { - // Do not pollute the real root directory or its child nodes with pipes - // Looks like it is OK to create another pseudo-root node not linked to the FS.root hierarchy this way - return FS.createNode(null, '/', 16384 | 0o777, 0); - }, - createPipe() { - var pipe = { - buckets: [], - // refcnt 2 because pipe has a read end and a write end. We need to be - // able to read from the read end after write end is closed. - refcnt: 2, - timestamp: new Date(), - }; - - pipe.buckets.push({ - buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE), - offset: 0, - roffset: 0, - }); - - var rName = PIPEFS.nextname(); - var wName = PIPEFS.nextname(); - var rNode = FS.createNode(PIPEFS.root, rName, 4096, 0); - var wNode = FS.createNode(PIPEFS.root, wName, 4096, 0); - - rNode.pipe = pipe; - wNode.pipe = pipe; - - var readableStream = FS.createStream({ - path: rName, - node: rNode, - flags: 0, - seekable: false, - stream_ops: PIPEFS.stream_ops, - }); - rNode.stream = readableStream; - - var writableStream = FS.createStream({ - path: wName, - node: wNode, - flags: 1, - seekable: false, - stream_ops: PIPEFS.stream_ops, - }); - wNode.stream = writableStream; - - return { - readable_fd: readableStream.fd, - writable_fd: writableStream.fd, - }; - }, - stream_ops: { - getattr(stream) { - var node = stream.node; - var timestamp = node.pipe.timestamp; - return { - dev: 14, - ino: node.id, - mode: 0o10600, - nlink: 1, - uid: 0, - gid: 0, - rdev: 0, - size: 0, - atime: timestamp, - mtime: timestamp, - ctime: timestamp, - blksize: 4096, - blocks: 0, - }; - }, - poll(stream) { - var pipe = stream.node.pipe; - - if ((stream.flags & 2097155) === 1) { - return 256 | 4; - } - for (var bucket of pipe.buckets) { - if (bucket.offset - bucket.roffset > 0) { - return 64 | 1; - } - } - - return 0; - }, - dup(stream) { - stream.node.pipe.refcnt++; - }, - ioctl(stream, request, varargs) { - return 28; - }, - fsync(stream) { - return 28; - }, - read(stream, buffer, offset, length, position /* ignored */) { - var pipe = stream.node.pipe; - var currentLength = 0; - - for (var bucket of pipe.buckets) { - currentLength += bucket.offset - bucket.roffset; - } - - var data = buffer.subarray(offset, offset + length); - - if (length <= 0) { - return 0; - } - if (currentLength == 0) { - if (pipe.refcnt < 2) { - return 0; - } - throw new FS.ErrnoError(6); - } - var toRead = Math.min(currentLength, length); - - var totalRead = toRead; - var toRemove = 0; - - for (var bucket of pipe.buckets) { - var bucketSize = bucket.offset - bucket.roffset; - - if (toRead <= bucketSize) { - var tmpSlice = bucket.buffer.subarray( - bucket.roffset, - bucket.offset - ); - if (toRead < bucketSize) { - tmpSlice = tmpSlice.subarray(0, toRead); - bucket.roffset += toRead; - } else { - toRemove++; - } - data.set(tmpSlice); - break; - } else { - var tmpSlice = bucket.buffer.subarray( - bucket.roffset, - bucket.offset - ); - data.set(tmpSlice); - data = data.subarray(tmpSlice.byteLength); - toRead -= tmpSlice.byteLength; - toRemove++; - } - } - - if (toRemove && toRemove == pipe.buckets.length) { - // Do not generate excessive garbage in use cases such as - // write several bytes, read everything, write several bytes, read everything... - toRemove--; - pipe.buckets[toRemove].offset = 0; - pipe.buckets[toRemove].roffset = 0; - } - - pipe.buckets.splice(0, toRemove); - - return totalRead; - }, - write(stream, buffer, offset, length, position /* ignored */) { - var pipe = stream.node.pipe; - - var data = buffer.subarray(offset, offset + length); - - var dataLen = data.byteLength; - if (dataLen <= 0) { - return 0; - } - - var currBucket = null; - - if (pipe.buckets.length == 0) { - currBucket = { - buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE), - offset: 0, - roffset: 0, - }; - pipe.buckets.push(currBucket); - } else { - currBucket = pipe.buckets[pipe.buckets.length - 1]; - } - - var freeBytesInCurrBuffer = - PIPEFS.BUCKET_BUFFER_SIZE - currBucket.offset; - if (freeBytesInCurrBuffer >= dataLen) { - currBucket.buffer.set(data, currBucket.offset); - currBucket.offset += dataLen; - return dataLen; - } else if (freeBytesInCurrBuffer > 0) { - currBucket.buffer.set( - data.subarray(0, freeBytesInCurrBuffer), - currBucket.offset - ); - currBucket.offset += freeBytesInCurrBuffer; - data = data.subarray( - freeBytesInCurrBuffer, - data.byteLength - ); - } - - var numBuckets = - (data.byteLength / PIPEFS.BUCKET_BUFFER_SIZE) | 0; - var remElements = data.byteLength % PIPEFS.BUCKET_BUFFER_SIZE; - - for (var i = 0; i < numBuckets; i++) { - var newBucket = { - buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE), - offset: PIPEFS.BUCKET_BUFFER_SIZE, - roffset: 0, - }; - pipe.buckets.push(newBucket); - newBucket.buffer.set( - data.subarray(0, PIPEFS.BUCKET_BUFFER_SIZE) - ); - data = data.subarray( - PIPEFS.BUCKET_BUFFER_SIZE, - data.byteLength - ); - } - - if (remElements > 0) { - var newBucket = { - buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE), - offset: data.byteLength, - roffset: 0, - }; - pipe.buckets.push(newBucket); - newBucket.buffer.set(data); - } - - return dataLen; - }, - close(stream) { - var pipe = stream.node.pipe; - pipe.refcnt--; - if (pipe.refcnt === 0) { - pipe.buckets = null; - } - }, - }, - nextname() { - if (!PIPEFS.nextname.current) { - PIPEFS.nextname.current = 0; - } - return 'pipe[' + PIPEFS.nextname.current++ + ']'; - }, - }; - function ___syscall_pipe(fdPtr) { - try { - if (fdPtr == 0) { - throw new FS.ErrnoError(21); - } - - var res = PIPEFS.createPipe(); - - HEAP32[fdPtr >> 2] = res.readable_fd; - HEAP32[(fdPtr + 4) >> 2] = res.writable_fd; - - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_pipe.sig = 'ip'; - - function ___syscall_poll(fds, nfds, timeout) { - try { - var nonzero = 0; - for (var i = 0; i < nfds; i++) { - var pollfd = fds + 8 * i; - var fd = HEAP32[pollfd >> 2]; - var events = HEAP16[(pollfd + 4) >> 1]; - var mask = 32; - var stream = FS.getStream(fd); - if (stream) { - mask = SYSCALLS.DEFAULT_POLLMASK; - if (stream.stream_ops?.poll) { - mask = stream.stream_ops.poll(stream, -1); - } - } - mask &= events | 8 | 16; - if (mask) nonzero++; - HEAP16[(pollfd + 6) >> 1] = mask; - } - return nonzero; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_poll.sig = 'ipii'; - - function ___syscall_readlinkat(dirfd, path, buf, bufsize) { - try { - path = SYSCALLS.getStr(path); - path = SYSCALLS.calculateAt(dirfd, path); - if (bufsize <= 0) return -28; - var ret = FS.readlink(path); - - var len = Math.min(bufsize, lengthBytesUTF8(ret)); - var endChar = HEAP8[buf + len]; - stringToUTF8(ret, buf, bufsize + 1); - // readlink is one of the rare functions that write out a C string, but does never append a null to the output buffer(!) - // stringToUTF8() always appends a null byte, so restore the character under the null byte after the write. - HEAP8[buf + len] = endChar; - return len; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_readlinkat.sig = 'iippp'; - - function ___syscall_recvfrom(fd, buf, len, flags, addr, addrlen) { - try { - var sock = getSocketFromFD(fd); - var msg = sock.sock_ops.recvmsg( - sock, - len, - typeof flags !== 'undefined' ? flags : 0 - ); - if (!msg) return 0; // socket is closed - if (addr) { - var errno = writeSockaddr( - addr, - sock.family, - DNS.lookup_name(msg.addr), - msg.port, - addrlen - ); - } - HEAPU8.set(msg.buffer, buf); - return msg.buffer.byteLength; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_recvfrom.sig = 'iippipp'; - - function ___syscall_recvmsg(fd, message, flags, d1, d2, d3) { - try { - var sock = getSocketFromFD(fd); - var iov = HEAPU32[(message + 8) >> 2]; - var num = HEAP32[(message + 12) >> 2]; - // get the total amount of data we can read across all arrays - var total = 0; - for (var i = 0; i < num; i++) { - total += HEAP32[(iov + (8 * i + 4)) >> 2]; - } - // try to read total data - var msg = sock.sock_ops.recvmsg(sock, total); - if (!msg) return 0; // socket is closed - - // TODO honor flags: - // MSG_OOB - // Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific. - // MSG_PEEK - // Peeks at the incoming message. - // MSG_WAITALL - // Requests that the function block until the full amount of data requested can be returned. The function may return a smaller amount of data if a signal is caught, if the connection is terminated, if MSG_PEEK was specified, or if an error is pending for the socket. - - // write the source address out - var name = HEAPU32[message >> 2]; - if (name) { - var errno = writeSockaddr( - name, - sock.family, - DNS.lookup_name(msg.addr), - msg.port - ); - } - // write the buffer out to the scatter-gather arrays - var bytesRead = 0; - var bytesRemaining = msg.buffer.byteLength; - for (var i = 0; bytesRemaining > 0 && i < num; i++) { - var iovbase = HEAPU32[(iov + (8 * i + 0)) >> 2]; - var iovlen = HEAP32[(iov + (8 * i + 4)) >> 2]; - if (!iovlen) { - continue; - } - var length = Math.min(iovlen, bytesRemaining); - var buf = msg.buffer.subarray(bytesRead, bytesRead + length); - HEAPU8.set(buf, iovbase + bytesRead); - bytesRead += length; - bytesRemaining -= length; - } - - // TODO set msghdr.msg_flags - // MSG_EOR - // End of record was received (if supported by the protocol). - // MSG_OOB - // Out-of-band data was received. - // MSG_TRUNC - // Normal data was truncated. - // MSG_CTRUNC - - return bytesRead; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_recvmsg.sig = 'iipiiii'; - - function ___syscall_renameat(olddirfd, oldpath, newdirfd, newpath) { - try { - oldpath = SYSCALLS.getStr(oldpath); - newpath = SYSCALLS.getStr(newpath); - oldpath = SYSCALLS.calculateAt(olddirfd, oldpath); - newpath = SYSCALLS.calculateAt(newdirfd, newpath); - FS.rename(oldpath, newpath); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_renameat.sig = 'iipip'; - - function ___syscall_rmdir(path) { - try { - path = SYSCALLS.getStr(path); - FS.rmdir(path); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_rmdir.sig = 'ip'; - - function ___syscall_sendmsg(fd, message, flags, d1, d2, d3) { - try { - var sock = getSocketFromFD(fd); - var iov = HEAPU32[(message + 8) >> 2]; - var num = HEAP32[(message + 12) >> 2]; - // read the address and port to send to - var addr, port; - var name = HEAPU32[message >> 2]; - var namelen = HEAP32[(message + 4) >> 2]; - if (name) { - var info = getSocketAddress(name, namelen); - port = info.port; - addr = info.addr; - } - // concatenate scatter-gather arrays into one message buffer - var total = 0; - for (var i = 0; i < num; i++) { - total += HEAP32[(iov + (8 * i + 4)) >> 2]; - } - var view = new Uint8Array(total); - var offset = 0; - for (var i = 0; i < num; i++) { - var iovbase = HEAPU32[(iov + (8 * i + 0)) >> 2]; - var iovlen = HEAP32[(iov + (8 * i + 4)) >> 2]; - for (var j = 0; j < iovlen; j++) { - view[offset++] = HEAP8[iovbase + j]; - } - } - // write the buffer - return sock.sock_ops.sendmsg(sock, view, 0, total, addr, port); - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_sendmsg.sig = 'iipippi'; - - function ___syscall_sendto(fd, message, length, flags, addr, addr_len) { - try { - var sock = getSocketFromFD(fd); - if (!addr) { - // send, no address provided - return FS.write(sock.stream, HEAP8, message, length); - } - var dest = getSocketAddress(addr, addr_len); - // sendto an address - return sock.sock_ops.sendmsg( - sock, - HEAP8, - message, - length, - dest.addr, - dest.port - ); - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_sendto.sig = 'iippipp'; - - function ___syscall_socket(domain, type, protocol) { - try { - var sock = SOCKFS.createSocket(domain, type, protocol); - return sock.stream.fd; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_socket.sig = 'iiiiiii'; - - function ___syscall_stat64(path, buf) { - try { - path = SYSCALLS.getStr(path); - return SYSCALLS.writeStat(buf, FS.stat(path)); - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_stat64.sig = 'ipp'; - - function ___syscall_statfs64(path, size, buf) { - try { - SYSCALLS.writeStatFs(buf, FS.statfs(SYSCALLS.getStr(path))); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_statfs64.sig = 'ippp'; - - function ___syscall_symlinkat(target, dirfd, linkpath) { - try { - target = SYSCALLS.getStr(target); - linkpath = SYSCALLS.getStr(linkpath); - linkpath = SYSCALLS.calculateAt(dirfd, linkpath); - FS.symlink(target, linkpath); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_symlinkat.sig = 'ipip'; - - function ___syscall_truncate64(path, length) { - length = bigintToI53Checked(length); - - try { - if (isNaN(length)) return -61; - path = SYSCALLS.getStr(path); - FS.truncate(path, length); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_truncate64.sig = 'ipj'; - - function ___syscall_unlinkat(dirfd, path, flags) { - try { - path = SYSCALLS.getStr(path); - path = SYSCALLS.calculateAt(dirfd, path); - if (!flags) { - FS.unlink(path); - } else if (flags === 512) { - FS.rmdir(path); - } else { - return -28; - } - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_unlinkat.sig = 'iipi'; - - var readI53FromI64 = (ptr) => { - return HEAPU32[ptr >> 2] + HEAP32[(ptr + 4) >> 2] * 4294967296; - }; - - function ___syscall_utimensat(dirfd, path, times, flags) { - try { - path = SYSCALLS.getStr(path); - path = SYSCALLS.calculateAt(dirfd, path, true); - var now = Date.now(), - atime, - mtime; - if (!times) { - atime = now; - mtime = now; - } else { - var seconds = readI53FromI64(times); - var nanoseconds = HEAP32[(times + 8) >> 2]; - if (nanoseconds == 1073741823) { - atime = now; - } else if (nanoseconds == 1073741822) { - atime = null; - } else { - atime = seconds * 1000 + nanoseconds / (1000 * 1000); - } - times += 16; - seconds = readI53FromI64(times); - nanoseconds = HEAP32[(times + 8) >> 2]; - if (nanoseconds == 1073741823) { - mtime = now; - } else if (nanoseconds == 1073741822) { - mtime = null; - } else { - mtime = seconds * 1000 + nanoseconds / (1000 * 1000); - } - } - // null here means UTIME_OMIT was passed. If both were set to UTIME_OMIT then - // we can skip the call completely. - if ((mtime ?? atime) !== null) { - FS.utime(path, atime, mtime); - } - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - ___syscall_utimensat.sig = 'iippi'; - - var __abort_js = () => abort(''); - __abort_js.sig = 'v'; - - var dlSetError = (msg) => { - var sp = stackSave(); - var cmsg = stringToUTF8OnStack(msg); - ___dl_seterr(cmsg, 0); - stackRestore(sp); - }; - - var dlopenInternal = (handle, jsflags) => { - // void *dlopen(const char *file, int mode); - // http://pubs.opengroup.org/onlinepubs/009695399/functions/dlopen.html - var filename = UTF8ToString(handle + 36); - var flags = HEAP32[(handle + 4) >> 2]; - filename = PATH.normalize(filename); - var searchpaths = []; - - var global = Boolean(flags & 256); - var localScope = global ? null : {}; - - // We don't care about RTLD_NOW and RTLD_LAZY. - var combinedFlags = { - global, - nodelete: Boolean(flags & 4096), - loadAsync: jsflags.loadAsync, - }; - - if (jsflags.loadAsync) { - return loadDynamicLibrary( - filename, - combinedFlags, - localScope, - handle - ); - } - - try { - return loadDynamicLibrary( - filename, - combinedFlags, - localScope, - handle - ); - } catch (e) { - dlSetError(`could not load dynamic lib: ${filename}\n${e}`); - return 0; - } - }; - function __dlopen_js(handle) { - var jsflags = { loadAsync: false }; - return dlopenInternal(handle, jsflags); - } - __dlopen_js.sig = 'pp'; - - var __dlsym_js = (handle, symbol, symbolIndex) => { - // void *dlsym(void *restrict handle, const char *restrict name); - // http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html - symbol = UTF8ToString(symbol); - var result; - var newSymIndex; - - var lib = LDSO.loadedLibsByHandle[handle]; - newSymIndex = Object.keys(lib.exports).indexOf(symbol); - if (newSymIndex == -1 || lib.exports[symbol].stub) { - dlSetError( - `Tried to lookup unknown symbol "${symbol}" in dynamic lib: ${lib.name}` - ); - return 0; - } - result = lib.exports[symbol]; - - if (typeof result == 'function') { - // Asyncify wraps exports, and we need to look through those wrappers. - if (result.orig) { - result = result.orig; - } - var addr = getFunctionAddress(result); - if (addr) { - result = addr; - } else { - // Insert the function into the wasm table. If its a direct wasm - // function the second argument will not be needed. If its a JS - // function we rely on the `sig` attribute being set based on the - // `__sig` specified in library JS file. - result = addFunction(result, result.sig); - HEAPU32[symbolIndex >> 2] = newSymIndex; - } - } - return result; - }; - __dlsym_js.sig = 'pppp'; - - var handleException = (e) => { - // Certain exception types we do not treat as errors since they are used for - // internal control flow. - // 1. ExitStatus, which is thrown by exit() - // 2. "unwind", which is thrown by emscripten_unwind_to_js_event_loop() and others - // that wish to return to JS event loop. - if (e instanceof ExitStatus || e == 'unwind') { - return EXITSTATUS; - } - quit_(1, e); - }; - - var runtimeKeepaliveCounter = 0; - var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0; - var _proc_exit = (code) => { - EXITSTATUS = code; - if (!keepRuntimeAlive()) { - Module['onExit']?.(code); - ABORT = true; - } - quit_(code, new ExitStatus(code)); - }; - _proc_exit.sig = 'vi'; - - /** @param {boolean|number=} implicit */ - var exitJS = (status, implicit) => { - EXITSTATUS = status; - - if (!keepRuntimeAlive()) { - exitRuntime(); - } - - _proc_exit(status); - }; - var _exit = exitJS; - _exit.sig = 'vi'; - - var maybeExit = () => { - if (runtimeExited) { - return; - } - if (!keepRuntimeAlive()) { - try { - _exit(EXITSTATUS); - } catch (e) { - handleException(e); - } - } - }; - var callUserCallback = (func) => { - if (runtimeExited || ABORT) { - return; - } - try { - func(); - maybeExit(); - } catch (e) { - handleException(e); - } - }; - - var runtimeKeepalivePush = () => { - runtimeKeepaliveCounter += 1; - }; - runtimeKeepalivePush.sig = 'v'; - - var runtimeKeepalivePop = () => { - runtimeKeepaliveCounter -= 1; - }; - runtimeKeepalivePop.sig = 'v'; - - var __emscripten_dlopen_js = (handle, onsuccess, onerror, user_data) => { - /** @param {Object=} e */ - function errorCallback(e) { - var filename = UTF8ToString(handle + 36); - dlSetError(`'Could not load dynamic lib: ${filename}\n${e}`); - runtimeKeepalivePop(); - callUserCallback(() => - (( - a1, - a2 - ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - handle, - user_data - ) - ); - } - function successCallback() { - runtimeKeepalivePop(); - callUserCallback(() => - (( - a1, - a2 - ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - handle, - user_data - ) - ); - } - - runtimeKeepalivePush(); - var promise = dlopenInternal(handle, { loadAsync: true }); - if (promise) { - promise.then(successCallback, errorCallback); - } else { - errorCallback(); - } - }; - __emscripten_dlopen_js.sig = 'vpppp'; - - var getExecutableName = () => thisProgram || './this.program'; - - var __emscripten_get_progname = (str, len) => - stringToUTF8(getExecutableName(), str, len); - __emscripten_get_progname.sig = 'vpi'; - - var jsStackTrace = () => new Error().stack.toString(); - /** @param {number=} flags */ - var getCallstack = (flags) => { - var callstack = jsStackTrace(); - - // Process all lines: - var lines = callstack.split('\n'); - callstack = ''; - // Extract components of form: - // ' Object._main@http://server.com:4324:12' - var firefoxRe = new RegExp('\\s*(.*?)@(.*?):([0-9]+):([0-9]+)'); - // Extract components of form: - // ' at Object._main (http://server.com/file.html:4324:12)' - var chromeRe = new RegExp('\\s*at (.*?) \\((.*):(.*):(.*)\\)'); - - for (var line of lines) { - var symbolName = ''; - var file = ''; - var lineno = 0; - var column = 0; - - var parts = chromeRe.exec(line); - if (parts?.length == 5) { - symbolName = parts[1]; - file = parts[2]; - lineno = parts[3]; - column = parts[4]; - } else { - parts = firefoxRe.exec(line); - if (parts?.length >= 4) { - symbolName = parts[1]; - file = parts[2]; - lineno = parts[3]; - // Old Firefox doesn't carry column information, but in new FF30, it - // is present. See https://bugzil.la/762556 - column = parts[4] | 0; - } else { - // Was not able to extract this line for demangling/sourcemapping - // purposes. Output it as-is. - callstack += line + '\n'; - continue; - } - } - - // Find the symbols in the callstack that corresponds to the functions that - // report callstack information, and remove everything up to these from the - // output. - if ( - symbolName == '_emscripten_log' || - symbolName == '_emscripten_get_callstack' - ) { - callstack = ''; - continue; - } - - if (flags & 24) { - if (flags & 64) { - file = file.substring( - file.replace(/\\/g, '/').lastIndexOf('/') + 1 - ); - } - callstack += ` at ${symbolName} (${file}:${lineno}:${column})\n`; - } - } - // Trim extra whitespace at the end of the output. - callstack = callstack.replace(/\s+$/, ''); - return callstack; - }; - - var __emscripten_log_formatted = (flags, str) => { - str = UTF8ToString(str); - - if (flags & 24) { - str = str.replace(/\s+$/, ''); // Ensure the message and the callstack are joined cleanly with exactly one newline. - str += (str.length > 0 ? '\n' : '') + getCallstack(flags); - } - - if (flags & 1) { - if (flags & 4) { - console.error(str); - } else if (flags & 2) { - console.warn(str); - } else if (flags & 512) { - console.info(str); - } else if (flags & 256) { - console.debug(str); - } else { - console.log(str); - } - } else if (flags & 6) { - err(str); - } else { - out(str); - } - }; - __emscripten_log_formatted.sig = 'vip'; - - var __emscripten_lookup_name = (name) => { - // uint32_t _emscripten_lookup_name(const char *name); - var nameString = UTF8ToString(name); - return inetPton4(DNS.lookup_name(nameString)); - }; - __emscripten_lookup_name.sig = 'ip'; - - var __emscripten_runtime_keepalive_clear = () => { - noExitRuntime = false; - runtimeKeepaliveCounter = 0; - }; - __emscripten_runtime_keepalive_clear.sig = 'v'; - - var __emscripten_system = (command) => { - if (ENVIRONMENT_IS_NODE) { - if (!command) return 1; // shell is available - - var cmdstr = UTF8ToString(command); - if (!cmdstr.length) return 0; // this is what glibc seems to do (shell works test?) - - var cp = require('child_process'); - var ret = cp.spawnSync(cmdstr, [], { - shell: true, - stdio: 'inherit', - }); - - var _W_EXITCODE = (ret, sig) => (ret << 8) | sig; - - // this really only can happen if process is killed by signal - if (ret.status === null) { - // sadly node doesn't expose such function - var signalToNumber = (sig) => { - // implement only the most common ones, and fallback to SIGINT - switch (sig) { - case 'SIGHUP': - return 1; - case 'SIGQUIT': - return 3; - case 'SIGFPE': - return 8; - case 'SIGKILL': - return 9; - case 'SIGALRM': - return 14; - case 'SIGTERM': - return 15; - default: - return 2; - } - }; - return _W_EXITCODE(0, signalToNumber(ret.signal)); - } - - return _W_EXITCODE(ret.status, 0); - } - // int system(const char *command); - // http://pubs.opengroup.org/onlinepubs/000095399/functions/system.html - // Can't call external programs. - if (!command) return 0; // no shell available - return -52; - }; - __emscripten_system.sig = 'ip'; - - var __emscripten_throw_longjmp = () => { - throw Infinity; - }; - __emscripten_throw_longjmp.sig = 'v'; - - function __gmtime_js(time, tmPtr) { - time = bigintToI53Checked(time); - - var date = new Date(time * 1000); - HEAP32[tmPtr >> 2] = date.getUTCSeconds(); - HEAP32[(tmPtr + 4) >> 2] = date.getUTCMinutes(); - HEAP32[(tmPtr + 8) >> 2] = date.getUTCHours(); - HEAP32[(tmPtr + 12) >> 2] = date.getUTCDate(); - HEAP32[(tmPtr + 16) >> 2] = date.getUTCMonth(); - HEAP32[(tmPtr + 20) >> 2] = date.getUTCFullYear() - 1900; - HEAP32[(tmPtr + 24) >> 2] = date.getUTCDay(); - var start = Date.UTC(date.getUTCFullYear(), 0, 1, 0, 0, 0, 0); - var yday = ((date.getTime() - start) / (1000 * 60 * 60 * 24)) | 0; - HEAP32[(tmPtr + 28) >> 2] = yday; - } - __gmtime_js.sig = 'vjp'; - - var isLeapYear = (year) => - year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); - - var MONTH_DAYS_LEAP_CUMULATIVE = [ - 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, - ]; - - var MONTH_DAYS_REGULAR_CUMULATIVE = [ - 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, - ]; - var ydayFromDate = (date) => { - var leap = isLeapYear(date.getFullYear()); - var monthDaysCumulative = leap - ? MONTH_DAYS_LEAP_CUMULATIVE - : MONTH_DAYS_REGULAR_CUMULATIVE; - var yday = monthDaysCumulative[date.getMonth()] + date.getDate() - 1; // -1 since it's days since Jan 1 - - return yday; - }; - - function __localtime_js(time, tmPtr) { - time = bigintToI53Checked(time); - - var date = new Date(time * 1000); - HEAP32[tmPtr >> 2] = date.getSeconds(); - HEAP32[(tmPtr + 4) >> 2] = date.getMinutes(); - HEAP32[(tmPtr + 8) >> 2] = date.getHours(); - HEAP32[(tmPtr + 12) >> 2] = date.getDate(); - HEAP32[(tmPtr + 16) >> 2] = date.getMonth(); - HEAP32[(tmPtr + 20) >> 2] = date.getFullYear() - 1900; - HEAP32[(tmPtr + 24) >> 2] = date.getDay(); - - var yday = ydayFromDate(date) | 0; - HEAP32[(tmPtr + 28) >> 2] = yday; - HEAP32[(tmPtr + 36) >> 2] = -(date.getTimezoneOffset() * 60); - - // Attention: DST is in December in South, and some regions don't have DST at all. - var start = new Date(date.getFullYear(), 0, 1); - var summerOffset = new Date( - date.getFullYear(), - 6, - 1 - ).getTimezoneOffset(); - var winterOffset = start.getTimezoneOffset(); - var dst = - (summerOffset != winterOffset && - date.getTimezoneOffset() == - Math.min(winterOffset, summerOffset)) | 0; - HEAP32[(tmPtr + 32) >> 2] = dst; - } - __localtime_js.sig = 'vjp'; - - var __mktime_js = function (tmPtr) { - var ret = (() => { - var date = new Date( - HEAP32[(tmPtr + 20) >> 2] + 1900, - HEAP32[(tmPtr + 16) >> 2], - HEAP32[(tmPtr + 12) >> 2], - HEAP32[(tmPtr + 8) >> 2], - HEAP32[(tmPtr + 4) >> 2], - HEAP32[tmPtr >> 2], - 0 - ); - - // There's an ambiguous hour when the time goes back; the tm_isdst field is - // used to disambiguate it. Date() basically guesses, so we fix it up if it - // guessed wrong, or fill in tm_isdst with the guess if it's -1. - var dst = HEAP32[(tmPtr + 32) >> 2]; - var guessedOffset = date.getTimezoneOffset(); - var start = new Date(date.getFullYear(), 0, 1); - var summerOffset = new Date( - date.getFullYear(), - 6, - 1 - ).getTimezoneOffset(); - var winterOffset = start.getTimezoneOffset(); - var dstOffset = Math.min(winterOffset, summerOffset); // DST is in December in South - if (dst < 0) { - // Attention: some regions don't have DST at all. - HEAP32[(tmPtr + 32) >> 2] = Number( - summerOffset != winterOffset && dstOffset == guessedOffset - ); - } else if (dst > 0 != (dstOffset == guessedOffset)) { - var nonDstOffset = Math.max(winterOffset, summerOffset); - var trueOffset = dst > 0 ? dstOffset : nonDstOffset; - // Don't try setMinutes(date.getMinutes() + ...) -- it's messed up. - date.setTime( - date.getTime() + (trueOffset - guessedOffset) * 60000 - ); - } - - HEAP32[(tmPtr + 24) >> 2] = date.getDay(); - var yday = ydayFromDate(date) | 0; - HEAP32[(tmPtr + 28) >> 2] = yday; - // To match expected behavior, update fields from date - HEAP32[tmPtr >> 2] = date.getSeconds(); - HEAP32[(tmPtr + 4) >> 2] = date.getMinutes(); - HEAP32[(tmPtr + 8) >> 2] = date.getHours(); - HEAP32[(tmPtr + 12) >> 2] = date.getDate(); - HEAP32[(tmPtr + 16) >> 2] = date.getMonth(); - HEAP32[(tmPtr + 20) >> 2] = date.getYear(); - - var timeMs = date.getTime(); - if (isNaN(timeMs)) { - return -1; - } - // Return time in microseconds - return timeMs / 1000; - })(); - return BigInt(ret); - }; - __mktime_js.sig = 'jp'; - - function __mmap_js(len, prot, flags, fd, offset, allocated, addr) { - offset = bigintToI53Checked(offset); - - try { - var stream = SYSCALLS.getStreamFromFD(fd); - var res = FS.mmap(stream, len, offset, prot, flags); - var ptr = res.ptr; - HEAP32[allocated >> 2] = res.allocated; - HEAPU32[addr >> 2] = ptr; - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - __mmap_js.sig = 'ipiiijpp'; - - function __msync_js(addr, len, prot, flags, fd, offset) { - offset = bigintToI53Checked(offset); - - try { - if (isNaN(offset)) return -61; - SYSCALLS.doMsync( - addr, - SYSCALLS.getStreamFromFD(fd), - len, - flags, - offset - ); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - __msync_js.sig = 'ippiiij'; - - function __munmap_js(addr, len, prot, flags, fd, offset) { - offset = bigintToI53Checked(offset); - - try { - var stream = SYSCALLS.getStreamFromFD(fd); - if (prot & 2) { - SYSCALLS.doMsync(addr, stream, len, flags, offset); - } - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } - } - __munmap_js.sig = 'ippiiij'; - - var timers = {}; - - var _emscripten_get_now = () => performance.now(); - _emscripten_get_now.sig = 'd'; - var __setitimer_js = (which, timeout_ms) => { - // First, clear any existing timer. - if (timers[which]) { - clearTimeout(timers[which].id); - delete timers[which]; - } - - // A timeout of zero simply cancels the current timeout so we have nothing - // more to do. - if (!timeout_ms) return 0; - - var id = setTimeout(() => { - delete timers[which]; - callUserCallback(() => - __emscripten_timeout(which, _emscripten_get_now()) - ); - }, timeout_ms); - timers[which] = { id, timeout_ms }; - return 0; - }; - __setitimer_js.sig = 'iid'; - - var __timegm_js = function (tmPtr) { - var ret = (() => { - var time = Date.UTC( - HEAP32[(tmPtr + 20) >> 2] + 1900, - HEAP32[(tmPtr + 16) >> 2], - HEAP32[(tmPtr + 12) >> 2], - HEAP32[(tmPtr + 8) >> 2], - HEAP32[(tmPtr + 4) >> 2], - HEAP32[tmPtr >> 2], - 0 - ); - var date = new Date(time); - - HEAP32[(tmPtr + 24) >> 2] = date.getUTCDay(); - var start = Date.UTC(date.getUTCFullYear(), 0, 1, 0, 0, 0, 0); - var yday = ((date.getTime() - start) / (1000 * 60 * 60 * 24)) | 0; - HEAP32[(tmPtr + 28) >> 2] = yday; - - return date.getTime() / 1000; - })(); - return BigInt(ret); - }; - __timegm_js.sig = 'jp'; - - var __tzset_js = (timezone, daylight, std_name, dst_name) => { - // TODO: Use (malleable) environment variables instead of system settings. - var currentYear = new Date().getFullYear(); - var winter = new Date(currentYear, 0, 1); - var summer = new Date(currentYear, 6, 1); - var winterOffset = winter.getTimezoneOffset(); - var summerOffset = summer.getTimezoneOffset(); - - // Local standard timezone offset. Local standard time is not adjusted for - // daylight savings. This code uses the fact that getTimezoneOffset returns - // a greater value during Standard Time versus Daylight Saving Time (DST). - // Thus it determines the expected output during Standard Time, and it - // compares whether the output of the given date the same (Standard) or less - // (DST). - var stdTimezoneOffset = Math.max(winterOffset, summerOffset); - - // timezone is specified as seconds west of UTC ("The external variable - // `timezone` shall be set to the difference, in seconds, between - // Coordinated Universal Time (UTC) and local standard time."), the same - // as returned by stdTimezoneOffset. - // See http://pubs.opengroup.org/onlinepubs/009695399/functions/tzset.html - HEAPU32[timezone >> 2] = stdTimezoneOffset * 60; - - HEAP32[daylight >> 2] = Number(winterOffset != summerOffset); - - var extractZone = (timezoneOffset) => { - // Why inverse sign? - // Read here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset - var sign = timezoneOffset >= 0 ? '-' : '+'; - - var absOffset = Math.abs(timezoneOffset); - var hours = String(Math.floor(absOffset / 60)).padStart(2, '0'); - var minutes = String(absOffset % 60).padStart(2, '0'); - - return `UTC${sign}${hours}${minutes}`; - }; - - var winterName = extractZone(winterOffset); - var summerName = extractZone(summerOffset); - if (summerOffset < winterOffset) { - // Northern hemisphere - stringToUTF8(winterName, std_name, 17); - stringToUTF8(summerName, dst_name, 17); - } else { - stringToUTF8(winterName, dst_name, 17); - stringToUTF8(summerName, std_name, 17); - } - }; - __tzset_js.sig = 'vpppp'; - - var _emscripten_set_main_loop_timing = (mode, value) => { - MainLoop.timingMode = mode; - MainLoop.timingValue = value; - - if (!MainLoop.func) { - return 1; // Return non-zero on failure, can't set timing mode when there is no main loop. - } - - if (!MainLoop.running) { - runtimeKeepalivePush(); - MainLoop.running = true; - } - if (mode == 0) { - MainLoop.scheduler = function MainLoop_scheduler_setTimeout() { - var timeUntilNextTick = - Math.max( - 0, - MainLoop.tickStartTime + value - _emscripten_get_now() - ) | 0; - setTimeout(MainLoop.runner, timeUntilNextTick); // doing this each time means that on exception, we stop - }; - MainLoop.method = 'timeout'; - } else if (mode == 1) { - MainLoop.scheduler = function MainLoop_scheduler_rAF() { - MainLoop.requestAnimationFrame(MainLoop.runner); - }; - MainLoop.method = 'rAF'; - } else if (mode == 2) { - if (!MainLoop.setImmediate) { - if (globalThis.setImmediate) { - MainLoop.setImmediate = setImmediate; - } else { - // Emulate setImmediate. (note: not a complete polyfill, we don't emulate clearImmediate() to keep code size to minimum, since not needed) - var setImmediates = []; - var emscriptenMainLoopMessageId = 'setimmediate'; - /** @param {Event} event */ - var MainLoop_setImmediate_messageHandler = (event) => { - // When called in current thread or Worker, the main loop ID is structured slightly different to accommodate for --proxy-to-worker runtime listening to Worker events, - // so check for both cases. - if ( - event.data === emscriptenMainLoopMessageId || - event.data.target === emscriptenMainLoopMessageId - ) { - event.stopPropagation(); - setImmediates.shift()(); - } - }; - addEventListener( - 'message', - MainLoop_setImmediate_messageHandler, - true - ); - MainLoop.setImmediate = - /** @type{function(function(): ?, ...?): number} */ ( - (func) => { - setImmediates.push(func); - if (ENVIRONMENT_IS_WORKER) { - Module['setImmediates'] ??= []; - Module['setImmediates'].push(func); - postMessage({ - target: emscriptenMainLoopMessageId, - }); // In --proxy-to-worker, route the message via proxyClient.js - } else - postMessage( - emscriptenMainLoopMessageId, - '*' - ); // On the main thread, can just send the message to itself. - } - ); - } - } - MainLoop.scheduler = function MainLoop_scheduler_setImmediate() { - MainLoop.setImmediate(MainLoop.runner); - }; - MainLoop.method = 'immediate'; - } - return 0; - }; - _emscripten_set_main_loop_timing.sig = 'iii'; - - /** - * @param {number=} arg - * @param {boolean=} noSetTiming - */ - var setMainLoop = ( - iterFunc, - fps, - simulateInfiniteLoop, - arg, - noSetTiming - ) => { - MainLoop.func = iterFunc; - MainLoop.arg = arg; - - var thisMainLoopId = MainLoop.currentlyRunningMainloop; - function checkIsRunning() { - if (thisMainLoopId < MainLoop.currentlyRunningMainloop) { - runtimeKeepalivePop(); - maybeExit(); - return false; - } - return true; - } - - // We create the loop runner here but it is not actually running until - // _emscripten_set_main_loop_timing is called (which might happen a - // later time). This member signifies that the current runner has not - // yet been started so that we can call runtimeKeepalivePush when it - // gets it timing set for the first time. - MainLoop.running = false; - MainLoop.runner = function MainLoop_runner() { - if (ABORT) return; - if (MainLoop.queue.length > 0) { - var start = Date.now(); - var blocker = MainLoop.queue.shift(); - blocker.func(blocker.arg); - if (MainLoop.remainingBlockers) { - var remaining = MainLoop.remainingBlockers; - var next = - remaining % 1 == 0 - ? remaining - 1 - : Math.floor(remaining); - if (blocker.counted) { - MainLoop.remainingBlockers = next; - } else { - // not counted, but move the progress along a tiny bit - next = next + 0.5; // do not steal all the next one's progress - MainLoop.remainingBlockers = (8 * remaining + next) / 9; - } - } - MainLoop.updateStatus(); - - // catches pause/resume main loop from blocker execution - if (!checkIsRunning()) return; - - setTimeout(MainLoop.runner, 0); - return; - } - - // catch pauses from non-main loop sources - if (!checkIsRunning()) return; - - // Implement very basic swap interval control - MainLoop.currentFrameNumber = (MainLoop.currentFrameNumber + 1) | 0; - if ( - MainLoop.timingMode == 1 && - MainLoop.timingValue > 1 && - MainLoop.currentFrameNumber % MainLoop.timingValue != 0 - ) { - // Not the scheduled time to render this frame - skip. - MainLoop.scheduler(); - return; - } else if (MainLoop.timingMode == 0) { - MainLoop.tickStartTime = _emscripten_get_now(); - } - - MainLoop.runIter(iterFunc); - - // catch pauses from the main loop itself - if (!checkIsRunning()) return; - - MainLoop.scheduler(); - }; - - if (!noSetTiming) { - if (fps > 0) { - _emscripten_set_main_loop_timing(0, 1000.0 / fps); - } else { - // Do rAF by rendering each frame (no decimating) - _emscripten_set_main_loop_timing(1, 1); - } - - MainLoop.scheduler(); - } - - if (simulateInfiniteLoop) { - throw 'unwind'; - } - }; - - var MainLoop = { - running: false, - scheduler: null, - method: '', - currentlyRunningMainloop: 0, - func: null, - arg: 0, - timingMode: 0, - timingValue: 0, - currentFrameNumber: 0, - queue: [], - preMainLoop: [], - postMainLoop: [], - pause() { - MainLoop.scheduler = null; - // Incrementing this signals the previous main loop that it's now become old, and it must return. - MainLoop.currentlyRunningMainloop++; - }, - resume() { - MainLoop.currentlyRunningMainloop++; - var timingMode = MainLoop.timingMode; - var timingValue = MainLoop.timingValue; - var func = MainLoop.func; - MainLoop.func = null; - // do not set timing and call scheduler, we will do it on the next lines - setMainLoop(func, 0, false, MainLoop.arg, true); - _emscripten_set_main_loop_timing(timingMode, timingValue); - MainLoop.scheduler(); - }, - updateStatus() { - if (Module['setStatus']) { - var message = Module['statusMessage'] || 'Please wait...'; - var remaining = MainLoop.remainingBlockers ?? 0; - var expected = MainLoop.expectedBlockers ?? 0; - if (remaining) { - if (remaining < expected) { - Module['setStatus']( - `{message} ({expected - remaining}/{expected})` - ); - } else { - Module['setStatus'](message); - } - } else { - Module['setStatus'](''); - } - } - }, - init() { - Module['preMainLoop'] && - MainLoop.preMainLoop.push(Module['preMainLoop']); - Module['postMainLoop'] && - MainLoop.postMainLoop.push(Module['postMainLoop']); - }, - runIter(func) { - if (ABORT) return; - for (var pre of MainLoop.preMainLoop) { - if (pre() === false) { - return; // |return false| skips a frame - } - } - callUserCallback(func); - for (var post of MainLoop.postMainLoop) { - post(); - } - }, - nextRAF: 0, - fakeRequestAnimationFrame(func) { - // try to keep 60fps between calls to here - var now = Date.now(); - if (MainLoop.nextRAF === 0) { - MainLoop.nextRAF = now + 1000 / 60; - } else { - while (now + 2 >= MainLoop.nextRAF) { - // fudge a little, to avoid timer jitter causing us to do lots of delay:0 - MainLoop.nextRAF += 1000 / 60; - } - } - var delay = Math.max(MainLoop.nextRAF - now, 0); - setTimeout(func, delay); - }, - requestAnimationFrame(func) { - if (globalThis.requestAnimationFrame) { - requestAnimationFrame(func); - } else { - MainLoop.fakeRequestAnimationFrame(func); - } - }, - }; - - var AL = { - QUEUE_INTERVAL: 25, - QUEUE_LOOKAHEAD: 0.1, - DEVICE_NAME: 'Emscripten OpenAL', - CAPTURE_DEVICE_NAME: 'Emscripten OpenAL capture', - ALC_EXTENSIONS: { - ALC_SOFT_pause_device: true, - ALC_SOFT_HRTF: true, - }, - AL_EXTENSIONS: { - AL_EXT_float32: true, - AL_SOFT_loop_points: true, - AL_SOFT_source_length: true, - AL_EXT_source_distance_model: true, - AL_SOFT_source_spatialize: true, - }, - _alcErr: 0, - alcErr: 0, - deviceRefCounts: {}, - alcStringCache: {}, - paused: false, - stringCache: {}, - contexts: {}, - currentCtx: null, - buffers: { - 0: { - id: 0, - refCount: 0, - audioBuf: null, - frequency: 0, - bytesPerSample: 2, - channels: 1, - length: 0, - }, - }, - paramArray: [], - _nextId: 1, - newId: () => (AL.freeIds.length > 0 ? AL.freeIds.pop() : AL._nextId++), - freeIds: [], - scheduleContextAudio: (ctx) => { - // If we are animating using the requestAnimationFrame method, then the main loop does not run when in the background. - // To give a perfect glitch-free audio stop when switching from foreground to background, we need to avoid updating - // audio altogether when in the background, so detect that case and kill audio buffer streaming if so. - if ( - MainLoop.timingMode === 1 && - document['visibilityState'] != 'visible' - ) { - return; - } - - for (var i in ctx.sources) { - AL.scheduleSourceAudio(ctx.sources[i]); - } - }, - scheduleSourceAudio: (src, lookahead) => { - // See comment on scheduleContextAudio above. - if ( - MainLoop.timingMode === 1 && - document['visibilityState'] != 'visible' - ) { - return; - } - if (src.state !== 4114) { - return; - } - - var currentTime = AL.updateSourceTime(src); - - var startTime = src.bufStartTime; - var startOffset = src.bufOffset; - var bufCursor = src.bufsProcessed; - - // Advance past any audio that is already scheduled - for (var i = 0; i < src.audioQueue.length; i++) { - var audioSrc = src.audioQueue[i]; - startTime = audioSrc._startTime + audioSrc._duration; - startOffset = 0.0; - bufCursor += audioSrc._skipCount + 1; - } - - if (!lookahead) { - lookahead = AL.QUEUE_LOOKAHEAD; - } - var lookaheadTime = currentTime + lookahead; - var skipCount = 0; - while (startTime < lookaheadTime) { - if (bufCursor >= src.bufQueue.length) { - if (src.looping) { - bufCursor %= src.bufQueue.length; - } else { - break; - } - } - - var buf = src.bufQueue[bufCursor % src.bufQueue.length]; - // If the buffer contains no data, skip it - if (buf.length === 0) { - skipCount++; - // If we've gone through the whole queue and everything is 0 length, just give up - if (skipCount === src.bufQueue.length) { - break; - } - } else { - var audioSrc = src.context.audioCtx.createBufferSource(); - audioSrc.buffer = buf.audioBuf; - audioSrc.playbackRate.value = src.playbackRate; - if (buf.audioBuf._loopStart || buf.audioBuf._loopEnd) { - audioSrc.loopStart = buf.audioBuf._loopStart; - audioSrc.loopEnd = buf.audioBuf._loopEnd; - } - - var duration = 0.0; - // If the source is a looping static buffer, use native looping for gapless playback - if (src.type === 4136 && src.looping) { - duration = Number.POSITIVE_INFINITY; - audioSrc.loop = true; - if (buf.audioBuf._loopStart) { - audioSrc.loopStart = buf.audioBuf._loopStart; - } - if (buf.audioBuf._loopEnd) { - audioSrc.loopEnd = buf.audioBuf._loopEnd; - } - } else { - duration = - (buf.audioBuf.duration - startOffset) / - src.playbackRate; - } - - audioSrc._startOffset = startOffset; - audioSrc._duration = duration; - audioSrc._skipCount = skipCount; - skipCount = 0; - - audioSrc.connect(src.gain); - - if (typeof audioSrc.start != 'undefined') { - // Sample the current time as late as possible to mitigate drift - startTime = Math.max( - startTime, - src.context.audioCtx.currentTime - ); - audioSrc.start(startTime, startOffset); - } else if (typeof audioSrc.noteOn != 'undefined') { - startTime = Math.max( - startTime, - src.context.audioCtx.currentTime - ); - audioSrc.noteOn(startTime); - } - audioSrc._startTime = startTime; - src.audioQueue.push(audioSrc); - - startTime += duration; - } - - startOffset = 0.0; - bufCursor++; - } - }, - updateSourceTime: (src) => { - var currentTime = src.context.audioCtx.currentTime; - if (src.state !== 4114) { - return currentTime; - } - - // if the start time is unset, determine it based on the current offset. - // This will be the case when a source is resumed after being paused, and - // allows us to pretend that the source actually started playing some time - // in the past such that it would just now have reached the stored offset. - if (!isFinite(src.bufStartTime)) { - src.bufStartTime = - currentTime - src.bufOffset / src.playbackRate; - src.bufOffset = 0.0; - } - - var nextStartTime = 0.0; - while (src.audioQueue.length) { - var audioSrc = src.audioQueue[0]; - src.bufsProcessed += audioSrc._skipCount; - nextStartTime = audioSrc._startTime + audioSrc._duration; // n.b. audioSrc._duration already factors in playbackRate, so no divide by src.playbackRate on it. - - if (currentTime < nextStartTime) { - break; - } - - src.audioQueue.shift(); - src.bufStartTime = nextStartTime; - src.bufOffset = 0.0; - src.bufsProcessed++; - } - - if (src.bufsProcessed >= src.bufQueue.length && !src.looping) { - // The source has played its entire queue and is non-looping, so just mark it as stopped. - AL.setSourceState(src, 4116); - } else if (src.type === 4136 && src.looping) { - // If the source is a looping static buffer, determine the buffer offset based on the loop points - var buf = src.bufQueue[0]; - if (buf.length === 0) { - src.bufOffset = 0.0; - } else { - var delta = - (currentTime - src.bufStartTime) * src.playbackRate; - var loopStart = buf.audioBuf._loopStart || 0.0; - var loopEnd = - buf.audioBuf._loopEnd || buf.audioBuf.duration; - if (loopEnd <= loopStart) { - loopEnd = buf.audioBuf.duration; - } - - if (delta < loopEnd) { - src.bufOffset = delta; - } else { - src.bufOffset = - loopStart + - ((delta - loopStart) % (loopEnd - loopStart)); - } - } - } else if (src.audioQueue[0]) { - // The source is still actively playing, so we just need to calculate where we are in the current buffer - // so it can be remembered if the source gets paused. - src.bufOffset = - (currentTime - src.audioQueue[0]._startTime) * - src.playbackRate; - } else { - // The source hasn't finished yet, but there is no scheduled audio left for it. This can be because - // the source has just been started/resumed, or due to an underrun caused by a long blocking operation. - // We need to determine what state we would be in by this point in time so that when we next schedule - // audio playback, it will be just as if no underrun occurred. - - if (src.type !== 4136 && src.looping) { - // if the source is a looping buffer queue, let's first calculate the queue duration, so we can - // quickly fast forward past any full loops of the queue and only worry about the remainder. - var srcDuration = AL.sourceDuration(src) / src.playbackRate; - if (srcDuration > 0.0) { - src.bufStartTime += - Math.floor( - (currentTime - src.bufStartTime) / srcDuration - ) * srcDuration; - } - } - - // Since we've already skipped any full-queue loops if there were any, we just need to find - // out where in the queue the remaining time puts us, which won't require stepping through the - // entire queue more than once. - for (var i = 0; i < src.bufQueue.length; i++) { - if (src.bufsProcessed >= src.bufQueue.length) { - if (src.looping) { - src.bufsProcessed %= src.bufQueue.length; - } else { - AL.setSourceState(src, 4116); - break; - } - } - - var buf = src.bufQueue[src.bufsProcessed]; - if (buf.length > 0) { - nextStartTime = - src.bufStartTime + - buf.audioBuf.duration / src.playbackRate; - - if (currentTime < nextStartTime) { - src.bufOffset = - (currentTime - src.bufStartTime) * - src.playbackRate; - break; - } - - src.bufStartTime = nextStartTime; - } - - src.bufOffset = 0.0; - src.bufsProcessed++; - } - } - - return currentTime; - }, - cancelPendingSourceAudio: (src) => { - AL.updateSourceTime(src); - - for (var i = 1; i < src.audioQueue.length; i++) { - var audioSrc = src.audioQueue[i]; - audioSrc.stop(); - } - - if (src.audioQueue.length > 1) { - src.audioQueue.length = 1; - } - }, - stopSourceAudio: (src) => { - for (var i = 0; i < src.audioQueue.length; i++) { - src.audioQueue[i].stop(); - } - src.audioQueue.length = 0; - }, - setSourceState: (src, state) => { - if (state === 4114) { - if (src.state === 4114 || src.state == 4116) { - src.bufsProcessed = 0; - src.bufOffset = 0.0; - } else { - } - - AL.stopSourceAudio(src); - - src.state = 4114; - src.bufStartTime = Number.NEGATIVE_INFINITY; - AL.scheduleSourceAudio(src); - } else if (state === 4115) { - if (src.state === 4114) { - // Store off the current offset to restore with on resume. - AL.updateSourceTime(src); - AL.stopSourceAudio(src); - - src.state = 4115; - } - } else if (state === 4116) { - if (src.state !== 4113) { - src.state = 4116; - src.bufsProcessed = src.bufQueue.length; - src.bufStartTime = Number.NEGATIVE_INFINITY; - src.bufOffset = 0.0; - AL.stopSourceAudio(src); - } - } else if (state === 4113) { - if (src.state !== 4113) { - src.state = 4113; - src.bufsProcessed = 0; - src.bufStartTime = Number.NEGATIVE_INFINITY; - src.bufOffset = 0.0; - AL.stopSourceAudio(src); - } - } - }, - initSourcePanner: (src) => { - if (src.type === 0x1030 /* AL_UNDETERMINED */) { - return; - } - - // Find the first non-zero buffer in the queue to determine the proper format - var templateBuf = AL.buffers[0]; - for (var i = 0; i < src.bufQueue.length; i++) { - if (src.bufQueue[i].id !== 0) { - templateBuf = src.bufQueue[i]; - break; - } - } - // Create a panner if AL_SOURCE_SPATIALIZE_SOFT is set to true, or alternatively if it's set to auto and the source is mono - if ( - src.spatialize === 1 || - (src.spatialize === 2 /* AL_AUTO_SOFT */ && - templateBuf.channels === 1) - ) { - if (src.panner) { - return; - } - src.panner = src.context.audioCtx.createPanner(); - - AL.updateSourceGlobal(src); - AL.updateSourceSpace(src); - - src.panner.connect(src.context.gain); - src.gain.disconnect(); - src.gain.connect(src.panner); - } else { - if (!src.panner) { - return; - } - - src.panner.disconnect(); - src.gain.disconnect(); - src.gain.connect(src.context.gain); - src.panner = null; - } - }, - updateContextGlobal: (ctx) => { - for (var i in ctx.sources) { - AL.updateSourceGlobal(ctx.sources[i]); - } - }, - updateSourceGlobal: (src) => { - var panner = src.panner; - if (!panner) { - return; - } - - panner.refDistance = src.refDistance; - panner.maxDistance = src.maxDistance; - panner.rolloffFactor = src.rolloffFactor; - - panner.panningModel = src.context.hrtf ? 'HRTF' : 'equalpower'; - - // Use the source's distance model if AL_SOURCE_DISTANCE_MODEL is enabled - var distanceModel = src.context.sourceDistanceModel - ? src.distanceModel - : src.context.distanceModel; - switch (distanceModel) { - case 0: - panner.distanceModel = 'inverse'; - panner.refDistance = 3.40282e38 /* FLT_MAX */; - break; - case 0xd001 /* AL_INVERSE_DISTANCE */: - case 0xd002 /* AL_INVERSE_DISTANCE_CLAMPED */: - panner.distanceModel = 'inverse'; - break; - case 0xd003 /* AL_LINEAR_DISTANCE */: - case 0xd004 /* AL_LINEAR_DISTANCE_CLAMPED */: - panner.distanceModel = 'linear'; - break; - case 0xd005 /* AL_EXPONENT_DISTANCE */: - case 0xd006 /* AL_EXPONENT_DISTANCE_CLAMPED */: - panner.distanceModel = 'exponential'; - break; - } - }, - updateListenerSpace: (ctx) => { - var listener = ctx.audioCtx.listener; - if (listener.positionX) { - listener.positionX.value = ctx.listener.position[0]; - listener.positionY.value = ctx.listener.position[1]; - listener.positionZ.value = ctx.listener.position[2]; - } else { - listener.setPosition( - ctx.listener.position[0], - ctx.listener.position[1], - ctx.listener.position[2] - ); - } - if (listener.forwardX) { - listener.forwardX.value = ctx.listener.direction[0]; - listener.forwardY.value = ctx.listener.direction[1]; - listener.forwardZ.value = ctx.listener.direction[2]; - listener.upX.value = ctx.listener.up[0]; - listener.upY.value = ctx.listener.up[1]; - listener.upZ.value = ctx.listener.up[2]; - } else { - listener.setOrientation( - ctx.listener.direction[0], - ctx.listener.direction[1], - ctx.listener.direction[2], - ctx.listener.up[0], - ctx.listener.up[1], - ctx.listener.up[2] - ); - } - - // Update sources that are relative to the listener - for (var i in ctx.sources) { - AL.updateSourceSpace(ctx.sources[i]); - } - }, - updateSourceSpace: (src) => { - if (!src.panner) { - return; - } - var panner = src.panner; - - var posX = src.position[0]; - var posY = src.position[1]; - var posZ = src.position[2]; - var dirX = src.direction[0]; - var dirY = src.direction[1]; - var dirZ = src.direction[2]; - - var listener = src.context.listener; - var lPosX = listener.position[0]; - var lPosY = listener.position[1]; - var lPosZ = listener.position[2]; - - // WebAudio does spatialization in world-space coordinates, meaning both the buffer sources and - // the listener position are in the same absolute coordinate system relative to a fixed origin. - // By default, OpenAL works this way as well, but it also provides a "listener relative" mode, where - // a buffer source's coordinate are interpreted not in absolute world space, but as being relative - // to the listener object itself, so as the listener moves the source appears to move with it - // with no update required. Since web audio does not support this mode, we must transform the source - // coordinates from listener-relative space to absolute world space. - // - // We do this via affine transformation matrices applied to the source position and source direction. - // A change-of-basis converts from listener-space displacements to world-space displacements, - // which must be done for both the source position and direction. Lastly, the source position must be - // added to the listener position to get the final source position, since the source position represents - // a displacement from the listener. - if (src.relative) { - // Negate the listener direction since forward is -Z. - var lBackX = -listener.direction[0]; - var lBackY = -listener.direction[1]; - var lBackZ = -listener.direction[2]; - var lUpX = listener.up[0]; - var lUpY = listener.up[1]; - var lUpZ = listener.up[2]; - - var inverseMagnitude = (x, y, z) => { - var length = Math.sqrt(x * x + y * y + z * z); - - if (length < Number.EPSILON) { - return 0.0; - } - - return 1.0 / length; - }; - - // Normalize the Back vector - var invMag = inverseMagnitude(lBackX, lBackY, lBackZ); - lBackX *= invMag; - lBackY *= invMag; - lBackZ *= invMag; - - // ...and the Up vector - invMag = inverseMagnitude(lUpX, lUpY, lUpZ); - lUpX *= invMag; - lUpY *= invMag; - lUpZ *= invMag; - - // Calculate the Right vector as the cross product of the Up and Back vectors - var lRightX = lUpY * lBackZ - lUpZ * lBackY; - var lRightY = lUpZ * lBackX - lUpX * lBackZ; - var lRightZ = lUpX * lBackY - lUpY * lBackX; - - // Back and Up might not be exactly perpendicular, so the cross product also needs normalization - invMag = inverseMagnitude(lRightX, lRightY, lRightZ); - lRightX *= invMag; - lRightY *= invMag; - lRightZ *= invMag; - - // Recompute Up from the now orthonormal Right and Back vectors so we have a fully orthonormal basis - lUpX = lBackY * lRightZ - lBackZ * lRightY; - lUpY = lBackZ * lRightX - lBackX * lRightZ; - lUpZ = lBackX * lRightY - lBackY * lRightX; - - var oldX = dirX; - var oldY = dirY; - var oldZ = dirZ; - - // Use our 3 vectors to apply a change-of-basis matrix to the source direction - dirX = oldX * lRightX + oldY * lUpX + oldZ * lBackX; - dirY = oldX * lRightY + oldY * lUpY + oldZ * lBackY; - dirZ = oldX * lRightZ + oldY * lUpZ + oldZ * lBackZ; - - oldX = posX; - oldY = posY; - oldZ = posZ; - - // ...and to the source position - posX = oldX * lRightX + oldY * lUpX + oldZ * lBackX; - posY = oldX * lRightY + oldY * lUpY + oldZ * lBackY; - posZ = oldX * lRightZ + oldY * lUpZ + oldZ * lBackZ; - - // The change-of-basis corrects the orientation, but the origin is still the listener. - // Translate the source position by the listener position to finish. - posX += lPosX; - posY += lPosY; - posZ += lPosZ; - } - - if (panner.positionX) { - // Assigning to panner.positionX/Y/Z unnecessarily seems to cause performance issues - // See https://github.com/emscripten-core/emscripten/issues/15847 - - if (posX != panner.positionX.value) - panner.positionX.value = posX; - if (posY != panner.positionY.value) - panner.positionY.value = posY; - if (posZ != panner.positionZ.value) - panner.positionZ.value = posZ; - } else { - panner.setPosition(posX, posY, posZ); - } - if (panner.orientationX) { - // Assigning to panner.orientation/Y/Z unnecessarily seems to cause performance issues - // See https://github.com/emscripten-core/emscripten/issues/15847 - - if (dirX != panner.orientationX.value) - panner.orientationX.value = dirX; - if (dirY != panner.orientationY.value) - panner.orientationY.value = dirY; - if (dirZ != panner.orientationZ.value) - panner.orientationZ.value = dirZ; - } else { - panner.setOrientation(dirX, dirY, dirZ); - } - - var oldShift = src.dopplerShift; - var velX = src.velocity[0]; - var velY = src.velocity[1]; - var velZ = src.velocity[2]; - var lVelX = listener.velocity[0]; - var lVelY = listener.velocity[1]; - var lVelZ = listener.velocity[2]; - if ( - (posX === lPosX && posY === lPosY && posZ === lPosZ) || - (velX === lVelX && velY === lVelY && velZ === lVelZ) - ) { - src.dopplerShift = 1.0; - } else { - // Doppler algorithm from 1.1 spec - var speedOfSound = src.context.speedOfSound; - var dopplerFactor = src.context.dopplerFactor; - - var slX = lPosX - posX; - var slY = lPosY - posY; - var slZ = lPosZ - posZ; - - var magSl = Math.sqrt(slX * slX + slY * slY + slZ * slZ); - var vls = (slX * lVelX + slY * lVelY + slZ * lVelZ) / magSl; - var vss = (slX * velX + slY * velY + slZ * velZ) / magSl; - - vls = Math.min(vls, speedOfSound / dopplerFactor); - vss = Math.min(vss, speedOfSound / dopplerFactor); - - src.dopplerShift = - (speedOfSound - dopplerFactor * vls) / - (speedOfSound - dopplerFactor * vss); - } - if (src.dopplerShift !== oldShift) { - AL.updateSourceRate(src); - } - }, - updateSourceRate: (src) => { - if (src.state === 4114) { - // clear scheduled buffers - AL.cancelPendingSourceAudio(src); - - var audioSrc = src.audioQueue[0]; - if (!audioSrc) { - return; // It is possible that AL.scheduleContextAudio() has not yet fed the next buffer, if so, skip. - } - - var duration; - if (src.type === 4136 && src.looping) { - duration = Number.POSITIVE_INFINITY; - } else { - // audioSrc._duration is expressed after factoring in playbackRate, so when changing playback rate, need - // to recompute/rescale the rate to the new playback speed. - duration = - (audioSrc.buffer.duration - audioSrc._startOffset) / - src.playbackRate; - } - - audioSrc._duration = duration; - audioSrc.playbackRate.value = src.playbackRate; - - // reschedule buffers with the new playbackRate - AL.scheduleSourceAudio(src); - } - }, - sourceDuration: (src) => { - var length = 0.0; - for (var i = 0; i < src.bufQueue.length; i++) { - var audioBuf = src.bufQueue[i].audioBuf; - length += audioBuf ? audioBuf.duration : 0.0; - } - return length; - }, - sourceTell: (src) => { - AL.updateSourceTime(src); - - var offset = 0.0; - for (var i = 0; i < src.bufsProcessed; i++) { - if (src.bufQueue[i].audioBuf) { - offset += src.bufQueue[i].audioBuf.duration; - } - } - offset += src.bufOffset; - - return offset; - }, - sourceSeek: (src, offset) => { - var playing = src.state == 4114; - if (playing) { - AL.setSourceState(src, 4113); - } - - if (src.bufQueue[src.bufsProcessed].audioBuf !== null) { - src.bufsProcessed = 0; - while ( - offset > src.bufQueue[src.bufsProcessed].audioBuf.duration - ) { - offset -= src.bufQueue[src.bufsProcessed].audioBuf.duration; - src.bufsProcessed++; - } - - src.bufOffset = offset; - } - - if (playing) { - AL.setSourceState(src, 4114); - } - }, - getGlobalParam: (funcname, param) => { - if (!AL.currentCtx) { - return null; - } - - switch (param) { - case 49152: - return AL.currentCtx.dopplerFactor; - case 49155: - return AL.currentCtx.speedOfSound; - case 53248: - return AL.currentCtx.distanceModel; - default: - AL.currentCtx.err = 40962; - return null; - } - }, - setGlobalParam: (funcname, param, value) => { - if (!AL.currentCtx) { - return; - } - - switch (param) { - case 49152: - if (!Number.isFinite(value) || value < 0.0) { - // Strictly negative values are disallowed - AL.currentCtx.err = 40963; - return; - } - - AL.currentCtx.dopplerFactor = value; - AL.updateListenerSpace(AL.currentCtx); - break; - case 49155: - if (!Number.isFinite(value) || value <= 0.0) { - // Negative or zero values are disallowed - AL.currentCtx.err = 40963; - return; - } - - AL.currentCtx.speedOfSound = value; - AL.updateListenerSpace(AL.currentCtx); - break; - case 53248: - switch (value) { - case 0: - case 0xd001 /* AL_INVERSE_DISTANCE */: - case 0xd002 /* AL_INVERSE_DISTANCE_CLAMPED */: - case 0xd003 /* AL_LINEAR_DISTANCE */: - case 0xd004 /* AL_LINEAR_DISTANCE_CLAMPED */: - case 0xd005 /* AL_EXPONENT_DISTANCE */: - case 0xd006 /* AL_EXPONENT_DISTANCE_CLAMPED */: - AL.currentCtx.distanceModel = value; - AL.updateContextGlobal(AL.currentCtx); - break; - default: - AL.currentCtx.err = 40963; - return; - } - break; - default: - AL.currentCtx.err = 40962; - return; - } - }, - getListenerParam: (funcname, param) => { - if (!AL.currentCtx) { - return null; - } - - switch (param) { - case 4100: - return AL.currentCtx.listener.position; - case 4102: - return AL.currentCtx.listener.velocity; - case 4111: - return AL.currentCtx.listener.direction.concat( - AL.currentCtx.listener.up - ); - case 4106: - return AL.currentCtx.gain.gain.value; - default: - AL.currentCtx.err = 40962; - return null; - } - }, - setListenerParam: (funcname, param, value) => { - if (!AL.currentCtx) { - return; - } - if (value === null) { - AL.currentCtx.err = 40962; - return; - } - - var listener = AL.currentCtx.listener; - switch (param) { - case 4100: - if ( - !Number.isFinite(value[0]) || - !Number.isFinite(value[1]) || - !Number.isFinite(value[2]) - ) { - AL.currentCtx.err = 40963; - return; - } - - listener.position[0] = value[0]; - listener.position[1] = value[1]; - listener.position[2] = value[2]; - AL.updateListenerSpace(AL.currentCtx); - break; - case 4102: - if ( - !Number.isFinite(value[0]) || - !Number.isFinite(value[1]) || - !Number.isFinite(value[2]) - ) { - AL.currentCtx.err = 40963; - return; - } - - listener.velocity[0] = value[0]; - listener.velocity[1] = value[1]; - listener.velocity[2] = value[2]; - AL.updateListenerSpace(AL.currentCtx); - break; - case 4106: - if (!Number.isFinite(value) || value < 0.0) { - AL.currentCtx.err = 40963; - return; - } - - AL.currentCtx.gain.gain.value = value; - break; - case 4111: - if ( - !Number.isFinite(value[0]) || - !Number.isFinite(value[1]) || - !Number.isFinite(value[2]) || - !Number.isFinite(value[3]) || - !Number.isFinite(value[4]) || - !Number.isFinite(value[5]) - ) { - AL.currentCtx.err = 40963; - return; - } - - listener.direction[0] = value[0]; - listener.direction[1] = value[1]; - listener.direction[2] = value[2]; - listener.up[0] = value[3]; - listener.up[1] = value[4]; - listener.up[2] = value[5]; - AL.updateListenerSpace(AL.currentCtx); - break; - default: - AL.currentCtx.err = 40962; - return; - } - }, - getBufferParam: (funcname, bufferId, param) => { - if (!AL.currentCtx) { - return; - } - var buf = AL.buffers[bufferId]; - if (!buf || bufferId === 0) { - AL.currentCtx.err = 40961; - return; - } - - switch (param) { - case 0x2001 /* AL_FREQUENCY */: - return buf.frequency; - case 0x2002 /* AL_BITS */: - return buf.bytesPerSample * 8; - case 0x2003 /* AL_CHANNELS */: - return buf.channels; - case 0x2004 /* AL_SIZE */: - return buf.length * buf.bytesPerSample * buf.channels; - case 0x2015 /* AL_LOOP_POINTS_SOFT */: - if (buf.length === 0) { - return [0, 0]; - } - return [ - (buf.audioBuf._loopStart || 0.0) * buf.frequency, - (buf.audioBuf._loopEnd || buf.length) * buf.frequency, - ]; - default: - AL.currentCtx.err = 40962; - return null; - } - }, - setBufferParam: (funcname, bufferId, param, value) => { - if (!AL.currentCtx) { - return; - } - var buf = AL.buffers[bufferId]; - if (!buf || bufferId === 0) { - AL.currentCtx.err = 40961; - return; - } - if (value === null) { - AL.currentCtx.err = 40962; - return; - } - - switch (param) { - case 0x2004 /* AL_SIZE */: - if (value !== 0) { - AL.currentCtx.err = 40963; - return; - } - - // Per the spec, setting AL_SIZE to 0 is a legal NOP. - break; - case 0x2015 /* AL_LOOP_POINTS_SOFT */: - if ( - value[0] < 0 || - value[0] > buf.length || - value[1] < 0 || - value[1] > buf.Length || - value[0] >= value[1] - ) { - AL.currentCtx.err = 40963; - return; - } - if (buf.refCount > 0) { - AL.currentCtx.err = 40964; - return; - } - - if (buf.audioBuf) { - buf.audioBuf._loopStart = value[0] / buf.frequency; - buf.audioBuf._loopEnd = value[1] / buf.frequency; - } - break; - default: - AL.currentCtx.err = 40962; - return; - } - }, - getSourceParam: (funcname, sourceId, param) => { - if (!AL.currentCtx) { - return null; - } - var src = AL.currentCtx.sources[sourceId]; - if (!src) { - AL.currentCtx.err = 40961; - return null; - } - - switch (param) { - case 0x202 /* AL_SOURCE_RELATIVE */: - return src.relative; - case 0x1001 /* AL_CONE_INNER_ANGLE */: - return src.coneInnerAngle; - case 0x1002 /* AL_CONE_OUTER_ANGLE */: - return src.coneOuterAngle; - case 0x1003 /* AL_PITCH */: - return src.pitch; - case 4100: - return src.position; - case 4101: - return src.direction; - case 4102: - return src.velocity; - case 0x1007 /* AL_LOOPING */: - return src.looping; - case 0x1009 /* AL_BUFFER */: - if (src.type === 4136) { - return src.bufQueue[0].id; - } - return 0; - case 4106: - return src.gain.gain.value; - case 0x100d /* AL_MIN_GAIN */: - return src.minGain; - case 0x100e /* AL_MAX_GAIN */: - return src.maxGain; - case 0x1010 /* AL_SOURCE_STATE */: - return src.state; - case 0x1015 /* AL_BUFFERS_QUEUED */: - if (src.bufQueue.length === 1 && src.bufQueue[0].id === 0) { - return 0; - } - return src.bufQueue.length; - case 0x1016 /* AL_BUFFERS_PROCESSED */: - if ( - (src.bufQueue.length === 1 && - src.bufQueue[0].id === 0) || - src.looping - ) { - return 0; - } - return src.bufsProcessed; - case 0x1020 /* AL_REFERENCE_DISTANCE */: - return src.refDistance; - case 0x1021 /* AL_ROLLOFF_FACTOR */: - return src.rolloffFactor; - case 0x1022 /* AL_CONE_OUTER_GAIN */: - return src.coneOuterGain; - case 0x1023 /* AL_MAX_DISTANCE */: - return src.maxDistance; - case 0x1024 /* AL_SEC_OFFSET */: - return AL.sourceTell(src); - case 0x1025 /* AL_SAMPLE_OFFSET */: - var offset = AL.sourceTell(src); - if (offset > 0.0) { - offset *= src.bufQueue[0].frequency; - } - return offset; - case 0x1026 /* AL_BYTE_OFFSET */: - var offset = AL.sourceTell(src); - if (offset > 0.0) { - offset *= - src.bufQueue[0].frequency * - src.bufQueue[0].bytesPerSample; - } - return offset; - case 0x1027 /* AL_SOURCE_TYPE */: - return src.type; - case 0x1214 /* AL_SOURCE_SPATIALIZE_SOFT */: - return src.spatialize; - case 0x2009 /* AL_BYTE_LENGTH_SOFT */: - var length = 0; - var bytesPerFrame = 0; - for (var i = 0; i < src.bufQueue.length; i++) { - length += src.bufQueue[i].length; - if (src.bufQueue[i].id !== 0) { - bytesPerFrame = - src.bufQueue[i].bytesPerSample * - src.bufQueue[i].channels; - } - } - return length * bytesPerFrame; - case 0x200a /* AL_SAMPLE_LENGTH_SOFT */: - var length = 0; - for (var i = 0; i < src.bufQueue.length; i++) { - length += src.bufQueue[i].length; - } - return length; - case 0x200b /* AL_SEC_LENGTH_SOFT */: - return AL.sourceDuration(src); - case 53248: - return src.distanceModel; - default: - AL.currentCtx.err = 40962; - return null; - } - }, - setSourceParam: (funcname, sourceId, param, value) => { - if (!AL.currentCtx) { - return; - } - var src = AL.currentCtx.sources[sourceId]; - if (!src) { - AL.currentCtx.err = 40961; - return; - } - if (value === null) { - AL.currentCtx.err = 40962; - return; - } - - switch (param) { - case 0x202 /* AL_SOURCE_RELATIVE */: - if (value === 1) { - src.relative = true; - AL.updateSourceSpace(src); - } else if (value === 0) { - src.relative = false; - AL.updateSourceSpace(src); - } else { - AL.currentCtx.err = 40963; - return; - } - break; - case 0x1001 /* AL_CONE_INNER_ANGLE */: - if (!Number.isFinite(value)) { - AL.currentCtx.err = 40963; - return; - } - - src.coneInnerAngle = value; - if (src.panner) { - src.panner.coneInnerAngle = value % 360.0; - } - break; - case 0x1002 /* AL_CONE_OUTER_ANGLE */: - if (!Number.isFinite(value)) { - AL.currentCtx.err = 40963; - return; - } - - src.coneOuterAngle = value; - if (src.panner) { - src.panner.coneOuterAngle = value % 360.0; - } - break; - case 0x1003 /* AL_PITCH */: - if (!Number.isFinite(value) || value <= 0.0) { - AL.currentCtx.err = 40963; - return; - } - - if (src.pitch === value) { - break; - } - - src.pitch = value; - AL.updateSourceRate(src); - break; - case 4100: - if ( - !Number.isFinite(value[0]) || - !Number.isFinite(value[1]) || - !Number.isFinite(value[2]) - ) { - AL.currentCtx.err = 40963; - return; - } - - src.position[0] = value[0]; - src.position[1] = value[1]; - src.position[2] = value[2]; - AL.updateSourceSpace(src); - break; - case 4101: - if ( - !Number.isFinite(value[0]) || - !Number.isFinite(value[1]) || - !Number.isFinite(value[2]) - ) { - AL.currentCtx.err = 40963; - return; - } - - src.direction[0] = value[0]; - src.direction[1] = value[1]; - src.direction[2] = value[2]; - AL.updateSourceSpace(src); - break; - case 4102: - if ( - !Number.isFinite(value[0]) || - !Number.isFinite(value[1]) || - !Number.isFinite(value[2]) - ) { - AL.currentCtx.err = 40963; - return; - } - - src.velocity[0] = value[0]; - src.velocity[1] = value[1]; - src.velocity[2] = value[2]; - AL.updateSourceSpace(src); - break; - case 0x1007 /* AL_LOOPING */: - if (value === 1) { - src.looping = true; - AL.updateSourceTime(src); - if (src.type === 4136 && src.audioQueue.length > 0) { - var audioSrc = src.audioQueue[0]; - audioSrc.loop = true; - audioSrc._duration = Number.POSITIVE_INFINITY; - } - } else if (value === 0) { - src.looping = false; - var currentTime = AL.updateSourceTime(src); - if (src.type === 4136 && src.audioQueue.length > 0) { - var audioSrc = src.audioQueue[0]; - audioSrc.loop = false; - audioSrc._duration = - src.bufQueue[0].audioBuf.duration / - src.playbackRate; - audioSrc._startTime = - currentTime - src.bufOffset / src.playbackRate; - } - } else { - AL.currentCtx.err = 40963; - return; - } - break; - case 0x1009 /* AL_BUFFER */: - if (src.state === 4114 || src.state === 4115) { - AL.currentCtx.err = 40964; - return; - } - - if (value === 0) { - for (var i in src.bufQueue) { - src.bufQueue[i].refCount--; - } - src.bufQueue.length = 1; - src.bufQueue[0] = AL.buffers[0]; - - src.bufsProcessed = 0; - src.type = 0x1030 /* AL_UNDETERMINED */; - } else { - var buf = AL.buffers[value]; - if (!buf) { - AL.currentCtx.err = 40963; - return; - } - - for (var i in src.bufQueue) { - src.bufQueue[i].refCount--; - } - src.bufQueue.length = 0; - - buf.refCount++; - src.bufQueue = [buf]; - src.bufsProcessed = 0; - src.type = 4136; - } - - AL.initSourcePanner(src); - AL.scheduleSourceAudio(src); - break; - case 4106: - if (!Number.isFinite(value) || value < 0.0) { - AL.currentCtx.err = 40963; - return; - } - src.gain.gain.value = value; - break; - case 0x100d /* AL_MIN_GAIN */: - if ( - !Number.isFinite(value) || - value < 0.0 || - value > Math.min(src.maxGain, 1.0) - ) { - AL.currentCtx.err = 40963; - return; - } - src.minGain = value; - break; - case 0x100e /* AL_MAX_GAIN */: - if ( - !Number.isFinite(value) || - value < Math.max(0.0, src.minGain) || - value > 1.0 - ) { - AL.currentCtx.err = 40963; - return; - } - src.maxGain = value; - break; - case 0x1020 /* AL_REFERENCE_DISTANCE */: - if (!Number.isFinite(value) || value < 0.0) { - AL.currentCtx.err = 40963; - return; - } - src.refDistance = value; - if (src.panner) { - src.panner.refDistance = value; - } - break; - case 0x1021 /* AL_ROLLOFF_FACTOR */: - if (!Number.isFinite(value) || value < 0.0) { - AL.currentCtx.err = 40963; - return; - } - src.rolloffFactor = value; - if (src.panner) { - src.panner.rolloffFactor = value; - } - break; - case 0x1022 /* AL_CONE_OUTER_GAIN */: - if (!Number.isFinite(value) || value < 0.0 || value > 1.0) { - AL.currentCtx.err = 40963; - return; - } - src.coneOuterGain = value; - if (src.panner) { - src.panner.coneOuterGain = value; - } - break; - case 0x1023 /* AL_MAX_DISTANCE */: - if (!Number.isFinite(value) || value < 0.0) { - AL.currentCtx.err = 40963; - return; - } - src.maxDistance = value; - if (src.panner) { - src.panner.maxDistance = value; - } - break; - case 0x1024 /* AL_SEC_OFFSET */: - if (value < 0.0 || value > AL.sourceDuration(src)) { - AL.currentCtx.err = 40963; - return; - } - - AL.sourceSeek(src, value); - break; - case 0x1025 /* AL_SAMPLE_OFFSET */: - var srcLen = AL.sourceDuration(src); - if (srcLen > 0.0) { - var frequency; - for (var bufId in src.bufQueue) { - if (bufId) { - frequency = src.bufQueue[bufId].frequency; - break; - } - } - value /= frequency; - } - if (value < 0.0 || value > srcLen) { - AL.currentCtx.err = 40963; - return; - } - - AL.sourceSeek(src, value); - break; - case 0x1026 /* AL_BYTE_OFFSET */: - var srcLen = AL.sourceDuration(src); - if (srcLen > 0.0) { - var bytesPerSec; - for (var bufId in src.bufQueue) { - if (bufId) { - var buf = src.bufQueue[bufId]; - bytesPerSec = - buf.frequency * - buf.bytesPerSample * - buf.channels; - break; - } - } - value /= bytesPerSec; - } - if (value < 0.0 || value > srcLen) { - AL.currentCtx.err = 40963; - return; - } - - AL.sourceSeek(src, value); - break; - case 0x1214 /* AL_SOURCE_SPATIALIZE_SOFT */: - if ( - value !== 0 && - value !== 1 && - value !== 2 /* AL_AUTO_SOFT */ - ) { - AL.currentCtx.err = 40963; - return; - } - - src.spatialize = value; - AL.initSourcePanner(src); - break; - case 0x2009 /* AL_BYTE_LENGTH_SOFT */: - case 0x200a /* AL_SAMPLE_LENGTH_SOFT */: - case 0x200b /* AL_SEC_LENGTH_SOFT */: - AL.currentCtx.err = 40964; - break; - case 53248: - switch (value) { - case 0: - case 0xd001 /* AL_INVERSE_DISTANCE */: - case 0xd002 /* AL_INVERSE_DISTANCE_CLAMPED */: - case 0xd003 /* AL_LINEAR_DISTANCE */: - case 0xd004 /* AL_LINEAR_DISTANCE_CLAMPED */: - case 0xd005 /* AL_EXPONENT_DISTANCE */: - case 0xd006 /* AL_EXPONENT_DISTANCE_CLAMPED */: - src.distanceModel = value; - if (AL.currentCtx.sourceDistanceModel) { - AL.updateContextGlobal(AL.currentCtx); - } - break; - default: - AL.currentCtx.err = 40963; - return; - } - break; - default: - AL.currentCtx.err = 40962; - return; - } - }, - captures: {}, - sharedCaptureAudioCtx: null, - requireValidCaptureDevice: (deviceId, funcname) => { - if (deviceId === 0) { - AL.alcErr = 40961; - return null; - } - var c = AL.captures[deviceId]; - if (!c) { - AL.alcErr = 40961; - return null; - } - var err = c.mediaStreamError; - if (err) { - AL.alcErr = 40961; - return null; - } - return c; - }, - }; - var _alBuffer3f = (bufferId, param, value0, value1, value2) => { - AL.setBufferParam('alBuffer3f', bufferId, param, null); - }; - _alBuffer3f.sig = 'viifff'; - - var _alBuffer3i = (bufferId, param, value0, value1, value2) => { - AL.setBufferParam('alBuffer3i', bufferId, param, null); - }; - _alBuffer3i.sig = 'viiiii'; - - var _alBufferData = (bufferId, format, pData, size, freq) => { - if (!AL.currentCtx) { - return; - } - var buf = AL.buffers[bufferId]; - if (!buf) { - AL.currentCtx.err = 40963; - return; - } - if (freq <= 0) { - AL.currentCtx.err = 40963; - return; - } - - var audioBuf = null; - try { - switch (format) { - case 0x1100 /* AL_FORMAT_MONO8 */: - if (size > 0) { - audioBuf = AL.currentCtx.audioCtx.createBuffer( - 1, - size, - freq - ); - var channel0 = audioBuf.getChannelData(0); - for (var i = 0; i < size; ++i) { - channel0[i] = - HEAPU8[pData++] * 0.0078125 /* 1/128 */ - 1.0; - } - } - buf.bytesPerSample = 1; - buf.channels = 1; - buf.length = size; - break; - case 0x1101 /* AL_FORMAT_MONO16 */: - if (size > 0) { - audioBuf = AL.currentCtx.audioCtx.createBuffer( - 1, - size >> 1, - freq - ); - var channel0 = audioBuf.getChannelData(0); - pData >>= 1; - for (var i = 0; i < size >> 1; ++i) { - channel0[i] = - HEAP16[pData++] * - 0.000030517578125 /* 1/32768 */; - } - } - buf.bytesPerSample = 2; - buf.channels = 1; - buf.length = size >> 1; - break; - case 0x1102 /* AL_FORMAT_STEREO8 */: - if (size > 0) { - audioBuf = AL.currentCtx.audioCtx.createBuffer( - 2, - size >> 1, - freq - ); - var channel0 = audioBuf.getChannelData(0); - var channel1 = audioBuf.getChannelData(1); - for (var i = 0; i < size >> 1; ++i) { - channel0[i] = - HEAPU8[pData++] * 0.0078125 /* 1/128 */ - 1.0; - channel1[i] = - HEAPU8[pData++] * 0.0078125 /* 1/128 */ - 1.0; - } - } - buf.bytesPerSample = 1; - buf.channels = 2; - buf.length = size >> 1; - break; - case 0x1103 /* AL_FORMAT_STEREO16 */: - if (size > 0) { - audioBuf = AL.currentCtx.audioCtx.createBuffer( - 2, - size >> 2, - freq - ); - var channel0 = audioBuf.getChannelData(0); - var channel1 = audioBuf.getChannelData(1); - pData >>= 1; - for (var i = 0; i < size >> 2; ++i) { - channel0[i] = - HEAP16[pData++] * - 0.000030517578125 /* 1/32768 */; - channel1[i] = - HEAP16[pData++] * - 0.000030517578125 /* 1/32768 */; - } - } - buf.bytesPerSample = 2; - buf.channels = 2; - buf.length = size >> 2; - break; - case 0x10010 /* AL_FORMAT_MONO_FLOAT32 */: - if (size > 0) { - audioBuf = AL.currentCtx.audioCtx.createBuffer( - 1, - size >> 2, - freq - ); - var channel0 = audioBuf.getChannelData(0); - pData >>= 2; - for (var i = 0; i < size >> 2; ++i) { - channel0[i] = HEAPF32[pData++]; - } - } - buf.bytesPerSample = 4; - buf.channels = 1; - buf.length = size >> 2; - break; - case 0x10011 /* AL_FORMAT_STEREO_FLOAT32 */: - if (size > 0) { - audioBuf = AL.currentCtx.audioCtx.createBuffer( - 2, - size >> 3, - freq - ); - var channel0 = audioBuf.getChannelData(0); - var channel1 = audioBuf.getChannelData(1); - pData >>= 2; - for (var i = 0; i < size >> 3; ++i) { - channel0[i] = HEAPF32[pData++]; - channel1[i] = HEAPF32[pData++]; - } - } - buf.bytesPerSample = 4; - buf.channels = 2; - buf.length = size >> 3; - break; - default: - AL.currentCtx.err = 40963; - return; - } - buf.frequency = freq; - buf.audioBuf = audioBuf; - } catch (e) { - AL.currentCtx.err = 40963; - return; - } - }; - _alBufferData.sig = 'viipii'; - - var _alBufferf = (bufferId, param, value) => { - AL.setBufferParam('alBufferf', bufferId, param, null); - }; - _alBufferf.sig = 'viif'; - - var _alBufferfv = (bufferId, param, pValues) => { - if (!AL.currentCtx) { - return; - } - if (!pValues) { - AL.currentCtx.err = 40963; - return; - } - - AL.setBufferParam('alBufferfv', bufferId, param, null); - }; - _alBufferfv.sig = 'viip'; - - var _alBufferi = (bufferId, param, value) => { - AL.setBufferParam('alBufferi', bufferId, param, null); - }; - _alBufferi.sig = 'viii'; - - var _alBufferiv = (bufferId, param, pValues) => { - if (!AL.currentCtx) { - return; - } - if (!pValues) { - AL.currentCtx.err = 40963; - return; - } - - switch (param) { - case 0x2015 /* AL_LOOP_POINTS_SOFT */: - AL.paramArray[0] = HEAP32[pValues >> 2]; - AL.paramArray[1] = HEAP32[(pValues + 4) >> 2]; - AL.setBufferParam('alBufferiv', bufferId, param, AL.paramArray); - break; - default: - AL.setBufferParam('alBufferiv', bufferId, param, null); - break; - } - }; - _alBufferiv.sig = 'viip'; - - var _alDeleteBuffers = (count, pBufferIds) => { - if (!AL.currentCtx) { - return; - } - - for (var i = 0; i < count; ++i) { - var bufId = HEAP32[(pBufferIds + i * 4) >> 2]; - /// Deleting the zero buffer is a legal NOP, so ignore it - if (bufId === 0) { - continue; - } - - // Make sure the buffer index is valid. - if (!AL.buffers[bufId]) { - AL.currentCtx.err = 40961; - return; - } - - // Make sure the buffer is no longer in use. - if (AL.buffers[bufId].refCount) { - AL.currentCtx.err = 40964; - return; - } - } - - for (var i = 0; i < count; ++i) { - var bufId = HEAP32[(pBufferIds + i * 4) >> 2]; - if (bufId === 0) { - continue; - } - - AL.deviceRefCounts[AL.buffers[bufId].deviceId]--; - delete AL.buffers[bufId]; - AL.freeIds.push(bufId); - } - }; - _alDeleteBuffers.sig = 'vip'; - - var _alSourcei = (sourceId, param, value) => { - switch (param) { - case 0x202 /* AL_SOURCE_RELATIVE */: - case 0x1001 /* AL_CONE_INNER_ANGLE */: - case 0x1002 /* AL_CONE_OUTER_ANGLE */: - case 0x1007 /* AL_LOOPING */: - case 0x1009 /* AL_BUFFER */: - case 0x1020 /* AL_REFERENCE_DISTANCE */: - case 0x1021 /* AL_ROLLOFF_FACTOR */: - case 0x1023 /* AL_MAX_DISTANCE */: - case 0x1024 /* AL_SEC_OFFSET */: - case 0x1025 /* AL_SAMPLE_OFFSET */: - case 0x1026 /* AL_BYTE_OFFSET */: - case 0x1214 /* AL_SOURCE_SPATIALIZE_SOFT */: - case 0x2009 /* AL_BYTE_LENGTH_SOFT */: - case 0x200a /* AL_SAMPLE_LENGTH_SOFT */: - case 53248: - AL.setSourceParam('alSourcei', sourceId, param, value); - break; - default: - AL.setSourceParam('alSourcei', sourceId, param, null); - break; - } - }; - _alSourcei.sig = 'viii'; - - var _alDeleteSources = (count, pSourceIds) => { - if (!AL.currentCtx) { - return; - } - - for (var i = 0; i < count; ++i) { - var srcId = HEAP32[(pSourceIds + i * 4) >> 2]; - if (!AL.currentCtx.sources[srcId]) { - AL.currentCtx.err = 40961; - return; - } - } - - for (var i = 0; i < count; ++i) { - var srcId = HEAP32[(pSourceIds + i * 4) >> 2]; - AL.setSourceState(AL.currentCtx.sources[srcId], 4116); - _alSourcei(srcId, 0x1009 /* AL_BUFFER */, 0); - delete AL.currentCtx.sources[srcId]; - AL.freeIds.push(srcId); - } - }; - _alDeleteSources.sig = 'vip'; - - var _alDisable = (param) => { - if (!AL.currentCtx) { - return; - } - switch (param) { - case 0x200 /* AL_SOURCE_DISTANCE_MODEL */: - AL.currentCtx.sourceDistanceModel = false; - AL.updateContextGlobal(AL.currentCtx); - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alDisable.sig = 'vi'; - - var _alDistanceModel = (model) => { - AL.setGlobalParam('alDistanceModel', 53248, model); - }; - _alDistanceModel.sig = 'vi'; - - var _alDopplerFactor = (value) => { - AL.setGlobalParam('alDopplerFactor', 49152, value); - }; - _alDopplerFactor.sig = 'vf'; - - var _alDopplerVelocity = (value) => { - warnOnce( - 'alDopplerVelocity() is deprecated, and only kept for compatibility with OpenAL 1.0. Use alSpeedOfSound() instead.' - ); - if (!AL.currentCtx) { - return; - } - if (value <= 0) { - // Negative or zero values are disallowed - AL.currentCtx.err = 40963; - return; - } - }; - _alDopplerVelocity.sig = 'vf'; - - var _alEnable = (param) => { - if (!AL.currentCtx) { - return; - } - switch (param) { - case 0x200 /* AL_SOURCE_DISTANCE_MODEL */: - AL.currentCtx.sourceDistanceModel = true; - AL.updateContextGlobal(AL.currentCtx); - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alEnable.sig = 'vi'; - - var _alGenBuffers = (count, pBufferIds) => { - if (!AL.currentCtx) { - return; - } - - for (var i = 0; i < count; ++i) { - var buf = { - deviceId: AL.currentCtx.deviceId, - id: AL.newId(), - refCount: 0, - audioBuf: null, - frequency: 0, - bytesPerSample: 2, - channels: 1, - length: 0, - }; - AL.deviceRefCounts[buf.deviceId]++; - AL.buffers[buf.id] = buf; - HEAP32[(pBufferIds + i * 4) >> 2] = buf.id; - } - }; - _alGenBuffers.sig = 'vip'; - - var _alGenSources = (count, pSourceIds) => { - if (!AL.currentCtx) { - return; - } - for (var i = 0; i < count; ++i) { - var gain = AL.currentCtx.audioCtx.createGain(); - gain.connect(AL.currentCtx.gain); - var src = { - context: AL.currentCtx, - id: AL.newId(), - type: 0x1030 /* AL_UNDETERMINED */, - state: 4113, - bufQueue: [AL.buffers[0]], - audioQueue: [], - looping: false, - pitch: 1.0, - dopplerShift: 1.0, - gain, - minGain: 0.0, - maxGain: 1.0, - panner: null, - bufsProcessed: 0, - bufStartTime: Number.NEGATIVE_INFINITY, - bufOffset: 0.0, - relative: false, - refDistance: 1.0, - maxDistance: 3.40282e38 /* FLT_MAX */, - rolloffFactor: 1.0, - position: [0.0, 0.0, 0.0], - velocity: [0.0, 0.0, 0.0], - direction: [0.0, 0.0, 0.0], - coneOuterGain: 0.0, - coneInnerAngle: 360.0, - coneOuterAngle: 360.0, - distanceModel: 0xd002 /* AL_INVERSE_DISTANCE_CLAMPED */, - spatialize: 2 /* AL_AUTO_SOFT */, - - get playbackRate() { - return this.pitch * this.dopplerShift; - }, - }; - AL.currentCtx.sources[src.id] = src; - HEAP32[(pSourceIds + i * 4) >> 2] = src.id; - } - }; - _alGenSources.sig = 'vip'; - - var _alGetBoolean = (param) => { - var val = AL.getGlobalParam('alGetBoolean', param); - if (val === null) { - return 0; - } - - switch (param) { - case 49152: - case 49155: - case 53248: - return val !== 0 ? 1 : 0; - default: - AL.currentCtx.err = 40962; - return 0; - } - }; - _alGetBoolean.sig = 'ii'; - - var _alGetBooleanv = (param, pValues) => { - var val = AL.getGlobalParam('alGetBooleanv', param); - // Silently ignore null destinations, as per the spec for global state functions - if (val === null || !pValues) { - return; - } - - switch (param) { - case 49152: - case 49155: - case 53248: - HEAP8[pValues] = val; - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alGetBooleanv.sig = 'vip'; - - var _alGetBuffer3f = (bufferId, param, pValue0, pValue1, pValue2) => { - var val = AL.getBufferParam('alGetBuffer3f', bufferId, param); - if (val === null) { - return; - } - if (!pValue0 || !pValue1 || !pValue2) { - AL.currentCtx.err = 40963; - return; - } - - AL.currentCtx.err = 40962; - }; - _alGetBuffer3f.sig = 'viippp'; - - var _alGetBuffer3i = (bufferId, param, pValue0, pValue1, pValue2) => { - var val = AL.getBufferParam('alGetBuffer3i', bufferId, param); - if (val === null) { - return; - } - if (!pValue0 || !pValue1 || !pValue2) { - AL.currentCtx.err = 40963; - return; - } - - AL.currentCtx.err = 40962; - }; - _alGetBuffer3i.sig = 'viippp'; - - var _alGetBufferf = (bufferId, param, pValue) => { - var val = AL.getBufferParam('alGetBufferf', bufferId, param); - if (val === null) { - return; - } - if (!pValue) { - AL.currentCtx.err = 40963; - return; - } - - AL.currentCtx.err = 40962; - }; - _alGetBufferf.sig = 'viip'; - - var _alGetBufferfv = (bufferId, param, pValues) => { - var val = AL.getBufferParam('alGetBufferfv', bufferId, param); - if (val === null) { - return; - } - if (!pValues) { - AL.currentCtx.err = 40963; - return; - } - - AL.currentCtx.err = 40962; - }; - _alGetBufferfv.sig = 'viip'; - - var _alGetBufferi = (bufferId, param, pValue) => { - var val = AL.getBufferParam('alGetBufferi', bufferId, param); - if (val === null) { - return; - } - if (!pValue) { - AL.currentCtx.err = 40963; - return; - } - - switch (param) { - case 0x2001 /* AL_FREQUENCY */: - case 0x2002 /* AL_BITS */: - case 0x2003 /* AL_CHANNELS */: - case 0x2004 /* AL_SIZE */: - HEAP32[pValue >> 2] = val; - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alGetBufferi.sig = 'viip'; - - var _alGetBufferiv = (bufferId, param, pValues) => { - var val = AL.getBufferParam('alGetBufferiv', bufferId, param); - if (val === null) { - return; - } - if (!pValues) { - AL.currentCtx.err = 40963; - return; - } - - switch (param) { - case 0x2001 /* AL_FREQUENCY */: - case 0x2002 /* AL_BITS */: - case 0x2003 /* AL_CHANNELS */: - case 0x2004 /* AL_SIZE */: - HEAP32[pValues >> 2] = val; - break; - case 0x2015 /* AL_LOOP_POINTS_SOFT */: - HEAP32[pValues >> 2] = val[0]; - HEAP32[(pValues + 4) >> 2] = val[1]; - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alGetBufferiv.sig = 'viip'; - - var _alGetDouble = (param) => { - var val = AL.getGlobalParam('alGetDouble', param); - if (val === null) { - return 0.0; - } - - switch (param) { - case 49152: - case 49155: - case 53248: - return val; - default: - AL.currentCtx.err = 40962; - return 0.0; - } - }; - _alGetDouble.sig = 'di'; - - var _alGetDoublev = (param, pValues) => { - var val = AL.getGlobalParam('alGetDoublev', param); - // Silently ignore null destinations, as per the spec for global state functions - if (val === null || !pValues) { - return; - } - - switch (param) { - case 49152: - case 49155: - case 53248: - HEAPF64[pValues >> 3] = val; - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alGetDoublev.sig = 'vip'; - - var _alGetEnumValue = (pEnumName) => { - if (!AL.currentCtx) { - return 0; - } - - if (!pEnumName) { - AL.currentCtx.err = 40963; - return 0; - } - var name = UTF8ToString(pEnumName); - - switch (name) { - // Spec doesn't clearly state that alGetEnumValue() is required to - // support _only_ extension tokens. - // We should probably follow OpenAL-Soft's example and support all - // of the names we know. - // See http://repo.or.cz/openal-soft.git/blob/HEAD:/Alc/ALc.c - case 'AL_BITS': - return 0x2002; - case 'AL_BUFFER': - return 0x1009; - case 'AL_BUFFERS_PROCESSED': - return 0x1016; - case 'AL_BUFFERS_QUEUED': - return 0x1015; - case 'AL_BYTE_OFFSET': - return 0x1026; - case 'AL_CHANNELS': - return 0x2003; - case 'AL_CONE_INNER_ANGLE': - return 0x1001; - case 'AL_CONE_OUTER_ANGLE': - return 0x1002; - case 'AL_CONE_OUTER_GAIN': - return 0x1022; - case 'AL_DIRECTION': - return 0x1005; - case 'AL_DISTANCE_MODEL': - return 0xd000; - case 'AL_DOPPLER_FACTOR': - return 0xc000; - case 'AL_DOPPLER_VELOCITY': - return 0xc001; - case 'AL_EXPONENT_DISTANCE': - return 0xd005; - case 'AL_EXPONENT_DISTANCE_CLAMPED': - return 0xd006; - case 'AL_EXTENSIONS': - return 0xb004; - case 'AL_FORMAT_MONO16': - return 0x1101; - case 'AL_FORMAT_MONO8': - return 0x1100; - case 'AL_FORMAT_STEREO16': - return 0x1103; - case 'AL_FORMAT_STEREO8': - return 0x1102; - case 'AL_FREQUENCY': - return 0x2001; - case 'AL_GAIN': - return 0x100a; - case 'AL_INITIAL': - return 0x1011; - case 'AL_INVALID': - return -1; - case 'AL_ILLEGAL_ENUM': // fallthrough - case 'AL_INVALID_ENUM': - return 0xa002; - case 'AL_INVALID_NAME': - return 0xa001; - case 'AL_ILLEGAL_COMMAND': // fallthrough - case 'AL_INVALID_OPERATION': - return 0xa004; - case 'AL_INVALID_VALUE': - return 0xa003; - case 'AL_INVERSE_DISTANCE': - return 0xd001; - case 'AL_INVERSE_DISTANCE_CLAMPED': - return 0xd002; - case 'AL_LINEAR_DISTANCE': - return 0xd003; - case 'AL_LINEAR_DISTANCE_CLAMPED': - return 0xd004; - case 'AL_LOOPING': - return 0x1007; - case 'AL_MAX_DISTANCE': - return 0x1023; - case 'AL_MAX_GAIN': - return 0x100e; - case 'AL_MIN_GAIN': - return 0x100d; - case 'AL_NONE': - return 0; - case 'AL_NO_ERROR': - return 0; - case 'AL_ORIENTATION': - return 0x100f; - case 'AL_OUT_OF_MEMORY': - return 0xa005; - case 'AL_PAUSED': - return 0x1013; - case 'AL_PENDING': - return 0x2011; - case 'AL_PITCH': - return 0x1003; - case 'AL_PLAYING': - return 0x1012; - case 'AL_POSITION': - return 0x1004; - case 'AL_PROCESSED': - return 0x2012; - case 'AL_REFERENCE_DISTANCE': - return 0x1020; - case 'AL_RENDERER': - return 0xb003; - case 'AL_ROLLOFF_FACTOR': - return 0x1021; - case 'AL_SAMPLE_OFFSET': - return 0x1025; - case 'AL_SEC_OFFSET': - return 0x1024; - case 'AL_SIZE': - return 0x2004; - case 'AL_SOURCE_RELATIVE': - return 0x202; - case 'AL_SOURCE_STATE': - return 0x1010; - case 'AL_SOURCE_TYPE': - return 0x1027; - case 'AL_SPEED_OF_SOUND': - return 0xc003; - case 'AL_STATIC': - return 0x1028; - case 'AL_STOPPED': - return 0x1014; - case 'AL_STREAMING': - return 0x1029; - case 'AL_UNDETERMINED': - return 0x1030; - case 'AL_UNUSED': - return 0x2010; - case 'AL_VELOCITY': - return 0x1006; - case 'AL_VENDOR': - return 0xb001; - case 'AL_VERSION': - return 0xb002; - - /* Extensions */ - case 'AL_AUTO_SOFT': - return 0x0002; - case 'AL_SOURCE_DISTANCE_MODEL': - return 0x200; - case 'AL_SOURCE_SPATIALIZE_SOFT': - return 0x1214; - case 'AL_LOOP_POINTS_SOFT': - return 0x2015; - case 'AL_BYTE_LENGTH_SOFT': - return 0x2009; - case 'AL_SAMPLE_LENGTH_SOFT': - return 0x200a; - case 'AL_SEC_LENGTH_SOFT': - return 0x200b; - case 'AL_FORMAT_MONO_FLOAT32': - return 0x10010; - case 'AL_FORMAT_STEREO_FLOAT32': - return 0x10011; - - default: - AL.currentCtx.err = 40963; - return 0; - } - }; - _alGetEnumValue.sig = 'ip'; - - var _alGetError = () => { - if (!AL.currentCtx) { - return 40964; - } - // Reset error on get. - var err = AL.currentCtx.err; - AL.currentCtx.err = 0; - return err; - }; - _alGetError.sig = 'i'; - - var _alGetFloat = (param) => { - var val = AL.getGlobalParam('alGetFloat', param); - if (val === null) { - return 0.0; - } - - switch (param) { - case 49152: - case 49155: - case 53248: - return val; - default: - return 0.0; - } - }; - _alGetFloat.sig = 'fi'; - - var _alGetFloatv = (param, pValues) => { - var val = AL.getGlobalParam('alGetFloatv', param); - // Silently ignore null destinations, as per the spec for global state functions - if (val === null || !pValues) { - return; - } - - switch (param) { - case 49152: - case 49155: - case 53248: - HEAPF32[pValues >> 2] = val; - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alGetFloatv.sig = 'vip'; - - var _alGetInteger = (param) => { - var val = AL.getGlobalParam('alGetInteger', param); - if (val === null) { - return 0; - } - - switch (param) { - case 49152: - case 49155: - case 53248: - return val; - default: - AL.currentCtx.err = 40962; - return 0; - } - }; - _alGetInteger.sig = 'ii'; - - var _alGetIntegerv = (param, pValues) => { - var val = AL.getGlobalParam('alGetIntegerv', param); - // Silently ignore null destinations, as per the spec for global state functions - if (val === null || !pValues) { - return; - } - - switch (param) { - case 49152: - case 49155: - case 53248: - HEAP32[pValues >> 2] = val; - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alGetIntegerv.sig = 'vip'; - - var _alGetListener3f = (param, pValue0, pValue1, pValue2) => { - var val = AL.getListenerParam('alGetListener3f', param); - if (val === null) { - return; - } - if (!pValue0 || !pValue1 || !pValue2) { - AL.currentCtx.err = 40963; - return; - } - - switch (param) { - case 4100: - case 4102: - HEAPF32[pValue0 >> 2] = val[0]; - HEAPF32[pValue1 >> 2] = val[1]; - HEAPF32[pValue2 >> 2] = val[2]; - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alGetListener3f.sig = 'vippp'; - - var _alGetListener3i = (param, pValue0, pValue1, pValue2) => { - var val = AL.getListenerParam('alGetListener3i', param); - if (val === null) { - return; - } - if (!pValue0 || !pValue1 || !pValue2) { - AL.currentCtx.err = 40963; - return; - } - - switch (param) { - case 4100: - case 4102: - HEAP32[pValue0 >> 2] = val[0]; - HEAP32[pValue1 >> 2] = val[1]; - HEAP32[pValue2 >> 2] = val[2]; - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alGetListener3i.sig = 'vippp'; - - var _alGetListenerf = (param, pValue) => { - var val = AL.getListenerParam('alGetListenerf', param); - if (val === null) { - return; - } - if (!pValue) { - AL.currentCtx.err = 40963; - return; - } - - switch (param) { - case 4106: - HEAPF32[pValue >> 2] = val; - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alGetListenerf.sig = 'vip'; - - var _alGetListenerfv = (param, pValues) => { - var val = AL.getListenerParam('alGetListenerfv', param); - if (val === null) { - return; - } - if (!pValues) { - AL.currentCtx.err = 40963; - return; - } - - switch (param) { - case 4100: - case 4102: - HEAPF32[pValues >> 2] = val[0]; - HEAPF32[(pValues + 4) >> 2] = val[1]; - HEAPF32[(pValues + 8) >> 2] = val[2]; - break; - case 4111: - HEAPF32[pValues >> 2] = val[0]; - HEAPF32[(pValues + 4) >> 2] = val[1]; - HEAPF32[(pValues + 8) >> 2] = val[2]; - HEAPF32[(pValues + 12) >> 2] = val[3]; - HEAPF32[(pValues + 16) >> 2] = val[4]; - HEAPF32[(pValues + 20) >> 2] = val[5]; - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alGetListenerfv.sig = 'vip'; - - var _alGetListeneri = (param, pValue) => { - var val = AL.getListenerParam('alGetListeneri', param); - if (val === null) { - return; - } - if (!pValue) { - AL.currentCtx.err = 40963; - return; - } - - AL.currentCtx.err = 40962; - }; - _alGetListeneri.sig = 'vip'; - - var _alGetListeneriv = (param, pValues) => { - var val = AL.getListenerParam('alGetListeneriv', param); - if (val === null) { - return; - } - if (!pValues) { - AL.currentCtx.err = 40963; - return; - } - - switch (param) { - case 4100: - case 4102: - HEAP32[pValues >> 2] = val[0]; - HEAP32[(pValues + 4) >> 2] = val[1]; - HEAP32[(pValues + 8) >> 2] = val[2]; - break; - case 4111: - HEAP32[pValues >> 2] = val[0]; - HEAP32[(pValues + 4) >> 2] = val[1]; - HEAP32[(pValues + 8) >> 2] = val[2]; - HEAP32[(pValues + 12) >> 2] = val[3]; - HEAP32[(pValues + 16) >> 2] = val[4]; - HEAP32[(pValues + 20) >> 2] = val[5]; - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alGetListeneriv.sig = 'vip'; - - var _alGetSource3f = (sourceId, param, pValue0, pValue1, pValue2) => { - var val = AL.getSourceParam('alGetSource3f', sourceId, param); - if (val === null) { - return; - } - if (!pValue0 || !pValue1 || !pValue2) { - AL.currentCtx.err = 40963; - return; - } - - switch (param) { - case 4100: - case 4101: - case 4102: - HEAPF32[pValue0 >> 2] = val[0]; - HEAPF32[pValue1 >> 2] = val[1]; - HEAPF32[pValue2 >> 2] = val[2]; - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alGetSource3f.sig = 'viippp'; - - var _alGetSource3i = (sourceId, param, pValue0, pValue1, pValue2) => { - var val = AL.getSourceParam('alGetSource3i', sourceId, param); - if (val === null) { - return; - } - if (!pValue0 || !pValue1 || !pValue2) { - AL.currentCtx.err = 40963; - return; - } - - switch (param) { - case 4100: - case 4101: - case 4102: - HEAP32[pValue0 >> 2] = val[0]; - HEAP32[pValue1 >> 2] = val[1]; - HEAP32[pValue2 >> 2] = val[2]; - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alGetSource3i.sig = 'viippp'; - - var _alGetSourcef = (sourceId, param, pValue) => { - var val = AL.getSourceParam('alGetSourcef', sourceId, param); - if (val === null) { - return; - } - if (!pValue) { - AL.currentCtx.err = 40963; - return; - } - - switch (param) { - case 0x1001 /* AL_CONE_INNER_ANGLE */: - case 0x1002 /* AL_CONE_OUTER_ANGLE */: - case 0x1003 /* AL_PITCH */: - case 4106: - case 0x100d /* AL_MIN_GAIN */: - case 0x100e /* AL_MAX_GAIN */: - case 0x1020 /* AL_REFERENCE_DISTANCE */: - case 0x1021 /* AL_ROLLOFF_FACTOR */: - case 0x1022 /* AL_CONE_OUTER_GAIN */: - case 0x1023 /* AL_MAX_DISTANCE */: - case 0x1024 /* AL_SEC_OFFSET */: - case 0x1025 /* AL_SAMPLE_OFFSET */: - case 0x1026 /* AL_BYTE_OFFSET */: - case 0x200b /* AL_SEC_LENGTH_SOFT */: - HEAPF32[pValue >> 2] = val; - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alGetSourcef.sig = 'viip'; - - var _alGetSourcefv = (sourceId, param, pValues) => { - var val = AL.getSourceParam('alGetSourcefv', sourceId, param); - if (val === null) { - return; - } - if (!pValues) { - AL.currentCtx.err = 40963; - return; - } - - switch (param) { - case 0x1001 /* AL_CONE_INNER_ANGLE */: - case 0x1002 /* AL_CONE_OUTER_ANGLE */: - case 0x1003 /* AL_PITCH */: - case 4106: - case 0x100d /* AL_MIN_GAIN */: - case 0x100e /* AL_MAX_GAIN */: - case 0x1020 /* AL_REFERENCE_DISTANCE */: - case 0x1021 /* AL_ROLLOFF_FACTOR */: - case 0x1022 /* AL_CONE_OUTER_GAIN */: - case 0x1023 /* AL_MAX_DISTANCE */: - case 0x1024 /* AL_SEC_OFFSET */: - case 0x1025 /* AL_SAMPLE_OFFSET */: - case 0x1026 /* AL_BYTE_OFFSET */: - case 0x200b /* AL_SEC_LENGTH_SOFT */: - HEAPF32[pValues >> 2] = val[0]; - break; - case 4100: - case 4101: - case 4102: - HEAPF32[pValues >> 2] = val[0]; - HEAPF32[(pValues + 4) >> 2] = val[1]; - HEAPF32[(pValues + 8) >> 2] = val[2]; - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alGetSourcefv.sig = 'viip'; - - var _alGetSourcei = (sourceId, param, pValue) => { - var val = AL.getSourceParam('alGetSourcei', sourceId, param); - if (val === null) { - return; - } - if (!pValue) { - AL.currentCtx.err = 40963; - return; - } - - switch (param) { - case 0x202 /* AL_SOURCE_RELATIVE */: - case 0x1001 /* AL_CONE_INNER_ANGLE */: - case 0x1002 /* AL_CONE_OUTER_ANGLE */: - case 0x1007 /* AL_LOOPING */: - case 0x1009 /* AL_BUFFER */: - case 0x1010 /* AL_SOURCE_STATE */: - case 0x1015 /* AL_BUFFERS_QUEUED */: - case 0x1016 /* AL_BUFFERS_PROCESSED */: - case 0x1020 /* AL_REFERENCE_DISTANCE */: - case 0x1021 /* AL_ROLLOFF_FACTOR */: - case 0x1023 /* AL_MAX_DISTANCE */: - case 0x1024 /* AL_SEC_OFFSET */: - case 0x1025 /* AL_SAMPLE_OFFSET */: - case 0x1026 /* AL_BYTE_OFFSET */: - case 0x1027 /* AL_SOURCE_TYPE */: - case 0x1214 /* AL_SOURCE_SPATIALIZE_SOFT */: - case 0x2009 /* AL_BYTE_LENGTH_SOFT */: - case 0x200a /* AL_SAMPLE_LENGTH_SOFT */: - case 53248: - HEAP32[pValue >> 2] = val; - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alGetSourcei.sig = 'viip'; - - var _alGetSourceiv = (sourceId, param, pValues) => { - var val = AL.getSourceParam('alGetSourceiv', sourceId, param); - if (val === null) { - return; - } - if (!pValues) { - AL.currentCtx.err = 40963; - return; - } - - switch (param) { - case 0x202 /* AL_SOURCE_RELATIVE */: - case 0x1001 /* AL_CONE_INNER_ANGLE */: - case 0x1002 /* AL_CONE_OUTER_ANGLE */: - case 0x1007 /* AL_LOOPING */: - case 0x1009 /* AL_BUFFER */: - case 0x1010 /* AL_SOURCE_STATE */: - case 0x1015 /* AL_BUFFERS_QUEUED */: - case 0x1016 /* AL_BUFFERS_PROCESSED */: - case 0x1020 /* AL_REFERENCE_DISTANCE */: - case 0x1021 /* AL_ROLLOFF_FACTOR */: - case 0x1023 /* AL_MAX_DISTANCE */: - case 0x1024 /* AL_SEC_OFFSET */: - case 0x1025 /* AL_SAMPLE_OFFSET */: - case 0x1026 /* AL_BYTE_OFFSET */: - case 0x1027 /* AL_SOURCE_TYPE */: - case 0x1214 /* AL_SOURCE_SPATIALIZE_SOFT */: - case 0x2009 /* AL_BYTE_LENGTH_SOFT */: - case 0x200a /* AL_SAMPLE_LENGTH_SOFT */: - case 53248: - HEAP32[pValues >> 2] = val; - break; - case 4100: - case 4101: - case 4102: - HEAP32[pValues >> 2] = val[0]; - HEAP32[(pValues + 4) >> 2] = val[1]; - HEAP32[(pValues + 8) >> 2] = val[2]; - break; - default: - AL.currentCtx.err = 40962; - return; - } - }; - _alGetSourceiv.sig = 'viip'; - - var stringToNewUTF8 = (str) => { - var size = lengthBytesUTF8(str) + 1; - var ret = _malloc(size); - if (ret) stringToUTF8(str, ret, size); - return ret; - }; - - var _alGetString = (param) => { - if (AL.stringCache[param]) { - return AL.stringCache[param]; - } - - var ret; - switch (param) { - case 0: - ret = 'No Error'; - break; - case 40961: - ret = 'Invalid Name'; - break; - case 40962: - ret = 'Invalid Enum'; - break; - case 40963: - ret = 'Invalid Value'; - break; - case 40964: - ret = 'Invalid Operation'; - break; - case 0xa005 /* AL_OUT_OF_MEMORY */: - ret = 'Out of Memory'; - break; - case 0xb001 /* AL_VENDOR */: - ret = 'Emscripten'; - break; - case 0xb002 /* AL_VERSION */: - ret = '1.1'; - break; - case 0xb003 /* AL_RENDERER */: - ret = 'WebAudio'; - break; - case 0xb004 /* AL_EXTENSIONS */: - ret = Object.keys(AL.AL_EXTENSIONS).join(' '); - break; - default: - if (AL.currentCtx) { - AL.currentCtx.err = 40962; - } else { - } - return 0; - } - - ret = stringToNewUTF8(ret); - AL.stringCache[param] = ret; - return ret; - }; - _alGetString.sig = 'pi'; - - var _alIsBuffer = (bufferId) => { - if (!AL.currentCtx) { - return false; - } - if (bufferId > AL.buffers.length) { - return false; - } - - if (!AL.buffers[bufferId]) { - return false; - } - return true; - }; - _alIsBuffer.sig = 'ii'; - - var _alIsEnabled = (param) => { - if (!AL.currentCtx) { - return 0; - } - switch (param) { - case 0x200 /* AL_SOURCE_DISTANCE_MODEL */: - return AL.currentCtx.sourceDistanceModel ? 0 : 1; - default: - AL.currentCtx.err = 40962; - return 0; - } - }; - _alIsEnabled.sig = 'ii'; - - var _alIsExtensionPresent = (pExtName) => { - var name = UTF8ToString(pExtName); - - return AL.AL_EXTENSIONS[name] ? 1 : 0; - }; - _alIsExtensionPresent.sig = 'ip'; - - var _alIsSource = (sourceId) => { - if (!AL.currentCtx) { - return false; - } - - if (!AL.currentCtx.sources[sourceId]) { - return false; - } - return true; - }; - _alIsSource.sig = 'ii'; - - var _alListener3f = (param, value0, value1, value2) => { - switch (param) { - case 4100: - case 4102: - AL.paramArray[0] = value0; - AL.paramArray[1] = value1; - AL.paramArray[2] = value2; - AL.setListenerParam('alListener3f', param, AL.paramArray); - break; - default: - AL.setListenerParam('alListener3f', param, null); - break; - } - }; - _alListener3f.sig = 'vifff'; - - var _alListener3i = (param, value0, value1, value2) => { - switch (param) { - case 4100: - case 4102: - AL.paramArray[0] = value0; - AL.paramArray[1] = value1; - AL.paramArray[2] = value2; - AL.setListenerParam('alListener3i', param, AL.paramArray); - break; - default: - AL.setListenerParam('alListener3i', param, null); - break; - } - }; - _alListener3i.sig = 'viiii'; - - var _alListenerf = (param, value) => { - switch (param) { - case 4106: - AL.setListenerParam('alListenerf', param, value); - break; - default: - AL.setListenerParam('alListenerf', param, null); - break; - } - }; - _alListenerf.sig = 'vif'; - - var _alListenerfv = (param, pValues) => { - if (!AL.currentCtx) { - return; - } - if (!pValues) { - AL.currentCtx.err = 40963; - return; - } - - switch (param) { - case 4100: - case 4102: - AL.paramArray[0] = HEAPF32[pValues >> 2]; - AL.paramArray[1] = HEAPF32[(pValues + 4) >> 2]; - AL.paramArray[2] = HEAPF32[(pValues + 8) >> 2]; - AL.setListenerParam('alListenerfv', param, AL.paramArray); - break; - case 4111: - AL.paramArray[0] = HEAPF32[pValues >> 2]; - AL.paramArray[1] = HEAPF32[(pValues + 4) >> 2]; - AL.paramArray[2] = HEAPF32[(pValues + 8) >> 2]; - AL.paramArray[3] = HEAPF32[(pValues + 12) >> 2]; - AL.paramArray[4] = HEAPF32[(pValues + 16) >> 2]; - AL.paramArray[5] = HEAPF32[(pValues + 20) >> 2]; - AL.setListenerParam('alListenerfv', param, AL.paramArray); - break; - default: - AL.setListenerParam('alListenerfv', param, null); - break; - } - }; - _alListenerfv.sig = 'vip'; - - var _alListeneri = (param, value) => { - AL.setListenerParam('alListeneri', param, null); - }; - _alListeneri.sig = 'vii'; - - var _alListeneriv = (param, pValues) => { - if (!AL.currentCtx) { - return; - } - if (!pValues) { - AL.currentCtx.err = 40963; - return; - } - - switch (param) { - case 4100: - case 4102: - AL.paramArray[0] = HEAP32[pValues >> 2]; - AL.paramArray[1] = HEAP32[(pValues + 4) >> 2]; - AL.paramArray[2] = HEAP32[(pValues + 8) >> 2]; - AL.setListenerParam('alListeneriv', param, AL.paramArray); - break; - case 4111: - AL.paramArray[0] = HEAP32[pValues >> 2]; - AL.paramArray[1] = HEAP32[(pValues + 4) >> 2]; - AL.paramArray[2] = HEAP32[(pValues + 8) >> 2]; - AL.paramArray[3] = HEAP32[(pValues + 12) >> 2]; - AL.paramArray[4] = HEAP32[(pValues + 16) >> 2]; - AL.paramArray[5] = HEAP32[(pValues + 20) >> 2]; - AL.setListenerParam('alListeneriv', param, AL.paramArray); - break; - default: - AL.setListenerParam('alListeneriv', param, null); - break; - } - }; - _alListeneriv.sig = 'vip'; - - var _alSource3f = (sourceId, param, value0, value1, value2) => { - switch (param) { - case 4100: - case 4101: - case 4102: - AL.paramArray[0] = value0; - AL.paramArray[1] = value1; - AL.paramArray[2] = value2; - AL.setSourceParam('alSource3f', sourceId, param, AL.paramArray); - break; - default: - AL.setSourceParam('alSource3f', sourceId, param, null); - break; - } - }; - _alSource3f.sig = 'viifff'; - - var _alSource3i = (sourceId, param, value0, value1, value2) => { - switch (param) { - case 4100: - case 4101: - case 4102: - AL.paramArray[0] = value0; - AL.paramArray[1] = value1; - AL.paramArray[2] = value2; - AL.setSourceParam('alSource3i', sourceId, param, AL.paramArray); - break; - default: - AL.setSourceParam('alSource3i', sourceId, param, null); - break; - } - }; - _alSource3i.sig = 'viiiii'; - - var _alSourcePause = (sourceId) => { - if (!AL.currentCtx) { - return; - } - var src = AL.currentCtx.sources[sourceId]; - if (!src) { - AL.currentCtx.err = 40961; - return; - } - AL.setSourceState(src, 4115); - }; - _alSourcePause.sig = 'vi'; - - var _alSourcePausev = (count, pSourceIds) => { - if (!AL.currentCtx) { - return; - } - if (!pSourceIds) { - AL.currentCtx.err = 40963; - } - for (var i = 0; i < count; ++i) { - if (!AL.currentCtx.sources[HEAP32[(pSourceIds + i * 4) >> 2]]) { - AL.currentCtx.err = 40961; - return; - } - } - - for (var i = 0; i < count; ++i) { - var srcId = HEAP32[(pSourceIds + i * 4) >> 2]; - AL.setSourceState(AL.currentCtx.sources[srcId], 4115); - } - }; - _alSourcePausev.sig = 'vip'; - - var _alSourcePlay = (sourceId) => { - if (!AL.currentCtx) { - return; - } - var src = AL.currentCtx.sources[sourceId]; - if (!src) { - AL.currentCtx.err = 40961; - return; - } - AL.setSourceState(src, 4114); - }; - _alSourcePlay.sig = 'vi'; - - var _alSourcePlayv = (count, pSourceIds) => { - if (!AL.currentCtx) { - return; - } - if (!pSourceIds) { - AL.currentCtx.err = 40963; - } - for (var i = 0; i < count; ++i) { - if (!AL.currentCtx.sources[HEAP32[(pSourceIds + i * 4) >> 2]]) { - AL.currentCtx.err = 40961; - return; - } - } - - for (var i = 0; i < count; ++i) { - var srcId = HEAP32[(pSourceIds + i * 4) >> 2]; - AL.setSourceState(AL.currentCtx.sources[srcId], 4114); - } - }; - _alSourcePlayv.sig = 'vip'; - - var _alSourceQueueBuffers = (sourceId, count, pBufferIds) => { - if (!AL.currentCtx) { - return; - } - var src = AL.currentCtx.sources[sourceId]; - if (!src) { - AL.currentCtx.err = 40961; - return; - } - if (src.type === 4136) { - AL.currentCtx.err = 40964; - return; - } - - if (count === 0) { - return; - } - - // Find the first non-zero buffer in the queue to determine the proper format - var templateBuf = AL.buffers[0]; - for (var buf of src.bufQueue) { - if (buf.id !== 0) { - templateBuf = buf; - break; - } - } - - for (var i = 0; i < count; ++i) { - var bufId = HEAP32[(pBufferIds + i * 4) >> 2]; - var buf = AL.buffers[bufId]; - if (!buf) { - AL.currentCtx.err = 40961; - return; - } - - // Check that the added buffer has the correct format. If the template is the zero buffer, any format is valid. - if ( - templateBuf.id !== 0 && - (buf.frequency !== templateBuf.frequency || - buf.bytesPerSample !== templateBuf.bytesPerSample || - buf.channels !== templateBuf.channels) - ) { - AL.currentCtx.err = 40964; - } - } - - // If the only buffer in the queue is the zero buffer, clear the queue before we add anything. - if (src.bufQueue.length === 1 && src.bufQueue[0].id === 0) { - src.bufQueue.length = 0; - } - - src.type = 0x1029 /* AL_STREAMING */; - for (var i = 0; i < count; ++i) { - var bufId = HEAP32[(pBufferIds + i * 4) >> 2]; - var buf = AL.buffers[bufId]; - buf.refCount++; - src.bufQueue.push(buf); - } - - // if the source is looping, cancel the schedule so we can reschedule the loop order - if (src.looping) { - AL.cancelPendingSourceAudio(src); - } - - AL.initSourcePanner(src); - AL.scheduleSourceAudio(src); - }; - _alSourceQueueBuffers.sig = 'viip'; - - var _alSourceRewind = (sourceId) => { - if (!AL.currentCtx) { - return; - } - var src = AL.currentCtx.sources[sourceId]; - if (!src) { - AL.currentCtx.err = 40961; - return; - } - // Stop the source first to clear the source queue - AL.setSourceState(src, 4116); - // Now set the state of AL_INITIAL according to the specification - AL.setSourceState(src, 4113); - }; - _alSourceRewind.sig = 'vi'; - - var _alSourceRewindv = (count, pSourceIds) => { - if (!AL.currentCtx) { - return; - } - if (!pSourceIds) { - AL.currentCtx.err = 40963; - } - for (var i = 0; i < count; ++i) { - if (!AL.currentCtx.sources[HEAP32[(pSourceIds + i * 4) >> 2]]) { - AL.currentCtx.err = 40961; - return; - } - } - - for (var i = 0; i < count; ++i) { - var srcId = HEAP32[(pSourceIds + i * 4) >> 2]; - AL.setSourceState(AL.currentCtx.sources[srcId], 4113); - } - }; - _alSourceRewindv.sig = 'vip'; - - var _alSourceStop = (sourceId) => { - if (!AL.currentCtx) { - return; - } - var src = AL.currentCtx.sources[sourceId]; - if (!src) { - AL.currentCtx.err = 40961; - return; - } - AL.setSourceState(src, 4116); - }; - _alSourceStop.sig = 'vi'; - - var _alSourceStopv = (count, pSourceIds) => { - if (!AL.currentCtx) { - return; - } - if (!pSourceIds) { - AL.currentCtx.err = 40963; - } - for (var i = 0; i < count; ++i) { - if (!AL.currentCtx.sources[HEAP32[(pSourceIds + i * 4) >> 2]]) { - AL.currentCtx.err = 40961; - return; - } - } - - for (var i = 0; i < count; ++i) { - var srcId = HEAP32[(pSourceIds + i * 4) >> 2]; - AL.setSourceState(AL.currentCtx.sources[srcId], 4116); - } - }; - _alSourceStopv.sig = 'vip'; - - var _alSourceUnqueueBuffers = (sourceId, count, pBufferIds) => { - if (!AL.currentCtx) { - return; - } - var src = AL.currentCtx.sources[sourceId]; - if (!src) { - AL.currentCtx.err = 40961; - return; - } - if ( - count > - (src.bufQueue.length === 1 && src.bufQueue[0].id === 0 - ? 0 - : src.bufsProcessed) - ) { - AL.currentCtx.err = 40963; - return; - } - - if (count === 0) { - return; - } - - for (var i = 0; i < count; i++) { - var buf = src.bufQueue.shift(); - buf.refCount--; - // Write the buffers index out to the return list. - HEAP32[(pBufferIds + i * 4) >> 2] = buf.id; - src.bufsProcessed--; - } - - /// If the queue is empty, put the zero buffer back in - if (src.bufQueue.length === 0) { - src.bufQueue.push(AL.buffers[0]); - } - - AL.initSourcePanner(src); - AL.scheduleSourceAudio(src); - }; - _alSourceUnqueueBuffers.sig = 'viip'; - - var _alSourcef = (sourceId, param, value) => { - switch (param) { - case 0x1001 /* AL_CONE_INNER_ANGLE */: - case 0x1002 /* AL_CONE_OUTER_ANGLE */: - case 0x1003 /* AL_PITCH */: - case 4106: - case 0x100d /* AL_MIN_GAIN */: - case 0x100e /* AL_MAX_GAIN */: - case 0x1020 /* AL_REFERENCE_DISTANCE */: - case 0x1021 /* AL_ROLLOFF_FACTOR */: - case 0x1022 /* AL_CONE_OUTER_GAIN */: - case 0x1023 /* AL_MAX_DISTANCE */: - case 0x1024 /* AL_SEC_OFFSET */: - case 0x1025 /* AL_SAMPLE_OFFSET */: - case 0x1026 /* AL_BYTE_OFFSET */: - case 0x200b /* AL_SEC_LENGTH_SOFT */: - AL.setSourceParam('alSourcef', sourceId, param, value); - break; - default: - AL.setSourceParam('alSourcef', sourceId, param, null); - break; - } - }; - _alSourcef.sig = 'viif'; - - var _alSourcefv = (sourceId, param, pValues) => { - if (!AL.currentCtx) { - return; - } - if (!pValues) { - AL.currentCtx.err = 40963; - return; - } - - switch (param) { - case 0x1001 /* AL_CONE_INNER_ANGLE */: - case 0x1002 /* AL_CONE_OUTER_ANGLE */: - case 0x1003 /* AL_PITCH */: - case 4106: - case 0x100d /* AL_MIN_GAIN */: - case 0x100e /* AL_MAX_GAIN */: - case 0x1020 /* AL_REFERENCE_DISTANCE */: - case 0x1021 /* AL_ROLLOFF_FACTOR */: - case 0x1022 /* AL_CONE_OUTER_GAIN */: - case 0x1023 /* AL_MAX_DISTANCE */: - case 0x1024 /* AL_SEC_OFFSET */: - case 0x1025 /* AL_SAMPLE_OFFSET */: - case 0x1026 /* AL_BYTE_OFFSET */: - case 0x200b /* AL_SEC_LENGTH_SOFT */: - var val = HEAPF32[pValues >> 2]; - AL.setSourceParam('alSourcefv', sourceId, param, val); - break; - case 4100: - case 4101: - case 4102: - AL.paramArray[0] = HEAPF32[pValues >> 2]; - AL.paramArray[1] = HEAPF32[(pValues + 4) >> 2]; - AL.paramArray[2] = HEAPF32[(pValues + 8) >> 2]; - AL.setSourceParam('alSourcefv', sourceId, param, AL.paramArray); - break; - default: - AL.setSourceParam('alSourcefv', sourceId, param, null); - break; - } - }; - _alSourcefv.sig = 'viip'; - - var _alSourceiv = (sourceId, param, pValues) => { - if (!AL.currentCtx) { - return; - } - if (!pValues) { - AL.currentCtx.err = 40963; - return; - } - - switch (param) { - case 0x202 /* AL_SOURCE_RELATIVE */: - case 0x1001 /* AL_CONE_INNER_ANGLE */: - case 0x1002 /* AL_CONE_OUTER_ANGLE */: - case 0x1007 /* AL_LOOPING */: - case 0x1009 /* AL_BUFFER */: - case 0x1020 /* AL_REFERENCE_DISTANCE */: - case 0x1021 /* AL_ROLLOFF_FACTOR */: - case 0x1023 /* AL_MAX_DISTANCE */: - case 0x1024 /* AL_SEC_OFFSET */: - case 0x1025 /* AL_SAMPLE_OFFSET */: - case 0x1026 /* AL_BYTE_OFFSET */: - case 0x1214 /* AL_SOURCE_SPATIALIZE_SOFT */: - case 0x2009 /* AL_BYTE_LENGTH_SOFT */: - case 0x200a /* AL_SAMPLE_LENGTH_SOFT */: - case 53248: - var val = HEAP32[pValues >> 2]; - AL.setSourceParam('alSourceiv', sourceId, param, val); - break; - case 4100: - case 4101: - case 4102: - AL.paramArray[0] = HEAP32[pValues >> 2]; - AL.paramArray[1] = HEAP32[(pValues + 4) >> 2]; - AL.paramArray[2] = HEAP32[(pValues + 8) >> 2]; - AL.setSourceParam('alSourceiv', sourceId, param, AL.paramArray); - break; - default: - AL.setSourceParam('alSourceiv', sourceId, param, null); - break; - } - }; - _alSourceiv.sig = 'viip'; - - var _alSpeedOfSound = (value) => { - AL.setGlobalParam('alSpeedOfSound', 49155, value); - }; - _alSpeedOfSound.sig = 'vf'; - - var _alcCaptureCloseDevice = (deviceId) => { - var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureCloseDevice'); - if (!c) return false; - - delete AL.captures[deviceId]; - AL.freeIds.push(deviceId); - - // This clean-up might be unnecessary (paranoid) ? - - // May happen if user hasn't decided to grant or deny input - c.mediaStreamSourceNode?.disconnect(); - c.mergerNode?.disconnect(); - c.splitterNode?.disconnect(); - // May happen if user hasn't decided to grant or deny input - c.scriptProcessorNode?.disconnect(); - if (c.mediaStream) { - // Disabling the microphone of the browser. - // Without this operation, the red dot on the browser tab page will remain. - c.mediaStream.getTracks().forEach((track) => track.stop()); - } - - delete c.buffers; - - c.capturedFrameCount = 0; - c.isCapturing = false; - - return true; - }; - _alcCaptureCloseDevice.sig = 'ip'; - - var autoResumeAudioContext = (ctx) => { - for (var event of ['keydown', 'mousedown', 'touchstart']) { - for (var element of [document, document.getElementById('canvas')]) { - element?.addEventListener( - event, - () => { - if (ctx.state === 'suspended') ctx.resume(); - }, - { once: true } - ); - } - } - }; - - var _alcCaptureOpenDevice = ( - pDeviceName, - requestedSampleRate, - format, - bufferFrameCapacity - ) => { - var resolvedDeviceName = AL.CAPTURE_DEVICE_NAME; - - // NULL is a valid device name here (resolves to default); - if (pDeviceName !== 0) { - resolvedDeviceName = UTF8ToString(pDeviceName); - if (resolvedDeviceName !== AL.CAPTURE_DEVICE_NAME) { - // ALC_OUT_OF_MEMORY - // From the programmer's guide, ALC_OUT_OF_MEMORY's meaning is - // overloaded here, to mean: - // 'The specified device is invalid, or can not capture audio.' - // This may be misleading to API users, but well... - AL.alcErr = 0xa005 /* ALC_OUT_OF_MEMORY */; - return 0; - } - } - - // Otherwise it's probably okay (though useless) for bufferFrameCapacity to be zero. - if (bufferFrameCapacity < 0) { - // ALCsizei is signed int - AL.alcErr = 40964; - return 0; - } - - navigator.getUserMedia = - navigator.getUserMedia || - navigator.webkitGetUserMedia || - navigator.mozGetUserMedia || - navigator.msGetUserMedia; - var has_getUserMedia = - navigator.getUserMedia || - (navigator.mediaDevices && navigator.mediaDevices.getUserMedia); - - if (!has_getUserMedia) { - // See previously mentioned rationale for ALC_OUT_OF_MEMORY - AL.alcErr = 0xa005 /* ALC_OUT_OF_MEMORY */; - return 0; - } - - var AudioContext = window.AudioContext || window.webkitAudioContext; - - if (!AL.sharedCaptureAudioCtx) { - try { - AL.sharedCaptureAudioCtx = new AudioContext(); - } catch (e) { - // See previously mentioned rationale for ALC_OUT_OF_MEMORY - AL.alcErr = 0xa005 /* ALC_OUT_OF_MEMORY */; - return 0; - } - } - - autoResumeAudioContext(AL.sharedCaptureAudioCtx); - - var outputChannelCount; - - switch (format) { - case 0x10010: /* AL_FORMAT_MONO_FLOAT32 */ - case 0x1101: /* AL_FORMAT_MONO16 */ - case 0x1100 /* AL_FORMAT_MONO8 */: - outputChannelCount = 1; - break; - case 0x10011: /* AL_FORMAT_STEREO_FLOAT32 */ - case 0x1103: /* AL_FORMAT_STEREO16 */ - case 0x1102 /* AL_FORMAT_STEREO8 */: - outputChannelCount = 2; - break; - default: - AL.alcErr = 40964; - return 0; - } - - function newF32Array(cap) { - return new Float32Array(cap); - } - function newI16Array(cap) { - return new Int16Array(cap); - } - function newU8Array(cap) { - return new Uint8Array(cap); - } - - var requestedSampleType; - var newSampleArray; - - switch (format) { - case 0x10010: /* AL_FORMAT_MONO_FLOAT32 */ - case 0x10011 /* AL_FORMAT_STEREO_FLOAT32 */: - requestedSampleType = 'f32'; - newSampleArray = newF32Array; - break; - case 0x1101: /* AL_FORMAT_MONO16 */ - case 0x1103 /* AL_FORMAT_STEREO16 */: - requestedSampleType = 'i16'; - newSampleArray = newI16Array; - break; - case 0x1100: /* AL_FORMAT_MONO8 */ - case 0x1102 /* AL_FORMAT_STEREO8 */: - requestedSampleType = 'u8'; - newSampleArray = newU8Array; - break; - } - - var buffers = []; - try { - for (var chan = 0; chan < outputChannelCount; ++chan) { - buffers[chan] = newSampleArray(bufferFrameCapacity); - } - } catch (e) { - AL.alcErr = 0xa005 /* ALC_OUT_OF_MEMORY */; - return 0; - } - - // What we'll place into the `AL.captures` array in the end, - // declared here for closures to access it - var newCapture = { - audioCtx: AL.sharedCaptureAudioCtx, - deviceName: resolvedDeviceName, - requestedSampleRate, - requestedSampleType, - outputChannelCount, - inputChannelCount: null, // Not known until the getUserMedia() promise resolves - mediaStreamError: null, // Used by other functions to return early and report an error. - mediaStreamSourceNode: null, - mediaStream: null, - // Either one, or none of the below two, is active. - mergerNode: null, - splitterNode: null, - scriptProcessorNode: null, - isCapturing: false, - buffers, - get bufferFrameCapacity() { - return buffers[0].length; - }, - capturePlayhead: 0, // current write position, in sample frames - captureReadhead: 0, - capturedFrameCount: 0, - }; - - // Preparing for getUserMedia() - - var onError = (mediaStreamError) => { - newCapture.mediaStreamError = mediaStreamError; - }; - var onSuccess = (mediaStream) => { - newCapture.mediaStreamSourceNode = - newCapture.audioCtx.createMediaStreamSource(mediaStream); - newCapture.mediaStream = mediaStream; - - var inputChannelCount = 1; - switch (newCapture.mediaStreamSourceNode.channelCountMode) { - case 'max': - inputChannelCount = outputChannelCount; - break; - case 'clamped-max': - inputChannelCount = Math.min( - outputChannelCount, - newCapture.mediaStreamSourceNode.channelCount - ); - break; - case 'explicit': - inputChannelCount = - newCapture.mediaStreamSourceNode.channelCount; - break; - } - - newCapture.inputChannelCount = inputChannelCount; - - // Have to pick a size from 256, 512, 1024, 2048, 4096, 8192, 16384. - // One can also set it to zero, which leaves the decision up to the impl. - // An extension could allow specifying this value. - var processorFrameCount = 512; - - newCapture.scriptProcessorNode = - newCapture.audioCtx.createScriptProcessor( - processorFrameCount, - inputChannelCount, - outputChannelCount - ); - - if (inputChannelCount > outputChannelCount) { - newCapture.mergerNode = - newCapture.audioCtx.createChannelMerger(inputChannelCount); - newCapture.mediaStreamSourceNode.connect(newCapture.mergerNode); - newCapture.mergerNode.connect(newCapture.scriptProcessorNode); - } else if (inputChannelCount < outputChannelCount) { - newCapture.splitterNode = - newCapture.audioCtx.createChannelSplitter( - outputChannelCount - ); - newCapture.mediaStreamSourceNode.connect( - newCapture.splitterNode - ); - newCapture.splitterNode.connect(newCapture.scriptProcessorNode); - } else { - newCapture.mediaStreamSourceNode.connect( - newCapture.scriptProcessorNode - ); - } - - newCapture.scriptProcessorNode.connect( - newCapture.audioCtx.destination - ); - - newCapture.scriptProcessorNode.onaudioprocess = ( - audioProcessingEvent - ) => { - if (!newCapture.isCapturing) { - return; - } - - var c = newCapture; - var srcBuf = audioProcessingEvent.inputBuffer; - - // Actually just copy srcBuf's channel data into - // c.buffers, optimizing for each case. - switch (format) { - case 0x10010 /* AL_FORMAT_MONO_FLOAT32 */: - var channel0 = srcBuf.getChannelData(0); - for (var i = 0; i < srcBuf.length; ++i) { - var wi = - (c.capturePlayhead + i) % c.bufferFrameCapacity; - c.buffers[0][wi] = channel0[i]; - } - break; - case 0x10011 /* AL_FORMAT_STEREO_FLOAT32 */: - var channel0 = srcBuf.getChannelData(0); - var channel1 = srcBuf.getChannelData(1); - for (var i = 0; i < srcBuf.length; ++i) { - var wi = - (c.capturePlayhead + i) % c.bufferFrameCapacity; - c.buffers[0][wi] = channel0[i]; - c.buffers[1][wi] = channel1[i]; - } - break; - case 0x1101 /* AL_FORMAT_MONO16 */: - var channel0 = srcBuf.getChannelData(0); - for (var i = 0; i < srcBuf.length; ++i) { - var wi = - (c.capturePlayhead + i) % c.bufferFrameCapacity; - c.buffers[0][wi] = channel0[i] * 32767; - } - break; - case 0x1103 /* AL_FORMAT_STEREO16 */: - var channel0 = srcBuf.getChannelData(0); - var channel1 = srcBuf.getChannelData(1); - for (var i = 0; i < srcBuf.length; ++i) { - var wi = - (c.capturePlayhead + i) % c.bufferFrameCapacity; - c.buffers[0][wi] = channel0[i] * 32767; - c.buffers[1][wi] = channel1[i] * 32767; - } - break; - case 0x1100 /* AL_FORMAT_MONO8 */: - var channel0 = srcBuf.getChannelData(0); - for (var i = 0; i < srcBuf.length; ++i) { - var wi = - (c.capturePlayhead + i) % c.bufferFrameCapacity; - c.buffers[0][wi] = (channel0[i] + 1.0) * 127; - } - break; - case 0x1102 /* AL_FORMAT_STEREO8 */: - var channel0 = srcBuf.getChannelData(0); - var channel1 = srcBuf.getChannelData(1); - for (var i = 0; i < srcBuf.length; ++i) { - var wi = - (c.capturePlayhead + i) % c.bufferFrameCapacity; - c.buffers[0][wi] = (channel0[i] + 1.0) * 127; - c.buffers[1][wi] = (channel1[i] + 1.0) * 127; - } - break; - } - - c.capturePlayhead += srcBuf.length; - c.capturePlayhead %= c.bufferFrameCapacity; - c.capturedFrameCount += srcBuf.length; - c.capturedFrameCount = Math.min( - c.capturedFrameCount, - c.bufferFrameCapacity - ); - }; - }; - - // The latest way to call getUserMedia() - if (navigator.mediaDevices?.getUserMedia) { - navigator.mediaDevices - .getUserMedia({ audio: true }) - .then(onSuccess) - .catch(onError); - } else { - // The usual (now deprecated) way - navigator.getUserMedia({ audio: true }, onSuccess, onError); - } - - var id = AL.newId(); - AL.captures[id] = newCapture; - return id; - }; - _alcCaptureOpenDevice.sig = 'ppiii'; - - var _alcCaptureSamples = (deviceId, pFrames, requestedFrameCount) => { - var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureSamples'); - if (!c) return; - - // ALCsizei is actually 32-bit signed int, so could be negative - // Also, spec says : - // Requesting more sample frames than are currently available is - // an error. - - var dstfreq = c.requestedSampleRate; - var srcfreq = c.audioCtx.sampleRate; - - var fratio = srcfreq / dstfreq; - - if ( - requestedFrameCount < 0 || - requestedFrameCount > c.capturedFrameCount / fratio - ) { - AL.alcErr = 40964; - return; - } - - function setF32Sample(i, sample) { - HEAPF32[(pFrames + 4 * i) >> 2] = sample; - } - function setI16Sample(i, sample) { - HEAP16[(pFrames + 2 * i) >> 1] = sample; - } - function setU8Sample(i, sample) { - HEAP8[pFrames + i] = sample; - } - - var setSample; - - switch (c.requestedSampleType) { - case 'f32': - setSample = setF32Sample; - break; - case 'i16': - setSample = setI16Sample; - break; - case 'u8': - setSample = setU8Sample; - break; - default: - return; - } - - // If fratio is an integer we don't need linear resampling, just skip samples - if (Math.floor(fratio) == fratio) { - for ( - var i = 0, frame_i = 0; - frame_i < requestedFrameCount; - ++frame_i - ) { - for (var chan = 0; chan < c.buffers.length; ++chan, ++i) { - setSample(i, c.buffers[chan][c.captureReadhead]); - } - c.captureReadhead = - (fratio + c.captureReadhead) % c.bufferFrameCapacity; - } - } else { - // Perform linear resampling. - - // There is room for improvement - right now we're fine with linear resampling. - // We don't use OfflineAudioContexts for this: See the discussion at - // https://github.com/jpernst/emscripten/issues/2#issuecomment-312729735 - // if you're curious about why. - for ( - var i = 0, frame_i = 0; - frame_i < requestedFrameCount; - ++frame_i - ) { - var lefti = Math.floor(c.captureReadhead); - var righti = Math.ceil(c.captureReadhead); - var d = c.captureReadhead - lefti; - for (var chan = 0; chan < c.buffers.length; ++chan, ++i) { - var lefts = c.buffers[chan][lefti]; - var rights = c.buffers[chan][righti]; - setSample(i, (1 - d) * lefts + d * rights); - } - c.captureReadhead = - (c.captureReadhead + fratio) % c.bufferFrameCapacity; - } - } - - // Spec doesn't say if alcCaptureSamples() must zero the number - // of available captured sample-frames, but not only would it - // be insane not to do, OpenAL-Soft happens to do that as well. - c.capturedFrameCount = 0; - }; - _alcCaptureSamples.sig = 'vppi'; - - var _alcCaptureStart = (deviceId) => { - var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureStart'); - if (!c) return; - - if (c.isCapturing) { - // NOTE: Spec says (emphasis mine): - // The amount of audio samples available after **restarting** a - // stopped capture device is reset to zero. - // So redundant calls to alcCaptureStart() must have no effect. - return; - } - c.isCapturing = true; - c.capturedFrameCount = 0; - c.capturePlayhead = 0; - }; - _alcCaptureStart.sig = 'vp'; - - var _alcCaptureStop = (deviceId) => { - var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureStop'); - if (!c) return; - - c.isCapturing = false; - }; - _alcCaptureStop.sig = 'vp'; - - var _alcCloseDevice = (deviceId) => { - if ( - !(deviceId in AL.deviceRefCounts) || - AL.deviceRefCounts[deviceId] > 0 - ) { - return 0; - } - - delete AL.deviceRefCounts[deviceId]; - AL.freeIds.push(deviceId); - return 1; - }; - _alcCloseDevice.sig = 'ip'; - - var _alcCreateContext = (deviceId, pAttrList) => { - if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = 0xa001; /* ALC_INVALID_DEVICE */ - return 0; - } - - var options = null; - var attrs = []; - var hrtf = null; - pAttrList >>= 2; - if (pAttrList) { - var attr = 0; - var val = 0; - while (true) { - attr = HEAP32[pAttrList++]; - attrs.push(attr); - if (attr === 0) { - break; - } - val = HEAP32[pAttrList++]; - attrs.push(val); - - switch (attr) { - case 0x1007 /* ALC_FREQUENCY */: - if (!options) { - options = {}; - } - - options.sampleRate = val; - break; - case 0x1010 /* ALC_MONO_SOURCES */: // fallthrough - case 0x1011 /* ALC_STEREO_SOURCES */: - // Do nothing; these hints are satisfied by default - break; - case 0x1992 /* ALC_HRTF_SOFT */: - switch (val) { - case 0: - hrtf = false; - break; - case 1: - hrtf = true; - break; - case 2 /* ALC_DONT_CARE_SOFT */: - break; - default: - AL.alcErr = 40964; - return 0; - } - break; - case 0x1996 /* ALC_HRTF_ID_SOFT */: - if (val !== 0) { - AL.alcErr = 40964; - return 0; - } - break; - default: - AL.alcErr = 0xa004; /* ALC_INVALID_VALUE */ - return 0; - } - } - } - - var AudioContext = window.AudioContext || window.webkitAudioContext; - var ac = null; - try { - // Only try to pass options if there are any, for compat with browsers that don't support this - if (options) { - ac = new AudioContext(options); - } else { - ac = new AudioContext(); - } - } catch (e) { - if (e.name === 'NotSupportedError') { - AL.alcErr = 0xa004; /* ALC_INVALID_VALUE */ - } else { - AL.alcErr = 0xa001; /* ALC_INVALID_DEVICE */ - } - - return 0; - } - - autoResumeAudioContext(ac); - - // Old Web Audio API (e.g. Safari 6.0.5) had an inconsistently named createGainNode function. - if (typeof ac.createGain == 'undefined') { - ac.createGain = ac.createGainNode; - } - - var gain = ac.createGain(); - gain.connect(ac.destination); - var ctx = { - deviceId, - id: AL.newId(), - attrs, - audioCtx: ac, - listener: { - position: [0.0, 0.0, 0.0], - velocity: [0.0, 0.0, 0.0], - direction: [0.0, 0.0, 0.0], - up: [0.0, 0.0, 0.0], - }, - sources: [], - interval: setInterval( - () => AL.scheduleContextAudio(ctx), - AL.QUEUE_INTERVAL - ), - gain, - distanceModel: 0xd002 /* AL_INVERSE_DISTANCE_CLAMPED */, - speedOfSound: 343.3, - dopplerFactor: 1.0, - sourceDistanceModel: false, - hrtf: hrtf || false, - - _err: 0, - get err() { - return this._err; - }, - set err(val) { - // Errors should not be overwritten by later errors until they are cleared by a query. - if (this._err === 0 || val === 0) { - this._err = val; - } - }, - }; - AL.deviceRefCounts[deviceId]++; - AL.contexts[ctx.id] = ctx; - - if (hrtf !== null) { - // Apply hrtf attrib to all contexts for this device - for (var ctxId in AL.contexts) { - var c = AL.contexts[ctxId]; - if (c.deviceId === deviceId) { - c.hrtf = hrtf; - AL.updateContextGlobal(c); - } - } - } - - return ctx.id; - }; - _alcCreateContext.sig = 'ppp'; - - var _alcDestroyContext = (contextId) => { - var ctx = AL.contexts[contextId]; - if (AL.currentCtx === ctx) { - AL.alcErr = 0xa002 /* ALC_INVALID_CONTEXT */; - return; - } - - // Stop playback, etc - if (AL.contexts[contextId].interval) { - clearInterval(AL.contexts[contextId].interval); - } - AL.deviceRefCounts[ctx.deviceId]--; - delete AL.contexts[contextId]; - AL.freeIds.push(contextId); - }; - _alcDestroyContext.sig = 'vp'; - - var _alcGetContextsDevice = (contextId) => { - if (contextId in AL.contexts) { - return AL.contexts[contextId].deviceId; - } - return 0; - }; - _alcGetContextsDevice.sig = 'pp'; - - var _alcGetCurrentContext = () => { - if (AL.currentCtx !== null) { - return AL.currentCtx.id; - } - return 0; - }; - _alcGetCurrentContext.sig = 'p'; - - var _alcGetEnumValue = (deviceId, pEnumName) => { - // Spec says : - // Using a NULL handle is legal, but only the - // tokens defined by the AL core are guaranteed. - if (deviceId !== 0 && !(deviceId in AL.deviceRefCounts)) { - // ALC_INVALID_DEVICE is not listed as a possible error state for - // this function, sadly. - return 0; - } else if (!pEnumName) { - AL.alcErr = 40964; - return 0; - } - var name = UTF8ToString(pEnumName); - // See alGetEnumValue(), but basically behave the same as OpenAL-Soft - switch (name) { - case 'ALC_NO_ERROR': - return 0; - case 'ALC_INVALID_DEVICE': - return 0xa001; - case 'ALC_INVALID_CONTEXT': - return 0xa002; - case 'ALC_INVALID_ENUM': - return 0xa003; - case 'ALC_INVALID_VALUE': - return 0xa004; - case 'ALC_OUT_OF_MEMORY': - return 0xa005; - case 'ALC_MAJOR_VERSION': - return 0x1000; - case 'ALC_MINOR_VERSION': - return 0x1001; - case 'ALC_ATTRIBUTES_SIZE': - return 0x1002; - case 'ALC_ALL_ATTRIBUTES': - return 0x1003; - case 'ALC_DEFAULT_DEVICE_SPECIFIER': - return 0x1004; - case 'ALC_DEVICE_SPECIFIER': - return 0x1005; - case 'ALC_EXTENSIONS': - return 0x1006; - case 'ALC_FREQUENCY': - return 0x1007; - case 'ALC_REFRESH': - return 0x1008; - case 'ALC_SYNC': - return 0x1009; - case 'ALC_MONO_SOURCES': - return 0x1010; - case 'ALC_STEREO_SOURCES': - return 0x1011; - case 'ALC_CAPTURE_DEVICE_SPECIFIER': - return 0x310; - case 'ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER': - return 0x311; - case 'ALC_CAPTURE_SAMPLES': - return 0x312; - - /* Extensions */ - case 'ALC_HRTF_SOFT': - return 0x1992; - case 'ALC_HRTF_ID_SOFT': - return 0x1996; - case 'ALC_DONT_CARE_SOFT': - return 0x0002; - case 'ALC_HRTF_STATUS_SOFT': - return 0x1993; - case 'ALC_NUM_HRTF_SPECIFIERS_SOFT': - return 0x1994; - case 'ALC_HRTF_SPECIFIER_SOFT': - return 0x1995; - case 'ALC_HRTF_DISABLED_SOFT': - return 0x0000; - case 'ALC_HRTF_ENABLED_SOFT': - return 0x0001; - case 'ALC_HRTF_DENIED_SOFT': - return 0x0002; - case 'ALC_HRTF_REQUIRED_SOFT': - return 0x0003; - case 'ALC_HRTF_HEADPHONES_DETECTED_SOFT': - return 0x0004; - case 'ALC_HRTF_UNSUPPORTED_FORMAT_SOFT': - return 0x0005; - - default: - AL.alcErr = 40964; - return 0; - } - }; - _alcGetEnumValue.sig = 'ipp'; - - var _alcGetError = (deviceId) => { - var err = AL.alcErr; - AL.alcErr = 0; - return err; - }; - _alcGetError.sig = 'ip'; - - var _alcGetIntegerv = (deviceId, param, size, pValues) => { - if (size === 0 || !pValues) { - // Ignore the query, per the spec - return; - } - - switch (param) { - case 0x1000 /* ALC_MAJOR_VERSION */: - HEAP32[pValues >> 2] = 1; - break; - case 0x1001 /* ALC_MINOR_VERSION */: - HEAP32[pValues >> 2] = 1; - break; - case 0x1002 /* ALC_ATTRIBUTES_SIZE */: - if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = 40961; - return; - } - if (!AL.currentCtx) { - AL.alcErr = 0xa002 /* ALC_INVALID_CONTEXT */; - return; - } - - HEAP32[pValues >> 2] = AL.currentCtx.attrs.length; - break; - case 0x1003 /* ALC_ALL_ATTRIBUTES */: - if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = 40961; - return; - } - if (!AL.currentCtx) { - AL.alcErr = 0xa002 /* ALC_INVALID_CONTEXT */; - return; - } - - for (var i = 0; i < AL.currentCtx.attrs.length; i++) { - HEAP32[(pValues + i * 4) >> 2] = AL.currentCtx.attrs[i]; - } - break; - case 0x1007 /* ALC_FREQUENCY */: - if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = 40961; - return; - } - if (!AL.currentCtx) { - AL.alcErr = 0xa002 /* ALC_INVALID_CONTEXT */; - return; - } - - HEAP32[pValues >> 2] = AL.currentCtx.audioCtx.sampleRate; - break; - case 0x1010 /* ALC_MONO_SOURCES */: - case 0x1011 /* ALC_STEREO_SOURCES */: - if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = 40961; - return; - } - if (!AL.currentCtx) { - AL.alcErr = 0xa002 /* ALC_INVALID_CONTEXT */; - return; - } - - HEAP32[pValues >> 2] = 0x7fffffff; - break; - case 0x1992 /* ALC_HRTF_SOFT */: - case 0x1993 /* ALC_HRTF_STATUS_SOFT */: - if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = 40961; - return; - } - - var hrtfStatus = 0; /* ALC_HRTF_DISABLED_SOFT */ - for (var ctxId in AL.contexts) { - var ctx = AL.contexts[ctxId]; - if (ctx.deviceId === deviceId) { - hrtfStatus = ctx.hrtf - ? 1 /* ALC_HRTF_ENABLED_SOFT */ - : 0 /* ALC_HRTF_DISABLED_SOFT */; - } - } - HEAP32[pValues >> 2] = hrtfStatus; - break; - case 0x1994 /* ALC_NUM_HRTF_SPECIFIERS_SOFT */: - if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = 40961; - return; - } - HEAP32[pValues >> 2] = 1; - break; - case 0x20003 /* ALC_MAX_AUXILIARY_SENDS */: - if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = 40961; - return; - } - if (!AL.currentCtx) { - AL.alcErr = 0xa002 /* ALC_INVALID_CONTEXT */; - return; - } - - HEAP32[pValues >> 2] = 1; - case 0x312 /* ALC_CAPTURE_SAMPLES */: - var c = AL.requireValidCaptureDevice( - deviceId, - 'alcGetIntegerv' - ); - if (!c) { - return; - } - var n = c.capturedFrameCount; - var dstfreq = c.requestedSampleRate; - var srcfreq = c.audioCtx.sampleRate; - var nsamples = Math.floor(n * (dstfreq / srcfreq)); - HEAP32[pValues >> 2] = nsamples; - break; - default: - AL.alcErr = 40963; - return; - } - }; - _alcGetIntegerv.sig = 'vpiip'; - - var _alcGetString = (deviceId, param) => { - if (AL.alcStringCache[param]) { - return AL.alcStringCache[param]; - } - - var ret; - switch (param) { - case 0: - ret = 'No Error'; - break; - case 40961: - ret = 'Invalid Device'; - break; - case 0xa002 /* ALC_INVALID_CONTEXT */: - ret = 'Invalid Context'; - break; - case 40963: - ret = 'Invalid Enum'; - break; - case 40964: - ret = 'Invalid Value'; - break; - case 0xa005 /* ALC_OUT_OF_MEMORY */: - ret = 'Out of Memory'; - break; - case 0x1004 /* ALC_DEFAULT_DEVICE_SPECIFIER */: - if (globalThis.AudioContext || globalThis.webkitAudioContext) { - ret = AL.DEVICE_NAME; - } else { - return 0; - } - break; - case 0x1005 /* ALC_DEVICE_SPECIFIER */: - if (globalThis.AudioContext || globalThis.webkitAudioContext) { - ret = AL.DEVICE_NAME + '\0'; - } else { - ret = '\0'; - } - break; - case 0x311 /* ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER */: - ret = AL.CAPTURE_DEVICE_NAME; - break; - case 0x310 /* ALC_CAPTURE_DEVICE_SPECIFIER */: - if (deviceId === 0) { - ret = AL.CAPTURE_DEVICE_NAME + '\0'; - } else { - var c = AL.requireValidCaptureDevice( - deviceId, - 'alcGetString' - ); - if (!c) { - return 0; - } - ret = c.deviceName; - } - break; - case 0x1006 /* ALC_EXTENSIONS */: - if (!deviceId) { - AL.alcErr = 40961; - return 0; - } - - ret = Object.keys(AL.ALC_EXTENSIONS).join(' '); - break; - default: - AL.alcErr = 40963; - return 0; - } - - ret = stringToNewUTF8(ret); - AL.alcStringCache[param] = ret; - return ret; - }; - _alcGetString.sig = 'ppi'; - - var _alcIsExtensionPresent = (deviceId, pExtName) => { - var name = UTF8ToString(pExtName); - - return AL.ALC_EXTENSIONS[name] ? 1 : 0; - }; - _alcIsExtensionPresent.sig = 'ipp'; - - var _alcMakeContextCurrent = (contextId) => { - if (contextId === 0) { - AL.currentCtx = null; - } else { - AL.currentCtx = AL.contexts[contextId]; - } - return 1; - }; - _alcMakeContextCurrent.sig = 'ip'; - - var _alcOpenDevice = (pDeviceName) => { - if (pDeviceName) { - var name = UTF8ToString(pDeviceName); - if (name !== AL.DEVICE_NAME) { - return 0; - } - } - - if (globalThis.AudioContext || globalThis.webkitAudioContext) { - var deviceId = AL.newId(); - AL.deviceRefCounts[deviceId] = 0; - return deviceId; - } - return 0; - }; - _alcOpenDevice.sig = 'pp'; - - var _alcProcessContext = (contextId) => {}; - _alcProcessContext.sig = 'vp'; - - var _alcSuspendContext = (contextId) => {}; - _alcSuspendContext.sig = 'vp'; - - var _emscripten_get_now_res = () => { - // return resolution of get_now, in nanoseconds - if (ENVIRONMENT_IS_NODE) { - return 1; // nanoseconds - } - // Modern environment where performance.now() is supported: - return 1000; // microseconds (1/1000 of a millisecond) - }; - _emscripten_get_now_res.sig = 'd'; - - var nowIsMonotonic = 1; - - var checkWasiClock = (clock_id) => clock_id >= 0 && clock_id <= 3; - var _clock_res_get = (clk_id, pres) => { - if (!checkWasiClock(clk_id)) { - return 28; - } - var nsec; - // all wasi clocks but realtime are monotonic - if (clk_id === 0) { - nsec = 1000 * 1000; // educated guess that it's milliseconds - } else if (nowIsMonotonic) { - nsec = _emscripten_get_now_res(); - } else { - return 52; - } - HEAP64[pres >> 3] = BigInt(nsec); - return 0; - }; - _clock_res_get.sig = 'iip'; - - var _emscripten_date_now = () => Date.now(); - _emscripten_date_now.sig = 'd'; - - function _clock_time_get(clk_id, ignored_precision, ptime) { - ignored_precision = bigintToI53Checked(ignored_precision); - - if (!checkWasiClock(clk_id)) { - return 28; - } - var now; - // all wasi clocks but realtime are monotonic - if (clk_id === 0) { - now = _emscripten_date_now(); - } else if (nowIsMonotonic) { - now = _emscripten_get_now(); - } else { - return 52; - } - // "now" is in ms, and wasi times are in ns. - var nsec = Math.round(now * 1000 * 1000); - HEAP64[ptime >> 3] = BigInt(nsec); - return 0; - } - _clock_time_get.sig = 'iijp'; - - var _emscripten_alcDevicePauseSOFT = (deviceId) => { - if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = 40961; - return; - } - - if (AL.paused) { - return; - } - AL.paused = true; - - for (var ctxId in AL.contexts) { - var ctx = AL.contexts[ctxId]; - if (ctx.deviceId !== deviceId) { - continue; - } - - ctx.audioCtx.suspend(); - clearInterval(ctx.interval); - ctx.interval = null; - } - }; - _emscripten_alcDevicePauseSOFT.sig = 'vi'; - - var _emscripten_alcDeviceResumeSOFT = (deviceId) => { - if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = 40961; - return; - } - - if (!AL.paused) { - return; - } - AL.paused = false; - - for (var ctxId in AL.contexts) { - var ctx = AL.contexts[ctxId]; - if (ctx.deviceId !== deviceId) { - continue; - } - - ctx.interval = setInterval( - () => AL.scheduleContextAudio(ctx), - AL.QUEUE_INTERVAL - ); - ctx.audioCtx.resume(); - } - }; - _emscripten_alcDeviceResumeSOFT.sig = 'vi'; - - var _emscripten_alcGetStringiSOFT = (deviceId, param, index) => { - if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = 40961; - return 0; - } - - if (AL.alcStringCache[param]) { - return AL.alcStringCache[param]; - } - - var ret; - switch (param) { - case 0x1995 /* ALC_HRTF_SPECIFIER_SOFT */: - if (index === 0) { - ret = 'Web Audio HRTF'; - } else { - AL.alcErr = 40964; - return 0; - } - break; - default: - if (index !== 0) { - AL.alcErr = 40963; - return 0; - } - return _alcGetString(deviceId, param); - } - - ret = stringToNewUTF8(ret); - AL.alcStringCache[param] = ret; - return ret; - }; - _emscripten_alcGetStringiSOFT.sig = 'iiii'; - - var _emscripten_alcResetDeviceSOFT = (deviceId, pAttrList) => { - if (!(deviceId in AL.deviceRefCounts)) { - AL.alcErr = 40961; - return 0; - } - - var hrtf = null; - pAttrList >>= 2; - if (pAttrList) { - var attr = 0; - var val = 0; - while (true) { - attr = HEAP32[pAttrList++]; - if (attr === 0) { - break; - } - val = HEAP32[pAttrList++]; - - switch (attr) { - case 0x1992 /* ALC_HRTF_SOFT */: - if (val === 1) { - hrtf = true; - } else if (val === 0) { - hrtf = false; - } - break; - } - } - } - - if (hrtf !== null) { - // Apply hrtf attrib to all contexts for this device - for (var ctxId in AL.contexts) { - var ctx = AL.contexts[ctxId]; - if (ctx.deviceId === deviceId) { - ctx.hrtf = hrtf; - AL.updateContextGlobal(ctx); - } - } - } - - return 1; - }; - _emscripten_alcResetDeviceSOFT.sig = 'iii'; - - var readEmAsmArgsArray = []; - var readEmAsmArgs = (sigPtr, buf) => { - readEmAsmArgsArray.length = 0; - var ch; - // Most arguments are i32s, so shift the buffer pointer so it is a plain - // index into HEAP32. - while ((ch = HEAPU8[sigPtr++])) { - // Floats are always passed as doubles, so all types except for 'i' - // are 8 bytes and require alignment. - var wide = ch != 105; - wide &= ch != 112; - buf += wide && buf % 8 ? 4 : 0; - readEmAsmArgsArray.push( - // Special case for pointers under wasm64 or CAN_ADDRESS_2GB mode. - ch == 112 - ? HEAPU32[buf >> 2] - : ch == 106 - ? HEAP64[buf >> 3] - : ch == 105 - ? HEAP32[buf >> 2] - : HEAPF64[buf >> 3] - ); - buf += wide ? 8 : 4; - } - return readEmAsmArgsArray; - }; - var runEmAsmFunction = (code, sigPtr, argbuf) => { - var args = readEmAsmArgs(sigPtr, argbuf); - return ASM_CONSTS[code](...args); - }; - var _emscripten_asm_const_int = (code, sigPtr, argbuf) => { - return runEmAsmFunction(code, sigPtr, argbuf); - }; - _emscripten_asm_const_int.sig = 'ippp'; - - var _emscripten_console_error = (str) => { - console.error(UTF8ToString(str)); - }; - _emscripten_console_error.sig = 'vp'; - - var _emscripten_console_log = (str) => { - console.log(UTF8ToString(str)); - }; - _emscripten_console_log.sig = 'vp'; - - var _emscripten_console_trace = (str) => { - console.trace(UTF8ToString(str)); - }; - _emscripten_console_trace.sig = 'vp'; - - var _emscripten_console_warn = (str) => { - console.warn(UTF8ToString(str)); - }; - _emscripten_console_warn.sig = 'vp'; - - var _emscripten_err = (str) => err(UTF8ToString(str)); - _emscripten_err.sig = 'vp'; - - var getHeapMax = () => - // Stay one Wasm page short of 4GB: while e.g. Chrome is able to allocate - // full 4GB Wasm memories, the size will wrap back to 0 bytes in Wasm side - // for any code that deals with heap sizes, which would require special - // casing all heap size related code to treat 0 specially. - 2147483648; - var _emscripten_get_heap_max = () => getHeapMax(); - _emscripten_get_heap_max.sig = 'p'; - - var GLctx; - - var webgl_enable_ANGLE_instanced_arrays = (ctx) => { - // Extension available in WebGL 1 from Firefox 26 and Google Chrome 30 onwards. Core feature in WebGL 2. - var ext = ctx.getExtension('ANGLE_instanced_arrays'); - // Because this extension is a core function in WebGL 2, assign the extension entry points in place of - // where the core functions will reside in WebGL 2. This way the calling code can call these without - // having to dynamically branch depending if running against WebGL 1 or WebGL 2. - if (ext) { - ctx['vertexAttribDivisor'] = (index, divisor) => - ext['vertexAttribDivisorANGLE'](index, divisor); - ctx['drawArraysInstanced'] = (mode, first, count, primcount) => - ext['drawArraysInstancedANGLE'](mode, first, count, primcount); - ctx['drawElementsInstanced'] = ( - mode, - count, - type, - indices, - primcount - ) => - ext['drawElementsInstancedANGLE']( - mode, - count, - type, - indices, - primcount - ); - return 1; - } - }; - - var webgl_enable_OES_vertex_array_object = (ctx) => { - // Extension available in WebGL 1 from Firefox 25 and WebKit 536.28/desktop Safari 6.0.3 onwards. Core feature in WebGL 2. - var ext = ctx.getExtension('OES_vertex_array_object'); - if (ext) { - ctx['createVertexArray'] = () => ext['createVertexArrayOES'](); - ctx['deleteVertexArray'] = (vao) => - ext['deleteVertexArrayOES'](vao); - ctx['bindVertexArray'] = (vao) => ext['bindVertexArrayOES'](vao); - ctx['isVertexArray'] = (vao) => ext['isVertexArrayOES'](vao); - return 1; - } - }; - - var webgl_enable_WEBGL_draw_buffers = (ctx) => { - // Extension available in WebGL 1 from Firefox 28 onwards. Core feature in WebGL 2. - var ext = ctx.getExtension('WEBGL_draw_buffers'); - if (ext) { - ctx['drawBuffers'] = (n, bufs) => ext['drawBuffersWEBGL'](n, bufs); - return 1; - } - }; - - var webgl_enable_EXT_polygon_offset_clamp = (ctx) => - !!(ctx.extPolygonOffsetClamp = ctx.getExtension( - 'EXT_polygon_offset_clamp' - )); - - var webgl_enable_EXT_clip_control = (ctx) => - !!(ctx.extClipControl = ctx.getExtension('EXT_clip_control')); - - var webgl_enable_WEBGL_polygon_mode = (ctx) => - !!(ctx.webglPolygonMode = ctx.getExtension('WEBGL_polygon_mode')); - - var webgl_enable_WEBGL_multi_draw = (ctx) => - // Closure is expected to be allowed to minify the '.multiDrawWebgl' property, so not accessing it quoted. - !!(ctx.multiDrawWebgl = ctx.getExtension('WEBGL_multi_draw')); - - var getEmscriptenSupportedExtensions = (ctx) => { - // Restrict the list of advertised extensions to those that we actually - // support. - var supportedExtensions = [ - // WebGL 1 extensions - 'ANGLE_instanced_arrays', - 'EXT_blend_minmax', - 'EXT_disjoint_timer_query', - 'EXT_frag_depth', - 'EXT_shader_texture_lod', - 'EXT_sRGB', - 'OES_element_index_uint', - 'OES_fbo_render_mipmap', - 'OES_standard_derivatives', - 'OES_texture_float', - 'OES_texture_half_float', - 'OES_texture_half_float_linear', - 'OES_vertex_array_object', - 'WEBGL_color_buffer_float', - 'WEBGL_depth_texture', - 'WEBGL_draw_buffers', - // WebGL 1 and WebGL 2 extensions - 'EXT_clip_control', - 'EXT_color_buffer_half_float', - 'EXT_depth_clamp', - 'EXT_float_blend', - 'EXT_polygon_offset_clamp', - 'EXT_texture_compression_bptc', - 'EXT_texture_compression_rgtc', - 'EXT_texture_filter_anisotropic', - 'KHR_parallel_shader_compile', - 'OES_texture_float_linear', - 'WEBGL_blend_func_extended', - 'WEBGL_compressed_texture_astc', - 'WEBGL_compressed_texture_etc', - 'WEBGL_compressed_texture_etc1', - 'WEBGL_compressed_texture_s3tc', - 'WEBGL_compressed_texture_s3tc_srgb', - 'WEBGL_debug_renderer_info', - 'WEBGL_debug_shaders', - 'WEBGL_lose_context', - 'WEBGL_multi_draw', - 'WEBGL_polygon_mode', - ]; - // .getSupportedExtensions() can return null if context is lost, so coerce to empty array. - return (ctx.getSupportedExtensions() || []).filter((ext) => - supportedExtensions.includes(ext) - ); - }; - - var GL = { - counter: 1, - buffers: [], - programs: [], - framebuffers: [], - renderbuffers: [], - textures: [], - shaders: [], - vaos: [], - contexts: [], - offscreenCanvases: {}, - queries: [], - stringCache: {}, - unpackAlignment: 4, - unpackRowLength: 0, - recordError: (errorCode) => { - if (!GL.lastError) { - GL.lastError = errorCode; - } - }, - getNewId: (table) => { - var ret = GL.counter++; - for (var i = table.length; i < ret; i++) { - table[i] = null; - } - return ret; - }, - genObject: (n, buffers, createFunction, objectTable) => { - for (var i = 0; i < n; i++) { - var buffer = GLctx[createFunction](); - var id = buffer && GL.getNewId(objectTable); - if (buffer) { - buffer.name = id; - objectTable[id] = buffer; - } else { - GL.recordError(0x502 /* GL_INVALID_OPERATION */); - } - HEAP32[(buffers + i * 4) >> 2] = id; - } - }, - getSource: (shader, count, string, length) => { - var source = ''; - for (var i = 0; i < count; ++i) { - var len = length ? HEAPU32[(length + i * 4) >> 2] : undefined; - source += UTF8ToString(HEAPU32[(string + i * 4) >> 2], len); - } - return source; - }, - createContext: ( - /** @type {HTMLCanvasElement} */ canvas, - webGLContextAttributes - ) => { - var ctx = canvas.getContext('webgl', webGLContextAttributes); - - if (!ctx) return 0; - - var handle = GL.registerContext(ctx, webGLContextAttributes); - - return handle; - }, - registerContext: (ctx, webGLContextAttributes) => { - // without pthreads a context is just an integer ID - var handle = GL.getNewId(GL.contexts); - - var context = { - handle, - attributes: webGLContextAttributes, - version: webGLContextAttributes.majorVersion, - GLctx: ctx, - }; - - // Store the created context object so that we can access the context - // given a canvas without having to pass the parameters again. - if (ctx.canvas) ctx.canvas.GLctxObject = context; - GL.contexts[handle] = context; - if ( - typeof webGLContextAttributes.enableExtensionsByDefault == - 'undefined' || - webGLContextAttributes.enableExtensionsByDefault - ) { - GL.initExtensions(context); - } - - return handle; - }, - makeContextCurrent: (contextHandle) => { - // Active Emscripten GL layer context object. - GL.currentContext = GL.contexts[contextHandle]; - // Active WebGL context object. - Module['ctx'] = GLctx = GL.currentContext?.GLctx; - return !(contextHandle && !GLctx); - }, - getContext: (contextHandle) => { - return GL.contexts[contextHandle]; - }, - deleteContext: (contextHandle) => { - if (GL.currentContext === GL.contexts[contextHandle]) { - GL.currentContext = null; - } - if (typeof JSEvents == 'object') { - // Release all JS event handlers on the DOM element that the GL context is - // associated with since the context is now deleted. - JSEvents.removeAllHandlersOnTarget( - GL.contexts[contextHandle].GLctx.canvas - ); - } - // Make sure the canvas object no longer refers to the context object so - // there are no GC surprises. - if (GL.contexts[contextHandle]?.GLctx.canvas) { - GL.contexts[contextHandle].GLctx.canvas.GLctxObject = undefined; - } - GL.contexts[contextHandle] = null; - }, - initExtensions: (context) => { - // If this function is called without a specific context object, init the - // extensions of the currently active context. - context ||= GL.currentContext; - - if (context.initExtensionsDone) return; - context.initExtensionsDone = true; - - var GLctx = context.GLctx; - - // Detect the presence of a few extensions manually, ction GL interop - // layer itself will need to know if they exist. - - // Extensions that are available in both WebGL 1 and WebGL 2 - webgl_enable_WEBGL_multi_draw(GLctx); - webgl_enable_EXT_polygon_offset_clamp(GLctx); - webgl_enable_EXT_clip_control(GLctx); - webgl_enable_WEBGL_polygon_mode(GLctx); - // Extensions that are only available in WebGL 1 (the calls will be no-ops - // if called on a WebGL 2 context active) - webgl_enable_ANGLE_instanced_arrays(GLctx); - webgl_enable_OES_vertex_array_object(GLctx); - webgl_enable_WEBGL_draw_buffers(GLctx); - { - GLctx.disjointTimerQueryExt = GLctx.getExtension( - 'EXT_disjoint_timer_query' - ); - } - - for (var ext of getEmscriptenSupportedExtensions(GLctx)) { - // WEBGL_lose_context, WEBGL_debug_renderer_info and WEBGL_debug_shaders - // are not enabled by default. - if (!ext.includes('lose_context') && !ext.includes('debug')) { - // Call .getExtension() to enable that extension permanently. - GLctx.getExtension(ext); - } - } - }, - }; - var _emscripten_glActiveTexture = (x0) => GLctx.activeTexture(x0); - _emscripten_glActiveTexture.sig = 'vi'; - - var _emscripten_glAttachShader = (program, shader) => { - GLctx.attachShader(GL.programs[program], GL.shaders[shader]); - }; - _emscripten_glAttachShader.sig = 'vii'; - - var _emscripten_glBeginQueryEXT = (target, id) => { - GLctx.disjointTimerQueryExt['beginQueryEXT'](target, GL.queries[id]); - }; - _emscripten_glBeginQueryEXT.sig = 'vii'; - - var _emscripten_glBindAttribLocation = (program, index, name) => { - GLctx.bindAttribLocation( - GL.programs[program], - index, - UTF8ToString(name) - ); - }; - _emscripten_glBindAttribLocation.sig = 'viip'; - - var _emscripten_glBindBuffer = (target, buffer) => { - GLctx.bindBuffer(target, GL.buffers[buffer]); - }; - _emscripten_glBindBuffer.sig = 'vii'; - - var _emscripten_glBindFramebuffer = (target, framebuffer) => { - GLctx.bindFramebuffer(target, GL.framebuffers[framebuffer]); - }; - _emscripten_glBindFramebuffer.sig = 'vii'; - - var _emscripten_glBindRenderbuffer = (target, renderbuffer) => { - GLctx.bindRenderbuffer(target, GL.renderbuffers[renderbuffer]); - }; - _emscripten_glBindRenderbuffer.sig = 'vii'; - - var _emscripten_glBindTexture = (target, texture) => { - GLctx.bindTexture(target, GL.textures[texture]); - }; - _emscripten_glBindTexture.sig = 'vii'; - - var _emscripten_glBindVertexArray = (vao) => { - GLctx.bindVertexArray(GL.vaos[vao]); - }; - _emscripten_glBindVertexArray.sig = 'vi'; - var _emscripten_glBindVertexArrayOES = _emscripten_glBindVertexArray; - _emscripten_glBindVertexArrayOES.sig = 'vi'; - - var _emscripten_glBlendColor = (x0, x1, x2, x3) => - GLctx.blendColor(x0, x1, x2, x3); - _emscripten_glBlendColor.sig = 'vffff'; - - var _emscripten_glBlendEquation = (x0) => GLctx.blendEquation(x0); - _emscripten_glBlendEquation.sig = 'vi'; - - var _emscripten_glBlendEquationSeparate = (x0, x1) => - GLctx.blendEquationSeparate(x0, x1); - _emscripten_glBlendEquationSeparate.sig = 'vii'; - - var _emscripten_glBlendFunc = (x0, x1) => GLctx.blendFunc(x0, x1); - _emscripten_glBlendFunc.sig = 'vii'; - - var _emscripten_glBlendFuncSeparate = (x0, x1, x2, x3) => - GLctx.blendFuncSeparate(x0, x1, x2, x3); - _emscripten_glBlendFuncSeparate.sig = 'viiii'; - - var _emscripten_glBufferData = (target, size, data, usage) => { - // N.b. here first form specifies a heap subarray, second form an integer - // size, so the ?: code here is polymorphic. It is advised to avoid - // randomly mixing both uses in calling code, to avoid any potential JS - // engine JIT issues. - GLctx.bufferData( - target, - data ? HEAPU8.subarray(data, data + size) : size, - usage - ); - }; - _emscripten_glBufferData.sig = 'vippi'; - - var _emscripten_glBufferSubData = (target, offset, size, data) => { - GLctx.bufferSubData(target, offset, HEAPU8.subarray(data, data + size)); - }; - _emscripten_glBufferSubData.sig = 'vippp'; - - var _emscripten_glCheckFramebufferStatus = (x0) => - GLctx.checkFramebufferStatus(x0); - _emscripten_glCheckFramebufferStatus.sig = 'ii'; - - var _emscripten_glClear = (x0) => GLctx.clear(x0); - _emscripten_glClear.sig = 'vi'; - - var _emscripten_glClearColor = (x0, x1, x2, x3) => - GLctx.clearColor(x0, x1, x2, x3); - _emscripten_glClearColor.sig = 'vffff'; - - var _emscripten_glClearDepthf = (x0) => GLctx.clearDepth(x0); - _emscripten_glClearDepthf.sig = 'vf'; - - var _emscripten_glClearStencil = (x0) => GLctx.clearStencil(x0); - _emscripten_glClearStencil.sig = 'vi'; - - var _emscripten_glClipControlEXT = (origin, depth) => { - GLctx.extClipControl['clipControlEXT'](origin, depth); - }; - _emscripten_glClipControlEXT.sig = 'vii'; - - var _emscripten_glColorMask = (red, green, blue, alpha) => { - GLctx.colorMask(!!red, !!green, !!blue, !!alpha); - }; - _emscripten_glColorMask.sig = 'viiii'; - - var _emscripten_glCompileShader = (shader) => { - GLctx.compileShader(GL.shaders[shader]); - }; - _emscripten_glCompileShader.sig = 'vi'; - - var _emscripten_glCompressedTexImage2D = ( - target, - level, - internalFormat, - width, - height, - border, - imageSize, - data - ) => { - // `data` may be null here, which means "allocate uniniitalized space but - // don't upload" in GLES parlance, but `compressedTexImage2D` requires the - // final data parameter, so we simply pass a heap view starting at zero - // effectively uploading whatever happens to be near address zero. See - // https://github.com/emscripten-core/emscripten/issues/19300. - GLctx.compressedTexImage2D( - target, - level, - internalFormat, - width, - height, - border, - HEAPU8.subarray(data, data + imageSize) - ); - }; - _emscripten_glCompressedTexImage2D.sig = 'viiiiiiip'; - - var _emscripten_glCompressedTexSubImage2D = ( - target, - level, - xoffset, - yoffset, - width, - height, - format, - imageSize, - data - ) => { - GLctx.compressedTexSubImage2D( - target, - level, - xoffset, - yoffset, - width, - height, - format, - HEAPU8.subarray(data, data + imageSize) - ); - }; - _emscripten_glCompressedTexSubImage2D.sig = 'viiiiiiiip'; - - var _emscripten_glCopyTexImage2D = (x0, x1, x2, x3, x4, x5, x6, x7) => - GLctx.copyTexImage2D(x0, x1, x2, x3, x4, x5, x6, x7); - _emscripten_glCopyTexImage2D.sig = 'viiiiiiii'; - - var _emscripten_glCopyTexSubImage2D = (x0, x1, x2, x3, x4, x5, x6, x7) => - GLctx.copyTexSubImage2D(x0, x1, x2, x3, x4, x5, x6, x7); - _emscripten_glCopyTexSubImage2D.sig = 'viiiiiiii'; - - var _emscripten_glCreateProgram = () => { - var id = GL.getNewId(GL.programs); - var program = GLctx.createProgram(); - // Store additional information needed for each shader program: - program.name = id; - // Lazy cache results of - // glGetProgramiv(GL_ACTIVE_UNIFORM_MAX_LENGTH/GL_ACTIVE_ATTRIBUTE_MAX_LENGTH/GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH) - program.maxUniformLength = - program.maxAttributeLength = - program.maxUniformBlockNameLength = - 0; - program.uniformIdCounter = 1; - GL.programs[id] = program; - return id; - }; - _emscripten_glCreateProgram.sig = 'i'; - - var _emscripten_glCreateShader = (shaderType) => { - var id = GL.getNewId(GL.shaders); - GL.shaders[id] = GLctx.createShader(shaderType); - - return id; - }; - _emscripten_glCreateShader.sig = 'ii'; - - var _emscripten_glCullFace = (x0) => GLctx.cullFace(x0); - _emscripten_glCullFace.sig = 'vi'; - - var _emscripten_glDeleteBuffers = (n, buffers) => { - for (var i = 0; i < n; i++) { - var id = HEAP32[(buffers + i * 4) >> 2]; - var buffer = GL.buffers[id]; - - // From spec: "glDeleteBuffers silently ignores 0's and names that do not - // correspond to existing buffer objects." - if (!buffer) continue; - - GLctx.deleteBuffer(buffer); - buffer.name = 0; - GL.buffers[id] = null; - } - }; - _emscripten_glDeleteBuffers.sig = 'vip'; - - var _emscripten_glDeleteFramebuffers = (n, framebuffers) => { - for (var i = 0; i < n; ++i) { - var id = HEAP32[(framebuffers + i * 4) >> 2]; - var framebuffer = GL.framebuffers[id]; - if (!framebuffer) continue; // GL spec: "glDeleteFramebuffers silently ignores 0s and names that do not correspond to existing framebuffer objects". - GLctx.deleteFramebuffer(framebuffer); - framebuffer.name = 0; - GL.framebuffers[id] = null; - } - }; - _emscripten_glDeleteFramebuffers.sig = 'vip'; - - var _emscripten_glDeleteProgram = (id) => { - if (!id) return; - var program = GL.programs[id]; - if (!program) { - // glDeleteProgram actually signals an error when deleting a nonexisting - // object, unlike some other GL delete functions. - GL.recordError(0x501 /* GL_INVALID_VALUE */); - return; - } - GLctx.deleteProgram(program); - program.name = 0; - GL.programs[id] = null; - }; - _emscripten_glDeleteProgram.sig = 'vi'; - - var _emscripten_glDeleteQueriesEXT = (n, ids) => { - for (var i = 0; i < n; i++) { - var id = HEAP32[(ids + i * 4) >> 2]; - var query = GL.queries[id]; - if (!query) continue; // GL spec: "unused names in ids are ignored, as is the name zero." - GLctx.disjointTimerQueryExt['deleteQueryEXT'](query); - GL.queries[id] = null; - } - }; - _emscripten_glDeleteQueriesEXT.sig = 'vip'; - - var _emscripten_glDeleteRenderbuffers = (n, renderbuffers) => { - for (var i = 0; i < n; i++) { - var id = HEAP32[(renderbuffers + i * 4) >> 2]; - var renderbuffer = GL.renderbuffers[id]; - if (!renderbuffer) continue; // GL spec: "glDeleteRenderbuffers silently ignores 0s and names that do not correspond to existing renderbuffer objects". - GLctx.deleteRenderbuffer(renderbuffer); - renderbuffer.name = 0; - GL.renderbuffers[id] = null; - } - }; - _emscripten_glDeleteRenderbuffers.sig = 'vip'; - - var _emscripten_glDeleteShader = (id) => { - if (!id) return; - var shader = GL.shaders[id]; - if (!shader) { - // glDeleteShader actually signals an error when deleting a nonexisting - // object, unlike some other GL delete functions. - GL.recordError(0x501 /* GL_INVALID_VALUE */); - return; - } - GLctx.deleteShader(shader); - GL.shaders[id] = null; - }; - _emscripten_glDeleteShader.sig = 'vi'; - - var _emscripten_glDeleteTextures = (n, textures) => { - for (var i = 0; i < n; i++) { - var id = HEAP32[(textures + i * 4) >> 2]; - var texture = GL.textures[id]; - // GL spec: "glDeleteTextures silently ignores 0s and names that do not - // correspond to existing textures". - if (!texture) continue; - GLctx.deleteTexture(texture); - texture.name = 0; - GL.textures[id] = null; - } - }; - _emscripten_glDeleteTextures.sig = 'vip'; - - var _emscripten_glDeleteVertexArrays = (n, vaos) => { - for (var i = 0; i < n; i++) { - var id = HEAP32[(vaos + i * 4) >> 2]; - GLctx.deleteVertexArray(GL.vaos[id]); - GL.vaos[id] = null; - } - }; - _emscripten_glDeleteVertexArrays.sig = 'vip'; - var _emscripten_glDeleteVertexArraysOES = _emscripten_glDeleteVertexArrays; - _emscripten_glDeleteVertexArraysOES.sig = 'vip'; - - var _emscripten_glDepthFunc = (x0) => GLctx.depthFunc(x0); - _emscripten_glDepthFunc.sig = 'vi'; - - var _emscripten_glDepthMask = (flag) => { - GLctx.depthMask(!!flag); - }; - _emscripten_glDepthMask.sig = 'vi'; - - var _emscripten_glDepthRangef = (x0, x1) => GLctx.depthRange(x0, x1); - _emscripten_glDepthRangef.sig = 'vff'; - - var _emscripten_glDetachShader = (program, shader) => { - GLctx.detachShader(GL.programs[program], GL.shaders[shader]); - }; - _emscripten_glDetachShader.sig = 'vii'; - - var _emscripten_glDisable = (x0) => GLctx.disable(x0); - _emscripten_glDisable.sig = 'vi'; - - var _emscripten_glDisableVertexAttribArray = (index) => { - GLctx.disableVertexAttribArray(index); - }; - _emscripten_glDisableVertexAttribArray.sig = 'vi'; - - var _emscripten_glDrawArrays = (mode, first, count) => { - GLctx.drawArrays(mode, first, count); - }; - _emscripten_glDrawArrays.sig = 'viii'; - - var _emscripten_glDrawArraysInstanced = (mode, first, count, primcount) => { - GLctx.drawArraysInstanced(mode, first, count, primcount); - }; - _emscripten_glDrawArraysInstanced.sig = 'viiii'; - var _emscripten_glDrawArraysInstancedANGLE = - _emscripten_glDrawArraysInstanced; - - var tempFixedLengthArray = []; - - var _emscripten_glDrawBuffers = (n, bufs) => { - var bufArray = tempFixedLengthArray[n]; - for (var i = 0; i < n; i++) { - bufArray[i] = HEAP32[(bufs + i * 4) >> 2]; - } - - GLctx.drawBuffers(bufArray); - }; - _emscripten_glDrawBuffers.sig = 'vip'; - var _emscripten_glDrawBuffersWEBGL = _emscripten_glDrawBuffers; - - var _emscripten_glDrawElements = (mode, count, type, indices) => { - GLctx.drawElements(mode, count, type, indices); - }; - _emscripten_glDrawElements.sig = 'viiip'; - - var _emscripten_glDrawElementsInstanced = ( - mode, - count, - type, - indices, - primcount - ) => { - GLctx.drawElementsInstanced(mode, count, type, indices, primcount); - }; - _emscripten_glDrawElementsInstanced.sig = 'viiipi'; - var _emscripten_glDrawElementsInstancedANGLE = - _emscripten_glDrawElementsInstanced; - - var _emscripten_glEnable = (x0) => GLctx.enable(x0); - _emscripten_glEnable.sig = 'vi'; - - var _emscripten_glEnableVertexAttribArray = (index) => { - GLctx.enableVertexAttribArray(index); - }; - _emscripten_glEnableVertexAttribArray.sig = 'vi'; - - var _emscripten_glEndQueryEXT = (target) => { - GLctx.disjointTimerQueryExt['endQueryEXT'](target); - }; - _emscripten_glEndQueryEXT.sig = 'vi'; - - var _emscripten_glFinish = () => GLctx.finish(); - _emscripten_glFinish.sig = 'v'; - - var _emscripten_glFlush = () => GLctx.flush(); - _emscripten_glFlush.sig = 'v'; - - var _emscripten_glFramebufferRenderbuffer = ( - target, - attachment, - renderbuffertarget, - renderbuffer - ) => { - GLctx.framebufferRenderbuffer( - target, - attachment, - renderbuffertarget, - GL.renderbuffers[renderbuffer] - ); - }; - _emscripten_glFramebufferRenderbuffer.sig = 'viiii'; - - var _emscripten_glFramebufferTexture2D = ( - target, - attachment, - textarget, - texture, - level - ) => { - GLctx.framebufferTexture2D( - target, - attachment, - textarget, - GL.textures[texture], - level - ); - }; - _emscripten_glFramebufferTexture2D.sig = 'viiiii'; - - var _emscripten_glFrontFace = (x0) => GLctx.frontFace(x0); - _emscripten_glFrontFace.sig = 'vi'; - - var _emscripten_glGenBuffers = (n, buffers) => { - GL.genObject(n, buffers, 'createBuffer', GL.buffers); - }; - _emscripten_glGenBuffers.sig = 'vip'; - - var _emscripten_glGenFramebuffers = (n, ids) => { - GL.genObject(n, ids, 'createFramebuffer', GL.framebuffers); - }; - _emscripten_glGenFramebuffers.sig = 'vip'; - - var _emscripten_glGenQueriesEXT = (n, ids) => { - for (var i = 0; i < n; i++) { - var query = GLctx.disjointTimerQueryExt['createQueryEXT'](); - if (!query) { - GL.recordError(0x502 /* GL_INVALID_OPERATION */); - while (i < n) HEAP32[(ids + i++ * 4) >> 2] = 0; - return; - } - var id = GL.getNewId(GL.queries); - query.name = id; - GL.queries[id] = query; - HEAP32[(ids + i * 4) >> 2] = id; - } - }; - _emscripten_glGenQueriesEXT.sig = 'vip'; - - var _emscripten_glGenRenderbuffers = (n, renderbuffers) => { - GL.genObject(n, renderbuffers, 'createRenderbuffer', GL.renderbuffers); - }; - _emscripten_glGenRenderbuffers.sig = 'vip'; - - var _emscripten_glGenTextures = (n, textures) => { - GL.genObject(n, textures, 'createTexture', GL.textures); - }; - _emscripten_glGenTextures.sig = 'vip'; - - var _emscripten_glGenVertexArrays = (n, arrays) => { - GL.genObject(n, arrays, 'createVertexArray', GL.vaos); - }; - _emscripten_glGenVertexArrays.sig = 'vip'; - var _emscripten_glGenVertexArraysOES = _emscripten_glGenVertexArrays; - _emscripten_glGenVertexArraysOES.sig = 'vip'; - - var _emscripten_glGenerateMipmap = (x0) => GLctx.generateMipmap(x0); - _emscripten_glGenerateMipmap.sig = 'vi'; - - var __glGetActiveAttribOrUniform = ( - funcName, - program, - index, - bufSize, - length, - size, - type, - name - ) => { - program = GL.programs[program]; - var info = GLctx[funcName](program, index); - if (info) { - // If an error occurs, nothing will be written to length, size and type and name. - var numBytesWrittenExclNull = - name && stringToUTF8(info.name, name, bufSize); - if (length) HEAP32[length >> 2] = numBytesWrittenExclNull; - if (size) HEAP32[size >> 2] = info.size; - if (type) HEAP32[type >> 2] = info.type; - } - }; - - var _emscripten_glGetActiveAttrib = ( - program, - index, - bufSize, - length, - size, - type, - name - ) => - __glGetActiveAttribOrUniform( - 'getActiveAttrib', - program, - index, - bufSize, - length, - size, - type, - name - ); - _emscripten_glGetActiveAttrib.sig = 'viiipppp'; - - var _emscripten_glGetActiveUniform = ( - program, - index, - bufSize, - length, - size, - type, - name - ) => - __glGetActiveAttribOrUniform( - 'getActiveUniform', - program, - index, - bufSize, - length, - size, - type, - name - ); - _emscripten_glGetActiveUniform.sig = 'viiipppp'; - - var _emscripten_glGetAttachedShaders = ( - program, - maxCount, - count, - shaders - ) => { - var result = GLctx.getAttachedShaders(GL.programs[program]); - var len = result.length; - if (len > maxCount) { - len = maxCount; - } - HEAP32[count >> 2] = len; - for (var i = 0; i < len; ++i) { - var id = GL.shaders.indexOf(result[i]); - HEAP32[(shaders + i * 4) >> 2] = id; - } - }; - _emscripten_glGetAttachedShaders.sig = 'viipp'; - - var _emscripten_glGetAttribLocation = (program, name) => - GLctx.getAttribLocation(GL.programs[program], UTF8ToString(name)); - _emscripten_glGetAttribLocation.sig = 'iip'; - - var writeI53ToI64 = (ptr, num) => { - HEAPU32[ptr >> 2] = num; - var lower = HEAPU32[ptr >> 2]; - HEAPU32[(ptr + 4) >> 2] = (num - lower) / 4294967296; - }; - - var emscriptenWebGLGet = (name_, p, type) => { - // Guard against user passing a null pointer. - // Note that GLES2 spec does not say anything about how passing a null - // pointer should be treated. Testing on desktop core GL 3, the application - // crashes on glGetIntegerv to a null pointer, but better to report an error - // instead of doing anything random. - if (!p) { - GL.recordError(0x501 /* GL_INVALID_VALUE */); - return; - } - var ret = undefined; - switch ( - name_ // Handle a few trivial GLES values - ) { - case 0x8dfa: // GL_SHADER_COMPILER - ret = 1; - break; - case 0x8df8: // GL_SHADER_BINARY_FORMATS - if (type != 0 && type != 1) { - GL.recordError(0x500); // GL_INVALID_ENUM - } - // Do not write anything to the out pointer, since no binary formats are - // supported. - return; - case 0x8df9: // GL_NUM_SHADER_BINARY_FORMATS - ret = 0; - break; - case 0x86a2: // GL_NUM_COMPRESSED_TEXTURE_FORMATS - // WebGL doesn't have GL_NUM_COMPRESSED_TEXTURE_FORMATS (it's obsolete - // since GL_COMPRESSED_TEXTURE_FORMATS returns a JS array that can be - // queried for length), so implement it ourselves to allow C++ GLES2 - // code get the length. - var formats = GLctx.getParameter( - 0x86a3 /*GL_COMPRESSED_TEXTURE_FORMATS*/ - ); - ret = formats ? formats.length : 0; - break; - } - - if (ret === undefined) { - var result = GLctx.getParameter(name_); - switch (typeof result) { - case 'number': - ret = result; - break; - case 'boolean': - ret = result ? 1 : 0; - break; - case 'string': - GL.recordError(0x500); // GL_INVALID_ENUM - return; - case 'object': - if (result === null) { - // null is a valid result for some (e.g., which buffer is bound - - // perhaps nothing is bound), but otherwise can mean an invalid - // name_, which we need to report as an error - switch (name_) { - case 0x8894: // ARRAY_BUFFER_BINDING - case 0x8b8d: // CURRENT_PROGRAM - case 0x8895: // ELEMENT_ARRAY_BUFFER_BINDING - case 0x8ca6: // FRAMEBUFFER_BINDING or DRAW_FRAMEBUFFER_BINDING - case 0x8ca7: // RENDERBUFFER_BINDING - case 0x8069: // TEXTURE_BINDING_2D - case 0x85b5: // WebGL 2 GL_VERTEX_ARRAY_BINDING, or WebGL 1 extension OES_vertex_array_object GL_VERTEX_ARRAY_BINDING_OES - case 0x8514: { - // TEXTURE_BINDING_CUBE_MAP - ret = 0; - break; - } - default: { - GL.recordError(0x500); // GL_INVALID_ENUM - return; - } - } - } else if ( - result instanceof Float32Array || - result instanceof Uint32Array || - result instanceof Int32Array || - result instanceof Array - ) { - for (var i = 0; i < result.length; ++i) { - switch (type) { - case 0: - HEAP32[(p + i * 4) >> 2] = result[i]; - break; - case 2: - HEAPF32[(p + i * 4) >> 2] = result[i]; - break; - case 4: - HEAP8[p + i] = result[i] ? 1 : 0; - break; - } - } - return; - } else { - try { - ret = result.name | 0; - } catch (e) { - GL.recordError(0x500); // GL_INVALID_ENUM - err( - `GL_INVALID_ENUM in glGet${type}v: Unknown object returned from WebGL getParameter(${name_})! (error: ${e})` - ); - return; - } - } - break; - default: - GL.recordError(0x500); // GL_INVALID_ENUM - err( - `GL_INVALID_ENUM in glGet${type}v: Native code calling glGet${type}v(${name_}) and it returns ${result} of type ${typeof result}!` - ); - return; - } - } - - switch (type) { - case 1: - writeI53ToI64(p, ret); - break; - case 0: - HEAP32[p >> 2] = ret; - break; - case 2: - HEAPF32[p >> 2] = ret; - break; - case 4: - HEAP8[p] = ret ? 1 : 0; - break; - } - }; - - var _emscripten_glGetBooleanv = (name_, p) => - emscriptenWebGLGet(name_, p, 4); - _emscripten_glGetBooleanv.sig = 'vip'; - - var _emscripten_glGetBufferParameteriv = (target, value, data) => { - if (!data) { - // GLES2 specification does not specify how to behave if data is a null - // pointer. Since calling this function does not make sense if data == - // null, issue a GL error to notify user about it. - GL.recordError(0x501 /* GL_INVALID_VALUE */); - return; - } - HEAP32[data >> 2] = GLctx.getBufferParameter(target, value); - }; - _emscripten_glGetBufferParameteriv.sig = 'viip'; - - var _emscripten_glGetError = () => { - var error = GLctx.getError() || GL.lastError; - GL.lastError = 0 /*GL_NO_ERROR*/; - return error; - }; - _emscripten_glGetError.sig = 'i'; - - var _emscripten_glGetFloatv = (name_, p) => emscriptenWebGLGet(name_, p, 2); - _emscripten_glGetFloatv.sig = 'vip'; - - var _emscripten_glGetFramebufferAttachmentParameteriv = ( - target, - attachment, - pname, - params - ) => { - var result = GLctx.getFramebufferAttachmentParameter( - target, - attachment, - pname - ); - if ( - result instanceof WebGLRenderbuffer || - result instanceof WebGLTexture - ) { - result = result.name | 0; - } - HEAP32[params >> 2] = result; - }; - _emscripten_glGetFramebufferAttachmentParameteriv.sig = 'viiip'; - - var _emscripten_glGetIntegerv = (name_, p) => - emscriptenWebGLGet(name_, p, 0); - _emscripten_glGetIntegerv.sig = 'vip'; - - var _emscripten_glGetProgramInfoLog = ( - program, - maxLength, - length, - infoLog - ) => { - var log = GLctx.getProgramInfoLog(GL.programs[program]); - if (log === null) log = '(unknown error)'; - var numBytesWrittenExclNull = - maxLength > 0 && infoLog - ? stringToUTF8(log, infoLog, maxLength) - : 0; - if (length) HEAP32[length >> 2] = numBytesWrittenExclNull; - }; - _emscripten_glGetProgramInfoLog.sig = 'viipp'; - - var _emscripten_glGetProgramiv = (program, pname, p) => { - if (!p) { - // GLES2 specification does not specify how to behave if p is a null - // pointer. Since calling this function does not make sense if p == null, - // issue a GL error to notify user about it. - GL.recordError(0x501 /* GL_INVALID_VALUE */); - return; - } - - if (program >= GL.counter) { - GL.recordError(0x501 /* GL_INVALID_VALUE */); - return; - } - - program = GL.programs[program]; - - if (pname == 0x8b84) { - // GL_INFO_LOG_LENGTH - var log = GLctx.getProgramInfoLog(program); - if (log === null) log = '(unknown error)'; - HEAP32[p >> 2] = log.length + 1; - } else if (pname == 0x8b87 /* GL_ACTIVE_UNIFORM_MAX_LENGTH */) { - if (!program.maxUniformLength) { - var numActiveUniforms = GLctx.getProgramParameter( - program, - 0x8b86 /*GL_ACTIVE_UNIFORMS*/ - ); - for (var i = 0; i < numActiveUniforms; ++i) { - program.maxUniformLength = Math.max( - program.maxUniformLength, - GLctx.getActiveUniform(program, i).name.length + 1 - ); - } - } - HEAP32[p >> 2] = program.maxUniformLength; - } else if (pname == 0x8b8a /* GL_ACTIVE_ATTRIBUTE_MAX_LENGTH */) { - if (!program.maxAttributeLength) { - var numActiveAttributes = GLctx.getProgramParameter( - program, - 0x8b89 /*GL_ACTIVE_ATTRIBUTES*/ - ); - for (var i = 0; i < numActiveAttributes; ++i) { - program.maxAttributeLength = Math.max( - program.maxAttributeLength, - GLctx.getActiveAttrib(program, i).name.length + 1 - ); - } - } - HEAP32[p >> 2] = program.maxAttributeLength; - } else if ( - pname == 0x8a35 /* GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH */ - ) { - if (!program.maxUniformBlockNameLength) { - var numActiveUniformBlocks = GLctx.getProgramParameter( - program, - 0x8a36 /*GL_ACTIVE_UNIFORM_BLOCKS*/ - ); - for (var i = 0; i < numActiveUniformBlocks; ++i) { - program.maxUniformBlockNameLength = Math.max( - program.maxUniformBlockNameLength, - GLctx.getActiveUniformBlockName(program, i).length + 1 - ); - } - } - HEAP32[p >> 2] = program.maxUniformBlockNameLength; - } else { - HEAP32[p >> 2] = GLctx.getProgramParameter(program, pname); - } - }; - _emscripten_glGetProgramiv.sig = 'viip'; - - var _emscripten_glGetQueryObjecti64vEXT = (id, pname, params) => { - if (!params) { - // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense - // if p == null, issue a GL error to notify user about it. - GL.recordError(0x501 /* GL_INVALID_VALUE */); - return; - } - var query = GL.queries[id]; - var param; - { - param = GLctx.disjointTimerQueryExt['getQueryObjectEXT']( - query, - pname - ); - } - var ret; - if (typeof param == 'boolean') { - ret = param ? 1 : 0; - } else { - ret = param; - } - writeI53ToI64(params, ret); - }; - _emscripten_glGetQueryObjecti64vEXT.sig = 'viip'; - - var _emscripten_glGetQueryObjectivEXT = (id, pname, params) => { - if (!params) { - // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense - // if p == null, issue a GL error to notify user about it. - GL.recordError(0x501 /* GL_INVALID_VALUE */); - return; - } - var query = GL.queries[id]; - var param = GLctx.disjointTimerQueryExt['getQueryObjectEXT']( - query, - pname - ); - var ret; - if (typeof param == 'boolean') { - ret = param ? 1 : 0; - } else { - ret = param; - } - HEAP32[params >> 2] = ret; - }; - _emscripten_glGetQueryObjectivEXT.sig = 'viip'; - - var _emscripten_glGetQueryObjectui64vEXT = - _emscripten_glGetQueryObjecti64vEXT; - - var _emscripten_glGetQueryObjectuivEXT = _emscripten_glGetQueryObjectivEXT; - - var _emscripten_glGetQueryivEXT = (target, pname, params) => { - if (!params) { - // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense - // if p == null, issue a GL error to notify user about it. - GL.recordError(0x501 /* GL_INVALID_VALUE */); - return; - } - HEAP32[params >> 2] = GLctx.disjointTimerQueryExt['getQueryEXT']( - target, - pname - ); - }; - _emscripten_glGetQueryivEXT.sig = 'viip'; - - var _emscripten_glGetRenderbufferParameteriv = (target, pname, params) => { - if (!params) { - // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense - // if params == null, issue a GL error to notify user about it. - GL.recordError(0x501 /* GL_INVALID_VALUE */); - return; - } - HEAP32[params >> 2] = GLctx.getRenderbufferParameter(target, pname); - }; - _emscripten_glGetRenderbufferParameteriv.sig = 'viip'; - - var _emscripten_glGetShaderInfoLog = ( - shader, - maxLength, - length, - infoLog - ) => { - var log = GLctx.getShaderInfoLog(GL.shaders[shader]); - if (log === null) log = '(unknown error)'; - var numBytesWrittenExclNull = - maxLength > 0 && infoLog - ? stringToUTF8(log, infoLog, maxLength) - : 0; - if (length) HEAP32[length >> 2] = numBytesWrittenExclNull; - }; - _emscripten_glGetShaderInfoLog.sig = 'viipp'; - - var _emscripten_glGetShaderPrecisionFormat = ( - shaderType, - precisionType, - range, - precision - ) => { - var result = GLctx.getShaderPrecisionFormat(shaderType, precisionType); - HEAP32[range >> 2] = result.rangeMin; - HEAP32[(range + 4) >> 2] = result.rangeMax; - HEAP32[precision >> 2] = result.precision; - }; - _emscripten_glGetShaderPrecisionFormat.sig = 'viipp'; - - var _emscripten_glGetShaderSource = (shader, bufSize, length, source) => { - var result = GLctx.getShaderSource(GL.shaders[shader]); - if (!result) return; // If an error occurs, nothing will be written to length or source. - var numBytesWrittenExclNull = - bufSize > 0 && source ? stringToUTF8(result, source, bufSize) : 0; - if (length) HEAP32[length >> 2] = numBytesWrittenExclNull; - }; - _emscripten_glGetShaderSource.sig = 'viipp'; - - var _emscripten_glGetShaderiv = (shader, pname, p) => { - if (!p) { - // GLES2 specification does not specify how to behave if p is a null - // pointer. Since calling this function does not make sense if p == null, - // issue a GL error to notify user about it. - GL.recordError(0x501 /* GL_INVALID_VALUE */); - return; - } - if (pname == 0x8b84) { - // GL_INFO_LOG_LENGTH - var log = GLctx.getShaderInfoLog(GL.shaders[shader]); - if (log === null) log = '(unknown error)'; - // The GLES2 specification says that if the shader has an empty info log, - // a value of 0 is returned. Otherwise the log has a null char appended. - // (An empty string is falsey, so we can just check that instead of - // looking at log.length.) - var logLength = log ? log.length + 1 : 0; - HEAP32[p >> 2] = logLength; - } else if (pname == 0x8b88) { - // GL_SHADER_SOURCE_LENGTH - var source = GLctx.getShaderSource(GL.shaders[shader]); - // source may be a null, or the empty string, both of which are falsey - // values that we report a 0 length for. - var sourceLength = source ? source.length + 1 : 0; - HEAP32[p >> 2] = sourceLength; - } else { - HEAP32[p >> 2] = GLctx.getShaderParameter( - GL.shaders[shader], - pname - ); - } - }; - _emscripten_glGetShaderiv.sig = 'viip'; - - var webglGetExtensions = () => { - var exts = getEmscriptenSupportedExtensions(GLctx); - exts = exts.concat(exts.map((e) => 'GL_' + e)); - return exts; - }; - - var _emscripten_glGetString = (name_) => { - var ret = GL.stringCache[name_]; - if (!ret) { - switch (name_) { - case 0x1f03 /* GL_EXTENSIONS */: - ret = stringToNewUTF8(webglGetExtensions().join(' ')); - break; - case 0x1f00 /* GL_VENDOR */: - case 0x1f01 /* GL_RENDERER */: - case 0x9245 /* UNMASKED_VENDOR_WEBGL */: - case 0x9246 /* UNMASKED_RENDERER_WEBGL */: - var s = GLctx.getParameter(name_); - if (!s) { - GL.recordError(0x500 /*GL_INVALID_ENUM*/); - } - ret = s ? stringToNewUTF8(s) : 0; - break; - - case 0x1f02 /* GL_VERSION */: - var webGLVersion = GLctx.getParameter( - 0x1f02 /*GL_VERSION*/ - ); - // return GLES version string corresponding to the version of the WebGL context - var glVersion = `OpenGL ES 2.0 (${webGLVersion})`; - ret = stringToNewUTF8(glVersion); - break; - case 0x8b8c /* GL_SHADING_LANGUAGE_VERSION */: - var glslVersion = GLctx.getParameter( - 0x8b8c /*GL_SHADING_LANGUAGE_VERSION*/ - ); - // extract the version number 'N.M' from the string 'WebGL GLSL ES N.M ...' - var ver_re = /^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/; - var ver_num = glslVersion.match(ver_re); - if (ver_num !== null) { - if (ver_num[1].length == 3) - ver_num[1] = ver_num[1] + '0'; // ensure minor version has 2 digits - glslVersion = `OpenGL ES GLSL ES ${ver_num[1]} (${glslVersion})`; - } - ret = stringToNewUTF8(glslVersion); - break; - default: - GL.recordError(0x500 /*GL_INVALID_ENUM*/); - // fall through - } - GL.stringCache[name_] = ret; - } - return ret; - }; - _emscripten_glGetString.sig = 'pi'; - - var _emscripten_glGetTexParameterfv = (target, pname, params) => { - if (!params) { - // GLES2 specification does not specify how to behave if params is a null - // pointer. Since calling this function does not make sense if p == null, - // issue a GL error to notify user about it. - GL.recordError(0x501 /* GL_INVALID_VALUE */); - return; - } - HEAPF32[params >> 2] = GLctx.getTexParameter(target, pname); - }; - _emscripten_glGetTexParameterfv.sig = 'viip'; - - var _emscripten_glGetTexParameteriv = (target, pname, params) => { - if (!params) { - // GLES2 specification does not specify how to behave if params is a null - // pointer. Since calling this function does not make sense if p == null, - // issue a GL error to notify user about it. - GL.recordError(0x501 /* GL_INVALID_VALUE */); - return; - } - HEAP32[params >> 2] = GLctx.getTexParameter(target, pname); - }; - _emscripten_glGetTexParameteriv.sig = 'viip'; - - /** @suppress {checkTypes} */ - var jstoi_q = (str) => parseInt(str); - - /** @noinline */ - var webglGetLeftBracePos = (name) => - name.slice(-1) == ']' && name.lastIndexOf('['); - - var webglPrepareUniformLocationsBeforeFirstUse = (program) => { - var uniformLocsById = program.uniformLocsById, // Maps GLuint -> WebGLUniformLocation - uniformSizeAndIdsByName = program.uniformSizeAndIdsByName, // Maps name -> [uniform array length, GLuint] - i, - j; - - // On the first time invocation of glGetUniformLocation on this shader program: - // initialize cache data structures and discover which uniforms are arrays. - if (!uniformLocsById) { - // maps GLint integer locations to WebGLUniformLocations - program.uniformLocsById = uniformLocsById = {}; - // maps integer locations back to uniform name strings, so that we can lazily fetch uniform array locations - program.uniformArrayNamesById = {}; - - var numActiveUniforms = GLctx.getProgramParameter( - program, - 0x8b86 /*GL_ACTIVE_UNIFORMS*/ - ); - for (i = 0; i < numActiveUniforms; ++i) { - var u = GLctx.getActiveUniform(program, i); - var nm = u.name; - var sz = u.size; - var lb = webglGetLeftBracePos(nm); - var arrayName = lb > 0 ? nm.slice(0, lb) : nm; - - // Assign a new location. - var id = program.uniformIdCounter; - program.uniformIdCounter += sz; - // Eagerly get the location of the uniformArray[0] base element. - // The remaining indices >0 will be left for lazy evaluation to - // improve performance. Those may never be needed to fetch, if the - // application fills arrays always in full starting from the first - // element of the array. - uniformSizeAndIdsByName[arrayName] = [sz, id]; - - // Store placeholder integers in place that highlight that these - // >0 index locations are array indices pending population. - for (j = 0; j < sz; ++j) { - uniformLocsById[id] = j; - program.uniformArrayNamesById[id++] = arrayName; - } - } - } - }; - - var _emscripten_glGetUniformLocation = (program, name) => { - name = UTF8ToString(name); - - if ((program = GL.programs[program])) { - webglPrepareUniformLocationsBeforeFirstUse(program); - var uniformLocsById = program.uniformLocsById; // Maps GLuint -> WebGLUniformLocation - var arrayIndex = 0; - var uniformBaseName = name; - - // Invariant: when populating integer IDs for uniform locations, we must - // maintain the precondition that arrays reside in contiguous addresses, - // i.e. for a 'vec4 colors[10];', colors[4] must be at location - // colors[0]+4. However, user might call glGetUniformLocation(program, - // "colors") for an array, so we cannot discover based on the user input - // arguments whether the uniform we are dealing with is an array. The only - // way to discover which uniforms are arrays is to enumerate over all the - // active uniforms in the program. - var leftBrace = webglGetLeftBracePos(name); - - // If user passed an array accessor "[index]", parse the array index off the accessor. - if (leftBrace > 0) { - arrayIndex = jstoi_q(name.slice(leftBrace + 1)) >>> 0; // "index]", coerce parseInt(']') with >>>0 to treat "foo[]" as "foo[0]" and foo[-1] as unsigned out-of-bounds. - uniformBaseName = name.slice(0, leftBrace); - } - - // Have we cached the location of this uniform before? - // A pair [array length, GLint of the uniform location] - var sizeAndId = program.uniformSizeAndIdsByName[uniformBaseName]; - - // If an uniform with this name exists, and if its index is within the - // array limits (if it's even an array), query the WebGLlocation, or - // return an existing cached location. - if (sizeAndId && arrayIndex < sizeAndId[0]) { - arrayIndex += sizeAndId[1]; // Add the base location of the uniform to the array index offset. - if ( - (uniformLocsById[arrayIndex] = - uniformLocsById[arrayIndex] || - GLctx.getUniformLocation(program, name)) - ) { - return arrayIndex; - } - } - } else { - // N.b. we are currently unable to distinguish between GL program IDs that - // never existed vs GL program IDs that have been deleted, so report - // GL_INVALID_VALUE in both cases. - GL.recordError(0x501 /* GL_INVALID_VALUE */); - } - return -1; - }; - _emscripten_glGetUniformLocation.sig = 'iip'; - - var webglGetUniformLocation = (location) => { - var p = GLctx.currentProgram; - - if (p) { - var webglLoc = p.uniformLocsById[location]; - // p.uniformLocsById[location] stores either an integer, or a - // WebGLUniformLocation. - // If an integer, we have not yet bound the location, so do it now. The - // integer value specifies the array index we should bind to. - if (typeof webglLoc == 'number') { - p.uniformLocsById[location] = webglLoc = - GLctx.getUniformLocation( - p, - p.uniformArrayNamesById[location] + - (webglLoc > 0 ? `[${webglLoc}]` : '') - ); - } - // Else an already cached WebGLUniformLocation, return it. - return webglLoc; - } else { - GL.recordError(0x502 /*GL_INVALID_OPERATION*/); - } - }; - - /** @suppress{checkTypes} */ - var emscriptenWebGLGetUniform = (program, location, params, type) => { - if (!params) { - // GLES2 specification does not specify how to behave if params is a null - // pointer. Since calling this function does not make sense if params == - // null, issue a GL error to notify user about it. - GL.recordError(0x501 /* GL_INVALID_VALUE */); - return; - } - program = GL.programs[program]; - webglPrepareUniformLocationsBeforeFirstUse(program); - var data = GLctx.getUniform(program, webglGetUniformLocation(location)); - if (typeof data == 'number' || typeof data == 'boolean') { - switch (type) { - case 0: - HEAP32[params >> 2] = data; - break; - case 2: - HEAPF32[params >> 2] = data; - break; - } - } else { - for (var i = 0; i < data.length; i++) { - switch (type) { - case 0: - HEAP32[(params + i * 4) >> 2] = data[i]; - break; - case 2: - HEAPF32[(params + i * 4) >> 2] = data[i]; - break; - } - } - } - }; - - var _emscripten_glGetUniformfv = (program, location, params) => { - emscriptenWebGLGetUniform(program, location, params, 2); - }; - _emscripten_glGetUniformfv.sig = 'viip'; - - var _emscripten_glGetUniformiv = (program, location, params) => { - emscriptenWebGLGetUniform(program, location, params, 0); - }; - _emscripten_glGetUniformiv.sig = 'viip'; - - var _emscripten_glGetVertexAttribPointerv = (index, pname, pointer) => { - if (!pointer) { - // GLES2 specification does not specify how to behave if pointer is a null - // pointer. Since calling this function does not make sense if pointer == - // null, issue a GL error to notify user about it. - GL.recordError(0x501 /* GL_INVALID_VALUE */); - return; - } - HEAP32[pointer >> 2] = GLctx.getVertexAttribOffset(index, pname); - }; - _emscripten_glGetVertexAttribPointerv.sig = 'viip'; - - /** @suppress{checkTypes} */ - var emscriptenWebGLGetVertexAttrib = (index, pname, params, type) => { - if (!params) { - // GLES2 specification does not specify how to behave if params is a null - // pointer. Since calling this function does not make sense if params == - // null, issue a GL error to notify user about it. - GL.recordError(0x501 /* GL_INVALID_VALUE */); - return; - } - var data = GLctx.getVertexAttrib(index, pname); - if (pname == 0x889f /*VERTEX_ATTRIB_ARRAY_BUFFER_BINDING*/) { - HEAP32[params >> 2] = data && data['name']; - } else if (typeof data == 'number' || typeof data == 'boolean') { - switch (type) { - case 0: - HEAP32[params >> 2] = data; - break; - case 2: - HEAPF32[params >> 2] = data; - break; - case 5: - HEAP32[params >> 2] = Math.fround(data); - break; - } - } else { - for (var i = 0; i < data.length; i++) { - switch (type) { - case 0: - HEAP32[(params + i * 4) >> 2] = data[i]; - break; - case 2: - HEAPF32[(params + i * 4) >> 2] = data[i]; - break; - case 5: - HEAP32[(params + i * 4) >> 2] = Math.fround(data[i]); - break; - } - } - } - }; - - var _emscripten_glGetVertexAttribfv = (index, pname, params) => { - // N.B. This function may only be called if the vertex attribute was - // specified using the function glVertexAttrib*f(), otherwise the results - // are undefined. (GLES3 spec 6.1.12) - emscriptenWebGLGetVertexAttrib(index, pname, params, 2); - }; - _emscripten_glGetVertexAttribfv.sig = 'viip'; - - var _emscripten_glGetVertexAttribiv = (index, pname, params) => { - // N.B. This function may only be called if the vertex attribute was - // specified using the function glVertexAttrib*f(), otherwise the results - // are undefined. (GLES3 spec 6.1.12) - emscriptenWebGLGetVertexAttrib(index, pname, params, 5); - }; - _emscripten_glGetVertexAttribiv.sig = 'viip'; - - var _emscripten_glHint = (x0, x1) => GLctx.hint(x0, x1); - _emscripten_glHint.sig = 'vii'; - - var _emscripten_glIsBuffer = (buffer) => { - var b = GL.buffers[buffer]; - if (!b) return 0; - return GLctx.isBuffer(b); - }; - _emscripten_glIsBuffer.sig = 'ii'; - - var _emscripten_glIsEnabled = (x0) => GLctx.isEnabled(x0); - _emscripten_glIsEnabled.sig = 'ii'; - - var _emscripten_glIsFramebuffer = (framebuffer) => { - var fb = GL.framebuffers[framebuffer]; - if (!fb) return 0; - return GLctx.isFramebuffer(fb); - }; - _emscripten_glIsFramebuffer.sig = 'ii'; - - var _emscripten_glIsProgram = (program) => { - program = GL.programs[program]; - if (!program) return 0; - return GLctx.isProgram(program); - }; - _emscripten_glIsProgram.sig = 'ii'; - - var _emscripten_glIsQueryEXT = (id) => { - var query = GL.queries[id]; - if (!query) return 0; - return GLctx.disjointTimerQueryExt['isQueryEXT'](query); - }; - _emscripten_glIsQueryEXT.sig = 'ii'; - - var _emscripten_glIsRenderbuffer = (renderbuffer) => { - var rb = GL.renderbuffers[renderbuffer]; - if (!rb) return 0; - return GLctx.isRenderbuffer(rb); - }; - _emscripten_glIsRenderbuffer.sig = 'ii'; - - var _emscripten_glIsShader = (shader) => { - var s = GL.shaders[shader]; - if (!s) return 0; - return GLctx.isShader(s); - }; - _emscripten_glIsShader.sig = 'ii'; - - var _emscripten_glIsTexture = (id) => { - var texture = GL.textures[id]; - if (!texture) return 0; - return GLctx.isTexture(texture); - }; - _emscripten_glIsTexture.sig = 'ii'; - - var _emscripten_glIsVertexArray = (array) => { - var vao = GL.vaos[array]; - if (!vao) return 0; - return GLctx.isVertexArray(vao); - }; - _emscripten_glIsVertexArray.sig = 'ii'; - var _emscripten_glIsVertexArrayOES = _emscripten_glIsVertexArray; - _emscripten_glIsVertexArrayOES.sig = 'ii'; - - var _emscripten_glLineWidth = (x0) => GLctx.lineWidth(x0); - _emscripten_glLineWidth.sig = 'vf'; - - var _emscripten_glLinkProgram = (program) => { - program = GL.programs[program]; - GLctx.linkProgram(program); - // Invalidate earlier computed uniform->ID mappings, those have now become stale - program.uniformLocsById = 0; // Mark as null-like so that glGetUniformLocation() knows to populate this again. - program.uniformSizeAndIdsByName = {}; - }; - _emscripten_glLinkProgram.sig = 'vi'; - - var _emscripten_glPixelStorei = (pname, param) => { - if (pname == 3317) { - GL.unpackAlignment = param; - } else if (pname == 3314) { - GL.unpackRowLength = param; - } - GLctx.pixelStorei(pname, param); - }; - _emscripten_glPixelStorei.sig = 'vii'; - - var _emscripten_glPolygonModeWEBGL = (face, mode) => { - GLctx.webglPolygonMode['polygonModeWEBGL'](face, mode); - }; - _emscripten_glPolygonModeWEBGL.sig = 'vii'; - - var _emscripten_glPolygonOffset = (x0, x1) => GLctx.polygonOffset(x0, x1); - _emscripten_glPolygonOffset.sig = 'vff'; - - var _emscripten_glPolygonOffsetClampEXT = (factor, units, clamp) => { - GLctx.extPolygonOffsetClamp['polygonOffsetClampEXT']( - factor, - units, - clamp - ); - }; - _emscripten_glPolygonOffsetClampEXT.sig = 'vfff'; - - var _emscripten_glQueryCounterEXT = (id, target) => { - GLctx.disjointTimerQueryExt['queryCounterEXT'](GL.queries[id], target); - }; - _emscripten_glQueryCounterEXT.sig = 'vii'; - - var computeUnpackAlignedImageSize = (width, height, sizePerPixel) => { - function roundedToNextMultipleOf(x, y) { - return (x + y - 1) & -y; - } - var plainRowSize = (GL.unpackRowLength || width) * sizePerPixel; - var alignedRowSize = roundedToNextMultipleOf( - plainRowSize, - GL.unpackAlignment - ); - return height * alignedRowSize; - }; - - var colorChannelsInGlTextureFormat = (format) => { - // Micro-optimizations for size: map format to size by subtracting smallest - // enum value (0x1902) from all values first. Also omit the most common - // size value (1) from the list, which is assumed by formats not on the - // list. - var colorChannels = { - // 0x1902 /* GL_DEPTH_COMPONENT */ - 0x1902: 1, - // 0x1906 /* GL_ALPHA */ - 0x1902: 1, - 5: 3, - 6: 4, - // 0x1909 /* GL_LUMINANCE */ - 0x1902: 1, - 8: 2, - 29502: 3, - 29504: 4, - }; - return colorChannels[format - 0x1902] || 1; - }; - - var heapObjectForWebGLType = (type) => { - // Micro-optimization for size: Subtract lowest GL enum number (0x1400/* GL_BYTE */) from type to compare - // smaller values for the heap, for shorter generated code size. - // Also the type HEAPU16 is not tested for explicitly, but any unrecognized type will return out HEAPU16. - // (since most types are HEAPU16) - type -= 0x1400; - - if (type == 1) return HEAPU8; - - if (type == 4) return HEAP32; - - if (type == 6) return HEAPF32; - - if (type == 5 || type == 28922) return HEAPU32; - - return HEAPU16; - }; - - var toTypedArrayIndex = (pointer, heap) => - pointer >>> (31 - Math.clz32(heap.BYTES_PER_ELEMENT)); - - var emscriptenWebGLGetTexPixelData = ( - type, - format, - width, - height, - pixels, - internalFormat - ) => { - var heap = heapObjectForWebGLType(type); - var sizePerPixel = - colorChannelsInGlTextureFormat(format) * heap.BYTES_PER_ELEMENT; - var bytes = computeUnpackAlignedImageSize(width, height, sizePerPixel); - return heap.subarray( - toTypedArrayIndex(pixels, heap), - toTypedArrayIndex(pixels + bytes, heap) - ); - }; - - var _emscripten_glReadPixels = ( - x, - y, - width, - height, - format, - type, - pixels - ) => { - var pixelData = emscriptenWebGLGetTexPixelData( - type, - format, - width, - height, - pixels, - format - ); - if (!pixelData) { - GL.recordError(0x500 /*GL_INVALID_ENUM*/); - return; - } - GLctx.readPixels(x, y, width, height, format, type, pixelData); - }; - _emscripten_glReadPixels.sig = 'viiiiiip'; - - var _emscripten_glReleaseShaderCompiler = () => { - // NOP (as allowed by GLES 2.0 spec) - }; - _emscripten_glReleaseShaderCompiler.sig = 'v'; - - var _emscripten_glRenderbufferStorage = (x0, x1, x2, x3) => - GLctx.renderbufferStorage(x0, x1, x2, x3); - _emscripten_glRenderbufferStorage.sig = 'viiii'; - - var _emscripten_glSampleCoverage = (value, invert) => { - GLctx.sampleCoverage(value, !!invert); - }; - _emscripten_glSampleCoverage.sig = 'vfi'; - - var _emscripten_glScissor = (x0, x1, x2, x3) => - GLctx.scissor(x0, x1, x2, x3); - _emscripten_glScissor.sig = 'viiii'; - - var _emscripten_glShaderBinary = ( - count, - shaders, - binaryformat, - binary, - length - ) => { - GL.recordError(0x500 /*GL_INVALID_ENUM*/); - }; - _emscripten_glShaderBinary.sig = 'vipipi'; - - var _emscripten_glShaderSource = (shader, count, string, length) => { - var source = GL.getSource(shader, count, string, length); - - GLctx.shaderSource(GL.shaders[shader], source); - }; - _emscripten_glShaderSource.sig = 'viipp'; - - var _emscripten_glStencilFunc = (x0, x1, x2) => - GLctx.stencilFunc(x0, x1, x2); - _emscripten_glStencilFunc.sig = 'viii'; - - var _emscripten_glStencilFuncSeparate = (x0, x1, x2, x3) => - GLctx.stencilFuncSeparate(x0, x1, x2, x3); - _emscripten_glStencilFuncSeparate.sig = 'viiii'; - - var _emscripten_glStencilMask = (x0) => GLctx.stencilMask(x0); - _emscripten_glStencilMask.sig = 'vi'; - - var _emscripten_glStencilMaskSeparate = (x0, x1) => - GLctx.stencilMaskSeparate(x0, x1); - _emscripten_glStencilMaskSeparate.sig = 'vii'; - - var _emscripten_glStencilOp = (x0, x1, x2) => GLctx.stencilOp(x0, x1, x2); - _emscripten_glStencilOp.sig = 'viii'; - - var _emscripten_glStencilOpSeparate = (x0, x1, x2, x3) => - GLctx.stencilOpSeparate(x0, x1, x2, x3); - _emscripten_glStencilOpSeparate.sig = 'viiii'; - - var _emscripten_glTexImage2D = ( - target, - level, - internalFormat, - width, - height, - border, - format, - type, - pixels - ) => { - var pixelData = pixels - ? emscriptenWebGLGetTexPixelData( - type, - format, - width, - height, - pixels, - internalFormat - ) - : null; - GLctx.texImage2D( - target, - level, - internalFormat, - width, - height, - border, - format, - type, - pixelData - ); - }; - _emscripten_glTexImage2D.sig = 'viiiiiiiip'; - - var _emscripten_glTexParameterf = (x0, x1, x2) => - GLctx.texParameterf(x0, x1, x2); - _emscripten_glTexParameterf.sig = 'viif'; - - var _emscripten_glTexParameterfv = (target, pname, params) => { - var param = HEAPF32[params >> 2]; - GLctx.texParameterf(target, pname, param); - }; - _emscripten_glTexParameterfv.sig = 'viip'; - - var _emscripten_glTexParameteri = (x0, x1, x2) => - GLctx.texParameteri(x0, x1, x2); - _emscripten_glTexParameteri.sig = 'viii'; - - var _emscripten_glTexParameteriv = (target, pname, params) => { - var param = HEAP32[params >> 2]; - GLctx.texParameteri(target, pname, param); - }; - _emscripten_glTexParameteriv.sig = 'viip'; - - var _emscripten_glTexSubImage2D = ( - target, - level, - xoffset, - yoffset, - width, - height, - format, - type, - pixels - ) => { - var pixelData = pixels - ? emscriptenWebGLGetTexPixelData( - type, - format, - width, - height, - pixels, - 0 - ) - : null; - GLctx.texSubImage2D( - target, - level, - xoffset, - yoffset, - width, - height, - format, - type, - pixelData - ); - }; - _emscripten_glTexSubImage2D.sig = 'viiiiiiiip'; - - var _emscripten_glUniform1f = (location, v0) => { - GLctx.uniform1f(webglGetUniformLocation(location), v0); - }; - _emscripten_glUniform1f.sig = 'vif'; - - var miniTempWebGLFloatBuffers = []; - - var _emscripten_glUniform1fv = (location, count, value) => { - if (count <= 288) { - // avoid allocation when uploading few enough uniforms - var view = miniTempWebGLFloatBuffers[count]; - for (var i = 0; i < count; ++i) { - view[i] = HEAPF32[(value + 4 * i) >> 2]; - } - } else { - var view = HEAPF32.subarray(value >> 2, (value + count * 4) >> 2); - } - GLctx.uniform1fv(webglGetUniformLocation(location), view); - }; - _emscripten_glUniform1fv.sig = 'viip'; - - var _emscripten_glUniform1i = (location, v0) => { - GLctx.uniform1i(webglGetUniformLocation(location), v0); - }; - _emscripten_glUniform1i.sig = 'vii'; - - var miniTempWebGLIntBuffers = []; - - var _emscripten_glUniform1iv = (location, count, value) => { - if (count <= 288) { - // avoid allocation when uploading few enough uniforms - var view = miniTempWebGLIntBuffers[count]; - for (var i = 0; i < count; ++i) { - view[i] = HEAP32[(value + 4 * i) >> 2]; - } - } else { - var view = HEAP32.subarray(value >> 2, (value + count * 4) >> 2); - } - GLctx.uniform1iv(webglGetUniformLocation(location), view); - }; - _emscripten_glUniform1iv.sig = 'viip'; - - var _emscripten_glUniform2f = (location, v0, v1) => { - GLctx.uniform2f(webglGetUniformLocation(location), v0, v1); - }; - _emscripten_glUniform2f.sig = 'viff'; - - var _emscripten_glUniform2fv = (location, count, value) => { - if (count <= 144) { - // avoid allocation when uploading few enough uniforms - count *= 2; - var view = miniTempWebGLFloatBuffers[count]; - for (var i = 0; i < count; i += 2) { - view[i] = HEAPF32[(value + 4 * i) >> 2]; - view[i + 1] = HEAPF32[(value + (4 * i + 4)) >> 2]; - } - } else { - var view = HEAPF32.subarray(value >> 2, (value + count * 8) >> 2); - } - GLctx.uniform2fv(webglGetUniformLocation(location), view); - }; - _emscripten_glUniform2fv.sig = 'viip'; - - var _emscripten_glUniform2i = (location, v0, v1) => { - GLctx.uniform2i(webglGetUniformLocation(location), v0, v1); - }; - _emscripten_glUniform2i.sig = 'viii'; - - var _emscripten_glUniform2iv = (location, count, value) => { - if (count <= 144) { - // avoid allocation when uploading few enough uniforms - count *= 2; - var view = miniTempWebGLIntBuffers[count]; - for (var i = 0; i < count; i += 2) { - view[i] = HEAP32[(value + 4 * i) >> 2]; - view[i + 1] = HEAP32[(value + (4 * i + 4)) >> 2]; - } - } else { - var view = HEAP32.subarray(value >> 2, (value + count * 8) >> 2); - } - GLctx.uniform2iv(webglGetUniformLocation(location), view); - }; - _emscripten_glUniform2iv.sig = 'viip'; - - var _emscripten_glUniform3f = (location, v0, v1, v2) => { - GLctx.uniform3f(webglGetUniformLocation(location), v0, v1, v2); - }; - _emscripten_glUniform3f.sig = 'vifff'; - - var _emscripten_glUniform3fv = (location, count, value) => { - if (count <= 96) { - // avoid allocation when uploading few enough uniforms - count *= 3; - var view = miniTempWebGLFloatBuffers[count]; - for (var i = 0; i < count; i += 3) { - view[i] = HEAPF32[(value + 4 * i) >> 2]; - view[i + 1] = HEAPF32[(value + (4 * i + 4)) >> 2]; - view[i + 2] = HEAPF32[(value + (4 * i + 8)) >> 2]; - } - } else { - var view = HEAPF32.subarray(value >> 2, (value + count * 12) >> 2); - } - GLctx.uniform3fv(webglGetUniformLocation(location), view); - }; - _emscripten_glUniform3fv.sig = 'viip'; - - var _emscripten_glUniform3i = (location, v0, v1, v2) => { - GLctx.uniform3i(webglGetUniformLocation(location), v0, v1, v2); - }; - _emscripten_glUniform3i.sig = 'viiii'; - - var _emscripten_glUniform3iv = (location, count, value) => { - if (count <= 96) { - // avoid allocation when uploading few enough uniforms - count *= 3; - var view = miniTempWebGLIntBuffers[count]; - for (var i = 0; i < count; i += 3) { - view[i] = HEAP32[(value + 4 * i) >> 2]; - view[i + 1] = HEAP32[(value + (4 * i + 4)) >> 2]; - view[i + 2] = HEAP32[(value + (4 * i + 8)) >> 2]; - } - } else { - var view = HEAP32.subarray(value >> 2, (value + count * 12) >> 2); - } - GLctx.uniform3iv(webglGetUniformLocation(location), view); - }; - _emscripten_glUniform3iv.sig = 'viip'; - - var _emscripten_glUniform4f = (location, v0, v1, v2, v3) => { - GLctx.uniform4f(webglGetUniformLocation(location), v0, v1, v2, v3); - }; - _emscripten_glUniform4f.sig = 'viffff'; - - var _emscripten_glUniform4fv = (location, count, value) => { - if (count <= 72) { - // avoid allocation when uploading few enough uniforms - var view = miniTempWebGLFloatBuffers[4 * count]; - // hoist the heap out of the loop for size and for pthreads+growth. - var heap = HEAPF32; - value = value >> 2; - count *= 4; - for (var i = 0; i < count; i += 4) { - var dst = value + i; - view[i] = heap[dst]; - view[i + 1] = heap[dst + 1]; - view[i + 2] = heap[dst + 2]; - view[i + 3] = heap[dst + 3]; - } - } else { - var view = HEAPF32.subarray(value >> 2, (value + count * 16) >> 2); - } - GLctx.uniform4fv(webglGetUniformLocation(location), view); - }; - _emscripten_glUniform4fv.sig = 'viip'; - - var _emscripten_glUniform4i = (location, v0, v1, v2, v3) => { - GLctx.uniform4i(webglGetUniformLocation(location), v0, v1, v2, v3); - }; - _emscripten_glUniform4i.sig = 'viiiii'; - - var _emscripten_glUniform4iv = (location, count, value) => { - if (count <= 72) { - // avoid allocation when uploading few enough uniforms - count *= 4; - var view = miniTempWebGLIntBuffers[count]; - for (var i = 0; i < count; i += 4) { - view[i] = HEAP32[(value + 4 * i) >> 2]; - view[i + 1] = HEAP32[(value + (4 * i + 4)) >> 2]; - view[i + 2] = HEAP32[(value + (4 * i + 8)) >> 2]; - view[i + 3] = HEAP32[(value + (4 * i + 12)) >> 2]; - } - } else { - var view = HEAP32.subarray(value >> 2, (value + count * 16) >> 2); - } - GLctx.uniform4iv(webglGetUniformLocation(location), view); - }; - _emscripten_glUniform4iv.sig = 'viip'; - - var _emscripten_glUniformMatrix2fv = ( - location, - count, - transpose, - value - ) => { - if (count <= 72) { - // avoid allocation when uploading few enough uniforms - count *= 4; - var view = miniTempWebGLFloatBuffers[count]; - for (var i = 0; i < count; i += 4) { - view[i] = HEAPF32[(value + 4 * i) >> 2]; - view[i + 1] = HEAPF32[(value + (4 * i + 4)) >> 2]; - view[i + 2] = HEAPF32[(value + (4 * i + 8)) >> 2]; - view[i + 3] = HEAPF32[(value + (4 * i + 12)) >> 2]; - } - } else { - var view = HEAPF32.subarray(value >> 2, (value + count * 16) >> 2); - } - GLctx.uniformMatrix2fv( - webglGetUniformLocation(location), - !!transpose, - view - ); - }; - _emscripten_glUniformMatrix2fv.sig = 'viiip'; - - var _emscripten_glUniformMatrix3fv = ( - location, - count, - transpose, - value - ) => { - if (count <= 32) { - // avoid allocation when uploading few enough uniforms - count *= 9; - var view = miniTempWebGLFloatBuffers[count]; - for (var i = 0; i < count; i += 9) { - view[i] = HEAPF32[(value + 4 * i) >> 2]; - view[i + 1] = HEAPF32[(value + (4 * i + 4)) >> 2]; - view[i + 2] = HEAPF32[(value + (4 * i + 8)) >> 2]; - view[i + 3] = HEAPF32[(value + (4 * i + 12)) >> 2]; - view[i + 4] = HEAPF32[(value + (4 * i + 16)) >> 2]; - view[i + 5] = HEAPF32[(value + (4 * i + 20)) >> 2]; - view[i + 6] = HEAPF32[(value + (4 * i + 24)) >> 2]; - view[i + 7] = HEAPF32[(value + (4 * i + 28)) >> 2]; - view[i + 8] = HEAPF32[(value + (4 * i + 32)) >> 2]; - } - } else { - var view = HEAPF32.subarray(value >> 2, (value + count * 36) >> 2); - } - GLctx.uniformMatrix3fv( - webglGetUniformLocation(location), - !!transpose, - view - ); - }; - _emscripten_glUniformMatrix3fv.sig = 'viiip'; - - var _emscripten_glUniformMatrix4fv = ( - location, - count, - transpose, - value - ) => { - if (count <= 18) { - // avoid allocation when uploading few enough uniforms - var view = miniTempWebGLFloatBuffers[16 * count]; - // hoist the heap out of the loop for size and for pthreads+growth. - var heap = HEAPF32; - value = value >> 2; - count *= 16; - for (var i = 0; i < count; i += 16) { - var dst = value + i; - view[i] = heap[dst]; - view[i + 1] = heap[dst + 1]; - view[i + 2] = heap[dst + 2]; - view[i + 3] = heap[dst + 3]; - view[i + 4] = heap[dst + 4]; - view[i + 5] = heap[dst + 5]; - view[i + 6] = heap[dst + 6]; - view[i + 7] = heap[dst + 7]; - view[i + 8] = heap[dst + 8]; - view[i + 9] = heap[dst + 9]; - view[i + 10] = heap[dst + 10]; - view[i + 11] = heap[dst + 11]; - view[i + 12] = heap[dst + 12]; - view[i + 13] = heap[dst + 13]; - view[i + 14] = heap[dst + 14]; - view[i + 15] = heap[dst + 15]; - } - } else { - var view = HEAPF32.subarray(value >> 2, (value + count * 64) >> 2); - } - GLctx.uniformMatrix4fv( - webglGetUniformLocation(location), - !!transpose, - view - ); - }; - _emscripten_glUniformMatrix4fv.sig = 'viiip'; - - var _emscripten_glUseProgram = (program) => { - program = GL.programs[program]; - GLctx.useProgram(program); - // Record the currently active program so that we can access the uniform - // mapping table of that program. - GLctx.currentProgram = program; - }; - _emscripten_glUseProgram.sig = 'vi'; - - var _emscripten_glValidateProgram = (program) => { - GLctx.validateProgram(GL.programs[program]); - }; - _emscripten_glValidateProgram.sig = 'vi'; - - var _emscripten_glVertexAttrib1f = (x0, x1) => GLctx.vertexAttrib1f(x0, x1); - _emscripten_glVertexAttrib1f.sig = 'vif'; - - var _emscripten_glVertexAttrib1fv = (index, v) => { - GLctx.vertexAttrib1f(index, HEAPF32[v >> 2]); - }; - _emscripten_glVertexAttrib1fv.sig = 'vip'; - - var _emscripten_glVertexAttrib2f = (x0, x1, x2) => - GLctx.vertexAttrib2f(x0, x1, x2); - _emscripten_glVertexAttrib2f.sig = 'viff'; - - var _emscripten_glVertexAttrib2fv = (index, v) => { - GLctx.vertexAttrib2f(index, HEAPF32[v >> 2], HEAPF32[(v + 4) >> 2]); - }; - _emscripten_glVertexAttrib2fv.sig = 'vip'; - - var _emscripten_glVertexAttrib3f = (x0, x1, x2, x3) => - GLctx.vertexAttrib3f(x0, x1, x2, x3); - _emscripten_glVertexAttrib3f.sig = 'vifff'; - - var _emscripten_glVertexAttrib3fv = (index, v) => { - GLctx.vertexAttrib3f( - index, - HEAPF32[v >> 2], - HEAPF32[(v + 4) >> 2], - HEAPF32[(v + 8) >> 2] - ); - }; - _emscripten_glVertexAttrib3fv.sig = 'vip'; - - var _emscripten_glVertexAttrib4f = (x0, x1, x2, x3, x4) => - GLctx.vertexAttrib4f(x0, x1, x2, x3, x4); - _emscripten_glVertexAttrib4f.sig = 'viffff'; - - var _emscripten_glVertexAttrib4fv = (index, v) => { - GLctx.vertexAttrib4f( - index, - HEAPF32[v >> 2], - HEAPF32[(v + 4) >> 2], - HEAPF32[(v + 8) >> 2], - HEAPF32[(v + 12) >> 2] - ); - }; - _emscripten_glVertexAttrib4fv.sig = 'vip'; - - var _emscripten_glVertexAttribDivisor = (index, divisor) => { - GLctx.vertexAttribDivisor(index, divisor); - }; - _emscripten_glVertexAttribDivisor.sig = 'vii'; - var _emscripten_glVertexAttribDivisorANGLE = - _emscripten_glVertexAttribDivisor; - - var _emscripten_glVertexAttribPointer = ( - index, - size, - type, - normalized, - stride, - ptr - ) => { - GLctx.vertexAttribPointer(index, size, type, !!normalized, stride, ptr); - }; - _emscripten_glVertexAttribPointer.sig = 'viiiiip'; - - var _emscripten_glViewport = (x0, x1, x2, x3) => - GLctx.viewport(x0, x1, x2, x3); - _emscripten_glViewport.sig = 'viiii'; - - var _emscripten_out = (str) => out(UTF8ToString(str)); - _emscripten_out.sig = 'vp'; - - class HandleAllocator { - allocated = [undefined]; - freelist = []; - get(id) { - return this.allocated[id]; - } - has(id) { - return this.allocated[id] !== undefined; - } - allocate(handle) { - var id = this.freelist.pop() || this.allocated.length; - this.allocated[id] = handle; - return id; - } - free(id) { - // Set the slot to `undefined` rather than using `delete` here since - // apparently arrays with holes in them can be less efficient. - this.allocated[id] = undefined; - this.freelist.push(id); - } - } - var promiseMap = new HandleAllocator(); - var makePromise = () => { - var promiseInfo = {}; - promiseInfo.promise = new Promise((resolve, reject) => { - promiseInfo.reject = reject; - promiseInfo.resolve = resolve; - }); - promiseInfo.id = promiseMap.allocate(promiseInfo); - return promiseInfo; - }; - var _emscripten_promise_create = () => makePromise().id; - _emscripten_promise_create.sig = 'p'; - - var _emscripten_promise_destroy = (id) => { - promiseMap.free(id); - }; - _emscripten_promise_destroy.sig = 'vp'; - - var getPromise = (id) => promiseMap.get(id).promise; - - var _emscripten_promise_resolve = (id, result, value) => { - var info = promiseMap.get(id); - switch (result) { - case 0: - info.resolve(value); - return; - case 1: - info.resolve(getPromise(value)); - return; - case 2: - info.resolve(getPromise(value)); - _emscripten_promise_destroy(value); - return; - case 3: - info.reject(value); - return; - } - }; - _emscripten_promise_resolve.sig = 'vpip'; - - var growMemory = (size) => { - var oldHeapSize = wasmMemory.buffer.byteLength; - var pages = ((size - oldHeapSize + 65535) / 65536) | 0; - try { - // round size grow request up to wasm page size (fixed 64KB per spec) - wasmMemory.grow(pages); // .grow() takes a delta compared to the previous size - updateMemoryViews(); - return 1 /*success*/; - } catch (e) {} - // implicit 0 return to save code size (caller will cast "undefined" into 0 - // anyhow) - }; - var _emscripten_resize_heap = (requestedSize) => { - var oldSize = HEAPU8.length; - // With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned. - requestedSize >>>= 0; - // With multithreaded builds, races can happen (another thread might increase the size - // in between), so return a failure, and let the caller retry. - - // Memory resize rules: - // 1. Always increase heap size to at least the requested size, rounded up - // to next page multiple. - // 2a. If MEMORY_GROWTH_LINEAR_STEP == -1, excessively resize the heap - // geometrically: increase the heap size according to - // MEMORY_GROWTH_GEOMETRIC_STEP factor (default +20%), At most - // overreserve by MEMORY_GROWTH_GEOMETRIC_CAP bytes (default 96MB). - // 2b. If MEMORY_GROWTH_LINEAR_STEP != -1, excessively resize the heap - // linearly: increase the heap size by at least - // MEMORY_GROWTH_LINEAR_STEP bytes. - // 3. Max size for the heap is capped at 2048MB-WASM_PAGE_SIZE, or by - // MAXIMUM_MEMORY, or by ASAN limit, depending on which is smallest - // 4. If we were unable to allocate as much memory, it may be due to - // over-eager decision to excessively reserve due to (3) above. - // Hence if an allocation fails, cut down on the amount of excess - // growth, in an attempt to succeed to perform a smaller allocation. - - // A limit is set for how much we can grow. We should not exceed that - // (the wasm binary specifies it, so if we tried, we'd fail anyhow). - var maxHeapSize = getHeapMax(); - if (requestedSize > maxHeapSize) { - return false; - } - - // Loop through potential heap size increases. If we attempt a too eager - // reservation that fails, cut down on the attempted size and reserve a - // smaller bump instead. (max 3 times, chosen somewhat arbitrarily) - for (var cutDown = 1; cutDown <= 4; cutDown *= 2) { - var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown); // ensure geometric growth - // but limit overreserving (default to capping at +96MB overgrowth at most) - overGrownHeapSize = Math.min( - overGrownHeapSize, - requestedSize + 100663296 - ); - - var newSize = Math.min( - maxHeapSize, - alignMemory(Math.max(requestedSize, overGrownHeapSize), 65536) - ); - - var replacement = growMemory(newSize); - if (replacement) { - return true; - } - } - return false; - }; - _emscripten_resize_heap.sig = 'ip'; - - var maybeCStringToJsString = (cString) => { - // "cString > 2" checks if the input is a number, and isn't of the special - // values we accept here, EMSCRIPTEN_EVENT_TARGET_* (which map to 0, 1, 2). - // In other words, if cString > 2 then it's a pointer to a valid place in - // memory, and points to a C string. - return cString > 2 ? UTF8ToString(cString) : cString; - }; - - /** @type {Object} */ - var specialHTMLTargets = [ - 0, - typeof document != 'undefined' ? document : 0, - typeof window != 'undefined' ? window : 0, - ]; - var findEventTarget = (target) => { - target = maybeCStringToJsString(target); - var domElement = - specialHTMLTargets[target] || - (typeof document != 'undefined' - ? document.querySelector(target) - : null); - return domElement; - }; - var findCanvasEventTarget = findEventTarget; - var _emscripten_set_canvas_element_size = (target, width, height) => { - var canvas = findCanvasEventTarget(target); - if (!canvas) return -4; - canvas.width = width; - canvas.height = height; - return 0; - }; - _emscripten_set_canvas_element_size.sig = 'ipii'; - - /** @param {number=} timeout */ - var safeSetTimeout = (func, timeout) => { - runtimeKeepalivePush(); - return setTimeout(() => { - runtimeKeepalivePop(); - callUserCallback(func); - }, timeout); - }; - var _emscripten_sleep = (ms) => - Asyncify.handleSleep((wakeUp) => safeSetTimeout(wakeUp, ms)); - _emscripten_sleep.sig = 'vi'; - _emscripten_sleep.isAsync = true; - - var _emscripten_wget_data = (url, pbuffer, pnum, perror) => - Asyncify.handleAsync(async () => { - /* no need for run dependency, this is async but will not do any prepare etc. step */ - try { - const byteArray = await asyncLoad(UTF8ToString(url)); - // can only allocate the buffer after the wakeUp, not during an asyncing - var buffer = _malloc(byteArray.length); // must be freed by caller! - HEAPU8.set(byteArray, buffer); - HEAPU32[pbuffer >> 2] = buffer; - HEAP32[pnum >> 2] = byteArray.length; - HEAP32[perror >> 2] = 0; - } catch (err) { - HEAP32[perror >> 2] = 1; - } - }); - _emscripten_wget_data.sig = 'vpppp'; - _emscripten_wget_data.isAsync = true; - - var ENV = PHPLoader.ENV || {}; - - var getEnvStrings = () => { - if (!getEnvStrings.strings) { - // Default values. - // Browser language detection #8751 - var lang = - ( - (typeof navigator == 'object' && navigator.language) || - 'C' - ).replace('-', '_') + '.UTF-8'; - var env = { - USER: 'web_user', - LOGNAME: 'web_user', - PATH: '/', - PWD: '/', - HOME: '/home/web_user', - LANG: lang, - _: getExecutableName(), - }; - // Apply the user-provided values, if any. - for (var x in ENV) { - // x is a key in ENV; if ENV[x] is undefined, that means it was - // explicitly set to be so. We allow user code to do that to - // force variables with default values to remain unset. - if (ENV[x] === undefined) delete env[x]; - else env[x] = ENV[x]; - } - var strings = []; - for (var x in env) { - strings.push(`${x}=${env[x]}`); - } - getEnvStrings.strings = strings; - } - return getEnvStrings.strings; - }; - - var _environ_get = (__environ, environ_buf) => { - var bufSize = 0; - var envp = 0; - for (var string of getEnvStrings()) { - var ptr = environ_buf + bufSize; - HEAPU32[(__environ + envp) >> 2] = ptr; - bufSize += stringToUTF8(string, ptr, Infinity) + 1; - envp += 4; - } - return 0; - }; - _environ_get.sig = 'ipp'; - - var _environ_sizes_get = (penviron_count, penviron_buf_size) => { - var strings = getEnvStrings(); - HEAPU32[penviron_count >> 2] = strings.length; - var bufSize = 0; - for (var string of strings) { - bufSize += lengthBytesUTF8(string) + 1; - } - HEAPU32[penviron_buf_size >> 2] = bufSize; - return 0; - }; - _environ_sizes_get.sig = 'ipp'; - - function _fd_fdstat_get(fd, pbuf) { - try { - var rightsBase = 0; - var rightsInheriting = 0; - var flags = 0; - { - var stream = SYSCALLS.getStreamFromFD(fd); - // All character devices are terminals (other things a Linux system would - // assume is a character device, like the mouse, we have special APIs for). - var type = stream.tty - ? 2 - : FS.isDir(stream.mode) - ? 3 - : FS.isLink(stream.mode) - ? 7 - : 4; - } - HEAP8[pbuf] = type; - HEAP16[(pbuf + 2) >> 1] = flags; - HEAP64[(pbuf + 8) >> 3] = BigInt(rightsBase); - HEAP64[(pbuf + 16) >> 3] = BigInt(rightsInheriting); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return e.errno; - } - } - _fd_fdstat_get.sig = 'iip'; - - /** @param {number=} offset */ - var doReadv = (stream, iov, iovcnt, offset) => { - var ret = 0; - for (var i = 0; i < iovcnt; i++) { - var ptr = HEAPU32[iov >> 2]; - var len = HEAPU32[(iov + 4) >> 2]; - iov += 8; - var curr = FS.read(stream, HEAP8, ptr, len, offset); - if (curr < 0) return -1; - ret += curr; - if (curr < len) break; // nothing more to read - if (typeof offset != 'undefined') { - offset += curr; - } - } - return ret; - }; - - function _fd_pread(fd, iov, iovcnt, offset, pnum) { - offset = bigintToI53Checked(offset); - - try { - if (isNaN(offset)) return 61; - var stream = SYSCALLS.getStreamFromFD(fd); - var num = doReadv(stream, iov, iovcnt, offset); - HEAPU32[pnum >> 2] = num; - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return e.errno; - } - } - _fd_pread.sig = 'iippjp'; - - /** @param {number=} offset */ - var doWritev = (stream, iov, iovcnt, offset) => { - var ret = 0; - for (var i = 0; i < iovcnt; i++) { - var ptr = HEAPU32[iov >> 2]; - var len = HEAPU32[(iov + 4) >> 2]; - iov += 8; - var curr = FS.write(stream, HEAP8, ptr, len, offset); - if (curr < 0) return -1; - ret += curr; - if (curr < len) { - // No more space to write. - break; - } - if (typeof offset != 'undefined') { - offset += curr; - } - } - return ret; - }; - - function _fd_pwrite(fd, iov, iovcnt, offset, pnum) { - offset = bigintToI53Checked(offset); - - try { - if (isNaN(offset)) return 61; - var stream = SYSCALLS.getStreamFromFD(fd); - var num = doWritev(stream, iov, iovcnt, offset); - HEAPU32[pnum >> 2] = num; - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return e.errno; - } - } - _fd_pwrite.sig = 'iippjp'; - - function _fd_read(fd, iov, iovcnt, pnum) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - var num = doReadv(stream, iov, iovcnt); - HEAPU32[pnum >> 2] = num; - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return e.errno; - } - } - _fd_read.sig = 'iippp'; - - function _fd_seek(fd, offset, whence, newOffset) { - offset = bigintToI53Checked(offset); - - try { - if (isNaN(offset)) return 61; - var stream = SYSCALLS.getStreamFromFD(fd); - FS.llseek(stream, offset, whence); - HEAP64[newOffset >> 3] = BigInt(stream.position); - if (stream.getdents && offset === 0 && whence === 0) - stream.getdents = null; // reset readdir state - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return e.errno; - } - } - _fd_seek.sig = 'iijip'; - - var _fd_sync = function (fd) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - return Asyncify.handleSleep((wakeUp) => { - var mount = stream.node.mount; - if (!mount.type.syncfs) { - // We write directly to the file system, so there's nothing to do here. - wakeUp(0); - return; - } - mount.type.syncfs(mount, false, (err) => { - wakeUp(err ? 29 : 0); - }); - }); - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return e.errno; - } - }; - _fd_sync.sig = 'ii'; - _fd_sync.isAsync = true; - - function _fd_write(fd, iov, iovcnt, pnum) { - try { - var stream = SYSCALLS.getStreamFromFD(fd); - var num = doWritev(stream, iov, iovcnt); - HEAPU32[pnum >> 2] = num; - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return e.errno; - } - } - _fd_write.sig = 'iippp'; - - var _getaddrinfo = (node, service, hint, out) => { - // Note getaddrinfo currently only returns a single addrinfo with ai_next defaulting to NULL. When NULL - // hints are specified or ai_family set to AF_UNSPEC or ai_socktype or ai_protocol set to 0 then we - // really should provide a linked list of suitable addrinfo values. - var addrs = []; - var canon = null; - var addr = 0; - var port = 0; - var flags = 0; - var family = 0; - var type = 0; - var proto = 0; - var ai, last; - - function allocaddrinfo(family, type, proto, canon, addr, port) { - var sa, salen, ai; - var errno; - - salen = family === 10 ? 28 : 16; - addr = family === 10 ? inetNtop6(addr) : inetNtop4(addr); - sa = _malloc(salen); - errno = writeSockaddr(sa, family, addr, port); - - ai = _malloc(32); - HEAP32[(ai + 4) >> 2] = family; - HEAP32[(ai + 8) >> 2] = type; - HEAP32[(ai + 12) >> 2] = proto; - HEAPU32[(ai + 24) >> 2] = canon; - HEAPU32[(ai + 20) >> 2] = sa; - if (family === 10) { - HEAP32[(ai + 16) >> 2] = 28; - } else { - HEAP32[(ai + 16) >> 2] = 16; - } - HEAP32[(ai + 28) >> 2] = 0; - - return ai; - } - - if (hint) { - flags = HEAP32[hint >> 2]; - family = HEAP32[(hint + 4) >> 2]; - type = HEAP32[(hint + 8) >> 2]; - proto = HEAP32[(hint + 12) >> 2]; - } - if (type && !proto) { - proto = type === 2 ? 17 : 6; - } - if (!type && proto) { - type = proto === 17 ? 2 : 1; - } - - // If type or proto are set to zero in hints we should really be returning multiple addrinfo values, but for - // now default to a TCP STREAM socket so we can at least return a sensible addrinfo given NULL hints. - if (proto === 0) { - proto = 6; - } - if (type === 0) { - type = 1; - } - - if (!node && !service) { - return -2; - } - if (flags & ~(1 | 2 | 4 | 1024 | 8 | 16 | 32)) { - return -1; - } - if (hint !== 0 && HEAP32[hint >> 2] & 2 && !node) { - return -1; - } - if (flags & 32) { - // TODO - return -2; - } - if (type !== 0 && type !== 1 && type !== 2) { - return -7; - } - if (family !== 0 && family !== 2 && family !== 10) { - return -6; - } - - if (service) { - service = UTF8ToString(service); - port = parseInt(service, 10); - - if (isNaN(port)) { - if (flags & 1024) { - return -2; - } - // TODO support resolving well-known service names from: - // http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt - return -8; - } - } - - if (!node) { - if (family === 0) { - family = 2; - } - if ((flags & 1) === 0) { - if (family === 2) { - addr = _htonl(2130706433); - } else { - addr = [0, 0, 0, _htonl(1)]; - } - } - ai = allocaddrinfo(family, type, proto, null, addr, port); - HEAPU32[out >> 2] = ai; - return 0; - } - - // - // try as a numeric address - // - node = UTF8ToString(node); - addr = inetPton4(node); - if (addr !== null) { - // incoming node is a valid ipv4 address - if (family === 0 || family === 2) { - family = 2; - } else if (family === 10 && flags & 8) { - addr = [0, 0, _htonl(0xffff), addr]; - family = 10; - } else { - return -2; - } - } else { - addr = inetPton6(node); - if (addr !== null) { - // incoming node is a valid ipv6 address - if (family === 0 || family === 10) { - family = 10; - } else { - return -2; - } - } - } - if (addr != null) { - ai = allocaddrinfo(family, type, proto, node, addr, port); - HEAPU32[out >> 2] = ai; - return 0; - } - if (flags & 4) { - return -2; - } - - // - // try as a hostname - // - // resolve the hostname to a temporary fake address - node = DNS.lookup_name(node); - addr = inetPton4(node); - if (family === 0) { - family = 2; - } else if (family === 10) { - addr = [0, 0, _htonl(0xffff), addr]; - } - ai = allocaddrinfo(family, type, proto, null, addr, port); - HEAPU32[out >> 2] = ai; - return 0; - }; - _getaddrinfo.sig = 'ipppp'; - - var _getnameinfo = (sa, salen, node, nodelen, serv, servlen, flags) => { - var info = readSockaddr(sa, salen); - if (info.errno) { - return -6; - } - var port = info.port; - var addr = info.addr; - - var overflowed = false; - - if (node && nodelen) { - var lookup; - if (flags & 1 || !(lookup = DNS.lookup_addr(addr))) { - if (flags & 8) { - return -2; - } - } else { - addr = lookup; - } - var numBytesWrittenExclNull = stringToUTF8(addr, node, nodelen); - - if (numBytesWrittenExclNull + 1 >= nodelen) { - overflowed = true; - } - } - - if (serv && servlen) { - port = '' + port; - var numBytesWrittenExclNull = stringToUTF8(port, serv, servlen); - - if (numBytesWrittenExclNull + 1 >= servlen) { - overflowed = true; - } - } - - if (overflowed) { - // Note: even when we overflow, getnameinfo() is specced to write out the truncated results. - return -12; - } - - return 0; - }; - _getnameinfo.sig = 'ipipipii'; - - var Protocols = { - list: [], - map: {}, - }; - - var stringToAscii = (str, buffer) => { - for (var i = 0; i < str.length; ++i) { - HEAP8[buffer++] = str.charCodeAt(i); - } - // Null-terminate the string - HEAP8[buffer] = 0; - }; - - var _setprotoent = (stayopen) => { - // void setprotoent(int stayopen); - - // Allocate and populate a protoent structure given a name, protocol number and array of aliases - function allocprotoent(name, proto, aliases) { - // write name into buffer - var nameBuf = _malloc(name.length + 1); - stringToAscii(name, nameBuf); - - // write aliases into buffer - var j = 0; - var length = aliases.length; - var aliasListBuf = _malloc((length + 1) * 4); // Use length + 1 so we have space for the terminating NULL ptr. - - for (var i = 0; i < length; i++, j += 4) { - var alias = aliases[i]; - var aliasBuf = _malloc(alias.length + 1); - stringToAscii(alias, aliasBuf); - HEAPU32[(aliasListBuf + j) >> 2] = aliasBuf; - } - HEAPU32[(aliasListBuf + j) >> 2] = 0; // Terminating NULL pointer. - - // generate protoent - var pe = _malloc(12); - HEAPU32[pe >> 2] = nameBuf; - HEAPU32[(pe + 4) >> 2] = aliasListBuf; - HEAP32[(pe + 8) >> 2] = proto; - return pe; - } - - // Populate the protocol 'database'. The entries are limited to tcp and udp, though it is fairly trivial - // to add extra entries from /etc/protocols if desired - though not sure if that'd actually be useful. - var list = Protocols.list; - var map = Protocols.map; - if (list.length === 0) { - var entry = allocprotoent('tcp', 6, ['TCP']); - list.push(entry); - map['tcp'] = map['6'] = entry; - entry = allocprotoent('udp', 17, ['UDP']); - list.push(entry); - map['udp'] = map['17'] = entry; - } - - _setprotoent.index = 0; - }; - _setprotoent.sig = 'vi'; - - var _getprotobyname = (name) => { - // struct protoent *getprotobyname(const char *); - name = UTF8ToString(name); - _setprotoent(true); - var result = Protocols.map[name]; - return result; - }; - _getprotobyname.sig = 'pp'; - - var _getprotobynumber = (number) => { - // struct protoent *getprotobynumber(int proto); - _setprotoent(true); - var result = Protocols.map[number]; - return result; - }; - _getprotobynumber.sig = 'pi'; - - function _js_flock(fd, op) { - _js_wasm_trace('js_flock(%d, %d)', fd, op); - // Emscripten does not expose these constants to JS, so we hardcode them here. - // Based on - // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 - const emscripten_LOCK_SH = 1; - const emscripten_LOCK_EX = 2; - const emscripten_LOCK_NB = 4; - const emscripten_LOCK_UN = 8; - - const flockToLockOpType = { - [emscripten_LOCK_SH]: 'shared', - [emscripten_LOCK_EX]: 'exclusive', - [emscripten_LOCK_UN]: 'unlocked', - }; - - let vfsPath; - let errno; - - [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', - fd, - op, - vfsPath, - errno - ); - return -errno; - } - - if (!locking.is_path_to_shared_fs(vfsPath)) { - _js_wasm_trace( - 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', - fd, - op, - vfsPath - ); - // If not a NodeFS path, we can't lock it. - // Default to succeeding as Emscripten does. - return 0; - } - - errno = locking.check_lock_params(fd, op); - if (errno !== 0) { - _js_wasm_trace( - 'js_flock(%d, %d) check_lock_params errno %d', - fd, - op, - errno - ); - return -errno; - } - - // @TODO: Consider supporting blocking mode of flock() - if (op & (emscripten_LOCK_NB === 0)) { - _js_wasm_trace( - 'js_flock(%d, %d) blocking mode of flock() is not implemented', - fd, - op - ); - // We do not yet support the blocking form of flock(). - // We respond with EINVAL to indicate failure - // because it is a known errno for a failed blocking flock(). - return -ERRNO_CODES.EINVAL; - } - - const maskedOp = - op & (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); - - const lockOpType = flockToLockOpType[maskedOp]; - if (lockOpType === undefined) { - _js_wasm_trace( - 'js_flock(%d, %d) invalid flock() operation', - fd, - op - ); - return -ERRNO_CODES.EINVAL; - } - - try { - const nativeFilePath = - locking.get_native_path_from_vfs_path(vfsPath); - const obtainedLock = PHPLoader.fileLockManager.lockWholeFile( - nativeFilePath, - { - type: lockOpType, - pid: PHPLoader.processId, - fd, - } - ); - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile %s returned %d', - fd, - op, - vfsPath, - obtainedLock - ); - if (obtainedLock) { - locking.maybeLockedFds.add(fd); - return 0; - } else { - return -ERRNO_CODES.EWOULDBLOCK; - } - } catch (e) { - _js_wasm_trace( - 'js_flock(%d, %d) lockWholeFile error %s', - fd, - op, - e - ); - return -ERRNO_CODES.EINVAL; - } - } +async function getWasmBinary(binaryFile) { + // If we don't have the binary yet, load it asynchronously using readAsync. + if (!wasmBinary) { + // Fetch the binary using readAsync + try { + var response = await readAsync(binaryFile); + return new Uint8Array(response); + } catch { + // Fall back to getBinarySync below; + } + } - function _js_open_process( - command, - argsPtr, - argsLength, - descriptorsPtr, - descriptorsLength, - cwdPtr, - cwdLength, - envPtr, - envLength - ) { - if (!command) { - ___errno_location(ERRNO_CODES.EINVAL); - return -1; - } - - const cmdstr = UTF8ToString(command); - if (!cmdstr.length) { - ___errno_location(ERRNO_CODES.EINVAL); - return -1; - } - - let argsArray = []; - if (argsLength) { - for (var i = 0; i < argsLength; i++) { - const charPointer = argsPtr + i * 4; - argsArray.push(UTF8ToString(HEAPU32[charPointer >> 2])); - } - } - - const cwdstr = cwdPtr ? UTF8ToString(cwdPtr) : FS.cwd(); - let envObject = null; - - if (envLength) { - envObject = {}; - for (var i = 0; i < envLength; i++) { - const envPointer = envPtr + i * 4; - const envEntry = UTF8ToString(HEAPU32[envPointer >> 2]); - const splitAt = envEntry.indexOf('='); - if (splitAt === -1) { - continue; - } - const key = envEntry.substring(0, splitAt); - const value = envEntry.substring(splitAt + 1); - envObject[key] = value; - } - } - - var std = {}; - // Extracts an array of available descriptors that should be dispatched to streams. - // On the C side, the descriptors are expressed as `**int` so we must go read - // each of the `descriptorsLength` `*int` pointers and convert the associated data into - // a JavaScript object { descriptor : { child : fd, parent : fd } }. - for (var i = 0; i < descriptorsLength; i++) { - const descriptorPtr = HEAPU32[(descriptorsPtr + i * 4) >> 2]; - std[HEAPU32[descriptorPtr >> 2]] = { - child: HEAPU32[(descriptorPtr + 4) >> 2], - parent: HEAPU32[(descriptorPtr + 8) >> 2], - }; - // swap parent and child descs until we rebuild PHP 7.4 - if (i === 0) { - HEAPU32[(descriptorPtr + 8) >> 2] = - std[HEAPU32[descriptorPtr >> 2]].parent; - HEAPU32[(descriptorPtr + 4) >> 2] = - std[HEAPU32[descriptorPtr >> 2]].child; - } - } - - return Asyncify.handleAsync(async () => { - let cp; - try { - const options = {}; - if (cwdstr !== null) { - options.cwd = cwdstr; - } - if (envObject !== null) { - options.env = envObject; - } - cp = PHPWASM.spawnProcess(cmdstr, argsArray, options); - if (cp instanceof Promise) { - cp = await cp; - } - } catch (e) { - if (e.code === 'SPAWN_UNSUPPORTED') { - ___errno_location(ERRNO_CODES.ENOSYS); - return -1; - } - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) - throw e; - ___errno_location(e.code); - return -1; - } - - const ProcInfo = { - pid: cp.pid, - exited: false, - }; - PHPWASM.processTable[ProcInfo.pid] = ProcInfo; - - const stdinParentFd = std[0]?.parent, - stdinChildFd = std[0]?.child, - stdoutChildFd = std[1]?.child, - stdoutParentFd = std[1]?.parent, - stderrChildFd = std[2]?.child, - stderrParentFd = std[2]?.parent; - - cp.on('exit', function (code) { - for (const fd of [ - // The child process exited. Let's clean up its output streams: - stdoutChildFd, - stderrChildFd, - stdinChildFd, - - // We won't close these because the PHP already handles that in the parent process: - // stdoutParentFd, - // stderrParentFd, - // stdinParentFd, - ]) { - if (FS.streams[fd] && !FS.isClosed(FS.streams[fd])) { - FS.close(FS.streams[fd]); - } - } - - ProcInfo.exitCode = code; - ProcInfo.exited = true; - }); - - // Pass data from child process's stdout to PHP's end of the stdout pipe. - if (stdoutChildFd) { - const stdoutStream = SYSCALLS.getStreamFromFD(stdoutChildFd); - let stdoutAt = 0; - cp.stdout.on('data', function (data) { - stdoutStream.stream_ops.write( - stdoutStream, - data, - 0, - data.length, - stdoutAt - ); - stdoutAt += data.length; - }); - } - - // Pass data from child process's stderr to PHP's end of the stdout pipe. - if (stderrChildFd) { - const stderrStream = SYSCALLS.getStreamFromFD(stderrChildFd); - let stderrAt = 0; - cp.stderr.on('data', function (data) { - stderrStream.stream_ops.write( - stderrStream, - data, - 0, - data.length, - stderrAt - ); - stderrAt += data.length; - }); - } - - /** - * Wait until the child process has been spawned. - * Unfortunately there is no Node.js API to check whether - * the process has already been spawned. We can only listen - * to the 'spawn' event and if it has already been spawned, - * listen to the 'exit' event. - */ - try { - await new Promise((resolve, reject) => { - /** - * There was no `await` between the `spawnProcess` call - * and the `await` below so the process haven't had a chance - * to run any of the exit-related callbacks yet. - * - * Good. - * - * Let's listen to all the lifecycle events and resolve - * the promise when the process starts or immediately crashes. - */ - let resolved = false; - cp.on('spawn', () => { - if (resolved) return; - resolved = true; - resolve(); - }); - cp.on('error', (e) => { - if (resolved) return; - resolved = true; - reject(e); - }); - cp.on('exit', function (code) { - if (resolved) return; - resolved = true; - if (code === 0) { - resolve(); - } else { - reject( - new Error(`Process exited with code ${code}`) - ); - } - }); - /** - * If the process haven't even started after 5 seconds, something - * is wrong. Perhaps we're missing an event listener, or perhaps - * the `spawnProcess` implementation failed to dispatch the relevant - * event. Either way, let's crash to avoid blocking the proc_open() - * call indefinitely. - */ - setTimeout(() => { - if (resolved) return; - resolved = true; - reject(new Error('Process timed out')); - }, 5000); - }); - } catch (e) { - // Process already started. Even if it exited early, PHP still - // needs to know about the pid and clean up the resources. - console.error(e); - return ProcInfo.pid; - } - - // Now we want to pass data from the STDIN source supplied by PHP - // to the child process. - if (stdinChildFd) { - // We're in a kernel function used instead of fork(). - // - // We are the ones responsible for pumping the data from the stdinChildFd - // into the child process. There is no concurrent task operating on the - // piped data or polling the file descriptors, etc. Nothing will ever - // read from the stdinChildFd if we don't do it here. - // - // Well, let's do it! We'll periodically read from the child end of the - // data pipe and push what we get into the child process. - let stdinStream; - try { - stdinStream = SYSCALLS.getStreamFromFD(stdinChildFd); - } catch (e) { - ___errno_location(ERRNO_CODES.EBADF); - return ProcInfo.pid; - } - if (!stdinStream?.node) { - return ProcInfo.pid; - } - - // Pipe the entire stdinStream to cp.stdin - const CHUNK_SIZE = 1024; - - const iov = _malloc(16); // Space for iovec structure - const pnum = _malloc(4); // Space for number of bytes read - const buffer = _malloc(CHUNK_SIZE); - - // Set up iovec structure pointing to our buffer - HEAPU32[iov >> 2] = buffer; // iov_base - HEAPU32[(iov + 4) >> 2] = CHUNK_SIZE; // iov_len - - function pump() { - try { - while (true) { - if (cp.killed) { - stopPumpingAndCloseStdin(); - return; - } - - const result = js_fd_read( - stdinChildFd, - iov, - 1, - pnum, - false - ); - const bytesRead = HEAPU32[pnum >> 2]; - if (result === 0 && bytesRead > 0) { - const wrote = HEAPU8.subarray( - buffer, - buffer + bytesRead - ); - cp.stdin.write(wrote); - // We've read some data. Let the next iteration decide - // how to break out of the loop. - } else if (result === 0 && bytesRead === 0) { - // result === 0 and bytesRead === 0 means the file descriptor - // is at EOF. Let's close the stdin stream and clean up. - stopPumpingAndCloseStdin(); - break; - } else if (result === ERRNO_CODES.EAGAIN) { - // The file descriptor is not ready for reading. - // Let's break out of the loop. setInterval will invoke - // this function again soon. - break; - } else { - throw new FS.ErrnoError(result); - } - } - } catch (e) { - if ( - typeof FS == 'undefined' || - !(e.name === 'ErrnoError') - ) { - throw e; - } - ___errno_location(e.errno); - stopPumpingAndCloseStdin(); - } - } - function stopPumpingAndCloseStdin() { - clearInterval(interval); - if (!cp.stdin.closed) { - cp.stdin.end(); - } - _free(buffer); - _free(iov); - _free(pnum); - } - - // pump() can never alter the result of this function. - // Even when it fails, we still return the pid. - // Why? - // Because the process already started. We wouldn't backtrack - // with fork(), we won't backtrack here. Let's give PHP the pid, - // and let it think it's the parent process. It will clean up the - // resources as needed. - - // stdin may be non-blocking – let's check for updates periodically. - // If we exhaust it at any point, pump() will self-terminate. - // - // Note handling any failures, closing the descriptor, etc. will not - // happen synchronously when PHP calls fclose($pipes[0]) or proc_close(). - // It will all happen asynchronously on the next tick. It seems off, - // but there doesn't seem to be a better way: cp.stdin.write() and - // cp.stdin.end() are both async APIs and they both accept onCompleted - // callbacks. - const interval = setInterval(pump, 20); - pump(); - } - - return ProcInfo.pid; - }); - } + // Otherwise, getBinarySync should be able to get it synchronously + return getBinarySync(binaryFile); +} - function _js_process_status(pid, exitCodePtr) { - if (!PHPWASM.processTable[pid]) { - return -1; - } - if (PHPWASM.processTable[pid].exited) { - HEAPU32[exitCodePtr >> 2] = PHPWASM.processTable[pid].exitCode; - return 1; - } - return 0; - } +async function instantiateArrayBuffer(binaryFile, imports) { + try { + var binary = await getWasmBinary(binaryFile); + var instance = await WebAssembly.instantiate(binary, imports); + return instance; + } catch (reason) { + err(`failed to asynchronously prepare wasm: ${reason}`); - function _js_release_file_locks() { - _js_wasm_trace('js_release_file_locks()'); - const pid = PHPLoader.processId; - if (!pid || !PHPLoader.fileLockManager) { - _js_wasm_trace('js_release_file_locks no pid or file lock manager'); - return 0; - } - - try { - PHPLoader.fileLockManager.releaseLocksForProcess(pid); - _js_wasm_trace('js_release_file_locks succeeded'); - } catch (e) { - _js_wasm_trace('js_release_file_locks error %s', e); - } - } + abort(reason); + } +} - function _js_waitpid(pid, exitCodePtr) { - if (!PHPWASM.processTable[pid]) { - return -1; - } - return Asyncify.handleSleep((wakeUp) => { - const poll = function () { - if (PHPWASM.processTable[pid]?.exited) { - HEAPU32[exitCodePtr >> 2] = - PHPWASM.processTable[pid].exitCode; - wakeUp(pid); - } else { - setTimeout(poll, 50); - } - }; - poll(); - }); - } +async function instantiateAsync(binary, binaryFile, imports) { + if (!binary + // Avoid instantiateStreaming() on Node.js environment for now, as while + // Node.js v18.1.0 implements it, it does not have a full fetch() + // implementation yet. + // + // Reference: + // https://github.com/emscripten-core/emscripten/pull/16917 + && !ENVIRONMENT_IS_NODE + ) { + try { + var response = fetch(binaryFile, { credentials: 'same-origin' }); + var instantiationResult = await WebAssembly.instantiateStreaming(response, imports); + return instantiationResult; + } catch (reason) { + // We expect the most common failure cause to be a bad MIME type for the binary, + // in which case falling back to ArrayBuffer instantiation should work. + err(`wasm streaming compile failed: ${reason}`); + err('falling back to ArrayBuffer instantiation'); + // fall back of instantiateArrayBuffer below + }; + } + return instantiateArrayBuffer(binaryFile, imports); +} - function _random_get(buffer, size) { - try { - randomFill(HEAPU8.subarray(buffer, buffer + size)); - return 0; - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return e.errno; - } - } - _random_get.sig = 'ipp'; - - var arraySum = (array, index) => { - var sum = 0; - for (var i = 0; i <= index; sum += array[i++]) { - // no-op - } - return sum; - }; - - var MONTH_DAYS_LEAP = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; - - var MONTH_DAYS_REGULAR = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; - var addDays = (date, days) => { - var newDate = new Date(date.getTime()); - while (days > 0) { - var leap = isLeapYear(newDate.getFullYear()); - var currentMonth = newDate.getMonth(); - var daysInCurrentMonth = ( - leap ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR - )[currentMonth]; - - if (days > daysInCurrentMonth - newDate.getDate()) { - // we spill over to next month - days -= daysInCurrentMonth - newDate.getDate() + 1; - newDate.setDate(1); - if (currentMonth < 11) { - newDate.setMonth(currentMonth + 1); - } else { - newDate.setMonth(0); - newDate.setFullYear(newDate.getFullYear() + 1); - } - } else { - // we stay in current month - newDate.setDate(newDate.getDate() + days); - return newDate; - } - } - - return newDate; - }; - - var _strptime = (buf, format, tm) => { - // char *strptime(const char *restrict buf, const char *restrict format, struct tm *restrict tm); - // http://pubs.opengroup.org/onlinepubs/009695399/functions/strptime.html - var pattern = UTF8ToString(format); - - // escape special characters - // TODO: not sure we really need to escape all of these in JS regexps - var SPECIAL_CHARS = '\\!@#$^&*()+=-[]/{}|:<>?,.'; - for (var i = 0, ii = SPECIAL_CHARS.length; i < ii; ++i) { - pattern = pattern.replace( - new RegExp('\\' + SPECIAL_CHARS[i], 'g'), - '\\' + SPECIAL_CHARS[i] - ); - } - - // reduce number of matchers - var EQUIVALENT_MATCHERS = { - A: '%a', - B: '%b', - c: '%a %b %d %H:%M:%S %Y', - D: '%m\\/%d\\/%y', - e: '%d', - F: '%Y-%m-%d', - h: '%b', - R: '%H\\:%M', - r: '%I\\:%M\\:%S\\s%p', - T: '%H\\:%M\\:%S', - x: '%m\\/%d\\/(?:%y|%Y)', - X: '%H\\:%M\\:%S', - }; - // TODO: take care of locale - - var DATE_PATTERNS = { - /* weekday name */ a: '(?:Sun(?:day)?)|(?:Mon(?:day)?)|(?:Tue(?:sday)?)|(?:Wed(?:nesday)?)|(?:Thu(?:rsday)?)|(?:Fri(?:day)?)|(?:Sat(?:urday)?)', - /* month name */ b: '(?:Jan(?:uary)?)|(?:Feb(?:ruary)?)|(?:Mar(?:ch)?)|(?:Apr(?:il)?)|May|(?:Jun(?:e)?)|(?:Jul(?:y)?)|(?:Aug(?:ust)?)|(?:Sep(?:tember)?)|(?:Oct(?:ober)?)|(?:Nov(?:ember)?)|(?:Dec(?:ember)?)', - /* century */ C: '\\d\\d', - /* day of month */ d: '0[1-9]|[1-9](?!\\d)|1\\d|2\\d|30|31', - /* hour (24hr) */ H: '\\d(?!\\d)|[0,1]\\d|20|21|22|23', - /* hour (12hr) */ I: '\\d(?!\\d)|0\\d|10|11|12', - /* day of year */ j: '00[1-9]|0?[1-9](?!\\d)|0?[1-9]\\d(?!\\d)|[1,2]\\d\\d|3[0-6]\\d', - /* month */ m: '0[1-9]|[1-9](?!\\d)|10|11|12', - /* minutes */ M: '0\\d|\\d(?!\\d)|[1-5]\\d', - /* whitespace */ n: ' ', - /* AM/PM */ p: 'AM|am|PM|pm|A\\.M\\.|a\\.m\\.|P\\.M\\.|p\\.m\\.', - /* seconds */ S: '0\\d|\\d(?!\\d)|[1-5]\\d|60', - /* week number */ U: '0\\d|\\d(?!\\d)|[1-4]\\d|50|51|52|53', - /* week number */ W: '0\\d|\\d(?!\\d)|[1-4]\\d|50|51|52|53', - /* weekday number */ w: '[0-6]', - /* 2-digit year */ y: '\\d\\d', - /* 4-digit year */ Y: '\\d\\d\\d\\d', - /* whitespace */ t: ' ', - /* time zone */ z: 'Z|(?:[\\+\\-]\\d\\d:?(?:\\d\\d)?)', - }; - - var MONTH_NUMBERS = { - JAN: 0, - FEB: 1, - MAR: 2, - APR: 3, - MAY: 4, - JUN: 5, - JUL: 6, - AUG: 7, - SEP: 8, - OCT: 9, - NOV: 10, - DEC: 11, - }; - var DAY_NUMBERS_SUN_FIRST = { - SUN: 0, - MON: 1, - TUE: 2, - WED: 3, - THU: 4, - FRI: 5, - SAT: 6, - }; - var DAY_NUMBERS_MON_FIRST = { - MON: 0, - TUE: 1, - WED: 2, - THU: 3, - FRI: 4, - SAT: 5, - SUN: 6, - }; - - var capture = []; - var pattern_out = pattern - .replace(/%(.)/g, (m, c) => EQUIVALENT_MATCHERS[c] || m) - .replace(/%(.)/g, (_, c) => { - let pat = DATE_PATTERNS[c]; - if (pat) { - capture.push(c); - return `(${pat})`; - } else { - return c; - } - }) - .replace( - // any number of space or tab characters match zero or more spaces - /\s+/g, - '\\s*' - ); - - var matches = new RegExp('^' + pattern_out, 'i').exec( - UTF8ToString(buf) - ); - - function initDate() { - function fixup(value, min, max) { - return typeof value != 'number' || isNaN(value) - ? min - : value >= min - ? value <= max - ? value - : max - : min; - } - return { - year: fixup(HEAP32[(tm + 20) >> 2] + 1900, 1970, 9999), - month: fixup(HEAP32[(tm + 16) >> 2], 0, 11), - day: fixup(HEAP32[(tm + 12) >> 2], 1, 31), - hour: fixup(HEAP32[(tm + 8) >> 2], 0, 23), - min: fixup(HEAP32[(tm + 4) >> 2], 0, 59), - sec: fixup(HEAP32[tm >> 2], 0, 59), - gmtoff: 0, - }; - } - - if (matches) { - var date = initDate(); - var value; - - var getMatch = (symbol) => { - var pos = capture.indexOf(symbol); - // check if symbol appears in regexp - if (pos >= 0) { - // return matched value or null (falsy!) for non-matches - return matches[pos + 1]; - } - return; - }; - - // seconds - if ((value = getMatch('S'))) { - date.sec = Number(value); - } - - // minutes - if ((value = getMatch('M'))) { - date.min = Number(value); - } - - // hours - if ((value = getMatch('H'))) { - // 24h clock - date.hour = Number(value); - } else if ((value = getMatch('I'))) { - // AM/PM clock - var hour = Number(value); - if ((value = getMatch('p'))) { - hour += value.toUpperCase()[0] === 'P' ? 12 : 0; - } - date.hour = hour; - } - - // year - if ((value = getMatch('Y'))) { - // parse from four-digit year - date.year = Number(value); - } else if ((value = getMatch('y'))) { - // parse from two-digit year... - var year = Number(value); - if ((value = getMatch('C'))) { - // ...and century - year += Number(value) * 100; - } else { - // ...and rule-of-thumb - year += year < 69 ? 2000 : 1900; - } - date.year = year; - } - - // month - if ((value = getMatch('m'))) { - // parse from month number - date.month = Number(value) - 1; - } else if ((value = getMatch('b'))) { - // parse from month name - date.month = - MONTH_NUMBERS[value.substring(0, 3).toUpperCase()] || 0; - // TODO: derive month from day in year+year, week number+day of week+year - } - - // day - if ((value = getMatch('d'))) { - // get day of month directly - date.day = Number(value); - } else if ((value = getMatch('j'))) { - // get day of month from day of year ... - var day = Number(value); - var leapYear = isLeapYear(date.year); - for (var month = 0; month < 12; ++month) { - var daysUntilMonth = arraySum( - leapYear ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR, - month - 1 - ); - if ( - day <= - daysUntilMonth + - (leapYear ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR)[ - month - ] - ) { - date.day = day - daysUntilMonth; - } - } - } else if ((value = getMatch('a'))) { - // get day of month from weekday ... - var weekDay = value.substring(0, 3).toUpperCase(); - if ((value = getMatch('U'))) { - // ... and week number (Sunday being first day of week) - // Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. - // All days in a new year preceding the first Sunday are considered to be in week 0. - var weekDayNumber = DAY_NUMBERS_SUN_FIRST[weekDay]; - var weekNumber = Number(value); - - // January 1st - var janFirst = new Date(date.year, 0, 1); - var endDate; - if (janFirst.getDay() === 0) { - // Jan 1st is a Sunday, and, hence in the 1st CW - endDate = addDays( - janFirst, - weekDayNumber + 7 * (weekNumber - 1) - ); - } else { - // Jan 1st is not a Sunday, and, hence still in the 0th CW - endDate = addDays( - janFirst, - 7 - - janFirst.getDay() + - weekDayNumber + - 7 * (weekNumber - 1) - ); - } - date.day = endDate.getDate(); - date.month = endDate.getMonth(); - } else if ((value = getMatch('W'))) { - // ... and week number (Monday being first day of week) - // Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. - // All days in a new year preceding the first Monday are considered to be in week 0. - var weekDayNumber = DAY_NUMBERS_MON_FIRST[weekDay]; - var weekNumber = Number(value); - - // January 1st - var janFirst = new Date(date.year, 0, 1); - var endDate; - if (janFirst.getDay() === 1) { - // Jan 1st is a Monday, and, hence in the 1st CW - endDate = addDays( - janFirst, - weekDayNumber + 7 * (weekNumber - 1) - ); - } else { - // Jan 1st is not a Monday, and, hence still in the 0th CW - endDate = addDays( - janFirst, - 7 - - janFirst.getDay() + - 1 + - weekDayNumber + - 7 * (weekNumber - 1) - ); - } - - date.day = endDate.getDate(); - date.month = endDate.getMonth(); - } - } - - // time zone - if ((value = getMatch('z'))) { - // GMT offset as either 'Z' or +-HH:MM or +-HH or +-HHMM - if (value.toLowerCase() === 'z') { - date.gmtoff = 0; - } else { - var match = value.match(/^((?:\-|\+)\d\d):?(\d\d)?/); - date.gmtoff = match[1] * 3600; - if (match[2]) { - date.gmtoff += - date.gmtoff > 0 ? match[2] * 60 : -match[2] * 60; - } - } - } - - /* - tm_sec int seconds after the minute 0-61* - tm_min int minutes after the hour 0-59 - tm_hour int hours since midnight 0-23 - tm_mday int day of the month 1-31 - tm_mon int months since January 0-11 - tm_year int years since 1900 - tm_wday int days since Sunday 0-6 - tm_yday int days since January 1 0-365 - tm_isdst int Daylight Saving Time flag - tm_gmtoff long offset from GMT (seconds) - */ +function getWasmImports() { + // prepare imports + var imports = { + 'env': wasmImports, + 'wasi_snapshot_preview1': wasmImports, + 'GOT.mem': new Proxy(wasmImports, GOTHandler), + 'GOT.func': new Proxy(wasmImports, GOTHandler), + }; + return imports; +} - var fullDate = new Date( - date.year, - date.month, - date.day, - date.hour, - date.min, - date.sec, - 0 - ); - HEAP32[tm >> 2] = fullDate.getSeconds(); - HEAP32[(tm + 4) >> 2] = fullDate.getMinutes(); - HEAP32[(tm + 8) >> 2] = fullDate.getHours(); - HEAP32[(tm + 12) >> 2] = fullDate.getDate(); - HEAP32[(tm + 16) >> 2] = fullDate.getMonth(); - HEAP32[(tm + 20) >> 2] = fullDate.getFullYear() - 1900; - HEAP32[(tm + 24) >> 2] = fullDate.getDay(); - HEAP32[(tm + 28) >> 2] = - arraySum( - isLeapYear(fullDate.getFullYear()) - ? MONTH_DAYS_LEAP - : MONTH_DAYS_REGULAR, - fullDate.getMonth() - 1 - ) + - fullDate.getDate() - - 1; - HEAP32[(tm + 32) >> 2] = 0; - HEAP32[(tm + 36) >> 2] = date.gmtoff; - - // we need to convert the matched sequence into an integer array to take care of UTF-8 characters > 0x7F - // TODO: not sure that intArrayFromString handles all unicode characters correctly - return buf + lengthBytesUTF8(matches[0]); - } - - return 0; - }; - _strptime.sig = 'pppp'; - - function _wasm_close(socketd) { - return PHPWASM.shutdownSocket(socketd, 2); - } +// Create the wasm instance. +// Receives the wasm imports, returns the exports. +async function createWasm() { + // Load the wasm module and create an instance of using native support in the JS engine. + // handle a generated wasm instance, receiving its exports and + // performing other necessary setup + /** @param {WebAssembly.Module=} module*/ + function receiveInstance(instance, module) { + wasmExports = instance.exports; + + // No relocation needed here.. but calling this just so that updateGOT is + // called. + var origExports = wasmExports = relocateExports(wasmExports); + + wasmExports = Asyncify.instrumentWasmExports(wasmExports); + + mergeLibSymbols(wasmExports, 'main') + var metadata = getDylinkMetadata(module); + if (metadata.neededDynlibs) { + dynamicLibraries = metadata.neededDynlibs.concat(dynamicLibraries); + } - function _wasm_setsockopt( - socketd, - level, - optionName, - optionValuePtr, - optionLen - ) { - const optionValue = HEAPU8[optionValuePtr]; - const SOL_SOCKET = 1; - const SO_KEEPALIVE = 9; - const IPPROTO_TCP = 6; - const TCP_NODELAY = 1; - const isSupported = - (level === SOL_SOCKET && optionName === SO_KEEPALIVE) || - (level === IPPROTO_TCP && optionName === TCP_NODELAY); - if (!isSupported) { - console.warn( - `Unsupported socket option: ${level}, ${optionName}, ${optionValue}` - ); - return -1; - } - const ws = PHPWASM.getAllWebSockets(socketd)[0]; - if (!ws) { - return -1; - } - ws.setSocketOpt(level, optionName, optionValuePtr); - return 0; - } + assignWasmExports(wasmExports); + + updateGOT(origExports); + + Module['wasmExports'] = wasmExports; + + LDSO.init(); + loadDylibs(); + + updateMemoryViews(); + + removeRunDependency('wasm-instantiate'); + return wasmExports; + } + addRunDependency('wasm-instantiate'); + + // Prefer streaming instantiation if available. + function receiveInstantiationResult(result) { + // 'result' is a ResultObject object which has both the module and instance. + // receiveInstance() will swap in the exports (to Module.asm) so they can be called + return receiveInstance(result['instance'], result['module']); + } + + var info = getWasmImports(); + + // User shell pages can write their own Module.instantiateWasm = function(imports, successCallback) callback + // to manually instantiate the Wasm module themselves. This allows pages to + // run the instantiation parallel to any other async startup actions they are + // performing. + // Also pthreads and wasm workers initialize the wasm instance through this + // path. + if (Module['instantiateWasm']) { + return new Promise((resolve, reject) => { + Module['instantiateWasm'](info, (inst, mod) => { + resolve(receiveInstance(inst, mod)); + }); + }); + } + + wasmBinaryFile ??= findWasmBinary(); + var result = await instantiateAsync(wasmBinary, wasmBinaryFile, info); + var exports = receiveInstantiationResult(result); + return exports; +} - var runAndAbortIfError = (func) => { - try { - return func(); - } catch (e) { - abort(e); - } - }; - - var Asyncify = { - instrumentWasmImports(imports) { - var importPattern = - /^(invoke_i|invoke_ii|invoke_iii|invoke_iiii|invoke_iiiii|invoke_iiiiii|invoke_iiiiiii|invoke_iiiiiiii|invoke_iiiiiiiii|invoke_iiiiiiiiii|invoke_v|invoke_vi|invoke_vii|invoke_viidii|invoke_viii|invoke_viiii|invoke_viiiii|invoke_viiiiii|invoke_viiiiiii|invoke_viiiiiiiii|invoke_i|invoke_ii|invoke_iii|invoke_iiii|invoke_iiiii|invoke_iiiiii|invoke_iiiiiii|invoke_iiiiiiii|invoke_iiiiiiiiii|invoke_iij|invoke_iiji|invoke_iiij|invoke_iijii|invoke_iijiji|invoke_jii|invoke_jiii|invoke_viijii|invoke_vji|js_open_process|_js_open_process|_asyncjs__js_open_process|js_popen_to_file|_js_popen_to_file|_asyncjs__js_popen_to_file|__syscall_fcntl64|___syscall_fcntl64|_asyncjs___syscall_fcntl64|js_release_file_locks|_js_release_file_locks|_async_js_release_file_locks|js_flock|_js_flock|_async_js_flock|js_fd_read|_js_fd_read|fd_close|_fd_close|_asyncjs__fd_close|close|_close|js_module_onMessage|zend_hash_str_find|_js_module_onMessage|_asyncjs__js_module_onMessage|js_waitpid|_js_waitpid|_asyncjs__js_waitpid|wasm_poll_socket|_wasm_poll_socket|_asyncjs__wasm_poll_socket|_wasm_shutdown|_asyncjs__wasm_shutdown|__asyncjs__.*)$/; - - for (let [x, original] of Object.entries(imports)) { - if (typeof original == 'function') { - let isAsyncifyImport = - original.isAsync || importPattern.test(x); - } - } - }, - instrumentFunction(original) { - var wrapper = (...args) => { - Asyncify.exportCallStack.push(original); - try { - return original(...args); - } finally { - if (!ABORT) { - var top = Asyncify.exportCallStack.pop(); - Asyncify.maybeStopUnwind(); - } - } - }; - Asyncify.funcWrappers.set(original, wrapper); - wrapper.orig = original; - return wrapper; - }, - instrumentWasmExports(exports) { - var ret = {}; - for (let [x, original] of Object.entries(exports)) { - if (typeof original == 'function') { - var wrapper = Asyncify.instrumentFunction(original); - ret[x] = wrapper; - } else { - ret[x] = original; - } - } - return ret; - }, - State: { - Normal: 0, - Unwinding: 1, - Rewinding: 2, - Disabled: 3, - }, - state: 0, - StackSize: 4096, - currData: null, - handleSleepReturnValue: 0, - exportCallStack: [], - callstackFuncToId: new Map(), - callStackIdToFunc: new Map(), - funcWrappers: new Map(), - callStackId: 0, - asyncPromiseHandlers: null, - sleepCallbacks: [], - getCallStackId(func) { - if (!Asyncify.callstackFuncToId.has(func)) { - var id = Asyncify.callStackId++; - Asyncify.callstackFuncToId.set(func, id); - Asyncify.callStackIdToFunc.set(id, func); - } - return Asyncify.callstackFuncToId.get(func); - }, - maybeStopUnwind() { - if ( - Asyncify.currData && - Asyncify.state === Asyncify.State.Unwinding && - Asyncify.exportCallStack.length === 0 - ) { - // We just finished unwinding. - // Be sure to set the state before calling any other functions to avoid - // possible infinite recursion here (For example in debug pthread builds - // the dbg() function itself can call back into WebAssembly to get the - // current pthread_self() pointer). - Asyncify.state = Asyncify.State.Normal; - runtimeKeepalivePush(); - // Keep the runtime alive so that a re-wind can be done later. - runAndAbortIfError(_asyncify_stop_unwind); - if (typeof Fibers != 'undefined') { - Fibers.trampoline(); - } - } - }, - whenDone() { - return new Promise((resolve, reject) => { - Asyncify.asyncPromiseHandlers = { resolve, reject }; - }); - }, - allocateData() { - // An asyncify data structure has three fields: - // 0 current stack pos - // 4 max stack pos - // 8 id of function at bottom of the call stack (callStackIdToFunc[id] == wasm func) - // - // The Asyncify ABI only interprets the first two fields, the rest is for the runtime. - // We also embed a stack in the same memory region here, right next to the structure. - // This struct is also defined as asyncify_data_t in emscripten/fiber.h - var ptr = _malloc(12 + Asyncify.StackSize); - Asyncify.setDataHeader(ptr, ptr + 12, Asyncify.StackSize); - Asyncify.setDataRewindFunc(ptr); - return ptr; - }, - setDataHeader(ptr, stack, stackSize) { - HEAPU32[ptr >> 2] = stack; - HEAPU32[(ptr + 4) >> 2] = stack + stackSize; - }, - setDataRewindFunc(ptr) { - var bottomOfCallStack = Asyncify.exportCallStack[0]; - var rewindId = Asyncify.getCallStackId(bottomOfCallStack); - HEAP32[(ptr + 8) >> 2] = rewindId; - }, - getDataRewindFunc(ptr) { - var id = HEAP32[(ptr + 8) >> 2]; - var func = Asyncify.callStackIdToFunc.get(id); - return func; - }, - doRewind(ptr) { - var original = Asyncify.getDataRewindFunc(ptr); - var func = Asyncify.funcWrappers.get(original); - // Once we have rewound and the stack we no longer need to artificially - // keep the runtime alive. - runtimeKeepalivePop(); - return func(); - }, - handleSleep(startAsync) { - if (ABORT) return; - if (Asyncify.state === Asyncify.State.Normal) { - // Prepare to sleep. Call startAsync, and see what happens: - // if the code decided to call our callback synchronously, - // then no async operation was in fact begun, and we don't - // need to do anything. - var reachedCallback = false; - var reachedAfterCallback = false; - startAsync((handleSleepReturnValue = 0) => { - if (ABORT) return; - Asyncify.handleSleepReturnValue = handleSleepReturnValue; - reachedCallback = true; - if (!reachedAfterCallback) { - // We are happening synchronously, so no need for async. - return; - } - Asyncify.state = Asyncify.State.Rewinding; - runAndAbortIfError(() => - _asyncify_start_rewind(Asyncify.currData) - ); - if (typeof MainLoop != 'undefined' && MainLoop.func) { - MainLoop.resume(); - } - var asyncWasmReturnValue, - isError = false; - try { - asyncWasmReturnValue = Asyncify.doRewind( - Asyncify.currData - ); - } catch (err) { - asyncWasmReturnValue = err; - isError = true; - } - // Track whether the return value was handled by any promise handlers. - var handled = false; - if (!Asyncify.currData) { - // All asynchronous execution has finished. - // `asyncWasmReturnValue` now contains the final - // return value of the exported async WASM function. - // - // Note: `asyncWasmReturnValue` is distinct from - // `Asyncify.handleSleepReturnValue`. - // `Asyncify.handleSleepReturnValue` contains the return - // value of the last C function to have executed - // `Asyncify.handleSleep()`, where as `asyncWasmReturnValue` - // contains the return value of the exported WASM function - // that may have called C functions that - // call `Asyncify.handleSleep()`. - var asyncPromiseHandlers = - Asyncify.asyncPromiseHandlers; - if (asyncPromiseHandlers) { - Asyncify.asyncPromiseHandlers = null; - (isError - ? asyncPromiseHandlers.reject - : asyncPromiseHandlers.resolve)( - asyncWasmReturnValue - ); - handled = true; - } - } - if (isError && !handled) { - // If there was an error and it was not handled by now, we have no choice but to - // rethrow that error into the global scope where it can be caught only by - // `onerror` or `onunhandledpromiserejection`. - throw asyncWasmReturnValue; - } - }); - reachedAfterCallback = true; - if (!reachedCallback) { - // A true async operation was begun; start a sleep. - Asyncify.state = Asyncify.State.Unwinding; - // TODO: reuse, don't alloc/free every sleep - Asyncify.currData = Asyncify.allocateData(); - if (typeof MainLoop != 'undefined' && MainLoop.func) { - MainLoop.pause(); - } - runAndAbortIfError(() => - _asyncify_start_unwind(Asyncify.currData) - ); - } - } else if (Asyncify.state === Asyncify.State.Rewinding) { - // Stop a resume. - Asyncify.state = Asyncify.State.Normal; - runAndAbortIfError(_asyncify_stop_rewind); - _free(Asyncify.currData); - Asyncify.currData = null; - // Call all sleep callbacks now that the sleep-resume is all done. - Asyncify.sleepCallbacks.forEach(callUserCallback); - } else { - abort(`invalid state: ${Asyncify.state}`); - } - return Asyncify.handleSleepReturnValue; - }, - handleAsync: (startAsync) => - Asyncify.handleSleep((wakeUp) => { - // TODO: add error handling as a second param when handleSleep implements it. - startAsync().then(wakeUp); - }), - }; - - var getCFunc = (ident) => { - var func = Module['_' + ident]; // closure exported function - return func; - }; - - var writeArrayToMemory = (array, buffer) => { - HEAP8.set(array, buffer); - }; - - /** - * @param {string|null=} returnType - * @param {Array=} argTypes - * @param {Array=} args - * @param {Object=} opts - */ - var ccall = (ident, returnType, argTypes, args, opts) => { - // For fast lookup of conversion functions - var toC = { - string: (str) => { - var ret = 0; - if (str !== null && str !== undefined && str !== 0) { - // null string - ret = stringToUTF8OnStack(str); - } - return ret; - }, - array: (arr) => { - var ret = stackAlloc(arr.length); - writeArrayToMemory(arr, ret); - return ret; - }, - }; - - function convertReturnValue(ret) { - if (returnType === 'string') { - return UTF8ToString(ret); - } - if (returnType === 'boolean') return Boolean(ret); - return ret; - } - - var func = getCFunc(ident); - var cArgs = []; - var stack = 0; - if (args) { - for (var i = 0; i < args.length; i++) { - var converter = toC[argTypes[i]]; - if (converter) { - if (stack === 0) stack = stackSave(); - cArgs[i] = converter(args[i]); - } else { - cArgs[i] = args[i]; - } - } - } - // Data for a previous async operation that was in flight before us. - var previousAsync = Asyncify.currData; - var ret = func(...cArgs); - function onDone(ret) { - runtimeKeepalivePop(); - if (stack !== 0) stackRestore(stack); - return convertReturnValue(ret); - } - var asyncMode = opts?.async; - - // Keep the runtime alive through all calls. Note that this call might not be - // async, but for simplicity we push and pop in all calls. - runtimeKeepalivePush(); - if (Asyncify.currData != previousAsync) { - // This is a new async operation. The wasm is paused and has unwound its stack. - // We need to return a Promise that resolves the return value - // once the stack is rewound and execution finishes. - return Asyncify.whenDone().then(onDone); - } - - ret = onDone(ret); - // If this is an async ccall, ensure we return a promise - if (asyncMode) return Promise.resolve(ret); - return ret; - }; - - var FS_createPath = (...args) => FS.createPath(...args); - - var FS_unlink = (...args) => FS.unlink(...args); - - var FS_createLazyFile = (...args) => FS.createLazyFile(...args); - - var FS_createDevice = (...args) => FS.createDevice(...args); - - var writeI53ToI64Clamped = (ptr, num) => { - if (num > 0x7fffffffffffffff) { - HEAPU32[ptr >> 2] = 4294967295; - HEAPU32[(ptr + 4) >> 2] = 2147483647; - } else if (num < -0x8000000000000000) { - HEAPU32[ptr >> 2] = 0; - HEAPU32[(ptr + 4) >> 2] = 2147483648; - } else { - writeI53ToI64(ptr, num); - } - }; - - var writeI53ToI64Signaling = (ptr, num) => { - if (num > 0x7fffffffffffffff || num < -0x8000000000000000) { - throw `RangeError: ${num}`; - } - writeI53ToI64(ptr, num); - }; - - var writeI53ToU64Clamped = (ptr, num) => { - if (num > 0xffffffffffffffff) { - HEAPU32[ptr >> 2] = 4294967295; - HEAPU32[(ptr + 4) >> 2] = 4294967295; - } else if (num < 0) { - HEAPU32[ptr >> 2] = 0; - HEAPU32[(ptr + 4) >> 2] = 0; - } else { - writeI53ToI64(ptr, num); - } - }; - - var writeI53ToU64Signaling = (ptr, num) => { - if (num < 0 || num > 0xffffffffffffffff) { - throw `RangeError: ${num}`; - } - writeI53ToI64(ptr, num); - }; - - var readI53FromU64 = (ptr) => { - return HEAPU32[ptr >> 2] + HEAPU32[(ptr + 4) >> 2] * 4294967296; - }; - - var convertI32PairToI53 = (lo, hi) => { - return (lo >>> 0) + hi * 4294967296; - }; - - var convertI32PairToI53Checked = (lo, hi) => { - return (hi + 0x200000) >>> 0 < 0x400001 - !!lo - ? (lo >>> 0) + hi * 4294967296 - : NaN; - }; - - var convertU32PairToI53 = (lo, hi) => { - return (lo >>> 0) + (hi >>> 0) * 4294967296; - }; - - var getTempRet0 = (val) => __emscripten_tempret_get(); - - var _stackAlloc = stackAlloc; - - var _stackSave = stackSave; - - var _stackRestore = stackSave; - - var _setTempRet0 = setTempRet0; - - var _getTempRet0 = getTempRet0; - - var ptrToString = (ptr) => { - // Convert to 32-bit unsigned value - ptr >>>= 0; - return '0x' + ptr.toString(16).padStart(8, '0'); - }; - - var _emscripten_notify_memory_growth = (memoryIndex) => { - updateMemoryViews(); - }; - _emscripten_notify_memory_growth.sig = 'vp'; - - var strError = (errno) => UTF8ToString(_strerror(errno)); - - var _endprotoent = () => { - // void endprotoent(void); - // We're not using a real protocol database so we don't do a real close. - }; - _endprotoent.sig = 'v'; - - var _getprotoent = (number) => { - // struct protoent *getprotoent(void); - // reads the next entry from the protocols 'database' or return NULL if 'eof' - if (_setprotoent.index === Protocols.list.length) { - return 0; - } - var result = Protocols.list[_setprotoent.index++]; - return result; - }; - _getprotoent.sig = 'p'; - - var Sockets = { - BUFFER_SIZE: 10240, - MAX_BUFFER_SIZE: 10485760, - nextFd: 1, - fds: {}, - nextport: 1, - maxport: 65535, - peer: null, - connections: {}, - portmap: {}, - localAddr: 4261412874, - addrPool: [ - 33554442, 50331658, 67108874, 83886090, 100663306, 117440522, - 134217738, 150994954, 167772170, 184549386, 201326602, 218103818, - 234881034, - ], - }; - - var _emscripten_run_script = (ptr) => { - eval(UTF8ToString(ptr)); - }; - _emscripten_run_script.sig = 'vp'; - - /** @suppress{checkTypes} */ - var _emscripten_run_script_int = (ptr) => { - return eval(UTF8ToString(ptr)) | 0; - }; - _emscripten_run_script_int.sig = 'ip'; - - var _emscripten_run_script_string = (ptr) => { - var s = eval(UTF8ToString(ptr)); - if (s == null) { - return 0; - } - s += ''; - var me = _emscripten_run_script_string; - me.bufferSize = lengthBytesUTF8(s) + 1; - me.buffer = _realloc(me.buffer ?? 0, me.bufferSize); - stringToUTF8(s, me.buffer, me.bufferSize); - return me.buffer; - }; - _emscripten_run_script_string.sig = 'pp'; - - var _emscripten_random = () => Math.random(); - _emscripten_random.sig = 'f'; - - var _emscripten_performance_now = () => performance.now(); - _emscripten_performance_now.sig = 'd'; - - var __emscripten_get_now_is_monotonic = () => nowIsMonotonic; - __emscripten_get_now_is_monotonic.sig = 'i'; - - var warnOnce = (text) => { - warnOnce.shown ||= {}; - if (!warnOnce.shown[text]) { - warnOnce.shown[text] = 1; - if (ENVIRONMENT_IS_NODE) text = 'warning: ' + text; - err(text); - } - }; - - var _emscripten_get_compiler_setting = (name) => - abort( - 'You must build with -sRETAIN_COMPILER_SETTINGS for getCompilerSetting or emscripten_get_compiler_setting to work' - ); - _emscripten_get_compiler_setting.sig = 'pp'; - - var _emscripten_has_asyncify = () => 1; - _emscripten_has_asyncify.sig = 'i'; - - var _emscripten_debugger = () => { - debugger; - }; - _emscripten_debugger.sig = 'v'; - - var _emscripten_print_double = (x, to, max) => { - var str = x + ''; - if (to) return stringToUTF8(str, to, max); - else return lengthBytesUTF8(str); - }; - _emscripten_print_double.sig = 'idpi'; - - var _emscripten_asm_const_double = (code, sigPtr, argbuf) => { - return runEmAsmFunction(code, sigPtr, argbuf); - }; - _emscripten_asm_const_double.sig = 'dppp'; - - var _emscripten_asm_const_ptr = (code, sigPtr, argbuf) => { - return runEmAsmFunction(code, sigPtr, argbuf); - }; - _emscripten_asm_const_ptr.sig = 'pppp'; - - var runMainThreadEmAsm = (emAsmAddr, sigPtr, argbuf, sync) => { - var args = readEmAsmArgs(sigPtr, argbuf); - return ASM_CONSTS[emAsmAddr](...args); - }; - - var _emscripten_asm_const_int_sync_on_main_thread = ( - emAsmAddr, - sigPtr, - argbuf - ) => runMainThreadEmAsm(emAsmAddr, sigPtr, argbuf, 1); - _emscripten_asm_const_int_sync_on_main_thread.sig = 'ippp'; - - var _emscripten_asm_const_ptr_sync_on_main_thread = ( - emAsmAddr, - sigPtr, - argbuf - ) => runMainThreadEmAsm(emAsmAddr, sigPtr, argbuf, 1); - _emscripten_asm_const_ptr_sync_on_main_thread.sig = 'pppp'; - - var _emscripten_asm_const_double_sync_on_main_thread = - _emscripten_asm_const_int_sync_on_main_thread; - _emscripten_asm_const_double_sync_on_main_thread.sig = 'dppp'; - - var _emscripten_asm_const_async_on_main_thread = ( - emAsmAddr, - sigPtr, - argbuf - ) => runMainThreadEmAsm(emAsmAddr, sigPtr, argbuf, 0); - _emscripten_asm_const_async_on_main_thread.sig = 'vppp'; - - var __Unwind_Backtrace = (func, arg) => { - var trace = getCallstack(); - var parts = trace.split('\n'); - for (var i = 0; i < parts.length; i++) { - var ret = (( - a1, - a2 - ) => {}) /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - 0, - arg - ); - if (ret !== 0) return; - } - }; - __Unwind_Backtrace.sig = 'ipp'; - - var __Unwind_GetIPInfo = (context, ipBefore) => abort('Unwind_GetIPInfo'); - __Unwind_GetIPInfo.sig = 'ppp'; - - var __Unwind_FindEnclosingFunction = (ip) => 0; - __Unwind_FindEnclosingFunction.sig = 'pp'; - - var uncaughtExceptionCount = 0; - var ___cxa_throw = (ptr, type, destructor) => { - var info = new ExceptionInfo(ptr); - // Initialize ExceptionInfo content after it was allocated in __cxa_allocate_exception. - info.init(type, destructor); - exceptionLast = ptr; - uncaughtExceptionCount++; - throw exceptionLast; - }; - ___cxa_throw.sig = 'vppp'; - var __Unwind_RaiseException = (ex) => { - err('Warning: _Unwind_RaiseException is not correctly implemented'); - return ___cxa_throw(ex, 0, 0); - }; - __Unwind_RaiseException.sig = 'ip'; - - var __Unwind_DeleteException = (ex) => err('TODO: Unwind_DeleteException'); - __Unwind_DeleteException.sig = 'vp'; - - var getDynCaller = (sig, ptr, promising = false) => { - return (...args) => dynCall(sig, ptr, args, promising); - }; - - var _emscripten_exit_with_live_runtime = () => { - runtimeKeepalivePush(); - throw 'unwind'; - }; - _emscripten_exit_with_live_runtime.sig = 'v'; - - var _emscripten_force_exit = (status) => { - __emscripten_runtime_keepalive_clear(); - _exit(status); - }; - _emscripten_force_exit.sig = 'vi'; - - var _emscripten_outn = (str, len) => out(UTF8ToString(str, len)); - _emscripten_outn.sig = 'vpp'; - - var _emscripten_errn = (str, len) => err(UTF8ToString(str, len)); - _emscripten_errn.sig = 'vpp'; - - var _emscripten_throw_number = (number) => { - throw number; - }; - _emscripten_throw_number.sig = 'vd'; - - var _emscripten_throw_string = (str) => { - throw UTF8ToString(str); - }; - _emscripten_throw_string.sig = 'vp'; - - var _emscripten_runtime_keepalive_push = runtimeKeepalivePush; - _emscripten_runtime_keepalive_push.sig = 'v'; - - var _emscripten_runtime_keepalive_pop = runtimeKeepalivePop; - _emscripten_runtime_keepalive_pop.sig = 'v'; - - var _emscripten_runtime_keepalive_check = keepRuntimeAlive; - _emscripten_runtime_keepalive_check.sig = 'i'; - - var asmjsMangle = (x) => { - if (x == '__main_argc_argv') { - x = 'main'; - } - return x.startsWith('dynCall_') ? x : '_' + x; - }; - - var __emscripten_fs_load_embedded_files = (ptr) => { - do { - var name_addr = HEAPU32[ptr >> 2]; - ptr += 4; - var len = HEAPU32[ptr >> 2]; - ptr += 4; - var content = HEAPU32[ptr >> 2]; - ptr += 4; - var name = UTF8ToString(name_addr); - FS.createPath('/', PATH.dirname(name), true, true); - // canOwn this data in the filesystem, it is a slice of wasm memory that will never change - FS.createDataFile( - name, - null, - HEAP8.subarray(content, content + len), - true, - true, - true - ); - } while (HEAPU32[ptr >> 2]); - }; - __emscripten_fs_load_embedded_files.sig = 'vp'; - - var onInits = []; - - var addOnInit = (cb) => onInits.push(cb); - - var onMains = []; - - var addOnPreMain = (cb) => onMains.push(cb); - - var onExits = []; - - var addOnExit = (cb) => onExits.push(cb); - - var STACK_SIZE = 1048576; - - var STACK_ALIGN = 16; - - var POINTER_SIZE = 4; - - var ASSERTIONS = 0; - - /** - * @param {string=} returnType - * @param {Array=} argTypes - * @param {Object=} opts - */ - var cwrap = (ident, returnType, argTypes, opts) => { - // When the function takes numbers and returns a number, we can just return - // the original function - var numericArgs = - !argTypes || - argTypes.every((type) => type === 'number' || type === 'boolean'); - var numericRet = returnType !== 'string'; - if (numericRet && numericArgs && !opts) { - return getCFunc(ident); - } - return (...args) => ccall(ident, returnType, argTypes, args, opts); - }; +// With MAIN_MODULE + ASYNCIFY the normal method of placing stub functions in +// wasmImports for as-yet-undefined symbols doesn't work since ASYNCIFY then +// wraps these stub functions and we can't then replace them directly. Instead +// the stub functions call into `asyncifyStubs` which gets populated by the +// dynamic linker as symbols are loaded. +var asyncifyStubs = {}; +// end include: preamble.js - var removeFunction = (index) => { - functionsInTableMap.delete(getWasmTableEntry(index)); - setWasmTableEntry(index, null); - freeTableIndexes.push(index); - }; +// Begin JS library code - var _emscripten_math_cbrt = Math.cbrt; - _emscripten_math_cbrt.sig = 'dd'; - - var _emscripten_math_pow = Math.pow; - _emscripten_math_pow.sig = 'ddd'; - - var _emscripten_math_random = Math.random; - _emscripten_math_random.sig = 'd'; - - var _emscripten_math_sign = Math.sign; - _emscripten_math_sign.sig = 'dd'; - - var _emscripten_math_sqrt = Math.sqrt; - _emscripten_math_sqrt.sig = 'dd'; - - var _emscripten_math_exp = Math.exp; - _emscripten_math_exp.sig = 'dd'; - - var _emscripten_math_expm1 = Math.expm1; - _emscripten_math_expm1.sig = 'dd'; - - var _emscripten_math_fmod = (x, y) => x % y; - _emscripten_math_fmod.sig = 'ddd'; - - var _emscripten_math_log = Math.log; - _emscripten_math_log.sig = 'dd'; - - var _emscripten_math_log1p = Math.log1p; - _emscripten_math_log1p.sig = 'dd'; - - var _emscripten_math_log10 = Math.log10; - _emscripten_math_log10.sig = 'dd'; - - var _emscripten_math_log2 = Math.log2; - _emscripten_math_log2.sig = 'dd'; - - var _emscripten_math_round = Math.round; - _emscripten_math_round.sig = 'dd'; - - var _emscripten_math_acos = Math.acos; - _emscripten_math_acos.sig = 'dd'; - - var _emscripten_math_acosh = Math.acosh; - _emscripten_math_acosh.sig = 'dd'; - - var _emscripten_math_asin = Math.asin; - _emscripten_math_asin.sig = 'dd'; - - var _emscripten_math_asinh = Math.asinh; - _emscripten_math_asinh.sig = 'dd'; - - var _emscripten_math_atan = Math.atan; - _emscripten_math_atan.sig = 'dd'; - - var _emscripten_math_atanh = Math.atanh; - _emscripten_math_atanh.sig = 'dd'; - - var _emscripten_math_atan2 = Math.atan2; - _emscripten_math_atan2.sig = 'ddd'; - - var _emscripten_math_cos = Math.cos; - _emscripten_math_cos.sig = 'dd'; - - var _emscripten_math_cosh = Math.cosh; - _emscripten_math_cosh.sig = 'dd'; - - var _emscripten_math_hypot = (count, varargs) => { - var args = []; - for (var i = 0; i < count; ++i) { - args.push(HEAPF64[(varargs + i * 8) >> 3]); - } - return Math.hypot(...args); - }; - _emscripten_math_hypot.sig = 'dip'; - - var _emscripten_math_sin = Math.sin; - _emscripten_math_sin.sig = 'dd'; - - var _emscripten_math_sinh = Math.sinh; - _emscripten_math_sinh.sig = 'dd'; - - var _emscripten_math_tan = Math.tan; - _emscripten_math_tan.sig = 'dd'; - - var _emscripten_math_tanh = Math.tanh; - _emscripten_math_tanh.sig = 'dd'; - - var intArrayToString = (array) => { - var ret = []; - for (var i = 0; i < array.length; i++) { - var chr = array[i]; - if (chr > 0xff) { - chr &= 0xff; - } - ret.push(String.fromCharCode(chr)); - } - return ret.join(''); - }; - - var AsciiToString = (ptr) => { - var str = ''; - while (1) { - var ch = HEAPU8[ptr++]; - if (!ch) return str; - str += String.fromCharCode(ch); - } - }; - - var UTF16Decoder = globalThis.TextDecoder - ? new TextDecoder('utf-16le') - : undefined; - - var UTF16ToString = (ptr, maxBytesToRead, ignoreNul) => { - var idx = ptr >> 1; - var endIdx = findStringEnd(HEAPU16, idx, maxBytesToRead / 2, ignoreNul); - - // When using conditional TextDecoder, skip it for short strings as the overhead of the native call is not worth it. - if (endIdx - idx > 16 && UTF16Decoder) - return UTF16Decoder.decode(HEAPU16.subarray(idx, endIdx)); - - // Fallback: decode without UTF16Decoder - var str = ''; - - // If maxBytesToRead is not passed explicitly, it will be undefined, and the - // for-loop's condition will always evaluate to true. The loop is then - // terminated on the first null char. - for (var i = idx; i < endIdx; ++i) { - var codeUnit = HEAPU16[i]; - // fromCharCode constructs a character from a UTF-16 code unit, so we can - // pass the UTF16 string right through. - str += String.fromCharCode(codeUnit); - } - - return str; - }; - - var stringToUTF16 = (str, outPtr, maxBytesToWrite) => { - // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. - maxBytesToWrite ??= 0x7fffffff; - if (maxBytesToWrite < 2) return 0; - maxBytesToWrite -= 2; // Null terminator. - var startPtr = outPtr; - var numCharsToWrite = - maxBytesToWrite < str.length * 2 ? maxBytesToWrite / 2 : str.length; - for (var i = 0; i < numCharsToWrite; ++i) { - // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP. - var codeUnit = str.charCodeAt(i); // possibly a lead surrogate - HEAP16[outPtr >> 1] = codeUnit; - outPtr += 2; - } - // Null-terminate the pointer to the HEAP. - HEAP16[outPtr >> 1] = 0; - return outPtr - startPtr; - }; - - var lengthBytesUTF16 = (str) => str.length * 2; - - var UTF32ToString = (ptr, maxBytesToRead, ignoreNul) => { - var str = ''; - var startIdx = ptr >> 2; - // If maxBytesToRead is not passed explicitly, it will be undefined, and this - // will always evaluate to true. This saves on code size. - for (var i = 0; !(i >= maxBytesToRead / 4); i++) { - var utf32 = HEAPU32[startIdx + i]; - if (!utf32 && !ignoreNul) break; - str += String.fromCodePoint(utf32); - } - return str; - }; - - var stringToUTF32 = (str, outPtr, maxBytesToWrite) => { - // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. - maxBytesToWrite ??= 0x7fffffff; - if (maxBytesToWrite < 4) return 0; - var startPtr = outPtr; - var endPtr = startPtr + maxBytesToWrite - 4; - for (var i = 0; i < str.length; ++i) { - var codePoint = str.codePointAt(i); - // Gotcha: if codePoint is over 0xFFFF, it is represented as a surrogate pair in UTF-16. - // We need to manually skip over the second code unit for correct iteration. - if (codePoint > 0xffff) { - i++; - } - HEAP32[outPtr >> 2] = codePoint; - outPtr += 4; - if (outPtr + 4 > endPtr) break; - } - // Null-terminate the pointer to the HEAP. - HEAP32[outPtr >> 2] = 0; - return outPtr - startPtr; - }; - - var lengthBytesUTF32 = (str) => { - var len = 0; - for (var i = 0; i < str.length; ++i) { - var codePoint = str.codePointAt(i); - // Gotcha: if codePoint is over 0xFFFF, it is represented as a surrogate pair in UTF-16. - // We need to manually skip over the second code unit for correct iteration. - if (codePoint > 0xffff) { - i++; - } - len += 4; - } - - return len; - }; - - var JSEvents = { - memcpy(target, src, size) { - HEAP8.set(HEAP8.subarray(src, src + size), target); - }, - removeAllEventListeners() { - while (JSEvents.eventHandlers.length) { - JSEvents._removeHandler(JSEvents.eventHandlers.length - 1); - } - JSEvents.deferredCalls = []; - }, - registerRemoveEventListeners() { - if (!JSEvents.removeEventListenersRegistered) { - addOnExit(JSEvents.removeAllEventListeners); - JSEvents.removeEventListenersRegistered = true; - } - }, - inEventHandler: 0, - deferredCalls: [], - deferCall(targetFunction, precedence, argsList) { - function arraysHaveEqualContent(arrA, arrB) { - if (arrA.length != arrB.length) return false; - - for (var i in arrA) { - if (arrA[i] != arrB[i]) return false; - } - return true; - } - // Test if the given call was already queued, and if so, don't add it again. - for (var call of JSEvents.deferredCalls) { - if ( - call.targetFunction == targetFunction && - arraysHaveEqualContent(call.argsList, argsList) - ) { - return; - } - } - JSEvents.deferredCalls.push({ - targetFunction, - precedence, - argsList, - }); - - JSEvents.deferredCalls.sort((x, y) => x.precedence < y.precedence); - }, - removeDeferredCalls(targetFunction) { - JSEvents.deferredCalls = JSEvents.deferredCalls.filter( - (call) => call.targetFunction != targetFunction - ); - }, - canPerformEventHandlerRequests() { - if (navigator.userActivation) { - // Verify against transient activation status from UserActivation API - // whether it is possible to perform a request here without needing to defer. See - // https://developer.mozilla.org/en-US/docs/Web/Security/User_activation#transient_activation - // and https://caniuse.com/mdn-api_useractivation - // At the time of writing, Firefox does not support this API: https://bugzil.la/1791079 - return navigator.userActivation.isActive; - } - - return ( - JSEvents.inEventHandler && - JSEvents.currentEventHandler.allowsDeferredCalls - ); - }, - runDeferredCalls() { - if (!JSEvents.canPerformEventHandlerRequests()) { - return; - } - var deferredCalls = JSEvents.deferredCalls; - JSEvents.deferredCalls = []; - for (var call of deferredCalls) { - call.targetFunction(...call.argsList); - } - }, - eventHandlers: [], - removeAllHandlersOnTarget: (target, eventTypeString) => { - for (var i = 0; i < JSEvents.eventHandlers.length; ++i) { - if ( - JSEvents.eventHandlers[i].target == target && - (!eventTypeString || - eventTypeString == - JSEvents.eventHandlers[i].eventTypeString) - ) { - JSEvents._removeHandler(i--); - } - } - }, - _removeHandler(i) { - var h = JSEvents.eventHandlers[i]; - h.target.removeEventListener( - h.eventTypeString, - h.eventListenerFunc, - h.useCapture - ); - JSEvents.eventHandlers.splice(i, 1); - }, - registerOrRemoveHandler(eventHandler) { - if (!eventHandler.target) { - return -4; - } - if (eventHandler.callbackfunc) { - eventHandler.eventListenerFunc = function (event) { - // Increment nesting count for the event handler. - ++JSEvents.inEventHandler; - JSEvents.currentEventHandler = eventHandler; - // Process any old deferred calls the user has placed. - JSEvents.runDeferredCalls(); - // Process the actual event, calls back to user C code handler. - eventHandler.handlerFunc(event); - // Process any new deferred calls that were placed right now from this event handler. - JSEvents.runDeferredCalls(); - // Out of event handler - restore nesting count. - --JSEvents.inEventHandler; - }; - - eventHandler.target.addEventListener( - eventHandler.eventTypeString, - eventHandler.eventListenerFunc, - eventHandler.useCapture - ); - JSEvents.eventHandlers.push(eventHandler); - JSEvents.registerRemoveEventListeners(); - } else { - for (var i = 0; i < JSEvents.eventHandlers.length; ++i) { - if ( - JSEvents.eventHandlers[i].target == - eventHandler.target && - JSEvents.eventHandlers[i].eventTypeString == - eventHandler.eventTypeString - ) { - JSEvents._removeHandler(i--); - } - } - } - return 0; - }, - getNodeNameForTarget(target) { - if (!target) return ''; - if (target == window) return '#window'; - if (target == screen) return '#screen'; - return target?.nodeName || ''; - }, - fullscreenEnabled() { - return document.fullscreenEnabled; - }, - }; - - function getFullscreenElement() { - return ( - document.fullscreenElement || - document.mozFullScreenElement || - document.webkitFullscreenElement || - document.webkitCurrentFullScreenElement || - document.msFullscreenElement - ); - } - var registerKeyEventCallback = ( - target, - userData, - useCapture, - callbackfunc, - eventTypeId, - eventTypeString, - targetThread - ) => { - JSEvents.keyEvent ||= _malloc(160); - - var keyEventHandlerFunc = (e) => { - var keyEventData = JSEvents.keyEvent; - HEAPF64[keyEventData >> 3] = e.timeStamp; - - var idx = keyEventData >> 2; - - HEAP32[idx + 2] = e.location; - HEAP8[keyEventData + 12] = e.ctrlKey; - HEAP8[keyEventData + 13] = e.shiftKey; - HEAP8[keyEventData + 14] = e.altKey; - HEAP8[keyEventData + 15] = e.metaKey; - HEAP8[keyEventData + 16] = e.repeat; - HEAP32[idx + 5] = e.charCode; - HEAP32[idx + 6] = e.keyCode; - HEAP32[idx + 7] = e.which; - stringToUTF8(e.key || '', keyEventData + 32, 32); - stringToUTF8(e.code || '', keyEventData + 64, 32); - stringToUTF8(e.char || '', keyEventData + 96, 32); - stringToUTF8(e.locale || '', keyEventData + 128, 32); - - if ( - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - eventTypeId, - keyEventData, - userData - ) - ) - e.preventDefault(); - }; - - var eventHandler = { - target: findEventTarget(target), - eventTypeString, - callbackfunc, - handlerFunc: keyEventHandlerFunc, - useCapture, - }; - return JSEvents.registerOrRemoveHandler(eventHandler); - }; - - var _emscripten_set_keypress_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerKeyEventCallback( - target, - userData, - useCapture, - callbackfunc, - 1, - 'keypress', - targetThread - ); - _emscripten_set_keypress_callback_on_thread.sig = 'ippipp'; - - var _emscripten_set_keydown_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerKeyEventCallback( - target, - userData, - useCapture, - callbackfunc, - 2, - 'keydown', - targetThread - ); - _emscripten_set_keydown_callback_on_thread.sig = 'ippipp'; - - var _emscripten_set_keyup_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerKeyEventCallback( - target, - userData, - useCapture, - callbackfunc, - 3, - 'keyup', - targetThread - ); - _emscripten_set_keyup_callback_on_thread.sig = 'ippipp'; - - var getBoundingClientRect = (e) => - specialHTMLTargets.indexOf(e) < 0 - ? e.getBoundingClientRect() - : { left: 0, top: 0 }; - - var fillMouseEventData = (eventStruct, e, target) => { - HEAPF64[eventStruct >> 3] = e.timeStamp; - var idx = eventStruct >> 2; - HEAP32[idx + 2] = e.screenX; - HEAP32[idx + 3] = e.screenY; - HEAP32[idx + 4] = e.clientX; - HEAP32[idx + 5] = e.clientY; - HEAP8[eventStruct + 24] = e.ctrlKey; - HEAP8[eventStruct + 25] = e.shiftKey; - HEAP8[eventStruct + 26] = e.altKey; - HEAP8[eventStruct + 27] = e.metaKey; - HEAP16[idx * 2 + 14] = e.button; - HEAP16[idx * 2 + 15] = e.buttons; - - HEAP32[idx + 8] = e['movementX']; - - HEAP32[idx + 9] = e['movementY']; - - // Note: rect contains doubles (truncated to placate SAFE_HEAP, which is the same behaviour when writing to HEAP32 anyway) - var rect = getBoundingClientRect(target); - HEAP32[idx + 10] = e.clientX - (rect.left | 0); - HEAP32[idx + 11] = e.clientY - (rect.top | 0); - }; - - var registerMouseEventCallback = ( - target, - userData, - useCapture, - callbackfunc, - eventTypeId, - eventTypeString, - targetThread - ) => { - JSEvents.mouseEvent ||= _malloc(64); - target = findEventTarget(target); - - var mouseEventHandlerFunc = (e = event) => { - // TODO: Make this access thread safe, or this could update live while app is reading it. - fillMouseEventData(JSEvents.mouseEvent, e, target); - - if ( - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - eventTypeId, - JSEvents.mouseEvent, - userData - ) - ) - e.preventDefault(); - }; - - var eventHandler = { - target, - allowsDeferredCalls: - eventTypeString != 'mousemove' && - eventTypeString != 'mouseenter' && - eventTypeString != 'mouseleave', // Mouse move events do not allow fullscreen/pointer lock requests to be handled in them! - eventTypeString, - callbackfunc, - handlerFunc: mouseEventHandlerFunc, - useCapture, - }; - return JSEvents.registerOrRemoveHandler(eventHandler); - }; - - var _emscripten_set_click_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerMouseEventCallback( - target, - userData, - useCapture, - callbackfunc, - 4, - 'click', - targetThread - ); - _emscripten_set_click_callback_on_thread.sig = 'ippipp'; - - var _emscripten_set_mousedown_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerMouseEventCallback( - target, - userData, - useCapture, - callbackfunc, - 5, - 'mousedown', - targetThread - ); - _emscripten_set_mousedown_callback_on_thread.sig = 'ippipp'; - - var _emscripten_set_mouseup_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerMouseEventCallback( - target, - userData, - useCapture, - callbackfunc, - 6, - 'mouseup', - targetThread - ); - _emscripten_set_mouseup_callback_on_thread.sig = 'ippipp'; - - var _emscripten_set_dblclick_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerMouseEventCallback( - target, - userData, - useCapture, - callbackfunc, - 7, - 'dblclick', - targetThread - ); - _emscripten_set_dblclick_callback_on_thread.sig = 'ippipp'; - - var _emscripten_set_mousemove_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerMouseEventCallback( - target, - userData, - useCapture, - callbackfunc, - 8, - 'mousemove', - targetThread - ); - _emscripten_set_mousemove_callback_on_thread.sig = 'ippipp'; - - var _emscripten_set_mouseenter_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerMouseEventCallback( - target, - userData, - useCapture, - callbackfunc, - 33, - 'mouseenter', - targetThread - ); - _emscripten_set_mouseenter_callback_on_thread.sig = 'ippipp'; - - var _emscripten_set_mouseleave_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerMouseEventCallback( - target, - userData, - useCapture, - callbackfunc, - 34, - 'mouseleave', - targetThread - ); - _emscripten_set_mouseleave_callback_on_thread.sig = 'ippipp'; - - var _emscripten_set_mouseover_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerMouseEventCallback( - target, - userData, - useCapture, - callbackfunc, - 35, - 'mouseover', - targetThread - ); - _emscripten_set_mouseover_callback_on_thread.sig = 'ippipp'; - - var _emscripten_set_mouseout_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerMouseEventCallback( - target, - userData, - useCapture, - callbackfunc, - 36, - 'mouseout', - targetThread - ); - _emscripten_set_mouseout_callback_on_thread.sig = 'ippipp'; - - var _emscripten_get_mouse_status = (mouseState) => { - if (!JSEvents.mouseEvent) return -7; - // HTML5 does not really have a polling API for mouse events, so implement one manually by - // returning the data from the most recently received event. This requires that user has registered - // at least some no-op function as an event handler to any of the mouse function. - JSEvents.memcpy(mouseState, JSEvents.mouseEvent, 64); - return 0; - }; - _emscripten_get_mouse_status.sig = 'ip'; - - var registerWheelEventCallback = ( - target, - userData, - useCapture, - callbackfunc, - eventTypeId, - eventTypeString, - targetThread - ) => { - JSEvents.wheelEvent ||= _malloc(96); - - // The DOM Level 3 events spec event 'wheel' - var wheelHandlerFunc = (e = event) => { - var wheelEvent = JSEvents.wheelEvent; - fillMouseEventData(wheelEvent, e, target); - HEAPF64[(wheelEvent + 64) >> 3] = e['deltaX']; - HEAPF64[(wheelEvent + 72) >> 3] = e['deltaY']; - HEAPF64[(wheelEvent + 80) >> 3] = e['deltaZ']; - HEAP32[(wheelEvent + 88) >> 2] = e['deltaMode']; - if ( - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - eventTypeId, - wheelEvent, - userData - ) - ) - e.preventDefault(); - }; - - var eventHandler = { - target, - allowsDeferredCalls: true, - eventTypeString, - callbackfunc, - handlerFunc: wheelHandlerFunc, - useCapture, - }; - return JSEvents.registerOrRemoveHandler(eventHandler); - }; - - var _emscripten_set_wheel_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => { - target = findEventTarget(target); - if (!target) return -4; - if (typeof target.onwheel != 'undefined') { - return registerWheelEventCallback( - target, - userData, - useCapture, - callbackfunc, - 9, - 'wheel', - targetThread - ); - } else { - return -1; - } - }; - _emscripten_set_wheel_callback_on_thread.sig = 'ippipp'; - - var registerUiEventCallback = ( - target, - userData, - useCapture, - callbackfunc, - eventTypeId, - eventTypeString, - targetThread - ) => { - JSEvents.uiEvent ||= _malloc(36); - - target = findEventTarget(target); - - var uiEventHandlerFunc = (e = event) => { - if (e.target != target) { - // Never take ui events such as scroll via a 'bubbled' route, but always from the direct element that - // was targeted. Otherwise e.g. if app logs a message in response to a page scroll, the Emscripten log - // message box could cause to scroll, generating a new (bubbled) scroll message, causing a new log print, - // causing a new scroll, etc.. - return; - } - var b = document.body; // Take document.body to a variable, Closure compiler does not outline access to it on its own. - if (!b) { - // During a page unload 'body' can be null, with "Cannot read property 'clientWidth' of null" being thrown - return; - } - var uiEvent = JSEvents.uiEvent; - HEAP32[uiEvent >> 2] = 0; // always zero for resize and scroll - HEAP32[(uiEvent + 4) >> 2] = b.clientWidth; - HEAP32[(uiEvent + 8) >> 2] = b.clientHeight; - HEAP32[(uiEvent + 12) >> 2] = innerWidth; - HEAP32[(uiEvent + 16) >> 2] = innerHeight; - HEAP32[(uiEvent + 20) >> 2] = outerWidth; - HEAP32[(uiEvent + 24) >> 2] = outerHeight; - HEAP32[(uiEvent + 28) >> 2] = pageXOffset | 0; // scroll offsets are float - HEAP32[(uiEvent + 32) >> 2] = pageYOffset | 0; - if ( - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - eventTypeId, - uiEvent, - userData - ) - ) - e.preventDefault(); - }; - - var eventHandler = { - target, - eventTypeString, - callbackfunc, - handlerFunc: uiEventHandlerFunc, - useCapture, - }; - return JSEvents.registerOrRemoveHandler(eventHandler); - }; - - var _emscripten_set_resize_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerUiEventCallback( - target, - userData, - useCapture, - callbackfunc, - 10, - 'resize', - targetThread - ); - _emscripten_set_resize_callback_on_thread.sig = 'ippipp'; - - var _emscripten_set_scroll_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerUiEventCallback( - target, - userData, - useCapture, - callbackfunc, - 11, - 'scroll', - targetThread - ); - _emscripten_set_scroll_callback_on_thread.sig = 'ippipp'; - - var registerFocusEventCallback = ( - target, - userData, - useCapture, - callbackfunc, - eventTypeId, - eventTypeString, - targetThread - ) => { - JSEvents.focusEvent ||= _malloc(256); - - var focusEventHandlerFunc = (e = event) => { - var nodeName = JSEvents.getNodeNameForTarget(e.target); - var id = e.target.id ? e.target.id : ''; - - var focusEvent = JSEvents.focusEvent; - stringToUTF8(nodeName, focusEvent + 0, 128); - stringToUTF8(id, focusEvent + 128, 128); - - if ( - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - eventTypeId, - focusEvent, - userData - ) - ) - e.preventDefault(); - }; - - var eventHandler = { - target: findEventTarget(target), - eventTypeString, - callbackfunc, - handlerFunc: focusEventHandlerFunc, - useCapture, - }; - return JSEvents.registerOrRemoveHandler(eventHandler); - }; - - var _emscripten_set_blur_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerFocusEventCallback( - target, - userData, - useCapture, - callbackfunc, - 12, - 'blur', - targetThread - ); - _emscripten_set_blur_callback_on_thread.sig = 'ippipp'; - - var _emscripten_set_focus_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerFocusEventCallback( - target, - userData, - useCapture, - callbackfunc, - 13, - 'focus', - targetThread - ); - _emscripten_set_focus_callback_on_thread.sig = 'ippipp'; - - var _emscripten_set_focusin_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerFocusEventCallback( - target, - userData, - useCapture, - callbackfunc, - 14, - 'focusin', - targetThread - ); - _emscripten_set_focusin_callback_on_thread.sig = 'ippipp'; - - var _emscripten_set_focusout_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerFocusEventCallback( - target, - userData, - useCapture, - callbackfunc, - 15, - 'focusout', - targetThread - ); - _emscripten_set_focusout_callback_on_thread.sig = 'ippipp'; - - var fillDeviceOrientationEventData = (eventStruct, e, target) => { - HEAPF64[eventStruct >> 3] = e.alpha; - HEAPF64[(eventStruct + 8) >> 3] = e.beta; - HEAPF64[(eventStruct + 16) >> 3] = e.gamma; - HEAP8[eventStruct + 24] = e.absolute; - }; - - var registerDeviceOrientationEventCallback = ( - target, - userData, - useCapture, - callbackfunc, - eventTypeId, - eventTypeString, - targetThread - ) => { - JSEvents.deviceOrientationEvent ||= _malloc(32); - - var deviceOrientationEventHandlerFunc = (e = event) => { - fillDeviceOrientationEventData( - JSEvents.deviceOrientationEvent, - e, - target - ); // TODO: Thread-safety with respect to emscripten_get_deviceorientation_status() - - if ( - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - eventTypeId, - JSEvents.deviceOrientationEvent, - userData - ) - ) - e.preventDefault(); - }; - - var eventHandler = { - target: findEventTarget(target), - eventTypeString, - callbackfunc, - handlerFunc: deviceOrientationEventHandlerFunc, - useCapture, - }; - return JSEvents.registerOrRemoveHandler(eventHandler); - }; - - var _emscripten_set_deviceorientation_callback_on_thread = ( - userData, - useCapture, - callbackfunc, - targetThread - ) => { - return registerDeviceOrientationEventCallback( - 2, - userData, - useCapture, - callbackfunc, - 16, - 'deviceorientation', - targetThread - ); - }; - _emscripten_set_deviceorientation_callback_on_thread.sig = 'ipipp'; - - var _emscripten_get_deviceorientation_status = (orientationState) => { - if (!JSEvents.deviceOrientationEvent) return -7; - // HTML5 does not really have a polling API for device orientation events, so implement one manually by - // returning the data from the most recently received event. This requires that user has registered - // at least some no-op function as an event handler. - JSEvents.memcpy(orientationState, JSEvents.deviceOrientationEvent, 32); - return 0; - }; - _emscripten_get_deviceorientation_status.sig = 'ip'; - - var fillDeviceMotionEventData = (eventStruct, e, target) => { - var supportedFields = 0; - var a = e['acceleration']; - supportedFields |= a && 1; - var ag = e['accelerationIncludingGravity']; - supportedFields |= ag && 2; - var rr = e['rotationRate']; - supportedFields |= rr && 4; - a = a || {}; - ag = ag || {}; - rr = rr || {}; - HEAP32[(eventStruct + 72) >> 2] = supportedFields; - HEAPF64[eventStruct >> 3] = a['x']; - HEAPF64[(eventStruct + 8) >> 3] = a['y']; - HEAPF64[(eventStruct + 16) >> 3] = a['z']; - HEAPF64[(eventStruct + 24) >> 3] = ag['x']; - HEAPF64[(eventStruct + 32) >> 3] = ag['y']; - HEAPF64[(eventStruct + 40) >> 3] = ag['z']; - HEAPF64[(eventStruct + 48) >> 3] = rr['alpha']; - HEAPF64[(eventStruct + 56) >> 3] = rr['beta']; - HEAPF64[(eventStruct + 64) >> 3] = rr['gamma']; - }; - - var registerDeviceMotionEventCallback = ( - target, - userData, - useCapture, - callbackfunc, - eventTypeId, - eventTypeString, - targetThread - ) => { - JSEvents.deviceMotionEvent ||= _malloc(80); - - var deviceMotionEventHandlerFunc = (e = event) => { - fillDeviceMotionEventData(JSEvents.deviceMotionEvent, e, target); // TODO: Thread-safety with respect to emscripten_get_devicemotion_status() - - if ( - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - eventTypeId, - JSEvents.deviceMotionEvent, - userData - ) - ) - e.preventDefault(); - }; - - var eventHandler = { - target: findEventTarget(target), - eventTypeString, - callbackfunc, - handlerFunc: deviceMotionEventHandlerFunc, - useCapture, - }; - return JSEvents.registerOrRemoveHandler(eventHandler); - }; - - var _emscripten_set_devicemotion_callback_on_thread = ( - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerDeviceMotionEventCallback( - 2, - userData, - useCapture, - callbackfunc, - 17, - 'devicemotion', - targetThread - ); - _emscripten_set_devicemotion_callback_on_thread.sig = 'ipipp'; - - var _emscripten_get_devicemotion_status = (motionState) => { - if (!JSEvents.deviceMotionEvent) return -7; - // HTML5 does not really have a polling API for device motion events, so implement one manually by - // returning the data from the most recently received event. This requires that user has registered - // at least some no-op function as an event handler. - JSEvents.memcpy(motionState, JSEvents.deviceMotionEvent, 80); - return 0; - }; - _emscripten_get_devicemotion_status.sig = 'ip'; - - var screenOrientation = () => { - if (!window.screen) return undefined; - return ( - screen.orientation || - screen['mozOrientation'] || - screen['webkitOrientation'] - ); - }; - - var fillOrientationChangeEventData = (eventStruct) => { - // OrientationType enum - var orientationsType1 = [ - 'portrait-primary', - 'portrait-secondary', - 'landscape-primary', - 'landscape-secondary', - ]; - // alternative selection from OrientationLockType enum - var orientationsType2 = [ - 'portrait', - 'portrait', - 'landscape', - 'landscape', - ]; - - var orientationIndex = 0; - var orientationAngle = 0; - var screenOrientObj = screenOrientation(); - if (typeof screenOrientObj === 'object') { - orientationIndex = orientationsType1.indexOf(screenOrientObj.type); - if (orientationIndex < 0) { - orientationIndex = orientationsType2.indexOf( - screenOrientObj.type - ); - } - if (orientationIndex >= 0) { - orientationIndex = 1 << orientationIndex; - } - orientationAngle = screenOrientObj.angle; - } - - HEAP32[eventStruct >> 2] = orientationIndex; - HEAP32[(eventStruct + 4) >> 2] = orientationAngle; - }; - - var registerOrientationChangeEventCallback = ( - target, - userData, - useCapture, - callbackfunc, - eventTypeId, - eventTypeString, - targetThread - ) => { - JSEvents.orientationChangeEvent ||= _malloc(8); - - var orientationChangeEventHandlerFunc = (e = event) => { - var orientationChangeEvent = JSEvents.orientationChangeEvent; - - fillOrientationChangeEventData(orientationChangeEvent); - - if ( - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - eventTypeId, - orientationChangeEvent, - userData - ) - ) - e.preventDefault(); - }; - - var eventHandler = { - target, - eventTypeString, - callbackfunc, - handlerFunc: orientationChangeEventHandlerFunc, - useCapture, - }; - return JSEvents.registerOrRemoveHandler(eventHandler); - }; - - var _emscripten_set_orientationchange_callback_on_thread = ( - userData, - useCapture, - callbackfunc, - targetThread - ) => { - if (!window.screen || !screen.orientation) return -1; - return registerOrientationChangeEventCallback( - screen.orientation, - userData, - useCapture, - callbackfunc, - 18, - 'change', - targetThread - ); - }; - _emscripten_set_orientationchange_callback_on_thread.sig = 'ipipp'; - - var _emscripten_get_orientation_status = (orientationChangeEvent) => { - // screenOrientation() resolving standard, window.orientation being the deprecated mobile-only - if (!screenOrientation() && typeof orientation == 'undefined') - return -1; - fillOrientationChangeEventData(orientationChangeEvent); - return 0; - }; - _emscripten_get_orientation_status.sig = 'ip'; - - var _emscripten_lock_orientation = (allowedOrientations) => { - var orientations = []; - if (allowedOrientations & 1) orientations.push('portrait-primary'); - if (allowedOrientations & 2) orientations.push('portrait-secondary'); - if (allowedOrientations & 4) orientations.push('landscape-primary'); - if (allowedOrientations & 8) orientations.push('landscape-secondary'); - var succeeded; - if (screen.lockOrientation) { - succeeded = screen.lockOrientation(orientations); - } else if (screen.mozLockOrientation) { - succeeded = screen.mozLockOrientation(orientations); - } else if (screen.webkitLockOrientation) { - succeeded = screen.webkitLockOrientation(orientations); - } else { - return -1; - } - if (succeeded) { - return 0; - } - return -6; - }; - _emscripten_lock_orientation.sig = 'ii'; - - var _emscripten_unlock_orientation = () => { - if (screen.unlockOrientation) { - screen.unlockOrientation(); - } else if (screen.mozUnlockOrientation) { - screen.mozUnlockOrientation(); - } else if (screen.webkitUnlockOrientation) { - screen.webkitUnlockOrientation(); - } else { - return -1; - } - return 0; - }; - _emscripten_unlock_orientation.sig = 'i'; - - var fillFullscreenChangeEventData = (eventStruct) => { - var fullscreenElement = getFullscreenElement(); - var isFullscreen = !!fullscreenElement; - // Assigning a boolean to HEAP32 with expected type coercion. - /** @suppress{checkTypes} */ - HEAP8[eventStruct] = isFullscreen; - HEAP8[eventStruct + 1] = JSEvents.fullscreenEnabled(); - // If transitioning to fullscreen, report info about the element that is now fullscreen. - // If transitioning to windowed mode, report info about the element that just was fullscreen. - var reportedElement = isFullscreen - ? fullscreenElement - : JSEvents.previousFullscreenElement; - var nodeName = JSEvents.getNodeNameForTarget(reportedElement); - var id = reportedElement?.id || ''; - stringToUTF8(nodeName, eventStruct + 2, 128); - stringToUTF8(id, eventStruct + 130, 128); - HEAP32[(eventStruct + 260) >> 2] = reportedElement - ? reportedElement.clientWidth - : 0; - HEAP32[(eventStruct + 264) >> 2] = reportedElement - ? reportedElement.clientHeight - : 0; - HEAP32[(eventStruct + 268) >> 2] = screen.width; - HEAP32[(eventStruct + 272) >> 2] = screen.height; - if (isFullscreen) { - JSEvents.previousFullscreenElement = fullscreenElement; - } - }; - - var registerFullscreenChangeEventCallback = ( - target, - userData, - useCapture, - callbackfunc, - eventTypeId, - eventTypeString, - targetThread - ) => { - JSEvents.fullscreenChangeEvent ||= _malloc(276); - - var fullscreenChangeEventhandlerFunc = (e = event) => { - var fullscreenChangeEvent = JSEvents.fullscreenChangeEvent; - - fillFullscreenChangeEventData(fullscreenChangeEvent); - - if ( - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - eventTypeId, - fullscreenChangeEvent, - userData - ) - ) - e.preventDefault(); - }; - - var eventHandler = { - target, - eventTypeString, - callbackfunc, - handlerFunc: fullscreenChangeEventhandlerFunc, - useCapture, - }; - return JSEvents.registerOrRemoveHandler(eventHandler); - }; - - var _emscripten_set_fullscreenchange_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => { - if (!JSEvents.fullscreenEnabled()) return -1; - target = findEventTarget(target); - if (!target) return -4; - - return registerFullscreenChangeEventCallback( - target, - userData, - useCapture, - callbackfunc, - 19, - 'fullscreenchange', - targetThread - ); - }; - _emscripten_set_fullscreenchange_callback_on_thread.sig = 'ippipp'; - - var _emscripten_get_fullscreen_status = (fullscreenStatus) => { - if (!JSEvents.fullscreenEnabled()) return -1; - fillFullscreenChangeEventData(fullscreenStatus); - return 0; - }; - _emscripten_get_fullscreen_status.sig = 'ip'; - - var _emscripten_get_canvas_element_size = (target, width, height) => { - var canvas = findCanvasEventTarget(target); - if (!canvas) return -4; - HEAP32[width >> 2] = canvas.width; - HEAP32[height >> 2] = canvas.height; - }; - _emscripten_get_canvas_element_size.sig = 'ippp'; - - var getCanvasElementSize = (target) => { - var sp = stackSave(); - var w = stackAlloc(8); - var h = w + 4; - - var targetInt = stringToUTF8OnStack(target.id); - var ret = _emscripten_get_canvas_element_size(targetInt, w, h); - var size = [HEAP32[w >> 2], HEAP32[h >> 2]]; - stackRestore(sp); - return size; - }; - - var setCanvasElementSize = (target, width, height) => { - if (!target.controlTransferredOffscreen) { - target.width = width; - target.height = height; - } else { - // This function is being called from high-level JavaScript code instead of asm.js/Wasm, - // and it needs to synchronously proxy over to another thread, so marshal the string onto the heap to do the call. - var sp = stackSave(); - var targetInt = stringToUTF8OnStack(target.id); - _emscripten_set_canvas_element_size(targetInt, width, height); - stackRestore(sp); - } - }; - - var currentFullscreenStrategy = {}; - var registerRestoreOldStyle = (canvas) => { - var canvasSize = getCanvasElementSize(canvas); - var oldWidth = canvasSize[0]; - var oldHeight = canvasSize[1]; - var oldCssWidth = canvas.style.width; - var oldCssHeight = canvas.style.height; - var oldBackgroundColor = canvas.style.backgroundColor; // Chrome reads color from here. - var oldDocumentBackgroundColor = document.body.style.backgroundColor; // IE11 reads color from here. - // Firefox always has black background color. - var oldPaddingLeft = canvas.style.paddingLeft; // Chrome, FF, Safari - var oldPaddingRight = canvas.style.paddingRight; - var oldPaddingTop = canvas.style.paddingTop; - var oldPaddingBottom = canvas.style.paddingBottom; - var oldMarginLeft = canvas.style.marginLeft; // IE11 - var oldMarginRight = canvas.style.marginRight; - var oldMarginTop = canvas.style.marginTop; - var oldMarginBottom = canvas.style.marginBottom; - var oldDocumentBodyMargin = document.body.style.margin; - var oldDocumentOverflow = document.documentElement.style.overflow; // Chrome, Firefox - var oldDocumentScroll = document.body.scroll; // IE - var oldImageRendering = canvas.style.imageRendering; - - function restoreOldStyle() { - if (!getFullscreenElement()) { - document.removeEventListener( - 'fullscreenchange', - restoreOldStyle - ); - - setCanvasElementSize(canvas, oldWidth, oldHeight); - - canvas.style.width = oldCssWidth; - canvas.style.height = oldCssHeight; - canvas.style.backgroundColor = oldBackgroundColor; // Chrome - // IE11 hack: assigning 'undefined' or an empty string to document.body.style.backgroundColor has no effect, so first assign back the default color - // before setting the undefined value. Setting undefined value is also important, or otherwise we would later treat that as something that the user - // had explicitly set so subsequent fullscreen transitions would not set background color properly. - if (!oldDocumentBackgroundColor) - document.body.style.backgroundColor = 'white'; - document.body.style.backgroundColor = - oldDocumentBackgroundColor; // IE11 - canvas.style.paddingLeft = oldPaddingLeft; // Chrome, FF, Safari - canvas.style.paddingRight = oldPaddingRight; - canvas.style.paddingTop = oldPaddingTop; - canvas.style.paddingBottom = oldPaddingBottom; - canvas.style.marginLeft = oldMarginLeft; // IE11 - canvas.style.marginRight = oldMarginRight; - canvas.style.marginTop = oldMarginTop; - canvas.style.marginBottom = oldMarginBottom; - document.body.style.margin = oldDocumentBodyMargin; - document.documentElement.style.overflow = oldDocumentOverflow; // Chrome, Firefox - document.body.scroll = oldDocumentScroll; // IE - canvas.style.imageRendering = oldImageRendering; - if (canvas.GLctxObject) - canvas.GLctxObject.GLctx.viewport( - 0, - 0, - oldWidth, - oldHeight - ); - - if (currentFullscreenStrategy.canvasResizedCallback) { - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - 37, - 0, - currentFullscreenStrategy.canvasResizedCallbackUserData - ); - } - } - } - document.addEventListener('fullscreenchange', restoreOldStyle); - return restoreOldStyle; - }; - - var setLetterbox = (element, topBottom, leftRight) => { - // Cannot use margin to specify letterboxes in FF or Chrome, since those ignore margins in fullscreen mode. - element.style.paddingLeft = element.style.paddingRight = - leftRight + 'px'; - element.style.paddingTop = element.style.paddingBottom = - topBottom + 'px'; - }; - - var JSEvents_resizeCanvasForFullscreen = (target, strategy) => { - var restoreOldStyle = registerRestoreOldStyle(target); - var cssWidth = strategy.softFullscreen ? innerWidth : screen.width; - var cssHeight = strategy.softFullscreen ? innerHeight : screen.height; - var rect = getBoundingClientRect(target); - var windowedCssWidth = rect.width; - var windowedCssHeight = rect.height; - var canvasSize = getCanvasElementSize(target); - var windowedRttWidth = canvasSize[0]; - var windowedRttHeight = canvasSize[1]; - - if (strategy.scaleMode == 3) { - setLetterbox( - target, - (cssHeight - windowedCssHeight) / 2, - (cssWidth - windowedCssWidth) / 2 - ); - cssWidth = windowedCssWidth; - cssHeight = windowedCssHeight; - } else if (strategy.scaleMode == 2) { - if (cssWidth * windowedRttHeight < windowedRttWidth * cssHeight) { - var desiredCssHeight = - (windowedRttHeight * cssWidth) / windowedRttWidth; - setLetterbox(target, (cssHeight - desiredCssHeight) / 2, 0); - cssHeight = desiredCssHeight; - } else { - var desiredCssWidth = - (windowedRttWidth * cssHeight) / windowedRttHeight; - setLetterbox(target, 0, (cssWidth - desiredCssWidth) / 2); - cssWidth = desiredCssWidth; - } - } - - // If we are adding padding, must choose a background color or otherwise Chrome will give the - // padding a default white color. Do it only if user has not customized their own background color. - target.style.backgroundColor ||= 'black'; - // IE11 does the same, but requires the color to be set in the document body. - document.body.style.backgroundColor ||= 'black'; // IE11 - // Firefox always shows black letterboxes independent of style color. - - target.style.width = cssWidth + 'px'; - target.style.height = cssHeight + 'px'; - - if (strategy.filteringMode == 1) { - target.style.imageRendering = 'optimizeSpeed'; - target.style.imageRendering = '-moz-crisp-edges'; - target.style.imageRendering = '-o-crisp-edges'; - target.style.imageRendering = '-webkit-optimize-contrast'; - target.style.imageRendering = 'optimize-contrast'; - target.style.imageRendering = 'crisp-edges'; - target.style.imageRendering = 'pixelated'; - } - - var dpiScale = - strategy.canvasResolutionScaleMode == 2 ? devicePixelRatio : 1; - if (strategy.canvasResolutionScaleMode != 0) { - var newWidth = (cssWidth * dpiScale) | 0; - var newHeight = (cssHeight * dpiScale) | 0; - setCanvasElementSize(target, newWidth, newHeight); - if (target.GLctxObject) - target.GLctxObject.GLctx.viewport(0, 0, newWidth, newHeight); - } - return restoreOldStyle; - }; - var JSEvents_requestFullscreen = (target, strategy) => { - // EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT + EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE is a mode where no extra logic is performed to the DOM elements. - if ( - strategy.scaleMode != 0 || - strategy.canvasResolutionScaleMode != 0 - ) { - JSEvents_resizeCanvasForFullscreen(target, strategy); - } - - if (target.requestFullscreen) { - target.requestFullscreen(); - } else { - return JSEvents.fullscreenEnabled() ? -3 : -1; - } - - currentFullscreenStrategy = strategy; - - if (strategy.canvasResizedCallback) { - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - 37, - 0, - strategy.canvasResizedCallbackUserData - ); - } - - return 0; - }; - - var hideEverythingExceptGivenElement = (onlyVisibleElement) => { - var child = onlyVisibleElement; - var parent = child.parentNode; - var hiddenElements = []; - while (child != document.body) { - var children = parent.children; - for (var currChild of children) { - if (currChild != child) { - hiddenElements.push({ - node: currChild, - displayState: currChild.style.display, - }); - currChild.style.display = 'none'; - } - } - child = parent; - parent = parent.parentNode; - } - return hiddenElements; - }; - - var restoreHiddenElements = (hiddenElements) => { - for (var elem of hiddenElements) { - elem.node.style.display = elem.displayState; - } - }; - - var restoreOldWindowedStyle = null; - - var softFullscreenResizeWebGLRenderTarget = () => { - var dpr = devicePixelRatio; - var inHiDPIFullscreenMode = - currentFullscreenStrategy.canvasResolutionScaleMode == 2; - var inAspectRatioFixedFullscreenMode = - currentFullscreenStrategy.scaleMode == 2; - var inPixelPerfectFullscreenMode = - currentFullscreenStrategy.canvasResolutionScaleMode != 0; - var inCenteredWithoutScalingFullscreenMode = - currentFullscreenStrategy.scaleMode == 3; - var screenWidth = inHiDPIFullscreenMode - ? Math.round(innerWidth * dpr) - : innerWidth; - var screenHeight = inHiDPIFullscreenMode - ? Math.round(innerHeight * dpr) - : innerHeight; - var w = screenWidth; - var h = screenHeight; - var canvas = currentFullscreenStrategy.target; - var canvasSize = getCanvasElementSize(canvas); - var x = canvasSize[0]; - var y = canvasSize[1]; - var topMargin; - - if (inAspectRatioFixedFullscreenMode) { - if (w * y < x * h) h = ((w * y) / x) | 0; - else if (w * y > x * h) w = ((h * x) / y) | 0; - topMargin = ((screenHeight - h) / 2) | 0; - } - - if (inPixelPerfectFullscreenMode) { - setCanvasElementSize(canvas, w, h); - if (canvas.GLctxObject) - canvas.GLctxObject.GLctx.viewport(0, 0, w, h); - } - - // Back to CSS pixels. - if (inHiDPIFullscreenMode) { - topMargin /= dpr; - w /= dpr; - h /= dpr; - // Round to nearest 4 digits of precision. - w = Math.round(w * 1e4) / 1e4; - h = Math.round(h * 1e4) / 1e4; - topMargin = Math.round(topMargin * 1e4) / 1e4; - } - - if (inCenteredWithoutScalingFullscreenMode) { - var t = (innerHeight - jstoi_q(canvas.style.height)) / 2; - var b = (innerWidth - jstoi_q(canvas.style.width)) / 2; - setLetterbox(canvas, t, b); - } else { - canvas.style.width = w + 'px'; - canvas.style.height = h + 'px'; - var b = (innerWidth - w) / 2; - setLetterbox(canvas, topMargin, b); - } - - if ( - !inCenteredWithoutScalingFullscreenMode && - currentFullscreenStrategy.canvasResizedCallback - ) { - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - 37, - 0, - currentFullscreenStrategy.canvasResizedCallbackUserData - ); - } - }; - - var doRequestFullscreen = (target, strategy) => { - if (!JSEvents.fullscreenEnabled()) return -1; - target = findEventTarget(target); - if (!target) return -4; - - if (!target.requestFullscreen) { - return -3; - } - - // Queue this function call if we're not currently in an event handler and - // the user saw it appropriate to do so. - if (!JSEvents.canPerformEventHandlerRequests()) { - if (strategy.deferUntilInEventHandler) { - JSEvents.deferCall( - JSEvents_requestFullscreen, - 1 /* priority over pointer lock */, - [target, strategy] - ); - return 1; - } - return -2; - } - - return JSEvents_requestFullscreen(target, strategy); - }; - - var _emscripten_request_fullscreen = (target, deferUntilInEventHandler) => { - var strategy = { - // These options perform no added logic, but just bare request fullscreen. - scaleMode: 0, - canvasResolutionScaleMode: 0, - filteringMode: 0, - deferUntilInEventHandler, - canvasResizedCallbackTargetThread: 2, - }; - return doRequestFullscreen(target, strategy); - }; - _emscripten_request_fullscreen.sig = 'ipi'; - - var _emscripten_request_fullscreen_strategy = ( - target, - deferUntilInEventHandler, - fullscreenStrategy - ) => { - var strategy = { - scaleMode: HEAP32[fullscreenStrategy >> 2], - canvasResolutionScaleMode: HEAP32[(fullscreenStrategy + 4) >> 2], - filteringMode: HEAP32[(fullscreenStrategy + 8) >> 2], - deferUntilInEventHandler, - canvasResizedCallback: HEAP32[(fullscreenStrategy + 12) >> 2], - canvasResizedCallbackUserData: - HEAP32[(fullscreenStrategy + 16) >> 2], - }; - - return doRequestFullscreen(target, strategy); - }; - _emscripten_request_fullscreen_strategy.sig = 'ipip'; - - var _emscripten_enter_soft_fullscreen = (target, fullscreenStrategy) => { - target = findEventTarget(target); - if (!target) return -4; - - var strategy = { - scaleMode: HEAP32[fullscreenStrategy >> 2], - canvasResolutionScaleMode: HEAP32[(fullscreenStrategy + 4) >> 2], - filteringMode: HEAP32[(fullscreenStrategy + 8) >> 2], - canvasResizedCallback: HEAP32[(fullscreenStrategy + 12) >> 2], - canvasResizedCallbackUserData: - HEAP32[(fullscreenStrategy + 16) >> 2], - target, - softFullscreen: true, - }; - - var restoreOldStyle = JSEvents_resizeCanvasForFullscreen( - target, - strategy - ); - - document.documentElement.style.overflow = 'hidden'; // Firefox, Chrome - document.body.scroll = 'no'; // IE11 - document.body.style.margin = '0px'; // Override default document margin area on all browsers. - - var hiddenElements = hideEverythingExceptGivenElement(target); - - function restoreWindowedState() { - restoreOldStyle(); - restoreHiddenElements(hiddenElements); - removeEventListener( - 'resize', - softFullscreenResizeWebGLRenderTarget - ); - if (strategy.canvasResizedCallback) { - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - 37, - 0, - strategy.canvasResizedCallbackUserData - ); - } - currentFullscreenStrategy = 0; - } - restoreOldWindowedStyle = restoreWindowedState; - currentFullscreenStrategy = strategy; - addEventListener('resize', softFullscreenResizeWebGLRenderTarget); - - // Inform the caller that the canvas size has changed. - if (strategy.canvasResizedCallback) { - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - 37, - 0, - strategy.canvasResizedCallbackUserData - ); - } - - return 0; - }; - _emscripten_enter_soft_fullscreen.sig = 'ipp'; - - var _emscripten_exit_soft_fullscreen = () => { - restoreOldWindowedStyle?.(); - restoreOldWindowedStyle = null; - - return 0; - }; - _emscripten_exit_soft_fullscreen.sig = 'i'; - - var _emscripten_exit_fullscreen = () => { - if (!JSEvents.fullscreenEnabled()) return -1; - // Make sure no queued up calls will fire after this. - JSEvents.removeDeferredCalls(JSEvents_requestFullscreen); - - var d = specialHTMLTargets[1]; - if (d.exitFullscreen) { - d.fullscreenElement && d.exitFullscreen(); - } else { - return -1; - } - - return 0; - }; - _emscripten_exit_fullscreen.sig = 'i'; - - var fillPointerlockChangeEventData = (eventStruct) => { - var pointerLockElement = document.pointerLockElement; - var isPointerlocked = !!pointerLockElement; - // Assigning a boolean to HEAP32 with expected type coercion. - /** @suppress{checkTypes} */ - HEAP8[eventStruct] = isPointerlocked; - var nodeName = JSEvents.getNodeNameForTarget(pointerLockElement); - var id = pointerLockElement?.id || ''; - stringToUTF8(nodeName, eventStruct + 1, 128); - stringToUTF8(id, eventStruct + 129, 128); - }; - - var registerPointerlockChangeEventCallback = ( - target, - userData, - useCapture, - callbackfunc, - eventTypeId, - eventTypeString, - targetThread - ) => { - JSEvents.pointerlockChangeEvent ||= _malloc(257); - - var pointerlockChangeEventHandlerFunc = (e = event) => { - var pointerlockChangeEvent = JSEvents.pointerlockChangeEvent; - fillPointerlockChangeEventData(pointerlockChangeEvent); - - if ( - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - eventTypeId, - pointerlockChangeEvent, - userData - ) - ) - e.preventDefault(); - }; - - var eventHandler = { - target, - eventTypeString, - callbackfunc, - handlerFunc: pointerlockChangeEventHandlerFunc, - useCapture, - }; - return JSEvents.registerOrRemoveHandler(eventHandler); - }; - - var _emscripten_set_pointerlockchange_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => { - if (!document.body?.requestPointerLock) { - return -1; - } - - target = findEventTarget(target); - if (!target) return -4; - return registerPointerlockChangeEventCallback( - target, - userData, - useCapture, - callbackfunc, - 20, - 'pointerlockchange', - targetThread - ); - }; - _emscripten_set_pointerlockchange_callback_on_thread.sig = 'ippipp'; - - var registerPointerlockErrorEventCallback = ( - target, - userData, - useCapture, - callbackfunc, - eventTypeId, - eventTypeString, - targetThread - ) => { - var pointerlockErrorEventHandlerFunc = (e = event) => { - if ( - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - eventTypeId, - 0, - userData - ) - ) - e.preventDefault(); - }; - - var eventHandler = { - target, - eventTypeString, - callbackfunc, - handlerFunc: pointerlockErrorEventHandlerFunc, - useCapture, - }; - return JSEvents.registerOrRemoveHandler(eventHandler); - }; - - var _emscripten_set_pointerlockerror_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => { - if (!document.body?.requestPointerLock) { - return -1; - } - - target = findEventTarget(target); - - if (!target) return -4; - return registerPointerlockErrorEventCallback( - target, - userData, - useCapture, - callbackfunc, - 38, - 'pointerlockerror', - targetThread - ); - }; - _emscripten_set_pointerlockerror_callback_on_thread.sig = 'ippipp'; - - var _emscripten_get_pointerlock_status = (pointerlockStatus) => { - if (pointerlockStatus) - fillPointerlockChangeEventData(pointerlockStatus); - if (!document.body?.requestPointerLock) { - return -1; - } - return 0; - }; - _emscripten_get_pointerlock_status.sig = 'ip'; - - var requestPointerLock = (target) => { - if (target.requestPointerLock) { - target.requestPointerLock(); - } else { - // document.body is known to accept pointer lock, so use that to differentiate if the user passed a bad element, - // or if the whole browser just doesn't support the feature. - if (document.body.requestPointerLock) { - return -3; - } - return -1; - } - return 0; - }; - - var _emscripten_request_pointerlock = ( - target, - deferUntilInEventHandler - ) => { - target = findEventTarget(target); - if (!target) return -4; - if (!target.requestPointerLock) { - return -1; - } - - // Queue this function call if we're not currently in an event handler and - // the user saw it appropriate to do so. - if (!JSEvents.canPerformEventHandlerRequests()) { - if (deferUntilInEventHandler) { - JSEvents.deferCall( - requestPointerLock, - 2 /* priority below fullscreen */, - [target] - ); - return 1; - } - return -2; - } - - return requestPointerLock(target); - }; - _emscripten_request_pointerlock.sig = 'ipi'; - - var _emscripten_exit_pointerlock = () => { - // Make sure no queued up calls will fire after this. - JSEvents.removeDeferredCalls(requestPointerLock); - if (!document.exitPointerLock) return -1; - document.exitPointerLock(); - return 0; - }; - _emscripten_exit_pointerlock.sig = 'i'; - - var _emscripten_vibrate = (msecs) => { - if (!navigator.vibrate) return -1; - navigator.vibrate(msecs); - return 0; - }; - _emscripten_vibrate.sig = 'ii'; - - var _emscripten_vibrate_pattern = (msecsArray, numEntries) => { - if (!navigator.vibrate) return -1; - - var vibrateList = []; - for (var i = 0; i < numEntries; ++i) { - var msecs = HEAP32[(msecsArray + i * 4) >> 2]; - vibrateList.push(msecs); - } - navigator.vibrate(vibrateList); - return 0; - }; - _emscripten_vibrate_pattern.sig = 'ipi'; - - var fillVisibilityChangeEventData = (eventStruct) => { - var visibilityStates = ['hidden', 'visible', 'prerender', 'unloaded']; - var visibilityState = visibilityStates.indexOf( - document.visibilityState - ); - - // Assigning a boolean to HEAP32 with expected type coercion. - /** @suppress{checkTypes} */ - HEAP8[eventStruct] = document.hidden; - HEAP32[(eventStruct + 4) >> 2] = visibilityState; - }; - - var registerVisibilityChangeEventCallback = ( - target, - userData, - useCapture, - callbackfunc, - eventTypeId, - eventTypeString, - targetThread - ) => { - JSEvents.visibilityChangeEvent ||= _malloc(8); - - var visibilityChangeEventHandlerFunc = (e = event) => { - var visibilityChangeEvent = JSEvents.visibilityChangeEvent; - - fillVisibilityChangeEventData(visibilityChangeEvent); - - if ( - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - eventTypeId, - visibilityChangeEvent, - userData - ) - ) - e.preventDefault(); - }; - - var eventHandler = { - target, - eventTypeString, - callbackfunc, - handlerFunc: visibilityChangeEventHandlerFunc, - useCapture, - }; - return JSEvents.registerOrRemoveHandler(eventHandler); - }; - - var _emscripten_set_visibilitychange_callback_on_thread = ( - userData, - useCapture, - callbackfunc, - targetThread - ) => { - if (!specialHTMLTargets[1]) { - return -4; - } - return registerVisibilityChangeEventCallback( - specialHTMLTargets[1], - userData, - useCapture, - callbackfunc, - 21, - 'visibilitychange', - targetThread - ); - }; - _emscripten_set_visibilitychange_callback_on_thread.sig = 'ipipp'; - - var _emscripten_get_visibility_status = (visibilityStatus) => { - if ( - typeof document.visibilityState == 'undefined' && - typeof document.hidden == 'undefined' - ) { - return -1; - } - fillVisibilityChangeEventData(visibilityStatus); - return 0; - }; - _emscripten_get_visibility_status.sig = 'ip'; - - var registerTouchEventCallback = ( - target, - userData, - useCapture, - callbackfunc, - eventTypeId, - eventTypeString, - targetThread - ) => { - JSEvents.touchEvent ||= _malloc(1552); - - target = findEventTarget(target); - - var touchEventHandlerFunc = (e) => { - var t, - touches = {}, - et = e.touches; - // To ease marshalling different kinds of touches that browser reports (all touches are listed in e.touches, - // only changed touches in e.changedTouches, and touches on target at a.targetTouches), mark a boolean in - // each Touch object so that we can later loop only once over all touches we see to marshall over to Wasm. - - for (let t of et) { - // Browser might recycle the generated Touch objects between each frame (Firefox on Android), so reset any - // changed/target states we may have set from previous frame. - t.isChanged = t.onTarget = 0; - touches[t.identifier] = t; - } - // Mark which touches are part of the changedTouches list. - for (let t of e.changedTouches) { - t.isChanged = 1; - touches[t.identifier] = t; - } - // Mark which touches are part of the targetTouches list. - for (let t of e.targetTouches) { - touches[t.identifier].onTarget = 1; - } - - var touchEvent = JSEvents.touchEvent; - HEAPF64[touchEvent >> 3] = e.timeStamp; - HEAP8[touchEvent + 12] = e.ctrlKey; - HEAP8[touchEvent + 13] = e.shiftKey; - HEAP8[touchEvent + 14] = e.altKey; - HEAP8[touchEvent + 15] = e.metaKey; - var idx = touchEvent + 16; - var targetRect = getBoundingClientRect(target); - var numTouches = 0; - for (let t of Object.values(touches)) { - var idx32 = idx >> 2; // Pre-shift the ptr to index to HEAP32 to save code size - HEAP32[idx32 + 0] = t.identifier; - HEAP32[idx32 + 1] = t.screenX; - HEAP32[idx32 + 2] = t.screenY; - HEAP32[idx32 + 3] = t.clientX; - HEAP32[idx32 + 4] = t.clientY; - HEAP32[idx32 + 5] = t.pageX; - HEAP32[idx32 + 6] = t.pageY; - HEAP8[idx + 28] = t.isChanged; - HEAP8[idx + 29] = t.onTarget; - HEAP32[idx32 + 8] = t.clientX - (targetRect.left | 0); - HEAP32[idx32 + 9] = t.clientY - (targetRect.top | 0); - - idx += 48; - - if (++numTouches > 31) { - break; - } - } - HEAP32[(touchEvent + 8) >> 2] = numTouches; - - if ( - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - eventTypeId, - touchEvent, - userData - ) - ) - e.preventDefault(); - }; - - var eventHandler = { - target, - allowsDeferredCalls: - eventTypeString == 'touchstart' || - eventTypeString == 'touchend', - eventTypeString, - callbackfunc, - handlerFunc: touchEventHandlerFunc, - useCapture, - }; - return JSEvents.registerOrRemoveHandler(eventHandler); - }; - - var _emscripten_set_touchstart_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerTouchEventCallback( - target, - userData, - useCapture, - callbackfunc, - 22, - 'touchstart', - targetThread - ); - _emscripten_set_touchstart_callback_on_thread.sig = 'ippipp'; - - var _emscripten_set_touchend_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerTouchEventCallback( - target, - userData, - useCapture, - callbackfunc, - 23, - 'touchend', - targetThread - ); - _emscripten_set_touchend_callback_on_thread.sig = 'ippipp'; - - var _emscripten_set_touchmove_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerTouchEventCallback( - target, - userData, - useCapture, - callbackfunc, - 24, - 'touchmove', - targetThread - ); - _emscripten_set_touchmove_callback_on_thread.sig = 'ippipp'; - - var _emscripten_set_touchcancel_callback_on_thread = ( - target, - userData, - useCapture, - callbackfunc, - targetThread - ) => - registerTouchEventCallback( - target, - userData, - useCapture, - callbackfunc, - 25, - 'touchcancel', - targetThread - ); - _emscripten_set_touchcancel_callback_on_thread.sig = 'ippipp'; - - var fillGamepadEventData = (eventStruct, e) => { - HEAPF64[eventStruct >> 3] = e.timestamp; - for (var i = 0; i < e.axes.length; ++i) { - HEAPF64[(eventStruct + i * 8 + 16) >> 3] = e.axes[i]; - } - for (var i = 0; i < e.buttons.length; ++i) { - if (typeof e.buttons[i] == 'object') { - HEAPF64[(eventStruct + i * 8 + 528) >> 3] = e.buttons[i].value; - } else { - HEAPF64[(eventStruct + i * 8 + 528) >> 3] = e.buttons[i]; - } - } - for (var i = 0; i < e.buttons.length; ++i) { - if (typeof e.buttons[i] == 'object') { - HEAP8[eventStruct + i + 1040] = e.buttons[i].pressed; - } else { - // Assigning a boolean to HEAP32, that's ok, but Closure would like to warn about it: - /** @suppress {checkTypes} */ - HEAP8[eventStruct + i + 1040] = e.buttons[i] == 1; - } - } - HEAP8[eventStruct + 1104] = e.connected; - HEAP32[(eventStruct + 1108) >> 2] = e.index; - HEAP32[(eventStruct + 8) >> 2] = e.axes.length; - HEAP32[(eventStruct + 12) >> 2] = e.buttons.length; - stringToUTF8(e.id, eventStruct + 1112, 64); - stringToUTF8(e.mapping, eventStruct + 1176, 64); - }; - - var registerGamepadEventCallback = ( - target, - userData, - useCapture, - callbackfunc, - eventTypeId, - eventTypeString, - targetThread - ) => { - JSEvents.gamepadEvent ||= _malloc(1240); - - var gamepadEventHandlerFunc = (e = event) => { - var gamepadEvent = JSEvents.gamepadEvent; - fillGamepadEventData(gamepadEvent, e['gamepad']); - - if ( - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - eventTypeId, - gamepadEvent, - userData - ) - ) - e.preventDefault(); - }; - - var eventHandler = { - target: findEventTarget(target), - allowsDeferredCalls: true, - eventTypeString, - callbackfunc, - handlerFunc: gamepadEventHandlerFunc, - useCapture, - }; - return JSEvents.registerOrRemoveHandler(eventHandler); - }; - - /** @suppress {checkTypes} */ - var _emscripten_sample_gamepad_data = () => { - try { - if (navigator.getGamepads) - return (JSEvents.lastGamepadState = navigator.getGamepads()) - ? 0 - : -1; - } catch (e) { - navigator.getGamepads = null; // Disable getGamepads() so that it won't be attempted to be used again. - } - return -1; - }; - _emscripten_sample_gamepad_data.sig = 'i'; - var _emscripten_set_gamepadconnected_callback_on_thread = ( - userData, - useCapture, - callbackfunc, - targetThread - ) => { - if (_emscripten_sample_gamepad_data()) return -1; - return registerGamepadEventCallback( - 2, - userData, - useCapture, - callbackfunc, - 26, - 'gamepadconnected', - targetThread - ); - }; - _emscripten_set_gamepadconnected_callback_on_thread.sig = 'ipipp'; - - var _emscripten_set_gamepaddisconnected_callback_on_thread = ( - userData, - useCapture, - callbackfunc, - targetThread - ) => { - if (_emscripten_sample_gamepad_data()) return -1; - return registerGamepadEventCallback( - 2, - userData, - useCapture, - callbackfunc, - 27, - 'gamepaddisconnected', - targetThread - ); - }; - _emscripten_set_gamepaddisconnected_callback_on_thread.sig = 'ipipp'; - - var _emscripten_get_num_gamepads = () => { - // N.B. Do not call emscripten_get_num_gamepads() unless having first called emscripten_sample_gamepad_data(), and that has returned EMSCRIPTEN_RESULT_SUCCESS. - // Otherwise the following line will throw an exception. - return JSEvents.lastGamepadState.length; - }; - _emscripten_get_num_gamepads.sig = 'i'; - - var _emscripten_get_gamepad_status = (index, gamepadState) => { - // INVALID_PARAM is returned on a Gamepad index that never was there. - if (index < 0 || index >= JSEvents.lastGamepadState.length) return -5; - - // NO_DATA is returned on a Gamepad index that was removed. - // For previously disconnected gamepads there should be an empty slot (null/undefined/false) at the index. - // This is because gamepads must keep their original position in the array. - // For example, removing the first of two gamepads produces [null/undefined/false, gamepad]. - if (!JSEvents.lastGamepadState[index]) return -7; - - fillGamepadEventData(gamepadState, JSEvents.lastGamepadState[index]); - return 0; - }; - _emscripten_get_gamepad_status.sig = 'iip'; - - var registerBeforeUnloadEventCallback = ( - target, - userData, - useCapture, - callbackfunc, - eventTypeId, - eventTypeString - ) => { - var beforeUnloadEventHandlerFunc = (e = event) => { - // Note: This is always called on the main browser thread, since it needs synchronously return a value! - var confirmationMessage = (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - eventTypeId, - 0, - userData - ); - - if (confirmationMessage) { - confirmationMessage = UTF8ToString(confirmationMessage); - } - if (confirmationMessage) { - e.preventDefault(); - e.returnValue = confirmationMessage; - return confirmationMessage; - } - }; - - var eventHandler = { - target: findEventTarget(target), - eventTypeString, - callbackfunc, - handlerFunc: beforeUnloadEventHandlerFunc, - useCapture, - }; - return JSEvents.registerOrRemoveHandler(eventHandler); - }; - - var _emscripten_set_beforeunload_callback_on_thread = ( - userData, - callbackfunc, - targetThread - ) => { - if (typeof onbeforeunload == 'undefined') return -1; - // beforeunload callback can only be registered on the main browser thread, because the page will go away immediately after returning from the handler, - // and there is no time to start proxying it anywhere. - if (targetThread !== 1) return -5; - return registerBeforeUnloadEventCallback( - 2, - userData, - true, - callbackfunc, - 28, - 'beforeunload' - ); - }; - _emscripten_set_beforeunload_callback_on_thread.sig = 'ippp'; - - var fillBatteryEventData = (eventStruct, battery) => { - HEAPF64[eventStruct >> 3] = battery.chargingTime; - HEAPF64[(eventStruct + 8) >> 3] = battery.dischargingTime; - HEAPF64[(eventStruct + 16) >> 3] = battery.level; - HEAP8[eventStruct + 24] = battery.charging; - }; - - var hasBatteryAPI = () => - typeof navigator != 'undefined' && navigator.getBattery; - - var registerBatteryEventCallback = ( - battery, - userData, - useCapture, - callbackfunc, - eventTypeId, - eventTypeString, - targetThread - ) => { - JSEvents.batteryEvent ||= _malloc(32); - - var batteryEventHandlerFunc = (e = event) => { - var batteryEvent = JSEvents.batteryEvent; - fillBatteryEventData(batteryEvent, battery); - - if ( - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - eventTypeId, - batteryEvent, - userData - ) - ) - e.preventDefault(); - }; - - var eventHandler = { - target: battery, - eventTypeString, - callbackfunc, - handlerFunc: batteryEventHandlerFunc, - useCapture, - }; - return JSEvents.registerOrRemoveHandler(eventHandler); - }; - - var _emscripten_set_batterychargingchange_callback_on_thread = ( - userData, - callbackfunc, - targetThread - ) => { - if (!hasBatteryAPI()) return -1; - navigator.getBattery().then((b) => { - registerBatteryEventCallback( - b, - userData, - true, - callbackfunc, - 29, - 'chargingchange', - targetThread - ); - }); - }; - _emscripten_set_batterychargingchange_callback_on_thread.sig = 'ippp'; - - var _emscripten_set_batterylevelchange_callback_on_thread = ( - userData, - callbackfunc, - targetThread - ) => { - if (!hasBatteryAPI()) return -1; - navigator.getBattery().then((b) => { - registerBatteryEventCallback( - b, - userData, - true, - callbackfunc, - 30, - 'levelchange', - targetThread - ); - }); - }; - _emscripten_set_batterylevelchange_callback_on_thread.sig = 'ippp'; - - var batteryManager; - - var _emscripten_get_battery_status = (batteryState) => { - if (!hasBatteryAPI()) return -1; - if (!batteryManager) { - navigator.getBattery().then((b) => { - batteryManager = b; - }); - return -7; - } - fillBatteryEventData(batteryState, batteryManager); - return 0; - }; - _emscripten_get_battery_status.sig = 'ip'; - - var _emscripten_set_element_css_size = (target, width, height) => { - target = findEventTarget(target); - if (!target) return -4; - - target.style.width = width + 'px'; - target.style.height = height + 'px'; - - return 0; - }; - _emscripten_set_element_css_size.sig = 'ipdd'; - - var _emscripten_get_element_css_size = (target, width, height) => { - target = findEventTarget(target); - if (!target) return -4; - - var rect = getBoundingClientRect(target); - HEAPF64[width >> 3] = rect.width; - HEAPF64[height >> 3] = rect.height; - - return 0; - }; - _emscripten_get_element_css_size.sig = 'ippp'; - - var _emscripten_html5_remove_all_event_listeners = () => - JSEvents.removeAllEventListeners(); - _emscripten_html5_remove_all_event_listeners.sig = 'v'; - - var _emscripten_request_animation_frame = (cb, userData) => - requestAnimationFrame((timeStamp) => - (( - a1, - a2 - ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - timeStamp, - userData - ) - ); - _emscripten_request_animation_frame.sig = 'ipp'; - - var _emscripten_cancel_animation_frame = (id) => cancelAnimationFrame(id); - _emscripten_cancel_animation_frame.sig = 'vi'; - - var _emscripten_request_animation_frame_loop = (cb, userData) => { - function tick(timeStamp) { - if ( - (( - a1, - a2 - ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - timeStamp, - userData - ) - ) { - requestAnimationFrame(tick); - } - } - return requestAnimationFrame(tick); - }; - _emscripten_request_animation_frame_loop.sig = 'vpp'; - - var _emscripten_get_device_pixel_ratio = () => { - return (typeof devicePixelRatio == 'number' && devicePixelRatio) || 1.0; - }; - _emscripten_get_device_pixel_ratio.sig = 'd'; - - var _emscripten_get_callstack = (flags, str, maxbytes) => { - var callstack = getCallstack(flags); - // User can query the required amount of bytes to hold the callstack. - if (!str || maxbytes <= 0) { - return lengthBytesUTF8(callstack) + 1; - } - // Output callstack string as C string to HEAP. - var bytesWrittenExcludingNull = stringToUTF8(callstack, str, maxbytes); - - // Return number of bytes written, including null. - return bytesWrittenExcludingNull + 1; - }; - _emscripten_get_callstack.sig = 'iipi'; - - /** @returns {number} */ - var convertFrameToPC = (frame) => { - var match; - - if ((match = /\bwasm-function\[\d+\]:(0x[0-9a-f]+)/.exec(frame))) { - // Wasm engines give the binary offset directly, so we use that as return address - return +match[1]; - } else if ((match = /:(\d+):\d+(?:\)|$)/.exec(frame))) { - // If we are in js, we can use the js line number as the "return address". - // This should work for wasm2js. We tag the high bit to distinguish this - // from wasm addresses. - return 0x80000000 | +match[1]; - } - // return 0 if we can't find any - return 0; - }; - - var _emscripten_return_address = (level) => { - var callstack = jsStackTrace().split('\n'); - if (callstack[0] == 'Error') { - callstack.shift(); - } - // skip this function and the caller to get caller's return address - var caller = callstack[level + 3]; - return convertFrameToPC(caller); - }; - _emscripten_return_address.sig = 'pi'; - - var UNWIND_CACHE = {}; - - var saveInUnwindCache = (callstack) => { - for (var line of callstack) { - var pc = convertFrameToPC(line); - if (pc) { - UNWIND_CACHE[pc] = line; - } - } - }; - - var _emscripten_stack_snapshot = () => { - var callstack = jsStackTrace().split('\n'); - if (callstack[0] == 'Error') { - callstack.shift(); - } - saveInUnwindCache(callstack); - - // Caches the stack snapshot so that emscripten_stack_unwind_buffer() can - // unwind from this spot. - UNWIND_CACHE.last_addr = convertFrameToPC(callstack[3]); - UNWIND_CACHE.last_stack = callstack; - return UNWIND_CACHE.last_addr; - }; - _emscripten_stack_snapshot.sig = 'p'; - - var _emscripten_stack_unwind_buffer = (addr, buffer, count) => { - var stack; - if (UNWIND_CACHE.last_addr == addr) { - stack = UNWIND_CACHE.last_stack; - } else { - stack = jsStackTrace().split('\n'); - if (stack[0] == 'Error') { - stack.shift(); - } - saveInUnwindCache(stack); - } - - var offset = 3; - while (stack[offset] && convertFrameToPC(stack[offset]) != addr) { - ++offset; - } - - for (var i = 0; i < count && stack[i + offset]; ++i) { - HEAP32[(buffer + i * 4) >> 2] = convertFrameToPC(stack[i + offset]); - } - return i; - }; - _emscripten_stack_unwind_buffer.sig = 'ippi'; - - var _emscripten_pc_get_function = (pc) => { - var frame = UNWIND_CACHE[pc]; - if (!frame) return 0; - - var name; - var match; - // First try to match foo.wasm.sym files explcitly. e.g. - // - // at test_return_address.wasm.main (wasm://wasm/test_return_address.wasm-0012cc2a:wasm-function[26]:0x9f3 - // - // Then match JS symbols which don't include that module name: - // - // at invokeEntryPoint (.../test_return_address.js:1500:42) - // - // Finally match firefox format: - // - // Object._main@http://server.com:4324:12' - if ((match = /^\s+at .*\.wasm\.(.*) \(.*\)$/.exec(frame))) { - name = match[1]; - } else if ((match = /^\s+at (.*) \(.*\)$/.exec(frame))) { - name = match[1]; - } else if ((match = /^(.+?)@/.exec(frame))) { - name = match[1]; - } else { - return 0; - } - - _free(_emscripten_pc_get_function.ret ?? 0); - _emscripten_pc_get_function.ret = stringToNewUTF8(name); - return _emscripten_pc_get_function.ret; - }; - _emscripten_pc_get_function.sig = 'pp'; - - var convertPCtoSourceLocation = (pc) => { - if (UNWIND_CACHE.last_get_source_pc == pc) - return UNWIND_CACHE.last_source; - - var match; - var source; - - if (!source) { - var frame = UNWIND_CACHE[pc]; - if (!frame) return null; - // Example: at callMain (a.out.js:6335:22) - if ((match = /\((.*):(\d+):(\d+)\)$/.exec(frame))) { - source = { file: match[1], line: match[2], column: match[3] }; - // Example: main@a.out.js:1337:42 - } else if ((match = /@(.*):(\d+):(\d+)/.exec(frame))) { - source = { file: match[1], line: match[2], column: match[3] }; - } - } - UNWIND_CACHE.last_get_source_pc = pc; - UNWIND_CACHE.last_source = source; - return source; - }; - - var _emscripten_pc_get_file = (pc) => { - var result = convertPCtoSourceLocation(pc); - if (!result) return 0; - - _free(_emscripten_pc_get_file.ret ?? 0); - _emscripten_pc_get_file.ret = stringToNewUTF8(result.file); - return _emscripten_pc_get_file.ret; - }; - _emscripten_pc_get_file.sig = 'pp'; - - var _emscripten_pc_get_line = (pc) => { - var result = convertPCtoSourceLocation(pc); - return result ? result.line : 0; - }; - _emscripten_pc_get_line.sig = 'ip'; - - var _emscripten_pc_get_column = (pc) => { - var result = convertPCtoSourceLocation(pc); - return result ? result.column || 0 : 0; - }; - _emscripten_pc_get_column.sig = 'ip'; - - var _sched_yield = () => 0; - _sched_yield.sig = 'i'; - - var wasiRightsToMuslOFlags = (rights) => { - if (rights & 2 && rights & 64) { - return 2; - } - if (rights & 2) { - return 0; - } - if (rights & 64) { - return 1; - } - throw new FS.ErrnoError(28); - }; - - var wasiOFlagsToMuslOFlags = (oflags) => { - var musl_oflags = 0; - if (oflags & 1) { - musl_oflags |= 64; - } - if (oflags & 8) { - musl_oflags |= 512; - } - if (oflags & 2) { - musl_oflags |= 65536; - } - if (oflags & 4) { - musl_oflags |= 128; - } - return musl_oflags; - }; - - var _emscripten_unwind_to_js_event_loop = () => { - throw 'unwind'; - }; - _emscripten_unwind_to_js_event_loop.sig = 'v'; - - var setImmediateWrapped = (func) => { - setImmediateWrapped.mapping ||= []; - var id = setImmediateWrapped.mapping.length; - setImmediateWrapped.mapping[id] = setImmediate(() => { - setImmediateWrapped.mapping[id] = undefined; - func(); - }); - return id; - }; - - var safeRequestAnimationFrame = (func) => { - runtimeKeepalivePush(); - return MainLoop.requestAnimationFrame(() => { - runtimeKeepalivePop(); - callUserCallback(func); - }); - }; - - var clearImmediateWrapped = (id) => { - clearImmediate(setImmediateWrapped.mapping[id]); - setImmediateWrapped.mapping[id] = undefined; - }; - - var emClearImmediate; - var emSetImmediate; - - var emClearImmediate_deps = ['$emSetImmediate']; - - var _emscripten_set_immediate = (cb, userData) => { - runtimeKeepalivePush(); - return emSetImmediate(() => { - runtimeKeepalivePop(); - callUserCallback(() => - (( - a1 - ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - userData - ) - ); - }); - }; - _emscripten_set_immediate.sig = 'ipp'; - - var _emscripten_clear_immediate = (id) => { - runtimeKeepalivePop(); - emClearImmediate(id); - }; - _emscripten_clear_immediate.sig = 'vi'; - - var _emscripten_set_immediate_loop = (cb, userData) => { - function tick() { - callUserCallback(() => { - if ( - (( - a1 - ) => {}) /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - userData - ) - ) { - emSetImmediate(tick); - } else { - runtimeKeepalivePop(); - } - }); - } - runtimeKeepalivePush(); - emSetImmediate(tick); - }; - _emscripten_set_immediate_loop.sig = 'vpp'; - - var _emscripten_set_timeout = (cb, msecs, userData) => - safeSetTimeout( - () => - (( - a1 - ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - userData - ), - msecs - ); - _emscripten_set_timeout.sig = 'ipdp'; - - var _emscripten_clear_timeout = clearTimeout; - _emscripten_clear_timeout.sig = 'vi'; - - var _emscripten_set_timeout_loop = (cb, msecs, userData) => { - function tick() { - var t = _emscripten_get_now(); - var n = t + msecs; - runtimeKeepalivePop(); - callUserCallback(() => { - if ( - (( - a1, - a2 - ) => {}) /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - t, - userData - ) - ) { - runtimeKeepalivePush(); - // Save a little bit of code space: modern browsers should treat - // negative setTimeout as timeout of 0 - // (https://stackoverflow.com/questions/8430966/is-calling-settimeout-with-a-negative-delay-ok) - var remaining = n - _emscripten_get_now(); - // Recent revsions of node, however, give TimeoutNegativeWarning - remaining = Math.max(0, remaining); - setTimeout(tick, remaining); - } - }); - } - runtimeKeepalivePush(); - return setTimeout(tick, 0); - }; - _emscripten_set_timeout_loop.sig = 'vpdp'; - - var _emscripten_set_interval = (cb, msecs, userData) => { - runtimeKeepalivePush(); - return setInterval(() => { - callUserCallback(() => - (( - a1 - ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - userData - ) - ); - }, msecs); - }; - _emscripten_set_interval.sig = 'ipdp'; - - var _emscripten_clear_interval = (id) => { - runtimeKeepalivePop(); - clearInterval(id); - }; - _emscripten_clear_interval.sig = 'vi'; - - var _emscripten_async_call = (func, arg, millis) => { - var wrapper = () => - (( - a1 - ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - arg - ); - - if ( - millis >= 0 || - // node does not support requestAnimationFrame - ENVIRONMENT_IS_NODE - ) { - safeSetTimeout(wrapper, millis); - } else { - safeRequestAnimationFrame(wrapper); - } - }; - _emscripten_async_call.sig = 'vppi'; - - var registerPostMainLoop = (f) => { - // Does nothing unless $MainLoop is included/used. - typeof MainLoop != 'undefined' && MainLoop.postMainLoop.push(f); - }; - - var registerPreMainLoop = (f) => { - // Does nothing unless $MainLoop is included/used. - typeof MainLoop != 'undefined' && MainLoop.preMainLoop.push(f); - }; - - var _emscripten_get_main_loop_timing = (mode, value) => { - if (mode) HEAP32[mode >> 2] = MainLoop.timingMode; - if (value) HEAP32[value >> 2] = MainLoop.timingValue; - }; - _emscripten_get_main_loop_timing.sig = 'vpp'; - - var _emscripten_set_main_loop = (func, fps, simulateInfiniteLoop) => { - var iterFunc = - () => {} /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */; - setMainLoop(iterFunc, fps, simulateInfiniteLoop); - }; - _emscripten_set_main_loop.sig = 'vpii'; - - var _emscripten_set_main_loop_arg = ( - func, - arg, - fps, - simulateInfiniteLoop - ) => { - var iterFunc = () => - (( - a1 - ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - arg - ); - setMainLoop(iterFunc, fps, simulateInfiniteLoop, arg); - }; - _emscripten_set_main_loop_arg.sig = 'vppii'; - - var _emscripten_cancel_main_loop = () => { - MainLoop.pause(); - MainLoop.func = null; - }; - _emscripten_cancel_main_loop.sig = 'v'; - - var _emscripten_pause_main_loop = () => MainLoop.pause(); - _emscripten_pause_main_loop.sig = 'v'; - - var _emscripten_resume_main_loop = () => MainLoop.resume(); - _emscripten_resume_main_loop.sig = 'v'; - - var __emscripten_push_main_loop_blocker = (func, arg, name) => { - MainLoop.queue.push({ - func: () => { - (( - a1 - ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - arg - ); - }, - name: UTF8ToString(name), - counted: true, - }); - MainLoop.updateStatus(); - }; - __emscripten_push_main_loop_blocker.sig = 'vppp'; - - var __emscripten_push_uncounted_main_loop_blocker = (func, arg, name) => { - MainLoop.queue.push({ - func: () => { - (( - a1 - ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - arg - ); - }, - name: UTF8ToString(name), - counted: false, - }); - MainLoop.updateStatus(); - }; - __emscripten_push_uncounted_main_loop_blocker.sig = 'vppp'; - - var _emscripten_set_main_loop_expected_blockers = (num) => { - MainLoop.expectedBlockers = num; - MainLoop.remainingBlockers = num; - MainLoop.updateStatus(); - }; - _emscripten_set_main_loop_expected_blockers.sig = 'vi'; - - var idsToPromises = (idBuf, size) => { - var promises = []; - for (var i = 0; i < size; i++) { - var id = HEAP32[(idBuf + i * 4) >> 2]; - promises[i] = getPromise(id); - } - return promises; - }; - - var makePromiseCallback = (callback, userData) => { - return (value) => { - runtimeKeepalivePop(); - var stack = stackSave(); - // Allocate space for the result value and initialize it to NULL. - var resultPtr = stackAlloc(POINTER_SIZE); - HEAPU32[resultPtr >> 2] = 0; - try { - var result = (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - resultPtr, - userData, - value - ); - var resultVal = HEAPU32[resultPtr >> 2]; - } catch (e) { - // If the thrown value is potentially a valid pointer, use it as the - // rejection reason. Otherwise use a null pointer as the reason. If we - // allow arbitrary objects to be thrown here, we will get a TypeError in - // MEMORY64 mode when they are later converted to void* rejection - // values. - if (typeof e != 'number') { - throw 0; - } - throw e; - } finally { - // Thrown errors will reject the promise, but at least we will restore - // the stack first. - stackRestore(stack); - } - switch (result) { - case 0: - return resultVal; - case 1: - return getPromise(resultVal); - case 2: - var ret = getPromise(resultVal); - _emscripten_promise_destroy(resultVal); - return ret; - case 3: - throw resultVal; - } - }; - }; - - var _emscripten_promise_then = (id, onFulfilled, onRejected, userData) => { - runtimeKeepalivePush(); - var promise = getPromise(id); - var newId = promiseMap.allocate({ - promise: promise.then( - makePromiseCallback(onFulfilled, userData), - makePromiseCallback(onRejected, userData) - ), - }); - return newId; - }; - _emscripten_promise_then.sig = 'ppppp'; - - var _emscripten_promise_all = (idBuf, resultBuf, size) => { - var promises = idsToPromises(idBuf, size); - var id = promiseMap.allocate({ - promise: Promise.all(promises).then((results) => { - if (resultBuf) { - for (var i = 0; i < size; i++) { - var result = results[i]; - HEAPU32[(resultBuf + i * 4) >> 2] = result; - } - } - return resultBuf; - }), - }); - return id; - }; - _emscripten_promise_all.sig = 'pppp'; - - var setPromiseResult = (ptr, fulfill, value) => { - var result = fulfill ? 0 : 3; - HEAP32[ptr >> 2] = result; - HEAPU32[(ptr + 4) >> 2] = value; - }; - - var _emscripten_promise_all_settled = (idBuf, resultBuf, size) => { - var promises = idsToPromises(idBuf, size); - var id = promiseMap.allocate({ - promise: Promise.allSettled(promises).then((results) => { - if (resultBuf) { - var offset = resultBuf; - for (var i = 0; i < size; i++, offset += 8) { - if (results[i].status === 'fulfilled') { - setPromiseResult(offset, true, results[i].value); - } else { - setPromiseResult(offset, false, results[i].reason); - } - } - } - return resultBuf; - }), - }); - return id; - }; - _emscripten_promise_all_settled.sig = 'pppp'; - - var _emscripten_promise_any = (idBuf, errorBuf, size) => { - var promises = idsToPromises(idBuf, size); - var id = promiseMap.allocate({ - promise: Promise.any(promises).catch((err) => { - if (errorBuf) { - for (var i = 0; i < size; i++) { - HEAPU32[(errorBuf + i * 4) >> 2] = err.errors[i]; - } - } - throw errorBuf; - }), - }); - return id; - }; - _emscripten_promise_any.sig = 'pppp'; - - var _emscripten_promise_race = (idBuf, size) => { - var promises = idsToPromises(idBuf, size); - var id = promiseMap.allocate({ - promise: Promise.race(promises), - }); - return id; - }; - _emscripten_promise_race.sig = 'ppp'; - - var _emscripten_promise_await = (returnValuePtr, id) => { - return Asyncify.handleAsync(() => - getPromise(id).then( - (value) => setPromiseResult(returnValuePtr, true, value), - (error) => setPromiseResult(returnValuePtr, false, error) - ) - ); - }; - _emscripten_promise_await.sig = 'vpp'; - _emscripten_promise_await.isAsync = true; - - var ___cxa_find_matching_catch_3 = (arg0) => findMatchingCatch([arg0]); - ___cxa_find_matching_catch_3.sig = 'pp'; - - var ___cxa_find_matching_catch_4 = (arg0, arg1) => - findMatchingCatch([arg0, arg1]); - ___cxa_find_matching_catch_4.sig = 'ppp'; - - var exceptionCaught = []; - - var ___cxa_rethrow = () => { - var info = exceptionCaught.pop(); - if (!info) { - abort('no exception to throw'); - } - var ptr = info.excPtr; - if (!info.get_rethrown()) { - // Only pop if the corresponding push was through rethrow_primary_exception - exceptionCaught.push(info); - info.set_rethrown(true); - info.set_caught(false); - uncaughtExceptionCount++; - } - exceptionLast = ptr; - throw exceptionLast; - }; - ___cxa_rethrow.sig = 'v'; - - var _llvm_eh_typeid_for = (type) => type; - _llvm_eh_typeid_for.sig = 'vp'; - - var ___cxa_begin_catch = (ptr) => { - var info = new ExceptionInfo(ptr); - if (!info.get_caught()) { - info.set_caught(true); - uncaughtExceptionCount--; - } - info.set_rethrown(false); - exceptionCaught.push(info); - ___cxa_increment_exception_refcount(ptr); - return ___cxa_get_exception_ptr(ptr); - }; - ___cxa_begin_catch.sig = 'pp'; - - var ___cxa_end_catch = () => { - // Clear state flag. - _setThrew(0, 0); - // Call destructor if one is registered then clear it. - var info = exceptionCaught.pop(); - - ___cxa_decrement_exception_refcount(info.excPtr); - exceptionLast = 0; // XXX in decRef? - }; - ___cxa_end_catch.sig = 'v'; - - var ___cxa_uncaught_exceptions = () => uncaughtExceptionCount; - ___cxa_uncaught_exceptions.sig = 'i'; - - var ___cxa_call_unexpected = (exception) => - abort( - 'Unexpected exception thrown, this is not properly supported - aborting' - ); - ___cxa_call_unexpected.sig = 'vp'; - - var ___cxa_current_primary_exception = () => { - if (!exceptionCaught.length) { - return 0; - } - var info = exceptionCaught[exceptionCaught.length - 1]; - ___cxa_increment_exception_refcount(info.excPtr); - return info.excPtr; - }; - ___cxa_current_primary_exception.sig = 'p'; - - function ___cxa_current_exception_type() { - if (!exceptionCaught.length) { - return 0; - } - var info = exceptionCaught[exceptionCaught.length - 1]; - return info.get_type(); - } - ___cxa_current_exception_type.sig = 'p'; - - var ___cxa_rethrow_primary_exception = (ptr) => { - if (!ptr) return; - var info = new ExceptionInfo(ptr); - exceptionCaught.push(info); - info.set_rethrown(true); - ___cxa_rethrow(); - }; - ___cxa_rethrow_primary_exception.sig = 'vp'; - - var Browser = { - useWebGL: false, - isFullscreen: false, - pointerLock: false, - moduleContextCreatedCallbacks: [], - workers: [], - preloadedImages: {}, - preloadedAudios: {}, - getCanvas: () => Module['canvas'], - init() { - if (Browser.initted) return; - Browser.initted = true; - - // Support for plugins that can process preloaded files. You can add more of these to - // your app by creating and appending to preloadPlugins. - // - // Each plugin is asked if it can handle a file based on the file's name. If it can, - // it is given the file's raw data. When it is done, it calls a callback with the file's - // (possibly modified) data. For example, a plugin might decompress a file, or it - // might create some side data structure for use later (like an Image element, etc.). - - var imagePlugin = {}; - imagePlugin['canHandle'] = function imagePlugin_canHandle(name) { - return ( - !Module['noImageDecoding'] && - /\.(jpg|jpeg|png|bmp|webp)$/i.test(name) - ); - }; - imagePlugin['handle'] = async function imagePlugin_handle( - byteArray, - name - ) { - var b = new Blob([byteArray], { - type: Browser.getMimetype(name), - }); - if (b.size !== byteArray.length) { - // Safari bug #118630 - // Safari's Blob can only take an ArrayBuffer - b = new Blob([new Uint8Array(byteArray).buffer], { - type: Browser.getMimetype(name), - }); - } - var url = URL.createObjectURL(b); - return new Promise((resolve, reject) => { - var img = new Image(); - img.onload = () => { - var canvas = /** @type {!HTMLCanvasElement} */ ( - document.createElement('canvas') - ); - canvas.width = img.width; - canvas.height = img.height; - var ctx = canvas.getContext('2d'); - ctx.drawImage(img, 0, 0); - Browser.preloadedImages[name] = canvas; - URL.revokeObjectURL(url); - resolve(byteArray); - }; - img.onerror = (event) => { - err(`Image ${url} could not be decoded`); - reject(); - }; - img.src = url; - }); - }; - preloadPlugins.push(imagePlugin); - - var audioPlugin = {}; - audioPlugin['canHandle'] = function audioPlugin_canHandle(name) { - return ( - !Module['noAudioDecoding'] && - name.slice(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 } - ); - }; - audioPlugin['handle'] = async function audioPlugin_handle( - byteArray, - name - ) { - return new Promise((resolve, reject) => { - var done = false; - function finish(audio) { - if (done) return; - done = true; - Browser.preloadedAudios[name] = audio; - resolve(byteArray); - } - var b = new Blob([byteArray], { - type: Browser.getMimetype(name), - }); - var url = URL.createObjectURL(b); // XXX we never revoke this! - var audio = new Audio(); - audio.addEventListener( - 'canplaythrough', - () => finish(audio), - false - ); // use addEventListener due to chromium bug 124926 - audio.onerror = function audio_onerror(event) { - if (done) return; - err( - `warning: browser could not fully decode audio ${name}, trying slower base64 approach` - ); - function encode64(data) { - var BASE = - 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - var PAD = '='; - var ret = ''; - var leftchar = 0; - var leftbits = 0; - for (var i = 0; i < data.length; i++) { - leftchar = (leftchar << 8) | data[i]; - leftbits += 8; - while (leftbits >= 6) { - var curr = - (leftchar >> (leftbits - 6)) & 0x3f; - leftbits -= 6; - ret += BASE[curr]; - } - } - if (leftbits == 2) { - ret += BASE[(leftchar & 3) << 4]; - ret += PAD + PAD; - } else if (leftbits == 4) { - ret += BASE[(leftchar & 0xf) << 2]; - ret += PAD; - } - return ret; - } - audio.src = - 'data:audio/x-' + - name.slice(-3) + - ';base64,' + - encode64(byteArray); - finish(audio); // we don't wait for confirmation this worked - but it's worth trying - }; - audio.src = url; - // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror - safeSetTimeout(() => { - finish(audio); // try to use it even though it is not necessarily ready to play - }, 10000); - }); - }; - preloadPlugins.push(audioPlugin); - - // Canvas event setup - - function pointerLockChange() { - var canvas = Browser.getCanvas(); - Browser.pointerLock = document.pointerLockElement === canvas; - } - var canvas = Browser.getCanvas(); - if (canvas) { - // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module - // Module['forcedAspectRatio'] = 4 / 3; - - document.addEventListener( - 'pointerlockchange', - pointerLockChange, - false - ); - - if (Module['elementPointerLock']) { - canvas.addEventListener( - 'click', - (ev) => { - if ( - !Browser.pointerLock && - Browser.getCanvas().requestPointerLock - ) { - Browser.getCanvas().requestPointerLock(); - ev.preventDefault(); - } - }, - false - ); - } - } - }, - createContext( - /** @type {HTMLCanvasElement} */ canvas, - useWebGL, - setInModule, - webGLContextAttributes - ) { - if (useWebGL && Module['ctx'] && canvas == Browser.getCanvas()) - return Module['ctx']; // no need to recreate GL context if it's already been created for this canvas. - - var ctx; - var contextHandle; - if (useWebGL) { - // For GLES2/desktop GL compatibility, adjust a few defaults to be different to WebGL defaults, so that they align better with the desktop defaults. - var contextAttributes = { - antialias: false, - alpha: false, - majorVersion: 1, - }; - - if (webGLContextAttributes) { - for (var attribute in webGLContextAttributes) { - contextAttributes[attribute] = - webGLContextAttributes[attribute]; - } - } - - // This check of existence of GL is here to satisfy Closure compiler, which yells if variable GL is referenced below but GL object is not - // actually compiled in because application is not doing any GL operations. TODO: Ideally if GL is not being used, this function - // Browser.createContext() should not even be emitted. - if (typeof GL != 'undefined') { - contextHandle = GL.createContext(canvas, contextAttributes); - if (contextHandle) { - ctx = GL.getContext(contextHandle).GLctx; - } - } - } else { - ctx = canvas.getContext('2d'); - } - - if (!ctx) return null; - - if (setInModule) { - Module['ctx'] = ctx; - if (useWebGL) GL.makeContextCurrent(contextHandle); - Browser.useWebGL = useWebGL; - Browser.moduleContextCreatedCallbacks.forEach((callback) => - callback() - ); - Browser.init(); - } - return ctx; - }, - fullscreenHandlersInstalled: false, - lockPointer: undefined, - resizeCanvas: undefined, - requestFullscreen(lockPointer, resizeCanvas) { - Browser.lockPointer = lockPointer; - Browser.resizeCanvas = resizeCanvas; - if (typeof Browser.lockPointer == 'undefined') - Browser.lockPointer = true; - if (typeof Browser.resizeCanvas == 'undefined') - Browser.resizeCanvas = false; - - var canvas = Browser.getCanvas(); - function fullscreenChange() { - Browser.isFullscreen = false; - var canvasContainer = canvas.parentNode; - if (getFullscreenElement() === canvasContainer) { - canvas.exitFullscreen = Browser.exitFullscreen; - if (Browser.lockPointer) canvas.requestPointerLock(); - Browser.isFullscreen = true; - if (Browser.resizeCanvas) { - Browser.setFullscreenCanvasSize(); - } else { - Browser.updateCanvasDimensions(canvas); - } - } else { - // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen - canvasContainer.parentNode.insertBefore( - canvas, - canvasContainer - ); - canvasContainer.parentNode.removeChild(canvasContainer); - - if (Browser.resizeCanvas) { - Browser.setWindowedCanvasSize(); - } else { - Browser.updateCanvasDimensions(canvas); - } - } - Module['onFullScreen']?.(Browser.isFullscreen); - Module['onFullscreen']?.(Browser.isFullscreen); - } - - if (!Browser.fullscreenHandlersInstalled) { - Browser.fullscreenHandlersInstalled = true; - document.addEventListener( - 'fullscreenchange', - fullscreenChange, - false - ); - document.addEventListener( - 'mozfullscreenchange', - fullscreenChange, - false - ); - document.addEventListener( - 'webkitfullscreenchange', - fullscreenChange, - false - ); - document.addEventListener( - 'MSFullscreenChange', - fullscreenChange, - false - ); - } - - // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root - var canvasContainer = document.createElement('div'); - canvas.parentNode.insertBefore(canvasContainer, canvas); - canvasContainer.appendChild(canvas); - - // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size) - canvasContainer.requestFullscreen = - canvasContainer['requestFullscreen'] || - canvasContainer['mozRequestFullScreen'] || - canvasContainer['msRequestFullscreen'] || - (canvasContainer['webkitRequestFullscreen'] - ? () => - canvasContainer['webkitRequestFullscreen']( - Element['ALLOW_KEYBOARD_INPUT'] - ) - : null) || - (canvasContainer['webkitRequestFullScreen'] - ? () => - canvasContainer['webkitRequestFullScreen']( - Element['ALLOW_KEYBOARD_INPUT'] - ) - : null); - - canvasContainer.requestFullscreen(); - }, - exitFullscreen() { - // This is workaround for chrome. Trying to exit from fullscreen - // not in fullscreen state will cause "TypeError: Document not active" - // in chrome. See https://github.com/emscripten-core/emscripten/pull/8236 - if (!Browser.isFullscreen) { - return false; - } - - var CFS = - document['exitFullscreen'] || - document['cancelFullScreen'] || - document['mozCancelFullScreen'] || - document['msExitFullscreen'] || - document['webkitCancelFullScreen'] || - (() => {}); - CFS.apply(document, []); - return true; - }, - safeSetTimeout(func, timeout) { - // Legacy function, this is used by the SDL2 port so we need to keep it - // around at least until that is updated. - // See https://github.com/libsdl-org/SDL/pull/6304 - return safeSetTimeout(func, timeout); - }, - getMimetype(name) { - return { - jpg: 'image/jpeg', - jpeg: 'image/jpeg', - png: 'image/png', - bmp: 'image/bmp', - ogg: 'audio/ogg', - wav: 'audio/wav', - mp3: 'audio/mpeg', - }[name.slice(name.lastIndexOf('.') + 1)]; - }, - getUserMedia(func) { - window.getUserMedia ||= - navigator['getUserMedia'] || navigator['mozGetUserMedia']; - window.getUserMedia(func); - }, - getMovementX(event) { - return ( - event['movementX'] || - event['mozMovementX'] || - event['webkitMovementX'] || - 0 - ); - }, - getMovementY(event) { - return ( - event['movementY'] || - event['mozMovementY'] || - event['webkitMovementY'] || - 0 - ); - }, - getMouseWheelDelta(event) { - var delta = 0; - switch (event.type) { - case 'DOMMouseScroll': - // 3 lines make up a step - delta = event.detail / 3; - break; - case 'mousewheel': - // 120 units make up a step - delta = event.wheelDelta / 120; - break; - case 'wheel': - delta = event.deltaY; - switch (event.deltaMode) { - case 0: - // DOM_DELTA_PIXEL: 100 pixels make up a step - delta /= 100; - break; - case 1: - // DOM_DELTA_LINE: 3 lines make up a step - delta /= 3; - break; - case 2: - // DOM_DELTA_PAGE: A page makes up 80 steps - delta *= 80; - break; - default: - abort( - 'unrecognized mouse wheel delta mode: ' + - event.deltaMode - ); - } - break; - default: - abort('unrecognized mouse wheel event: ' + event.type); - } - return delta; - }, - mouseX: 0, - mouseY: 0, - mouseMovementX: 0, - mouseMovementY: 0, - touches: {}, - lastTouches: {}, - calculateMouseCoords(pageX, pageY) { - // Calculate the movement based on the changes - // in the coordinates. - var canvas = Browser.getCanvas(); - var rect = canvas.getBoundingClientRect(); - - // Neither .scrollX or .pageXOffset are defined in a spec, but - // we prefer .scrollX because it is currently in a spec draft. - // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/) - var scrollX = - typeof window.scrollX != 'undefined' - ? window.scrollX - : window.pageXOffset; - var scrollY = - typeof window.scrollY != 'undefined' - ? window.scrollY - : window.pageYOffset; - var adjustedX = pageX - (scrollX + rect.left); - var adjustedY = pageY - (scrollY + rect.top); - - // the canvas might be CSS-scaled compared to its backbuffer; - // SDL-using content will want mouse coordinates in terms - // of backbuffer units. - adjustedX = adjustedX * (canvas.width / rect.width); - adjustedY = adjustedY * (canvas.height / rect.height); - - return { x: adjustedX, y: adjustedY }; - }, - setMouseCoords(pageX, pageY) { - const { x, y } = Browser.calculateMouseCoords(pageX, pageY); - Browser.mouseMovementX = x - Browser.mouseX; - Browser.mouseMovementY = y - Browser.mouseY; - Browser.mouseX = x; - Browser.mouseY = y; - }, - calculateMouseEvent(event) { - // event should be mousemove, mousedown or mouseup - if (Browser.pointerLock) { - // When the pointer is locked, calculate the coordinates - // based on the movement of the mouse. - // Workaround for Firefox bug 764498 - if (event.type != 'mousemove' && 'mozMovementX' in event) { - Browser.mouseMovementX = Browser.mouseMovementY = 0; - } else { - Browser.mouseMovementX = Browser.getMovementX(event); - Browser.mouseMovementY = Browser.getMovementY(event); - } - - // add the mouse delta to the current absolute mouse position - Browser.mouseX += Browser.mouseMovementX; - Browser.mouseY += Browser.mouseMovementY; - } else { - if ( - event.type === 'touchstart' || - event.type === 'touchend' || - event.type === 'touchmove' - ) { - var touch = event.touch; - if (touch === undefined) { - return; // the "touch" property is only defined in SDL - } - var coords = Browser.calculateMouseCoords( - touch.pageX, - touch.pageY - ); - - if (event.type === 'touchstart') { - Browser.lastTouches[touch.identifier] = coords; - Browser.touches[touch.identifier] = coords; - } else if ( - event.type === 'touchend' || - event.type === 'touchmove' - ) { - var last = Browser.touches[touch.identifier]; - last ||= coords; - Browser.lastTouches[touch.identifier] = last; - Browser.touches[touch.identifier] = coords; - } - return; - } - - Browser.setMouseCoords(event.pageX, event.pageY); - } - }, - resizeListeners: [], - updateResizeListeners() { - var canvas = Browser.getCanvas(); - Browser.resizeListeners.forEach((listener) => - listener(canvas.width, canvas.height) - ); - }, - setCanvasSize(width, height, noUpdates) { - var canvas = Browser.getCanvas(); - Browser.updateCanvasDimensions(canvas, width, height); - if (!noUpdates) Browser.updateResizeListeners(); - }, - windowedWidth: 0, - windowedHeight: 0, - setFullscreenCanvasSize() { - // check if SDL is available - if (typeof SDL != 'undefined') { - var flags = HEAPU32[SDL.screen >> 2]; - flags = flags | 0x00800000; // set SDL_FULLSCREEN flag - HEAP32[SDL.screen >> 2] = flags; - } - Browser.updateCanvasDimensions(Browser.getCanvas()); - Browser.updateResizeListeners(); - }, - setWindowedCanvasSize() { - // check if SDL is available - if (typeof SDL != 'undefined') { - var flags = HEAPU32[SDL.screen >> 2]; - flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag - HEAP32[SDL.screen >> 2] = flags; - } - Browser.updateCanvasDimensions(Browser.getCanvas()); - Browser.updateResizeListeners(); - }, - updateCanvasDimensions(canvas, wNative, hNative) { - if (wNative && hNative) { - canvas.widthNative = wNative; - canvas.heightNative = hNative; - } else { - wNative = canvas.widthNative; - hNative = canvas.heightNative; - } - var w = wNative; - var h = hNative; - if (Module['forcedAspectRatio'] > 0) { - if (w / h < Module['forcedAspectRatio']) { - w = Math.round(h * Module['forcedAspectRatio']); - } else { - h = Math.round(w / Module['forcedAspectRatio']); - } - } - if ( - getFullscreenElement() === canvas.parentNode && - typeof screen != 'undefined' - ) { - var factor = Math.min(screen.width / w, screen.height / h); - w = Math.round(w * factor); - h = Math.round(h * factor); - } - if (Browser.resizeCanvas) { - if (canvas.width != w) canvas.width = w; - if (canvas.height != h) canvas.height = h; - if (typeof canvas.style != 'undefined') { - canvas.style.removeProperty('width'); - canvas.style.removeProperty('height'); - } - } else { - if (canvas.width != wNative) canvas.width = wNative; - if (canvas.height != hNative) canvas.height = hNative; - if (typeof canvas.style != 'undefined') { - if (w != wNative || h != hNative) { - canvas.style.setProperty( - 'width', - w + 'px', - 'important' - ); - canvas.style.setProperty( - 'height', - h + 'px', - 'important' - ); - } else { - canvas.style.removeProperty('width'); - canvas.style.removeProperty('height'); - } - } - } - }, - }; - - var requestFullscreen = Browser.requestFullscreen; - - var setCanvasSize = Browser.setCanvasSize; - - var getUserMedia = Browser.getUserMedia; - - var createContext = Browser.createContext; - - var _emscripten_run_preload_plugins = (file, onload, onerror) => { - runtimeKeepalivePush(); - - var _file = UTF8ToString(file); - var data = FS.analyzePath(_file); - if (!data.exists) return -1; - FS.createPreloadedFile( - PATH.dirname(_file), - PATH.basename(_file), - // TODO: This copy is not needed if the contents are already a Uint8Array, - // which they often are (and always are in WasmFS). - new Uint8Array(data.object.contents), - true, - true, - () => { - runtimeKeepalivePop(); - if (onload) - (( - a1 - ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - file - ); - }, - () => { - runtimeKeepalivePop(); - if (onerror) - (( - a1 - ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - file - ); - }, - true // don'tCreateFile - it's already there - ); - return 0; - }; - _emscripten_run_preload_plugins.sig = 'ippp'; - - var Browser_asyncPrepareDataCounter = 0; - - var _emscripten_run_preload_plugins_data = ( - data, - size, - suffix, - arg, - onload, - onerror - ) => { - runtimeKeepalivePush(); - - var _suffix = UTF8ToString(suffix); - var name = - 'prepare_data_' + Browser_asyncPrepareDataCounter++ + '.' + _suffix; - var cname = stringToNewUTF8(name); - FS.createPreloadedFile( - '/', - name, - HEAPU8.subarray(data, data + size), - true, - true, - () => { - runtimeKeepalivePop(); - if (onload) - (( - a1, - a2 - ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - arg, - cname - ); - }, - () => { - runtimeKeepalivePop(); - if (onerror) - (( - a1 - ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - arg - ); - }, - true // don'tCreateFile - it's already there - ); - }; - _emscripten_run_preload_plugins_data.sig = 'vpipppp'; - - var _emscripten_async_run_script = (script, millis) => { - // TODO: cache these to avoid generating garbage - safeSetTimeout(() => _emscripten_run_script(script), millis); - }; - _emscripten_async_run_script.sig = 'vpi'; - - var _emscripten_async_load_script = async (url, onload, onerror) => { - url = UTF8ToString(url); - runtimeKeepalivePush(); - - var loadDone = () => { - runtimeKeepalivePop(); - if (onload) { - var onloadCallback = () => - callUserCallback( - () => {} /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ - ); - if (runDependencies > 0) { - dependenciesFulfilled = onloadCallback; - } else { - onloadCallback(); - } - } - }; - - var loadError = () => { - runtimeKeepalivePop(); - if (onerror) { - callUserCallback( - () => {} /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */ - ); - } - }; - - if (ENVIRONMENT_IS_NODE) { - try { - var data = await readAsync(url, false); - eval(data); - loadDone(); - } catch (e) { - err(e); - loadError(); - } - return; - } - - var script = document.createElement('script'); - script.onload = loadDone; - script.onerror = loadError; - script.src = url; - document.body.appendChild(script); - }; - _emscripten_async_load_script.sig = 'vppp'; - - var _emscripten_get_window_title = () => { - var buflen = 256; - - if (!_emscripten_get_window_title.buffer) { - _emscripten_get_window_title.buffer = _malloc(buflen); - } - - stringToUTF8( - document.title, - _emscripten_get_window_title.buffer, - buflen - ); - - return _emscripten_get_window_title.buffer; - }; - _emscripten_get_window_title.sig = 'p'; - - var _emscripten_set_window_title = (title) => - (document.title = UTF8ToString(title)); - _emscripten_set_window_title.sig = 'vp'; - - var _emscripten_get_screen_size = (width, height) => { - HEAP32[width >> 2] = screen.width; - HEAP32[height >> 2] = screen.height; - }; - _emscripten_get_screen_size.sig = 'vpp'; - - var _emscripten_hide_mouse = () => { - var styleSheet = document.styleSheets[0]; - var rules = styleSheet.cssRules; - for (var i = 0; i < rules.length; i++) { - if (rules[i].cssText.startsWith('canvas')) { - styleSheet.deleteRule(i); - i--; - } - } - styleSheet.insertRule( - 'canvas.emscripten { border: 1px solid black; cursor: none; }', - 0 - ); - }; - _emscripten_hide_mouse.sig = 'v'; - - var _emscripten_set_canvas_size = (width, height) => - Browser.setCanvasSize(width, height); - _emscripten_set_canvas_size.sig = 'vii'; - - var _emscripten_get_canvas_size = (width, height, isFullscreen) => { - var canvas = Browser.getCanvas(); - HEAP32[width >> 2] = canvas.width; - HEAP32[height >> 2] = canvas.height; - HEAP32[isFullscreen >> 2] = Browser.isFullscreen ? 1 : 0; - }; - _emscripten_get_canvas_size.sig = 'vppp'; - - var _emscripten_create_worker = (url) => { - url = UTF8ToString(url); - var id = Browser.workers.length; - var info = { - worker: new Worker(url), - callbacks: [], - awaited: 0, - buffer: 0, - }; - info.worker.onmessage = function info_worker_onmessage(msg) { - if (ABORT) return; - var info = Browser.workers[id]; - if (!info) return; // worker was destroyed meanwhile - var callbackId = msg.data['callbackId']; - var callbackInfo = info.callbacks[callbackId]; - if (!callbackInfo) return; // no callback or callback removed meanwhile - // Don't trash our callback state if we expect additional calls. - if (msg.data['finalResponse']) { - info.awaited--; - info.callbacks[callbackId] = null; // TODO: reuse callbackIds, compress this - runtimeKeepalivePop(); - } - var data = msg.data['data']; - if (data) { - if (!data.byteLength) data = new Uint8Array(data); - info.buffer = _realloc(info.buffer, data.length); - HEAPU8.set(data, info.buffer); - callbackInfo.func(info.buffer, data.length, callbackInfo.arg); - } else { - callbackInfo.func(0, 0, callbackInfo.arg); - } - }; - Browser.workers.push(info); - return id; - }; - _emscripten_create_worker.sig = 'ip'; - - var _emscripten_destroy_worker = (id) => { - var info = Browser.workers[id]; - info.worker.terminate(); - _free(info.buffer); - Browser.workers[id] = null; - }; - _emscripten_destroy_worker.sig = 'vi'; - - var _emscripten_call_worker = (id, funcName, data, size, callback, arg) => { - funcName = UTF8ToString(funcName); - var info = Browser.workers[id]; - var callbackId = -1; - if (callback) { - // If we are waiting for a response from the worker we need to keep - // the runtime alive at least long enough to receive it. - // The corresponding runtimeKeepalivePop is in the `finalResponse` - // handler above. - runtimeKeepalivePush(); - callbackId = info.callbacks.length; - info.callbacks.push({ - func: ( - a1, - a2, - a3 - ) => {} /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */, - arg, - }); - info.awaited++; - } - var transferObject = { - funcName: funcName, - callbackId: callbackId, - data: data ? new Uint8Array(HEAPU8.subarray(data, data + size)) : 0, - }; - if (data) { - info.worker.postMessage(transferObject, [ - transferObject.data.buffer, - ]); - } else { - info.worker.postMessage(transferObject); - } - }; - _emscripten_call_worker.sig = 'vippipp'; - - var _emscripten_get_worker_queue_size = (id) => { - var info = Browser.workers[id]; - if (!info) return -1; - return info.awaited; - }; - _emscripten_get_worker_queue_size.sig = 'ii'; - - var getPreloadedImageData = (path, w, h) => { - path = PATH_FS.resolve(path); - - var canvas = /** @type {HTMLCanvasElement} */ ( - Browser.preloadedImages[path] - ); - if (!canvas) return 0; - - var ctx = canvas.getContext('2d'); - var image = ctx.getImageData(0, 0, canvas.width, canvas.height); - var buf = _malloc(canvas.width * canvas.height * 4); - - HEAPU8.set(image.data, buf); - - HEAP32[w >> 2] = canvas.width; - HEAP32[h >> 2] = canvas.height; - return buf; - }; - - var _emscripten_get_preloaded_image_data = (path, w, h) => - getPreloadedImageData(UTF8ToString(path), w, h); - _emscripten_get_preloaded_image_data.sig = 'pppp'; - - var getPreloadedImageData__data = ['$PATH_FS', 'malloc']; - - var _emscripten_get_preloaded_image_data_from_FILE = (file, w, h) => { - var fd = _fileno(file); - var stream = FS.getStream(fd); - if (stream) { - return getPreloadedImageData(stream.path, w, h); - } - - return 0; - }; - _emscripten_get_preloaded_image_data_from_FILE.sig = 'pppp'; - - var wget = { - wgetRequests: {}, - nextWgetRequestHandle: 0, - getNextWgetRequestHandle() { - var handle = wget.nextWgetRequestHandle; - wget.nextWgetRequestHandle++; - return handle; - }, - }; - - /** - * @param {number=} mode Optionally, the mode to create in. Uses mkdir's - * default if not set. - */ - var FS_mkdirTree = (path, mode) => FS.mkdirTree(path, mode); - - var _emscripten_async_wget = (url, file, onload, onerror) => { - runtimeKeepalivePush(); - - var _url = UTF8ToString(url); - var _file = UTF8ToString(file); - _file = PATH_FS.resolve(_file); - function doCallback(callback) { - if (callback) { - runtimeKeepalivePop(); - callUserCallback(() => - withStackSave(() => - (( - a1 - ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - stringToUTF8OnStack(_file) - ) - ) - ); - } - } - var destinationDirectory = PATH.dirname(_file); - FS_preloadFile( - destinationDirectory, - PATH.basename(_file), - _url, - true, - true, - false, // dontCreateFile - false, // canOwn - () => { - // preFinish - // if a file exists there, we overwrite it - try { - FS_unlink(_file); - } catch (e) {} - // if the destination directory does not yet exist, create it - FS_mkdirTree(destinationDirectory); - } - ) - .then(() => doCallback(onload)) - .catch(() => doCallback(onerror)); - }; - _emscripten_async_wget.sig = 'vpppp'; - - var _emscripten_async_wget_data = async ( - url, - userdata, - onload, - onerror - ) => { - runtimeKeepalivePush(); - /* no need for run dependency, this is async but will not do any prepare etc. step */ - try { - var byteArray = await asyncLoad(UTF8ToString(url)); - runtimeKeepalivePop(); - callUserCallback(() => { - var buffer = _malloc(byteArray.length); - HEAPU8.set(byteArray, buffer); - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - userdata, - buffer, - byteArray.length - ); - _free(buffer); - }); - } catch (e) { - if (onerror) { - runtimeKeepalivePop(); - callUserCallback(() => { - (( - a1 - ) => {}) /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - userdata - ); - }); - } - } - }; - _emscripten_async_wget_data.sig = 'vpppp'; - - var _emscripten_async_wget2 = ( - url, - file, - request, - param, - userdata, - onload, - onerror, - onprogress - ) => { - runtimeKeepalivePush(); - - var _url = UTF8ToString(url); - var _file = UTF8ToString(file); - _file = PATH_FS.resolve(_file); - var _request = UTF8ToString(request); - var _param = UTF8ToString(param); - var index = _file.lastIndexOf('/'); - - var http = new XMLHttpRequest(); - http.open(_request, _url, true); - http.responseType = 'arraybuffer'; - - var handle = wget.getNextWgetRequestHandle(); - - var destinationDirectory = PATH.dirname(_file); - - // LOAD - http.onload = (e) => { - runtimeKeepalivePop(); - if (http.status >= 200 && http.status < 300) { - // if a file exists there, we overwrite it - try { - FS.unlink(_file); - } catch (e) {} - // if the destination directory does not yet exist, create it - FS.mkdirTree(destinationDirectory); - - FS.createDataFile( - _file.slice(0, index), - _file.slice(index + 1), - new Uint8Array(/** @type{ArrayBuffer}*/ (http.response)), - true, - true, - false - ); - if (onload) { - var sp = stackSave(); - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - handle, - userdata, - stringToUTF8OnStack(_file) - ); - stackRestore(sp); - } - } else { - if (onerror) - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - handle, - userdata, - http.status - ); - } - - delete wget.wgetRequests[handle]; - }; - - // ERROR - http.onerror = (e) => { - runtimeKeepalivePop(); - if (onerror) - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - handle, - userdata, - http.status - ); - delete wget.wgetRequests[handle]; - }; - - // PROGRESS - http.onprogress = (e) => { - if ( - e.lengthComputable || - (e.lengthComputable === undefined && e.total != 0) - ) { - var percentComplete = (e.loaded / e.total) * 100; - if (onprogress) - (( - a1, - a2, - a3 - ) => {}) /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - handle, - userdata, - percentComplete - ); - } - }; - - // ABORT - http.onabort = (e) => { - runtimeKeepalivePop(); - delete wget.wgetRequests[handle]; - }; - - if (_request == 'POST') { - //Send the proper header information along with the request - http.setRequestHeader( - 'Content-type', - 'application/x-www-form-urlencoded' - ); - http.send(_param); - } else { - http.send(null); - } - - wget.wgetRequests[handle] = http; - - return handle; - }; - _emscripten_async_wget2.sig = 'ipppppppp'; - - var _emscripten_async_wget2_data = ( - url, - request, - param, - userdata, - free, - onload, - onerror, - onprogress - ) => { - var _url = UTF8ToString(url); - var _request = UTF8ToString(request); - var _param = UTF8ToString(param); - - var http = new XMLHttpRequest(); - http.open(_request, _url, true); - http.responseType = 'arraybuffer'; - - var handle = wget.getNextWgetRequestHandle(); - - function onerrorjs() { - if (onerror) { - var sp = stackSave(); - var statusText = 0; - if (http.statusText) { - statusText = stringToUTF8OnStack(http.statusText); - } - (( - a1, - a2, - a3, - a4 - ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - handle, - userdata, - http.status, - statusText - ); - stackRestore(sp); - } - } - - // LOAD - http.onload = (e) => { - if ( - (http.status >= 200 && http.status < 300) || - (http.status === 0 && _url.slice(0, 4).toLowerCase() != 'http') - ) { - var byteArray = new Uint8Array( - /** @type{ArrayBuffer} */ (http.response) - ); - var buffer = _malloc(byteArray.length); - HEAPU8.set(byteArray, buffer); - if (onload) - (( - a1, - a2, - a3, - a4 - ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - handle, - userdata, - buffer, - byteArray.length - ); - if (free) _free(buffer); - } else { - onerrorjs(); - } - delete wget.wgetRequests[handle]; - }; - - // ERROR - http.onerror = (e) => { - onerrorjs(); - delete wget.wgetRequests[handle]; - }; - - // PROGRESS - http.onprogress = (e) => { - if (onprogress) - (( - a1, - a2, - a3, - a4 - ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - handle, - userdata, - e.loaded, - e.lengthComputable || e.lengthComputable === undefined - ? e.total - : 0 - ); - }; - - // ABORT - http.onabort = (e) => { - delete wget.wgetRequests[handle]; - }; - - if (_request == 'POST') { - //Send the proper header information along with the request - http.setRequestHeader( - 'Content-type', - 'application/x-www-form-urlencoded' - ); - http.send(_param); - } else { - http.send(null); - } - - wget.wgetRequests[handle] = http; - - return handle; - }; - _emscripten_async_wget2_data.sig = 'ippppippp'; - - var _emscripten_async_wget2_abort = (handle) => { - var http = wget.wgetRequests[handle]; - http?.abort(); - }; - _emscripten_async_wget2_abort.sig = 'vi'; - - var ___asctime_r = (tmPtr, buf) => { - var date = { - tm_sec: HEAP32[tmPtr >> 2], - tm_min: HEAP32[(tmPtr + 4) >> 2], - tm_hour: HEAP32[(tmPtr + 8) >> 2], - tm_mday: HEAP32[(tmPtr + 12) >> 2], - tm_mon: HEAP32[(tmPtr + 16) >> 2], - tm_year: HEAP32[(tmPtr + 20) >> 2], - tm_wday: HEAP32[(tmPtr + 24) >> 2], - }; - var days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; - var months = [ - 'Jan', - 'Feb', - 'Mar', - 'Apr', - 'May', - 'Jun', - 'Jul', - 'Aug', - 'Sep', - 'Oct', - 'Nov', - 'Dec', - ]; - var s = - days[date.tm_wday] + - ' ' + - months[date.tm_mon] + - (date.tm_mday < 10 ? ' ' : ' ') + - date.tm_mday + - (date.tm_hour < 10 ? ' 0' : ' ') + - date.tm_hour + - (date.tm_min < 10 ? ':0' : ':') + - date.tm_min + - (date.tm_sec < 10 ? ':0' : ':') + - date.tm_sec + - ' ' + - (1900 + date.tm_year) + - '\n'; - - // asctime_r is specced to behave in an undefined manner if the algorithm would attempt - // to write out more than 26 bytes (including the null terminator). - // See http://pubs.opengroup.org/onlinepubs/9699919799/functions/asctime.html - // Our undefined behavior is to truncate the write to at most 26 bytes, including null terminator. - stringToUTF8(s, buf, 26); - return buf; - }; - ___asctime_r.sig = 'ppp'; - - var _strptime_l = (buf, format, tm, locale) => _strptime(buf, format, tm); - _strptime_l.sig = 'ppppp'; - - function ___syscall_shutdown(fd, how) { - try { - getSocketFromFD(fd); - return -52; // unsupported feature - } catch (e) { - if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; - return -e.errno; - } + class ExitStatus { + name = 'ExitStatus'; + constructor(status) { + this.message = `Program terminated with exit(${status})`; + this.status = status; + } + } +ExitStatus = class PHPExitStatus extends Error { + constructor(status) { + super(status); + this.name = 'ExitStatus'; + this.message = 'Program terminated with exit(' + status + ')'; + this.status = status; } - ___syscall_shutdown.sig = 'iiiiiii'; - - var __dlsym_catchup_js = (handle, symbolIndex) => { - var lib = LDSO.loadedLibsByHandle[handle]; - var symDict = lib.exports; - var symName = Object.keys(symDict)[symbolIndex]; - var sym = symDict[symName]; - var result = addFunction(sym, sym.sig); - return result; - }; - __dlsym_catchup_js.sig = 'ppi'; - - var FS_readFile = (...args) => FS.readFile(...args); - - var FS_root = (...args) => FS.root(...args); - - var FS_mounts = (...args) => FS.mounts(...args); - - var FS_devices = (...args) => FS.devices(...args); - - var FS_streams = (...args) => FS.streams(...args); - - var FS_nextInode = (...args) => FS.nextInode(...args); - - var FS_nameTable = (...args) => FS.nameTable(...args); - - var FS_currentPath = (...args) => FS.currentPath(...args); - - var FS_initialized = (...args) => FS.initialized(...args); - - var FS_ignorePermissions = (...args) => FS.ignorePermissions(...args); - - var FS_filesystems = (...args) => FS.filesystems(...args); - - var FS_syncFSRequests = (...args) => FS.syncFSRequests(...args); - - var FS_readFiles = (...args) => FS.readFiles(...args); - - var FS_lookupPath = (...args) => FS.lookupPath(...args); - - var FS_getPath = (...args) => FS.getPath(...args); - - var FS_hashName = (...args) => FS.hashName(...args); - - var FS_hashAddNode = (...args) => FS.hashAddNode(...args); - - var FS_hashRemoveNode = (...args) => FS.hashRemoveNode(...args); - - var FS_lookupNode = (...args) => FS.lookupNode(...args); - - var FS_createNode = (...args) => FS.createNode(...args); - - var FS_destroyNode = (...args) => FS.destroyNode(...args); - - var FS_isRoot = (...args) => FS.isRoot(...args); - - var FS_isMountpoint = (...args) => FS.isMountpoint(...args); - - var FS_isFile = (...args) => FS.isFile(...args); - - var FS_isDir = (...args) => FS.isDir(...args); - - var FS_isLink = (...args) => FS.isLink(...args); - - var FS_isChrdev = (...args) => FS.isChrdev(...args); - - var FS_isBlkdev = (...args) => FS.isBlkdev(...args); - - var FS_isFIFO = (...args) => FS.isFIFO(...args); - - var FS_isSocket = (...args) => FS.isSocket(...args); - - var FS_flagsToPermissionString = (...args) => - FS.flagsToPermissionString(...args); - - var FS_nodePermissions = (...args) => FS.nodePermissions(...args); - - var FS_mayLookup = (...args) => FS.mayLookup(...args); - - var FS_mayCreate = (...args) => FS.mayCreate(...args); - - var FS_mayDelete = (...args) => FS.mayDelete(...args); - - var FS_mayOpen = (...args) => FS.mayOpen(...args); - - var FS_checkOpExists = (...args) => FS.checkOpExists(...args); - - var FS_nextfd = (...args) => FS.nextfd(...args); - - var FS_getStreamChecked = (...args) => FS.getStreamChecked(...args); - - var FS_getStream = (...args) => FS.getStream(...args); - - var FS_createStream = (...args) => FS.createStream(...args); - - var FS_closeStream = (...args) => FS.closeStream(...args); - - var FS_dupStream = (...args) => FS.dupStream(...args); - - var FS_doSetAttr = (...args) => FS.doSetAttr(...args); - - var FS_chrdev_stream_ops = (...args) => FS.chrdev_stream_ops(...args); - - var FS_major = (...args) => FS.major(...args); - - var FS_minor = (...args) => FS.minor(...args); - - var FS_makedev = (...args) => FS.makedev(...args); - - var FS_registerDevice = (...args) => FS.registerDevice(...args); - - var FS_getDevice = (...args) => FS.getDevice(...args); - - var FS_getMounts = (...args) => FS.getMounts(...args); - - var FS_syncfs = (...args) => FS.syncfs(...args); - - var FS_mount = (...args) => FS.mount(...args); - - var FS_unmount = (...args) => FS.unmount(...args); - - var FS_lookup = (...args) => FS.lookup(...args); - - var FS_mknod = (...args) => FS.mknod(...args); - - var FS_statfs = (...args) => FS.statfs(...args); - - var FS_statfsStream = (...args) => FS.statfsStream(...args); - - var FS_statfsNode = (...args) => FS.statfsNode(...args); - - var FS_create = (...args) => FS.create(...args); - - var FS_mkdir = (...args) => FS.mkdir(...args); - - var FS_mkdev = (...args) => FS.mkdev(...args); - - var FS_symlink = (...args) => FS.symlink(...args); - - var FS_rename = (...args) => FS.rename(...args); - - var FS_rmdir = (...args) => FS.rmdir(...args); - - var FS_readdir = (...args) => FS.readdir(...args); - - var FS_readlink = (...args) => FS.readlink(...args); - - var FS_stat = (...args) => FS.stat(...args); - - var FS_fstat = (...args) => FS.fstat(...args); - - var FS_lstat = (...args) => FS.lstat(...args); - - var FS_doChmod = (...args) => FS.doChmod(...args); - - var FS_chmod = (...args) => FS.chmod(...args); - - var FS_lchmod = (...args) => FS.lchmod(...args); - - var FS_fchmod = (...args) => FS.fchmod(...args); - - var FS_doChown = (...args) => FS.doChown(...args); - - var FS_chown = (...args) => FS.chown(...args); - - var FS_lchown = (...args) => FS.lchown(...args); - - var FS_fchown = (...args) => FS.fchown(...args); - - var FS_doTruncate = (...args) => FS.doTruncate(...args); - - var FS_truncate = (...args) => FS.truncate(...args); - - var FS_ftruncate = (...args) => FS.ftruncate(...args); - - var FS_utime = (...args) => FS.utime(...args); - - var FS_open = (...args) => FS.open(...args); - - var FS_close = (...args) => FS.close(...args); - - var FS_isClosed = (...args) => FS.isClosed(...args); - - var FS_llseek = (...args) => FS.llseek(...args); - - var FS_read = (...args) => FS.read(...args); - - var FS_write = (...args) => FS.write(...args); - - var FS_mmap = (...args) => FS.mmap(...args); - - var FS_msync = (...args) => FS.msync(...args); - - var FS_ioctl = (...args) => FS.ioctl(...args); - - var FS_writeFile = (...args) => FS.writeFile(...args); - - var FS_cwd = (...args) => FS.cwd(...args); - - var FS_chdir = (...args) => FS.chdir(...args); - - var FS_createDefaultDirectories = (...args) => - FS.createDefaultDirectories(...args); - - var FS_createDefaultDevices = (...args) => FS.createDefaultDevices(...args); - - var FS_createSpecialDirectories = (...args) => - FS.createSpecialDirectories(...args); - - var FS_createStandardStreams = (...args) => - FS.createStandardStreams(...args); - - var FS_staticInit = (...args) => FS.staticInit(...args); - - var FS_init = (...args) => FS.init(...args); - - var FS_quit = (...args) => FS.quit(...args); - - var FS_findObject = (...args) => FS.findObject(...args); - - var FS_analyzePath = (...args) => FS.analyzePath(...args); - - var FS_createFile = (...args) => FS.createFile(...args); - - var FS_forceLoadFile = (...args) => FS.forceLoadFile(...args); - - var _setNetworkCallback = (event, userData, callback) => { - function _callback(data) { - callUserCallback(() => { - if (event === 'error') { - withStackSave(() => { - var msg = stringToUTF8OnStack(data[2]); - (( - a1, - a2, - a3, - a4 - ) => {}) /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - data[0], - data[1], - msg, - userData - ); - }); - } else { - (( - a1, - a2 - ) => {}) /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */( - data, - userData - ); - } - }); - } - - // FIXME(sbc): This has no corresponding Pop so will currently keep the - // runtime alive indefinitely. - runtimeKeepalivePush(); - SOCKFS.on(event, callback ? _callback : null); - }; - - var _emscripten_set_socket_error_callback = (userData, callback) => - _setNetworkCallback('error', userData, callback); - _emscripten_set_socket_error_callback.sig = 'vpp'; - - var _emscripten_set_socket_open_callback = (userData, callback) => - _setNetworkCallback('open', userData, callback); - _emscripten_set_socket_open_callback.sig = 'vpp'; - - var _emscripten_set_socket_listen_callback = (userData, callback) => - _setNetworkCallback('listen', userData, callback); - _emscripten_set_socket_listen_callback.sig = 'vpp'; - - var _emscripten_set_socket_connection_callback = (userData, callback) => - _setNetworkCallback('connection', userData, callback); - _emscripten_set_socket_connection_callback.sig = 'vpp'; +}; + + var GOT = { + }; + + var currentModuleWeakSymbols = new Set(["__start___llvm_prf_data","__stop___llvm_prf_data","__start___llvm_prf_names","__stop___llvm_prf_names","__start___llvm_prf_vns","__stop___llvm_prf_vns","__start___llvm_prf_vtab","__stop___llvm_prf_vtab","__start___llvm_prf_cnts","__stop___llvm_prf_cnts","__start___llvm_prf_bits","__stop___llvm_prf_bits","__start___llvm_prf_vnds","__stop___llvm_prf_vnds"]); + var GOTHandler = { + get(obj, symName) { + var rtn = GOT[symName]; + if (!rtn) { + rtn = GOT[symName] = new WebAssembly.Global({'value': 'i32', 'mutable': true}, -1); + } + if (!currentModuleWeakSymbols.has(symName)) { + // Any non-weak reference to a symbol marks it as `required`, which + // enabled `reportUndefinedSymbols` to report undefined symbol errors + // correctly. + rtn.required = true; + } + return rtn; + }, + }; + + var callRuntimeCallbacks = (callbacks) => { + while (callbacks.length > 0) { + // Pass the module as the first argument. + callbacks.shift()(Module); + } + }; + var onPostRuns = []; + var addOnPostRun = (cb) => onPostRuns.push(cb); + + var onPreRuns = []; + var addOnPreRun = (cb) => onPreRuns.push(cb); + + var runDependencies = 0; + + + var dependenciesFulfilled = null; + var removeRunDependency = (id) => { + runDependencies--; + + Module['monitorRunDependencies']?.(runDependencies); + + if (runDependencies == 0) { + if (dependenciesFulfilled) { + var callback = dependenciesFulfilled; + dependenciesFulfilled = null; + callback(); // can add another dependenciesFulfilled + } + } + }; + var addRunDependency = (id) => { + runDependencies++; + + Module['monitorRunDependencies']?.(runDependencies); + + }; + + + var dynCalls = { + }; + var dynCallLegacy = (sig, ptr, args) => { + sig = sig.replace(/p/g, 'i') + var f = dynCalls[sig]; + return f(ptr, ...args); + }; + var dynCall = (sig, ptr, args = [], promising = false) => { + var rtn = dynCallLegacy(sig, ptr, args); + + function convert(rtn) { + return rtn; + } + + return convert(rtn); + }; + + var UTF8Decoder = globalThis.TextDecoder && new TextDecoder(); + + var findStringEnd = (heapOrArray, idx, maxBytesToRead, ignoreNul) => { + var maxIdx = idx + maxBytesToRead; + if (ignoreNul) return maxIdx; + // TextDecoder needs to know the byte length in advance, it doesn't stop on + // null terminator by itself. + // As a tiny code save trick, compare idx against maxIdx using a negation, + // so that maxBytesToRead=undefined/NaN means Infinity. + while (heapOrArray[idx] && !(idx >= maxIdx)) ++idx; + return idx; + }; + + /** + * Given a pointer 'idx' to a null-terminated UTF8-encoded string in the given + * array that contains uint8 values, returns a copy of that string as a + * Javascript String object. + * heapOrArray is either a regular array, or a JavaScript typed array view. + * @param {number=} idx + * @param {number=} maxBytesToRead + * @param {boolean=} ignoreNul - If true, the function will not stop on a NUL character. + * @return {string} + */ + var UTF8ArrayToString = (heapOrArray, idx = 0, maxBytesToRead, ignoreNul) => { + + var endPtr = findStringEnd(heapOrArray, idx, maxBytesToRead, ignoreNul); + + // When using conditional TextDecoder, skip it for short strings as the overhead of the native call is not worth it. + if (endPtr - idx > 16 && heapOrArray.buffer && UTF8Decoder) { + return UTF8Decoder.decode(heapOrArray.subarray(idx, endPtr)); + } + var str = ''; + while (idx < endPtr) { + // For UTF8 byte structure, see: + // http://en.wikipedia.org/wiki/UTF-8#Description + // https://www.ietf.org/rfc/rfc2279.txt + // https://tools.ietf.org/html/rfc3629 + var u0 = heapOrArray[idx++]; + if (!(u0 & 0x80)) { str += String.fromCharCode(u0); continue; } + var u1 = heapOrArray[idx++] & 63; + if ((u0 & 0xE0) == 0xC0) { str += String.fromCharCode(((u0 & 31) << 6) | u1); continue; } + var u2 = heapOrArray[idx++] & 63; + if ((u0 & 0xF0) == 0xE0) { + u0 = ((u0 & 15) << 12) | (u1 << 6) | u2; + } else { + u0 = ((u0 & 7) << 18) | (u1 << 12) | (u2 << 6) | (heapOrArray[idx++] & 63); + } + + if (u0 < 0x10000) { + str += String.fromCharCode(u0); + } else { + var ch = u0 - 0x10000; + str += String.fromCharCode(0xD800 | (ch >> 10), 0xDC00 | (ch & 0x3FF)); + } + } + return str; + }; + var getDylinkMetadata = (binary) => { + var offset = 0; + var end = 0; + + function getU8() { + return binary[offset++]; + } + + function getLEB() { + var ret = 0; + var mul = 1; + while (1) { + var byte = binary[offset++]; + ret += ((byte & 0x7f) * mul); + mul *= 0x80; + if (!(byte & 0x80)) break; + } + return ret; + } + + function getString() { + var len = getLEB(); + offset += len; + return UTF8ArrayToString(binary, offset - len, len); + } + + function getStringList() { + var count = getLEB(); + var rtn = [] + while (count--) rtn.push(getString()); + return rtn; + } + + /** @param {string=} message */ + function failIf(condition, message) { + if (condition) throw new Error(message); + } + + if (binary instanceof WebAssembly.Module) { + var dylinkSection = WebAssembly.Module.customSections(binary, 'dylink.0'); + failIf(dylinkSection.length === 0, 'need dylink section'); + binary = new Uint8Array(dylinkSection[0]); + end = binary.length + } else { + var int32View = new Uint32Array(new Uint8Array(binary.subarray(0, 24)).buffer); + var magicNumberFound = int32View[0] == 0x6d736100; + failIf(!magicNumberFound, 'need to see wasm magic number'); // \0asm + // we should see the dylink custom section right after the magic number and wasm version + failIf(binary[8] !== 0, 'need the dylink section to be first') + offset = 9; + var section_size = getLEB(); //section size + end = offset + section_size; + var name = getString(); + failIf(name !== 'dylink.0'); + } + + var customSection = { neededDynlibs: [], tlsExports: new Set(), weakImports: new Set(), runtimePaths: [] }; + var WASM_DYLINK_MEM_INFO = 0x1; + var WASM_DYLINK_NEEDED = 0x2; + var WASM_DYLINK_EXPORT_INFO = 0x3; + var WASM_DYLINK_IMPORT_INFO = 0x4; + var WASM_DYLINK_RUNTIME_PATH = 0x5; + var WASM_SYMBOL_TLS = 0x100; + var WASM_SYMBOL_BINDING_MASK = 0x3; + var WASM_SYMBOL_BINDING_WEAK = 0x1; + while (offset < end) { + var subsectionType = getU8(); + var subsectionSize = getLEB(); + if (subsectionType === WASM_DYLINK_MEM_INFO) { + customSection.memorySize = getLEB(); + customSection.memoryAlign = getLEB(); + customSection.tableSize = getLEB(); + customSection.tableAlign = getLEB(); + } else if (subsectionType === WASM_DYLINK_NEEDED) { + customSection.neededDynlibs = getStringList(); + } else if (subsectionType === WASM_DYLINK_EXPORT_INFO) { + var count = getLEB(); + while (count--) { + var symname = getString(); + var flags = getLEB(); + if (flags & WASM_SYMBOL_TLS) { + customSection.tlsExports.add(symname); + } + } + } else if (subsectionType === WASM_DYLINK_IMPORT_INFO) { + var count = getLEB(); + while (count--) { + var modname = getString(); + var symname = getString(); + var flags = getLEB(); + if ((flags & WASM_SYMBOL_BINDING_MASK) == WASM_SYMBOL_BINDING_WEAK) { + customSection.weakImports.add(symname); + } + } + } else if (subsectionType === WASM_DYLINK_RUNTIME_PATH) { + customSection.runtimePaths = getStringList(); + } else { + // unknown subsection + offset += subsectionSize; + } + } + + return customSection; + }; + + + /** + * @param {number} ptr + * @param {string} type + */ + function getValue(ptr, type = 'i8') { + if (type.endsWith('*')) type = '*'; + switch (type) { + case 'i1': return HEAP8[ptr]; + case 'i8': return HEAP8[ptr]; + case 'i16': return HEAP16[((ptr)>>1)]; + case 'i32': return HEAP32[((ptr)>>2)]; + case 'i64': return HEAP64[((ptr)>>3)]; + case 'float': return HEAPF32[((ptr)>>2)]; + case 'double': return HEAPF64[((ptr)>>3)]; + case '*': return HEAPU32[((ptr)>>2)]; + default: abort(`invalid type for getValue: ${type}`); + } + } + + var newDSO = (name, handle, syms) => { + var dso = { + refcount: Infinity, + name, + exports: syms, + global: true, + }; + LDSO.loadedLibsByName[name] = dso; + if (handle != undefined) { + LDSO.loadedLibsByHandle[handle] = dso; + } + return dso; + }; + var LDSO = { + loadedLibsByName:{ + }, + loadedLibsByHandle:{ + }, + init() { + newDSO('__main__', 0, wasmImports); + }, + }; + + + + + + var alignMemory = (size, alignment) => { + return Math.ceil(size / alignment) * alignment; + }; + + var getMemory = (size) => { + // After the runtime is initialized, we must only use sbrk() normally. + if (runtimeInitialized) { + // Currently we don't support freeing of static data when modules are + // unloaded via dlclose. This function is tagged as `noleakcheck` to + // avoid having this reported as leak. + return _calloc(size, 1); + } + var ret = ___heap_base; + // Keep __heap_base stack aligned. + var end = ret + alignMemory(size, 16); + ___heap_base = end; + + // After allocating the memory from the start of the heap we need to ensure + // that once the program starts it doesn't use this region. In relocatable + // mode we can just update the __heap_base symbol that we are exporting to + // the main module. + // When not relocatable `__heap_base` is fixed and exported by the main + // module, but we can update the `sbrk_ptr` value instead. We call + // `_emscripten_get_sbrk_ptr` knowing that it is safe to call prior to + // runtime initialization (unlike, the higher level sbrk function) + var sbrk_ptr = _emscripten_get_sbrk_ptr(); + HEAPU32[((sbrk_ptr)>>2)] = end + return ret; + }; + + + var isInternalSym = (symName) => { + // TODO: find a way to mark these in the binary or avoid exporting them. + return [ + 'memory', + '__memory_base', + '__table_base', + '__stack_pointer', + '__indirect_function_table', + '__cpp_exception', + '__c_longjmp', + '__wasm_apply_data_relocs', + '__dso_handle', + '__tls_size', + '__tls_align', + '__set_stack_limits', + '_emscripten_tls_init', + '__wasm_init_tls', + '__wasm_call_ctors', + '__start_em_asm', + '__stop_em_asm', + '__start_em_js', + '__stop_em_js', + ].includes(symName) || symName.startsWith('__em_js__') + ; + }; + + var wasmTableMirror = []; + + + var getWasmTableEntry = (funcPtr) => { + var func = wasmTableMirror[funcPtr]; + if (!func) { + /** @suppress {checkTypes} */ + wasmTableMirror[funcPtr] = func = wasmTable.get(funcPtr); + } + return func; + }; + + var updateTableMap = (offset, count) => { + if (functionsInTableMap) { + for (var i = offset; i < offset + count; i++) { + var item = getWasmTableEntry(i); + // Ignore null values. + if (item) { + functionsInTableMap.set(item, i); + } + } + } + }; + + var functionsInTableMap; + + var getFunctionAddress = (func) => { + // First, create the map if this is the first use. + if (!functionsInTableMap) { + functionsInTableMap = new WeakMap(); + updateTableMap(0, wasmTable.length); + } + return functionsInTableMap.get(func) || 0; + }; + + + var freeTableIndexes = []; + + var getEmptyTableSlot = () => { + // Reuse a free index if there is one, otherwise grow. + if (freeTableIndexes.length) { + return freeTableIndexes.pop(); + } + // Grow the table + return wasmTable['grow'](1); + }; + + + var setWasmTableEntry = (idx, func) => { + /** @suppress {checkTypes} */ + wasmTable.set(idx, func); + // With ABORT_ON_WASM_EXCEPTIONS wasmTable.get is overridden to return wrapped + // functions so we need to call it here to retrieve the potential wrapper correctly + // instead of just storing 'func' directly into wasmTableMirror + /** @suppress {checkTypes} */ + wasmTableMirror[idx] = wasmTable.get(idx); + }; + + var uleb128EncodeWithLen = (arr) => { + const n = arr.length; + // Note: this LEB128 length encoding produces extra byte for n < 128, + // but we don't care as it's only used in a temporary representation. + return [(n % 128) | 128, n >> 7, ...arr]; + }; + + + var wasmTypeCodes = { + 'i': 0x7f, // i32 + 'p': 0x7f, // i32 + 'j': 0x7e, // i64 + 'f': 0x7d, // f32 + 'd': 0x7c, // f64 + 'e': 0x6f, // externref + }; + var generateTypePack = (types) => uleb128EncodeWithLen(Array.from(types, (type) => { + var code = wasmTypeCodes[type]; + return code; + })); + var convertJsFunctionToWasm = (func, sig) => { + + // Rest of the module is static + var bytes = Uint8Array.of( + 0x00, 0x61, 0x73, 0x6d, // magic ("\0asm") + 0x01, 0x00, 0x00, 0x00, // version: 1 + 0x01, // Type section code + // The module is static, with the exception of the type section, which is + // generated based on the signature passed in. + ...uleb128EncodeWithLen([ + 0x01, // count: 1 + 0x60 /* form: func */, + // param types + ...generateTypePack(sig.slice(1)), + // return types (for now only supporting [] if `void` and single [T] otherwise) + ...generateTypePack(sig[0] === 'v' ? '' : sig[0]) + ]), + // The rest of the module is static + 0x02, 0x07, // import section + // (import "e" "f" (func 0 (type 0))) + 0x01, 0x01, 0x65, 0x01, 0x66, 0x00, 0x00, + 0x07, 0x05, // export section + // (export "f" (func 0 (type 0))) + 0x01, 0x01, 0x66, 0x00, 0x00, + ); + + // We can compile this wasm module synchronously because it is very small. + // This accepts an import (at "e.f"), that it reroutes to an export (at "f") + var module = new WebAssembly.Module(bytes); + var instance = new WebAssembly.Instance(module, { 'e': { 'f': func } }); + var wrappedFunc = instance.exports['f']; + return wrappedFunc; + }; + /** @param {string=} sig */ + var addFunction = (func, sig) => { + // Check if the function is already in the table, to ensure each function + // gets a unique index. + var rtn = getFunctionAddress(func); + if (rtn) { + return rtn; + } + + // It's not in the table, add it now. + + var ret = getEmptyTableSlot(); + + // Set the new value. + try { + // Attempting to call this with JS function will cause of table.set() to fail + setWasmTableEntry(ret, func); + } catch (err) { + if (!(err instanceof TypeError)) { + throw err; + } + var wrapped = convertJsFunctionToWasm(func, sig); + setWasmTableEntry(ret, wrapped); + } + + functionsInTableMap.set(func, ret); + + return ret; + }; + /** @param {boolean=} replace */ + var updateGOT = (exports, replace) => { + for (var symName in exports) { + if (isInternalSym(symName)) { + continue; + } + + var value = exports[symName]; + + var existingEntry = GOT[symName] && GOT[symName].value != -1; + if (replace || !existingEntry) { + var newValue; + if (typeof value == 'function') { + newValue = addFunction(value); + } else if (typeof value == 'number') { + newValue = value; + } else { + // The GOT can only contain addresses (i.e data addresses or function + // addresses so we currently ignore other types export here. + continue; + } + GOT[symName] ??= new WebAssembly.Global({'value': 'i32', 'mutable': true}); + GOT[symName].value = newValue; + } + } + }; + + var isImmutableGlobal = (val) => { + if (val instanceof WebAssembly.Global) { + try { + val.value = val.value; + } catch { + return true; + } + } + return false; + }; + var relocateExports = (exports, memoryBase = 0) => { + + function relocateExport(name, value) { + // Detect immuable wasm global exports. These represent data addresses + // which are relative to `memoryBase` + if (isImmutableGlobal(value)) { + return value.value + memoryBase; + } + + // Return unmodified value (no relocation required). + return value; + } + + var relocated = {}; + for (var e in exports) { + relocated[e] = relocateExport(e, exports[e]) + } + return relocated; + }; + + var isSymbolDefined = (symName) => { + // Ignore 'stub' symbols that are auto-generated as part of the original + // `wasmImports` used to instantiate the main module. + var existing = wasmImports[symName]; + if (!existing || existing.stub) { + return false; + } + // Even if a symbol exists in wasmImports, and is not itself a stub, it + // could be an ASYNCIFY wrapper function that wraps a stub function. + if (symName in asyncifyStubs && !asyncifyStubs[symName]) { + return false; + } + return true; + }; + + var createNamedFunction = (name, func) => Object.defineProperty(func, 'name', { value: name }); + + + + var stackSave = () => _emscripten_stack_get_current(); + + var stackRestore = (val) => __emscripten_stack_restore(val); + var createInvokeFunction = (sig) => (ptr, ...args) => { + var sp = stackSave(); + try { + return dynCall(sig, ptr, args); + } catch(e) { + stackRestore(sp); + // Create a try-catch guard that rethrows the Emscripten EH exception. + // Exceptions thrown from C++ will be a pointer (number) and longjmp + // will throw the number Infinity. Use the compact and fast "e !== e+0" + // test to check if e was not a Number. + if (e !== e+0) throw e; + _setThrew(1, 0); + // In theory this if statement could be done on + // creating the function, but I just added this to + // save wasting code space as it only happens on exception. + if (sig[0] == "j") return 0n; + } + }; + var resolveGlobalSymbol = (symName, direct = false) => { + var sym; + if (isSymbolDefined(symName)) { + sym = wasmImports[symName]; + } + // Asm.js-style exception handling: invoke wrapper generation + else if (symName.startsWith('invoke_')) { + // Create (and cache) new invoke_ functions on demand. + sym = wasmImports[symName] = createNamedFunction(symName, createInvokeFunction(symName.split('_')[1])); + } + return {sym, name: symName}; + }; + + + + + + + + var onPostCtors = []; + var addOnPostCtor = (cb) => onPostCtors.push(cb); + + + /** + * Given a pointer 'ptr' to a null-terminated UTF8-encoded string in the + * emscripten HEAP, returns a copy of that string as a Javascript String object. + * + * @param {number} ptr + * @param {number=} maxBytesToRead - An optional length that specifies the + * maximum number of bytes to read. You can omit this parameter to scan the + * string until the first 0 byte. If maxBytesToRead is passed, and the string + * at [ptr, ptr+maxBytesToReadr[ contains a null byte in the middle, then the + * string will cut short at that byte index. + * @param {boolean=} ignoreNul - If true, the function will not stop on a NUL character. + * @return {string} + */ + var UTF8ToString = (ptr, maxBytesToRead, ignoreNul) => { + return ptr ? UTF8ArrayToString(HEAPU8, ptr, maxBytesToRead, ignoreNul) : ''; + }; + + /** + * @param {string=} libName + * @param {Object=} localScope + * @param {number=} handle + */ + var loadWebAssemblyModule = (binary, flags, libName, localScope, handle) => { + var metadata = getDylinkMetadata(binary); + + // loadModule loads the wasm module after all its dependencies have been loaded. + // can be called both sync/async. + function loadModule() { + // alignments are powers of 2 + var memAlign = Math.pow(2, metadata.memoryAlign); + // prepare memory + var memoryBase = metadata.memorySize ? alignMemory(getMemory(metadata.memorySize + memAlign), memAlign) : 0; // TODO: add to cleanups + var tableBase = metadata.tableSize ? wasmTable.length : 0; + if (handle) { + HEAP8[(handle)+(8)] = 1; + HEAPU32[(((handle)+(12))>>2)] = memoryBase; + HEAP32[(((handle)+(16))>>2)] = metadata.memorySize; + HEAPU32[(((handle)+(20))>>2)] = tableBase; + HEAP32[(((handle)+(24))>>2)] = metadata.tableSize; + } + + if (metadata.tableSize) { + wasmTable.grow(metadata.tableSize); + } + + // This is the export map that we ultimately return. We declare it here + // so it can be used within resolveSymbol. We resolve symbols against + // this local symbol map in the case there they are not present on the + // global Module object. We need this fallback because Modules sometime + // need to import their own symbols + var moduleExports; + + function resolveSymbol(sym) { + var resolved = resolveGlobalSymbol(sym).sym; + if (!resolved && localScope) { + resolved = localScope[sym]; + } + if (!resolved) { + resolved = moduleExports[sym]; + } + return resolved; + } + + // TODO kill ↓↓↓ (except "symbols local to this module", it will likely be + // not needed if we require that if A wants symbols from B it has to link + // to B explicitly: similarly to -Wl,--no-undefined) + // + // wasm dynamic libraries are pure wasm, so they cannot assist in + // their own loading. When side module A wants to import something + // provided by a side module B that is loaded later, we need to + // add a layer of indirection, but worse, we can't even tell what + // to add the indirection for, without inspecting what A's imports + // are. To do that here, we use a JS proxy (another option would + // be to inspect the binary directly). + var proxyHandler = { + get(stubs, prop) { + // symbols that should be local to this module + switch (prop) { + case '__memory_base': + return memoryBase; + case '__table_base': + return tableBase; + } + if (prop in wasmImports && !wasmImports[prop].stub) { + // No stub needed, symbol already exists in symbol table + var res = wasmImports[prop]; + // Asyncify wraps exports, and we need to look through those wrappers. + if (res.orig) { + res = res.orig; + } + return res; + } + // Return a stub function that will resolve the symbol + // when first called. + if (!(prop in stubs)) { + var resolved; + stubs[prop] = (...args) => { + resolved ||= resolveSymbol(prop); + return resolved(...args); + }; + } + return stubs[prop]; + } + }; + var proxy = new Proxy({}, proxyHandler); + currentModuleWeakSymbols = metadata.weakImports; + var info = { + 'GOT.mem': new Proxy({}, GOTHandler), + 'GOT.func': new Proxy({}, GOTHandler), + 'env': proxy, + 'wasi_snapshot_preview1': proxy, + }; + + function postInstantiation(module, instance) { + // add new entries to functionsInTableMap + updateTableMap(tableBase, metadata.tableSize); + moduleExports = relocateExports(instance.exports, memoryBase); + updateGOT(moduleExports); + moduleExports = Asyncify.instrumentWasmExports(moduleExports); + if (!flags.allowUndefined) { + reportUndefinedSymbols(); + } + + function addEmAsm(addr, body) { + var args = []; + for (var arity = 0; ; arity++) { + var argName = '$' + arity; + if (!body.includes(argName)) break; + args.push(argName); + } + args = args.join(','); + var func = `(${args}) => { ${body} };`; + ASM_CONSTS[start] = eval(func); + } + + // Add any EM_ASM function that exist in the side module + if ('__start_em_asm' in moduleExports) { + var start = moduleExports['__start_em_asm']; + var stop = moduleExports['__stop_em_asm']; + + + while (start < stop) { + var jsString = UTF8ToString(start); + addEmAsm(start, jsString); + start = HEAPU8.indexOf(0, start) + 1; + } + } + + function addEmJs(name, cSig, body) { + // The signature here is a C signature (e.g. "(int foo, char* bar)"). + // See `create_em_js` in emcc.py` for the build-time version of this + // code. + var jsArgs = []; + cSig = cSig.slice(1, -1) + if (cSig != 'void') { + cSig = cSig.split(','); + for (var arg of cSig) { + var jsArg = arg.split(' ').pop(); + jsArgs.push(jsArg.replace('*', '')); + } + } + var func = `(${jsArgs}) => ${body};`; + moduleExports[name] = eval(func); + } + + for (var name in moduleExports) { + if (name.startsWith('__em_js__')) { + var start = moduleExports[name] + var jsString = UTF8ToString(start); + // EM_JS strings are stored in the data section in the form + // SIG<::>BODY. + var [sig, body] = jsString.split('<::>'); + addEmJs(name.replace('__em_js__', ''), sig, body); + delete moduleExports[name]; + } + } + + // initialize the module + var applyRelocs = moduleExports['__wasm_apply_data_relocs']; + if (applyRelocs) { + if (runtimeInitialized) { + applyRelocs(); + } else { + __RELOC_FUNCS__.push(applyRelocs); + } + } + var init = moduleExports['__wasm_call_ctors']; + if (init) { + if (runtimeInitialized) { + init(); + } else { + // we aren't ready to run compiled code yet + addOnPostCtor(init); + } + } + return moduleExports; + } + + if (flags.loadAsync) { + return (async () => { + var instance; + if (binary instanceof WebAssembly.Module) { + instance = new WebAssembly.Instance(binary, info); + } else { + // Destructuring assignment without declaration has to be wrapped + // with parens or parser will treat the l-value as an object + // literal instead. + ({ module: binary, instance } = await WebAssembly.instantiate(binary, info)); + } + return postInstantiation(binary, instance); + })(); + } + + var module = binary instanceof WebAssembly.Module ? binary : new WebAssembly.Module(binary); + var instance = new WebAssembly.Instance(module, info); + return postInstantiation(module, instance); + } + + // We need to set rpath in flags based on the current library's rpath. + // We can't mutate flags or else if a depends on b and c and b depends on d, + // then c will be loaded with b's rpath instead of a's. + flags = {...flags, rpath: { parentLibPath: libName, paths: metadata.runtimePaths }} + // now load needed libraries and the module itself. + if (flags.loadAsync) { + return metadata.neededDynlibs + .reduce((chain, dynNeeded) => chain.then(() => + loadDynamicLibrary(dynNeeded, flags, localScope) + ), Promise.resolve()) + .then(loadModule); + } + + for (var needed of metadata.neededDynlibs) { + loadDynamicLibrary(needed, flags, localScope) + } + return loadModule(); + }; + + var mergeLibSymbols = (exports, libName) => { + registerDynCallSymbols(exports); + // add symbols into global namespace TODO: weak linking etc. + for (var [sym, exp] of Object.entries(exports)) { + + // When RTLD_GLOBAL is enabled, the symbols defined by this shared object + // will be made available for symbol resolution of subsequently loaded + // shared objects. + // + // We should copy the symbols (which include methods and variables) from + // SIDE_MODULE to MAIN_MODULE. + const setImport = (target) => { + if (target in asyncifyStubs) { + asyncifyStubs[target] = exp; + } + if (!isSymbolDefined(target)) { + wasmImports[target] = exp; + } + } + setImport(sym); + + // Special case for handling of main symbol: If a side module exports + // `main` that also acts a definition for `__main_argc_argv` and vice + // versa. + const main_alias = '__main_argc_argv'; + if (sym == 'main') { + setImport(main_alias) + } + if (sym == main_alias) { + setImport('main') + } + } + }; + + + var asyncLoad = async (url) => { + var arrayBuffer = await readAsync(url); + return new Uint8Array(arrayBuffer); + }; + + var preloadPlugins = []; + var registerWasmPlugin = () => { + // Use string keys here for public methods to avoid minification since the + // plugin consumer also uses string keys. + var wasmPlugin = { + promiseChainEnd: Promise.resolve(), + 'canHandle': (name) => { + return !Module['noWasmDecoding'] && name.endsWith('.so') + }, + 'handle': async (byteArray, name) => + // loadWebAssemblyModule can not load modules out-of-order, so rather + // than just running the promises in parallel, this makes a chain of + // promises to run in series. + wasmPlugin.promiseChainEnd = wasmPlugin.promiseChainEnd.then(async () => { + try { + var exports = await loadWebAssemblyModule(byteArray, {loadAsync: true, nodelete: true}, name, {}); + } catch (error) { + throw new Error(`failed to instantiate wasm: ${name}: ${error}`); + } + preloadedWasm[name] = exports; + return byteArray; + }) + }; + preloadPlugins.push(wasmPlugin); + }; + var preloadedWasm = { + }; + + var PATH = { + isAbs:(path) => path.charAt(0) === '/', + splitPath:(filename) => { + var splitPathRe = /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; + return splitPathRe.exec(filename).slice(1); + }, + normalizeArray:(parts, allowAboveRoot) => { + // if the path tries to go above the root, `up` ends up > 0 + var up = 0; + for (var i = parts.length - 1; i >= 0; i--) { + var last = parts[i]; + if (last === '.') { + parts.splice(i, 1); + } else if (last === '..') { + parts.splice(i, 1); + up++; + } else if (up) { + parts.splice(i, 1); + up--; + } + } + // if the path is allowed to go above the root, restore leading ..s + if (allowAboveRoot) { + for (; up; up--) { + parts.unshift('..'); + } + } + return parts; + }, + normalize:(path) => { + var isAbsolute = PATH.isAbs(path), + trailingSlash = path.slice(-1) === '/'; + // Normalize the path + path = PATH.normalizeArray(path.split('/').filter((p) => !!p), !isAbsolute).join('/'); + if (!path && !isAbsolute) { + path = '.'; + } + if (path && trailingSlash) { + path += '/'; + } + return (isAbsolute ? '/' : '') + path; + }, + dirname:(path) => { + var result = PATH.splitPath(path), + root = result[0], + dir = result[1]; + if (!root && !dir) { + // No dirname whatsoever + return '.'; + } + if (dir) { + // It has a dirname, strip trailing slash + dir = dir.slice(0, -1); + } + return root + dir; + }, + basename:(path) => path && path.match(/([^\/]+|\/)\/*$/)[1], + join:(...paths) => PATH.normalize(paths.join('/')), + join2:(l, r) => PATH.normalize(l + '/' + r), + }; + var replaceORIGIN = (parentLibName, rpath) => { + if (rpath.startsWith('$ORIGIN')) { + // TODO: what to do if we only know the relative path of the file? It will return "." here. + var origin = PATH.dirname(parentLibName); + return rpath.replace('$ORIGIN', origin); + } + + return rpath; + }; + + + + var withStackSave = (f) => { + var stack = stackSave(); + var ret = f(); + stackRestore(stack); + return ret; + }; + + var stackAlloc = (sz) => __emscripten_stack_alloc(sz); + + var lengthBytesUTF8 = (str) => { + var len = 0; + for (var i = 0; i < str.length; ++i) { + // Gotcha: charCodeAt returns a 16-bit word that is a UTF-16 encoded code + // unit, not a Unicode code point of the character! So decode + // UTF16->UTF32->UTF8. + // See http://unicode.org/faq/utf_bom.html#utf16-3 + var c = str.charCodeAt(i); // possibly a lead surrogate + if (c <= 0x7F) { + len++; + } else if (c <= 0x7FF) { + len += 2; + } else if (c >= 0xD800 && c <= 0xDFFF) { + len += 4; ++i; + } else { + len += 3; + } + } + return len; + }; + + + var stringToUTF8Array = (str, heap, outIdx, maxBytesToWrite) => { + // Parameter maxBytesToWrite is not optional. Negative values, 0, null, + // undefined and false each don't write out any bytes. + if (!(maxBytesToWrite > 0)) + return 0; + + var startIdx = outIdx; + var endIdx = outIdx + maxBytesToWrite - 1; // -1 for string null terminator. + for (var i = 0; i < str.length; ++i) { + // For UTF8 byte structure, see http://en.wikipedia.org/wiki/UTF-8#Description + // and https://www.ietf.org/rfc/rfc2279.txt + // and https://tools.ietf.org/html/rfc3629 + var u = str.codePointAt(i); + if (u <= 0x7F) { + if (outIdx >= endIdx) break; + heap[outIdx++] = u; + } else if (u <= 0x7FF) { + if (outIdx + 1 >= endIdx) break; + heap[outIdx++] = 0xC0 | (u >> 6); + heap[outIdx++] = 0x80 | (u & 63); + } else if (u <= 0xFFFF) { + if (outIdx + 2 >= endIdx) break; + heap[outIdx++] = 0xE0 | (u >> 12); + heap[outIdx++] = 0x80 | ((u >> 6) & 63); + heap[outIdx++] = 0x80 | (u & 63); + } else { + if (outIdx + 3 >= endIdx) break; + heap[outIdx++] = 0xF0 | (u >> 18); + heap[outIdx++] = 0x80 | ((u >> 12) & 63); + heap[outIdx++] = 0x80 | ((u >> 6) & 63); + heap[outIdx++] = 0x80 | (u & 63); + // Gotcha: if codePoint is over 0xFFFF, it is represented as a surrogate pair in UTF-16. + // We need to manually skip over the second code unit for correct iteration. + i++; + } + } + // Null-terminate the pointer to the buffer. + heap[outIdx] = 0; + return outIdx - startIdx; + }; + var stringToUTF8 = (str, outPtr, maxBytesToWrite) => { + return stringToUTF8Array(str, HEAPU8, outPtr, maxBytesToWrite); + }; + + var stringToUTF8OnStack = (str) => { + var size = lengthBytesUTF8(str) + 1; + var ret = stackAlloc(size); + stringToUTF8(str, ret, size); + return ret; + }; + + + var initRandomFill = () => { + + return (view) => crypto.getRandomValues(view); + }; + var randomFill = (view) => { + // Lazily init on the first invocation. + (randomFill = initRandomFill())(view); + }; + + + + var PATH_FS = { + resolve:(...args) => { + var resolvedPath = '', + resolvedAbsolute = false; + for (var i = args.length - 1; i >= -1 && !resolvedAbsolute; i--) { + var path = (i >= 0) ? args[i] : FS.cwd(); + // Skip empty and invalid entries + if (typeof path != 'string') { + throw new TypeError('Arguments to path.resolve must be strings'); + } else if (!path) { + return ''; // an invalid portion invalidates the whole thing + } + resolvedPath = path + '/' + resolvedPath; + resolvedAbsolute = PATH.isAbs(path); + } + // At this point the path should be resolved to a full absolute path, but + // handle relative paths to be safe (might happen when process.cwd() fails) + resolvedPath = PATH.normalizeArray(resolvedPath.split('/').filter((p) => !!p), !resolvedAbsolute).join('/'); + return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; + }, + relative:(from, to) => { + from = PATH_FS.resolve(from).slice(1); + to = PATH_FS.resolve(to).slice(1); + function trim(arr) { + var start = 0; + for (; start < arr.length; start++) { + if (arr[start] !== '') break; + } + var end = arr.length - 1; + for (; end >= 0; end--) { + if (arr[end] !== '') break; + } + if (start > end) return []; + return arr.slice(start, end - start + 1); + } + var fromParts = trim(from.split('/')); + var toParts = trim(to.split('/')); + var length = Math.min(fromParts.length, toParts.length); + var samePartsLength = length; + for (var i = 0; i < length; i++) { + if (fromParts[i] !== toParts[i]) { + samePartsLength = i; + break; + } + } + var outputParts = []; + for (var i = samePartsLength; i < fromParts.length; i++) { + outputParts.push('..'); + } + outputParts = outputParts.concat(toParts.slice(samePartsLength)); + return outputParts.join('/'); + }, + }; + + + + var FS_stdin_getChar_buffer = []; + + + /** @type {function(string, boolean=, number=)} */ + var intArrayFromString = (stringy, dontAddNull, length) => { + var len = length > 0 ? length : lengthBytesUTF8(stringy)+1; + var u8array = new Array(len); + var numBytesWritten = stringToUTF8Array(stringy, u8array, 0, u8array.length); + if (dontAddNull) u8array.length = numBytesWritten; + return u8array; + }; + var FS_stdin_getChar = () => { + if (!FS_stdin_getChar_buffer.length) { + var result = null; + if (ENVIRONMENT_IS_NODE) { + // we will read data by chunks of BUFSIZE + var BUFSIZE = 256; + var buf = Buffer.alloc(BUFSIZE); + var bytesRead = 0; + + // For some reason we must suppress a closure warning here, even though + // fd definitely exists on process.stdin, and is even the proper way to + // get the fd of stdin, + // https://github.com/nodejs/help/issues/2136#issuecomment-523649904 + // This started to happen after moving this logic out of library_tty.js, + // so it is related to the surrounding code in some unclear manner. + /** @suppress {missingProperties} */ + var fd = process.stdin.fd; + + try { + bytesRead = fs.readSync(fd, buf, 0, BUFSIZE); + } catch(e) { + // Cross-platform differences: on Windows, reading EOF throws an + // exception, but on other OSes, reading EOF returns 0. Uniformize + // behavior by treating the EOF exception to return 0. + if (e.toString().includes('EOF')) bytesRead = 0; + else throw e; + } + + if (bytesRead > 0) { + result = buf.slice(0, bytesRead).toString('utf-8'); + } + } else + {} + if (!result) { + return null; + } + FS_stdin_getChar_buffer = intArrayFromString(result, true); + } + return FS_stdin_getChar_buffer.shift(); + }; + var TTY = { + ttys:[], + init() { + // https://github.com/emscripten-core/emscripten/pull/1555 + // if (ENVIRONMENT_IS_NODE) { + // // currently, FS.init does not distinguish if process.stdin is a file or TTY + // // device, it always assumes it's a TTY device. because of this, we're forcing + // // process.stdin to UTF8 encoding to at least make stdin reading compatible + // // with text files until FS.init can be refactored. + // process.stdin.setEncoding('utf8'); + // } + }, + shutdown() { + // https://github.com/emscripten-core/emscripten/pull/1555 + // if (ENVIRONMENT_IS_NODE) { + // // inolen: any idea as to why node -e 'process.stdin.read()' wouldn't exit immediately (with process.stdin being a tty)? + // // isaacs: because now it's reading from the stream, you've expressed interest in it, so that read() kicks off a _read() which creates a ReadReq operation + // // inolen: I thought read() in that case was a synchronous operation that just grabbed some amount of buffered data if it exists? + // // isaacs: it is. but it also triggers a _read() call, which calls readStart() on the handle + // // isaacs: do process.stdin.pause() and i'd think it'd probably close the pending call + // process.stdin.pause(); + // } + }, + register(dev, ops) { + TTY.ttys[dev] = { input: [], output: [], ops: ops }; + FS.registerDevice(dev, TTY.stream_ops); + }, + stream_ops:{ + open(stream) { + var tty = TTY.ttys[stream.node.rdev]; + if (!tty) { + throw new FS.ErrnoError(43); + } + stream.tty = tty; + stream.seekable = false; + }, + close(stream) { + // flush any pending line data + stream.tty.ops.fsync(stream.tty); + }, + fsync(stream) { + stream.tty.ops.fsync(stream.tty); + }, + read(stream, buffer, offset, length, pos /* ignored */) { + if (!stream.tty || !stream.tty.ops.get_char) { + throw new FS.ErrnoError(60); + } + var bytesRead = 0; + for (var i = 0; i < length; i++) { + var result; + try { + result = stream.tty.ops.get_char(stream.tty); + } catch (e) { + throw new FS.ErrnoError(29); + } + if (result === undefined && bytesRead === 0) { + throw new FS.ErrnoError(6); + } + if (result === null || result === undefined) break; + bytesRead++; + buffer[offset+i] = result; + } + if (bytesRead) { + stream.node.atime = Date.now(); + } + return bytesRead; + }, + write(stream, buffer, offset, length, pos) { + if (!stream.tty || !stream.tty.ops.put_char) { + throw new FS.ErrnoError(60); + } + try { + for (var i = 0; i < length; i++) { + stream.tty.ops.put_char(stream.tty, buffer[offset+i]); + } + } catch (e) { + throw new FS.ErrnoError(29); + } + if (length) { + stream.node.mtime = stream.node.ctime = Date.now(); + } + return i; + }, + }, + default_tty_ops:{ + get_char(tty) { + return FS_stdin_getChar(); + }, + put_char(tty, val) { + if (val === null || val === 10) { + out(UTF8ArrayToString(tty.output)); + tty.output = []; + } else { + if (val != 0) tty.output.push(val); // val == 0 would cut text output off in the middle. + } + }, + fsync(tty) { + if (tty.output?.length > 0) { + out(UTF8ArrayToString(tty.output)); + tty.output = []; + } + }, + ioctl_tcgets(tty) { + // typical setting + return { + c_iflag: 25856, + c_oflag: 5, + c_cflag: 191, + c_lflag: 35387, + c_cc: [ + 0x03, 0x1c, 0x7f, 0x15, 0x04, 0x00, 0x01, 0x00, 0x11, 0x13, 0x1a, 0x00, + 0x12, 0x0f, 0x17, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ] + }; + }, + ioctl_tcsets(tty, optional_actions, data) { + // currently just ignore + return 0; + }, + ioctl_tiocgwinsz(tty) { + return [24, 80]; + }, + }, + default_tty1_ops:{ + put_char(tty, val) { + if (val === null || val === 10) { + err(UTF8ArrayToString(tty.output)); + tty.output = []; + } else { + if (val != 0) tty.output.push(val); + } + }, + fsync(tty) { + if (tty.output?.length > 0) { + err(UTF8ArrayToString(tty.output)); + tty.output = []; + } + }, + }, + }; + + + var zeroMemory = (ptr, size) => HEAPU8.fill(0, ptr, ptr + size); + + var mmapAlloc = (size) => { + size = alignMemory(size, 65536); + var ptr = _emscripten_builtin_memalign(65536, size); + if (ptr) zeroMemory(ptr, size); + return ptr; + }; + var MEMFS = { + ops_table:null, + mount(mount) { + return MEMFS.createNode(null, '/', 16895, 0); + }, + createNode(parent, name, mode, dev) { + if (FS.isBlkdev(mode) || FS.isFIFO(mode)) { + // no supported + throw new FS.ErrnoError(63); + } + MEMFS.ops_table ||= { + dir: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + lookup: MEMFS.node_ops.lookup, + mknod: MEMFS.node_ops.mknod, + rename: MEMFS.node_ops.rename, + unlink: MEMFS.node_ops.unlink, + rmdir: MEMFS.node_ops.rmdir, + readdir: MEMFS.node_ops.readdir, + symlink: MEMFS.node_ops.symlink + }, + stream: { + llseek: MEMFS.stream_ops.llseek + } + }, + file: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr + }, + stream: { + llseek: MEMFS.stream_ops.llseek, + read: MEMFS.stream_ops.read, + write: MEMFS.stream_ops.write, + mmap: MEMFS.stream_ops.mmap, + msync: MEMFS.stream_ops.msync + } + }, + link: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr, + readlink: MEMFS.node_ops.readlink + }, + stream: {} + }, + chrdev: { + node: { + getattr: MEMFS.node_ops.getattr, + setattr: MEMFS.node_ops.setattr + }, + stream: FS.chrdev_stream_ops + } + }; + var node = FS.createNode(parent, name, mode, dev); + if (FS.isDir(node.mode)) { + node.node_ops = MEMFS.ops_table.dir.node; + node.stream_ops = MEMFS.ops_table.dir.stream; + node.contents = {}; + } else if (FS.isFile(node.mode)) { + node.node_ops = MEMFS.ops_table.file.node; + node.stream_ops = MEMFS.ops_table.file.stream; + node.usedBytes = 0; // The actual number of bytes used in the typed array, as opposed to contents.length which gives the whole capacity. + // When the byte data of the file is populated, this will point to either a typed array, or a normal JS array. Typed arrays are preferred + // for performance, and used by default. However, typed arrays are not resizable like normal JS arrays are, so there is a small disk size + // penalty involved for appending file writes that continuously grow a file similar to std::vector capacity vs used -scheme. + node.contents = null; + } else if (FS.isLink(node.mode)) { + node.node_ops = MEMFS.ops_table.link.node; + node.stream_ops = MEMFS.ops_table.link.stream; + } else if (FS.isChrdev(node.mode)) { + node.node_ops = MEMFS.ops_table.chrdev.node; + node.stream_ops = MEMFS.ops_table.chrdev.stream; + } + node.atime = node.mtime = node.ctime = Date.now(); + // add the new node to the parent + if (parent) { + parent.contents[name] = node; + parent.atime = parent.mtime = parent.ctime = node.atime; + } + return node; + }, + getFileDataAsTypedArray(node) { + if (!node.contents) return new Uint8Array(0); + if (node.contents.subarray) return node.contents.subarray(0, node.usedBytes); // Make sure to not return excess unused bytes. + return new Uint8Array(node.contents); + }, + expandFileStorage(node, newCapacity) { + var prevCapacity = node.contents ? node.contents.length : 0; + if (prevCapacity >= newCapacity) return; // No need to expand, the storage was already large enough. + // Don't expand strictly to the given requested limit if it's only a very small increase, but instead geometrically grow capacity. + // For small filesizes (<1MB), perform size*2 geometric increase, but for large sizes, do a much more conservative size*1.125 increase to + // avoid overshooting the allocation cap by a very large margin. + var CAPACITY_DOUBLING_MAX = 1024 * 1024; + newCapacity = Math.max(newCapacity, (prevCapacity * (prevCapacity < CAPACITY_DOUBLING_MAX ? 2.0 : 1.125)) >>> 0); + if (prevCapacity != 0) newCapacity = Math.max(newCapacity, 256); // At minimum allocate 256b for each file when expanding. + var oldContents = node.contents; + node.contents = new Uint8Array(newCapacity); // Allocate new storage. + if (node.usedBytes > 0) node.contents.set(oldContents.subarray(0, node.usedBytes), 0); // Copy old data over to the new storage. + }, + resizeFileStorage(node, newSize) { + if (node.usedBytes == newSize) return; + if (newSize == 0) { + node.contents = null; // Fully decommit when requesting a resize to zero. + node.usedBytes = 0; + } else { + var oldContents = node.contents; + node.contents = new Uint8Array(newSize); // Allocate new storage. + if (oldContents) { + node.contents.set(oldContents.subarray(0, Math.min(newSize, node.usedBytes))); // Copy old data over to the new storage. + } + node.usedBytes = newSize; + } + }, + node_ops:{ + getattr(node) { + var attr = {}; + // device numbers reuse inode numbers. + attr.dev = FS.isChrdev(node.mode) ? node.id : 1; + attr.ino = node.id; + attr.mode = node.mode; + attr.nlink = 1; + attr.uid = 0; + attr.gid = 0; + attr.rdev = node.rdev; + if (FS.isDir(node.mode)) { + attr.size = 4096; + } else if (FS.isFile(node.mode)) { + attr.size = node.usedBytes; + } else if (FS.isLink(node.mode)) { + attr.size = node.link.length; + } else { + attr.size = 0; + } + attr.atime = new Date(node.atime); + attr.mtime = new Date(node.mtime); + attr.ctime = new Date(node.ctime); + // NOTE: In our implementation, st_blocks = Math.ceil(st_size/st_blksize), + // but this is not required by the standard. + attr.blksize = 4096; + attr.blocks = Math.ceil(attr.size / attr.blksize); + return attr; + }, + setattr(node, attr) { + for (const key of ["mode", "atime", "mtime", "ctime"]) { + if (attr[key] != null) { + node[key] = attr[key]; + } + } + if (attr.size !== undefined) { + MEMFS.resizeFileStorage(node, attr.size); + } + }, + lookup(parent, name) { + // This error may happen quite a bit. To avoid overhead we reuse it (and + // suffer a lack of stack info). + if (!MEMFS.doesNotExistError) { + MEMFS.doesNotExistError = new FS.ErrnoError(44); + /** @suppress {checkTypes} */ + MEMFS.doesNotExistError.stack = ''; + } + throw MEMFS.doesNotExistError; + }, + mknod(parent, name, mode, dev) { + return MEMFS.createNode(parent, name, mode, dev); + }, + rename(old_node, new_dir, new_name) { + var new_node; + try { + new_node = FS.lookupNode(new_dir, new_name); + } catch (e) {} + if (new_node) { + if (FS.isDir(old_node.mode)) { + // if we're overwriting a directory at new_name, make sure it's empty. + for (var i in new_node.contents) { + throw new FS.ErrnoError(55); + } + } + FS.hashRemoveNode(new_node); + } + // do the internal rewiring + delete old_node.parent.contents[old_node.name]; + new_dir.contents[new_name] = old_node; + old_node.name = new_name; + new_dir.ctime = new_dir.mtime = old_node.parent.ctime = old_node.parent.mtime = Date.now(); + }, + unlink(parent, name) { + delete parent.contents[name]; + parent.ctime = parent.mtime = Date.now(); + }, + rmdir(parent, name) { + var node = FS.lookupNode(parent, name); + for (var i in node.contents) { + throw new FS.ErrnoError(55); + } + delete parent.contents[name]; + parent.ctime = parent.mtime = Date.now(); + }, + readdir(node) { + return ['.', '..', ...Object.keys(node.contents)]; + }, + symlink(parent, newname, oldpath) { + var node = MEMFS.createNode(parent, newname, 0o777 | 40960, 0); + node.link = oldpath; + return node; + }, + readlink(node) { + if (!FS.isLink(node.mode)) { + throw new FS.ErrnoError(28); + } + return node.link; + }, + }, + stream_ops:{ + read(stream, buffer, offset, length, position) { + var contents = stream.node.contents; + if (position >= stream.node.usedBytes) return 0; + var size = Math.min(stream.node.usedBytes - position, length); + if (size > 8 && contents.subarray) { // non-trivial, and typed array + buffer.set(contents.subarray(position, position + size), offset); + } else { + for (var i = 0; i < size; i++) buffer[offset + i] = contents[position + i]; + } + return size; + }, + write(stream, buffer, offset, length, position, canOwn) { + // If the buffer is located in main memory (HEAP), and if + // memory can grow, we can't hold on to references of the + // memory buffer, as they may get invalidated. That means we + // need to do copy its contents. + if (buffer.buffer === HEAP8.buffer) { + canOwn = false; + } + + if (!length) return 0; + var node = stream.node; + node.mtime = node.ctime = Date.now(); + + if (buffer.subarray && (!node.contents || node.contents.subarray)) { // This write is from a typed array to a typed array? + if (canOwn) { + node.contents = buffer.subarray(offset, offset + length); + node.usedBytes = length; + return length; + } else if (node.usedBytes === 0 && position === 0) { // If this is a simple first write to an empty file, do a fast set since we don't need to care about old data. + node.contents = buffer.slice(offset, offset + length); + node.usedBytes = length; + return length; + } else if (position + length <= node.usedBytes) { // Writing to an already allocated and used subrange of the file? + node.contents.set(buffer.subarray(offset, offset + length), position); + return length; + } + } + + // Appending to an existing file and we need to reallocate, or source data did not come as a typed array. + MEMFS.expandFileStorage(node, position+length); + if (node.contents.subarray && buffer.subarray) { + // Use typed array write which is available. + node.contents.set(buffer.subarray(offset, offset + length), position); + } else { + for (var i = 0; i < length; i++) { + node.contents[position + i] = buffer[offset + i]; // Or fall back to manual write if not. + } + } + node.usedBytes = Math.max(node.usedBytes, position + length); + return length; + }, + llseek(stream, offset, whence) { + var position = offset; + if (whence === 1) { + position += stream.position; + } else if (whence === 2) { + if (FS.isFile(stream.node.mode)) { + position += stream.node.usedBytes; + } + } + if (position < 0) { + throw new FS.ErrnoError(28); + } + return position; + }, + mmap(stream, length, position, prot, flags) { + if (!FS.isFile(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + var ptr; + var allocated; + var contents = stream.node.contents; + // Only make a new copy when MAP_PRIVATE is specified. + if (!(flags & 2) && contents && contents.buffer === HEAP8.buffer) { + // We can't emulate MAP_SHARED when the file is not backed by the + // buffer we're mapping to (e.g. the HEAP buffer). + allocated = false; + ptr = contents.byteOffset; + } else { + allocated = true; + ptr = mmapAlloc(length); + if (!ptr) { + throw new FS.ErrnoError(48); + } + if (contents) { + // Try to avoid unnecessary slices. + if (position > 0 || position + length < contents.length) { + if (contents.subarray) { + contents = contents.subarray(position, position + length); + } else { + contents = Array.prototype.slice.call(contents, position, position + length); + } + } + HEAP8.set(contents, ptr); + } + } + return { ptr, allocated }; + }, + msync(stream, buffer, offset, length, mmapFlags) { + MEMFS.stream_ops.write(stream, buffer, 0, length, offset, false); + // should we check if bytesWritten and length are the same? + return 0; + }, + }, + }; + + var FS_modeStringToFlags = (str) => { + var flagModes = { + 'r': 0, + 'r+': 2, + 'w': 512 | 64 | 1, + 'w+': 512 | 64 | 2, + 'a': 1024 | 64 | 1, + 'a+': 1024 | 64 | 2, + }; + var flags = flagModes[str]; + if (typeof flags == 'undefined') { + throw new Error(`Unknown file open mode: ${str}`); + } + return flags; + }; + + var FS_getMode = (canRead, canWrite) => { + var mode = 0; + if (canRead) mode |= 292 | 73; + if (canWrite) mode |= 146; + return mode; + }; + + + + + var ERRNO_CODES = { + 'EPERM': 63, + 'ENOENT': 44, + 'ESRCH': 71, + 'EINTR': 27, + 'EIO': 29, + 'ENXIO': 60, + 'E2BIG': 1, + 'ENOEXEC': 45, + 'EBADF': 8, + 'ECHILD': 12, + 'EAGAIN': 6, + 'EWOULDBLOCK': 6, + 'ENOMEM': 48, + 'EACCES': 2, + 'EFAULT': 21, + 'ENOTBLK': 105, + 'EBUSY': 10, + 'EEXIST': 20, + 'EXDEV': 75, + 'ENODEV': 43, + 'ENOTDIR': 54, + 'EISDIR': 31, + 'EINVAL': 28, + 'ENFILE': 41, + 'EMFILE': 33, + 'ENOTTY': 59, + 'ETXTBSY': 74, + 'EFBIG': 22, + 'ENOSPC': 51, + 'ESPIPE': 70, + 'EROFS': 69, + 'EMLINK': 34, + 'EPIPE': 64, + 'EDOM': 18, + 'ERANGE': 68, + 'ENOMSG': 49, + 'EIDRM': 24, + 'ECHRNG': 106, + 'EL2NSYNC': 156, + 'EL3HLT': 107, + 'EL3RST': 108, + 'ELNRNG': 109, + 'EUNATCH': 110, + 'ENOCSI': 111, + 'EL2HLT': 112, + 'EDEADLK': 16, + 'ENOLCK': 46, + 'EBADE': 113, + 'EBADR': 114, + 'EXFULL': 115, + 'ENOANO': 104, + 'EBADRQC': 103, + 'EBADSLT': 102, + 'EDEADLOCK': 16, + 'EBFONT': 101, + 'ENOSTR': 100, + 'ENODATA': 116, + 'ETIME': 117, + 'ENOSR': 118, + 'ENONET': 119, + 'ENOPKG': 120, + 'EREMOTE': 121, + 'ENOLINK': 47, + 'EADV': 122, + 'ESRMNT': 123, + 'ECOMM': 124, + 'EPROTO': 65, + 'EMULTIHOP': 36, + 'EDOTDOT': 125, + 'EBADMSG': 9, + 'ENOTUNIQ': 126, + 'EBADFD': 127, + 'EREMCHG': 128, + 'ELIBACC': 129, + 'ELIBBAD': 130, + 'ELIBSCN': 131, + 'ELIBMAX': 132, + 'ELIBEXEC': 133, + 'ENOSYS': 52, + 'ENOTEMPTY': 55, + 'ENAMETOOLONG': 37, + 'ELOOP': 32, + 'EOPNOTSUPP': 138, + 'EPFNOSUPPORT': 139, + 'ECONNRESET': 15, + 'ENOBUFS': 42, + 'EAFNOSUPPORT': 5, + 'EPROTOTYPE': 67, + 'ENOTSOCK': 57, + 'ENOPROTOOPT': 50, + 'ESHUTDOWN': 140, + 'ECONNREFUSED': 14, + 'EADDRINUSE': 3, + 'ECONNABORTED': 13, + 'ENETUNREACH': 40, + 'ENETDOWN': 38, + 'ETIMEDOUT': 73, + 'EHOSTDOWN': 142, + 'EHOSTUNREACH': 23, + 'EINPROGRESS': 26, + 'EALREADY': 7, + 'EDESTADDRREQ': 17, + 'EMSGSIZE': 35, + 'EPROTONOSUPPORT': 66, + 'ESOCKTNOSUPPORT': 137, + 'EADDRNOTAVAIL': 4, + 'ENETRESET': 39, + 'EISCONN': 30, + 'ENOTCONN': 53, + 'ETOOMANYREFS': 141, + 'EUSERS': 136, + 'EDQUOT': 19, + 'ESTALE': 72, + 'ENOTSUP': 138, + 'ENOMEDIUM': 148, + 'EILSEQ': 25, + 'EOVERFLOW': 61, + 'ECANCELED': 11, + 'ENOTRECOVERABLE': 56, + 'EOWNERDEAD': 62, + 'ESTRPIPE': 135, + }; + + var NODEFS = { + isWindows:false, + staticInit() { + NODEFS.isWindows = !!process.platform.match(/^win/); + var flags = process.binding("constants")["fs"]; + NODEFS.flagsForNodeMap = { + "1024": flags["O_APPEND"], + "64": flags["O_CREAT"], + "128": flags["O_EXCL"], + "256": flags["O_NOCTTY"], + "0": flags["O_RDONLY"], + "2": flags["O_RDWR"], + "4096": flags["O_SYNC"], + "512": flags["O_TRUNC"], + "1": flags["O_WRONLY"], + "131072": flags["O_NOFOLLOW"], + }; + }, + convertNodeCode(e) { + var code = e.code; + return ERRNO_CODES[code]; + }, + tryFSOperation(f) { + try { + return f(); + } catch (e) { + if (!e.code) throw e; + // node under windows can return code 'UNKNOWN' here: + // https://github.com/emscripten-core/emscripten/issues/15468 + if (e.code === 'UNKNOWN') throw new FS.ErrnoError(28); + throw new FS.ErrnoError(NODEFS.convertNodeCode(e)); + } + }, + mount(mount) { + return NODEFS.createNode(null, '/', NODEFS.getMode(mount.opts.root), 0); + }, + createNode(parent, name, mode, dev) { + if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) { + throw new FS.ErrnoError(28); + } + var node = FS.createNode(parent, name, mode); + node.node_ops = NODEFS.node_ops; + node.stream_ops = NODEFS.stream_ops; + return node; + }, + getMode(path) { + return NODEFS.tryFSOperation(() => { + var mode = fs.lstatSync(path).mode; + if (NODEFS.isWindows) { + // Windows does not report the 'x' permission bit, so propagate read + // bits to execute bits. + mode |= (mode & 292) >> 2; + } + return mode; + }); + }, + realPath(node) { + var parts = []; + while (node.parent !== node) { + parts.push(node.name); + node = node.parent; + } + parts.push(node.mount.opts.root); + parts.reverse(); + return PATH.join(...parts); + }, + flagsForNode(flags) { + flags &= ~2097152; // Ignore this flag from musl, otherwise node.js fails to open the file. + flags &= ~2048; // Ignore this flag from musl, otherwise node.js fails to open the file. + flags &= ~32768; // Ignore this flag from musl, otherwise node.js fails to open the file. + flags &= ~524288; // Some applications may pass it; it makes no sense for a single process. + flags &= ~65536; // Node.js doesn't need this passed in, it errors. + var newFlags = 0; + for (var k in NODEFS.flagsForNodeMap) { + if (flags & k) { + newFlags |= NODEFS.flagsForNodeMap[k]; + flags ^= k; + } + } + if (flags) { + throw new FS.ErrnoError(28); + } + return newFlags; + }, + getattr(func, node) { + var stat = NODEFS.tryFSOperation(func); + if (NODEFS.isWindows) { + // node.js v0.10.20 doesn't report blksize and blocks on Windows. Fake + // them with default blksize of 4096. + // See http://support.microsoft.com/kb/140365 + if (!stat.blksize) { + stat.blksize = 4096; + } + if (!stat.blocks) { + stat.blocks = (stat.size+stat.blksize-1)/stat.blksize|0; + } + // Windows does not report the 'x' permission bit, so propagate read + // bits to execute bits. + stat.mode |= (stat.mode & 292) >> 2; + } + return { + dev: stat.dev, + ino: node.id, + mode: stat.mode, + nlink: stat.nlink, + uid: stat.uid, + gid: stat.gid, + rdev: stat.rdev, + size: stat.size, + atime: stat.atime, + mtime: stat.mtime, + ctime: stat.ctime, + blksize: stat.blksize, + blocks: stat.blocks + }; + }, + setattr(arg, node, attr, chmod, utimes, truncate, stat) { + NODEFS.tryFSOperation(() => { + if (attr.mode !== undefined) { + var mode = attr.mode; + if (NODEFS.isWindows) { + // Windows only supports S_IREAD / S_IWRITE (S_IRUSR / S_IWUSR) + // https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/chmod-wchmod + mode &= 384; + } + chmod(arg, mode); + // update the common node structure mode as well + node.mode = attr.mode; + } + if (typeof (attr.atime ?? attr.mtime) === "number") { + // Unfortunately, we have to stat the current value if we don't want + // to change it. On top of that, since the times don't round trip + // this will only keep the value nearly unchanged not exactly + // unchanged. See: + // https://github.com/nodejs/node/issues/56492 + var atime = new Date(attr.atime ?? stat(arg).atime); + var mtime = new Date(attr.mtime ?? stat(arg).mtime); + utimes(arg, atime, mtime); + } + if (attr.size !== undefined) { + truncate(arg, attr.size); + } + }); + }, + node_ops:{ + getattr(node) { + var path = NODEFS.realPath(node); + return NODEFS.getattr(() => fs.lstatSync(path), node); + }, + setattr(node, attr) { + var path = NODEFS.realPath(node); + if (attr.mode != null && attr.dontFollow) { + throw new FS.ErrnoError(52); + } + NODEFS.setattr(path, node, attr, fs.chmodSync, fs.utimesSync, fs.truncateSync, fs.lstatSync); + }, + lookup(parent, name) { + var path = PATH.join2(NODEFS.realPath(parent), name); + var mode = NODEFS.getMode(path); + return NODEFS.createNode(parent, name, mode); + }, + mknod(parent, name, mode, dev) { + var node = NODEFS.createNode(parent, name, mode, dev); + // create the backing node for this in the fs root as well + var path = NODEFS.realPath(node); + NODEFS.tryFSOperation(() => { + if (FS.isDir(node.mode)) { + fs.mkdirSync(path, node.mode); + } else { + fs.writeFileSync(path, '', { mode: node.mode }); + } + }); + return node; + }, + rename(oldNode, newDir, newName) { + var oldPath = NODEFS.realPath(oldNode); + var newPath = PATH.join2(NODEFS.realPath(newDir), newName); + try { + FS.unlink(newPath); + } catch(e) {} + NODEFS.tryFSOperation(() => fs.renameSync(oldPath, newPath)); + oldNode.name = newName; + }, + unlink(parent, name) { + var path = PATH.join2(NODEFS.realPath(parent), name); + NODEFS.tryFSOperation(() => fs.unlinkSync(path)); + }, + rmdir(parent, name) { + var path = PATH.join2(NODEFS.realPath(parent), name); + NODEFS.tryFSOperation(() => fs.rmdirSync(path)); + }, + readdir(node) { + var path = NODEFS.realPath(node); + return NODEFS.tryFSOperation(() => fs.readdirSync(path)); + }, + symlink(parent, newName, oldPath) { + var newPath = PATH.join2(NODEFS.realPath(parent), newName); + NODEFS.tryFSOperation(() => fs.symlinkSync(oldPath, newPath)); + }, + readlink(node) { + var path = NODEFS.realPath(node); + return NODEFS.tryFSOperation(() => fs.readlinkSync(path)); + }, + statfs(path) { + var stats = NODEFS.tryFSOperation(() => fs.statfsSync(path)); + // Node.js doesn't provide frsize (fragment size). Set it to bsize (block size) + // as they're often the same in many file systems. May not be accurate for all. + stats.frsize = stats.bsize; + return stats; + }, + }, + stream_ops:{ + getattr(stream) { + return NODEFS.getattr(() => fs.fstatSync(stream.nfd), stream.node); + }, + setattr(stream, attr) { + NODEFS.setattr(stream.nfd, stream.node, attr, fs.fchmodSync, fs.futimesSync, fs.ftruncateSync, fs.fstatSync); + }, + open(stream) { + var path = NODEFS.realPath(stream.node); + NODEFS.tryFSOperation(() => { + stream.shared.refcount = 1; + stream.nfd = fs.openSync(path, NODEFS.flagsForNode(stream.flags)); + }); + }, + close(stream) { + NODEFS.tryFSOperation(() => { + if (stream.nfd && --stream.shared.refcount === 0) { + fs.closeSync(stream.nfd); + } + }); + }, + dup(stream) { + stream.shared.refcount++; + }, + read(stream, buffer, offset, length, position) { + return NODEFS.tryFSOperation(() => + fs.readSync(stream.nfd, new Int8Array(buffer.buffer, offset, length), 0, length, position) + ); + }, + write(stream, buffer, offset, length, position) { + return NODEFS.tryFSOperation(() => + fs.writeSync(stream.nfd, new Int8Array(buffer.buffer, offset, length), 0, length, position) + ); + }, + llseek(stream, offset, whence) { + var position = offset; + if (whence === 1) { + position += stream.position; + } else if (whence === 2) { + if (FS.isFile(stream.node.mode)) { + NODEFS.tryFSOperation(() => { + var stat = fs.fstatSync(stream.nfd); + position += stat.size; + }); + } + } + + if (position < 0) { + throw new FS.ErrnoError(28); + } + + return position; + }, + mmap(stream, length, position, prot, flags) { + if (!FS.isFile(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + + var ptr = mmapAlloc(length); + + NODEFS.stream_ops.read(stream, HEAP8, ptr, length, position); + return { ptr, allocated: true }; + }, + msync(stream, buffer, offset, length, mmapFlags) { + NODEFS.stream_ops.write(stream, buffer, 0, length, offset, false); + // should we check if bytesWritten and length are the same? + return 0; + }, + }, + }; + + + + var PROXYFS = { + mount(mount) { + return PROXYFS.createNode(null, '/', mount.opts.fs.lstat(mount.opts.root).mode, 0); + }, + createNode(parent, name, mode, dev) { + if (!FS.isDir(mode) && !FS.isFile(mode) && !FS.isLink(mode)) { + throw new FS.ErrnoError(ERRNO_CODES.EINVAL); + } + var node = FS.createNode(parent, name, mode); + node.node_ops = PROXYFS.node_ops; + node.stream_ops = PROXYFS.stream_ops; + return node; + }, + realPath(node) { + var parts = []; + while (node.parent !== node) { + parts.push(node.name); + node = node.parent; + } + parts.push(node.mount.opts.root); + parts.reverse(); + return PATH.join(...parts); + }, + node_ops:{ + getattr(node) { + var path = PROXYFS.realPath(node); + var stat; + try { + stat = node.mount.opts.fs.lstat(path); + } catch (e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + return { + dev: stat.dev, + ino: stat.ino, + mode: stat.mode, + nlink: stat.nlink, + uid: stat.uid, + gid: stat.gid, + rdev: stat.rdev, + size: stat.size, + atime: stat.atime, + mtime: stat.mtime, + ctime: stat.ctime, + blksize: stat.blksize, + blocks: stat.blocks + }; + }, + setattr(node, attr) { + var path = PROXYFS.realPath(node); + try { + if (attr.mode !== undefined) { + node.mount.opts.fs.chmod(path, attr.mode); + // update the common node structure mode as well + node.mode = attr.mode; + } + if (attr.atime || attr.mtime) { + var atime = new Date(attr.atime || attr.mtime); + var mtime = new Date(attr.mtime || attr.atime); + node.mount.opts.fs.utime(path, atime, mtime); + } + if (attr.size !== undefined) { + node.mount.opts.fs.truncate(path, attr.size); + } + } catch (e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + lookup(parent, name) { + try { + var path = PATH.join2(PROXYFS.realPath(parent), name); + var mode = parent.mount.opts.fs.lstat(path).mode; + var node = PROXYFS.createNode(parent, name, mode); + return node; + } catch(e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + mknod(parent, name, mode, dev) { + var node = PROXYFS.createNode(parent, name, mode, dev); + // create the backing node for this in the fs root as well + var path = PROXYFS.realPath(node); + try { + if (FS.isDir(node.mode)) { + node.mount.opts.fs.mkdir(path, node.mode); + } else { + node.mount.opts.fs.writeFile(path, '', { mode: node.mode }); + } + } catch (e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + return node; + }, + rename(oldNode, newDir, newName) { + var oldPath = PROXYFS.realPath(oldNode); + var newPath = PATH.join2(PROXYFS.realPath(newDir), newName); + try { + oldNode.mount.opts.fs.rename(oldPath, newPath); + oldNode.name = newName; + } catch(e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + unlink(parent, name) { + var path = PATH.join2(PROXYFS.realPath(parent), name); + try { + parent.mount.opts.fs.unlink(path); + } catch(e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + rmdir(parent, name) { + var path = PATH.join2(PROXYFS.realPath(parent), name); + try { + parent.mount.opts.fs.rmdir(path); + } catch(e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + readdir(node) { + var path = PROXYFS.realPath(node); + try { + return node.mount.opts.fs.readdir(path); + } catch(e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + symlink(parent, newName, oldPath) { + var newPath = PATH.join2(PROXYFS.realPath(parent), newName); + try { + parent.mount.opts.fs.symlink(oldPath, newPath); + } catch(e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + readlink(node) { + var path = PROXYFS.realPath(node); + try { + return node.mount.opts.fs.readlink(path); + } catch(e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + }, + stream_ops:{ + open(stream) { + var path = PROXYFS.realPath(stream.node); + try { + stream.nfd = stream.node.mount.opts.fs.open(path,stream.flags); + } catch(e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + close(stream) { + try { + stream.node.mount.opts.fs.close(stream.nfd); + } catch(e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + read(stream, buffer, offset, length, position) { + try { + return stream.node.mount.opts.fs.read(stream.nfd, buffer, offset, length, position); + } catch(e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + write(stream, buffer, offset, length, position) { + try { + return stream.node.mount.opts.fs.write(stream.nfd, buffer, offset, length, position); + } catch(e) { + if (!e.code) throw e; + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + }, + llseek(stream, offset, whence) { + var position = offset; + if (whence === 1) { + position += stream.position; + } else if (whence === 2) { + if (FS.isFile(stream.node.mode)) { + try { + var stat = stream.node.node_ops.getattr(stream.node); + position += stat.size; + } catch (e) { + throw new FS.ErrnoError(ERRNO_CODES[e.code]); + } + } + } + + if (position < 0) { + throw new FS.ErrnoError(ERRNO_CODES.EINVAL); + } + + return position; + }, + }, + }; + + + + var FS_createDataFile = (...args) => FS.createDataFile(...args); + + var getUniqueRunDependency = (id) => { + return id; + }; + + + + var FS_handledByPreloadPlugin = async (byteArray, fullname) => { + // Ensure plugins are ready. + if (typeof Browser != 'undefined') Browser.init(); + + for (var plugin of preloadPlugins) { + if (plugin['canHandle'](fullname)) { + return plugin['handle'](byteArray, fullname); + } + } + // In no plugin handled this file then return the original/unmodified + // byteArray. + return byteArray; + }; + var FS_preloadFile = async (parent, name, url, canRead, canWrite, dontCreateFile, canOwn, preFinish) => { + // TODO we should allow people to just pass in a complete filename instead + // of parent and name being that we just join them anyways + var fullname = name ? PATH_FS.resolve(PATH.join2(parent, name)) : parent; + var dep = getUniqueRunDependency(`cp ${fullname}`); // might have several active requests for the same fullname + addRunDependency(dep); + + try { + var byteArray = url; + if (typeof url == 'string') { + byteArray = await asyncLoad(url); + } + + byteArray = await FS_handledByPreloadPlugin(byteArray, fullname); + preFinish?.(); + if (!dontCreateFile) { + FS_createDataFile(parent, name, byteArray, canRead, canWrite, canOwn); + } + } finally { + removeRunDependency(dep); + } + }; + var FS_createPreloadedFile = (parent, name, url, canRead, canWrite, onload, onerror, dontCreateFile, canOwn, preFinish) => { + FS_preloadFile(parent, name, url, canRead, canWrite, dontCreateFile, canOwn, preFinish).then(onload).catch(onerror); + }; + var FS = { + root:null, + mounts:[], + devices:{ + }, + streams:[], + nextInode:1, + nameTable:null, + currentPath:"/", + initialized:false, + ignorePermissions:true, + filesystems:null, + syncFSRequests:0, + readFiles:{ + }, + ErrnoError:class { + name = 'ErrnoError'; + // We set the `name` property to be able to identify `FS.ErrnoError` + // - the `name` is a standard ECMA-262 property of error objects. Kind of good to have it anyway. + // - when using PROXYFS, an error can come from an underlying FS + // as different FS objects have their own FS.ErrnoError each, + // the test `err instanceof FS.ErrnoError` won't detect an error coming from another filesystem, causing bugs. + // we'll use the reliable test `err.name == "ErrnoError"` instead + constructor(errno) { + this.errno = errno; + } + }, + FSStream:class { + shared = {}; + get object() { + return this.node; + } + set object(val) { + this.node = val; + } + get isRead() { + return (this.flags & 2097155) !== 1; + } + get isWrite() { + return (this.flags & 2097155) !== 0; + } + get isAppend() { + return (this.flags & 1024); + } + get flags() { + return this.shared.flags; + } + set flags(val) { + this.shared.flags = val; + } + get position() { + return this.shared.position; + } + set position(val) { + this.shared.position = val; + } + }, + FSNode:class { + node_ops = {}; + stream_ops = {}; + readMode = 292 | 73; + writeMode = 146; + mounted = null; + constructor(parent, name, mode, rdev) { + if (!parent) { + parent = this; // root node sets parent to itself + } + this.parent = parent; + this.mount = parent.mount; + this.id = FS.nextInode++; + this.name = name; + this.mode = mode; + this.rdev = rdev; + this.atime = this.mtime = this.ctime = Date.now(); + } + get read() { + return (this.mode & this.readMode) === this.readMode; + } + set read(val) { + val ? this.mode |= this.readMode : this.mode &= ~this.readMode; + } + get write() { + return (this.mode & this.writeMode) === this.writeMode; + } + set write(val) { + val ? this.mode |= this.writeMode : this.mode &= ~this.writeMode; + } + get isFolder() { + return FS.isDir(this.mode); + } + get isDevice() { + return FS.isChrdev(this.mode); + } + }, + lookupPath(path, opts = {}) { + if (!path) { + throw new FS.ErrnoError(44); + } + opts.follow_mount ??= true + + if (!PATH.isAbs(path)) { + path = FS.cwd() + '/' + path; + } + + // limit max consecutive symlinks to 40 (SYMLOOP_MAX). + linkloop: for (var nlinks = 0; nlinks < 40; nlinks++) { + // split the absolute path + var parts = path.split('/').filter((p) => !!p); + + // start at the root + var current = FS.root; + var current_path = '/'; + + for (var i = 0; i < parts.length; i++) { + var islast = (i === parts.length-1); + if (islast && opts.parent) { + // stop resolving + break; + } + + if (parts[i] === '.') { + continue; + } + + if (parts[i] === '..') { + current_path = PATH.dirname(current_path); + if (FS.isRoot(current)) { + path = current_path + '/' + parts.slice(i + 1).join('/'); + // We're making progress here, don't let many consecutive ..'s + // lead to ELOOP + nlinks--; + continue linkloop; + } else { + current = current.parent; + } + continue; + } + + current_path = PATH.join2(current_path, parts[i]); + try { + current = FS.lookupNode(current, parts[i]); + } catch (e) { + // if noent_okay is true, suppress a ENOENT in the last component + // and return an object with an undefined node. This is needed for + // resolving symlinks in the path when creating a file. + if ((e?.errno === 44) && islast && opts.noent_okay) { + return { path: current_path }; + } + throw e; + } + + // jump to the mount's root node if this is a mountpoint + if (FS.isMountpoint(current) && (!islast || opts.follow_mount)) { + current = current.mounted.root; + } + + // by default, lookupPath will not follow a symlink if it is the final path component. + // setting opts.follow = true will override this behavior. + if (FS.isLink(current.mode) && (!islast || opts.follow)) { + if (!current.node_ops.readlink) { + throw new FS.ErrnoError(52); + } + var link = current.node_ops.readlink(current); + if (!PATH.isAbs(link)) { + link = PATH.dirname(current_path) + '/' + link; + } + path = link + '/' + parts.slice(i + 1).join('/'); + continue linkloop; + } + } + return { path: current_path, node: current }; + } + throw new FS.ErrnoError(32); + }, + getPath(node) { + var path; + while (true) { + if (FS.isRoot(node)) { + var mount = node.mount.mountpoint; + if (!path) return mount; + return mount[mount.length-1] !== '/' ? `${mount}/${path}` : mount + path; + } + path = path ? `${node.name}/${path}` : node.name; + node = node.parent; + } + }, + hashName(parentid, name) { + var hash = 0; + + for (var i = 0; i < name.length; i++) { + hash = ((hash << 5) - hash + name.charCodeAt(i)) | 0; + } + return ((parentid + hash) >>> 0) % FS.nameTable.length; + }, + hashAddNode(node) { + var hash = FS.hashName(node.parent.id, node.name); + node.name_next = FS.nameTable[hash]; + FS.nameTable[hash] = node; + }, + hashRemoveNode(node) { + var hash = FS.hashName(node.parent.id, node.name); + if (FS.nameTable[hash] === node) { + FS.nameTable[hash] = node.name_next; + } else { + var current = FS.nameTable[hash]; + while (current) { + if (current.name_next === node) { + current.name_next = node.name_next; + break; + } + current = current.name_next; + } + } + }, + lookupNode(parent, name) { + var errCode = FS.mayLookup(parent); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + var hash = FS.hashName(parent.id, name); + for (var node = FS.nameTable[hash]; node; node = node.name_next) { + var nodeName = node.name; + if (node.parent.id === parent.id && nodeName === name) { + return node; + } + } + // if we failed to find it in the cache, call into the VFS + return FS.lookup(parent, name); + }, + createNode(parent, name, mode, rdev) { + var node = new FS.FSNode(parent, name, mode, rdev); + + FS.hashAddNode(node); + + return node; + }, + destroyNode(node) { + FS.hashRemoveNode(node); + }, + isRoot(node) { + return node === node.parent; + }, + isMountpoint(node) { + return !!node.mounted; + }, + isFile(mode) { + return (mode & 61440) === 32768; + }, + isDir(mode) { + return (mode & 61440) === 16384; + }, + isLink(mode) { + return (mode & 61440) === 40960; + }, + isChrdev(mode) { + return (mode & 61440) === 8192; + }, + isBlkdev(mode) { + return (mode & 61440) === 24576; + }, + isFIFO(mode) { + return (mode & 61440) === 4096; + }, + isSocket(mode) { + return (mode & 49152) === 49152; + }, + flagsToPermissionString(flag) { + var perms = ['r', 'w', 'rw'][flag & 3]; + if ((flag & 512)) { + perms += 'w'; + } + return perms; + }, + nodePermissions(node, perms) { + if (FS.ignorePermissions) { + return 0; + } + // return 0 if any user, group or owner bits are set. + if (perms.includes('r') && !(node.mode & 292)) { + return 2; + } else if (perms.includes('w') && !(node.mode & 146)) { + return 2; + } else if (perms.includes('x') && !(node.mode & 73)) { + return 2; + } + return 0; + }, + mayLookup(dir) { + if (!FS.isDir(dir.mode)) return 54; + var errCode = FS.nodePermissions(dir, 'x'); + if (errCode) return errCode; + if (!dir.node_ops.lookup) return 2; + return 0; + }, + mayCreate(dir, name) { + if (!FS.isDir(dir.mode)) { + return 54; + } + try { + var node = FS.lookupNode(dir, name); + return 20; + } catch (e) { + } + return FS.nodePermissions(dir, 'wx'); + }, + mayDelete(dir, name, isdir) { + var node; + try { + node = FS.lookupNode(dir, name); + } catch (e) { + return e.errno; + } + var errCode = FS.nodePermissions(dir, 'wx'); + if (errCode) { + return errCode; + } + if (isdir) { + if (!FS.isDir(node.mode)) { + return 54; + } + if (FS.isRoot(node) || FS.getPath(node) === FS.cwd()) { + return 10; + } + } else { + if (FS.isDir(node.mode)) { + return 31; + } + } + return 0; + }, + mayOpen(node, flags) { + if (!node) { + return 44; + } + if (FS.isLink(node.mode)) { + return 32; + } else if (FS.isDir(node.mode)) { + if (FS.flagsToPermissionString(flags) !== 'r' // opening for write + || (flags & (512 | 64))) { // TODO: check for O_SEARCH? (== search for dir only) + return 31; + } + } + return FS.nodePermissions(node, FS.flagsToPermissionString(flags)); + }, + checkOpExists(op, err) { + if (!op) { + throw new FS.ErrnoError(err); + } + return op; + }, + MAX_OPEN_FDS:4096, + nextfd() { + for (var fd = 0; fd <= FS.MAX_OPEN_FDS; fd++) { + if (!FS.streams[fd]) { + return fd; + } + } + throw new FS.ErrnoError(33); + }, + getStreamChecked(fd) { + var stream = FS.getStream(fd); + if (!stream) { + throw new FS.ErrnoError(8); + } + return stream; + }, + getStream:(fd) => FS.streams[fd], + createStream(stream, fd = -1) { + + // clone it, so we can return an instance of FSStream + stream = Object.assign(new FS.FSStream(), stream); + if (fd == -1) { + fd = FS.nextfd(); + } + stream.fd = fd; + FS.streams[fd] = stream; + return stream; + }, + closeStream(fd) { + FS.streams[fd] = null; + }, + dupStream(origStream, fd = -1) { + var stream = FS.createStream(origStream, fd); + stream.stream_ops?.dup?.(stream); + return stream; + }, + doSetAttr(stream, node, attr) { + var setattr = stream?.stream_ops.setattr; + var arg = setattr ? stream : node; + setattr ??= node.node_ops.setattr; + FS.checkOpExists(setattr, 63) + setattr(arg, attr); + }, + chrdev_stream_ops:{ + open(stream) { + var device = FS.getDevice(stream.node.rdev); + // override node's stream ops with the device's + stream.stream_ops = device.stream_ops; + // forward the open call + stream.stream_ops.open?.(stream); + }, + llseek() { + throw new FS.ErrnoError(70); + }, + }, + major:(dev) => ((dev) >> 8), + minor:(dev) => ((dev) & 0xff), + makedev:(ma, mi) => ((ma) << 8 | (mi)), + registerDevice(dev, ops) { + FS.devices[dev] = { stream_ops: ops }; + }, + getDevice:(dev) => FS.devices[dev], + getMounts(mount) { + var mounts = []; + var check = [mount]; + + while (check.length) { + var m = check.pop(); + + mounts.push(m); + + check.push(...m.mounts); + } + + return mounts; + }, + syncfs(populate, callback) { + if (typeof populate == 'function') { + callback = populate; + populate = false; + } + + FS.syncFSRequests++; + + if (FS.syncFSRequests > 1) { + err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`); + } + + var mounts = FS.getMounts(FS.root.mount); + var completed = 0; + + function doCallback(errCode) { + FS.syncFSRequests--; + return callback(errCode); + } + + function done(errCode) { + if (errCode) { + if (!done.errored) { + done.errored = true; + return doCallback(errCode); + } + return; + } + if (++completed >= mounts.length) { + doCallback(null); + } + }; + + // sync all mounts + for (var mount of mounts) { + if (mount.type.syncfs) { + mount.type.syncfs(mount, populate, done); + } else { + done(null); + } + } + }, + mount(type, opts, mountpoint) { + var root = mountpoint === '/'; + var pseudo = !mountpoint; + var node; + + if (root && FS.root) { + throw new FS.ErrnoError(10); + } else if (!root && !pseudo) { + var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); + + mountpoint = lookup.path; // use the absolute path + node = lookup.node; + + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + + + } + + var mount = { + type, + opts, + mountpoint, + mounts: [] + }; + + // create a root node for the fs + var mountRoot = type.mount(mount); + mountRoot.mount = mount; + mount.root = mountRoot; + + if (root) { + FS.root = mountRoot; + } else if (node) { + // set as a mountpoint + node.mounted = mount; + + // add the new mount to the current mount's children + if (node.mount) { + node.mount.mounts.push(mount); + } + } + + return mountRoot; + }, + unmount(mountpoint) { + var lookup = FS.lookupPath(mountpoint, { follow_mount: false }); + + if (!FS.isMountpoint(lookup.node)) { + throw new FS.ErrnoError(28); + } + + // destroy the nodes for this mount, and all its child mounts + var node = lookup.node; + var mount = node.mounted; + var mounts = FS.getMounts(mount); + + for (var [hash, current] of Object.entries(FS.nameTable)) { + while (current) { + var next = current.name_next; + + if (mounts.includes(current.mount)) { + FS.destroyNode(current); + } + + current = next; + } + } + + // no longer a mountpoint + node.mounted = null; + + // remove this mount from the child mounts + var idx = node.mount.mounts.indexOf(mount); + node.mount.mounts.splice(idx, 1); + }, + lookup(parent, name) { + return parent.node_ops.lookup(parent, name); + }, + mknod(path, mode, dev) { + var lookup = FS.lookupPath(path, { parent: true }); + var parent = lookup.node; + var name = PATH.basename(path); + if (!name) { + throw new FS.ErrnoError(28); + } + if (name === '.' || name === '..') { + throw new FS.ErrnoError(20); + } + var errCode = FS.mayCreate(parent, name); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.mknod) { + throw new FS.ErrnoError(63); + } + return parent.node_ops.mknod(parent, name, mode, dev); + }, + statfs(path) { + return FS.statfsNode(FS.lookupPath(path, {follow: true}).node); + }, + statfsStream(stream) { + // We keep a separate statfsStream function because noderawfs overrides + // it. In noderawfs, stream.node is sometimes null. Instead, we need to + // look at stream.path. + return FS.statfsNode(stream.node); + }, + statfsNode(node) { + // NOTE: None of the defaults here are true. We're just returning safe and + // sane values. Currently nodefs and rawfs replace these defaults, + // other file systems leave them alone. + var rtn = { + bsize: 4096, + frsize: 4096, + blocks: 1e6, + bfree: 5e5, + bavail: 5e5, + files: FS.nextInode, + ffree: FS.nextInode - 1, + fsid: 42, + flags: 2, + namelen: 255, + }; + + if (node.node_ops.statfs) { + Object.assign(rtn, node.node_ops.statfs(node.mount.opts.root)); + } + return rtn; + }, + create(path, mode = 0o666) { + mode &= 4095; + mode |= 32768; + return FS.mknod(path, mode, 0); + }, + mkdir(path, mode = 0o777) { + mode &= 511 | 512; + mode |= 16384; + return FS.mknod(path, mode, 0); + }, + mkdirTree(path, mode) { + var dirs = path.split('/'); + var d = ''; + for (var dir of dirs) { + if (!dir) continue; + if (d || PATH.isAbs(path)) d += '/'; + d += dir; + try { + FS.mkdir(d, mode); + } catch(e) { + if (e.errno != 20) throw e; + } + } + }, + mkdev(path, mode, dev) { + if (typeof dev == 'undefined') { + dev = mode; + mode = 0o666; + } + mode |= 8192; + return FS.mknod(path, mode, dev); + }, + symlink(oldpath, newpath) { + if (!PATH_FS.resolve(oldpath)) { + throw new FS.ErrnoError(44); + } + var lookup = FS.lookupPath(newpath, { parent: true }); + var parent = lookup.node; + if (!parent) { + throw new FS.ErrnoError(44); + } + var newname = PATH.basename(newpath); + var errCode = FS.mayCreate(parent, newname); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.symlink) { + throw new FS.ErrnoError(63); + } + return parent.node_ops.symlink(parent, newname, oldpath); + }, + rename(old_path, new_path) { + var old_dirname = PATH.dirname(old_path); + var new_dirname = PATH.dirname(new_path); + var old_name = PATH.basename(old_path); + var new_name = PATH.basename(new_path); + // parents must exist + var lookup, old_dir, new_dir; + + // let the errors from non existent directories percolate up + lookup = FS.lookupPath(old_path, { parent: true }); + old_dir = lookup.node; + lookup = FS.lookupPath(new_path, { parent: true }); + new_dir = lookup.node; + + if (!old_dir || !new_dir) throw new FS.ErrnoError(44); + // need to be part of the same mount + if (old_dir.mount !== new_dir.mount) { + throw new FS.ErrnoError(75); + } + // source must exist + var old_node = FS.lookupNode(old_dir, old_name); + // old path should not be an ancestor of the new path + var relative = PATH_FS.relative(old_path, new_dirname); + if (relative.charAt(0) !== '.') { + throw new FS.ErrnoError(28); + } + // new path should not be an ancestor of the old path + relative = PATH_FS.relative(new_path, old_dirname); + if (relative.charAt(0) !== '.') { + throw new FS.ErrnoError(55); + } + // see if the new path already exists + var new_node; + try { + new_node = FS.lookupNode(new_dir, new_name); + } catch (e) { + // not fatal + } + // early out if nothing needs to change + if (old_node === new_node) { + return; + } + // we'll need to delete the old entry + var isdir = FS.isDir(old_node.mode); + var errCode = FS.mayDelete(old_dir, old_name, isdir); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + // need delete permissions if we'll be overwriting. + // need create permissions if new doesn't already exist. + errCode = new_node ? + FS.mayDelete(new_dir, new_name, isdir) : + FS.mayCreate(new_dir, new_name); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!old_dir.node_ops.rename) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(old_node) || (new_node && FS.isMountpoint(new_node))) { + throw new FS.ErrnoError(10); + } + // if we are going to change the parent, check write permissions + if (new_dir !== old_dir) { + errCode = FS.nodePermissions(old_dir, 'w'); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + } + // remove the node from the lookup hash + FS.hashRemoveNode(old_node); + // do the underlying fs rename + try { + old_dir.node_ops.rename(old_node, new_dir, new_name); + // update old node (we do this here to avoid each backend + // needing to) + old_node.parent = new_dir; + } catch (e) { + throw e; + } finally { + // add the node back to the hash (in case node_ops.rename + // changed its name) + FS.hashAddNode(old_node); + } + }, + rmdir(path) { + var lookup = FS.lookupPath(path, { parent: true }); + var parent = lookup.node; + var name = PATH.basename(path); + var node = FS.lookupNode(parent, name); + var errCode = FS.mayDelete(parent, name, true); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.rmdir) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + parent.node_ops.rmdir(parent, name); + FS.destroyNode(node); + }, + readdir(path) { + var lookup = FS.lookupPath(path, { follow: true }); + var node = lookup.node; + var readdir = FS.checkOpExists(node.node_ops.readdir, 54); + return readdir(node); + }, + unlink(path) { + var lookup = FS.lookupPath(path, { parent: true }); + var parent = lookup.node; + if (!parent) { + throw new FS.ErrnoError(44); + } + var name = PATH.basename(path); + var node = FS.lookupNode(parent, name); + var errCode = FS.mayDelete(parent, name, false); + if (errCode) { + // According to POSIX, we should map EISDIR to EPERM, but + // we instead do what Linux does (and we must, as we use + // the musl linux libc). + throw new FS.ErrnoError(errCode); + } + if (!parent.node_ops.unlink) { + throw new FS.ErrnoError(63); + } + if (FS.isMountpoint(node)) { + throw new FS.ErrnoError(10); + } + parent.node_ops.unlink(parent, name); + FS.destroyNode(node); + }, + readlink(path) { + var lookup = FS.lookupPath(path); + var link = lookup.node; + if (!link) { + throw new FS.ErrnoError(44); + } + if (!link.node_ops.readlink) { + throw new FS.ErrnoError(28); + } + return link.node_ops.readlink(link); + }, + stat(path, dontFollow) { + var lookup = FS.lookupPath(path, { follow: !dontFollow }); + var node = lookup.node; + var getattr = FS.checkOpExists(node.node_ops.getattr, 63); + return getattr(node); + }, + fstat(fd) { + var stream = FS.getStreamChecked(fd); + var node = stream.node; + var getattr = stream.stream_ops.getattr; + var arg = getattr ? stream : node; + getattr ??= node.node_ops.getattr; + FS.checkOpExists(getattr, 63) + return getattr(arg); + }, + lstat(path) { + return FS.stat(path, true); + }, + doChmod(stream, node, mode, dontFollow) { + FS.doSetAttr(stream, node, { + mode: (mode & 4095) | (node.mode & ~4095), + ctime: Date.now(), + dontFollow + }); + }, + chmod(path, mode, dontFollow) { + var node; + if (typeof path == 'string') { + var lookup = FS.lookupPath(path, { follow: !dontFollow }); + node = lookup.node; + } else { + node = path; + } + FS.doChmod(null, node, mode, dontFollow); + }, + lchmod(path, mode) { + FS.chmod(path, mode, true); + }, + fchmod(fd, mode) { + var stream = FS.getStreamChecked(fd); + FS.doChmod(stream, stream.node, mode, false); + }, + doChown(stream, node, dontFollow) { + FS.doSetAttr(stream, node, { + timestamp: Date.now(), + dontFollow + // we ignore the uid / gid for now + }); + }, + chown(path, uid, gid, dontFollow) { + var node; + if (typeof path == 'string') { + var lookup = FS.lookupPath(path, { follow: !dontFollow }); + node = lookup.node; + } else { + node = path; + } + FS.doChown(null, node, dontFollow); + }, + lchown(path, uid, gid) { + FS.chown(path, uid, gid, true); + }, + fchown(fd, uid, gid) { + var stream = FS.getStreamChecked(fd); + FS.doChown(stream, stream.node, false); + }, + doTruncate(stream, node, len) { + if (FS.isDir(node.mode)) { + throw new FS.ErrnoError(31); + } + if (!FS.isFile(node.mode)) { + throw new FS.ErrnoError(28); + } + var errCode = FS.nodePermissions(node, 'w'); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + FS.doSetAttr(stream, node, { + size: len, + timestamp: Date.now() + }); + }, + truncate(path, len) { + if (len < 0) { + throw new FS.ErrnoError(28); + } + var node; + if (typeof path == 'string') { + var lookup = FS.lookupPath(path, { follow: true }); + node = lookup.node; + } else { + node = path; + } + FS.doTruncate(null, node, len); + }, + ftruncate(fd, len) { + var stream = FS.getStreamChecked(fd); + if (len < 0 || (stream.flags & 2097155) === 0) { + throw new FS.ErrnoError(28); + } + FS.doTruncate(stream, stream.node, len); + }, + utime(path, atime, mtime) { + var lookup = FS.lookupPath(path, { follow: true }); + var node = lookup.node; + var setattr = FS.checkOpExists(node.node_ops.setattr, 63); + setattr(node, { + atime: atime, + mtime: mtime + }); + }, + open(path, flags, mode = 0o666) { + if (path === "") { + throw new FS.ErrnoError(44); + } + flags = typeof flags == 'string' ? FS_modeStringToFlags(flags) : flags; + if ((flags & 64)) { + mode = (mode & 4095) | 32768; + } else { + mode = 0; + } + var node; + var isDirPath; + if (typeof path == 'object') { + node = path; + } else { + isDirPath = path.endsWith("/"); + // noent_okay makes it so that if the final component of the path + // doesn't exist, lookupPath returns `node: undefined`. `path` will be + // updated to point to the target of all symlinks. + var lookup = FS.lookupPath(path, { + follow: !(flags & 131072), + noent_okay: true + }); + node = lookup.node; + path = lookup.path; + } + // perhaps we need to create the node + var created = false; + if ((flags & 64)) { + if (node) { + // if O_CREAT and O_EXCL are set, error out if the node already exists + if ((flags & 128)) { + throw new FS.ErrnoError(20); + } + } else if (isDirPath) { + throw new FS.ErrnoError(31); + } else { + // node doesn't exist, try to create it + // Ignore the permission bits here to ensure we can `open` this new + // file below. We use chmod below the apply the permissions once the + // file is open. + node = FS.mknod(path, mode | 0o777, 0); + created = true; + } + } + if (!node) { + throw new FS.ErrnoError(44); + } + // can't truncate a device + if (FS.isChrdev(node.mode)) { + flags &= ~512; + } + // if asked only for a directory, then this must be one + if ((flags & 65536) && !FS.isDir(node.mode)) { + throw new FS.ErrnoError(54); + } + // check permissions, if this is not a file we just created now (it is ok to + // create and write to a file with read-only permissions; it is read-only + // for later use) + if (!created) { + var errCode = FS.mayOpen(node, flags); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + } + // do truncation if necessary + if ((flags & 512) && !created) { + FS.truncate(node, 0); + } + // we've already handled these, don't pass down to the underlying vfs + flags &= ~(128 | 512 | 131072); + + // register the stream with the filesystem + var stream = FS.createStream({ + node, + path: FS.getPath(node), // we want the absolute path to the node + flags, + seekable: true, + position: 0, + stream_ops: node.stream_ops, + // used by the file family libc calls (fopen, fwrite, ferror, etc.) + ungotten: [], + error: false + }); + // call the new stream's open function + if (stream.stream_ops.open) { + stream.stream_ops.open(stream); + } + if (created) { + FS.chmod(node, mode & 0o777); + } + if (Module['logReadFiles'] && !(flags & 1)) { + if (!(path in FS.readFiles)) { + FS.readFiles[path] = 1; + } + } + return stream; + }, + close(stream) { + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if (stream.getdents) stream.getdents = null; // free readdir state + try { + if (stream.stream_ops.close) { + stream.stream_ops.close(stream); + } + } catch (e) { + throw e; + } finally { + FS.closeStream(stream.fd); + } + stream.fd = null; + }, + isClosed(stream) { + return stream.fd === null; + }, + llseek(stream, offset, whence) { + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if (!stream.seekable || !stream.stream_ops.llseek) { + throw new FS.ErrnoError(70); + } + if (whence != 0 && whence != 1 && whence != 2) { + throw new FS.ErrnoError(28); + } + stream.position = stream.stream_ops.llseek(stream, offset, whence); + stream.ungotten = []; + return stream.position; + }, + read(stream, buffer, offset, length, position) { + if (length < 0 || position < 0) { + throw new FS.ErrnoError(28); + } + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if ((stream.flags & 2097155) === 1) { + throw new FS.ErrnoError(8); + } + if (FS.isDir(stream.node.mode)) { + throw new FS.ErrnoError(31); + } + if (!stream.stream_ops.read) { + throw new FS.ErrnoError(28); + } + var seeking = typeof position != 'undefined'; + if (!seeking) { + position = stream.position; + } else if (!stream.seekable) { + throw new FS.ErrnoError(70); + } + var bytesRead = stream.stream_ops.read(stream, buffer, offset, length, position); + if (!seeking) stream.position += bytesRead; + return bytesRead; + }, + write(stream, buffer, offset, length, position, canOwn) { + if (length < 0 || position < 0) { + throw new FS.ErrnoError(28); + } + if (FS.isClosed(stream)) { + throw new FS.ErrnoError(8); + } + if ((stream.flags & 2097155) === 0) { + throw new FS.ErrnoError(8); + } + if (FS.isDir(stream.node.mode)) { + throw new FS.ErrnoError(31); + } + if (!stream.stream_ops.write) { + throw new FS.ErrnoError(28); + } + if (stream.seekable && stream.flags & 1024) { + // seek to the end before writing in append mode + FS.llseek(stream, 0, 2); + } + var seeking = typeof position != 'undefined'; + if (!seeking) { + position = stream.position; + } else if (!stream.seekable) { + throw new FS.ErrnoError(70); + } + var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn); + if (!seeking) stream.position += bytesWritten; + return bytesWritten; + }, + mmap(stream, length, position, prot, flags) { + // User requests writing to file (prot & PROT_WRITE != 0). + // Checking if we have permissions to write to the file unless + // MAP_PRIVATE flag is set. According to POSIX spec it is possible + // to write to file opened in read-only mode with MAP_PRIVATE flag, + // as all modifications will be visible only in the memory of + // the current process. + if ((prot & 2) !== 0 + && (flags & 2) === 0 + && (stream.flags & 2097155) !== 2) { + throw new FS.ErrnoError(2); + } + if ((stream.flags & 2097155) === 1) { + throw new FS.ErrnoError(2); + } + if (!stream.stream_ops.mmap) { + throw new FS.ErrnoError(43); + } + if (!length) { + throw new FS.ErrnoError(28); + } + return stream.stream_ops.mmap(stream, length, position, prot, flags); + }, + msync(stream, buffer, offset, length, mmapFlags) { + if (!stream.stream_ops.msync) { + return 0; + } + return stream.stream_ops.msync(stream, buffer, offset, length, mmapFlags); + }, + ioctl(stream, cmd, arg) { + if (!stream.stream_ops.ioctl) { + throw new FS.ErrnoError(59); + } + return stream.stream_ops.ioctl(stream, cmd, arg); + }, + readFile(path, opts = {}) { + opts.flags = opts.flags || 0; + opts.encoding = opts.encoding || 'binary'; + if (opts.encoding !== 'utf8' && opts.encoding !== 'binary') { + abort(`Invalid encoding type "${opts.encoding}"`); + } + var stream = FS.open(path, opts.flags); + var stat = FS.stat(path); + var length = stat.size; + var buf = new Uint8Array(length); + FS.read(stream, buf, 0, length, 0); + if (opts.encoding === 'utf8') { + buf = UTF8ArrayToString(buf); + } + FS.close(stream); + return buf; + }, + writeFile(path, data, opts = {}) { + opts.flags = opts.flags || 577; + var stream = FS.open(path, opts.flags, opts.mode); + if (typeof data == 'string') { + data = new Uint8Array(intArrayFromString(data, true)); + } + if (ArrayBuffer.isView(data)) { + FS.write(stream, data, 0, data.byteLength, undefined, opts.canOwn); + } else { + abort('Unsupported data type'); + } + FS.close(stream); + }, + cwd:() => FS.currentPath, + chdir(path) { + var lookup = FS.lookupPath(path, { follow: true }); + if (lookup.node === null) { + throw new FS.ErrnoError(44); + } + if (!FS.isDir(lookup.node.mode)) { + throw new FS.ErrnoError(54); + } + var errCode = FS.nodePermissions(lookup.node, 'x'); + if (errCode) { + throw new FS.ErrnoError(errCode); + } + FS.currentPath = lookup.path; + }, + createDefaultDirectories() { + FS.mkdir('/tmp'); + FS.mkdir('/home'); + FS.mkdir('/home/web_user'); + }, + createDefaultDevices() { + // create /dev + FS.mkdir('/dev'); + // setup /dev/null + FS.registerDevice(FS.makedev(1, 3), { + read: () => 0, + write: (stream, buffer, offset, length, pos) => length, + llseek: () => 0, + }); + FS.mkdev('/dev/null', FS.makedev(1, 3)); + // setup /dev/tty and /dev/tty1 + // stderr needs to print output using err() rather than out() + // so we register a second tty just for it. + TTY.register(FS.makedev(5, 0), TTY.default_tty_ops); + TTY.register(FS.makedev(6, 0), TTY.default_tty1_ops); + FS.mkdev('/dev/tty', FS.makedev(5, 0)); + FS.mkdev('/dev/tty1', FS.makedev(6, 0)); + // setup /dev/[u]random + // use a buffer to avoid overhead of individual crypto calls per byte + var randomBuffer = new Uint8Array(1024), randomLeft = 0; + var randomByte = () => { + if (randomLeft === 0) { + randomFill(randomBuffer); + randomLeft = randomBuffer.byteLength; + } + return randomBuffer[--randomLeft]; + }; + FS.createDevice('/dev', 'random', randomByte); + FS.createDevice('/dev', 'urandom', randomByte); + // we're not going to emulate the actual shm device, + // just create the tmp dirs that reside in it commonly + FS.mkdir('/dev/shm'); + FS.mkdir('/dev/shm/tmp'); + }, + createSpecialDirectories() { + // create /proc/self/fd which allows /proc/self/fd/6 => readlink gives the + // name of the stream for fd 6 (see test_unistd_ttyname) + FS.mkdir('/proc'); + var proc_self = FS.mkdir('/proc/self'); + FS.mkdir('/proc/self/fd'); + FS.mount({ + mount() { + var node = FS.createNode(proc_self, 'fd', 16895, 73); + node.stream_ops = { + llseek: MEMFS.stream_ops.llseek, + }; + node.node_ops = { + lookup(parent, name) { + var fd = +name; + var stream = FS.getStreamChecked(fd); + var ret = { + parent: null, + mount: { mountpoint: 'fake' }, + node_ops: { readlink: () => stream.path }, + id: fd + 1, + }; + ret.parent = ret; // make it look like a simple root node + return ret; + }, + readdir() { + return Array.from(FS.streams.entries()) + .filter(([k, v]) => v) + .map(([k, v]) => k.toString()); + } + }; + return node; + } + }, {}, '/proc/self/fd'); + }, + createStandardStreams(input, output, error) { + // TODO deprecate the old functionality of a single + // input / output callback and that utilizes FS.createDevice + // and instead require a unique set of stream ops + + // by default, we symlink the standard streams to the + // default tty devices. however, if the standard streams + // have been overwritten we create a unique device for + // them instead. + if (input) { + FS.createDevice('/dev', 'stdin', input); + } else { + FS.symlink('/dev/tty', '/dev/stdin'); + } + if (output) { + FS.createDevice('/dev', 'stdout', null, output); + } else { + FS.symlink('/dev/tty', '/dev/stdout'); + } + if (error) { + FS.createDevice('/dev', 'stderr', null, error); + } else { + FS.symlink('/dev/tty1', '/dev/stderr'); + } + + // open default streams for the stdin, stdout and stderr devices + var stdin = FS.open('/dev/stdin', 0); + var stdout = FS.open('/dev/stdout', 1); + var stderr = FS.open('/dev/stderr', 1); + }, + staticInit() { + FS.nameTable = new Array(4096); + + FS.mount(MEMFS, {}, '/'); + + FS.createDefaultDirectories(); + FS.createDefaultDevices(); + FS.createSpecialDirectories(); + + FS.filesystems = { + 'MEMFS': MEMFS, + 'NODEFS': NODEFS, + 'PROXYFS': PROXYFS, + }; + }, + init(input, output, error) { + FS.initialized = true; + + // Allow Module.stdin etc. to provide defaults, if none explicitly passed to us here + input ??= Module['stdin']; + output ??= Module['stdout']; + error ??= Module['stderr']; + + FS.createStandardStreams(input, output, error); + }, + quit() { + FS.initialized = false; + // force-flush all streams, so we get musl std streams printed out + _fflush(0); + // close all of our streams + for (var stream of FS.streams) { + if (stream) { + FS.close(stream); + } + } + }, + findObject(path, dontResolveLastLink) { + var ret = FS.analyzePath(path, dontResolveLastLink); + if (!ret.exists) { + return null; + } + return ret.object; + }, + analyzePath(path, dontResolveLastLink) { + // operate from within the context of the symlink's target + try { + var lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); + path = lookup.path; + } catch (e) { + } + var ret = { + isRoot: false, exists: false, error: 0, name: null, path: null, object: null, + parentExists: false, parentPath: null, parentObject: null + }; + try { + var lookup = FS.lookupPath(path, { parent: true }); + ret.parentExists = true; + ret.parentPath = lookup.path; + ret.parentObject = lookup.node; + ret.name = PATH.basename(path); + lookup = FS.lookupPath(path, { follow: !dontResolveLastLink }); + ret.exists = true; + ret.path = lookup.path; + ret.object = lookup.node; + ret.name = lookup.node.name; + ret.isRoot = lookup.path === '/'; + } catch (e) { + ret.error = e.errno; + }; + return ret; + }, + createPath(parent, path, canRead, canWrite) { + parent = typeof parent == 'string' ? parent : FS.getPath(parent); + var parts = path.split('/').reverse(); + while (parts.length) { + var part = parts.pop(); + if (!part) continue; + var current = PATH.join2(parent, part); + try { + FS.mkdir(current); + } catch (e) { + if (e.errno != 20) throw e; + } + parent = current; + } + return current; + }, + createFile(parent, name, properties, canRead, canWrite) { + var path = PATH.join2(typeof parent == 'string' ? parent : FS.getPath(parent), name); + var mode = FS_getMode(canRead, canWrite); + return FS.create(path, mode); + }, + createDataFile(parent, name, data, canRead, canWrite, canOwn) { + var path = name; + if (parent) { + parent = typeof parent == 'string' ? parent : FS.getPath(parent); + path = name ? PATH.join2(parent, name) : parent; + } + var mode = FS_getMode(canRead, canWrite); + var node = FS.create(path, mode); + if (data) { + if (typeof data == 'string') { + var arr = new Array(data.length); + for (var i = 0, len = data.length; i < len; ++i) arr[i] = data.charCodeAt(i); + data = arr; + } + // make sure we can write to the file + FS.chmod(node, mode | 146); + var stream = FS.open(node, 577); + FS.write(stream, data, 0, data.length, 0, canOwn); + FS.close(stream); + FS.chmod(node, mode); + } + }, + createDevice(parent, name, input, output) { + var path = PATH.join2(typeof parent == 'string' ? parent : FS.getPath(parent), name); + var mode = FS_getMode(!!input, !!output); + FS.createDevice.major ??= 64; + var dev = FS.makedev(FS.createDevice.major++, 0); + // Create a fake device that a set of stream ops to emulate + // the old behavior. + FS.registerDevice(dev, { + open(stream) { + stream.seekable = false; + }, + close(stream) { + // flush any pending line data + if (output?.buffer?.length) { + output(10); + } + }, + read(stream, buffer, offset, length, pos /* ignored */) { + var bytesRead = 0; + for (var i = 0; i < length; i++) { + var result; + try { + result = input(); + } catch (e) { + throw new FS.ErrnoError(29); + } + if (result === undefined && bytesRead === 0) { + throw new FS.ErrnoError(6); + } + if (result === null || result === undefined) break; + bytesRead++; + buffer[offset+i] = result; + } + if (bytesRead) { + stream.node.atime = Date.now(); + } + return bytesRead; + }, + write(stream, buffer, offset, length, pos) { + for (var i = 0; i < length; i++) { + try { + output(buffer[offset+i]); + } catch (e) { + throw new FS.ErrnoError(29); + } + } + if (length) { + stream.node.mtime = stream.node.ctime = Date.now(); + } + return i; + } + }); + return FS.mkdev(path, mode, dev); + }, + forceLoadFile(obj) { + if (obj.isDevice || obj.isFolder || obj.link || obj.contents) return true; + if (globalThis.XMLHttpRequest) { + abort("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread."); + } else { // Command-line. + try { + obj.contents = readBinary(obj.url); + } catch (e) { + throw new FS.ErrnoError(29); + } + } + }, + createLazyFile(parent, name, url, canRead, canWrite) { + // Lazy chunked Uint8Array (implements get and length from Uint8Array). + // Actual getting is abstracted away for eventual reuse. + class LazyUint8Array { + lengthKnown = false; + chunks = []; // Loaded chunks. Index is the chunk number + get(idx) { + if (idx > this.length-1 || idx < 0) { + return undefined; + } + var chunkOffset = idx % this.chunkSize; + var chunkNum = (idx / this.chunkSize)|0; + return this.getter(chunkNum)[chunkOffset]; + } + setDataGetter(getter) { + this.getter = getter; + } + cacheLength() { + // Find length + var xhr = new XMLHttpRequest(); + xhr.open('HEAD', url, false); + xhr.send(null); + if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) abort("Couldn't load " + url + ". Status: " + xhr.status); + var datalength = Number(xhr.getResponseHeader("Content-length")); + var header; + var hasByteServing = (header = xhr.getResponseHeader("Accept-Ranges")) && header === "bytes"; + var usesGzip = (header = xhr.getResponseHeader("Content-Encoding")) && header === "gzip"; + + var chunkSize = 1024*1024; // Chunk size in bytes + + if (!hasByteServing) chunkSize = datalength; + + // Function to get a range from the remote URL. + var doXHR = (from, to) => { + if (from > to) abort("invalid range (" + from + ", " + to + ") or no bytes requested!"); + if (to > datalength-1) abort("only " + datalength + " bytes available! programmer error!"); + + // TODO: Use mozResponseArrayBuffer, responseStream, etc. if available. + var xhr = new XMLHttpRequest(); + xhr.open('GET', url, false); + if (datalength !== chunkSize) xhr.setRequestHeader("Range", "bytes=" + from + "-" + to); + + // Some hints to the browser that we want binary data. + xhr.responseType = 'arraybuffer'; + if (xhr.overrideMimeType) { + xhr.overrideMimeType('text/plain; charset=x-user-defined'); + } + + xhr.send(null); + if (!(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304)) abort("Couldn't load " + url + ". Status: " + xhr.status); + if (xhr.response !== undefined) { + return new Uint8Array(/** @type{Array} */(xhr.response || [])); + } + return intArrayFromString(xhr.responseText || '', true); + }; + var lazyArray = this; + lazyArray.setDataGetter((chunkNum) => { + var start = chunkNum * chunkSize; + var end = (chunkNum+1) * chunkSize - 1; // including this byte + end = Math.min(end, datalength-1); // if datalength-1 is selected, this is the last block + if (typeof lazyArray.chunks[chunkNum] == 'undefined') { + lazyArray.chunks[chunkNum] = doXHR(start, end); + } + if (typeof lazyArray.chunks[chunkNum] == 'undefined') abort('doXHR failed!'); + return lazyArray.chunks[chunkNum]; + }); + + if (usesGzip || !datalength) { + // if the server uses gzip or doesn't supply the length, we have to download the whole file to get the (uncompressed) length + chunkSize = datalength = 1; // this will force getter(0)/doXHR do download the whole file + datalength = this.getter(0).length; + chunkSize = datalength; + out("LazyFiles on gzip forces download of the whole file when length is accessed"); + } + + this._length = datalength; + this._chunkSize = chunkSize; + this.lengthKnown = true; + } + get length() { + if (!this.lengthKnown) { + this.cacheLength(); + } + return this._length; + } + get chunkSize() { + if (!this.lengthKnown) { + this.cacheLength(); + } + return this._chunkSize; + } + } + + if (globalThis.XMLHttpRequest) { + if (!ENVIRONMENT_IS_WORKER) abort('Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc'); + var lazyArray = new LazyUint8Array(); + var properties = { isDevice: false, contents: lazyArray }; + } else { + var properties = { isDevice: false, url: url }; + } + + var node = FS.createFile(parent, name, properties, canRead, canWrite); + // This is a total hack, but I want to get this lazy file code out of the + // core of MEMFS. If we want to keep this lazy file concept I feel it should + // be its own thin LAZYFS proxying calls to MEMFS. + if (properties.contents) { + node.contents = properties.contents; + } else if (properties.url) { + node.contents = null; + node.url = properties.url; + } + // Add a function that defers querying the file size until it is asked the first time. + Object.defineProperties(node, { + usedBytes: { + get: function() { return this.contents.length; } + } + }); + // override each stream op with one that tries to force load the lazy file first + var stream_ops = {}; + for (const [key, fn] of Object.entries(node.stream_ops)) { + stream_ops[key] = (...args) => { + FS.forceLoadFile(node); + return fn(...args); + }; + } + function writeChunks(stream, buffer, offset, length, position) { + var contents = stream.node.contents; + if (position >= contents.length) + return 0; + var size = Math.min(contents.length - position, length); + if (contents.slice) { // normal array + for (var i = 0; i < size; i++) { + buffer[offset + i] = contents[position + i]; + } + } else { + for (var i = 0; i < size; i++) { // LazyUint8Array from sync binary XHR + buffer[offset + i] = contents.get(position + i); + } + } + return size; + } + // use a custom read function + stream_ops.read = (stream, buffer, offset, length, position) => { + FS.forceLoadFile(node); + return writeChunks(stream, buffer, offset, length, position) + }; + // use a custom mmap function + stream_ops.mmap = (stream, length, position, prot, flags) => { + FS.forceLoadFile(node); + var ptr = mmapAlloc(length); + if (!ptr) { + throw new FS.ErrnoError(48); + } + writeChunks(stream, HEAP8, ptr, length, position); + return { ptr, allocated: true }; + }; + node.stream_ops = stream_ops; + return node; + }, + }; + + + var findLibraryFS = (libName, rpath) => { + // If we're preloading a dynamic library, the runtime is not ready to call + // __wasmfs_identify or __emscripten_find_dylib. So just quit out. + // + // This means that DT_NEEDED for the main module and transitive dependencies + // of it won't work with this code path. Similarly, it means that calling + // loadDynamicLibrary in a preRun hook can't use this code path. + if (!runtimeInitialized) { + return undefined; + } + if (PATH.isAbs(libName)) { + try { + FS.lookupPath(libName); + return libName; + } catch (e) { + return undefined; + } + } + var rpathResolved = (rpath?.paths || []).map((p) => replaceORIGIN(rpath?.parentLibPath, p)); + return withStackSave(() => { + // In dylink.c we use: `char buf[2*NAME_MAX+2];` and NAME_MAX is 255. + // So we use the same size here. + var bufSize = 2*255 + 2; + var buf = stackAlloc(bufSize); + var rpathC = stringToUTF8OnStack(rpathResolved.join(':')); + var libNameC = stringToUTF8OnStack(libName); + var resLibNameC = __emscripten_find_dylib(buf, rpathC, libNameC, bufSize); + return resLibNameC ? UTF8ToString(resLibNameC) : undefined; + }); + }; + + var registerDynCallSymbols = (exports) => { + for (var [sym, exp] of Object.entries(exports)) { + if (sym.startsWith('dynCall_')) { + var sig = sym.substring(8); + if (!dynCalls.hasOwnProperty(sig)) { + dynCalls[sig] = exp; + } + } + } + }; + + /** + * @param {number=} handle + * @param {Object=} localScope + */ + function loadDynamicLibrary(libName, flags = {global: true, nodelete: true}, localScope, handle) { + // when loadDynamicLibrary did not have flags, libraries were loaded + // globally & permanently + + var dso = LDSO.loadedLibsByName[libName]; + if (dso) { + // the library is being loaded or has been loaded already. + if (!flags.global) { + if (localScope) { + Object.assign(localScope, dso.exports); + } + registerDynCallSymbols(dso.exports); + } else if (!dso.global) { + // The library was previously loaded only locally but not + // we have a request with global=true. + dso.global = true; + mergeLibSymbols(dso.exports, libName) + } + // same for "nodelete" + if (flags.nodelete && dso.refcount !== Infinity) { + dso.refcount = Infinity; + } + dso.refcount++ + if (handle) { + LDSO.loadedLibsByHandle[handle] = dso; + } + return flags.loadAsync ? Promise.resolve(true) : true; + } + + // allocate new DSO + dso = newDSO(libName, handle, 'loading'); + dso.refcount = flags.nodelete ? Infinity : 1; + dso.global = flags.global; + + // libName -> libData + function loadLibData() { + + // for wasm, we can use fetch for async, but for fs mode we can only imitate it + if (handle) { + var data = HEAPU32[(((handle)+(28))>>2)]; + var dataSize = HEAPU32[(((handle)+(32))>>2)]; + if (data && dataSize) { + var libData = HEAP8.slice(data, data + dataSize); + return flags.loadAsync ? Promise.resolve(libData) : libData; + } + } + + var f = findLibraryFS(libName, flags.rpath); + if (f) { + var libData = FS.readFile(f, {encoding: 'binary'}); + return flags.loadAsync ? Promise.resolve(libData) : libData; + } + + var libFile = locateFile(libName); + if (flags.loadAsync) { + return asyncLoad(libFile); + } + + // load the binary synchronously + if (!readBinary) { + throw new Error(`${libFile}: file not found, and synchronous loading of external files is not available`); + } + return readBinary(libFile); + } + + // libName -> exports + function getExports() { + // lookup preloaded cache first + var preloaded = preloadedWasm[libName]; + if (preloaded) { + return flags.loadAsync ? Promise.resolve(preloaded) : preloaded; + } + + // module not preloaded - load lib data and create new module from it + if (flags.loadAsync) { + return loadLibData().then((libData) => loadWebAssemblyModule(libData, flags, libName, localScope, handle)); + } + + return loadWebAssemblyModule(loadLibData(), flags, libName, localScope, handle); + } + + // module for lib is loaded - update the dso & global namespace + function moduleLoaded(exports) { + if (dso.global) { + mergeLibSymbols(exports, libName); + } else if (localScope) { + Object.assign(localScope, exports); + registerDynCallSymbols(exports); + } + dso.exports = exports; + } + + if (flags.loadAsync) { + return getExports().then((exports) => { + moduleLoaded(exports); + return true; + }); + } + + moduleLoaded(getExports()); + return true; + } + + + var reportUndefinedSymbols = () => { + for (var [symName, entry] of Object.entries(GOT)) { + if (entry.value == -1) { + var value = resolveGlobalSymbol(symName, true).sym; + if (!value && !entry.required) { + // Ignore undefined symbols that are imported as weak. + entry.value = 0; + continue; + } + if (typeof value == 'function') { + /** @suppress {checkTypes} */ + entry.value = addFunction(value, value.sig); + } else if (typeof value == 'number') { + entry.value = value; + } else { + throw new Error(`bad export type for '${symName}': ${typeof value} (${value})`); + } + } + } + }; + + + var loadDylibs = async () => { + if (!dynamicLibraries.length) { + reportUndefinedSymbols(); + return; + } + + addRunDependency('loadDylibs'); + + // Load binaries asynchronously + for (var lib of dynamicLibraries) { + await loadDynamicLibrary(lib, {loadAsync: true, global: true, nodelete: true, allowUndefined: true}) + } + // we got them all, wonderful + reportUndefinedSymbols(); + + removeRunDependency('loadDylibs'); + }; + + + var noExitRuntime = false; + + + + + + /** + * @param {number} ptr + * @param {number} value + * @param {string} type + */ + function setValue(ptr, value, type = 'i8') { + if (type.endsWith('*')) type = '*'; + switch (type) { + case 'i1': HEAP8[ptr] = value; break; + case 'i8': HEAP8[ptr] = value; break; + case 'i16': HEAP16[((ptr)>>1)] = value; break; + case 'i32': HEAP32[((ptr)>>2)] = value; break; + case 'i64': HEAP64[((ptr)>>3)] = BigInt(value); break; + case 'float': HEAPF32[((ptr)>>2)] = value; break; + case 'double': HEAPF64[((ptr)>>3)] = value; break; + case '*': HEAPU32[((ptr)>>2)] = value; break; + default: abort(`invalid type for setValue: ${type}`); + } + } + + + + + + var ___assert_fail = (condition, filename, line, func) => + abort(`Assertion failed: ${UTF8ToString(condition)}, at: ` + [filename ? UTF8ToString(filename) : 'unknown filename', line, func ? UTF8ToString(func) : 'unknown function']); + ___assert_fail.sig = 'vppip'; + + var ___asyncify_data = new WebAssembly.Global({'value': 'i32', 'mutable': true}, 0); + + var ___asyncify_state = new WebAssembly.Global({'value': 'i32', 'mutable': true}, 0); + + var ___call_sighandler = (fp, sig) => ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(sig); + ___call_sighandler.sig = 'vpi'; + + var exceptionLast = 0; + + class ExceptionInfo { + // excPtr - Thrown object pointer to wrap. Metadata pointer is calculated from it. + constructor(excPtr) { + this.excPtr = excPtr; + this.ptr = excPtr - 24; + } + + set_type(type) { + HEAPU32[(((this.ptr)+(4))>>2)] = type; + } + + get_type() { + return HEAPU32[(((this.ptr)+(4))>>2)]; + } + + set_destructor(destructor) { + HEAPU32[(((this.ptr)+(8))>>2)] = destructor; + } + + get_destructor() { + return HEAPU32[(((this.ptr)+(8))>>2)]; + } + + set_caught(caught) { + caught = caught ? 1 : 0; + HEAP8[(this.ptr)+(12)] = caught; + } + + get_caught() { + return HEAP8[(this.ptr)+(12)] != 0; + } + + set_rethrown(rethrown) { + rethrown = rethrown ? 1 : 0; + HEAP8[(this.ptr)+(13)] = rethrown; + } + + get_rethrown() { + return HEAP8[(this.ptr)+(13)] != 0; + } + + // Initialize native structure fields. Should be called once after allocated. + init(type, destructor) { + this.set_adjusted_ptr(0); + this.set_type(type); + this.set_destructor(destructor); + } + + set_adjusted_ptr(adjustedPtr) { + HEAPU32[(((this.ptr)+(16))>>2)] = adjustedPtr; + } + + get_adjusted_ptr() { + return HEAPU32[(((this.ptr)+(16))>>2)]; + } + } + + + var setTempRet0 = (val) => __emscripten_tempret_set(val); + var findMatchingCatch = (args) => { + var thrown = + exceptionLast; + if (!thrown) { + // just pass through the null ptr + setTempRet0(0); + return 0; + } + var info = new ExceptionInfo(thrown); + info.set_adjusted_ptr(thrown); + var thrownType = info.get_type(); + if (!thrownType) { + // just pass through the thrown ptr + setTempRet0(0); + return thrown; + } + + // can_catch receives a **, add indirection + // The different catch blocks are denoted by different types. + // Due to inheritance, those types may not precisely match the + // type of the thrown object. Find one which matches, and + // return the type of the catch block which should be called. + for (var caughtType of args) { + if (caughtType === 0 || caughtType === thrownType) { + // Catch all clause matched or exactly the same type is caught + break; + } + var adjusted_ptr_addr = info.ptr + 16; + if (___cxa_can_catch(caughtType, thrownType, adjusted_ptr_addr)) { + setTempRet0(caughtType); + return thrown; + } + } + setTempRet0(thrownType); + return thrown; + }; + var ___cxa_find_matching_catch_2 = () => findMatchingCatch([]); + ___cxa_find_matching_catch_2.sig = 'p'; + + var ___resumeException = (ptr) => { + if (!exceptionLast) { + exceptionLast = ptr; + } + throw exceptionLast; + }; + ___resumeException.sig = 'vp'; + + + + var SYSCALLS = { + DEFAULT_POLLMASK:5, + calculateAt(dirfd, path, allowEmpty) { + if (PATH.isAbs(path)) { + return path; + } + // relative path + var dir; + if (dirfd === -100) { + dir = FS.cwd(); + } else { + var dirstream = SYSCALLS.getStreamFromFD(dirfd); + dir = dirstream.path; + } + if (path.length == 0) { + if (!allowEmpty) { + throw new FS.ErrnoError(44);; + } + return dir; + } + return dir + '/' + path; + }, + writeStat(buf, stat) { + HEAPU32[((buf)>>2)] = stat.dev; + HEAPU32[(((buf)+(4))>>2)] = stat.mode; + HEAPU32[(((buf)+(8))>>2)] = stat.nlink; + HEAPU32[(((buf)+(12))>>2)] = stat.uid; + HEAPU32[(((buf)+(16))>>2)] = stat.gid; + HEAPU32[(((buf)+(20))>>2)] = stat.rdev; + HEAP64[(((buf)+(24))>>3)] = BigInt(stat.size); + HEAP32[(((buf)+(32))>>2)] = 4096; + HEAP32[(((buf)+(36))>>2)] = stat.blocks; + var atime = stat.atime.getTime(); + var mtime = stat.mtime.getTime(); + var ctime = stat.ctime.getTime(); + HEAP64[(((buf)+(40))>>3)] = BigInt(Math.floor(atime / 1000)); + HEAPU32[(((buf)+(48))>>2)] = (atime % 1000) * 1000 * 1000; + HEAP64[(((buf)+(56))>>3)] = BigInt(Math.floor(mtime / 1000)); + HEAPU32[(((buf)+(64))>>2)] = (mtime % 1000) * 1000 * 1000; + HEAP64[(((buf)+(72))>>3)] = BigInt(Math.floor(ctime / 1000)); + HEAPU32[(((buf)+(80))>>2)] = (ctime % 1000) * 1000 * 1000; + HEAP64[(((buf)+(88))>>3)] = BigInt(stat.ino); + return 0; + }, + writeStatFs(buf, stats) { + HEAPU32[(((buf)+(4))>>2)] = stats.bsize; + HEAPU32[(((buf)+(60))>>2)] = stats.bsize; + HEAP64[(((buf)+(8))>>3)] = BigInt(stats.blocks); + HEAP64[(((buf)+(16))>>3)] = BigInt(stats.bfree); + HEAP64[(((buf)+(24))>>3)] = BigInt(stats.bavail); + HEAP64[(((buf)+(32))>>3)] = BigInt(stats.files); + HEAP64[(((buf)+(40))>>3)] = BigInt(stats.ffree); + HEAPU32[(((buf)+(48))>>2)] = stats.fsid; + HEAPU32[(((buf)+(64))>>2)] = stats.flags; // ST_NOSUID + HEAPU32[(((buf)+(56))>>2)] = stats.namelen; + }, + doMsync(addr, stream, len, flags, offset) { + if (!FS.isFile(stream.node.mode)) { + throw new FS.ErrnoError(43); + } + if (flags & 2) { + // MAP_PRIVATE calls need not to be synced back to underlying fs + return 0; + } + var buffer = HEAPU8.slice(addr, addr + len); + FS.msync(stream, buffer, offset, len, flags); + }, + getStreamFromFD(fd) { + var stream = FS.getStreamChecked(fd); + return stream; + }, + varargs:undefined, + getStr(ptr) { + var ret = UTF8ToString(ptr); + return ret; + }, + }; + var ___syscall__newselect = function (nfds, readfds, writefds, exceptfds, timeout) { + try { + + // readfds are supported, + // writefds checks socket open status + // exceptfds are supported, although on web, such exceptional conditions never arise in web sockets + // and so the exceptfds list will always return empty. + // timeout is supported, although on SOCKFS and PIPEFS these are ignored and always treated as 0 - fully async + + var total = 0; + + var srcReadLow = (readfds ? HEAP32[((readfds)>>2)] : 0), + srcReadHigh = (readfds ? HEAP32[(((readfds)+(4))>>2)] : 0); + var srcWriteLow = (writefds ? HEAP32[((writefds)>>2)] : 0), + srcWriteHigh = (writefds ? HEAP32[(((writefds)+(4))>>2)] : 0); + var srcExceptLow = (exceptfds ? HEAP32[((exceptfds)>>2)] : 0), + srcExceptHigh = (exceptfds ? HEAP32[(((exceptfds)+(4))>>2)] : 0); + + var dstReadLow = 0, + dstReadHigh = 0; + var dstWriteLow = 0, + dstWriteHigh = 0; + var dstExceptLow = 0, + dstExceptHigh = 0; + + var allLow = (readfds ? HEAP32[((readfds)>>2)] : 0) | + (writefds ? HEAP32[((writefds)>>2)] : 0) | + (exceptfds ? HEAP32[((exceptfds)>>2)] : 0); + var allHigh = (readfds ? HEAP32[(((readfds)+(4))>>2)] : 0) | + (writefds ? HEAP32[(((writefds)+(4))>>2)] : 0) | + (exceptfds ? HEAP32[(((exceptfds)+(4))>>2)] : 0); + + var check = (fd, low, high, val) => fd < 32 ? (low & val) : (high & val); + + for (var fd = 0; fd < nfds; fd++) { + var mask = 1 << (fd % 32); + if (!(check(fd, allLow, allHigh, mask))) { + continue; // index isn't in the set + } + + var stream = SYSCALLS.getStreamFromFD(fd); + + var flags = SYSCALLS.DEFAULT_POLLMASK; + + if (stream.stream_ops?.poll) { + var timeoutInMillis = -1; + if (timeout) { + // select(2) is declared to accept "struct timeval { time_t tv_sec; suseconds_t tv_usec; }". + // However, musl passes the two values to the syscall as an array of long values. + // Note that sizeof(time_t) != sizeof(long) in wasm32. The former is 8, while the latter is 4. + // This means using "C_STRUCTS.timeval.tv_usec" leads to a wrong offset. + // So, instead, we use POINTER_SIZE. + var tv_sec = (readfds ? HEAP32[((timeout)>>2)] : 0), + tv_usec = (readfds ? HEAP32[(((timeout)+(4))>>2)] : 0); + timeoutInMillis = (tv_sec + tv_usec / 1000000) * 1000; + } + flags = stream.stream_ops.poll(stream, timeoutInMillis); + } + + if ((flags & 1) && check(fd, srcReadLow, srcReadHigh, mask)) { + fd < 32 ? (dstReadLow = dstReadLow | mask) : (dstReadHigh = dstReadHigh | mask); + total++; + } + if ((flags & 4) && check(fd, srcWriteLow, srcWriteHigh, mask)) { + fd < 32 ? (dstWriteLow = dstWriteLow | mask) : (dstWriteHigh = dstWriteHigh | mask); + total++; + } + if ((flags & 2) && check(fd, srcExceptLow, srcExceptHigh, mask)) { + fd < 32 ? (dstExceptLow = dstExceptLow | mask) : (dstExceptHigh = dstExceptHigh | mask); + total++; + } + } + + if (readfds) { + HEAP32[((readfds)>>2)] = dstReadLow; + HEAP32[(((readfds)+(4))>>2)] = dstReadHigh; + } + if (writefds) { + HEAP32[((writefds)>>2)] = dstWriteLow; + HEAP32[(((writefds)+(4))>>2)] = dstWriteHigh; + } + if (exceptfds) { + HEAP32[((exceptfds)>>2)] = dstExceptLow; + HEAP32[(((exceptfds)+(4))>>2)] = dstExceptHigh; + } + + return total; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + }; + ___syscall__newselect.sig = 'iipppp'; + + var SOCKFS = { + websocketArgs:{ + }, + callbacks:{ + }, + on(event, callback) { + SOCKFS.callbacks[event] = callback; + }, + emit(event, param) { + SOCKFS.callbacks[event]?.(param); + }, + mount(mount) { + // The incomming Module['websocket'] can be used for configuring + // configuring subprotocol/url, etc + SOCKFS.websocketArgs = Module['websocket'] || {}; + // Add the Event registration mechanism to the exported websocket configuration + // object so we can register network callbacks from native JavaScript too. + // For more documentation see system/include/emscripten/emscripten.h + (Module['websocket'] ??= {})['on'] = SOCKFS.on; + + return FS.createNode(null, '/', 16895, 0); + }, + createSocket(family, type, protocol) { + // Emscripten only supports AF_INET + if (family != 2) { + throw new FS.ErrnoError(5); + } + type &= ~526336; // Some applications may pass it; it makes no sense for a single process. + // Emscripten only supports SOCK_STREAM and SOCK_DGRAM + if (type != 1 && type != 2) { + throw new FS.ErrnoError(28); + } + var streaming = type == 1; + if (streaming && protocol && protocol != 6) { + throw new FS.ErrnoError(66); // if SOCK_STREAM, must be tcp or 0. + } + + // create our internal socket structure + var sock = { + family, + type, + protocol, + server: null, + error: null, // Used in getsockopt for SOL_SOCKET/SO_ERROR test + peers: {}, + pending: [], + recv_queue: [], + sock_ops: SOCKFS.websocket_sock_ops + }; + + // create the filesystem node to store the socket structure + var name = SOCKFS.nextname(); + var node = FS.createNode(SOCKFS.root, name, 49152, 0); + node.sock = sock; + + // and the wrapping stream that enables library functions such + // as read and write to indirectly interact with the socket + var stream = FS.createStream({ + path: name, + node, + flags: 2, + seekable: false, + stream_ops: SOCKFS.stream_ops + }); + + // map the new stream to the socket structure (sockets have a 1:1 + // relationship with a stream) + sock.stream = stream; + + return sock; + }, + getSocket(fd) { + var stream = FS.getStream(fd); + if (!stream || !FS.isSocket(stream.node.mode)) { + return null; + } + return stream.node.sock; + }, + stream_ops:{ + poll(stream) { + var sock = stream.node.sock; + return sock.sock_ops.poll(sock); + }, + ioctl(stream, request, varargs) { + var sock = stream.node.sock; + return sock.sock_ops.ioctl(sock, request, varargs); + }, + read(stream, buffer, offset, length, position /* ignored */) { + var sock = stream.node.sock; + var msg = sock.sock_ops.recvmsg(sock, length); + if (!msg) { + // socket is closed + return 0; + } + buffer.set(msg.buffer, offset); + return msg.buffer.length; + }, + write(stream, buffer, offset, length, position /* ignored */) { + var sock = stream.node.sock; + return sock.sock_ops.sendmsg(sock, buffer, offset, length); + }, + close(stream) { + var sock = stream.node.sock; + sock.sock_ops.close(sock); + }, + }, + nextname() { + if (!SOCKFS.nextname.current) { + SOCKFS.nextname.current = 0; + } + return `socket[${SOCKFS.nextname.current++}]`; + }, + websocket_sock_ops:{ + createPeer(sock, addr, port) { + var ws; + + if (typeof addr == 'object') { + ws = addr; + addr = null; + port = null; + } + + if (ws) { + // for sockets that've already connected (e.g. we're the server) + // we can inspect the _socket property for the address + if (ws._socket) { + addr = ws._socket.remoteAddress; + port = ws._socket.remotePort; + } + // if we're just now initializing a connection to the remote, + // inspect the url property + else { + var result = /ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url); + if (!result) { + throw new Error('WebSocket URL must be in the format ws(s)://address:port'); + } + addr = result[1]; + port = parseInt(result[2], 10); + } + } else { + // create the actual websocket object and connect + try { + // The default value is 'ws://' the replace is needed because the compiler replaces '//' comments with '#' + // comments without checking context, so we'd end up with ws:#, the replace swaps the '#' for '//' again. + var url = 'ws://'.replace('#', '//'); + // Make the WebSocket subprotocol (Sec-WebSocket-Protocol) default to binary if no configuration is set. + var subProtocols = 'binary'; // The default value is 'binary' + // The default WebSocket options + var opts = undefined; + + // Fetch runtime WebSocket URL config. + if("function"===typeof SOCKFS.websocketArgs["url"]) { +url = SOCKFS.websocketArgs["url"](...arguments); +}else if ("string" === typeof SOCKFS.websocketArgs["url"]) { + url = SOCKFS.websocketArgs['url']; + } + // Fetch runtime WebSocket subprotocol config. + if (SOCKFS.websocketArgs['subprotocol']) { + subProtocols = SOCKFS.websocketArgs['subprotocol']; + } else if (SOCKFS.websocketArgs['subprotocol'] === null) { + subProtocols = 'null' + } + + if (url === 'ws://' || url === 'wss://') { // Is the supplied URL config just a prefix, if so complete it. + var parts = addr.split('/'); + url = url + parts[0] + ":" + port + "/" + parts.slice(1).join('/'); + } + + if (subProtocols !== 'null') { + // The regex trims the string (removes spaces at the beginning and end, then splits the string by + // , into an Array. Whitespace removal is important for Websockify and ws. + subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */); + + opts = subProtocols; + } + + // If node we use the ws library. + var WebSocketConstructor; + if (ENVIRONMENT_IS_NODE) { + WebSocketConstructor = /** @type{(typeof WebSocket)} */(require('ws')); + } else + { + WebSocketConstructor = WebSocket; + } + if (Module['websocket']['decorator']) {WebSocketConstructor = Module['websocket']['decorator'](WebSocketConstructor);}ws = new WebSocketConstructor(url, opts); + ws.binaryType = 'arraybuffer'; + } catch (e) { + throw new FS.ErrnoError(23); + } + } + + var peer = { + addr, + port, + socket: ws, + msg_send_queue: [] + }; + + SOCKFS.websocket_sock_ops.addPeer(sock, peer); + SOCKFS.websocket_sock_ops.handlePeerEvents(sock, peer); + + // if this is a bound dgram socket, send the port number first to allow + // us to override the ephemeral port reported to us by remotePort on the + // remote end. + if (sock.type === 2 && typeof sock.sport != 'undefined') { + peer.msg_send_queue.push(new Uint8Array([ + 255, 255, 255, 255, + 'p'.charCodeAt(0), 'o'.charCodeAt(0), 'r'.charCodeAt(0), 't'.charCodeAt(0), + ((sock.sport & 0xff00) >> 8) , (sock.sport & 0xff) + ])); + } + + return peer; + }, + getPeer(sock, addr, port) { + return sock.peers[addr + ':' + port]; + }, + addPeer(sock, peer) { + sock.peers[peer.addr + ':' + peer.port] = peer; + }, + removePeer(sock, peer) { + delete sock.peers[peer.addr + ':' + peer.port]; + }, + handlePeerEvents(sock, peer) { + var first = true; + + var handleOpen = function () { + + sock.connecting = false; + SOCKFS.emit('open', sock.stream.fd); + + try { + var queued = peer.msg_send_queue.shift(); + while (queued) { + peer.socket.send(queued); + queued = peer.msg_send_queue.shift(); + } + } catch (e) { + // not much we can do here in the way of proper error handling as we've already + // lied and said this data was sent. shut it down. + peer.socket.close(); + } + }; + + function handleMessage(data) { + if (typeof data == 'string') { + var encoder = new TextEncoder(); // should be utf-8 + data = encoder.encode(data); // make a typed array from the string + } else { + if (data.byteLength == 0) { + // An empty ArrayBuffer will emit a pseudo disconnect event + // as recv/recvmsg will return zero which indicates that a socket + // has performed a shutdown although the connection has not been disconnected yet. + return; + } + data = new Uint8Array(data); // make a typed array view on the array buffer + } + + // if this is the port message, override the peer's port with it + var wasfirst = first; + first = false; + if (wasfirst && + data.length === 10 && + data[0] === 255 && data[1] === 255 && data[2] === 255 && data[3] === 255 && + data[4] === 'p'.charCodeAt(0) && data[5] === 'o'.charCodeAt(0) && data[6] === 'r'.charCodeAt(0) && data[7] === 't'.charCodeAt(0)) { + // update the peer's port and it's key in the peer map + var newport = ((data[8] << 8) | data[9]); + SOCKFS.websocket_sock_ops.removePeer(sock, peer); + peer.port = newport; + SOCKFS.websocket_sock_ops.addPeer(sock, peer); + return; + } + + sock.recv_queue.push({ addr: peer.addr, port: peer.port, data: data }); + SOCKFS.emit('message', sock.stream.fd); + }; + + if (ENVIRONMENT_IS_NODE) { + peer.socket.on('open', handleOpen); + peer.socket.on('message', function(data, isBinary) { + if (!isBinary) { + return; + } + handleMessage((new Uint8Array(data)).buffer); // copy from node Buffer -> ArrayBuffer + }); + peer.socket.on('close', function() { + SOCKFS.emit('close', sock.stream.fd); + }); + peer.socket.on('error', function(error) { + // Although the ws library may pass errors that may be more descriptive than + // ECONNREFUSED they are not necessarily the expected error code e.g. + // ENOTFOUND on getaddrinfo seems to be node.js specific, so using ECONNREFUSED + // is still probably the most useful thing to do. + sock.error = 14; // Used in getsockopt for SOL_SOCKET/SO_ERROR test. + SOCKFS.emit('error', [sock.stream.fd, sock.error, 'ECONNREFUSED: Connection refused']); + // don't throw + }); + } else { + peer.socket.onopen = handleOpen; + peer.socket.onclose = function() { + SOCKFS.emit('close', sock.stream.fd); + }; + peer.socket.onmessage = function peer_socket_onmessage(event) { + handleMessage(event.data); + }; + peer.socket.onerror = function(error) { + // The WebSocket spec only allows a 'simple event' to be thrown on error, + // so we only really know as much as ECONNREFUSED. + sock.error = 14; // Used in getsockopt for SOL_SOCKET/SO_ERROR test. + SOCKFS.emit('error', [sock.stream.fd, sock.error, 'ECONNREFUSED: Connection refused']); + }; + } + }, + poll(sock) { + if (sock.type === 1 && sock.server) { + // listen sockets should only say they're available for reading + // if there are pending clients. + return sock.pending.length ? (64 | 1) : 0; + } + + var mask = 0; + var dest = sock.type === 1 ? // we only care about the socket state for connection-based sockets + SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport) : + null; + + if (sock.recv_queue.length || + !dest || // connection-less sockets are always ready to read + (dest && dest.socket.readyState === dest.socket.CLOSING) || + (dest && dest.socket.readyState === dest.socket.CLOSED)) { // let recv return 0 once closed + mask |= (64 | 1); + } + + if (!dest || // connection-less sockets are always ready to write + (dest && dest.socket.readyState === dest.socket.OPEN)) { + mask |= 4; + } + + if ((dest && dest.socket.readyState === dest.socket.CLOSING) || + (dest && dest.socket.readyState === dest.socket.CLOSED)) { + // When an non-blocking connect fails mark the socket as writable. + // Its up to the calling code to then use getsockopt with SO_ERROR to + // retrieve the error. + // See https://man7.org/linux/man-pages/man2/connect.2.html + if (sock.connecting) { + mask |= 4; + } else { + mask |= 16; + } + } + + return mask; + }, + ioctl(sock, request, arg) { + switch (request) { + case 21531: + var bytes = 0; + if (sock.recv_queue.length) { + bytes = sock.recv_queue[0].data.length; + } + HEAP32[((arg)>>2)] = bytes; + return 0; + case 21537: + var on = HEAP32[((arg)>>2)]; + if (on) { + sock.stream.flags |= 2048; + } else { + sock.stream.flags &= ~2048; + } + return 0; + default: + return 28; + } + }, + close(sock) { + // if we've spawned a listen server, close it + if (sock.server) { + try { + sock.server.close(); + } catch (e) { + } + sock.server = null; + } + // close any peer connections + for (var peer of Object.values(sock.peers)) { + try { + peer.socket.close(); + } catch (e) { + } + SOCKFS.websocket_sock_ops.removePeer(sock, peer); + } + return 0; + }, + bind(sock, addr, port) { + if (typeof sock.saddr != 'undefined' || typeof sock.sport != 'undefined') { + throw new FS.ErrnoError(28); // already bound + } + sock.saddr = addr; + sock.sport = port; + // in order to emulate dgram sockets, we need to launch a listen server when + // binding on a connection-less socket + // note: this is only required on the server side + if (sock.type === 2) { + // close the existing server if it exists + if (sock.server) { + sock.server.close(); + sock.server = null; + } + // swallow error operation not supported error that occurs when binding in the + // browser where this isn't supported + try { + sock.sock_ops.listen(sock, 0); + } catch (e) { + if (!(e.name === 'ErrnoError')) throw e; + if (e.errno !== 138) throw e; + } + } + }, + connect(sock, addr, port) { + if (sock.server) { + throw new FS.ErrnoError(138); + } + + // TODO autobind + // if (!sock.addr && sock.type == 2) { + // } + + // early out if we're already connected / in the middle of connecting + if (typeof sock.daddr != 'undefined' && typeof sock.dport != 'undefined') { + var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport); + if (dest) { + if (dest.socket.readyState === dest.socket.CONNECTING) { + throw new FS.ErrnoError(7); + } else { + throw new FS.ErrnoError(30); + } + } + } + + // add the socket to our peer list and set our + // destination address / port to match + var peer = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port); + sock.daddr = peer.addr; + sock.dport = peer.port; + + // because we cannot synchronously block to wait for the WebSocket + // connection to complete, we return here pretending that the connection + // was a success. + sock.connecting = true; + }, + listen(sock, backlog) { + if (!ENVIRONMENT_IS_NODE) { + throw new FS.ErrnoError(138); + } + if (sock.server) { + throw new FS.ErrnoError(28); // already listening + } + var WebSocketServer = require('ws').Server; + var host = sock.saddr; + if (Module['websocket']['serverDecorator']) {WebSocketServer = Module['websocket']['serverDecorator'](WebSocketServer);}sock.server = new WebSocketServer({ + host, + port: sock.sport + // TODO support backlog + }); + SOCKFS.emit('listen', sock.stream.fd); // Send Event with listen fd. + + sock.server.on('connection', function(ws) { + if (sock.type === 1) { + var newsock = SOCKFS.createSocket(sock.family, sock.type, sock.protocol); + + // create a peer on the new socket + var peer = SOCKFS.websocket_sock_ops.createPeer(newsock, ws); + newsock.daddr = peer.addr; + newsock.dport = peer.port; + + // push to queue for accept to pick up + sock.pending.push(newsock); + SOCKFS.emit('connection', newsock.stream.fd); + } else { + // create a peer on the listen socket so calling sendto + // with the listen socket and an address will resolve + // to the correct client + SOCKFS.websocket_sock_ops.createPeer(sock, ws); + SOCKFS.emit('connection', sock.stream.fd); + } + }); + sock.server.on('close', function() { + SOCKFS.emit('close', sock.stream.fd); + sock.server = null; + }); + sock.server.on('error', function(error) { + // Although the ws library may pass errors that may be more descriptive than + // ECONNREFUSED they are not necessarily the expected error code e.g. + // ENOTFOUND on getaddrinfo seems to be node.js specific, so using EHOSTUNREACH + // is still probably the most useful thing to do. This error shouldn't + // occur in a well written app as errors should get trapped in the compiled + // app's own getaddrinfo call. + sock.error = 23; // Used in getsockopt for SOL_SOCKET/SO_ERROR test. + SOCKFS.emit('error', [sock.stream.fd, sock.error, 'EHOSTUNREACH: Host is unreachable']); + // don't throw + }); + }, + accept(listensock) { + if (!listensock.server || !listensock.pending.length) { + throw new FS.ErrnoError(28); + } + var newsock = listensock.pending.shift(); + newsock.stream.flags = listensock.stream.flags; + return newsock; + }, + getname(sock, peer) { + var addr, port; + if (peer) { + if (sock.daddr === undefined || sock.dport === undefined) { + throw new FS.ErrnoError(53); + } + addr = sock.daddr; + port = sock.dport; + } else { + // TODO saddr and sport will be set for bind()'d UDP sockets, but what + // should we be returning for TCP sockets that've been connect()'d? + addr = sock.saddr || 0; + port = sock.sport || 0; + } + return { addr, port }; + }, + sendmsg(sock, buffer, offset, length, addr, port) { + if (sock.type === 2) { + // connection-less sockets will honor the message address, + // and otherwise fall back to the bound destination address + if (addr === undefined || port === undefined) { + addr = sock.daddr; + port = sock.dport; + } + // if there was no address to fall back to, error out + if (addr === undefined || port === undefined) { + throw new FS.ErrnoError(17); + } + } else { + // connection-based sockets will only use the bound + addr = sock.daddr; + port = sock.dport; + } + + // find the peer for the destination address + var dest = SOCKFS.websocket_sock_ops.getPeer(sock, addr, port); + + // early out if not connected with a connection-based socket + if (sock.type === 1) { + if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) { + throw new FS.ErrnoError(53); + } + } + + // create a copy of the incoming data to send, as the WebSocket API + // doesn't work entirely with an ArrayBufferView, it'll just send + // the entire underlying buffer + if (ArrayBuffer.isView(buffer)) { + offset += buffer.byteOffset; + buffer = buffer.buffer; + } + + var data = buffer.slice(offset, offset + length); + + // if we don't have a cached connectionless UDP datagram connection, or + // the TCP socket is still connecting, queue the message to be sent upon + // connect, and lie, saying the data was sent now. + if (!dest || dest.socket.readyState !== dest.socket.OPEN) { + // if we're not connected, open a new connection + if (sock.type === 2) { + if (!dest || dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) { + dest = SOCKFS.websocket_sock_ops.createPeer(sock, addr, port); + } + } + dest.msg_send_queue.push(data); + return length; + } + + try { + // send the actual data + dest.socket.send(data); + return length; + } catch (e) { + throw new FS.ErrnoError(28); + } + }, + recvmsg(sock, length, flags) { + // http://pubs.opengroup.org/onlinepubs/7908799/xns/recvmsg.html + if (sock.type === 1 && sock.server) { + // tcp servers should not be recv()'ing on the listen socket + throw new FS.ErrnoError(53); + } + + var queued = sock.recv_queue.shift(); + if (!queued) { + if (sock.type === 1) { + var dest = SOCKFS.websocket_sock_ops.getPeer(sock, sock.daddr, sock.dport); + + if (!dest) { + // if we have a destination address but are not connected, error out + throw new FS.ErrnoError(53); + } + if (dest.socket.readyState === dest.socket.CLOSING || dest.socket.readyState === dest.socket.CLOSED) { + // return null if the socket has closed + return null; + } + // else, our socket is in a valid state but truly has nothing available + throw new FS.ErrnoError(6); + } + throw new FS.ErrnoError(6); + } + + // queued.data will be an ArrayBuffer if it's unadulterated, but if it's + // requeued TCP data it'll be an ArrayBufferView + var queuedLength = queued.data.byteLength || queued.data.length; + var queuedOffset = queued.data.byteOffset || 0; + var queuedBuffer = queued.data.buffer || queued.data; + var bytesRead = Math.min(length, queuedLength); + var res = { + buffer: new Uint8Array(queuedBuffer, queuedOffset, bytesRead), + addr: queued.addr, + port: queued.port + }; + + // push back any unread data for TCP connections + if (flags&2) {bytesRead = 0;} if (sock.type === 1 && bytesRead < queuedLength) { + var bytesRemaining = queuedLength - bytesRead; + queued.data = new Uint8Array(queuedBuffer, queuedOffset + bytesRead, bytesRemaining); + sock.recv_queue.unshift(queued); + } + + return res; + }, + }, + }; + + var getSocketFromFD = (fd) => { + var socket = SOCKFS.getSocket(fd); + if (!socket) throw new FS.ErrnoError(8); + return socket; + }; + + var inetPton4 = (str) => { + var b = str.split('.'); + for (var i = 0; i < 4; i++) { + var tmp = Number(b[i]); + if (isNaN(tmp)) return null; + b[i] = tmp; + } + return (b[0] | (b[1] << 8) | (b[2] << 16) | (b[3] << 24)) >>> 0; + }; + + var inetPton6 = (str) => { + var words; + var w, offset, z, i; + /* http://home.deds.nl/~aeron/regex/ */ + var valid6regx = /^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i + var parts = []; + if (!valid6regx.test(str)) { + return null; + } + if (str === "::") { + return [0, 0, 0, 0, 0, 0, 0, 0]; + } + // Z placeholder to keep track of zeros when splitting the string on ":" + if (str.startsWith("::")) { + str = str.replace("::", "Z:"); // leading zeros case + } else { + str = str.replace("::", ":Z:"); + } + + if (str.indexOf(".") > 0) { + // parse IPv4 embedded stress + str = str.replace(new RegExp('[.]', 'g'), ":"); + words = str.split(":"); + words[words.length-4] = Number(words[words.length-4]) + Number(words[words.length-3])*256; + words[words.length-3] = Number(words[words.length-2]) + Number(words[words.length-1])*256; + words = words.slice(0, words.length-2); + } else { + words = str.split(":"); + } + + offset = 0; z = 0; + for (w=0; w < words.length; w++) { + if (typeof words[w] == 'string') { + if (words[w] === 'Z') { + // compressed zeros - write appropriate number of zero words + for (z = 0; z < (8 - words.length+1); z++) { + parts[w+z] = 0; + } + offset = z-1; + } else { + // parse hex to field to 16-bit value and write it in network byte-order + parts[w+offset] = _htons(parseInt(words[w],16)); + } + } else { + // parsed IPv4 words + parts[w+offset] = words[w]; + } + } + return [ + (parts[1] << 16) | parts[0], + (parts[3] << 16) | parts[2], + (parts[5] << 16) | parts[4], + (parts[7] << 16) | parts[6] + ]; + }; + + + /** @param {number=} addrlen */ + var writeSockaddr = (sa, family, addr, port, addrlen) => { + switch (family) { + case 2: + addr = inetPton4(addr); + zeroMemory(sa, 16); + if (addrlen) { + HEAP32[((addrlen)>>2)] = 16; + } + HEAP16[((sa)>>1)] = family; + HEAP32[(((sa)+(4))>>2)] = addr; + HEAP16[(((sa)+(2))>>1)] = _htons(port); + break; + case 10: + addr = inetPton6(addr); + zeroMemory(sa, 28); + if (addrlen) { + HEAP32[((addrlen)>>2)] = 28; + } + HEAP32[((sa)>>2)] = family; + HEAP32[(((sa)+(8))>>2)] = addr[0]; + HEAP32[(((sa)+(12))>>2)] = addr[1]; + HEAP32[(((sa)+(16))>>2)] = addr[2]; + HEAP32[(((sa)+(20))>>2)] = addr[3]; + HEAP16[(((sa)+(2))>>1)] = _htons(port); + break; + default: + return 5; + } + return 0; + }; + + + var DNS = { + address_map:{ + id:1, + addrs:{ + }, + names:{ + }, + }, + lookup_name(name) { + // If the name is already a valid ipv4 / ipv6 address, don't generate a fake one. + var res = inetPton4(name); + if (res !== null) { + return name; + } + res = inetPton6(name); + if (res !== null) { + return name; + } + + // See if this name is already mapped. + var addr; + + if (DNS.address_map.addrs[name]) { + addr = DNS.address_map.addrs[name]; + } else { + var id = DNS.address_map.id++; + + addr = '172.29.' + (id & 0xff) + '.' + (id & 0xff00); + + DNS.address_map.names[addr] = name; + DNS.address_map.addrs[name] = addr; + } + + return addr; + }, + lookup_addr(addr) { + if (DNS.address_map.names[addr]) { + return DNS.address_map.names[addr]; + } + + return null; + }, + }; + function ___syscall_accept4(fd, addr, addrlen, flags, d1, d2) { + try { + + var sock = getSocketFromFD(fd); + var newsock = sock.sock_ops.accept(sock); + if (addr) { + var errno = writeSockaddr(addr, newsock.family, DNS.lookup_name(newsock.daddr), newsock.dport, addrlen); + } + return newsock.stream.fd; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_accept4.sig = 'iippiii'; + + + var inetNtop4 = (addr) => + (addr & 0xff) + '.' + ((addr >> 8) & 0xff) + '.' + ((addr >> 16) & 0xff) + '.' + ((addr >> 24) & 0xff); + + + var inetNtop6 = (ints) => { + // ref: http://www.ietf.org/rfc/rfc2373.txt - section 2.5.4 + // Format for IPv4 compatible and mapped 128-bit IPv6 Addresses + // 128-bits are split into eight 16-bit words + // stored in network byte order (big-endian) + // | 80 bits | 16 | 32 bits | + // +-----------------------------------------------------------------+ + // | 10 bytes | 2 | 4 bytes | + // +--------------------------------------+--------------------------+ + // + 5 words | 1 | 2 words | + // +--------------------------------------+--------------------------+ + // |0000..............................0000|0000| IPv4 ADDRESS | (compatible) + // +--------------------------------------+----+---------------------+ + // |0000..............................0000|FFFF| IPv4 ADDRESS | (mapped) + // +--------------------------------------+----+---------------------+ + var str = ""; + var word = 0; + var longest = 0; + var lastzero = 0; + var zstart = 0; + var len = 0; + var i = 0; + var parts = [ + ints[0] & 0xffff, + (ints[0] >> 16), + ints[1] & 0xffff, + (ints[1] >> 16), + ints[2] & 0xffff, + (ints[2] >> 16), + ints[3] & 0xffff, + (ints[3] >> 16) + ]; + + // Handle IPv4-compatible, IPv4-mapped, loopback and any/unspecified addresses + + var hasipv4 = true; + var v4part = ""; + // check if the 10 high-order bytes are all zeros (first 5 words) + for (i = 0; i < 5; i++) { + if (parts[i] !== 0) { hasipv4 = false; break; } + } + + if (hasipv4) { + // low-order 32-bits store an IPv4 address (bytes 13 to 16) (last 2 words) + v4part = inetNtop4(parts[6] | (parts[7] << 16)); + // IPv4-mapped IPv6 address if 16-bit value (bytes 11 and 12) == 0xFFFF (6th word) + if (parts[5] === -1) { + str = "::ffff:"; + str += v4part; + return str; + } + // IPv4-compatible IPv6 address if 16-bit value (bytes 11 and 12) == 0x0000 (6th word) + if (parts[5] === 0) { + str = "::"; + //special case IPv6 addresses + if (v4part === "0.0.0.0") v4part = ""; // any/unspecified address + if (v4part === "0.0.0.1") v4part = "1";// loopback address + str += v4part; + return str; + } + } + + // Handle all other IPv6 addresses + + // first run to find the longest contiguous zero words + for (word = 0; word < 8; word++) { + if (parts[word] === 0) { + if (word - lastzero > 1) { + len = 0; + } + lastzero = word; + len++; + } + if (len > longest) { + longest = len; + zstart = word - longest + 1; + } + } + + for (word = 0; word < 8; word++) { + if (longest > 1) { + // compress contiguous zeros - to produce "::" + if (parts[word] === 0 && word >= zstart && word < (zstart + longest) ) { + if (word === zstart) { + str += ":"; + if (zstart === 0) str += ":"; //leading zeros case + } + continue; + } + } + // converts 16-bit words from big-endian to little-endian before converting to hex string + str += Number(_ntohs(parts[word] & 0xffff)).toString(16); + str += word < 7 ? ":" : ""; + } + return str; + }; + + var readSockaddr = (sa, salen) => { + // family / port offsets are common to both sockaddr_in and sockaddr_in6 + var family = HEAP16[((sa)>>1)]; + var port = _ntohs(HEAPU16[(((sa)+(2))>>1)]); + var addr; + + switch (family) { + case 2: + if (salen !== 16) { + return { errno: 28 }; + } + addr = HEAP32[(((sa)+(4))>>2)]; + addr = inetNtop4(addr); + break; + case 10: + if (salen !== 28) { + return { errno: 28 }; + } + addr = [ + HEAP32[(((sa)+(8))>>2)], + HEAP32[(((sa)+(12))>>2)], + HEAP32[(((sa)+(16))>>2)], + HEAP32[(((sa)+(20))>>2)] + ]; + addr = inetNtop6(addr); + break; + default: + return { errno: 5 }; + } + + return { family: family, addr: addr, port: port }; + }; + + + var getSocketAddress = (addrp, addrlen) => { + var info = readSockaddr(addrp, addrlen); + if (info.errno) throw new FS.ErrnoError(info.errno); + info.addr = DNS.lookup_addr(info.addr) || info.addr; + return info; + }; + function ___syscall_bind(fd, addr, addrlen, d1, d2, d3) { + try { + + var sock = getSocketFromFD(fd); + var info = getSocketAddress(addr, addrlen); + sock.sock_ops.bind(sock, info.addr, info.port); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_bind.sig = 'iippiii'; + + function ___syscall_chdir(path) { + try { + + path = SYSCALLS.getStr(path); + FS.chdir(path); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_chdir.sig = 'ip'; + + function ___syscall_chmod(path, mode) { + try { + + path = SYSCALLS.getStr(path); + FS.chmod(path, mode); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_chmod.sig = 'ipi'; + + + function ___syscall_connect(fd, addr, addrlen, d1, d2, d3) { + try { + + var sock = getSocketFromFD(fd); + var info = getSocketAddress(addr, addrlen); + sock.sock_ops.connect(sock, info.addr, info.port); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_connect.sig = 'iippiii'; + + function ___syscall_dup(fd) { + try { + + var old = SYSCALLS.getStreamFromFD(fd); + return FS.dupStream(old).fd; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_dup.sig = 'ii'; + + function ___syscall_dup3(fd, newfd, flags) { + try { + + var old = SYSCALLS.getStreamFromFD(fd); + if (old.fd === newfd) return -28; + // Check newfd is within range of valid open file descriptors. + if (newfd < 0 || newfd >= FS.MAX_OPEN_FDS) return -8; + var existing = FS.getStream(newfd); + if (existing) FS.close(existing); + return FS.dupStream(old, newfd).fd; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_dup3.sig = 'iiii'; + + function ___syscall_faccessat(dirfd, path, amode, flags) { + try { + + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + if (amode & ~7) { + // need a valid mode + return -28; + } + var lookup = FS.lookupPath(path, { follow: true }); + var node = lookup.node; + if (!node) { + return -44; + } + var perms = ''; + if (amode & 4) perms += 'r'; + if (amode & 2) perms += 'w'; + if (amode & 1) perms += 'x'; + if (perms /* otherwise, they've just passed F_OK */ && FS.nodePermissions(node, perms)) { + return -2; + } + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_faccessat.sig = 'iipii'; + + var ___syscall_fadvise64 = (fd, offset, len, advice) => 0; + ___syscall_fadvise64.sig = 'iijji'; + + var INT53_MAX = 9007199254740992; + + var INT53_MIN = -9007199254740992; + var bigintToI53Checked = (num) => (num < INT53_MIN || num > INT53_MAX) ? NaN : Number(num); + function ___syscall_fallocate(fd, mode, offset, len) { + offset = bigintToI53Checked(offset); + len = bigintToI53Checked(len); + + + try { + + if (isNaN(offset) || isNaN(len)) return -61; + if (mode != 0) { + return -138 + } + if (offset < 0 || len < 0) { + return -28 + } + // We only support mode == 0, which means we can implement fallocate + // in terms of ftruncate. + var oldSize = FS.fstat(fd).size; + var newSize = offset + len; + if (newSize > oldSize) { + FS.ftruncate(fd, newSize); + } + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + ; + } + ___syscall_fallocate.sig = 'iiijj'; + + function ___syscall_fchdir(fd) { + try { + + var stream = SYSCALLS.getStreamFromFD(fd); + FS.chdir(stream.path); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_fchdir.sig = 'ii'; + + function ___syscall_fchmod(fd, mode) { + try { + + FS.fchmod(fd, mode); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_fchmod.sig = 'iii'; + + function ___syscall_fchmodat2(dirfd, path, mode, flags) { + try { + + var nofollow = flags & 256; + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + FS.chmod(path, mode, nofollow); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_fchmodat2.sig = 'iipii'; + + function ___syscall_fchown32(fd, owner, group) { + try { + + FS.fchown(fd, owner, group); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_fchown32.sig = 'iiii'; + + function ___syscall_fchownat(dirfd, path, owner, group, flags) { + try { + + path = SYSCALLS.getStr(path); + var nofollow = flags & 256; + flags = flags & (~256); + path = SYSCALLS.calculateAt(dirfd, path); + (nofollow ? FS.lchown : FS.chown)(path, owner, group); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_fchownat.sig = 'iipiii'; + + var syscallGetVarargI = () => { + // the `+` prepended here is necessary to convince the JSCompiler that varargs is indeed a number. + var ret = HEAP32[((+SYSCALLS.varargs)>>2)]; + SYSCALLS.varargs += 4; + return ret; + }; + var syscallGetVarargP = syscallGetVarargI; + + + + + + + + + + + + + + var allocateUTF8OnStack = (...args) => stringToUTF8OnStack(...args); + + + var PHPWASM = { + O_APPEND:1024, + O_NONBLOCK:2048, + POLLHUP:16, + SETFL_MASK:3072, + init:function (phpWasmInitOptions) { + Module['ENV'] = Module['ENV'] || {}; + // Ensure a platform-level bin directory for a fallback `php` binary. + Module['ENV']['PATH'] = [ + Module['ENV']['PATH'], + '/internal/shared/bin', + ] + .filter(Boolean) + .join(':'); + + // The /request directory is required by the C module. It's where the + // stdout, stderr, and headers information are written for the JavaScript + // code to read later on. This is per-request state that is isolated to a + // single PHP process. + FS.mkdir('/request'); + // The /internal directory is shared amongst all PHP processes + // and contains the php.ini, constants definitions, etc. + FS.mkdir('/internal'); + + if (phpWasmInitOptions?.nativeInternalDirPath) { + FS.mount( + FS.filesystems.NODEFS, + { root: phpWasmInitOptions.nativeInternalDirPath }, + '/internal' + ); + } + + // The files from the shared directory are shared between all the + // PHP processes managed by PHPProcessManager. + FS.mkdirTree('/internal/shared'); + + // The files from the preload directory are preloaded using the + // auto_prepend_file php.ini directive. + FS.mkdirTree('/internal/shared/preload'); + // Platform-level bin directory for a fallback `php` binary. Without it, + // PHP may not populate the PHP_BINARY constant. + FS.mkdirTree('/internal/shared/bin'); + const originalOnRuntimeInitialized = Module['onRuntimeInitialized']; + Module['onRuntimeInitialized'] = () => { + const { node: phpBinaryNode } = FS.lookupPath( + '/internal/shared/bin/php', + { noent_okay: true }, + ); + if (!phpBinaryNode) { + // Dummy PHP binary for PHP to populate the PHP_BINARY constant. + FS.writeFile( + '/internal/shared/bin/php', + new TextEncoder().encode('#!/bin/sh\nphp "$@"') + ); + // It must be executable to be used by PHP. + FS.chmod('/internal/shared/bin/php', 0o755); + } + originalOnRuntimeInitialized(); + }; + + // Create stdout and stderr devices. We can't just use Emscripten's + // default stdout and stderr devices because they stop processing data + // on the first null byte. However, when dealing with binary data, + // null bytes are valid and common. + FS.registerDevice(FS.makedev(64, 0), { + open: () => {}, + close: () => {}, + read: () => 0, + write: (stream, buffer, offset, length, pos) => { + const chunk = buffer.subarray(offset, offset + length); + PHPWASM.onStdout(chunk); + return length; + }, + }); + FS.mkdev('/request/stdout', FS.makedev(64, 0)); + + FS.registerDevice(FS.makedev(63, 0), { + open: () => {}, + close: () => {}, + read: () => 0, + write: (stream, buffer, offset, length, pos) => { + const chunk = buffer.subarray(offset, offset + length); + PHPWASM.onStderr(chunk); + return length; + }, + }); + FS.mkdev('/request/stderr', FS.makedev(63, 0)); + + FS.registerDevice(FS.makedev(62, 0), { + open: () => {}, + close: () => {}, + read: () => 0, + write: (stream, buffer, offset, length, pos) => { + const chunk = buffer.subarray(offset, offset + length); + PHPWASM.onHeaders(chunk); + return length; + }, + }); + FS.mkdev('/request/headers', FS.makedev(62, 0)); + + // Handle events. + PHPWASM.EventEmitter = ENVIRONMENT_IS_NODE + ? require('events').EventEmitter + : class EventEmitter { + constructor() { + this.listeners = {}; + } + emit(eventName, data) { + if (this.listeners[eventName]) { + this.listeners[eventName].forEach( + (callback) => { + callback(data); + } + ); + } + } + once(eventName, callback) { + const self = this; + function removedCallback() { + callback(...arguments); + self.removeListener(eventName, removedCallback); + } + this.on(eventName, removedCallback); + } + removeAllListeners(eventName) { + if (eventName) { + delete this.listeners[eventName]; + } else { + this.listeners = {}; + } + } + removeListener(eventName, callback) { + if (this.listeners[eventName]) { + const idx = + this.listeners[eventName].indexOf(callback); + if (idx !== -1) { + this.listeners[eventName].splice(idx, 1); + } + } + } + }; + + PHPWASM.processTable = {}; + + PHPWASM.input_devices = {}; + const originalWrite = TTY.stream_ops.write; + TTY.stream_ops.write = function (stream, ...rest) { + const retval = originalWrite(stream, ...rest); + // Implicit flush since PHP's fflush() doesn't seem to trigger the fsync event + // @TODO: Fix this at the wasm level + stream.tty.ops.fsync(stream.tty); + return retval; + }; + const originalPutChar = TTY.stream_ops.put_char; + TTY.stream_ops.put_char = function (tty, val) { + /** + * Buffer newlines that Emscripten normally ignores. + * + * Emscripten doesn't do it by default because its default + * print function is console.log that implicitly adds a newline. We are overwriting + * it with an environment-specific function that outputs exaclty what it was given, + * e.g. in Node.js it's process.stdout.write(). Therefore, we need to mak sure + * all the newlines make it to the output buffer. + */ + if (val === 10) tty.output.push(val); + return originalPutChar(tty, val); + }; + }, + onHeaders:function (chunk) { + if (Module['onHeaders']) { + Module['onHeaders'](chunk); + return; + } + console.log('headers', { chunk }); + }, + onStdout:function (chunk) { + if (Module['onStdout']) { + Module['onStdout'](chunk); + return; + } + if (ENVIRONMENT_IS_NODE) { + process.stdout.write(chunk); + } else { + console.log('stdout', { chunk }); + } + }, + onStderr:function (chunk) { + if (Module['onStderr']) { + Module['onStderr'](chunk); + return; + } + if (ENVIRONMENT_IS_NODE) { + process.stderr.write(chunk); + } else { + console.warn('stderr', { chunk }); + } + }, + getAllWebSockets:function (sock) { + const webSockets = /* @__PURE__ */ new Set(); + if (sock.server) { + sock.server.clients.forEach((ws) => { + webSockets.add(ws); + }); + } + for (const peer of PHPWASM.getAllPeers(sock)) { + webSockets.add(peer.socket); + } + return Array.from(webSockets); + }, + getAllPeers:function (sock) { + const peers = new Set(); + if (sock.server) { + sock.pending + .filter((pending) => pending.peers) + .forEach((pending) => { + for (const peer of Object.values(pending.peers)) { + peers.add(peer); + } + }); + } + if (sock.peers) { + for (const peer of Object.values(sock.peers)) { + peers.add(peer); + } + } + return Array.from(peers); + }, + awaitData:function (ws) { + return PHPWASM.awaitEvent(ws, 'message'); + }, + awaitConnection:function (ws) { + if (ws.OPEN === ws.readyState) { + return [Promise.resolve(), PHPWASM.noop]; + } + return PHPWASM.awaitEvent(ws, 'open'); + }, + awaitClose:function (ws) { + if ([ws.CLOSING, ws.CLOSED].includes(ws.readyState)) { + return [Promise.resolve(), PHPWASM.noop]; + } + return PHPWASM.awaitEvent(ws, 'close'); + }, + awaitError:function (ws) { + if ([ws.CLOSING, ws.CLOSED].includes(ws.readyState)) { + return [Promise.resolve(), PHPWASM.noop]; + } + return PHPWASM.awaitEvent(ws, 'error'); + }, + awaitEvent:function (ws, event) { + let resolve; + const listener = () => { + resolve(); + }; + const promise = new Promise(function (_resolve) { + resolve = _resolve; + ws.once(event, listener); + }); + const cancel = () => { + ws.removeListener(event, listener); + // Rejecting the promises bubbles up and kills the entire + // node process. Let's resolve them on the next tick instead + // to give the caller some space to unbind any handlers. + setTimeout(resolve); + }; + return [promise, cancel]; + }, + noop:function () {}, + spawnProcess:function (command, args, options) { + if (Module['spawnProcess']) { + const spawnedPromise = Module['spawnProcess']( + command, + args, + options + ); + return Promise.resolve(spawnedPromise).then(function (spawned) { + if (!spawned || !spawned.on) { + throw new Error( + 'spawnProcess() must return an EventEmitter but returned a different type.' + ); + } + return spawned; + }); + } + + if (ENVIRONMENT_IS_NODE) { + return require('child_process').spawn(command, args, { + ...options, + shell: true, + stdio: ['pipe', 'pipe', 'pipe'], + }); + } + const e = new Error( + 'popen(), proc_open() etc. are unsupported in the browser. Call php.setSpawnHandler() ' + + 'and provide a callback to handle spawning processes, or disable a popen(), proc_open() ' + + 'and similar functions via php.ini.' + ); + e.code = 'SPAWN_UNSUPPORTED'; + throw e; + }, + shutdownSocket:function (socketd, how) { + // This implementation only supports websockets at the moment + const sock = getSocketFromFD(socketd); + const peer = Object.values(sock.peers)[0]; + + if (!peer) { + return -1; + } + + try { + peer.socket.close(); + SOCKFS.websocket_sock_ops.removePeer(sock, peer); + return 0; + } catch (e) { + console.log('Socket shutdown error', e); + return -1; + } + }, + }; + + function _js_getpid() { + return PHPLoader.processId ?? 42; + } + + + function _js_wasm_trace(format, ...args) { + if (PHPLoader.trace instanceof Function) { + PHPLoader.trace(_js_getpid(), format, ...args); + } + } + + + + + function _fd_close(fd) { + // We have to get the VFS path from the file descriptor + // before closing it. + const [vfsPath, vfsPathResolutionErrno] = + locking.get_vfs_path_from_fd(fd); + + const fdCloseResult = _builtin_fd_close(fd); + if (fdCloseResult !== 0 || !locking.maybeLockedFds.has(fd)) { + _js_wasm_trace('fd_close(%d) result %d', fd, fdCloseResult); + return fdCloseResult; + } + + if (vfsPathResolutionErrno !== 0) { + _js_wasm_trace( + 'fd_close(%d) get_vfs_path_from_fd error %d', + fd, + vfsPathResolutionErrno + ); + /* + * It looks like the file may have had an associated lock, + * but since we cannot look up the path, + * there is nothing more for us to do. + * + * NOTE: This seems possible for files that are locked and + * then unlinked before close. It is an opportunity for a + * lock to be orphaned in the lock manager. + * @TODO: Explore how to ensure cleanup in this case. + */ + return fdCloseResult; + } + + try { + const nativeFilePath = + locking.get_native_path_from_vfs_path(vfsPath); + PHPLoader.fileLockManager + .releaseLocksForProcessFd( + PHPLoader.processId, + fd, + nativeFilePath + ); + _js_wasm_trace( + 'fd_close(%d) release locks success', + fd + ); + } catch (e) { + _js_wasm_trace("fd_close(%d) error '%s'", fd, e); + } finally { + locking.maybeLockedFds.delete(fd); + } + return fdCloseResult; + } + _fd_close.sig = 'ii'; + function _builtin_fd_close(fd) { + try { + + var stream = SYSCALLS.getStreamFromFD(fd); + FS.close(stream); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + } + + function _builtin_fcntl64(fd, cmd, varargs) { + SYSCALLS.varargs = varargs; + try { + + var stream = SYSCALLS.getStreamFromFD(fd); + switch (cmd) { + case 0: { + var arg = syscallGetVarargI(); + if (arg < 0) { + return -28; + } + while (FS.streams[arg]) { + arg++; + } + var newStream; + newStream = FS.dupStream(stream, arg); + return newStream.fd; + } + case 1: + case 2: + return 0; // FD_CLOEXEC makes no sense for a single process. + case 3: + return stream.flags; + case 4: { + var arg = syscallGetVarargI(); + stream.flags |= arg; + return 0; + } + case 12: { + var arg = syscallGetVarargP(); + var offset = 0; + // We're always unlocked. + HEAP16[(((arg)+(offset))>>1)] = 2; + return 0; + } + case 13: + case 14: + // Pretend that the locking is successful. These are process-level locks, + // and Emscripten programs are a single process. If we supported linking a + // filesystem between programs, we'd need to do more here. + // See https://github.com/emscripten-core/emscripten/issues/23697 + return 0; + } + return -28; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + + + + + var locking = { + maybeLockedFds:new Set, + F_RDLCK:0, + F_WRLCK:1, + F_UNLCK:2, + lockStateToFcntl:{ + shared:0, + exclusive:1, + unlocked:2, + }, + fcntlToLockState:{ + 0:"shared", + 1:"exclusive", + 2:"unlocked", + }, + is_path_to_shared_fs(path) { + _js_wasm_trace('is_path_to_shared_fs(%s)', path); + const { node } = FS.lookupPath( + path, + { noent_okay: true }, + ); + if (node.mount.type !== PROXYFS) { + return !!node.isSharedFS; + } + + // This looks like a PROXYFS node. Let's try a lookup. + const nodePath = PROXYFS.realPath(node); + const backingFs = node?.mount?.opts?.fs; + if (backingFs) { + // Tolerate ENOENT because looking up a MEMFS node by path always fails. + const { node: backingNode } = backingFs.lookupPath( + nodePath, + { noent_okay: true } + ); + return !!backingNode?.isSharedFS; + } + + return false; + }, + get_fd_access_mode(fd) { + const emscripten_F_GETFL = Number('3'); + const emscripten_O_ACCMODE = Number('2097155'); + + return ( + _builtin_fcntl64(fd, emscripten_F_GETFL) & emscripten_O_ACCMODE + ); + }, + get_vfs_path_from_fd(fd) { + try { + return [FS.readlink(`/proc/self/fd/${fd}`), 0]; + } catch (error) { + return [null, ERRNO_CODES.EBADF]; + } + }, + get_native_path_from_vfs_path(vfsPath) { + const { node } = FS.lookupPath(vfsPath, { + noent_okay: true, + }); + if (!node) { + throw new Error(`No node found for VFS path ${vfsPath}`); + } + if (node.mount.type === NODEFS) { + return NODEFS.realPath(node); + } else if (node.mount.type === PROXYFS) { + // TODO: Tolerate ENOENT here? + const { node: backingNode, path: backingPath } = node.mount.opts.fs.lookupPath(vfsPath); + _js_wasm_trace('backingNode for %s: %s', vfsPath, backingPath, backingNode); + return backingNode.mount.type.realPath(backingNode); + } else { + throw new Error(`Unsupported filesystem type for path ${vfsPath}`); + } + }, + check_lock_params(fd, l_type) { + const emscripten_O_RDONLY = Number('0'); + const emscripten_O_WRONLY = Number('1'); + + const accessMode = locking.get_fd_access_mode(fd); + if ( + (l_type === locking.F_WRLCK && + accessMode === emscripten_O_RDONLY) || + (l_type === locking.F_RDLCK && + accessMode === emscripten_O_WRONLY) + ) { + return ERRNO_CODES.EBADF; + } + + return 0; + }, + }; + + + + + function ___syscall_fcntl64(fd, cmd, varargs) { + if (!PHPLoader.fileLockManager) { + return _builtin_fcntl64(fd, cmd, varargs); + } + // Necessary to use varargs accessor + SYSCALLS.varargs = varargs; + + // These constants are replaced by Emscripten during the build process + const emscripten_F_SETFL = Number('4'); + const emscripten_F_GETLK = Number('12'); + const emscripten_F_SETLK = Number('13'); + const emscripten_F_SETLKW = Number('14'); + const emscripten_SEEK_SET = Number('0'); + + // NOTE: With the exception of l_type, these offsets are not exposed to + // JS by Emscripten, so we hardcode them here. + const emscripten_flock_l_type_offset = 0; + const emscripten_flock_l_whence_offset = 2; + const emscripten_flock_l_start_offset = 8; + const emscripten_flock_l_len_offset = 16; + const emscripten_flock_l_pid_offset = 24; + + /** + * Read the flock struct at the given address. + * + * @param {bigint} flockStructAddress - the address of the flock struct + * @returns the flock struct + */ + function read_flock_struct(flockStructAddress) { + /* + * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, + * we need to adjust offsets to address the word size of each HEAP. + * + * For example, an offset of 64 bytes is the following for each HEAP: + * - HEAP8: 64 (the 64th byte) + * - HEAP16: 32 (the 32nd 16-bit word) + * - HEAP32: 16 (the 16th 32-bit word) + * - HEAP64: 8 (the 8th 64-bit word) + * + * We get a word offset by dividing the byte offset by the word size. + */ + return { + l_type: HEAP16[ + // Shift right by 1 to divide by 2^1. + (flockStructAddress + emscripten_flock_l_type_offset) >> + 1 + ], + l_whence: + HEAP16[ + // Shift right by 1 to divide by 2^1. + (flockStructAddress + + emscripten_flock_l_whence_offset) >> + 1 + ], + l_start: + HEAP64[ + // Shift right by 3 to divide by 2^3. + (flockStructAddress + + emscripten_flock_l_start_offset) >> + 3 + ], + l_len: HEAP64[ + // Shift right by 3 to divide by 2^3. + (flockStructAddress + emscripten_flock_l_len_offset) >> + 3 + ], + l_pid: HEAP32[ + // Shift right by 2 to divide by 2^2. + (flockStructAddress + emscripten_flock_l_pid_offset) >> + 2 + ], + }; + } + + /** + * Update the flock struct at the given address with the given fields. + * + * @param {bigint} flockStructAddress - the address of the flock struct + * @param {object} fields - the fields to update + */ + function update_flock_struct(flockStructAddress, fields) { + /* + * NOTE: Since we are using HEAP vars like HEAP16 and HEAP64, + * we need to adjust offsets to address the word size of each HEAP. + * + * For example, an offset of 64 bytes is the following for each HEAP: + * - HEAP8: 64 (the 64th byte) + * - HEAP16: 32 (the 32nd 16-bit word) + * - HEAP32: 16 (the 16th 32-bit word) + * - HEAP64: 8 (the 8th 64-bit word) + * + * We get a word offset by dividing the byte offset by the word size. + */ + if (fields.l_type !== undefined) { + HEAP16[ + // Shift right by 1 to divide by 2^1. + (flockStructAddress + emscripten_flock_l_type_offset) >> + 1 + ] = fields.l_type; + } + if (fields.l_whence !== undefined) { + HEAP16[ + // Shift right by 1 to divide by 2^1. + (flockStructAddress + + emscripten_flock_l_whence_offset) >> + 1 + ] = fields.l_whence; + } + if (fields.l_start !== undefined) { + HEAP64[ + // Shift right by 3 to divide by 2^3. + (flockStructAddress + + emscripten_flock_l_start_offset) >> + 3 + ] = fields.l_start; + } + if (fields.l_len !== undefined) { + HEAP64[ + // Shift right by 3 to divide by 2^3. + (flockStructAddress + emscripten_flock_l_len_offset) >> + 3 + ] = fields.l_len; + } + if (fields.l_pid !== undefined) { + HEAP32[ + // Shift right by 2 to divide by 2^2. + (flockStructAddress + emscripten_flock_l_pid_offset) >> + 2 + ] = fields.l_pid; + } + } + + /** + * Resolve the base address of the range depending on the whence and start offset. + * + * @param {number} fd - the file descriptor + * @param {number} whence - what the start offset is relative to + * @param {bigint} startOffset - the offset from the whence + * @returns The resolved offset and the errno. If there is an error, + * the resolved offset is null, and the errno is non-zero. + */ + function get_base_address(fd, whence, startOffset) { + let baseAddress; + switch (whence) { + case emscripten_SEEK_SET: + baseAddress = 0n; + break; + case emscripten_SEEK_CUR: + baseAddress = FS.lseek(fd, 0, whence); + break; + case emscripten_SEEK_END: + baseAddress = _wasm_get_end_offset(fd); + break; + default: + return [null, ERRNO_CODES.EINVAL]; + } + + if (baseAddress == -1) { + // We cannot resolve the offset within the file. + // Let's treat this as a problem with the file descriptor. + return [null, ERRNO_CODES.EBADF]; + } + + const resolvedOffset = baseAddress + startOffset; + if (resolvedOffset < 0) { + // This is not a valid offset. Report args as invalid. + return [null, ERRNO_CODES.EINVAL]; + } + + return [resolvedOffset, 0]; + } + + const pid = PHPLoader.processId; + switch (cmd) { + case emscripten_F_GETLK: { + _js_wasm_trace('fcntl(%d, F_GETLK)', fd); + let vfsPath; + let errno; + + [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); + if (errno !== 0) { + _js_wasm_trace( + 'fcntl(%d, F_GETLK) %s get_vfs_path_from_fd errno %d', + fd, + vfsPath, + errno + ); + return -ERRNO_CODES.EBADF; + } + + const flockStructAddr = syscallGetVarargP(); + + if (!locking.is_path_to_shared_fs(vfsPath)) { + _js_wasm_trace( + "fcntl(%d, F_GETLK) locking is not implemented for non-NodeFS path '%s'", + fd, + vfsPath + ); + + // If not a NodeFS path, we can't lock it. + // Default to succeeding as Emscripten does. + update_flock_struct(flockStructAddr, { + l_type: F_UNLCK, + }); + return 0; + } + + const flockStruct = read_flock_struct(flockStructAddr); + + if (!(flockStruct.l_type in locking.fcntlToLockState)) { + return -ERRNO_CODES.EINVAL; + } + + errno = locking.check_lock_params(fd, flockStruct.l_type); + if (errno !== 0) { + _js_wasm_trace( + 'fcntl(%d, F_GETLK) %s check_lock_params errno %d', + fd, + vfsPath, + errno + ); + return -ERRNO_CODES.EINVAL; + } + + const requestedLockType = + locking.fcntlToLockState[flockStruct.l_type]; + let absoluteStartOffset; + [absoluteStartOffset, errno] = get_base_address( + fd, + flockStruct.l_whence, + flockStruct.l_start + ); + if (errno !== 0) { + _js_wasm_trace( + 'fcntl(%d, F_GETLK) %s get_base_address errno %d', + fd, + vfsPath, + errno + ); + return -ERRNO_CODES.EINVAL; + } + + try { + const nativeFilePath = + locking.get_native_path_from_vfs_path(vfsPath); + const conflictingLock = + PHPLoader.fileLockManager + .findFirstConflictingByteRangeLock(nativeFilePath, { + type: requestedLockType, + start: absoluteStartOffset, + end: absoluteStartOffset + flockStruct.l_len, + pid, + }) + ; + if (conflictingLock === undefined) { + _js_wasm_trace( + 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=unlocked start=0x%x end=0x%x', + fd, + vfsPath, + absoluteStartOffset, + absoluteStartOffset + flockStruct.l_len + ); + + update_flock_struct(flockStructAddr, { + l_type: F_UNLCK, + }); + return 0; + } + + _js_wasm_trace( + 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock type=%s start=0x%x end=0x%x conflictingLock %d', + fd, + vfsPath, + conflictingLock.type, + conflictingLock.start, + conflictingLock.end, + conflictingLock.pid + ); + + const fcntlLockState = + locking.lockStateToFcntl[conflictingLock.type]; + update_flock_struct(flockStructAddr, { + l_type: fcntlLockState, + l_whence: emscripten_SEEK_SET, + l_start: conflictingLock.start, + l_len: + conflictingLock.end - conflictingLock.start, + l_pid: conflictingLock.pid, + }); + return 0; + } catch (e) { + _js_wasm_trace( + 'fcntl(%d, F_GETLK) %s findFirstConflictingByteRangeLock error %s', + fd, + vfsPath, + e + ); + return -ERRNO_CODES.EINVAL; + } + } + case emscripten_F_SETLK: { + _js_wasm_trace('fcntl(%d, F_SETLK)', fd); + let vfsPath; + let errno; + [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); + if (errno !== 0) { + _js_wasm_trace( + 'fcntl(%d, F_SETLK) %s get_vfs_path_from_fd errno %d', + fd, + vfsPath, + errno + ); + return -errno; + } + + if (!locking.is_path_to_shared_fs(vfsPath)) { + _js_wasm_trace( + 'fcntl(%d, F_SETLK) locking is not implemented for non-NodeFS path %s', + fd, + vfsPath + ); + + // If not a NodeFS path, we can't lock it. + // Default to succeeding as Emscripten does. + return 0; + } + + var flockStructAddr = syscallGetVarargP(); + const flockStruct = read_flock_struct(flockStructAddr); + + let absoluteStartOffset; + [absoluteStartOffset, errno] = get_base_address( + fd, + flockStruct.l_whence, + flockStruct.l_start + ); + if (errno !== 0) { + _js_wasm_trace( + 'fcntl(%d, F_SETLK) %s get_base_address errno %d', + fd, + vfsPath, + errno + ); + return -errno; + } + + if (!(flockStruct.l_type in locking.fcntlToLockState)) { + _js_wasm_trace( + 'fcntl(%d, F_SETLK) %s invalid lock type %d', + fd, + vfsPath, + flockStruct.l_type + ); + return -ERRNO_CODES.EINVAL; + } + + errno = locking.check_lock_params(fd, flockStruct.l_type); + if (errno !== 0) { + _js_wasm_trace( + 'fcntl(%d, F_SETLK) %s check_lock_params errno %d', + fd, + vfsPath, + errno + ); + return -errno; + } + + locking.maybeLockedFds.add(fd); + + const requestedLockType = + locking.fcntlToLockState[flockStruct.l_type]; + const rangeLock = { + type: requestedLockType, + start: absoluteStartOffset, + end: absoluteStartOffset + flockStruct.l_len, + pid, + }; + + try { + const nativeFilePath = + locking.get_native_path_from_vfs_path(vfsPath); + _js_wasm_trace( + 'fcntl(%d, F_SETLK) %s calling lockFileByteRange for range lock %s', + fd, + vfsPath, + rangeLock + ); + + const succeeded = ( + PHPLoader.fileLockManager + .lockFileByteRange(nativeFilePath, rangeLock) + ); + + _js_wasm_trace( + 'fcntl(%d, F_SETLK) %s lockFileByteRange returned %d for range lock %s', + fd, + vfsPath, + succeeded, + rangeLock + ); + return succeeded ? 0 : -ERRNO_CODES.EAGAIN; + } catch (e) { + _js_wasm_trace( + 'fcntl(%d, F_SETLK) %s lockFileByteRange error %s for range lock %s', + fd, + vfsPath, + e, + rangeLock + ); + return -ERRNO_CODES.EINVAL; + } + } + // @TODO: Implement waiting for lock + case emscripten_F_SETLKW: { + // We do not yet support the blocking form of flock(). + // We respond with EDEADLK to indicate failure + // because it is a known errno for a failed F_SETLKW command. + return -ERRNO_CODES.EDEADLK; + } + case emscripten_F_SETFL: { + /** + * Overrides the core Emscripten implementation to reflect what + * fcntl does in linux kernel. This implementation is still missing + * a bunch of nuance, but, unlike the core Emscripten implementation, + * it overrides the stream flags while preserving non-stream flags. + * + * @see fcntl.c: + * https://github.com/torvalds/linux/blob/a79a588fc1761dc12a3064fc2f648ae66cea3c5a/fs/fcntl.c#L39 + */ + const arg = varargs ? syscallGetVarargI() : 0; + const stream = SYSCALLS.getStreamFromFD(fd); + + // Update the stream flags + stream.flags = + (arg & PHPWASM.SETFL_MASK) | + (stream.flags & ~PHPWASM.SETFL_MASK); + + return 0; + } + default: + return _builtin_fcntl64(fd, cmd, varargs); + } + } + ___syscall_fcntl64.sig = 'iiip'; + + function ___syscall_fdatasync(fd) { + try { + + var stream = SYSCALLS.getStreamFromFD(fd); + return 0; // we can't do anything synchronously; the in-memory FS is already synced to + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_fdatasync.sig = 'ii'; + + function ___syscall_fstat64(fd, buf) { + try { + + return SYSCALLS.writeStat(buf, FS.fstat(fd)); + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_fstat64.sig = 'iip'; + + function ___syscall_fstatfs64(fd, size, buf) { + try { + + var stream = SYSCALLS.getStreamFromFD(fd); + SYSCALLS.writeStatFs(buf, FS.statfsStream(stream)); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_fstatfs64.sig = 'iipp'; + + function ___syscall_ftruncate64(fd, length) { + length = bigintToI53Checked(length); + + + try { + + if (isNaN(length)) return -61; + FS.ftruncate(fd, length); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + ; + } + ___syscall_ftruncate64.sig = 'iij'; + + + function ___syscall_getcwd(buf, size) { + try { + + if (size === 0) return -28; + var cwd = FS.cwd(); + var cwdLengthInBytes = lengthBytesUTF8(cwd) + 1; + if (size < cwdLengthInBytes) return -68; + stringToUTF8(cwd, buf, size); + return cwdLengthInBytes; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_getcwd.sig = 'ipp'; + + + function ___syscall_getdents64(fd, dirp, count) { + try { + + var stream = SYSCALLS.getStreamFromFD(fd) + stream.getdents ||= FS.readdir(stream.path); + + var struct_size = 280; + var pos = 0; + var off = FS.llseek(stream, 0, 1); + + var startIdx = Math.floor(off / struct_size); + var endIdx = Math.min(stream.getdents.length, startIdx + Math.floor(count/struct_size)) + for (var idx = startIdx; idx < endIdx; idx++) { + var id; + var type; + var name = stream.getdents[idx]; + if (name === '.') { + id = stream.node.id; + type = 4; // DT_DIR + } + else if (name === '..') { + var lookup = FS.lookupPath(stream.path, { parent: true }); + id = lookup.node.id; + type = 4; // DT_DIR + } + else { + var child; + try { + child = FS.lookupNode(stream.node, name); + } catch (e) { + // If the entry is not a directory, file, or symlink, nodefs + // lookupNode will raise EINVAL. Skip these and continue. + if (e?.errno === 28) { + continue; + } + throw e; + } + id = child.id; + type = FS.isChrdev(child.mode) ? 2 : // DT_CHR, character device. + FS.isDir(child.mode) ? 4 : // DT_DIR, directory. + FS.isLink(child.mode) ? 10 : // DT_LNK, symbolic link. + 8; // DT_REG, regular file. + } + HEAP64[((dirp + pos)>>3)] = BigInt(id); + HEAP64[(((dirp + pos)+(8))>>3)] = BigInt((idx + 1) * struct_size); + HEAP16[(((dirp + pos)+(16))>>1)] = 280; + HEAP8[(dirp + pos)+(18)] = type; + stringToUTF8(name, dirp + pos + 19, 256); + pos += struct_size; + } + FS.llseek(stream, idx * struct_size, 0); + return pos; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_getdents64.sig = 'iipp'; + + + + function ___syscall_getpeername(fd, addr, addrlen, d1, d2, d3) { + try { + + var sock = getSocketFromFD(fd); + if (!sock.daddr) { + return -53; // The socket is not connected. + } + var errno = writeSockaddr(addr, sock.family, DNS.lookup_name(sock.daddr), sock.dport, addrlen); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_getpeername.sig = 'iippiii'; + + + + function ___syscall_getsockname(fd, addr, addrlen, d1, d2, d3) { + try { + + var sock = getSocketFromFD(fd); + // TODO: sock.saddr should never be undefined, see TODO in websocket_sock_ops.getname + var errno = writeSockaddr(addr, sock.family, DNS.lookup_name(sock.saddr || '0.0.0.0'), sock.sport, addrlen); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_getsockname.sig = 'iippiii'; + + function ___syscall_getsockopt(fd, level, optname, optval, optlen, d1) { + try { + + var sock = getSocketFromFD(fd); + // Minimal getsockopt aimed at resolving https://github.com/emscripten-core/emscripten/issues/2211 + // so only supports SOL_SOCKET with SO_ERROR. + if (level === 1) { + if (optname === 4) { + HEAP32[((optval)>>2)] = sock.error; + HEAP32[((optlen)>>2)] = 4; + sock.error = null; // Clear the error (The SO_ERROR option obtains and then clears this field). + return 0; + } + } + return -50; // The option is unknown at the level indicated. + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_getsockopt.sig = 'iiiippi'; + + + function ___syscall_ioctl(fd, op, varargs) { + SYSCALLS.varargs = varargs; + try { + + var stream = SYSCALLS.getStreamFromFD(fd); + switch (op) { + case 21509: { + if (!stream.tty) return -59; + return 0; + } + case 21505: { + if (!stream.tty) return -59; + if (stream.tty.ops.ioctl_tcgets) { + var termios = stream.tty.ops.ioctl_tcgets(stream); + var argp = syscallGetVarargP(); + HEAP32[((argp)>>2)] = termios.c_iflag || 0; + HEAP32[(((argp)+(4))>>2)] = termios.c_oflag || 0; + HEAP32[(((argp)+(8))>>2)] = termios.c_cflag || 0; + HEAP32[(((argp)+(12))>>2)] = termios.c_lflag || 0; + for (var i = 0; i < 32; i++) { + HEAP8[(argp + i)+(17)] = termios.c_cc[i] || 0; + } + return 0; + } + return 0; + } + case 21510: + case 21511: + case 21512: { + if (!stream.tty) return -59; + return 0; // no-op, not actually adjusting terminal settings + } + case 21506: + case 21507: + case 21508: { + if (!stream.tty) return -59; + if (stream.tty.ops.ioctl_tcsets) { + var argp = syscallGetVarargP(); + var c_iflag = HEAP32[((argp)>>2)]; + var c_oflag = HEAP32[(((argp)+(4))>>2)]; + var c_cflag = HEAP32[(((argp)+(8))>>2)]; + var c_lflag = HEAP32[(((argp)+(12))>>2)]; + var c_cc = [] + for (var i = 0; i < 32; i++) { + c_cc.push(HEAP8[(argp + i)+(17)]); + } + return stream.tty.ops.ioctl_tcsets(stream.tty, op, { c_iflag, c_oflag, c_cflag, c_lflag, c_cc }); + } + return 0; // no-op, not actually adjusting terminal settings + } + case 21519: { + if (!stream.tty) return -59; + var argp = syscallGetVarargP(); + HEAP32[((argp)>>2)] = 0; + return 0; + } + case 21520: { + if (!stream.tty) return -59; + return -28; // not supported + } + case 21537: + case 21531: { + var argp = syscallGetVarargP(); + return FS.ioctl(stream, op, argp); + } + case 21523: { + // TODO: in theory we should write to the winsize struct that gets + // passed in, but for now musl doesn't read anything on it + if (!stream.tty) return -59; + if (stream.tty.ops.ioctl_tiocgwinsz) { + var winsize = stream.tty.ops.ioctl_tiocgwinsz(stream.tty); + var argp = syscallGetVarargP(); + HEAP16[((argp)>>1)] = winsize[0]; + HEAP16[(((argp)+(2))>>1)] = winsize[1]; + } + return 0; + } + case 21524: { + // TODO: technically, this ioctl call should change the window size. + // but, since emscripten doesn't have any concept of a terminal window + // yet, we'll just silently throw it away as we do TIOCGWINSZ + if (!stream.tty) return -59; + return 0; + } + case 21515: { + if (!stream.tty) return -59; + return 0; + } + default: return -28; // not supported + } + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_ioctl.sig = 'iiip'; + + function ___syscall_listen(fd, backlog) { + try { + + var sock = getSocketFromFD(fd); + sock.sock_ops.listen(sock, backlog); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_listen.sig = 'iiiiiii'; + + function ___syscall_lstat64(path, buf) { + try { + + path = SYSCALLS.getStr(path); + return SYSCALLS.writeStat(buf, FS.lstat(path)); + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_lstat64.sig = 'ipp'; + + function ___syscall_mkdirat(dirfd, path, mode) { + try { + + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + FS.mkdir(path, mode, 0); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_mkdirat.sig = 'iipi'; + + function ___syscall_mknodat(dirfd, path, mode, dev) { + try { + + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + // we don't want this in the JS API as it uses mknod to create all nodes. + switch (mode & 61440) { + case 32768: + case 8192: + case 24576: + case 4096: + case 49152: + break; + default: return -28; + } + FS.mknod(path, mode, dev); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_mknodat.sig = 'iipii'; + + function ___syscall_newfstatat(dirfd, path, buf, flags) { + try { + + path = SYSCALLS.getStr(path); + var nofollow = flags & 256; + var allowEmpty = flags & 4096; + flags = flags & (~6400); + path = SYSCALLS.calculateAt(dirfd, path, allowEmpty); + return SYSCALLS.writeStat(buf, nofollow ? FS.lstat(path) : FS.stat(path)); + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_newfstatat.sig = 'iippi'; + + + function ___syscall_openat(dirfd, path, flags, varargs) { + SYSCALLS.varargs = varargs; + try { + + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + var mode = varargs ? syscallGetVarargI() : 0; + return FS.open(path, flags, mode).fd; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_openat.sig = 'iipip'; + + var PIPEFS = { + BUCKET_BUFFER_SIZE:8192, + mount(mount) { + // Do not pollute the real root directory or its child nodes with pipes + // Looks like it is OK to create another pseudo-root node not linked to the FS.root hierarchy this way + return FS.createNode(null, '/', 16384 | 0o777, 0); + }, + createPipe() { + var pipe = { + buckets: [], + // refcnt 2 because pipe has a read end and a write end. We need to be + // able to read from the read end after write end is closed. + refcnt : 2, + timestamp: new Date(), + }; + + pipe.buckets.push({ + buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE), + offset: 0, + roffset: 0 + }); + + var rName = PIPEFS.nextname(); + var wName = PIPEFS.nextname(); + var rNode = FS.createNode(PIPEFS.root, rName, 4096, 0); + var wNode = FS.createNode(PIPEFS.root, wName, 4096, 0); + + rNode.pipe = pipe; + wNode.pipe = pipe; + + var readableStream = FS.createStream({ + path: rName, + node: rNode, + flags: 0, + seekable: false, + stream_ops: PIPEFS.stream_ops + }); + rNode.stream = readableStream; + + var writableStream = FS.createStream({ + path: wName, + node: wNode, + flags: 1, + seekable: false, + stream_ops: PIPEFS.stream_ops + }); + wNode.stream = writableStream; + + return { + readable_fd: readableStream.fd, + writable_fd: writableStream.fd + }; + }, + stream_ops:{ + getattr(stream) { + var node = stream.node; + var timestamp = node.pipe.timestamp; + return { + dev: 14, + ino: node.id, + mode: 0o10600, + nlink: 1, + uid: 0, + gid: 0, + rdev: 0, + size: 0, + atime: timestamp, + mtime: timestamp, + ctime: timestamp, + blksize: 4096, + blocks: 0, + }; + }, + poll(stream) { + var pipe = stream.node.pipe; + + if ((stream.flags & 2097155) === 1) { + return (256 | 4); + } + for (var bucket of pipe.buckets) { + if (bucket.offset - bucket.roffset > 0) { + return (64 | 1); + } + } + + return 0; + }, + dup(stream) { + stream.node.pipe.refcnt++; + }, + ioctl(stream, request, varargs) { + return 28; + }, + fsync(stream) { + return 28; + }, + read(stream, buffer, offset, length, position /* ignored */) { + var pipe = stream.node.pipe; + var currentLength = 0; + + for (var bucket of pipe.buckets) { + currentLength += bucket.offset - bucket.roffset; + } + + var data = buffer.subarray(offset, offset + length); + + if (length <= 0) { + return 0; + } + if(currentLength==0){if(pipe.refcnt<2){return 0;}throw new FS.ErrnoError(6); + } + var toRead = Math.min(currentLength, length); + + var totalRead = toRead; + var toRemove = 0; + + for (var bucket of pipe.buckets) { + var bucketSize = bucket.offset - bucket.roffset; + + if (toRead <= bucketSize) { + var tmpSlice = bucket.buffer.subarray(bucket.roffset, bucket.offset); + if (toRead < bucketSize) { + tmpSlice = tmpSlice.subarray(0, toRead); + bucket.roffset += toRead; + } else { + toRemove++; + } + data.set(tmpSlice); + break; + } else { + var tmpSlice = bucket.buffer.subarray(bucket.roffset, bucket.offset); + data.set(tmpSlice); + data = data.subarray(tmpSlice.byteLength); + toRead -= tmpSlice.byteLength; + toRemove++; + } + } + + if (toRemove && toRemove == pipe.buckets.length) { + // Do not generate excessive garbage in use cases such as + // write several bytes, read everything, write several bytes, read everything... + toRemove--; + pipe.buckets[toRemove].offset = 0; + pipe.buckets[toRemove].roffset = 0; + } + + pipe.buckets.splice(0, toRemove); + + return totalRead; + }, + write(stream, buffer, offset, length, position /* ignored */) { + var pipe = stream.node.pipe; + + var data = buffer.subarray(offset, offset + length); + + var dataLen = data.byteLength; + if (dataLen <= 0) { + return 0; + } + + var currBucket = null; + + if (pipe.buckets.length == 0) { + currBucket = { + buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE), + offset: 0, + roffset: 0 + }; + pipe.buckets.push(currBucket); + } else { + currBucket = pipe.buckets[pipe.buckets.length - 1]; + } + + var freeBytesInCurrBuffer = PIPEFS.BUCKET_BUFFER_SIZE - currBucket.offset; + if (freeBytesInCurrBuffer >= dataLen) { + currBucket.buffer.set(data, currBucket.offset); + currBucket.offset += dataLen; + return dataLen; + } else if (freeBytesInCurrBuffer > 0) { + currBucket.buffer.set(data.subarray(0, freeBytesInCurrBuffer), currBucket.offset); + currBucket.offset += freeBytesInCurrBuffer; + data = data.subarray(freeBytesInCurrBuffer, data.byteLength); + } + + var numBuckets = (data.byteLength / PIPEFS.BUCKET_BUFFER_SIZE) | 0; + var remElements = data.byteLength % PIPEFS.BUCKET_BUFFER_SIZE; + + for (var i = 0; i < numBuckets; i++) { + var newBucket = { + buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE), + offset: PIPEFS.BUCKET_BUFFER_SIZE, + roffset: 0 + }; + pipe.buckets.push(newBucket); + newBucket.buffer.set(data.subarray(0, PIPEFS.BUCKET_BUFFER_SIZE)); + data = data.subarray(PIPEFS.BUCKET_BUFFER_SIZE, data.byteLength); + } + + if (remElements > 0) { + var newBucket = { + buffer: new Uint8Array(PIPEFS.BUCKET_BUFFER_SIZE), + offset: data.byteLength, + roffset: 0 + }; + pipe.buckets.push(newBucket); + newBucket.buffer.set(data); + } + + return dataLen; + }, + close(stream) { + var pipe = stream.node.pipe; + pipe.refcnt--; + if (pipe.refcnt === 0) { + pipe.buckets = null; + } + }, + }, + nextname() { + if (!PIPEFS.nextname.current) { + PIPEFS.nextname.current = 0; + } + return 'pipe[' + (PIPEFS.nextname.current++) + ']'; + }, + }; + function ___syscall_pipe(fdPtr) { + try { + + if (fdPtr == 0) { + throw new FS.ErrnoError(21); + } + + var res = PIPEFS.createPipe(); + + HEAP32[((fdPtr)>>2)] = res.readable_fd; + HEAP32[(((fdPtr)+(4))>>2)] = res.writable_fd; + + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_pipe.sig = 'ip'; + + function ___syscall_poll(fds, nfds, timeout) { + try { + + var nonzero = 0; + for (var i = 0; i < nfds; i++) { + var pollfd = fds + 8 * i; + var fd = HEAP32[((pollfd)>>2)]; + var events = HEAP16[(((pollfd)+(4))>>1)]; + var mask = 32; + var stream = FS.getStream(fd); + if (stream) { + mask = SYSCALLS.DEFAULT_POLLMASK; + if (stream.stream_ops?.poll) { + mask = stream.stream_ops.poll(stream, -1); + } + } + mask &= events | 8 | 16; + if (mask) nonzero++; + HEAP16[(((pollfd)+(6))>>1)] = mask; + } + return nonzero; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_poll.sig = 'ipii'; + + + + function ___syscall_readlinkat(dirfd, path, buf, bufsize) { + try { + + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + if (bufsize <= 0) return -28; + var ret = FS.readlink(path); + + var len = Math.min(bufsize, lengthBytesUTF8(ret)); + var endChar = HEAP8[buf+len]; + stringToUTF8(ret, buf, bufsize+1); + // readlink is one of the rare functions that write out a C string, but does never append a null to the output buffer(!) + // stringToUTF8() always appends a null byte, so restore the character under the null byte after the write. + HEAP8[buf+len] = endChar; + return len; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_readlinkat.sig = 'iippp'; + + + + function ___syscall_recvfrom(fd, buf, len, flags, addr, addrlen) { + try { + + var sock = getSocketFromFD(fd); + var msg = sock.sock_ops.recvmsg(sock, len, typeof flags !== "undefined" ? flags : 0); + if (!msg) return 0; // socket is closed + if (addr) { + var errno = writeSockaddr(addr, sock.family, DNS.lookup_name(msg.addr), msg.port, addrlen); + } + HEAPU8.set(msg.buffer, buf); + return msg.buffer.byteLength; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_recvfrom.sig = 'iippipp'; + + + + function ___syscall_recvmsg(fd, message, flags, d1, d2, d3) { + try { + + var sock = getSocketFromFD(fd); + var iov = HEAPU32[(((message)+(8))>>2)]; + var num = HEAP32[(((message)+(12))>>2)]; + // get the total amount of data we can read across all arrays + var total = 0; + for (var i = 0; i < num; i++) { + total += HEAP32[(((iov)+((8 * i) + 4))>>2)]; + } + // try to read total data + var msg = sock.sock_ops.recvmsg(sock, total); + if (!msg) return 0; // socket is closed + + // TODO honor flags: + // MSG_OOB + // Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific. + // MSG_PEEK + // Peeks at the incoming message. + // MSG_WAITALL + // Requests that the function block until the full amount of data requested can be returned. The function may return a smaller amount of data if a signal is caught, if the connection is terminated, if MSG_PEEK was specified, or if an error is pending for the socket. + + // write the source address out + var name = HEAPU32[((message)>>2)]; + if (name) { + var errno = writeSockaddr(name, sock.family, DNS.lookup_name(msg.addr), msg.port); + } + // write the buffer out to the scatter-gather arrays + var bytesRead = 0; + var bytesRemaining = msg.buffer.byteLength; + for (var i = 0; bytesRemaining > 0 && i < num; i++) { + var iovbase = HEAPU32[(((iov)+((8 * i) + 0))>>2)]; + var iovlen = HEAP32[(((iov)+((8 * i) + 4))>>2)]; + if (!iovlen) { + continue; + } + var length = Math.min(iovlen, bytesRemaining); + var buf = msg.buffer.subarray(bytesRead, bytesRead + length); + HEAPU8.set(buf, iovbase + bytesRead); + bytesRead += length; + bytesRemaining -= length; + } + + // TODO set msghdr.msg_flags + // MSG_EOR + // End of record was received (if supported by the protocol). + // MSG_OOB + // Out-of-band data was received. + // MSG_TRUNC + // Normal data was truncated. + // MSG_CTRUNC + + return bytesRead; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_recvmsg.sig = 'iipiiii'; + + function ___syscall_renameat(olddirfd, oldpath, newdirfd, newpath) { + try { + + oldpath = SYSCALLS.getStr(oldpath); + newpath = SYSCALLS.getStr(newpath); + oldpath = SYSCALLS.calculateAt(olddirfd, oldpath); + newpath = SYSCALLS.calculateAt(newdirfd, newpath); + FS.rename(oldpath, newpath); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_renameat.sig = 'iipip'; + + function ___syscall_rmdir(path) { + try { + + path = SYSCALLS.getStr(path); + FS.rmdir(path); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_rmdir.sig = 'ip'; + + + function ___syscall_sendmsg(fd, message, flags, d1, d2, d3) { + try { + + var sock = getSocketFromFD(fd); + var iov = HEAPU32[(((message)+(8))>>2)]; + var num = HEAP32[(((message)+(12))>>2)]; + // read the address and port to send to + var addr, port; + var name = HEAPU32[((message)>>2)]; + var namelen = HEAP32[(((message)+(4))>>2)]; + if (name) { + var info = getSocketAddress(name, namelen); + port = info.port; + addr = info.addr; + } + // concatenate scatter-gather arrays into one message buffer + var total = 0; + for (var i = 0; i < num; i++) { + total += HEAP32[(((iov)+((8 * i) + 4))>>2)]; + } + var view = new Uint8Array(total); + var offset = 0; + for (var i = 0; i < num; i++) { + var iovbase = HEAPU32[(((iov)+((8 * i) + 0))>>2)]; + var iovlen = HEAP32[(((iov)+((8 * i) + 4))>>2)]; + for (var j = 0; j < iovlen; j++) { + view[offset++] = HEAP8[(iovbase)+(j)]; + } + } + // write the buffer + return sock.sock_ops.sendmsg(sock, view, 0, total, addr, port); + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_sendmsg.sig = 'iipippi'; + + + function ___syscall_sendto(fd, message, length, flags, addr, addr_len) { + try { + + var sock = getSocketFromFD(fd); + if (!addr) { + // send, no address provided + return FS.write(sock.stream, HEAP8, message, length); + } + var dest = getSocketAddress(addr, addr_len); + // sendto an address + return sock.sock_ops.sendmsg(sock, HEAP8, message, length, dest.addr, dest.port); + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_sendto.sig = 'iippipp'; + + function ___syscall_socket(domain, type, protocol) { + try { + + var sock = SOCKFS.createSocket(domain, type, protocol); + return sock.stream.fd; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_socket.sig = 'iiiiiii'; + + function ___syscall_stat64(path, buf) { + try { + + path = SYSCALLS.getStr(path); + return SYSCALLS.writeStat(buf, FS.stat(path)); + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_stat64.sig = 'ipp'; + + function ___syscall_statfs64(path, size, buf) { + try { + + SYSCALLS.writeStatFs(buf, FS.statfs(SYSCALLS.getStr(path))); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_statfs64.sig = 'ippp'; + + function ___syscall_symlinkat(target, dirfd, linkpath) { + try { + + target = SYSCALLS.getStr(target); + linkpath = SYSCALLS.getStr(linkpath); + linkpath = SYSCALLS.calculateAt(dirfd, linkpath); + FS.symlink(target, linkpath); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_symlinkat.sig = 'ipip'; + + + function ___syscall_truncate64(path, length) { + length = bigintToI53Checked(length); + + + try { + + if (isNaN(length)) return -61; + path = SYSCALLS.getStr(path); + FS.truncate(path, length); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + ; + } + ___syscall_truncate64.sig = 'ipj'; + + function ___syscall_unlinkat(dirfd, path, flags) { + try { + + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path); + if (!flags) { + FS.unlink(path); + } else if (flags === 512) { + FS.rmdir(path); + } else { + return -28; + } + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_unlinkat.sig = 'iipi'; + + var readI53FromI64 = (ptr) => { + return HEAPU32[((ptr)>>2)] + HEAP32[(((ptr)+(4))>>2)] * 4294967296; + }; + + function ___syscall_utimensat(dirfd, path, times, flags) { + try { + + path = SYSCALLS.getStr(path); + path = SYSCALLS.calculateAt(dirfd, path, true); + var now = Date.now(), atime, mtime; + if (!times) { + atime = now; + mtime = now; + } else { + var seconds = readI53FromI64(times); + var nanoseconds = HEAP32[(((times)+(8))>>2)]; + if (nanoseconds == 1073741823) { + atime = now; + } else if (nanoseconds == 1073741822) { + atime = null; + } else { + atime = (seconds*1000) + (nanoseconds/(1000*1000)); + } + times += 16; + seconds = readI53FromI64(times); + nanoseconds = HEAP32[(((times)+(8))>>2)]; + if (nanoseconds == 1073741823) { + mtime = now; + } else if (nanoseconds == 1073741822) { + mtime = null; + } else { + mtime = (seconds*1000) + (nanoseconds/(1000*1000)); + } + } + // null here means UTIME_OMIT was passed. If both were set to UTIME_OMIT then + // we can skip the call completely. + if ((mtime ?? atime) !== null) { + FS.utime(path, atime, mtime); + } + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_utimensat.sig = 'iippi'; + + var __abort_js = () => + abort(''); + __abort_js.sig = 'v'; + + + + + var dlSetError = (msg) => { + var sp = stackSave(); + var cmsg = stringToUTF8OnStack(msg); + ___dl_seterr(cmsg, 0); + stackRestore(sp); + }; + + + var dlopenInternal = (handle, jsflags) => { + // void *dlopen(const char *file, int mode); + // http://pubs.opengroup.org/onlinepubs/009695399/functions/dlopen.html + var filename = UTF8ToString(handle + 36); + var flags = HEAP32[(((handle)+(4))>>2)]; + filename = PATH.normalize(filename); + var searchpaths = []; + + var global = Boolean(flags & 256); + var localScope = global ? null : {}; + + // We don't care about RTLD_NOW and RTLD_LAZY. + var combinedFlags = { + global, + nodelete: Boolean(flags & 4096), + loadAsync: jsflags.loadAsync, + } + + if (jsflags.loadAsync) { + return loadDynamicLibrary(filename, combinedFlags, localScope, handle); + } + + try { + return loadDynamicLibrary(filename, combinedFlags, localScope, handle) + } catch (e) { + dlSetError(`could not load dynamic lib: ${filename}\n${e}`); + return 0; + } + }; + function __dlopen_js(handle) { + var jsflags = { loadAsync: false } + return dlopenInternal(handle, jsflags); + } + __dlopen_js.sig = 'pp'; + + + + + var __dlsym_js = (handle, symbol, symbolIndex) => { + // void *dlsym(void *restrict handle, const char *restrict name); + // http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html + symbol = UTF8ToString(symbol); + var result; + var newSymIndex; + + var lib = LDSO.loadedLibsByHandle[handle]; + newSymIndex = Object.keys(lib.exports).indexOf(symbol); + if (newSymIndex == -1 || lib.exports[symbol].stub) { + dlSetError(`Tried to lookup unknown symbol "${symbol}" in dynamic lib: ${lib.name}`) + return 0; + } + result = lib.exports[symbol]; + + if (typeof result == 'function') { + + // Asyncify wraps exports, and we need to look through those wrappers. + if (result.orig) { + result = result.orig; + } + var addr = getFunctionAddress(result); + if (addr) { + result = addr; + } else { + // Insert the function into the wasm table. If its a direct wasm + // function the second argument will not be needed. If its a JS + // function we rely on the `sig` attribute being set based on the + // `__sig` specified in library JS file. + result = addFunction(result, result.sig); + HEAPU32[((symbolIndex)>>2)] = newSymIndex; + } + } + return result; + }; + __dlsym_js.sig = 'pppp'; + + + var handleException = (e) => { + // Certain exception types we do not treat as errors since they are used for + // internal control flow. + // 1. ExitStatus, which is thrown by exit() + // 2. "unwind", which is thrown by emscripten_unwind_to_js_event_loop() and others + // that wish to return to JS event loop. + if (e instanceof ExitStatus || e == 'unwind') { + return EXITSTATUS; + } + quit_(1, e); + }; + + + var runtimeKeepaliveCounter = 0; + var keepRuntimeAlive = () => noExitRuntime || runtimeKeepaliveCounter > 0; + var _proc_exit = (code) => { + EXITSTATUS = code; + if (!keepRuntimeAlive()) { + Module['onExit']?.(code); + ABORT = true; + } + quit_(code, new ExitStatus(code)); + }; + _proc_exit.sig = 'vi'; + + /** @param {boolean|number=} implicit */ + var exitJS = (status, implicit) => { + EXITSTATUS = status; + + if (!keepRuntimeAlive()) { + exitRuntime(); + } + + _proc_exit(status); + }; + var _exit = exitJS; + _exit.sig = 'vi'; + + + var maybeExit = () => { + if (runtimeExited) { + return; + } + if (!keepRuntimeAlive()) { + try { + _exit(EXITSTATUS); + } catch (e) { + handleException(e); + } + } + }; + var callUserCallback = (func) => { + if (runtimeExited || ABORT) { + return; + } + try { + func(); + maybeExit(); + } catch (e) { + handleException(e); + } + }; + + + var runtimeKeepalivePush = () => { + runtimeKeepaliveCounter += 1; + }; + runtimeKeepalivePush.sig = 'v'; + + var runtimeKeepalivePop = () => { + runtimeKeepaliveCounter -= 1; + }; + runtimeKeepalivePop.sig = 'v'; + + var __emscripten_dlopen_js = (handle, onsuccess, onerror, user_data) => { + /** @param {Object=} e */ + function errorCallback(e) { + var filename = UTF8ToString(handle + 36); + dlSetError(`'Could not load dynamic lib: ${filename}\n${e}`); + runtimeKeepalivePop(); + callUserCallback(() => ((a1, a2) => {} /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(handle, user_data)); + } + function successCallback() { + runtimeKeepalivePop(); + callUserCallback(() => ((a1, a2) => {} /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(handle, user_data)); + } + + runtimeKeepalivePush(); + var promise = dlopenInternal(handle, { loadAsync: true }); + if (promise) { + promise.then(successCallback, errorCallback); + } else { + errorCallback(); + } + }; + __emscripten_dlopen_js.sig = 'vpppp'; + + var getExecutableName = () => thisProgram || './this.program'; + + var __emscripten_get_progname = (str, len) => stringToUTF8(getExecutableName(), str, len); + __emscripten_get_progname.sig = 'vpi'; + + var jsStackTrace = () => new Error().stack.toString(); + /** @param {number=} flags */ + var getCallstack = (flags) => { + var callstack = jsStackTrace(); + + // Process all lines: + var lines = callstack.split('\n'); + callstack = ''; + // Extract components of form: + // ' Object._main@http://server.com:4324:12' + var firefoxRe = new RegExp('\\s*(.*?)@(.*?):([0-9]+):([0-9]+)'); + // Extract components of form: + // ' at Object._main (http://server.com/file.html:4324:12)' + var chromeRe = new RegExp('\\s*at (.*?) \\\((.*):(.*):(.*)\\\)'); + + for (var line of lines) { + var symbolName = ''; + var file = ''; + var lineno = 0; + var column = 0; + + var parts = chromeRe.exec(line); + if (parts?.length == 5) { + symbolName = parts[1]; + file = parts[2]; + lineno = parts[3]; + column = parts[4]; + } else { + parts = firefoxRe.exec(line); + if (parts?.length >= 4) { + symbolName = parts[1]; + file = parts[2]; + lineno = parts[3]; + // Old Firefox doesn't carry column information, but in new FF30, it + // is present. See https://bugzil.la/762556 + column = parts[4]|0; + } else { + // Was not able to extract this line for demangling/sourcemapping + // purposes. Output it as-is. + callstack += line + '\n'; + continue; + } + } + + // Find the symbols in the callstack that corresponds to the functions that + // report callstack information, and remove everything up to these from the + // output. + if (symbolName == '_emscripten_log' || symbolName == '_emscripten_get_callstack') { + callstack = ''; + continue; + } + + if ((flags & 24)) { + if (flags & 64) { + file = file.substring(file.replace(/\\/g, "/").lastIndexOf('/')+1); + } + callstack += ` at ${symbolName} (${file}:${lineno}:${column})\n`; + } + } + // Trim extra whitespace at the end of the output. + callstack = callstack.replace(/\s+$/, ''); + return callstack; + }; + + var __emscripten_log_formatted = (flags, str) => { + str = UTF8ToString(str); + + if (flags & 24) { + str = str.replace(/\s+$/, ''); // Ensure the message and the callstack are joined cleanly with exactly one newline. + str += (str.length > 0 ? '\n' : '') + getCallstack(flags); + } + + if (flags & 1) { + if (flags & 4) { + console.error(str); + } else if (flags & 2) { + console.warn(str); + } else if (flags & 512) { + console.info(str); + } else if (flags & 256) { + console.debug(str); + } else { + console.log(str); + } + } else if (flags & 6) { + err(str); + } else { + out(str); + } + }; + __emscripten_log_formatted.sig = 'vip'; + + + + + var __emscripten_lookup_name = (name) => { + // uint32_t _emscripten_lookup_name(const char *name); + var nameString = UTF8ToString(name); + return inetPton4(DNS.lookup_name(nameString)); + }; + __emscripten_lookup_name.sig = 'ip'; + + var __emscripten_runtime_keepalive_clear = () => { + noExitRuntime = false; + runtimeKeepaliveCounter = 0; + }; + __emscripten_runtime_keepalive_clear.sig = 'v'; + + var __emscripten_system = (command) => { + if (ENVIRONMENT_IS_NODE) { + if (!command) return 1; // shell is available + + var cmdstr = UTF8ToString(command); + if (!cmdstr.length) return 0; // this is what glibc seems to do (shell works test?) + + var cp = require('child_process'); + var ret = cp.spawnSync(cmdstr, [], {shell:true, stdio:'inherit'}); + + var _W_EXITCODE = (ret, sig) => ((ret) << 8 | (sig)); + + // this really only can happen if process is killed by signal + if (ret.status === null) { + // sadly node doesn't expose such function + var signalToNumber = (sig) => { + // implement only the most common ones, and fallback to SIGINT + switch (sig) { + case 'SIGHUP': return 1; + case 'SIGQUIT': return 3; + case 'SIGFPE': return 8; + case 'SIGKILL': return 9; + case 'SIGALRM': return 14; + case 'SIGTERM': return 15; + default: return 2; + } + } + return _W_EXITCODE(0, signalToNumber(ret.signal)); + } + + return _W_EXITCODE(ret.status, 0); + } + // int system(const char *command); + // http://pubs.opengroup.org/onlinepubs/000095399/functions/system.html + // Can't call external programs. + if (!command) return 0; // no shell available + return -52; + }; + __emscripten_system.sig = 'ip'; + + var __emscripten_throw_longjmp = () => { + throw Infinity; + }; + __emscripten_throw_longjmp.sig = 'v'; + + function __gmtime_js(time, tmPtr) { + time = bigintToI53Checked(time); + + + var date = new Date(time * 1000); + HEAP32[((tmPtr)>>2)] = date.getUTCSeconds(); + HEAP32[(((tmPtr)+(4))>>2)] = date.getUTCMinutes(); + HEAP32[(((tmPtr)+(8))>>2)] = date.getUTCHours(); + HEAP32[(((tmPtr)+(12))>>2)] = date.getUTCDate(); + HEAP32[(((tmPtr)+(16))>>2)] = date.getUTCMonth(); + HEAP32[(((tmPtr)+(20))>>2)] = date.getUTCFullYear()-1900; + HEAP32[(((tmPtr)+(24))>>2)] = date.getUTCDay(); + var start = Date.UTC(date.getUTCFullYear(), 0, 1, 0, 0, 0, 0); + var yday = ((date.getTime() - start) / (1000 * 60 * 60 * 24))|0; + HEAP32[(((tmPtr)+(28))>>2)] = yday; + ; + } + __gmtime_js.sig = 'vjp'; + + var isLeapYear = (year) => year%4 === 0 && (year%100 !== 0 || year%400 === 0); + + var MONTH_DAYS_LEAP_CUMULATIVE = [0,31,60,91,121,152,182,213,244,274,305,335]; + + var MONTH_DAYS_REGULAR_CUMULATIVE = [0,31,59,90,120,151,181,212,243,273,304,334]; + var ydayFromDate = (date) => { + var leap = isLeapYear(date.getFullYear()); + var monthDaysCumulative = (leap ? MONTH_DAYS_LEAP_CUMULATIVE : MONTH_DAYS_REGULAR_CUMULATIVE); + var yday = monthDaysCumulative[date.getMonth()] + date.getDate() - 1; // -1 since it's days since Jan 1 + + return yday; + }; + + function __localtime_js(time, tmPtr) { + time = bigintToI53Checked(time); + + + var date = new Date(time*1000); + HEAP32[((tmPtr)>>2)] = date.getSeconds(); + HEAP32[(((tmPtr)+(4))>>2)] = date.getMinutes(); + HEAP32[(((tmPtr)+(8))>>2)] = date.getHours(); + HEAP32[(((tmPtr)+(12))>>2)] = date.getDate(); + HEAP32[(((tmPtr)+(16))>>2)] = date.getMonth(); + HEAP32[(((tmPtr)+(20))>>2)] = date.getFullYear()-1900; + HEAP32[(((tmPtr)+(24))>>2)] = date.getDay(); + + var yday = ydayFromDate(date)|0; + HEAP32[(((tmPtr)+(28))>>2)] = yday; + HEAP32[(((tmPtr)+(36))>>2)] = -(date.getTimezoneOffset() * 60); + + // Attention: DST is in December in South, and some regions don't have DST at all. + var start = new Date(date.getFullYear(), 0, 1); + var summerOffset = new Date(date.getFullYear(), 6, 1).getTimezoneOffset(); + var winterOffset = start.getTimezoneOffset(); + var dst = (summerOffset != winterOffset && date.getTimezoneOffset() == Math.min(winterOffset, summerOffset))|0; + HEAP32[(((tmPtr)+(32))>>2)] = dst; + ; + } + __localtime_js.sig = 'vjp'; + + + var __mktime_js = function(tmPtr) { + + var ret = (() => { + var date = new Date(HEAP32[(((tmPtr)+(20))>>2)] + 1900, + HEAP32[(((tmPtr)+(16))>>2)], + HEAP32[(((tmPtr)+(12))>>2)], + HEAP32[(((tmPtr)+(8))>>2)], + HEAP32[(((tmPtr)+(4))>>2)], + HEAP32[((tmPtr)>>2)], + 0); + + // There's an ambiguous hour when the time goes back; the tm_isdst field is + // used to disambiguate it. Date() basically guesses, so we fix it up if it + // guessed wrong, or fill in tm_isdst with the guess if it's -1. + var dst = HEAP32[(((tmPtr)+(32))>>2)]; + var guessedOffset = date.getTimezoneOffset(); + var start = new Date(date.getFullYear(), 0, 1); + var summerOffset = new Date(date.getFullYear(), 6, 1).getTimezoneOffset(); + var winterOffset = start.getTimezoneOffset(); + var dstOffset = Math.min(winterOffset, summerOffset); // DST is in December in South + if (dst < 0) { + // Attention: some regions don't have DST at all. + HEAP32[(((tmPtr)+(32))>>2)] = Number(summerOffset != winterOffset && dstOffset == guessedOffset); + } else if ((dst > 0) != (dstOffset == guessedOffset)) { + var nonDstOffset = Math.max(winterOffset, summerOffset); + var trueOffset = dst > 0 ? dstOffset : nonDstOffset; + // Don't try setMinutes(date.getMinutes() + ...) -- it's messed up. + date.setTime(date.getTime() + (trueOffset - guessedOffset)*60000); + } + + HEAP32[(((tmPtr)+(24))>>2)] = date.getDay(); + var yday = ydayFromDate(date)|0; + HEAP32[(((tmPtr)+(28))>>2)] = yday; + // To match expected behavior, update fields from date + HEAP32[((tmPtr)>>2)] = date.getSeconds(); + HEAP32[(((tmPtr)+(4))>>2)] = date.getMinutes(); + HEAP32[(((tmPtr)+(8))>>2)] = date.getHours(); + HEAP32[(((tmPtr)+(12))>>2)] = date.getDate(); + HEAP32[(((tmPtr)+(16))>>2)] = date.getMonth(); + HEAP32[(((tmPtr)+(20))>>2)] = date.getYear(); + + var timeMs = date.getTime(); + if (isNaN(timeMs)) { + return -1; + } + // Return time in microseconds + return timeMs / 1000; + })(); + return BigInt(ret); + }; + __mktime_js.sig = 'jp'; + + + + + + + function __mmap_js(len, prot, flags, fd, offset, allocated, addr) { + offset = bigintToI53Checked(offset); + + + try { + + var stream = SYSCALLS.getStreamFromFD(fd); + var res = FS.mmap(stream, len, offset, prot, flags); + var ptr = res.ptr; + HEAP32[((allocated)>>2)] = res.allocated; + HEAPU32[((addr)>>2)] = ptr; + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + ; + } + __mmap_js.sig = 'ipiiijpp'; + + + function __msync_js(addr, len, prot, flags, fd, offset) { + offset = bigintToI53Checked(offset); + + + try { + + if (isNaN(offset)) return -61; + SYSCALLS.doMsync(addr, SYSCALLS.getStreamFromFD(fd), len, flags, offset); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + ; + } + __msync_js.sig = 'ippiiij'; + + + function __munmap_js(addr, len, prot, flags, fd, offset) { + offset = bigintToI53Checked(offset); + + + try { + + var stream = SYSCALLS.getStreamFromFD(fd); + if (prot & 2) { + SYSCALLS.doMsync(addr, stream, len, flags, offset); + } + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + ; + } + __munmap_js.sig = 'ippiiij'; + + var timers = { + }; + + + + var _emscripten_get_now = () => performance.now(); + _emscripten_get_now.sig = 'd'; + var __setitimer_js = (which, timeout_ms) => { + // First, clear any existing timer. + if (timers[which]) { + clearTimeout(timers[which].id); + delete timers[which]; + } + + // A timeout of zero simply cancels the current timeout so we have nothing + // more to do. + if (!timeout_ms) return 0; + + var id = setTimeout(() => { + delete timers[which]; + callUserCallback(() => __emscripten_timeout(which, _emscripten_get_now())); + }, timeout_ms); + timers[which] = { id, timeout_ms }; + return 0; + }; + __setitimer_js.sig = 'iid'; + + var __timegm_js = function(tmPtr) { + + var ret = (() => { + var time = Date.UTC(HEAP32[(((tmPtr)+(20))>>2)] + 1900, + HEAP32[(((tmPtr)+(16))>>2)], + HEAP32[(((tmPtr)+(12))>>2)], + HEAP32[(((tmPtr)+(8))>>2)], + HEAP32[(((tmPtr)+(4))>>2)], + HEAP32[((tmPtr)>>2)], + 0); + var date = new Date(time); + + HEAP32[(((tmPtr)+(24))>>2)] = date.getUTCDay(); + var start = Date.UTC(date.getUTCFullYear(), 0, 1, 0, 0, 0, 0); + var yday = ((date.getTime() - start) / (1000 * 60 * 60 * 24))|0; + HEAP32[(((tmPtr)+(28))>>2)] = yday; + + return date.getTime() / 1000; + })(); + return BigInt(ret); + }; + __timegm_js.sig = 'jp'; + + var __tzset_js = (timezone, daylight, std_name, dst_name) => { + // TODO: Use (malleable) environment variables instead of system settings. + var currentYear = new Date().getFullYear(); + var winter = new Date(currentYear, 0, 1); + var summer = new Date(currentYear, 6, 1); + var winterOffset = winter.getTimezoneOffset(); + var summerOffset = summer.getTimezoneOffset(); + + // Local standard timezone offset. Local standard time is not adjusted for + // daylight savings. This code uses the fact that getTimezoneOffset returns + // a greater value during Standard Time versus Daylight Saving Time (DST). + // Thus it determines the expected output during Standard Time, and it + // compares whether the output of the given date the same (Standard) or less + // (DST). + var stdTimezoneOffset = Math.max(winterOffset, summerOffset); + + // timezone is specified as seconds west of UTC ("The external variable + // `timezone` shall be set to the difference, in seconds, between + // Coordinated Universal Time (UTC) and local standard time."), the same + // as returned by stdTimezoneOffset. + // See http://pubs.opengroup.org/onlinepubs/009695399/functions/tzset.html + HEAPU32[((timezone)>>2)] = stdTimezoneOffset * 60; + + HEAP32[((daylight)>>2)] = Number(winterOffset != summerOffset); + + var extractZone = (timezoneOffset) => { + // Why inverse sign? + // Read here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getTimezoneOffset + var sign = timezoneOffset >= 0 ? "-" : "+"; + + var absOffset = Math.abs(timezoneOffset) + var hours = String(Math.floor(absOffset / 60)).padStart(2, "0"); + var minutes = String(absOffset % 60).padStart(2, "0"); + + return `UTC${sign}${hours}${minutes}`; + } + + var winterName = extractZone(winterOffset); + var summerName = extractZone(summerOffset); + if (summerOffset < winterOffset) { + // Northern hemisphere + stringToUTF8(winterName, std_name, 17); + stringToUTF8(summerName, dst_name, 17); + } else { + stringToUTF8(winterName, dst_name, 17); + stringToUTF8(summerName, std_name, 17); + } + }; + __tzset_js.sig = 'vpppp'; + + + + var _emscripten_set_main_loop_timing = (mode, value) => { + MainLoop.timingMode = mode; + MainLoop.timingValue = value; + + if (!MainLoop.func) { + return 1; // Return non-zero on failure, can't set timing mode when there is no main loop. + } + + if (!MainLoop.running) { + runtimeKeepalivePush(); + MainLoop.running = true; + } + if (mode == 0) { + MainLoop.scheduler = function MainLoop_scheduler_setTimeout() { + var timeUntilNextTick = Math.max(0, MainLoop.tickStartTime + value - _emscripten_get_now())|0; + setTimeout(MainLoop.runner, timeUntilNextTick); // doing this each time means that on exception, we stop + }; + MainLoop.method = 'timeout'; + } else if (mode == 1) { + MainLoop.scheduler = function MainLoop_scheduler_rAF() { + MainLoop.requestAnimationFrame(MainLoop.runner); + }; + MainLoop.method = 'rAF'; + } else if (mode == 2) { + if (!MainLoop.setImmediate) { + if (globalThis.setImmediate) { + MainLoop.setImmediate = setImmediate; + } else { + // Emulate setImmediate. (note: not a complete polyfill, we don't emulate clearImmediate() to keep code size to minimum, since not needed) + var setImmediates = []; + var emscriptenMainLoopMessageId = 'setimmediate'; + /** @param {Event} event */ + var MainLoop_setImmediate_messageHandler = (event) => { + // When called in current thread or Worker, the main loop ID is structured slightly different to accommodate for --proxy-to-worker runtime listening to Worker events, + // so check for both cases. + if (event.data === emscriptenMainLoopMessageId || event.data.target === emscriptenMainLoopMessageId) { + event.stopPropagation(); + setImmediates.shift()(); + } + }; + addEventListener("message", MainLoop_setImmediate_messageHandler, true); + MainLoop.setImmediate = /** @type{function(function(): ?, ...?): number} */((func) => { + setImmediates.push(func); + if (ENVIRONMENT_IS_WORKER) { + Module['setImmediates'] ??= []; + Module['setImmediates'].push(func); + postMessage({target: emscriptenMainLoopMessageId}); // In --proxy-to-worker, route the message via proxyClient.js + } else postMessage(emscriptenMainLoopMessageId, "*"); // On the main thread, can just send the message to itself. + }); + } + } + MainLoop.scheduler = function MainLoop_scheduler_setImmediate() { + MainLoop.setImmediate(MainLoop.runner); + }; + MainLoop.method = 'immediate'; + } + return 0; + }; + _emscripten_set_main_loop_timing.sig = 'iii'; + + + + + /** + * @param {number=} arg + * @param {boolean=} noSetTiming + */ + var setMainLoop = (iterFunc, fps, simulateInfiniteLoop, arg, noSetTiming) => { + MainLoop.func = iterFunc; + MainLoop.arg = arg; + + var thisMainLoopId = MainLoop.currentlyRunningMainloop; + function checkIsRunning() { + if (thisMainLoopId < MainLoop.currentlyRunningMainloop) { + runtimeKeepalivePop(); + maybeExit(); + return false; + } + return true; + } + + // We create the loop runner here but it is not actually running until + // _emscripten_set_main_loop_timing is called (which might happen a + // later time). This member signifies that the current runner has not + // yet been started so that we can call runtimeKeepalivePush when it + // gets it timing set for the first time. + MainLoop.running = false; + MainLoop.runner = function MainLoop_runner() { + if (ABORT) return; + if (MainLoop.queue.length > 0) { + var start = Date.now(); + var blocker = MainLoop.queue.shift(); + blocker.func(blocker.arg); + if (MainLoop.remainingBlockers) { + var remaining = MainLoop.remainingBlockers; + var next = remaining%1 == 0 ? remaining-1 : Math.floor(remaining); + if (blocker.counted) { + MainLoop.remainingBlockers = next; + } else { + // not counted, but move the progress along a tiny bit + next = next + 0.5; // do not steal all the next one's progress + MainLoop.remainingBlockers = (8*remaining + next)/9; + } + } + MainLoop.updateStatus(); + + // catches pause/resume main loop from blocker execution + if (!checkIsRunning()) return; + + setTimeout(MainLoop.runner, 0); + return; + } + + // catch pauses from non-main loop sources + if (!checkIsRunning()) return; + + // Implement very basic swap interval control + MainLoop.currentFrameNumber = MainLoop.currentFrameNumber + 1 | 0; + if (MainLoop.timingMode == 1 && MainLoop.timingValue > 1 && MainLoop.currentFrameNumber % MainLoop.timingValue != 0) { + // Not the scheduled time to render this frame - skip. + MainLoop.scheduler(); + return; + } else if (MainLoop.timingMode == 0) { + MainLoop.tickStartTime = _emscripten_get_now(); + } + + MainLoop.runIter(iterFunc); + + // catch pauses from the main loop itself + if (!checkIsRunning()) return; + + MainLoop.scheduler(); + } + + if (!noSetTiming) { + if (fps > 0) { + _emscripten_set_main_loop_timing(0, 1000.0 / fps); + } else { + // Do rAF by rendering each frame (no decimating) + _emscripten_set_main_loop_timing(1, 1); + } + + MainLoop.scheduler(); + } + + if (simulateInfiniteLoop) { + throw 'unwind'; + } + }; + + + var MainLoop = { + running:false, + scheduler:null, + method:"", + currentlyRunningMainloop:0, + func:null, + arg:0, + timingMode:0, + timingValue:0, + currentFrameNumber:0, + queue:[], + preMainLoop:[], + postMainLoop:[], + pause() { + MainLoop.scheduler = null; + // Incrementing this signals the previous main loop that it's now become old, and it must return. + MainLoop.currentlyRunningMainloop++; + }, + resume() { + MainLoop.currentlyRunningMainloop++; + var timingMode = MainLoop.timingMode; + var timingValue = MainLoop.timingValue; + var func = MainLoop.func; + MainLoop.func = null; + // do not set timing and call scheduler, we will do it on the next lines + setMainLoop(func, 0, false, MainLoop.arg, true); + _emscripten_set_main_loop_timing(timingMode, timingValue); + MainLoop.scheduler(); + }, + updateStatus() { + if (Module['setStatus']) { + var message = Module['statusMessage'] || 'Please wait...'; + var remaining = MainLoop.remainingBlockers ?? 0; + var expected = MainLoop.expectedBlockers ?? 0; + if (remaining) { + if (remaining < expected) { + Module['setStatus'](`{message} ({expected - remaining}/{expected})`); + } else { + Module['setStatus'](message); + } + } else { + Module['setStatus'](''); + } + } + }, + init() { + Module['preMainLoop'] && MainLoop.preMainLoop.push(Module['preMainLoop']); + Module['postMainLoop'] && MainLoop.postMainLoop.push(Module['postMainLoop']); + }, + runIter(func) { + if (ABORT) return; + for (var pre of MainLoop.preMainLoop) { + if (pre() === false) { + return; // |return false| skips a frame + } + } + callUserCallback(func); + for (var post of MainLoop.postMainLoop) { + post(); + } + }, + nextRAF:0, + fakeRequestAnimationFrame(func) { + // try to keep 60fps between calls to here + var now = Date.now(); + if (MainLoop.nextRAF === 0) { + MainLoop.nextRAF = now + 1000/60; + } else { + while (now + 2 >= MainLoop.nextRAF) { // fudge a little, to avoid timer jitter causing us to do lots of delay:0 + MainLoop.nextRAF += 1000/60; + } + } + var delay = Math.max(MainLoop.nextRAF - now, 0); + setTimeout(func, delay); + }, + requestAnimationFrame(func) { + if (globalThis.requestAnimationFrame) { + requestAnimationFrame(func); + } else { + MainLoop.fakeRequestAnimationFrame(func); + } + }, + }; + + var AL = { + QUEUE_INTERVAL:25, + QUEUE_LOOKAHEAD:0.1, + DEVICE_NAME:"Emscripten OpenAL", + CAPTURE_DEVICE_NAME:"Emscripten OpenAL capture", + ALC_EXTENSIONS:{ + ALC_SOFT_pause_device:true, + ALC_SOFT_HRTF:true, + }, + AL_EXTENSIONS:{ + AL_EXT_float32:true, + AL_SOFT_loop_points:true, + AL_SOFT_source_length:true, + AL_EXT_source_distance_model:true, + AL_SOFT_source_spatialize:true, + }, + _alcErr:0, + alcErr:0, + deviceRefCounts:{ + }, + alcStringCache:{ + }, + paused:false, + stringCache:{ + }, + contexts:{ + }, + currentCtx:null, + buffers:{ + 0:{ + id:0, + refCount:0, + audioBuf:null, + frequency:0, + bytesPerSample:2, + channels:1, + length:0, + }, + }, + paramArray:[], + _nextId:1, + newId:() => AL.freeIds.length > 0 ? AL.freeIds.pop() : AL._nextId++, + freeIds:[], + scheduleContextAudio:(ctx) => { + // If we are animating using the requestAnimationFrame method, then the main loop does not run when in the background. + // To give a perfect glitch-free audio stop when switching from foreground to background, we need to avoid updating + // audio altogether when in the background, so detect that case and kill audio buffer streaming if so. + if (MainLoop.timingMode === 1 && document['visibilityState'] != 'visible') { + return; + } + + for (var i in ctx.sources) { + AL.scheduleSourceAudio(ctx.sources[i]); + } + }, + scheduleSourceAudio:(src, lookahead) => { + // See comment on scheduleContextAudio above. + if (MainLoop.timingMode === 1 && document['visibilityState'] != 'visible') { + return; + } + if (src.state !== 4114) { + return; + } + + var currentTime = AL.updateSourceTime(src); + + var startTime = src.bufStartTime; + var startOffset = src.bufOffset; + var bufCursor = src.bufsProcessed; + + // Advance past any audio that is already scheduled + for (var i = 0; i < src.audioQueue.length; i++) { + var audioSrc = src.audioQueue[i]; + startTime = audioSrc._startTime + audioSrc._duration; + startOffset = 0.0; + bufCursor += audioSrc._skipCount + 1; + } + + if (!lookahead) { + lookahead = AL.QUEUE_LOOKAHEAD; + } + var lookaheadTime = currentTime + lookahead; + var skipCount = 0; + while (startTime < lookaheadTime) { + if (bufCursor >= src.bufQueue.length) { + if (src.looping) { + bufCursor %= src.bufQueue.length; + } else { + break; + } + } + + var buf = src.bufQueue[bufCursor % src.bufQueue.length]; + // If the buffer contains no data, skip it + if (buf.length === 0) { + skipCount++; + // If we've gone through the whole queue and everything is 0 length, just give up + if (skipCount === src.bufQueue.length) { + break; + } + } else { + var audioSrc = src.context.audioCtx.createBufferSource(); + audioSrc.buffer = buf.audioBuf; + audioSrc.playbackRate.value = src.playbackRate; + if (buf.audioBuf._loopStart || buf.audioBuf._loopEnd) { + audioSrc.loopStart = buf.audioBuf._loopStart; + audioSrc.loopEnd = buf.audioBuf._loopEnd; + } + + var duration = 0.0; + // If the source is a looping static buffer, use native looping for gapless playback + if (src.type === 4136 && src.looping) { + duration = Number.POSITIVE_INFINITY; + audioSrc.loop = true; + if (buf.audioBuf._loopStart) { + audioSrc.loopStart = buf.audioBuf._loopStart; + } + if (buf.audioBuf._loopEnd) { + audioSrc.loopEnd = buf.audioBuf._loopEnd; + } + } else { + duration = (buf.audioBuf.duration - startOffset) / src.playbackRate; + } + + audioSrc._startOffset = startOffset; + audioSrc._duration = duration; + audioSrc._skipCount = skipCount; + skipCount = 0; + + audioSrc.connect(src.gain); + + if (typeof audioSrc.start != 'undefined') { + // Sample the current time as late as possible to mitigate drift + startTime = Math.max(startTime, src.context.audioCtx.currentTime); + audioSrc.start(startTime, startOffset); + } else if (typeof audioSrc.noteOn != 'undefined') { + startTime = Math.max(startTime, src.context.audioCtx.currentTime); + audioSrc.noteOn(startTime); + } + audioSrc._startTime = startTime; + src.audioQueue.push(audioSrc); + + startTime += duration; + } + + startOffset = 0.0; + bufCursor++; + } + }, + updateSourceTime:(src) => { + var currentTime = src.context.audioCtx.currentTime; + if (src.state !== 4114) { + return currentTime; + } + + // if the start time is unset, determine it based on the current offset. + // This will be the case when a source is resumed after being paused, and + // allows us to pretend that the source actually started playing some time + // in the past such that it would just now have reached the stored offset. + if (!isFinite(src.bufStartTime)) { + src.bufStartTime = currentTime - src.bufOffset / src.playbackRate; + src.bufOffset = 0.0; + } + + var nextStartTime = 0.0; + while (src.audioQueue.length) { + var audioSrc = src.audioQueue[0]; + src.bufsProcessed += audioSrc._skipCount; + nextStartTime = audioSrc._startTime + audioSrc._duration; // n.b. audioSrc._duration already factors in playbackRate, so no divide by src.playbackRate on it. + + if (currentTime < nextStartTime) { + break; + } + + src.audioQueue.shift(); + src.bufStartTime = nextStartTime; + src.bufOffset = 0.0; + src.bufsProcessed++; + } + + if (src.bufsProcessed >= src.bufQueue.length && !src.looping) { + // The source has played its entire queue and is non-looping, so just mark it as stopped. + AL.setSourceState(src, 4116); + } else if (src.type === 4136 && src.looping) { + // If the source is a looping static buffer, determine the buffer offset based on the loop points + var buf = src.bufQueue[0]; + if (buf.length === 0) { + src.bufOffset = 0.0; + } else { + var delta = (currentTime - src.bufStartTime) * src.playbackRate; + var loopStart = buf.audioBuf._loopStart || 0.0; + var loopEnd = buf.audioBuf._loopEnd || buf.audioBuf.duration; + if (loopEnd <= loopStart) { + loopEnd = buf.audioBuf.duration; + } + + if (delta < loopEnd) { + src.bufOffset = delta; + } else { + src.bufOffset = loopStart + (delta - loopStart) % (loopEnd - loopStart); + } + } + } else if (src.audioQueue[0]) { + // The source is still actively playing, so we just need to calculate where we are in the current buffer + // so it can be remembered if the source gets paused. + src.bufOffset = (currentTime - src.audioQueue[0]._startTime) * src.playbackRate; + } else { + // The source hasn't finished yet, but there is no scheduled audio left for it. This can be because + // the source has just been started/resumed, or due to an underrun caused by a long blocking operation. + // We need to determine what state we would be in by this point in time so that when we next schedule + // audio playback, it will be just as if no underrun occurred. + + if (src.type !== 4136 && src.looping) { + // if the source is a looping buffer queue, let's first calculate the queue duration, so we can + // quickly fast forward past any full loops of the queue and only worry about the remainder. + var srcDuration = AL.sourceDuration(src) / src.playbackRate; + if (srcDuration > 0.0) { + src.bufStartTime += Math.floor((currentTime - src.bufStartTime) / srcDuration) * srcDuration; + } + } + + // Since we've already skipped any full-queue loops if there were any, we just need to find + // out where in the queue the remaining time puts us, which won't require stepping through the + // entire queue more than once. + for (var i = 0; i < src.bufQueue.length; i++) { + if (src.bufsProcessed >= src.bufQueue.length) { + if (src.looping) { + src.bufsProcessed %= src.bufQueue.length; + } else { + AL.setSourceState(src, 4116); + break; + } + } + + var buf = src.bufQueue[src.bufsProcessed]; + if (buf.length > 0) { + nextStartTime = src.bufStartTime + buf.audioBuf.duration / src.playbackRate; + + if (currentTime < nextStartTime) { + src.bufOffset = (currentTime - src.bufStartTime) * src.playbackRate; + break; + } + + src.bufStartTime = nextStartTime; + } + + src.bufOffset = 0.0; + src.bufsProcessed++; + } + } + + return currentTime; + }, + cancelPendingSourceAudio:(src) => { + AL.updateSourceTime(src); + + for (var i = 1; i < src.audioQueue.length; i++) { + var audioSrc = src.audioQueue[i]; + audioSrc.stop(); + } + + if (src.audioQueue.length > 1) { + src.audioQueue.length = 1; + } + }, + stopSourceAudio:(src) => { + for (var i = 0; i < src.audioQueue.length; i++) { + src.audioQueue[i].stop(); + } + src.audioQueue.length = 0; + }, + setSourceState:(src, state) => { + if (state === 4114) { + if (src.state === 4114 || src.state == 4116) { + src.bufsProcessed = 0; + src.bufOffset = 0.0; + } else { + } + + AL.stopSourceAudio(src); + + src.state = 4114; + src.bufStartTime = Number.NEGATIVE_INFINITY; + AL.scheduleSourceAudio(src); + } else if (state === 4115) { + if (src.state === 4114) { + // Store off the current offset to restore with on resume. + AL.updateSourceTime(src); + AL.stopSourceAudio(src); + + src.state = 4115; + } + } else if (state === 4116) { + if (src.state !== 4113) { + src.state = 4116; + src.bufsProcessed = src.bufQueue.length; + src.bufStartTime = Number.NEGATIVE_INFINITY; + src.bufOffset = 0.0; + AL.stopSourceAudio(src); + } + } else if (state === 4113) { + if (src.state !== 4113) { + src.state = 4113; + src.bufsProcessed = 0; + src.bufStartTime = Number.NEGATIVE_INFINITY; + src.bufOffset = 0.0; + AL.stopSourceAudio(src); + } + } + }, + initSourcePanner:(src) => { + if (src.type === 0x1030 /* AL_UNDETERMINED */) { + return; + } + + // Find the first non-zero buffer in the queue to determine the proper format + var templateBuf = AL.buffers[0]; + for (var i = 0; i < src.bufQueue.length; i++) { + if (src.bufQueue[i].id !== 0) { + templateBuf = src.bufQueue[i]; + break; + } + } + // Create a panner if AL_SOURCE_SPATIALIZE_SOFT is set to true, or alternatively if it's set to auto and the source is mono + if (src.spatialize === 1 || (src.spatialize === 2 /* AL_AUTO_SOFT */ && templateBuf.channels === 1)) { + if (src.panner) { + return; + } + src.panner = src.context.audioCtx.createPanner(); + + AL.updateSourceGlobal(src); + AL.updateSourceSpace(src); + + src.panner.connect(src.context.gain); + src.gain.disconnect(); + src.gain.connect(src.panner); + } else { + if (!src.panner) { + return; + } + + src.panner.disconnect(); + src.gain.disconnect(); + src.gain.connect(src.context.gain); + src.panner = null; + } + }, + updateContextGlobal:(ctx) => { + for (var i in ctx.sources) { + AL.updateSourceGlobal(ctx.sources[i]); + } + }, + updateSourceGlobal:(src) => { + var panner = src.panner; + if (!panner) { + return; + } + + panner.refDistance = src.refDistance; + panner.maxDistance = src.maxDistance; + panner.rolloffFactor = src.rolloffFactor; + + panner.panningModel = src.context.hrtf ? 'HRTF' : 'equalpower'; + + // Use the source's distance model if AL_SOURCE_DISTANCE_MODEL is enabled + var distanceModel = src.context.sourceDistanceModel ? src.distanceModel : src.context.distanceModel; + switch (distanceModel) { + case 0: + panner.distanceModel = 'inverse'; + panner.refDistance = 3.40282e38 /* FLT_MAX */; + break; + case 0xd001 /* AL_INVERSE_DISTANCE */: + case 0xd002 /* AL_INVERSE_DISTANCE_CLAMPED */: + panner.distanceModel = 'inverse'; + break; + case 0xd003 /* AL_LINEAR_DISTANCE */: + case 0xd004 /* AL_LINEAR_DISTANCE_CLAMPED */: + panner.distanceModel = 'linear'; + break; + case 0xd005 /* AL_EXPONENT_DISTANCE */: + case 0xd006 /* AL_EXPONENT_DISTANCE_CLAMPED */: + panner.distanceModel = 'exponential'; + break; + } + }, + updateListenerSpace:(ctx) => { + var listener = ctx.audioCtx.listener; + if (listener.positionX) { + listener.positionX.value = ctx.listener.position[0]; + listener.positionY.value = ctx.listener.position[1]; + listener.positionZ.value = ctx.listener.position[2]; + } else { + listener.setPosition(ctx.listener.position[0], ctx.listener.position[1], ctx.listener.position[2]); + } + if (listener.forwardX) { + listener.forwardX.value = ctx.listener.direction[0]; + listener.forwardY.value = ctx.listener.direction[1]; + listener.forwardZ.value = ctx.listener.direction[2]; + listener.upX.value = ctx.listener.up[0]; + listener.upY.value = ctx.listener.up[1]; + listener.upZ.value = ctx.listener.up[2]; + } else { + listener.setOrientation( + ctx.listener.direction[0], ctx.listener.direction[1], ctx.listener.direction[2], + ctx.listener.up[0], ctx.listener.up[1], ctx.listener.up[2]); + } + + // Update sources that are relative to the listener + for (var i in ctx.sources) { + AL.updateSourceSpace(ctx.sources[i]); + } + }, + updateSourceSpace:(src) => { + if (!src.panner) { + return; + } + var panner = src.panner; + + var posX = src.position[0]; + var posY = src.position[1]; + var posZ = src.position[2]; + var dirX = src.direction[0]; + var dirY = src.direction[1]; + var dirZ = src.direction[2]; + + var listener = src.context.listener; + var lPosX = listener.position[0]; + var lPosY = listener.position[1]; + var lPosZ = listener.position[2]; + + // WebAudio does spatialization in world-space coordinates, meaning both the buffer sources and + // the listener position are in the same absolute coordinate system relative to a fixed origin. + // By default, OpenAL works this way as well, but it also provides a "listener relative" mode, where + // a buffer source's coordinate are interpreted not in absolute world space, but as being relative + // to the listener object itself, so as the listener moves the source appears to move with it + // with no update required. Since web audio does not support this mode, we must transform the source + // coordinates from listener-relative space to absolute world space. + // + // We do this via affine transformation matrices applied to the source position and source direction. + // A change-of-basis converts from listener-space displacements to world-space displacements, + // which must be done for both the source position and direction. Lastly, the source position must be + // added to the listener position to get the final source position, since the source position represents + // a displacement from the listener. + if (src.relative) { + // Negate the listener direction since forward is -Z. + var lBackX = -listener.direction[0]; + var lBackY = -listener.direction[1]; + var lBackZ = -listener.direction[2]; + var lUpX = listener.up[0]; + var lUpY = listener.up[1]; + var lUpZ = listener.up[2]; + + var inverseMagnitude = (x, y, z) => { + var length = Math.sqrt(x * x + y * y + z * z); + + if (length < Number.EPSILON) { + return 0.0; + } + + return 1.0 / length; + }; + + // Normalize the Back vector + var invMag = inverseMagnitude(lBackX, lBackY, lBackZ); + lBackX *= invMag; + lBackY *= invMag; + lBackZ *= invMag; + + // ...and the Up vector + invMag = inverseMagnitude(lUpX, lUpY, lUpZ); + lUpX *= invMag; + lUpY *= invMag; + lUpZ *= invMag; + + // Calculate the Right vector as the cross product of the Up and Back vectors + var lRightX = (lUpY * lBackZ - lUpZ * lBackY); + var lRightY = (lUpZ * lBackX - lUpX * lBackZ); + var lRightZ = (lUpX * lBackY - lUpY * lBackX); + + // Back and Up might not be exactly perpendicular, so the cross product also needs normalization + invMag = inverseMagnitude(lRightX, lRightY, lRightZ); + lRightX *= invMag; + lRightY *= invMag; + lRightZ *= invMag; + + // Recompute Up from the now orthonormal Right and Back vectors so we have a fully orthonormal basis + lUpX = (lBackY * lRightZ - lBackZ * lRightY); + lUpY = (lBackZ * lRightX - lBackX * lRightZ); + lUpZ = (lBackX * lRightY - lBackY * lRightX); + + var oldX = dirX; + var oldY = dirY; + var oldZ = dirZ; + + // Use our 3 vectors to apply a change-of-basis matrix to the source direction + dirX = oldX * lRightX + oldY * lUpX + oldZ * lBackX; + dirY = oldX * lRightY + oldY * lUpY + oldZ * lBackY; + dirZ = oldX * lRightZ + oldY * lUpZ + oldZ * lBackZ; + + oldX = posX; + oldY = posY; + oldZ = posZ; + + // ...and to the source position + posX = oldX * lRightX + oldY * lUpX + oldZ * lBackX; + posY = oldX * lRightY + oldY * lUpY + oldZ * lBackY; + posZ = oldX * lRightZ + oldY * lUpZ + oldZ * lBackZ; + + // The change-of-basis corrects the orientation, but the origin is still the listener. + // Translate the source position by the listener position to finish. + posX += lPosX; + posY += lPosY; + posZ += lPosZ; + } + + if (panner.positionX) { + // Assigning to panner.positionX/Y/Z unnecessarily seems to cause performance issues + // See https://github.com/emscripten-core/emscripten/issues/15847 + + if (posX != panner.positionX.value) panner.positionX.value = posX; + if (posY != panner.positionY.value) panner.positionY.value = posY; + if (posZ != panner.positionZ.value) panner.positionZ.value = posZ; + } else { + panner.setPosition(posX, posY, posZ); + } + if (panner.orientationX) { + // Assigning to panner.orientation/Y/Z unnecessarily seems to cause performance issues + // See https://github.com/emscripten-core/emscripten/issues/15847 + + if (dirX != panner.orientationX.value) panner.orientationX.value = dirX; + if (dirY != panner.orientationY.value) panner.orientationY.value = dirY; + if (dirZ != panner.orientationZ.value) panner.orientationZ.value = dirZ; + } else { + panner.setOrientation(dirX, dirY, dirZ); + } + + var oldShift = src.dopplerShift; + var velX = src.velocity[0]; + var velY = src.velocity[1]; + var velZ = src.velocity[2]; + var lVelX = listener.velocity[0]; + var lVelY = listener.velocity[1]; + var lVelZ = listener.velocity[2]; + if (posX === lPosX && posY === lPosY && posZ === lPosZ + || velX === lVelX && velY === lVelY && velZ === lVelZ) + { + src.dopplerShift = 1.0; + } else { + // Doppler algorithm from 1.1 spec + var speedOfSound = src.context.speedOfSound; + var dopplerFactor = src.context.dopplerFactor; + + var slX = lPosX - posX; + var slY = lPosY - posY; + var slZ = lPosZ - posZ; + + var magSl = Math.sqrt(slX * slX + slY * slY + slZ * slZ); + var vls = (slX * lVelX + slY * lVelY + slZ * lVelZ) / magSl; + var vss = (slX * velX + slY * velY + slZ * velZ) / magSl; + + vls = Math.min(vls, speedOfSound / dopplerFactor); + vss = Math.min(vss, speedOfSound / dopplerFactor); + + src.dopplerShift = (speedOfSound - dopplerFactor * vls) / (speedOfSound - dopplerFactor * vss); + } + if (src.dopplerShift !== oldShift) { + AL.updateSourceRate(src); + } + }, + updateSourceRate:(src) => { + if (src.state === 4114) { + // clear scheduled buffers + AL.cancelPendingSourceAudio(src); + + var audioSrc = src.audioQueue[0]; + if (!audioSrc) { + return; // It is possible that AL.scheduleContextAudio() has not yet fed the next buffer, if so, skip. + } + + var duration; + if (src.type === 4136 && src.looping) { + duration = Number.POSITIVE_INFINITY; + } else { + // audioSrc._duration is expressed after factoring in playbackRate, so when changing playback rate, need + // to recompute/rescale the rate to the new playback speed. + duration = (audioSrc.buffer.duration - audioSrc._startOffset) / src.playbackRate; + } + + audioSrc._duration = duration; + audioSrc.playbackRate.value = src.playbackRate; + + // reschedule buffers with the new playbackRate + AL.scheduleSourceAudio(src); + } + }, + sourceDuration:(src) => { + var length = 0.0; + for (var i = 0; i < src.bufQueue.length; i++) { + var audioBuf = src.bufQueue[i].audioBuf; + length += audioBuf ? audioBuf.duration : 0.0; + } + return length; + }, + sourceTell:(src) => { + AL.updateSourceTime(src); + + var offset = 0.0; + for (var i = 0; i < src.bufsProcessed; i++) { + if (src.bufQueue[i].audioBuf) { + offset += src.bufQueue[i].audioBuf.duration; + } + } + offset += src.bufOffset; + + return offset; + }, + sourceSeek:(src, offset) => { + var playing = src.state == 4114; + if (playing) { + AL.setSourceState(src, 4113); + } + + if (src.bufQueue[src.bufsProcessed].audioBuf !== null) { + src.bufsProcessed = 0; + while (offset > src.bufQueue[src.bufsProcessed].audioBuf.duration) { + offset -= src.bufQueue[src.bufsProcessed].audioBuf.duration; + src.bufsProcessed++; + } + + src.bufOffset = offset; + } + + if (playing) { + AL.setSourceState(src, 4114); + } + }, + getGlobalParam:(funcname, param) => { + if (!AL.currentCtx) { + return null; + } + + switch (param) { + case 49152: + return AL.currentCtx.dopplerFactor; + case 49155: + return AL.currentCtx.speedOfSound; + case 53248: + return AL.currentCtx.distanceModel; + default: + AL.currentCtx.err = 40962; + return null; + } + }, + setGlobalParam:(funcname, param, value) => { + if (!AL.currentCtx) { + return; + } + + switch (param) { + case 49152: + if (!Number.isFinite(value) || value < 0.0) { // Strictly negative values are disallowed + AL.currentCtx.err = 40963; + return; + } + + AL.currentCtx.dopplerFactor = value; + AL.updateListenerSpace(AL.currentCtx); + break; + case 49155: + if (!Number.isFinite(value) || value <= 0.0) { // Negative or zero values are disallowed + AL.currentCtx.err = 40963; + return; + } + + AL.currentCtx.speedOfSound = value; + AL.updateListenerSpace(AL.currentCtx); + break; + case 53248: + switch (value) { + case 0: + case 0xd001 /* AL_INVERSE_DISTANCE */: + case 0xd002 /* AL_INVERSE_DISTANCE_CLAMPED */: + case 0xd003 /* AL_LINEAR_DISTANCE */: + case 0xd004 /* AL_LINEAR_DISTANCE_CLAMPED */: + case 0xd005 /* AL_EXPONENT_DISTANCE */: + case 0xd006 /* AL_EXPONENT_DISTANCE_CLAMPED */: + AL.currentCtx.distanceModel = value; + AL.updateContextGlobal(AL.currentCtx); + break; + default: + AL.currentCtx.err = 40963; + return; + } + break; + default: + AL.currentCtx.err = 40962; + return; + } + }, + getListenerParam:(funcname, param) => { + if (!AL.currentCtx) { + return null; + } + + switch (param) { + case 4100: + return AL.currentCtx.listener.position; + case 4102: + return AL.currentCtx.listener.velocity; + case 4111: + return AL.currentCtx.listener.direction.concat(AL.currentCtx.listener.up); + case 4106: + return AL.currentCtx.gain.gain.value; + default: + AL.currentCtx.err = 40962; + return null; + } + }, + setListenerParam:(funcname, param, value) => { + if (!AL.currentCtx) { + return; + } + if (value === null) { + AL.currentCtx.err = 40962; + return; + } + + var listener = AL.currentCtx.listener; + switch (param) { + case 4100: + if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) { + AL.currentCtx.err = 40963; + return; + } + + listener.position[0] = value[0]; + listener.position[1] = value[1]; + listener.position[2] = value[2]; + AL.updateListenerSpace(AL.currentCtx); + break; + case 4102: + if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) { + AL.currentCtx.err = 40963; + return; + } + + listener.velocity[0] = value[0]; + listener.velocity[1] = value[1]; + listener.velocity[2] = value[2]; + AL.updateListenerSpace(AL.currentCtx); + break; + case 4106: + if (!Number.isFinite(value) || value < 0.0) { + AL.currentCtx.err = 40963; + return; + } + + AL.currentCtx.gain.gain.value = value; + break; + case 4111: + if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2]) + || !Number.isFinite(value[3]) || !Number.isFinite(value[4]) || !Number.isFinite(value[5]) + ) { + AL.currentCtx.err = 40963; + return; + } + + listener.direction[0] = value[0]; + listener.direction[1] = value[1]; + listener.direction[2] = value[2]; + listener.up[0] = value[3]; + listener.up[1] = value[4]; + listener.up[2] = value[5]; + AL.updateListenerSpace(AL.currentCtx); + break; + default: + AL.currentCtx.err = 40962; + return; + } + }, + getBufferParam:(funcname, bufferId, param) => { + if (!AL.currentCtx) { + return; + } + var buf = AL.buffers[bufferId]; + if (!buf || bufferId === 0) { + AL.currentCtx.err = 40961; + return; + } + + switch (param) { + case 0x2001 /* AL_FREQUENCY */: + return buf.frequency; + case 0x2002 /* AL_BITS */: + return buf.bytesPerSample * 8; + case 0x2003 /* AL_CHANNELS */: + return buf.channels; + case 0x2004 /* AL_SIZE */: + return buf.length * buf.bytesPerSample * buf.channels; + case 0x2015 /* AL_LOOP_POINTS_SOFT */: + if (buf.length === 0) { + return [0, 0]; + } + return [ + (buf.audioBuf._loopStart || 0.0) * buf.frequency, + (buf.audioBuf._loopEnd || buf.length) * buf.frequency + ]; + default: + AL.currentCtx.err = 40962; + return null; + } + }, + setBufferParam:(funcname, bufferId, param, value) => { + if (!AL.currentCtx) { + return; + } + var buf = AL.buffers[bufferId]; + if (!buf || bufferId === 0) { + AL.currentCtx.err = 40961; + return; + } + if (value === null) { + AL.currentCtx.err = 40962; + return; + } + + switch (param) { + case 0x2004 /* AL_SIZE */: + if (value !== 0) { + AL.currentCtx.err = 40963; + return; + } + + // Per the spec, setting AL_SIZE to 0 is a legal NOP. + break; + case 0x2015 /* AL_LOOP_POINTS_SOFT */: + if (value[0] < 0 || value[0] > buf.length || value[1] < 0 || value[1] > buf.Length || value[0] >= value[1]) { + AL.currentCtx.err = 40963; + return; + } + if (buf.refCount > 0) { + AL.currentCtx.err = 40964; + return; + } + + if (buf.audioBuf) { + buf.audioBuf._loopStart = value[0] / buf.frequency; + buf.audioBuf._loopEnd = value[1] / buf.frequency; + } + break; + default: + AL.currentCtx.err = 40962; + return; + } + }, + getSourceParam:(funcname, sourceId, param) => { + if (!AL.currentCtx) { + return null; + } + var src = AL.currentCtx.sources[sourceId]; + if (!src) { + AL.currentCtx.err = 40961; + return null; + } + + switch (param) { + case 0x202 /* AL_SOURCE_RELATIVE */: + return src.relative; + case 0x1001 /* AL_CONE_INNER_ANGLE */: + return src.coneInnerAngle; + case 0x1002 /* AL_CONE_OUTER_ANGLE */: + return src.coneOuterAngle; + case 0x1003 /* AL_PITCH */: + return src.pitch; + case 4100: + return src.position; + case 4101: + return src.direction; + case 4102: + return src.velocity; + case 0x1007 /* AL_LOOPING */: + return src.looping; + case 0x1009 /* AL_BUFFER */: + if (src.type === 4136) { + return src.bufQueue[0].id; + } + return 0; + case 4106: + return src.gain.gain.value; + case 0x100D /* AL_MIN_GAIN */: + return src.minGain; + case 0x100E /* AL_MAX_GAIN */: + return src.maxGain; + case 0x1010 /* AL_SOURCE_STATE */: + return src.state; + case 0x1015 /* AL_BUFFERS_QUEUED */: + if (src.bufQueue.length === 1 && src.bufQueue[0].id === 0) { + return 0; + } + return src.bufQueue.length; + case 0x1016 /* AL_BUFFERS_PROCESSED */: + if ((src.bufQueue.length === 1 && src.bufQueue[0].id === 0) || src.looping) { + return 0; + } + return src.bufsProcessed; + case 0x1020 /* AL_REFERENCE_DISTANCE */: + return src.refDistance; + case 0x1021 /* AL_ROLLOFF_FACTOR */: + return src.rolloffFactor; + case 0x1022 /* AL_CONE_OUTER_GAIN */: + return src.coneOuterGain; + case 0x1023 /* AL_MAX_DISTANCE */: + return src.maxDistance; + case 0x1024 /* AL_SEC_OFFSET */: + return AL.sourceTell(src); + case 0x1025 /* AL_SAMPLE_OFFSET */: + var offset = AL.sourceTell(src); + if (offset > 0.0) { + offset *= src.bufQueue[0].frequency; + } + return offset; + case 0x1026 /* AL_BYTE_OFFSET */: + var offset = AL.sourceTell(src); + if (offset > 0.0) { + offset *= src.bufQueue[0].frequency * src.bufQueue[0].bytesPerSample; + } + return offset; + case 0x1027 /* AL_SOURCE_TYPE */: + return src.type; + case 0x1214 /* AL_SOURCE_SPATIALIZE_SOFT */: + return src.spatialize; + case 0x2009 /* AL_BYTE_LENGTH_SOFT */: + var length = 0; + var bytesPerFrame = 0; + for (var i = 0; i < src.bufQueue.length; i++) { + length += src.bufQueue[i].length; + if (src.bufQueue[i].id !== 0) { + bytesPerFrame = src.bufQueue[i].bytesPerSample * src.bufQueue[i].channels; + } + } + return length * bytesPerFrame; + case 0x200A /* AL_SAMPLE_LENGTH_SOFT */: + var length = 0; + for (var i = 0; i < src.bufQueue.length; i++) { + length += src.bufQueue[i].length; + } + return length; + case 0x200B /* AL_SEC_LENGTH_SOFT */: + return AL.sourceDuration(src); + case 53248: + return src.distanceModel; + default: + AL.currentCtx.err = 40962; + return null; + } + }, + setSourceParam:(funcname, sourceId, param, value) => { + if (!AL.currentCtx) { + return; + } + var src = AL.currentCtx.sources[sourceId]; + if (!src) { + AL.currentCtx.err = 40961; + return; + } + if (value === null) { + AL.currentCtx.err = 40962; + return; + } + + switch (param) { + case 0x202 /* AL_SOURCE_RELATIVE */: + if (value === 1) { + src.relative = true; + AL.updateSourceSpace(src); + } else if (value === 0) { + src.relative = false; + AL.updateSourceSpace(src); + } else { + AL.currentCtx.err = 40963; + return; + } + break; + case 0x1001 /* AL_CONE_INNER_ANGLE */: + if (!Number.isFinite(value)) { + AL.currentCtx.err = 40963; + return; + } + + src.coneInnerAngle = value; + if (src.panner) { + src.panner.coneInnerAngle = value % 360.0; + } + break; + case 0x1002 /* AL_CONE_OUTER_ANGLE */: + if (!Number.isFinite(value)) { + AL.currentCtx.err = 40963; + return; + } + + src.coneOuterAngle = value; + if (src.panner) { + src.panner.coneOuterAngle = value % 360.0; + } + break; + case 0x1003 /* AL_PITCH */: + if (!Number.isFinite(value) || value <= 0.0) { + AL.currentCtx.err = 40963; + return; + } + + if (src.pitch === value) { + break; + } + + src.pitch = value; + AL.updateSourceRate(src); + break; + case 4100: + if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) { + AL.currentCtx.err = 40963; + return; + } + + src.position[0] = value[0]; + src.position[1] = value[1]; + src.position[2] = value[2]; + AL.updateSourceSpace(src); + break; + case 4101: + if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) { + AL.currentCtx.err = 40963; + return; + } + + src.direction[0] = value[0]; + src.direction[1] = value[1]; + src.direction[2] = value[2]; + AL.updateSourceSpace(src); + break; + case 4102: + if (!Number.isFinite(value[0]) || !Number.isFinite(value[1]) || !Number.isFinite(value[2])) { + AL.currentCtx.err = 40963; + return; + } + + src.velocity[0] = value[0]; + src.velocity[1] = value[1]; + src.velocity[2] = value[2]; + AL.updateSourceSpace(src); + break; + case 0x1007 /* AL_LOOPING */: + if (value === 1) { + src.looping = true; + AL.updateSourceTime(src); + if (src.type === 4136 && src.audioQueue.length > 0) { + var audioSrc = src.audioQueue[0]; + audioSrc.loop = true; + audioSrc._duration = Number.POSITIVE_INFINITY; + } + } else if (value === 0) { + src.looping = false; + var currentTime = AL.updateSourceTime(src); + if (src.type === 4136 && src.audioQueue.length > 0) { + var audioSrc = src.audioQueue[0]; + audioSrc.loop = false; + audioSrc._duration = src.bufQueue[0].audioBuf.duration / src.playbackRate; + audioSrc._startTime = currentTime - src.bufOffset / src.playbackRate; + } + } else { + AL.currentCtx.err = 40963; + return; + } + break; + case 0x1009 /* AL_BUFFER */: + if (src.state === 4114 || src.state === 4115) { + AL.currentCtx.err = 40964; + return; + } + + if (value === 0) { + for (var i in src.bufQueue) { + src.bufQueue[i].refCount--; + } + src.bufQueue.length = 1; + src.bufQueue[0] = AL.buffers[0]; + + src.bufsProcessed = 0; + src.type = 0x1030 /* AL_UNDETERMINED */; + } else { + var buf = AL.buffers[value]; + if (!buf) { + AL.currentCtx.err = 40963; + return; + } + + for (var i in src.bufQueue) { + src.bufQueue[i].refCount--; + } + src.bufQueue.length = 0; + + buf.refCount++; + src.bufQueue = [buf]; + src.bufsProcessed = 0; + src.type = 4136; + } + + AL.initSourcePanner(src); + AL.scheduleSourceAudio(src); + break; + case 4106: + if (!Number.isFinite(value) || value < 0.0) { + AL.currentCtx.err = 40963; + return; + } + src.gain.gain.value = value; + break; + case 0x100D /* AL_MIN_GAIN */: + if (!Number.isFinite(value) || value < 0.0 || value > Math.min(src.maxGain, 1.0)) { + AL.currentCtx.err = 40963; + return; + } + src.minGain = value; + break; + case 0x100E /* AL_MAX_GAIN */: + if (!Number.isFinite(value) || value < Math.max(0.0, src.minGain) || value > 1.0) { + AL.currentCtx.err = 40963; + return; + } + src.maxGain = value; + break; + case 0x1020 /* AL_REFERENCE_DISTANCE */: + if (!Number.isFinite(value) || value < 0.0) { + AL.currentCtx.err = 40963; + return; + } + src.refDistance = value; + if (src.panner) { + src.panner.refDistance = value; + } + break; + case 0x1021 /* AL_ROLLOFF_FACTOR */: + if (!Number.isFinite(value) || value < 0.0) { + AL.currentCtx.err = 40963; + return; + } + src.rolloffFactor = value; + if (src.panner) { + src.panner.rolloffFactor = value; + } + break; + case 0x1022 /* AL_CONE_OUTER_GAIN */: + if (!Number.isFinite(value) || value < 0.0 || value > 1.0) { + AL.currentCtx.err = 40963; + return; + } + src.coneOuterGain = value; + if (src.panner) { + src.panner.coneOuterGain = value; + } + break; + case 0x1023 /* AL_MAX_DISTANCE */: + if (!Number.isFinite(value) || value < 0.0) { + AL.currentCtx.err = 40963; + return; + } + src.maxDistance = value; + if (src.panner) { + src.panner.maxDistance = value; + } + break; + case 0x1024 /* AL_SEC_OFFSET */: + if (value < 0.0 || value > AL.sourceDuration(src)) { + AL.currentCtx.err = 40963; + return; + } + + AL.sourceSeek(src, value); + break; + case 0x1025 /* AL_SAMPLE_OFFSET */: + var srcLen = AL.sourceDuration(src); + if (srcLen > 0.0) { + var frequency; + for (var bufId in src.bufQueue) { + if (bufId) { + frequency = src.bufQueue[bufId].frequency; + break; + } + } + value /= frequency; + } + if (value < 0.0 || value > srcLen) { + AL.currentCtx.err = 40963; + return; + } + + AL.sourceSeek(src, value); + break; + case 0x1026 /* AL_BYTE_OFFSET */: + var srcLen = AL.sourceDuration(src); + if (srcLen > 0.0) { + var bytesPerSec; + for (var bufId in src.bufQueue) { + if (bufId) { + var buf = src.bufQueue[bufId]; + bytesPerSec = buf.frequency * buf.bytesPerSample * buf.channels; + break; + } + } + value /= bytesPerSec; + } + if (value < 0.0 || value > srcLen) { + AL.currentCtx.err = 40963; + return; + } + + AL.sourceSeek(src, value); + break; + case 0x1214 /* AL_SOURCE_SPATIALIZE_SOFT */: + if (value !== 0 && value !== 1 && value !== 2 /* AL_AUTO_SOFT */) { + AL.currentCtx.err = 40963; + return; + } + + src.spatialize = value; + AL.initSourcePanner(src); + break; + case 0x2009 /* AL_BYTE_LENGTH_SOFT */: + case 0x200A /* AL_SAMPLE_LENGTH_SOFT */: + case 0x200B /* AL_SEC_LENGTH_SOFT */: + AL.currentCtx.err = 40964; + break; + case 53248: + switch (value) { + case 0: + case 0xd001 /* AL_INVERSE_DISTANCE */: + case 0xd002 /* AL_INVERSE_DISTANCE_CLAMPED */: + case 0xd003 /* AL_LINEAR_DISTANCE */: + case 0xd004 /* AL_LINEAR_DISTANCE_CLAMPED */: + case 0xd005 /* AL_EXPONENT_DISTANCE */: + case 0xd006 /* AL_EXPONENT_DISTANCE_CLAMPED */: + src.distanceModel = value; + if (AL.currentCtx.sourceDistanceModel) { + AL.updateContextGlobal(AL.currentCtx); + } + break; + default: + AL.currentCtx.err = 40963; + return; + } + break; + default: + AL.currentCtx.err = 40962; + return; + } + }, + captures:{ + }, + sharedCaptureAudioCtx:null, + requireValidCaptureDevice:(deviceId, funcname) => { + if (deviceId === 0) { + AL.alcErr = 40961; + return null; + } + var c = AL.captures[deviceId]; + if (!c) { + AL.alcErr = 40961; + return null; + } + var err = c.mediaStreamError; + if (err) { + AL.alcErr = 40961; + return null; + } + return c; + }, + }; + var _alBuffer3f = (bufferId, param, value0, value1, value2) => { + AL.setBufferParam('alBuffer3f', bufferId, param, null); + }; + _alBuffer3f.sig = 'viifff'; + + var _alBuffer3i = (bufferId, param, value0, value1, value2) => { + AL.setBufferParam('alBuffer3i', bufferId, param, null); + }; + _alBuffer3i.sig = 'viiiii'; + + var _alBufferData = (bufferId, format, pData, size, freq) => { + if (!AL.currentCtx) { + return; + } + var buf = AL.buffers[bufferId]; + if (!buf) { + AL.currentCtx.err = 40963; + return; + } + if (freq <= 0) { + AL.currentCtx.err = 40963; + return; + } + + var audioBuf = null; + try { + switch (format) { + case 0x1100 /* AL_FORMAT_MONO8 */: + if (size > 0) { + audioBuf = AL.currentCtx.audioCtx.createBuffer(1, size, freq); + var channel0 = audioBuf.getChannelData(0); + for (var i = 0; i < size; ++i) { + channel0[i] = HEAPU8[pData++] * 0.0078125 /* 1/128 */ - 1.0; + } + } + buf.bytesPerSample = 1; + buf.channels = 1; + buf.length = size; + break; + case 0x1101 /* AL_FORMAT_MONO16 */: + if (size > 0) { + audioBuf = AL.currentCtx.audioCtx.createBuffer(1, size >> 1, freq); + var channel0 = audioBuf.getChannelData(0); + pData >>= 1; + for (var i = 0; i < size >> 1; ++i) { + channel0[i] = HEAP16[pData++] * 0.000030517578125 /* 1/32768 */; + } + } + buf.bytesPerSample = 2; + buf.channels = 1; + buf.length = size >> 1; + break; + case 0x1102 /* AL_FORMAT_STEREO8 */: + if (size > 0) { + audioBuf = AL.currentCtx.audioCtx.createBuffer(2, size >> 1, freq); + var channel0 = audioBuf.getChannelData(0); + var channel1 = audioBuf.getChannelData(1); + for (var i = 0; i < size >> 1; ++i) { + channel0[i] = HEAPU8[pData++] * 0.0078125 /* 1/128 */ - 1.0; + channel1[i] = HEAPU8[pData++] * 0.0078125 /* 1/128 */ - 1.0; + } + } + buf.bytesPerSample = 1; + buf.channels = 2; + buf.length = size >> 1; + break; + case 0x1103 /* AL_FORMAT_STEREO16 */: + if (size > 0) { + audioBuf = AL.currentCtx.audioCtx.createBuffer(2, size >> 2, freq); + var channel0 = audioBuf.getChannelData(0); + var channel1 = audioBuf.getChannelData(1); + pData >>= 1; + for (var i = 0; i < size >> 2; ++i) { + channel0[i] = HEAP16[pData++] * 0.000030517578125 /* 1/32768 */; + channel1[i] = HEAP16[pData++] * 0.000030517578125 /* 1/32768 */; + } + } + buf.bytesPerSample = 2; + buf.channels = 2; + buf.length = size >> 2; + break; + case 0x10010 /* AL_FORMAT_MONO_FLOAT32 */: + if (size > 0) { + audioBuf = AL.currentCtx.audioCtx.createBuffer(1, size >> 2, freq); + var channel0 = audioBuf.getChannelData(0); + pData >>= 2; + for (var i = 0; i < size >> 2; ++i) { + channel0[i] = HEAPF32[pData++]; + } + } + buf.bytesPerSample = 4; + buf.channels = 1; + buf.length = size >> 2; + break; + case 0x10011 /* AL_FORMAT_STEREO_FLOAT32 */: + if (size > 0) { + audioBuf = AL.currentCtx.audioCtx.createBuffer(2, size >> 3, freq); + var channel0 = audioBuf.getChannelData(0); + var channel1 = audioBuf.getChannelData(1); + pData >>= 2; + for (var i = 0; i < size >> 3; ++i) { + channel0[i] = HEAPF32[pData++]; + channel1[i] = HEAPF32[pData++]; + } + } + buf.bytesPerSample = 4; + buf.channels = 2; + buf.length = size >> 3; + break; + default: + AL.currentCtx.err = 40963; + return; + } + buf.frequency = freq; + buf.audioBuf = audioBuf; + } catch (e) { + AL.currentCtx.err = 40963; + return; + } + }; + _alBufferData.sig = 'viipii'; + + var _alBufferf = (bufferId, param, value) => { + AL.setBufferParam('alBufferf', bufferId, param, null); + }; + _alBufferf.sig = 'viif'; + + var _alBufferfv = (bufferId, param, pValues) => { + if (!AL.currentCtx) { + return; + } + if (!pValues) { + AL.currentCtx.err = 40963; + return; + } + + AL.setBufferParam('alBufferfv', bufferId, param, null); + }; + _alBufferfv.sig = 'viip'; + + var _alBufferi = (bufferId, param, value) => { + AL.setBufferParam('alBufferi', bufferId, param, null); + }; + _alBufferi.sig = 'viii'; + + var _alBufferiv = (bufferId, param, pValues) => { + if (!AL.currentCtx) { + return; + } + if (!pValues) { + AL.currentCtx.err = 40963; + return; + } + + switch (param) { + case 0x2015 /* AL_LOOP_POINTS_SOFT */: + AL.paramArray[0] = HEAP32[((pValues)>>2)]; + AL.paramArray[1] = HEAP32[(((pValues)+(4))>>2)]; + AL.setBufferParam('alBufferiv', bufferId, param, AL.paramArray); + break; + default: + AL.setBufferParam('alBufferiv', bufferId, param, null); + break; + } + }; + _alBufferiv.sig = 'viip'; + + var _alDeleteBuffers = (count, pBufferIds) => { + if (!AL.currentCtx) { + return; + } + + for (var i = 0; i < count; ++i) { + var bufId = HEAP32[(((pBufferIds)+(i*4))>>2)]; + /// Deleting the zero buffer is a legal NOP, so ignore it + if (bufId === 0) { + continue; + } + + // Make sure the buffer index is valid. + if (!AL.buffers[bufId]) { + AL.currentCtx.err = 40961; + return; + } + + // Make sure the buffer is no longer in use. + if (AL.buffers[bufId].refCount) { + AL.currentCtx.err = 40964; + return; + } + } + + for (var i = 0; i < count; ++i) { + var bufId = HEAP32[(((pBufferIds)+(i*4))>>2)]; + if (bufId === 0) { + continue; + } + + AL.deviceRefCounts[AL.buffers[bufId].deviceId]--; + delete AL.buffers[bufId]; + AL.freeIds.push(bufId); + } + }; + _alDeleteBuffers.sig = 'vip'; + + var _alSourcei = (sourceId, param, value) => { + switch (param) { + case 0x202 /* AL_SOURCE_RELATIVE */: + case 0x1001 /* AL_CONE_INNER_ANGLE */: + case 0x1002 /* AL_CONE_OUTER_ANGLE */: + case 0x1007 /* AL_LOOPING */: + case 0x1009 /* AL_BUFFER */: + case 0x1020 /* AL_REFERENCE_DISTANCE */: + case 0x1021 /* AL_ROLLOFF_FACTOR */: + case 0x1023 /* AL_MAX_DISTANCE */: + case 0x1024 /* AL_SEC_OFFSET */: + case 0x1025 /* AL_SAMPLE_OFFSET */: + case 0x1026 /* AL_BYTE_OFFSET */: + case 0x1214 /* AL_SOURCE_SPATIALIZE_SOFT */: + case 0x2009 /* AL_BYTE_LENGTH_SOFT */: + case 0x200A /* AL_SAMPLE_LENGTH_SOFT */: + case 53248: + AL.setSourceParam('alSourcei', sourceId, param, value); + break; + default: + AL.setSourceParam('alSourcei', sourceId, param, null); + break; + } + }; + _alSourcei.sig = 'viii'; + + var _alDeleteSources = (count, pSourceIds) => { + if (!AL.currentCtx) { + return; + } + + for (var i = 0; i < count; ++i) { + var srcId = HEAP32[(((pSourceIds)+(i*4))>>2)]; + if (!AL.currentCtx.sources[srcId]) { + AL.currentCtx.err = 40961; + return; + } + } + + for (var i = 0; i < count; ++i) { + var srcId = HEAP32[(((pSourceIds)+(i*4))>>2)]; + AL.setSourceState(AL.currentCtx.sources[srcId], 4116); + _alSourcei(srcId, 0x1009 /* AL_BUFFER */, 0); + delete AL.currentCtx.sources[srcId]; + AL.freeIds.push(srcId); + } + }; + _alDeleteSources.sig = 'vip'; + + var _alDisable = (param) => { + if (!AL.currentCtx) { + return; + } + switch (param) { + case 0x200 /* AL_SOURCE_DISTANCE_MODEL */: + AL.currentCtx.sourceDistanceModel = false; + AL.updateContextGlobal(AL.currentCtx); + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alDisable.sig = 'vi'; + + var _alDistanceModel = (model) => { + AL.setGlobalParam('alDistanceModel', 53248, model); + }; + _alDistanceModel.sig = 'vi'; + + var _alDopplerFactor = (value) => { + AL.setGlobalParam('alDopplerFactor', 49152, value); + }; + _alDopplerFactor.sig = 'vf'; + + var _alDopplerVelocity = (value) => { + warnOnce('alDopplerVelocity() is deprecated, and only kept for compatibility with OpenAL 1.0. Use alSpeedOfSound() instead.'); + if (!AL.currentCtx) { + return; + } + if (value <= 0) { // Negative or zero values are disallowed + AL.currentCtx.err = 40963; + return; + } + }; + _alDopplerVelocity.sig = 'vf'; + + var _alEnable = (param) => { + if (!AL.currentCtx) { + return; + } + switch (param) { + case 0x200 /* AL_SOURCE_DISTANCE_MODEL */: + AL.currentCtx.sourceDistanceModel = true; + AL.updateContextGlobal(AL.currentCtx); + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alEnable.sig = 'vi'; + + var _alGenBuffers = (count, pBufferIds) => { + if (!AL.currentCtx) { + return; + } + + for (var i = 0; i < count; ++i) { + var buf = { + deviceId: AL.currentCtx.deviceId, + id: AL.newId(), + refCount: 0, + audioBuf: null, + frequency: 0, + bytesPerSample: 2, + channels: 1, + length: 0, + }; + AL.deviceRefCounts[buf.deviceId]++; + AL.buffers[buf.id] = buf; + HEAP32[(((pBufferIds)+(i*4))>>2)] = buf.id; + } + }; + _alGenBuffers.sig = 'vip'; + + var _alGenSources = (count, pSourceIds) => { + if (!AL.currentCtx) { + return; + } + for (var i = 0; i < count; ++i) { + var gain = AL.currentCtx.audioCtx.createGain(); + gain.connect(AL.currentCtx.gain); + var src = { + context: AL.currentCtx, + id: AL.newId(), + type: 0x1030 /* AL_UNDETERMINED */, + state: 4113, + bufQueue: [AL.buffers[0]], + audioQueue: [], + looping: false, + pitch: 1.0, + dopplerShift: 1.0, + gain, + minGain: 0.0, + maxGain: 1.0, + panner: null, + bufsProcessed: 0, + bufStartTime: Number.NEGATIVE_INFINITY, + bufOffset: 0.0, + relative: false, + refDistance: 1.0, + maxDistance: 3.40282e38 /* FLT_MAX */, + rolloffFactor: 1.0, + position: [0.0, 0.0, 0.0], + velocity: [0.0, 0.0, 0.0], + direction: [0.0, 0.0, 0.0], + coneOuterGain: 0.0, + coneInnerAngle: 360.0, + coneOuterAngle: 360.0, + distanceModel: 0xd002 /* AL_INVERSE_DISTANCE_CLAMPED */, + spatialize: 2 /* AL_AUTO_SOFT */, + + get playbackRate() { + return this.pitch * this.dopplerShift; + } + }; + AL.currentCtx.sources[src.id] = src; + HEAP32[(((pSourceIds)+(i*4))>>2)] = src.id; + } + }; + _alGenSources.sig = 'vip'; + + var _alGetBoolean = (param) => { + var val = AL.getGlobalParam('alGetBoolean', param); + if (val === null) { + return 0; + } + + switch (param) { + case 49152: + case 49155: + case 53248: + return val !== 0 ? 1 : 0; + default: + AL.currentCtx.err = 40962; + return 0; + } + }; + _alGetBoolean.sig = 'ii'; + + var _alGetBooleanv = (param, pValues) => { + var val = AL.getGlobalParam('alGetBooleanv', param); + // Silently ignore null destinations, as per the spec for global state functions + if (val === null || !pValues) { + return; + } + + switch (param) { + case 49152: + case 49155: + case 53248: + HEAP8[pValues] = val; + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alGetBooleanv.sig = 'vip'; + + var _alGetBuffer3f = (bufferId, param, pValue0, pValue1, pValue2) => { + var val = AL.getBufferParam('alGetBuffer3f', bufferId, param); + if (val === null) { + return; + } + if (!pValue0 || !pValue1 || !pValue2) { + AL.currentCtx.err = 40963; + return; + } + + AL.currentCtx.err = 40962; + }; + _alGetBuffer3f.sig = 'viippp'; + + var _alGetBuffer3i = (bufferId, param, pValue0, pValue1, pValue2) => { + var val = AL.getBufferParam('alGetBuffer3i', bufferId, param); + if (val === null) { + return; + } + if (!pValue0 || !pValue1 || !pValue2) { + AL.currentCtx.err = 40963; + return; + } + + AL.currentCtx.err = 40962; + }; + _alGetBuffer3i.sig = 'viippp'; + + var _alGetBufferf = (bufferId, param, pValue) => { + var val = AL.getBufferParam('alGetBufferf', bufferId, param); + if (val === null) { + return; + } + if (!pValue) { + AL.currentCtx.err = 40963; + return; + } + + AL.currentCtx.err = 40962; + }; + _alGetBufferf.sig = 'viip'; + + var _alGetBufferfv = (bufferId, param, pValues) => { + var val = AL.getBufferParam('alGetBufferfv', bufferId, param); + if (val === null) { + return; + } + if (!pValues) { + AL.currentCtx.err = 40963; + return; + } + + AL.currentCtx.err = 40962; + }; + _alGetBufferfv.sig = 'viip'; + + var _alGetBufferi = (bufferId, param, pValue) => { + var val = AL.getBufferParam('alGetBufferi', bufferId, param); + if (val === null) { + return; + } + if (!pValue) { + AL.currentCtx.err = 40963; + return; + } + + switch (param) { + case 0x2001 /* AL_FREQUENCY */: + case 0x2002 /* AL_BITS */: + case 0x2003 /* AL_CHANNELS */: + case 0x2004 /* AL_SIZE */: + HEAP32[((pValue)>>2)] = val; + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alGetBufferi.sig = 'viip'; + + var _alGetBufferiv = (bufferId, param, pValues) => { + var val = AL.getBufferParam('alGetBufferiv', bufferId, param); + if (val === null) { + return; + } + if (!pValues) { + AL.currentCtx.err = 40963; + return; + } + + switch (param) { + case 0x2001 /* AL_FREQUENCY */: + case 0x2002 /* AL_BITS */: + case 0x2003 /* AL_CHANNELS */: + case 0x2004 /* AL_SIZE */: + HEAP32[((pValues)>>2)] = val; + break; + case 0x2015 /* AL_LOOP_POINTS_SOFT */: + HEAP32[((pValues)>>2)] = val[0]; + HEAP32[(((pValues)+(4))>>2)] = val[1]; + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alGetBufferiv.sig = 'viip'; + + var _alGetDouble = (param) => { + var val = AL.getGlobalParam('alGetDouble', param); + if (val === null) { + return 0.0; + } + + switch (param) { + case 49152: + case 49155: + case 53248: + return val; + default: + AL.currentCtx.err = 40962; + return 0.0; + } + }; + _alGetDouble.sig = 'di'; + + var _alGetDoublev = (param, pValues) => { + var val = AL.getGlobalParam('alGetDoublev', param); + // Silently ignore null destinations, as per the spec for global state functions + if (val === null || !pValues) { + return; + } + + switch (param) { + case 49152: + case 49155: + case 53248: + HEAPF64[((pValues)>>3)] = val; + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alGetDoublev.sig = 'vip'; + + + var _alGetEnumValue = (pEnumName) => { + if (!AL.currentCtx) { + return 0; + } + + if (!pEnumName) { + AL.currentCtx.err = 40963; + return 0; + } + var name = UTF8ToString(pEnumName); + + switch (name) { + // Spec doesn't clearly state that alGetEnumValue() is required to + // support _only_ extension tokens. + // We should probably follow OpenAL-Soft's example and support all + // of the names we know. + // See http://repo.or.cz/openal-soft.git/blob/HEAD:/Alc/ALc.c + case 'AL_BITS': return 0x2002; + case 'AL_BUFFER': return 0x1009; + case 'AL_BUFFERS_PROCESSED': return 0x1016; + case 'AL_BUFFERS_QUEUED': return 0x1015; + case 'AL_BYTE_OFFSET': return 0x1026; + case 'AL_CHANNELS': return 0x2003; + case 'AL_CONE_INNER_ANGLE': return 0x1001; + case 'AL_CONE_OUTER_ANGLE': return 0x1002; + case 'AL_CONE_OUTER_GAIN': return 0x1022; + case 'AL_DIRECTION': return 0x1005; + case 'AL_DISTANCE_MODEL': return 0xD000; + case 'AL_DOPPLER_FACTOR': return 0xC000; + case 'AL_DOPPLER_VELOCITY': return 0xC001; + case 'AL_EXPONENT_DISTANCE': return 0xD005; + case 'AL_EXPONENT_DISTANCE_CLAMPED': return 0xD006; + case 'AL_EXTENSIONS': return 0xB004; + case 'AL_FORMAT_MONO16': return 0x1101; + case 'AL_FORMAT_MONO8': return 0x1100; + case 'AL_FORMAT_STEREO16': return 0x1103; + case 'AL_FORMAT_STEREO8': return 0x1102; + case 'AL_FREQUENCY': return 0x2001; + case 'AL_GAIN': return 0x100A; + case 'AL_INITIAL': return 0x1011; + case 'AL_INVALID': return -1; + case 'AL_ILLEGAL_ENUM': // fallthrough + case 'AL_INVALID_ENUM': return 0xA002; + case 'AL_INVALID_NAME': return 0xA001; + case 'AL_ILLEGAL_COMMAND': // fallthrough + case 'AL_INVALID_OPERATION': return 0xA004; + case 'AL_INVALID_VALUE': return 0xA003; + case 'AL_INVERSE_DISTANCE': return 0xD001; + case 'AL_INVERSE_DISTANCE_CLAMPED': return 0xD002; + case 'AL_LINEAR_DISTANCE': return 0xD003; + case 'AL_LINEAR_DISTANCE_CLAMPED': return 0xD004; + case 'AL_LOOPING': return 0x1007; + case 'AL_MAX_DISTANCE': return 0x1023; + case 'AL_MAX_GAIN': return 0x100E; + case 'AL_MIN_GAIN': return 0x100D; + case 'AL_NONE': return 0; + case 'AL_NO_ERROR': return 0; + case 'AL_ORIENTATION': return 0x100F; + case 'AL_OUT_OF_MEMORY': return 0xA005; + case 'AL_PAUSED': return 0x1013; + case 'AL_PENDING': return 0x2011; + case 'AL_PITCH': return 0x1003; + case 'AL_PLAYING': return 0x1012; + case 'AL_POSITION': return 0x1004; + case 'AL_PROCESSED': return 0x2012; + case 'AL_REFERENCE_DISTANCE': return 0x1020; + case 'AL_RENDERER': return 0xB003; + case 'AL_ROLLOFF_FACTOR': return 0x1021; + case 'AL_SAMPLE_OFFSET': return 0x1025; + case 'AL_SEC_OFFSET': return 0x1024; + case 'AL_SIZE': return 0x2004; + case 'AL_SOURCE_RELATIVE': return 0x202; + case 'AL_SOURCE_STATE': return 0x1010; + case 'AL_SOURCE_TYPE': return 0x1027; + case 'AL_SPEED_OF_SOUND': return 0xC003; + case 'AL_STATIC': return 0x1028; + case 'AL_STOPPED': return 0x1014; + case 'AL_STREAMING': return 0x1029; + case 'AL_UNDETERMINED': return 0x1030; + case 'AL_UNUSED': return 0x2010; + case 'AL_VELOCITY': return 0x1006; + case 'AL_VENDOR': return 0xB001; + case 'AL_VERSION': return 0xB002; + + /* Extensions */ + case 'AL_AUTO_SOFT': return 0x0002; + case 'AL_SOURCE_DISTANCE_MODEL': return 0x200; + case 'AL_SOURCE_SPATIALIZE_SOFT': return 0x1214; + case 'AL_LOOP_POINTS_SOFT': return 0x2015; + case 'AL_BYTE_LENGTH_SOFT': return 0x2009; + case 'AL_SAMPLE_LENGTH_SOFT': return 0x200A; + case 'AL_SEC_LENGTH_SOFT': return 0x200B; + case 'AL_FORMAT_MONO_FLOAT32': return 0x10010; + case 'AL_FORMAT_STEREO_FLOAT32': return 0x10011; + + default: + AL.currentCtx.err = 40963; + return 0; + } + }; + _alGetEnumValue.sig = 'ip'; + + var _alGetError = () => { + if (!AL.currentCtx) { + return 40964; + } + // Reset error on get. + var err = AL.currentCtx.err; + AL.currentCtx.err = 0; + return err; + }; + _alGetError.sig = 'i'; + + var _alGetFloat = (param) => { + var val = AL.getGlobalParam('alGetFloat', param); + if (val === null) { + return 0.0; + } + + switch (param) { + case 49152: + case 49155: + case 53248: + return val; + default: + return 0.0; + } + }; + _alGetFloat.sig = 'fi'; + + var _alGetFloatv = (param, pValues) => { + var val = AL.getGlobalParam('alGetFloatv', param); + // Silently ignore null destinations, as per the spec for global state functions + if (val === null || !pValues) { + return; + } + + switch (param) { + case 49152: + case 49155: + case 53248: + HEAPF32[((pValues)>>2)] = val; + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alGetFloatv.sig = 'vip'; + + var _alGetInteger = (param) => { + var val = AL.getGlobalParam('alGetInteger', param); + if (val === null) { + return 0; + } + + switch (param) { + case 49152: + case 49155: + case 53248: + return val; + default: + AL.currentCtx.err = 40962; + return 0; + } + }; + _alGetInteger.sig = 'ii'; + + var _alGetIntegerv = (param, pValues) => { + var val = AL.getGlobalParam('alGetIntegerv', param); + // Silently ignore null destinations, as per the spec for global state functions + if (val === null || !pValues) { + return; + } + + switch (param) { + case 49152: + case 49155: + case 53248: + HEAP32[((pValues)>>2)] = val; + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alGetIntegerv.sig = 'vip'; + + var _alGetListener3f = (param, pValue0, pValue1, pValue2) => { + var val = AL.getListenerParam('alGetListener3f', param); + if (val === null) { + return; + } + if (!pValue0 || !pValue1 || !pValue2) { + AL.currentCtx.err = 40963; + return; + } + + switch (param) { + case 4100: + case 4102: + HEAPF32[((pValue0)>>2)] = val[0]; + HEAPF32[((pValue1)>>2)] = val[1]; + HEAPF32[((pValue2)>>2)] = val[2]; + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alGetListener3f.sig = 'vippp'; + + var _alGetListener3i = (param, pValue0, pValue1, pValue2) => { + var val = AL.getListenerParam('alGetListener3i', param); + if (val === null) { + return; + } + if (!pValue0 || !pValue1 || !pValue2) { + AL.currentCtx.err = 40963; + return; + } + + switch (param) { + case 4100: + case 4102: + HEAP32[((pValue0)>>2)] = val[0]; + HEAP32[((pValue1)>>2)] = val[1]; + HEAP32[((pValue2)>>2)] = val[2]; + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alGetListener3i.sig = 'vippp'; + + var _alGetListenerf = (param, pValue) => { + var val = AL.getListenerParam('alGetListenerf', param); + if (val === null) { + return; + } + if (!pValue) { + AL.currentCtx.err = 40963; + return; + } + + switch (param) { + case 4106: + HEAPF32[((pValue)>>2)] = val; + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alGetListenerf.sig = 'vip'; + + var _alGetListenerfv = (param, pValues) => { + var val = AL.getListenerParam('alGetListenerfv', param); + if (val === null) { + return; + } + if (!pValues) { + AL.currentCtx.err = 40963; + return; + } + + switch (param) { + case 4100: + case 4102: + HEAPF32[((pValues)>>2)] = val[0]; + HEAPF32[(((pValues)+(4))>>2)] = val[1]; + HEAPF32[(((pValues)+(8))>>2)] = val[2]; + break; + case 4111: + HEAPF32[((pValues)>>2)] = val[0]; + HEAPF32[(((pValues)+(4))>>2)] = val[1]; + HEAPF32[(((pValues)+(8))>>2)] = val[2]; + HEAPF32[(((pValues)+(12))>>2)] = val[3]; + HEAPF32[(((pValues)+(16))>>2)] = val[4]; + HEAPF32[(((pValues)+(20))>>2)] = val[5]; + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alGetListenerfv.sig = 'vip'; + + var _alGetListeneri = (param, pValue) => { + var val = AL.getListenerParam('alGetListeneri', param); + if (val === null) { + return; + } + if (!pValue) { + AL.currentCtx.err = 40963; + return; + } + + AL.currentCtx.err = 40962; + }; + _alGetListeneri.sig = 'vip'; + + var _alGetListeneriv = (param, pValues) => { + var val = AL.getListenerParam('alGetListeneriv', param); + if (val === null) { + return; + } + if (!pValues) { + AL.currentCtx.err = 40963; + return; + } + + switch (param) { + case 4100: + case 4102: + HEAP32[((pValues)>>2)] = val[0]; + HEAP32[(((pValues)+(4))>>2)] = val[1]; + HEAP32[(((pValues)+(8))>>2)] = val[2]; + break; + case 4111: + HEAP32[((pValues)>>2)] = val[0]; + HEAP32[(((pValues)+(4))>>2)] = val[1]; + HEAP32[(((pValues)+(8))>>2)] = val[2]; + HEAP32[(((pValues)+(12))>>2)] = val[3]; + HEAP32[(((pValues)+(16))>>2)] = val[4]; + HEAP32[(((pValues)+(20))>>2)] = val[5]; + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alGetListeneriv.sig = 'vip'; + + var _alGetSource3f = (sourceId, param, pValue0, pValue1, pValue2) => { + var val = AL.getSourceParam('alGetSource3f', sourceId, param); + if (val === null) { + return; + } + if (!pValue0 || !pValue1 || !pValue2) { + AL.currentCtx.err = 40963; + return; + } + + switch (param) { + case 4100: + case 4101: + case 4102: + HEAPF32[((pValue0)>>2)] = val[0]; + HEAPF32[((pValue1)>>2)] = val[1]; + HEAPF32[((pValue2)>>2)] = val[2]; + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alGetSource3f.sig = 'viippp'; + + var _alGetSource3i = (sourceId, param, pValue0, pValue1, pValue2) => { + var val = AL.getSourceParam('alGetSource3i', sourceId, param); + if (val === null) { + return; + } + if (!pValue0 || !pValue1 || !pValue2) { + AL.currentCtx.err = 40963; + return; + } + + switch (param) { + case 4100: + case 4101: + case 4102: + HEAP32[((pValue0)>>2)] = val[0]; + HEAP32[((pValue1)>>2)] = val[1]; + HEAP32[((pValue2)>>2)] = val[2]; + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alGetSource3i.sig = 'viippp'; + + var _alGetSourcef = (sourceId, param, pValue) => { + var val = AL.getSourceParam('alGetSourcef', sourceId, param); + if (val === null) { + return; + } + if (!pValue) { + AL.currentCtx.err = 40963; + return; + } + + switch (param) { + case 0x1001 /* AL_CONE_INNER_ANGLE */: + case 0x1002 /* AL_CONE_OUTER_ANGLE */: + case 0x1003 /* AL_PITCH */: + case 4106: + case 0x100D /* AL_MIN_GAIN */: + case 0x100E /* AL_MAX_GAIN */: + case 0x1020 /* AL_REFERENCE_DISTANCE */: + case 0x1021 /* AL_ROLLOFF_FACTOR */: + case 0x1022 /* AL_CONE_OUTER_GAIN */: + case 0x1023 /* AL_MAX_DISTANCE */: + case 0x1024 /* AL_SEC_OFFSET */: + case 0x1025 /* AL_SAMPLE_OFFSET */: + case 0x1026 /* AL_BYTE_OFFSET */: + case 0x200B /* AL_SEC_LENGTH_SOFT */: + HEAPF32[((pValue)>>2)] = val; + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alGetSourcef.sig = 'viip'; + + var _alGetSourcefv = (sourceId, param, pValues) => { + var val = AL.getSourceParam('alGetSourcefv', sourceId, param); + if (val === null) { + return; + } + if (!pValues) { + AL.currentCtx.err = 40963; + return; + } + + switch (param) { + case 0x1001 /* AL_CONE_INNER_ANGLE */: + case 0x1002 /* AL_CONE_OUTER_ANGLE */: + case 0x1003 /* AL_PITCH */: + case 4106: + case 0x100D /* AL_MIN_GAIN */: + case 0x100E /* AL_MAX_GAIN */: + case 0x1020 /* AL_REFERENCE_DISTANCE */: + case 0x1021 /* AL_ROLLOFF_FACTOR */: + case 0x1022 /* AL_CONE_OUTER_GAIN */: + case 0x1023 /* AL_MAX_DISTANCE */: + case 0x1024 /* AL_SEC_OFFSET */: + case 0x1025 /* AL_SAMPLE_OFFSET */: + case 0x1026 /* AL_BYTE_OFFSET */: + case 0x200B /* AL_SEC_LENGTH_SOFT */: + HEAPF32[((pValues)>>2)] = val[0]; + break; + case 4100: + case 4101: + case 4102: + HEAPF32[((pValues)>>2)] = val[0]; + HEAPF32[(((pValues)+(4))>>2)] = val[1]; + HEAPF32[(((pValues)+(8))>>2)] = val[2]; + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alGetSourcefv.sig = 'viip'; + + var _alGetSourcei = (sourceId, param, pValue) => { + var val = AL.getSourceParam('alGetSourcei', sourceId, param); + if (val === null) { + return; + } + if (!pValue) { + AL.currentCtx.err = 40963; + return; + } + + switch (param) { + case 0x202 /* AL_SOURCE_RELATIVE */: + case 0x1001 /* AL_CONE_INNER_ANGLE */: + case 0x1002 /* AL_CONE_OUTER_ANGLE */: + case 0x1007 /* AL_LOOPING */: + case 0x1009 /* AL_BUFFER */: + case 0x1010 /* AL_SOURCE_STATE */: + case 0x1015 /* AL_BUFFERS_QUEUED */: + case 0x1016 /* AL_BUFFERS_PROCESSED */: + case 0x1020 /* AL_REFERENCE_DISTANCE */: + case 0x1021 /* AL_ROLLOFF_FACTOR */: + case 0x1023 /* AL_MAX_DISTANCE */: + case 0x1024 /* AL_SEC_OFFSET */: + case 0x1025 /* AL_SAMPLE_OFFSET */: + case 0x1026 /* AL_BYTE_OFFSET */: + case 0x1027 /* AL_SOURCE_TYPE */: + case 0x1214 /* AL_SOURCE_SPATIALIZE_SOFT */: + case 0x2009 /* AL_BYTE_LENGTH_SOFT */: + case 0x200A /* AL_SAMPLE_LENGTH_SOFT */: + case 53248: + HEAP32[((pValue)>>2)] = val; + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alGetSourcei.sig = 'viip'; + + var _alGetSourceiv = (sourceId, param, pValues) => { + var val = AL.getSourceParam('alGetSourceiv', sourceId, param); + if (val === null) { + return; + } + if (!pValues) { + AL.currentCtx.err = 40963; + return; + } + + switch (param) { + case 0x202 /* AL_SOURCE_RELATIVE */: + case 0x1001 /* AL_CONE_INNER_ANGLE */: + case 0x1002 /* AL_CONE_OUTER_ANGLE */: + case 0x1007 /* AL_LOOPING */: + case 0x1009 /* AL_BUFFER */: + case 0x1010 /* AL_SOURCE_STATE */: + case 0x1015 /* AL_BUFFERS_QUEUED */: + case 0x1016 /* AL_BUFFERS_PROCESSED */: + case 0x1020 /* AL_REFERENCE_DISTANCE */: + case 0x1021 /* AL_ROLLOFF_FACTOR */: + case 0x1023 /* AL_MAX_DISTANCE */: + case 0x1024 /* AL_SEC_OFFSET */: + case 0x1025 /* AL_SAMPLE_OFFSET */: + case 0x1026 /* AL_BYTE_OFFSET */: + case 0x1027 /* AL_SOURCE_TYPE */: + case 0x1214 /* AL_SOURCE_SPATIALIZE_SOFT */: + case 0x2009 /* AL_BYTE_LENGTH_SOFT */: + case 0x200A /* AL_SAMPLE_LENGTH_SOFT */: + case 53248: + HEAP32[((pValues)>>2)] = val; + break; + case 4100: + case 4101: + case 4102: + HEAP32[((pValues)>>2)] = val[0]; + HEAP32[(((pValues)+(4))>>2)] = val[1]; + HEAP32[(((pValues)+(8))>>2)] = val[2]; + break; + default: + AL.currentCtx.err = 40962; + return; + } + }; + _alGetSourceiv.sig = 'viip'; + + + + var stringToNewUTF8 = (str) => { + var size = lengthBytesUTF8(str) + 1; + var ret = _malloc(size); + if (ret) stringToUTF8(str, ret, size); + return ret; + }; + + var _alGetString = (param) => { + if (AL.stringCache[param]) { + return AL.stringCache[param]; + } + + var ret; + switch (param) { + case 0: + ret = 'No Error'; + break; + case 40961: + ret = 'Invalid Name'; + break; + case 40962: + ret = 'Invalid Enum'; + break; + case 40963: + ret = 'Invalid Value'; + break; + case 40964: + ret = 'Invalid Operation'; + break; + case 0xA005 /* AL_OUT_OF_MEMORY */: + ret = 'Out of Memory'; + break; + case 0xB001 /* AL_VENDOR */: + ret = 'Emscripten'; + break; + case 0xB002 /* AL_VERSION */: + ret = '1.1'; + break; + case 0xB003 /* AL_RENDERER */: + ret = 'WebAudio'; + break; + case 0xB004 /* AL_EXTENSIONS */: + ret = Object.keys(AL.AL_EXTENSIONS).join(' '); + break; + default: + if (AL.currentCtx) { + AL.currentCtx.err = 40962; + } else { + } + return 0; + } + + ret = stringToNewUTF8(ret); + AL.stringCache[param] = ret; + return ret; + }; + _alGetString.sig = 'pi'; + + var _alIsBuffer = (bufferId) => { + if (!AL.currentCtx) { + return false; + } + if (bufferId > AL.buffers.length) { + return false; + } + + if (!AL.buffers[bufferId]) { + return false; + } + return true; + }; + _alIsBuffer.sig = 'ii'; + + var _alIsEnabled = (param) => { + if (!AL.currentCtx) { + return 0; + } + switch (param) { + case 0x200 /* AL_SOURCE_DISTANCE_MODEL */: + return AL.currentCtx.sourceDistanceModel ? 0 : 1; + default: + AL.currentCtx.err = 40962; + return 0; + } + }; + _alIsEnabled.sig = 'ii'; + + + var _alIsExtensionPresent = (pExtName) => { + var name = UTF8ToString(pExtName); + + return AL.AL_EXTENSIONS[name] ? 1 : 0; + }; + _alIsExtensionPresent.sig = 'ip'; + + var _alIsSource = (sourceId) => { + if (!AL.currentCtx) { + return false; + } + + if (!AL.currentCtx.sources[sourceId]) { + return false; + } + return true; + }; + _alIsSource.sig = 'ii'; + + var _alListener3f = (param, value0, value1, value2) => { + switch (param) { + case 4100: + case 4102: + AL.paramArray[0] = value0; + AL.paramArray[1] = value1; + AL.paramArray[2] = value2; + AL.setListenerParam('alListener3f', param, AL.paramArray); + break; + default: + AL.setListenerParam('alListener3f', param, null); + break; + } + }; + _alListener3f.sig = 'vifff'; + + var _alListener3i = (param, value0, value1, value2) => { + switch (param) { + case 4100: + case 4102: + AL.paramArray[0] = value0; + AL.paramArray[1] = value1; + AL.paramArray[2] = value2; + AL.setListenerParam('alListener3i', param, AL.paramArray); + break; + default: + AL.setListenerParam('alListener3i', param, null); + break; + } + }; + _alListener3i.sig = 'viiii'; + + var _alListenerf = (param, value) => { + switch (param) { + case 4106: + AL.setListenerParam('alListenerf', param, value); + break; + default: + AL.setListenerParam('alListenerf', param, null); + break; + } + }; + _alListenerf.sig = 'vif'; + + var _alListenerfv = (param, pValues) => { + if (!AL.currentCtx) { + return; + } + if (!pValues) { + AL.currentCtx.err = 40963; + return; + } + + switch (param) { + case 4100: + case 4102: + AL.paramArray[0] = HEAPF32[((pValues)>>2)]; + AL.paramArray[1] = HEAPF32[(((pValues)+(4))>>2)]; + AL.paramArray[2] = HEAPF32[(((pValues)+(8))>>2)]; + AL.setListenerParam('alListenerfv', param, AL.paramArray); + break; + case 4111: + AL.paramArray[0] = HEAPF32[((pValues)>>2)]; + AL.paramArray[1] = HEAPF32[(((pValues)+(4))>>2)]; + AL.paramArray[2] = HEAPF32[(((pValues)+(8))>>2)]; + AL.paramArray[3] = HEAPF32[(((pValues)+(12))>>2)]; + AL.paramArray[4] = HEAPF32[(((pValues)+(16))>>2)]; + AL.paramArray[5] = HEAPF32[(((pValues)+(20))>>2)]; + AL.setListenerParam('alListenerfv', param, AL.paramArray); + break; + default: + AL.setListenerParam('alListenerfv', param, null); + break; + } + }; + _alListenerfv.sig = 'vip'; + + var _alListeneri = (param, value) => { + AL.setListenerParam('alListeneri', param, null); + }; + _alListeneri.sig = 'vii'; + + var _alListeneriv = (param, pValues) => { + if (!AL.currentCtx) { + return; + } + if (!pValues) { + AL.currentCtx.err = 40963; + return; + } + + switch (param) { + case 4100: + case 4102: + AL.paramArray[0] = HEAP32[((pValues)>>2)]; + AL.paramArray[1] = HEAP32[(((pValues)+(4))>>2)]; + AL.paramArray[2] = HEAP32[(((pValues)+(8))>>2)]; + AL.setListenerParam('alListeneriv', param, AL.paramArray); + break; + case 4111: + AL.paramArray[0] = HEAP32[((pValues)>>2)]; + AL.paramArray[1] = HEAP32[(((pValues)+(4))>>2)]; + AL.paramArray[2] = HEAP32[(((pValues)+(8))>>2)]; + AL.paramArray[3] = HEAP32[(((pValues)+(12))>>2)]; + AL.paramArray[4] = HEAP32[(((pValues)+(16))>>2)]; + AL.paramArray[5] = HEAP32[(((pValues)+(20))>>2)]; + AL.setListenerParam('alListeneriv', param, AL.paramArray); + break; + default: + AL.setListenerParam('alListeneriv', param, null); + break; + } + }; + _alListeneriv.sig = 'vip'; + + var _alSource3f = (sourceId, param, value0, value1, value2) => { + switch (param) { + case 4100: + case 4101: + case 4102: + AL.paramArray[0] = value0; + AL.paramArray[1] = value1; + AL.paramArray[2] = value2; + AL.setSourceParam('alSource3f', sourceId, param, AL.paramArray); + break; + default: + AL.setSourceParam('alSource3f', sourceId, param, null); + break; + } + }; + _alSource3f.sig = 'viifff'; + + var _alSource3i = (sourceId, param, value0, value1, value2) => { + switch (param) { + case 4100: + case 4101: + case 4102: + AL.paramArray[0] = value0; + AL.paramArray[1] = value1; + AL.paramArray[2] = value2; + AL.setSourceParam('alSource3i', sourceId, param, AL.paramArray); + break; + default: + AL.setSourceParam('alSource3i', sourceId, param, null); + break; + } + }; + _alSource3i.sig = 'viiiii'; + + var _alSourcePause = (sourceId) => { + if (!AL.currentCtx) { + return; + } + var src = AL.currentCtx.sources[sourceId]; + if (!src) { + AL.currentCtx.err = 40961; + return; + } + AL.setSourceState(src, 4115); + }; + _alSourcePause.sig = 'vi'; + + var _alSourcePausev = (count, pSourceIds) => { + if (!AL.currentCtx) { + return; + } + if (!pSourceIds) { + AL.currentCtx.err = 40963; + } + for (var i = 0; i < count; ++i) { + if (!AL.currentCtx.sources[HEAP32[(((pSourceIds)+(i*4))>>2)]]) { + AL.currentCtx.err = 40961; + return; + } + } + + for (var i = 0; i < count; ++i) { + var srcId = HEAP32[(((pSourceIds)+(i*4))>>2)]; + AL.setSourceState(AL.currentCtx.sources[srcId], 4115); + } + }; + _alSourcePausev.sig = 'vip'; + + var _alSourcePlay = (sourceId) => { + if (!AL.currentCtx) { + return; + } + var src = AL.currentCtx.sources[sourceId]; + if (!src) { + AL.currentCtx.err = 40961; + return; + } + AL.setSourceState(src, 4114); + }; + _alSourcePlay.sig = 'vi'; + + var _alSourcePlayv = (count, pSourceIds) => { + if (!AL.currentCtx) { + return; + } + if (!pSourceIds) { + AL.currentCtx.err = 40963; + } + for (var i = 0; i < count; ++i) { + if (!AL.currentCtx.sources[HEAP32[(((pSourceIds)+(i*4))>>2)]]) { + AL.currentCtx.err = 40961; + return; + } + } + + for (var i = 0; i < count; ++i) { + var srcId = HEAP32[(((pSourceIds)+(i*4))>>2)]; + AL.setSourceState(AL.currentCtx.sources[srcId], 4114); + } + }; + _alSourcePlayv.sig = 'vip'; + + var _alSourceQueueBuffers = (sourceId, count, pBufferIds) => { + if (!AL.currentCtx) { + return; + } + var src = AL.currentCtx.sources[sourceId]; + if (!src) { + AL.currentCtx.err = 40961; + return; + } + if (src.type === 4136) { + AL.currentCtx.err = 40964; + return; + } + + if (count === 0) { + return; + } + + // Find the first non-zero buffer in the queue to determine the proper format + var templateBuf = AL.buffers[0]; + for (var buf of src.bufQueue) { + if (buf.id !== 0) { + templateBuf = buf; + break; + } + } + + for (var i = 0; i < count; ++i) { + var bufId = HEAP32[(((pBufferIds)+(i*4))>>2)]; + var buf = AL.buffers[bufId]; + if (!buf) { + AL.currentCtx.err = 40961; + return; + } + + // Check that the added buffer has the correct format. If the template is the zero buffer, any format is valid. + if (templateBuf.id !== 0 && ( + buf.frequency !== templateBuf.frequency + || buf.bytesPerSample !== templateBuf.bytesPerSample + || buf.channels !== templateBuf.channels) + ) { + AL.currentCtx.err = 40964; + } + } + + // If the only buffer in the queue is the zero buffer, clear the queue before we add anything. + if (src.bufQueue.length === 1 && src.bufQueue[0].id === 0) { + src.bufQueue.length = 0; + } + + src.type = 0x1029 /* AL_STREAMING */; + for (var i = 0; i < count; ++i) { + var bufId = HEAP32[(((pBufferIds)+(i*4))>>2)]; + var buf = AL.buffers[bufId]; + buf.refCount++; + src.bufQueue.push(buf); + } + + // if the source is looping, cancel the schedule so we can reschedule the loop order + if (src.looping) { + AL.cancelPendingSourceAudio(src); + } + + AL.initSourcePanner(src); + AL.scheduleSourceAudio(src); + }; + _alSourceQueueBuffers.sig = 'viip'; + + var _alSourceRewind = (sourceId) => { + if (!AL.currentCtx) { + return; + } + var src = AL.currentCtx.sources[sourceId]; + if (!src) { + AL.currentCtx.err = 40961; + return; + } + // Stop the source first to clear the source queue + AL.setSourceState(src, 4116); + // Now set the state of AL_INITIAL according to the specification + AL.setSourceState(src, 4113); + }; + _alSourceRewind.sig = 'vi'; + + var _alSourceRewindv = (count, pSourceIds) => { + if (!AL.currentCtx) { + return; + } + if (!pSourceIds) { + AL.currentCtx.err = 40963; + } + for (var i = 0; i < count; ++i) { + if (!AL.currentCtx.sources[HEAP32[(((pSourceIds)+(i*4))>>2)]]) { + AL.currentCtx.err = 40961; + return; + } + } + + for (var i = 0; i < count; ++i) { + var srcId = HEAP32[(((pSourceIds)+(i*4))>>2)]; + AL.setSourceState(AL.currentCtx.sources[srcId], 4113); + } + }; + _alSourceRewindv.sig = 'vip'; + + var _alSourceStop = (sourceId) => { + if (!AL.currentCtx) { + return; + } + var src = AL.currentCtx.sources[sourceId]; + if (!src) { + AL.currentCtx.err = 40961; + return; + } + AL.setSourceState(src, 4116); + }; + _alSourceStop.sig = 'vi'; + + var _alSourceStopv = (count, pSourceIds) => { + if (!AL.currentCtx) { + return; + } + if (!pSourceIds) { + AL.currentCtx.err = 40963; + } + for (var i = 0; i < count; ++i) { + if (!AL.currentCtx.sources[HEAP32[(((pSourceIds)+(i*4))>>2)]]) { + AL.currentCtx.err = 40961; + return; + } + } + + for (var i = 0; i < count; ++i) { + var srcId = HEAP32[(((pSourceIds)+(i*4))>>2)]; + AL.setSourceState(AL.currentCtx.sources[srcId], 4116); + } + }; + _alSourceStopv.sig = 'vip'; + + var _alSourceUnqueueBuffers = (sourceId, count, pBufferIds) => { + if (!AL.currentCtx) { + return; + } + var src = AL.currentCtx.sources[sourceId]; + if (!src) { + AL.currentCtx.err = 40961; + return; + } + if (count > (src.bufQueue.length === 1 && src.bufQueue[0].id === 0 ? 0 : src.bufsProcessed)) { + AL.currentCtx.err = 40963; + return; + } + + if (count === 0) { + return; + } + + for (var i = 0; i < count; i++) { + var buf = src.bufQueue.shift(); + buf.refCount--; + // Write the buffers index out to the return list. + HEAP32[(((pBufferIds)+(i*4))>>2)] = buf.id; + src.bufsProcessed--; + } + + /// If the queue is empty, put the zero buffer back in + if (src.bufQueue.length === 0) { + src.bufQueue.push(AL.buffers[0]); + } + + AL.initSourcePanner(src); + AL.scheduleSourceAudio(src); + }; + _alSourceUnqueueBuffers.sig = 'viip'; + + var _alSourcef = (sourceId, param, value) => { + switch (param) { + case 0x1001 /* AL_CONE_INNER_ANGLE */: + case 0x1002 /* AL_CONE_OUTER_ANGLE */: + case 0x1003 /* AL_PITCH */: + case 4106: + case 0x100D /* AL_MIN_GAIN */: + case 0x100E /* AL_MAX_GAIN */: + case 0x1020 /* AL_REFERENCE_DISTANCE */: + case 0x1021 /* AL_ROLLOFF_FACTOR */: + case 0x1022 /* AL_CONE_OUTER_GAIN */: + case 0x1023 /* AL_MAX_DISTANCE */: + case 0x1024 /* AL_SEC_OFFSET */: + case 0x1025 /* AL_SAMPLE_OFFSET */: + case 0x1026 /* AL_BYTE_OFFSET */: + case 0x200B /* AL_SEC_LENGTH_SOFT */: + AL.setSourceParam('alSourcef', sourceId, param, value); + break; + default: + AL.setSourceParam('alSourcef', sourceId, param, null); + break; + } + }; + _alSourcef.sig = 'viif'; + + var _alSourcefv = (sourceId, param, pValues) => { + if (!AL.currentCtx) { + return; + } + if (!pValues) { + AL.currentCtx.err = 40963; + return; + } + + switch (param) { + case 0x1001 /* AL_CONE_INNER_ANGLE */: + case 0x1002 /* AL_CONE_OUTER_ANGLE */: + case 0x1003 /* AL_PITCH */: + case 4106: + case 0x100D /* AL_MIN_GAIN */: + case 0x100E /* AL_MAX_GAIN */: + case 0x1020 /* AL_REFERENCE_DISTANCE */: + case 0x1021 /* AL_ROLLOFF_FACTOR */: + case 0x1022 /* AL_CONE_OUTER_GAIN */: + case 0x1023 /* AL_MAX_DISTANCE */: + case 0x1024 /* AL_SEC_OFFSET */: + case 0x1025 /* AL_SAMPLE_OFFSET */: + case 0x1026 /* AL_BYTE_OFFSET */: + case 0x200B /* AL_SEC_LENGTH_SOFT */: + var val = HEAPF32[((pValues)>>2)]; + AL.setSourceParam('alSourcefv', sourceId, param, val); + break; + case 4100: + case 4101: + case 4102: + AL.paramArray[0] = HEAPF32[((pValues)>>2)]; + AL.paramArray[1] = HEAPF32[(((pValues)+(4))>>2)]; + AL.paramArray[2] = HEAPF32[(((pValues)+(8))>>2)]; + AL.setSourceParam('alSourcefv', sourceId, param, AL.paramArray); + break; + default: + AL.setSourceParam('alSourcefv', sourceId, param, null); + break; + } + }; + _alSourcefv.sig = 'viip'; + + + var _alSourceiv = (sourceId, param, pValues) => { + if (!AL.currentCtx) { + return; + } + if (!pValues) { + AL.currentCtx.err = 40963; + return; + } + + switch (param) { + case 0x202 /* AL_SOURCE_RELATIVE */: + case 0x1001 /* AL_CONE_INNER_ANGLE */: + case 0x1002 /* AL_CONE_OUTER_ANGLE */: + case 0x1007 /* AL_LOOPING */: + case 0x1009 /* AL_BUFFER */: + case 0x1020 /* AL_REFERENCE_DISTANCE */: + case 0x1021 /* AL_ROLLOFF_FACTOR */: + case 0x1023 /* AL_MAX_DISTANCE */: + case 0x1024 /* AL_SEC_OFFSET */: + case 0x1025 /* AL_SAMPLE_OFFSET */: + case 0x1026 /* AL_BYTE_OFFSET */: + case 0x1214 /* AL_SOURCE_SPATIALIZE_SOFT */: + case 0x2009 /* AL_BYTE_LENGTH_SOFT */: + case 0x200A /* AL_SAMPLE_LENGTH_SOFT */: + case 53248: + var val = HEAP32[((pValues)>>2)]; + AL.setSourceParam('alSourceiv', sourceId, param, val); + break; + case 4100: + case 4101: + case 4102: + AL.paramArray[0] = HEAP32[((pValues)>>2)]; + AL.paramArray[1] = HEAP32[(((pValues)+(4))>>2)]; + AL.paramArray[2] = HEAP32[(((pValues)+(8))>>2)]; + AL.setSourceParam('alSourceiv', sourceId, param, AL.paramArray); + break; + default: + AL.setSourceParam('alSourceiv', sourceId, param, null); + break; + } + }; + _alSourceiv.sig = 'viip'; + + var _alSpeedOfSound = (value) => { + AL.setGlobalParam('alSpeedOfSound', 49155, value); + }; + _alSpeedOfSound.sig = 'vf'; + + var _alcCaptureCloseDevice = (deviceId) => { + var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureCloseDevice'); + if (!c) return false; + + delete AL.captures[deviceId]; + AL.freeIds.push(deviceId); + + // This clean-up might be unnecessary (paranoid) ? + + // May happen if user hasn't decided to grant or deny input + c.mediaStreamSourceNode?.disconnect(); + c.mergerNode?.disconnect(); + c.splitterNode?.disconnect(); + // May happen if user hasn't decided to grant or deny input + c.scriptProcessorNode?.disconnect(); + if (c.mediaStream) { + // Disabling the microphone of the browser. + // Without this operation, the red dot on the browser tab page will remain. + c.mediaStream.getTracks().forEach((track) => track.stop()); + } + + delete c.buffers; + + c.capturedFrameCount = 0; + c.isCapturing = false; + + return true; + }; + _alcCaptureCloseDevice.sig = 'ip'; + + var autoResumeAudioContext = (ctx) => { + for (var event of ['keydown', 'mousedown', 'touchstart']) { + for (var element of [document, document.getElementById('canvas')]) { + element?.addEventListener(event, () => { + if (ctx.state === 'suspended') ctx.resume(); + }, { 'once': true }); + } + } + }; + + + var _alcCaptureOpenDevice = (pDeviceName, requestedSampleRate, format, bufferFrameCapacity) => { + + var resolvedDeviceName = AL.CAPTURE_DEVICE_NAME; + + // NULL is a valid device name here (resolves to default); + if (pDeviceName !== 0) { + resolvedDeviceName = UTF8ToString(pDeviceName); + if (resolvedDeviceName !== AL.CAPTURE_DEVICE_NAME) { + // ALC_OUT_OF_MEMORY + // From the programmer's guide, ALC_OUT_OF_MEMORY's meaning is + // overloaded here, to mean: + // 'The specified device is invalid, or can not capture audio.' + // This may be misleading to API users, but well... + AL.alcErr = 0xA005 /* ALC_OUT_OF_MEMORY */; + return 0; + } + } + + // Otherwise it's probably okay (though useless) for bufferFrameCapacity to be zero. + if (bufferFrameCapacity < 0) { // ALCsizei is signed int + AL.alcErr = 40964; + return 0; + } + + navigator.getUserMedia = navigator.getUserMedia + || navigator.webkitGetUserMedia + || navigator.mozGetUserMedia + || navigator.msGetUserMedia; + var has_getUserMedia = navigator.getUserMedia + || (navigator.mediaDevices + && navigator.mediaDevices.getUserMedia); + + if (!has_getUserMedia) { + // See previously mentioned rationale for ALC_OUT_OF_MEMORY + AL.alcErr = 0xA005 /* ALC_OUT_OF_MEMORY */; + return 0; + } + + var AudioContext = window.AudioContext || window.webkitAudioContext; + + if (!AL.sharedCaptureAudioCtx) { + try { + AL.sharedCaptureAudioCtx = new AudioContext(); + } catch(e) { + // See previously mentioned rationale for ALC_OUT_OF_MEMORY + AL.alcErr = 0xA005 /* ALC_OUT_OF_MEMORY */; + return 0; + } + } + + autoResumeAudioContext(AL.sharedCaptureAudioCtx); + + var outputChannelCount; + + switch (format) { + case 0x10010: /* AL_FORMAT_MONO_FLOAT32 */ + case 0x1101: /* AL_FORMAT_MONO16 */ + case 0x1100: /* AL_FORMAT_MONO8 */ + outputChannelCount = 1; + break; + case 0x10011: /* AL_FORMAT_STEREO_FLOAT32 */ + case 0x1103: /* AL_FORMAT_STEREO16 */ + case 0x1102: /* AL_FORMAT_STEREO8 */ + outputChannelCount = 2; + break; + default: + AL.alcErr = 40964; + return 0; + } + + function newF32Array(cap) { return new Float32Array(cap);} + function newI16Array(cap) { return new Int16Array(cap); } + function newU8Array(cap) { return new Uint8Array(cap); } + + var requestedSampleType; + var newSampleArray; + + switch (format) { + case 0x10010: /* AL_FORMAT_MONO_FLOAT32 */ + case 0x10011: /* AL_FORMAT_STEREO_FLOAT32 */ + requestedSampleType = 'f32'; + newSampleArray = newF32Array; + break; + case 0x1101: /* AL_FORMAT_MONO16 */ + case 0x1103: /* AL_FORMAT_STEREO16 */ + requestedSampleType = 'i16'; + newSampleArray = newI16Array; + break; + case 0x1100: /* AL_FORMAT_MONO8 */ + case 0x1102: /* AL_FORMAT_STEREO8 */ + requestedSampleType = 'u8'; + newSampleArray = newU8Array; + break; + } + + var buffers = []; + try { + for (var chan=0; chan < outputChannelCount; ++chan) { + buffers[chan] = newSampleArray(bufferFrameCapacity); + } + } catch(e) { + AL.alcErr = 0xA005 /* ALC_OUT_OF_MEMORY */; + return 0; + } + + // What we'll place into the `AL.captures` array in the end, + // declared here for closures to access it + var newCapture = { + audioCtx: AL.sharedCaptureAudioCtx, + deviceName: resolvedDeviceName, + requestedSampleRate, + requestedSampleType, + outputChannelCount, + inputChannelCount: null, // Not known until the getUserMedia() promise resolves + mediaStreamError: null, // Used by other functions to return early and report an error. + mediaStreamSourceNode: null, + mediaStream: null, + // Either one, or none of the below two, is active. + mergerNode: null, + splitterNode: null, + scriptProcessorNode: null, + isCapturing: false, + buffers, + get bufferFrameCapacity() { + return buffers[0].length; + }, + capturePlayhead: 0, // current write position, in sample frames + captureReadhead: 0, + capturedFrameCount: 0 + }; + + // Preparing for getUserMedia() + + var onError = (mediaStreamError) => { + newCapture.mediaStreamError = mediaStreamError; + }; + var onSuccess = (mediaStream) => { + newCapture.mediaStreamSourceNode = newCapture.audioCtx.createMediaStreamSource(mediaStream); + newCapture.mediaStream = mediaStream; + + var inputChannelCount = 1; + switch (newCapture.mediaStreamSourceNode.channelCountMode) { + case 'max': + inputChannelCount = outputChannelCount; + break; + case 'clamped-max': + inputChannelCount = Math.min(outputChannelCount, newCapture.mediaStreamSourceNode.channelCount); + break; + case 'explicit': + inputChannelCount = newCapture.mediaStreamSourceNode.channelCount; + break; + } + + newCapture.inputChannelCount = inputChannelCount; + + // Have to pick a size from 256, 512, 1024, 2048, 4096, 8192, 16384. + // One can also set it to zero, which leaves the decision up to the impl. + // An extension could allow specifying this value. + var processorFrameCount = 512; + + newCapture.scriptProcessorNode = newCapture.audioCtx.createScriptProcessor( + processorFrameCount, inputChannelCount, outputChannelCount + ); + + if (inputChannelCount > outputChannelCount) { + newCapture.mergerNode = newCapture.audioCtx.createChannelMerger(inputChannelCount); + newCapture.mediaStreamSourceNode.connect(newCapture.mergerNode); + newCapture.mergerNode.connect(newCapture.scriptProcessorNode); + } else if (inputChannelCount < outputChannelCount) { + newCapture.splitterNode = newCapture.audioCtx.createChannelSplitter(outputChannelCount); + newCapture.mediaStreamSourceNode.connect(newCapture.splitterNode); + newCapture.splitterNode.connect(newCapture.scriptProcessorNode); + } else { + newCapture.mediaStreamSourceNode.connect(newCapture.scriptProcessorNode); + } + + newCapture.scriptProcessorNode.connect(newCapture.audioCtx.destination); + + newCapture.scriptProcessorNode.onaudioprocess = (audioProcessingEvent) => { + if (!newCapture.isCapturing) { + return; + } + + var c = newCapture; + var srcBuf = audioProcessingEvent.inputBuffer; + + // Actually just copy srcBuf's channel data into + // c.buffers, optimizing for each case. + switch (format) { + case 0x10010: /* AL_FORMAT_MONO_FLOAT32 */ + var channel0 = srcBuf.getChannelData(0); + for (var i = 0 ; i < srcBuf.length; ++i) { + var wi = (c.capturePlayhead + i) % c.bufferFrameCapacity; + c.buffers[0][wi] = channel0[i]; + } + break; + case 0x10011: /* AL_FORMAT_STEREO_FLOAT32 */ + var channel0 = srcBuf.getChannelData(0); + var channel1 = srcBuf.getChannelData(1); + for (var i = 0 ; i < srcBuf.length; ++i) { + var wi = (c.capturePlayhead + i) % c.bufferFrameCapacity; + c.buffers[0][wi] = channel0[i]; + c.buffers[1][wi] = channel1[i]; + } + break; + case 0x1101: /* AL_FORMAT_MONO16 */ + var channel0 = srcBuf.getChannelData(0); + for (var i = 0 ; i < srcBuf.length; ++i) { + var wi = (c.capturePlayhead + i) % c.bufferFrameCapacity; + c.buffers[0][wi] = channel0[i] * 32767; + } + break; + case 0x1103: /* AL_FORMAT_STEREO16 */ + var channel0 = srcBuf.getChannelData(0); + var channel1 = srcBuf.getChannelData(1); + for (var i = 0 ; i < srcBuf.length; ++i) { + var wi = (c.capturePlayhead + i) % c.bufferFrameCapacity; + c.buffers[0][wi] = channel0[i] * 32767; + c.buffers[1][wi] = channel1[i] * 32767; + } + break; + case 0x1100: /* AL_FORMAT_MONO8 */ + var channel0 = srcBuf.getChannelData(0); + for (var i = 0 ; i < srcBuf.length; ++i) { + var wi = (c.capturePlayhead + i) % c.bufferFrameCapacity; + c.buffers[0][wi] = (channel0[i] + 1.0) * 127; + } + break; + case 0x1102: /* AL_FORMAT_STEREO8 */ + var channel0 = srcBuf.getChannelData(0); + var channel1 = srcBuf.getChannelData(1); + for (var i = 0 ; i < srcBuf.length; ++i) { + var wi = (c.capturePlayhead + i) % c.bufferFrameCapacity; + c.buffers[0][wi] = (channel0[i] + 1.0) * 127; + c.buffers[1][wi] = (channel1[i] + 1.0) * 127; + } + break; + } + + c.capturePlayhead += srcBuf.length; + c.capturePlayhead %= c.bufferFrameCapacity; + c.capturedFrameCount += srcBuf.length; + c.capturedFrameCount = Math.min(c.capturedFrameCount, c.bufferFrameCapacity); + }; + }; + + // The latest way to call getUserMedia() + if (navigator.mediaDevices?.getUserMedia) { + navigator.mediaDevices + .getUserMedia({audio: true}) + .then(onSuccess) + .catch(onError); + } else { // The usual (now deprecated) way + navigator.getUserMedia({audio: true}, onSuccess, onError); + } + + var id = AL.newId(); + AL.captures[id] = newCapture; + return id; + }; + _alcCaptureOpenDevice.sig = 'ppiii'; + + var _alcCaptureSamples = (deviceId, pFrames, requestedFrameCount) => { + var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureSamples'); + if (!c) return; + + // ALCsizei is actually 32-bit signed int, so could be negative + // Also, spec says : + // Requesting more sample frames than are currently available is + // an error. + + var dstfreq = c.requestedSampleRate; + var srcfreq = c.audioCtx.sampleRate; + + var fratio = srcfreq / dstfreq; + + if (requestedFrameCount < 0 + || requestedFrameCount > (c.capturedFrameCount / fratio)) + { + AL.alcErr = 40964; + return; + } + + function setF32Sample(i, sample) { + HEAPF32[(((pFrames)+(4*i))>>2)] = sample; + } + function setI16Sample(i, sample) { + HEAP16[(((pFrames)+(2*i))>>1)] = sample; + } + function setU8Sample(i, sample) { + HEAP8[(pFrames)+(i)] = sample; + } + + var setSample; + + switch (c.requestedSampleType) { + case 'f32': setSample = setF32Sample; break; + case 'i16': setSample = setI16Sample; break; + case 'u8' : setSample = setU8Sample ; break; + default: + return; + } + + // If fratio is an integer we don't need linear resampling, just skip samples + if (Math.floor(fratio) == fratio) { + for (var i = 0, frame_i = 0; frame_i < requestedFrameCount; ++frame_i) { + for (var chan = 0; chan < c.buffers.length; ++chan, ++i) { + setSample(i, c.buffers[chan][c.captureReadhead]); + } + c.captureReadhead = (fratio + c.captureReadhead) % c.bufferFrameCapacity; + } + } else { + // Perform linear resampling. + + // There is room for improvement - right now we're fine with linear resampling. + // We don't use OfflineAudioContexts for this: See the discussion at + // https://github.com/jpernst/emscripten/issues/2#issuecomment-312729735 + // if you're curious about why. + for (var i = 0, frame_i = 0; frame_i < requestedFrameCount; ++frame_i) { + var lefti = Math.floor(c.captureReadhead); + var righti = Math.ceil(c.captureReadhead); + var d = c.captureReadhead - lefti; + for (var chan = 0; chan < c.buffers.length; ++chan, ++i) { + var lefts = c.buffers[chan][lefti]; + var rights = c.buffers[chan][righti]; + setSample(i, (1 - d) * lefts + d * rights); + } + c.captureReadhead = (c.captureReadhead + fratio) % c.bufferFrameCapacity; + } + } + + // Spec doesn't say if alcCaptureSamples() must zero the number + // of available captured sample-frames, but not only would it + // be insane not to do, OpenAL-Soft happens to do that as well. + c.capturedFrameCount = 0; + }; + _alcCaptureSamples.sig = 'vppi'; + + var _alcCaptureStart = (deviceId) => { + var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureStart'); + if (!c) return; + + if (c.isCapturing) { + // NOTE: Spec says (emphasis mine): + // The amount of audio samples available after **restarting** a + // stopped capture device is reset to zero. + // So redundant calls to alcCaptureStart() must have no effect. + return; + } + c.isCapturing = true; + c.capturedFrameCount = 0; + c.capturePlayhead = 0; + }; + _alcCaptureStart.sig = 'vp'; + + var _alcCaptureStop = (deviceId) => { + var c = AL.requireValidCaptureDevice(deviceId, 'alcCaptureStop'); + if (!c) return; + + c.isCapturing = false; + }; + _alcCaptureStop.sig = 'vp'; + + var _alcCloseDevice = (deviceId) => { + if (!(deviceId in AL.deviceRefCounts) || AL.deviceRefCounts[deviceId] > 0) { + return 0; + } + + delete AL.deviceRefCounts[deviceId]; + AL.freeIds.push(deviceId); + return 1; + }; + _alcCloseDevice.sig = 'ip'; + + + var _alcCreateContext = (deviceId, pAttrList) => { + if (!(deviceId in AL.deviceRefCounts)) { + AL.alcErr = 0xA001; /* ALC_INVALID_DEVICE */ + return 0; + } + + var options = null; + var attrs = []; + var hrtf = null; + pAttrList >>= 2; + if (pAttrList) { + var attr = 0; + var val = 0; + while (true) { + attr = HEAP32[pAttrList++]; + attrs.push(attr); + if (attr === 0) { + break; + } + val = HEAP32[pAttrList++]; + attrs.push(val); + + switch (attr) { + case 0x1007 /* ALC_FREQUENCY */: + if (!options) { + options = {}; + } + + options.sampleRate = val; + break; + case 0x1010 /* ALC_MONO_SOURCES */: // fallthrough + case 0x1011 /* ALC_STEREO_SOURCES */: + // Do nothing; these hints are satisfied by default + break + case 0x1992 /* ALC_HRTF_SOFT */: + switch (val) { + case 0: + hrtf = false; + break; + case 1: + hrtf = true; + break; + case 2 /* ALC_DONT_CARE_SOFT */: + break; + default: + AL.alcErr = 40964; + return 0; + } + break; + case 0x1996 /* ALC_HRTF_ID_SOFT */: + if (val !== 0) { + AL.alcErr = 40964; + return 0; + } + break; + default: + AL.alcErr = 0xA004; /* ALC_INVALID_VALUE */ + return 0; + } + } + } + + var AudioContext = window.AudioContext || window.webkitAudioContext; + var ac = null; + try { + // Only try to pass options if there are any, for compat with browsers that don't support this + if (options) { + ac = new AudioContext(options); + } else { + ac = new AudioContext(); + } + } catch (e) { + if (e.name === 'NotSupportedError') { + AL.alcErr = 0xA004; /* ALC_INVALID_VALUE */ + } else { + AL.alcErr = 0xA001; /* ALC_INVALID_DEVICE */ + } + + return 0; + } + + autoResumeAudioContext(ac); + + // Old Web Audio API (e.g. Safari 6.0.5) had an inconsistently named createGainNode function. + if (typeof ac.createGain == 'undefined') { + ac.createGain = ac.createGainNode; + } + + var gain = ac.createGain(); + gain.connect(ac.destination); + var ctx = { + deviceId, + id: AL.newId(), + attrs, + audioCtx: ac, + listener: { + position: [0.0, 0.0, 0.0], + velocity: [0.0, 0.0, 0.0], + direction: [0.0, 0.0, 0.0], + up: [0.0, 0.0, 0.0] + }, + sources: [], + interval: setInterval(() => AL.scheduleContextAudio(ctx), AL.QUEUE_INTERVAL), + gain, + distanceModel: 0xd002 /* AL_INVERSE_DISTANCE_CLAMPED */, + speedOfSound: 343.3, + dopplerFactor: 1.0, + sourceDistanceModel: false, + hrtf: hrtf || false, + + _err: 0, + get err() { + return this._err; + }, + set err(val) { + // Errors should not be overwritten by later errors until they are cleared by a query. + if (this._err === 0 || val === 0) { + this._err = val; + } + } + }; + AL.deviceRefCounts[deviceId]++; + AL.contexts[ctx.id] = ctx; + + if (hrtf !== null) { + // Apply hrtf attrib to all contexts for this device + for (var ctxId in AL.contexts) { + var c = AL.contexts[ctxId]; + if (c.deviceId === deviceId) { + c.hrtf = hrtf; + AL.updateContextGlobal(c); + } + } + } + + return ctx.id; + }; + _alcCreateContext.sig = 'ppp'; + + var _alcDestroyContext = (contextId) => { + var ctx = AL.contexts[contextId]; + if (AL.currentCtx === ctx) { + AL.alcErr = 0xA002 /* ALC_INVALID_CONTEXT */; + return; + } + + // Stop playback, etc + if (AL.contexts[contextId].interval) { + clearInterval(AL.contexts[contextId].interval); + } + AL.deviceRefCounts[ctx.deviceId]--; + delete AL.contexts[contextId]; + AL.freeIds.push(contextId); + }; + _alcDestroyContext.sig = 'vp'; + + var _alcGetContextsDevice = (contextId) => { + if (contextId in AL.contexts) { + return AL.contexts[contextId].deviceId; + } + return 0; + }; + _alcGetContextsDevice.sig = 'pp'; + + var _alcGetCurrentContext = () => { + if (AL.currentCtx !== null) { + return AL.currentCtx.id; + } + return 0; + }; + _alcGetCurrentContext.sig = 'p'; + + + var _alcGetEnumValue = (deviceId, pEnumName) => { + // Spec says : + // Using a NULL handle is legal, but only the + // tokens defined by the AL core are guaranteed. + if (deviceId !== 0 && !(deviceId in AL.deviceRefCounts)) { + // ALC_INVALID_DEVICE is not listed as a possible error state for + // this function, sadly. + return 0; + } else if (!pEnumName) { + AL.alcErr = 40964; + return 0; + } + var name = UTF8ToString(pEnumName); + // See alGetEnumValue(), but basically behave the same as OpenAL-Soft + switch (name) { + case 'ALC_NO_ERROR': return 0; + case 'ALC_INVALID_DEVICE': return 0xA001; + case 'ALC_INVALID_CONTEXT': return 0xA002; + case 'ALC_INVALID_ENUM': return 0xA003; + case 'ALC_INVALID_VALUE': return 0xA004; + case 'ALC_OUT_OF_MEMORY': return 0xA005; + case 'ALC_MAJOR_VERSION': return 0x1000; + case 'ALC_MINOR_VERSION': return 0x1001; + case 'ALC_ATTRIBUTES_SIZE': return 0x1002; + case 'ALC_ALL_ATTRIBUTES': return 0x1003; + case 'ALC_DEFAULT_DEVICE_SPECIFIER': return 0x1004; + case 'ALC_DEVICE_SPECIFIER': return 0x1005; + case 'ALC_EXTENSIONS': return 0x1006; + case 'ALC_FREQUENCY': return 0x1007; + case 'ALC_REFRESH': return 0x1008; + case 'ALC_SYNC': return 0x1009; + case 'ALC_MONO_SOURCES': return 0x1010; + case 'ALC_STEREO_SOURCES': return 0x1011; + case 'ALC_CAPTURE_DEVICE_SPECIFIER': return 0x310; + case 'ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER': return 0x311; + case 'ALC_CAPTURE_SAMPLES': return 0x312; + + /* Extensions */ + case 'ALC_HRTF_SOFT': return 0x1992; + case 'ALC_HRTF_ID_SOFT': return 0x1996; + case 'ALC_DONT_CARE_SOFT': return 0x0002; + case 'ALC_HRTF_STATUS_SOFT': return 0x1993; + case 'ALC_NUM_HRTF_SPECIFIERS_SOFT': return 0x1994; + case 'ALC_HRTF_SPECIFIER_SOFT': return 0x1995; + case 'ALC_HRTF_DISABLED_SOFT': return 0x0000; + case 'ALC_HRTF_ENABLED_SOFT': return 0x0001; + case 'ALC_HRTF_DENIED_SOFT': return 0x0002; + case 'ALC_HRTF_REQUIRED_SOFT': return 0x0003; + case 'ALC_HRTF_HEADPHONES_DETECTED_SOFT': return 0x0004; + case 'ALC_HRTF_UNSUPPORTED_FORMAT_SOFT': return 0x0005; + + default: + AL.alcErr = 40964; + return 0; + } + }; + _alcGetEnumValue.sig = 'ipp'; + + var _alcGetError = (deviceId) => { + var err = AL.alcErr; + AL.alcErr = 0; + return err; + }; + _alcGetError.sig = 'ip'; + + var _alcGetIntegerv = (deviceId, param, size, pValues) => { + if (size === 0 || !pValues) { + // Ignore the query, per the spec + return; + } + + switch (param) { + case 0x1000 /* ALC_MAJOR_VERSION */: + HEAP32[((pValues)>>2)] = 1; + break; + case 0x1001 /* ALC_MINOR_VERSION */: + HEAP32[((pValues)>>2)] = 1; + break; + case 0x1002 /* ALC_ATTRIBUTES_SIZE */: + if (!(deviceId in AL.deviceRefCounts)) { + AL.alcErr = 40961; + return; + } + if (!AL.currentCtx) { + AL.alcErr = 0xA002 /* ALC_INVALID_CONTEXT */; + return; + } + + HEAP32[((pValues)>>2)] = AL.currentCtx.attrs.length; + break; + case 0x1003 /* ALC_ALL_ATTRIBUTES */: + if (!(deviceId in AL.deviceRefCounts)) { + AL.alcErr = 40961; + return; + } + if (!AL.currentCtx) { + AL.alcErr = 0xA002 /* ALC_INVALID_CONTEXT */; + return; + } + + for (var i = 0; i < AL.currentCtx.attrs.length; i++) { + HEAP32[(((pValues)+(i*4))>>2)] = AL.currentCtx.attrs[i]; + } + break; + case 0x1007 /* ALC_FREQUENCY */: + if (!(deviceId in AL.deviceRefCounts)) { + AL.alcErr = 40961; + return; + } + if (!AL.currentCtx) { + AL.alcErr = 0xA002 /* ALC_INVALID_CONTEXT */; + return; + } + + HEAP32[((pValues)>>2)] = AL.currentCtx.audioCtx.sampleRate; + break; + case 0x1010 /* ALC_MONO_SOURCES */: + case 0x1011 /* ALC_STEREO_SOURCES */: + if (!(deviceId in AL.deviceRefCounts)) { + AL.alcErr = 40961; + return; + } + if (!AL.currentCtx) { + AL.alcErr = 0xA002 /* ALC_INVALID_CONTEXT */; + return; + } + + HEAP32[((pValues)>>2)] = 0x7FFFFFFF; + break; + case 0x1992 /* ALC_HRTF_SOFT */: + case 0x1993 /* ALC_HRTF_STATUS_SOFT */: + if (!(deviceId in AL.deviceRefCounts)) { + AL.alcErr = 40961; + return; + } + + var hrtfStatus = 0 /* ALC_HRTF_DISABLED_SOFT */; + for (var ctxId in AL.contexts) { + var ctx = AL.contexts[ctxId]; + if (ctx.deviceId === deviceId) { + hrtfStatus = ctx.hrtf ? 1 /* ALC_HRTF_ENABLED_SOFT */ : 0 /* ALC_HRTF_DISABLED_SOFT */; + } + } + HEAP32[((pValues)>>2)] = hrtfStatus; + break; + case 0x1994 /* ALC_NUM_HRTF_SPECIFIERS_SOFT */: + if (!(deviceId in AL.deviceRefCounts)) { + AL.alcErr = 40961; + return; + } + HEAP32[((pValues)>>2)] = 1; + break; + case 0x20003 /* ALC_MAX_AUXILIARY_SENDS */: + if (!(deviceId in AL.deviceRefCounts)) { + AL.alcErr = 40961; + return; + } + if (!AL.currentCtx) { + AL.alcErr = 0xA002 /* ALC_INVALID_CONTEXT */; + return; + } + + HEAP32[((pValues)>>2)] = 1; + case 0x312 /* ALC_CAPTURE_SAMPLES */: + var c = AL.requireValidCaptureDevice(deviceId, 'alcGetIntegerv'); + if (!c) { + return; + } + var n = c.capturedFrameCount; + var dstfreq = c.requestedSampleRate; + var srcfreq = c.audioCtx.sampleRate; + var nsamples = Math.floor(n * (dstfreq/srcfreq)); + HEAP32[((pValues)>>2)] = nsamples; + break; + default: + AL.alcErr = 40963; + return; + } + }; + _alcGetIntegerv.sig = 'vpiip'; + + + var _alcGetString = (deviceId, param) => { + if (AL.alcStringCache[param]) { + return AL.alcStringCache[param]; + } + + var ret; + switch (param) { + case 0: + ret = 'No Error'; + break; + case 40961: + ret = 'Invalid Device'; + break; + case 0xA002 /* ALC_INVALID_CONTEXT */: + ret = 'Invalid Context'; + break; + case 40963: + ret = 'Invalid Enum'; + break; + case 40964: + ret = 'Invalid Value'; + break; + case 0xA005 /* ALC_OUT_OF_MEMORY */: + ret = 'Out of Memory'; + break; + case 0x1004 /* ALC_DEFAULT_DEVICE_SPECIFIER */: + if (globalThis.AudioContext || globalThis.webkitAudioContext) { + ret = AL.DEVICE_NAME; + } else { + return 0; + } + break; + case 0x1005 /* ALC_DEVICE_SPECIFIER */: + if (globalThis.AudioContext || globalThis.webkitAudioContext) { + ret = AL.DEVICE_NAME + '\0'; + } else { + ret = '\0'; + } + break; + case 0x311 /* ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER */: + ret = AL.CAPTURE_DEVICE_NAME; + break; + case 0x310 /* ALC_CAPTURE_DEVICE_SPECIFIER */: + if (deviceId === 0) { + ret = AL.CAPTURE_DEVICE_NAME + '\0'; + } else { + var c = AL.requireValidCaptureDevice(deviceId, 'alcGetString'); + if (!c) { + return 0; + } + ret = c.deviceName; + } + break; + case 0x1006 /* ALC_EXTENSIONS */: + if (!deviceId) { + AL.alcErr = 40961; + return 0; + } + + ret = Object.keys(AL.ALC_EXTENSIONS).join(' ') + break; + default: + AL.alcErr = 40963; + return 0; + } + + ret = stringToNewUTF8(ret); + AL.alcStringCache[param] = ret; + return ret; + }; + _alcGetString.sig = 'ppi'; + + + var _alcIsExtensionPresent = (deviceId, pExtName) => { + var name = UTF8ToString(pExtName); + + return AL.ALC_EXTENSIONS[name] ? 1 : 0; + }; + _alcIsExtensionPresent.sig = 'ipp'; + + var _alcMakeContextCurrent = (contextId) => { + if (contextId === 0) { + AL.currentCtx = null; + } else { + AL.currentCtx = AL.contexts[contextId]; + } + return 1; + }; + _alcMakeContextCurrent.sig = 'ip'; + + + var _alcOpenDevice = (pDeviceName) => { + if (pDeviceName) { + var name = UTF8ToString(pDeviceName); + if (name !== AL.DEVICE_NAME) { + return 0; + } + } + + if (globalThis.AudioContext || globalThis.webkitAudioContext) { + var deviceId = AL.newId(); + AL.deviceRefCounts[deviceId] = 0; + return deviceId; + } + return 0; + }; + _alcOpenDevice.sig = 'pp'; + + var _alcProcessContext = (contextId) => {}; + _alcProcessContext.sig = 'vp'; + + var _alcSuspendContext = (contextId) => {}; + _alcSuspendContext.sig = 'vp'; + + + var _emscripten_get_now_res = () => { // return resolution of get_now, in nanoseconds + if (ENVIRONMENT_IS_NODE) { + return 1; // nanoseconds + } + // Modern environment where performance.now() is supported: + return 1000; // microseconds (1/1000 of a millisecond) + }; + _emscripten_get_now_res.sig = 'd'; + + var nowIsMonotonic = 1; + + var checkWasiClock = (clock_id) => clock_id >= 0 && clock_id <= 3; + var _clock_res_get = (clk_id, pres) => { + if (!checkWasiClock(clk_id)) { + return 28; + } + var nsec; + // all wasi clocks but realtime are monotonic + if (clk_id === 0) { + nsec = 1000 * 1000; // educated guess that it's milliseconds + } else if (nowIsMonotonic) { + nsec = _emscripten_get_now_res(); + } else { + return 52; + } + HEAP64[((pres)>>3)] = BigInt(nsec); + return 0; + }; + _clock_res_get.sig = 'iip'; + + + var _emscripten_date_now = () => Date.now(); + _emscripten_date_now.sig = 'd'; + + + + function _clock_time_get(clk_id, ignored_precision, ptime) { + ignored_precision = bigintToI53Checked(ignored_precision); + + + if (!checkWasiClock(clk_id)) { + return 28; + } + var now; + // all wasi clocks but realtime are monotonic + if (clk_id === 0) { + now = _emscripten_date_now(); + } else if (nowIsMonotonic) { + now = _emscripten_get_now(); + } else { + return 52; + } + // "now" is in ms, and wasi times are in ns. + var nsec = Math.round(now * 1000 * 1000); + HEAP64[((ptime)>>3)] = BigInt(nsec); + return 0; + ; + } + _clock_time_get.sig = 'iijp'; + + var _emscripten_alcDevicePauseSOFT = (deviceId) => { + if (!(deviceId in AL.deviceRefCounts)) { + AL.alcErr = 40961; + return; + } + + if (AL.paused) { + return; + } + AL.paused = true; + + for (var ctxId in AL.contexts) { + var ctx = AL.contexts[ctxId]; + if (ctx.deviceId !== deviceId) { + continue; + } + + ctx.audioCtx.suspend(); + clearInterval(ctx.interval); + ctx.interval = null; + } + }; + _emscripten_alcDevicePauseSOFT.sig = 'vi'; + + var _emscripten_alcDeviceResumeSOFT = (deviceId) => { + if (!(deviceId in AL.deviceRefCounts)) { + AL.alcErr = 40961; + return; + } + + if (!AL.paused) { + return; + } + AL.paused = false; + + for (var ctxId in AL.contexts) { + var ctx = AL.contexts[ctxId]; + if (ctx.deviceId !== deviceId) { + continue; + } + + ctx.interval = setInterval(() => AL.scheduleContextAudio(ctx), AL.QUEUE_INTERVAL); + ctx.audioCtx.resume(); + } + }; + _emscripten_alcDeviceResumeSOFT.sig = 'vi'; + + + + var _emscripten_alcGetStringiSOFT = (deviceId, param, index) => { + if (!(deviceId in AL.deviceRefCounts)) { + AL.alcErr = 40961; + return 0; + } + + if (AL.alcStringCache[param]) { + return AL.alcStringCache[param]; + } + + var ret; + switch (param) { + case 0x1995 /* ALC_HRTF_SPECIFIER_SOFT */: + if (index === 0) { + ret = 'Web Audio HRTF'; + } else { + AL.alcErr = 40964; + return 0; + } + break; + default: + if (index !== 0) { + AL.alcErr = 40963; + return 0; + } + return _alcGetString(deviceId, param); + } + + ret = stringToNewUTF8(ret); + AL.alcStringCache[param] = ret; + return ret; + }; + _emscripten_alcGetStringiSOFT.sig = 'iiii'; + + var _emscripten_alcResetDeviceSOFT = (deviceId, pAttrList) => { + if (!(deviceId in AL.deviceRefCounts)) { + AL.alcErr = 40961; + return 0; + } + + var hrtf = null; + pAttrList >>= 2; + if (pAttrList) { + var attr = 0; + var val = 0; + while (true) { + attr = HEAP32[pAttrList++]; + if (attr === 0) { + break; + } + val = HEAP32[pAttrList++]; + + switch (attr) { + case 0x1992 /* ALC_HRTF_SOFT */: + if (val === 1) { + hrtf = true; + } else if (val === 0) { + hrtf = false; + } + break; + } + } + } + + if (hrtf !== null) { + // Apply hrtf attrib to all contexts for this device + for (var ctxId in AL.contexts) { + var ctx = AL.contexts[ctxId]; + if (ctx.deviceId === deviceId) { + ctx.hrtf = hrtf; + AL.updateContextGlobal(ctx); + } + } + } + + return 1; + }; + _emscripten_alcResetDeviceSOFT.sig = 'iii'; + + var readEmAsmArgsArray = []; + var readEmAsmArgs = (sigPtr, buf) => { + readEmAsmArgsArray.length = 0; + var ch; + // Most arguments are i32s, so shift the buffer pointer so it is a plain + // index into HEAP32. + while (ch = HEAPU8[sigPtr++]) { + // Floats are always passed as doubles, so all types except for 'i' + // are 8 bytes and require alignment. + var wide = (ch != 105); + wide &= (ch != 112); + buf += wide && (buf % 8) ? 4 : 0; + readEmAsmArgsArray.push( + // Special case for pointers under wasm64 or CAN_ADDRESS_2GB mode. + ch == 112 ? HEAPU32[((buf)>>2)] : + ch == 106 ? HEAP64[((buf)>>3)] : + ch == 105 ? + HEAP32[((buf)>>2)] : + HEAPF64[((buf)>>3)] + ); + buf += wide ? 8 : 4; + } + return readEmAsmArgsArray; + }; + var runEmAsmFunction = (code, sigPtr, argbuf) => { + var args = readEmAsmArgs(sigPtr, argbuf); + return ASM_CONSTS[code](...args); + }; + var _emscripten_asm_const_int = (code, sigPtr, argbuf) => { + return runEmAsmFunction(code, sigPtr, argbuf); + }; + _emscripten_asm_const_int.sig = 'ippp'; + + var _emscripten_console_error = (str) => { + console.error(UTF8ToString(str)); + }; + _emscripten_console_error.sig = 'vp'; + + var _emscripten_console_log = (str) => { + console.log(UTF8ToString(str)); + }; + _emscripten_console_log.sig = 'vp'; + + var _emscripten_console_trace = (str) => { + console.trace(UTF8ToString(str)); + }; + _emscripten_console_trace.sig = 'vp'; + + var _emscripten_console_warn = (str) => { + console.warn(UTF8ToString(str)); + }; + _emscripten_console_warn.sig = 'vp'; + + + var _emscripten_err = (str) => err(UTF8ToString(str)); + _emscripten_err.sig = 'vp'; + + var getHeapMax = () => + // Stay one Wasm page short of 4GB: while e.g. Chrome is able to allocate + // full 4GB Wasm memories, the size will wrap back to 0 bytes in Wasm side + // for any code that deals with heap sizes, which would require special + // casing all heap size related code to treat 0 specially. + 2147483648; + var _emscripten_get_heap_max = () => getHeapMax(); + _emscripten_get_heap_max.sig = 'p'; + + + var GLctx; + + var webgl_enable_ANGLE_instanced_arrays = (ctx) => { + // Extension available in WebGL 1 from Firefox 26 and Google Chrome 30 onwards. Core feature in WebGL 2. + var ext = ctx.getExtension('ANGLE_instanced_arrays'); + // Because this extension is a core function in WebGL 2, assign the extension entry points in place of + // where the core functions will reside in WebGL 2. This way the calling code can call these without + // having to dynamically branch depending if running against WebGL 1 or WebGL 2. + if (ext) { + ctx['vertexAttribDivisor'] = (index, divisor) => ext['vertexAttribDivisorANGLE'](index, divisor); + ctx['drawArraysInstanced'] = (mode, first, count, primcount) => ext['drawArraysInstancedANGLE'](mode, first, count, primcount); + ctx['drawElementsInstanced'] = (mode, count, type, indices, primcount) => ext['drawElementsInstancedANGLE'](mode, count, type, indices, primcount); + return 1; + } + }; + + var webgl_enable_OES_vertex_array_object = (ctx) => { + // Extension available in WebGL 1 from Firefox 25 and WebKit 536.28/desktop Safari 6.0.3 onwards. Core feature in WebGL 2. + var ext = ctx.getExtension('OES_vertex_array_object'); + if (ext) { + ctx['createVertexArray'] = () => ext['createVertexArrayOES'](); + ctx['deleteVertexArray'] = (vao) => ext['deleteVertexArrayOES'](vao); + ctx['bindVertexArray'] = (vao) => ext['bindVertexArrayOES'](vao); + ctx['isVertexArray'] = (vao) => ext['isVertexArrayOES'](vao); + return 1; + } + }; + + var webgl_enable_WEBGL_draw_buffers = (ctx) => { + // Extension available in WebGL 1 from Firefox 28 onwards. Core feature in WebGL 2. + var ext = ctx.getExtension('WEBGL_draw_buffers'); + if (ext) { + ctx['drawBuffers'] = (n, bufs) => ext['drawBuffersWEBGL'](n, bufs); + return 1; + } + }; + + var webgl_enable_EXT_polygon_offset_clamp = (ctx) => + !!(ctx.extPolygonOffsetClamp = ctx.getExtension('EXT_polygon_offset_clamp')); + + var webgl_enable_EXT_clip_control = (ctx) => + !!(ctx.extClipControl = ctx.getExtension('EXT_clip_control')); + + var webgl_enable_WEBGL_polygon_mode = (ctx) => + !!(ctx.webglPolygonMode = ctx.getExtension('WEBGL_polygon_mode')); + + var webgl_enable_WEBGL_multi_draw = (ctx) => + // Closure is expected to be allowed to minify the '.multiDrawWebgl' property, so not accessing it quoted. + !!(ctx.multiDrawWebgl = ctx.getExtension('WEBGL_multi_draw')); + + var getEmscriptenSupportedExtensions = (ctx) => { + // Restrict the list of advertised extensions to those that we actually + // support. + var supportedExtensions = [ + // WebGL 1 extensions + 'ANGLE_instanced_arrays', + 'EXT_blend_minmax', + 'EXT_disjoint_timer_query', + 'EXT_frag_depth', + 'EXT_shader_texture_lod', + 'EXT_sRGB', + 'OES_element_index_uint', + 'OES_fbo_render_mipmap', + 'OES_standard_derivatives', + 'OES_texture_float', + 'OES_texture_half_float', + 'OES_texture_half_float_linear', + 'OES_vertex_array_object', + 'WEBGL_color_buffer_float', + 'WEBGL_depth_texture', + 'WEBGL_draw_buffers', + // WebGL 1 and WebGL 2 extensions + 'EXT_clip_control', + 'EXT_color_buffer_half_float', + 'EXT_depth_clamp', + 'EXT_float_blend', + 'EXT_polygon_offset_clamp', + 'EXT_texture_compression_bptc', + 'EXT_texture_compression_rgtc', + 'EXT_texture_filter_anisotropic', + 'KHR_parallel_shader_compile', + 'OES_texture_float_linear', + 'WEBGL_blend_func_extended', + 'WEBGL_compressed_texture_astc', + 'WEBGL_compressed_texture_etc', + 'WEBGL_compressed_texture_etc1', + 'WEBGL_compressed_texture_s3tc', + 'WEBGL_compressed_texture_s3tc_srgb', + 'WEBGL_debug_renderer_info', + 'WEBGL_debug_shaders', + 'WEBGL_lose_context', + 'WEBGL_multi_draw', + 'WEBGL_polygon_mode' + ]; + // .getSupportedExtensions() can return null if context is lost, so coerce to empty array. + return (ctx.getSupportedExtensions() || []).filter(ext => supportedExtensions.includes(ext)); + }; + + + var GL = { + counter:1, + buffers:[], + programs:[], + framebuffers:[], + renderbuffers:[], + textures:[], + shaders:[], + vaos:[], + contexts:[], + offscreenCanvases:{ + }, + queries:[], + stringCache:{ + }, + unpackAlignment:4, + unpackRowLength:0, + recordError:(errorCode) => { + if (!GL.lastError) { + GL.lastError = errorCode; + } + }, + getNewId:(table) => { + var ret = GL.counter++; + for (var i = table.length; i < ret; i++) { + table[i] = null; + } + return ret; + }, + genObject:(n, buffers, createFunction, objectTable + ) => { + for (var i = 0; i < n; i++) { + var buffer = GLctx[createFunction](); + var id = buffer && GL.getNewId(objectTable); + if (buffer) { + buffer.name = id; + objectTable[id] = buffer; + } else { + GL.recordError(0x502 /* GL_INVALID_OPERATION */); + } + HEAP32[(((buffers)+(i*4))>>2)] = id; + } + }, + getSource:(shader, count, string, length) => { + var source = ''; + for (var i = 0; i < count; ++i) { + var len = length ? HEAPU32[(((length)+(i*4))>>2)] : undefined; + source += UTF8ToString(HEAPU32[(((string)+(i*4))>>2)], len); + } + return source; + }, + createContext:(/** @type {HTMLCanvasElement} */ canvas, webGLContextAttributes) => { + + var ctx = + canvas.getContext("webgl", webGLContextAttributes); + + if (!ctx) return 0; + + var handle = GL.registerContext(ctx, webGLContextAttributes); + + return handle; + }, + registerContext:(ctx, webGLContextAttributes) => { + // without pthreads a context is just an integer ID + var handle = GL.getNewId(GL.contexts); + + var context = { + handle, + attributes: webGLContextAttributes, + version: webGLContextAttributes.majorVersion, + GLctx: ctx + }; + + // Store the created context object so that we can access the context + // given a canvas without having to pass the parameters again. + if (ctx.canvas) ctx.canvas.GLctxObject = context; + GL.contexts[handle] = context; + if (typeof webGLContextAttributes.enableExtensionsByDefault == 'undefined' || webGLContextAttributes.enableExtensionsByDefault) { + GL.initExtensions(context); + } + + return handle; + }, + makeContextCurrent:(contextHandle) => { + + // Active Emscripten GL layer context object. + GL.currentContext = GL.contexts[contextHandle]; + // Active WebGL context object. + Module['ctx'] = GLctx = GL.currentContext?.GLctx; + return !(contextHandle && !GLctx); + }, + getContext:(contextHandle) => { + return GL.contexts[contextHandle]; + }, + deleteContext:(contextHandle) => { + if (GL.currentContext === GL.contexts[contextHandle]) { + GL.currentContext = null; + } + if (typeof JSEvents == 'object') { + // Release all JS event handlers on the DOM element that the GL context is + // associated with since the context is now deleted. + JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx.canvas); + } + // Make sure the canvas object no longer refers to the context object so + // there are no GC surprises. + if (GL.contexts[contextHandle]?.GLctx.canvas) { + GL.contexts[contextHandle].GLctx.canvas.GLctxObject = undefined; + } + GL.contexts[contextHandle] = null; + }, + initExtensions:(context) => { + // If this function is called without a specific context object, init the + // extensions of the currently active context. + context ||= GL.currentContext; + + if (context.initExtensionsDone) return; + context.initExtensionsDone = true; + + var GLctx = context.GLctx; + + // Detect the presence of a few extensions manually, ction GL interop + // layer itself will need to know if they exist. + + // Extensions that are available in both WebGL 1 and WebGL 2 + webgl_enable_WEBGL_multi_draw(GLctx); + webgl_enable_EXT_polygon_offset_clamp(GLctx); + webgl_enable_EXT_clip_control(GLctx); + webgl_enable_WEBGL_polygon_mode(GLctx); + // Extensions that are only available in WebGL 1 (the calls will be no-ops + // if called on a WebGL 2 context active) + webgl_enable_ANGLE_instanced_arrays(GLctx); + webgl_enable_OES_vertex_array_object(GLctx); + webgl_enable_WEBGL_draw_buffers(GLctx); + { + GLctx.disjointTimerQueryExt = GLctx.getExtension("EXT_disjoint_timer_query"); + } + + for (var ext of getEmscriptenSupportedExtensions(GLctx)) { + // WEBGL_lose_context, WEBGL_debug_renderer_info and WEBGL_debug_shaders + // are not enabled by default. + if (!ext.includes('lose_context') && !ext.includes('debug')) { + // Call .getExtension() to enable that extension permanently. + GLctx.getExtension(ext); + } + } + }, + }; + var _emscripten_glActiveTexture = (x0) => GLctx.activeTexture(x0); + _emscripten_glActiveTexture.sig = 'vi'; + + var _emscripten_glAttachShader = (program, shader) => { + GLctx.attachShader(GL.programs[program], GL.shaders[shader]); + }; + _emscripten_glAttachShader.sig = 'vii'; + + var _emscripten_glBeginQueryEXT = (target, id) => { + GLctx.disjointTimerQueryExt['beginQueryEXT'](target, GL.queries[id]); + }; + _emscripten_glBeginQueryEXT.sig = 'vii'; + + + var _emscripten_glBindAttribLocation = (program, index, name) => { + GLctx.bindAttribLocation(GL.programs[program], index, UTF8ToString(name)); + }; + _emscripten_glBindAttribLocation.sig = 'viip'; + + var _emscripten_glBindBuffer = (target, buffer) => { + + GLctx.bindBuffer(target, GL.buffers[buffer]); + }; + _emscripten_glBindBuffer.sig = 'vii'; + + var _emscripten_glBindFramebuffer = (target, framebuffer) => { + + GLctx.bindFramebuffer(target, GL.framebuffers[framebuffer]); + + }; + _emscripten_glBindFramebuffer.sig = 'vii'; + + var _emscripten_glBindRenderbuffer = (target, renderbuffer) => { + GLctx.bindRenderbuffer(target, GL.renderbuffers[renderbuffer]); + }; + _emscripten_glBindRenderbuffer.sig = 'vii'; + + var _emscripten_glBindTexture = (target, texture) => { + GLctx.bindTexture(target, GL.textures[texture]); + }; + _emscripten_glBindTexture.sig = 'vii'; + + + var _emscripten_glBindVertexArray = (vao) => { + GLctx.bindVertexArray(GL.vaos[vao]); + }; + _emscripten_glBindVertexArray.sig = 'vi'; + var _emscripten_glBindVertexArrayOES = _emscripten_glBindVertexArray; + _emscripten_glBindVertexArrayOES.sig = 'vi'; + + var _emscripten_glBlendColor = (x0, x1, x2, x3) => GLctx.blendColor(x0, x1, x2, x3); + _emscripten_glBlendColor.sig = 'vffff'; + + var _emscripten_glBlendEquation = (x0) => GLctx.blendEquation(x0); + _emscripten_glBlendEquation.sig = 'vi'; + + var _emscripten_glBlendEquationSeparate = (x0, x1) => GLctx.blendEquationSeparate(x0, x1); + _emscripten_glBlendEquationSeparate.sig = 'vii'; + + var _emscripten_glBlendFunc = (x0, x1) => GLctx.blendFunc(x0, x1); + _emscripten_glBlendFunc.sig = 'vii'; + + var _emscripten_glBlendFuncSeparate = (x0, x1, x2, x3) => GLctx.blendFuncSeparate(x0, x1, x2, x3); + _emscripten_glBlendFuncSeparate.sig = 'viiii'; + + var _emscripten_glBufferData = (target, size, data, usage) => { + + // N.b. here first form specifies a heap subarray, second form an integer + // size, so the ?: code here is polymorphic. It is advised to avoid + // randomly mixing both uses in calling code, to avoid any potential JS + // engine JIT issues. + GLctx.bufferData(target, data ? HEAPU8.subarray(data, data+size) : size, usage); + }; + _emscripten_glBufferData.sig = 'vippi'; + + var _emscripten_glBufferSubData = (target, offset, size, data) => { + GLctx.bufferSubData(target, offset, HEAPU8.subarray(data, data+size)); + }; + _emscripten_glBufferSubData.sig = 'vippp'; + + var _emscripten_glCheckFramebufferStatus = (x0) => GLctx.checkFramebufferStatus(x0); + _emscripten_glCheckFramebufferStatus.sig = 'ii'; + + var _emscripten_glClear = (x0) => GLctx.clear(x0); + _emscripten_glClear.sig = 'vi'; + + var _emscripten_glClearColor = (x0, x1, x2, x3) => GLctx.clearColor(x0, x1, x2, x3); + _emscripten_glClearColor.sig = 'vffff'; + + var _emscripten_glClearDepthf = (x0) => GLctx.clearDepth(x0); + _emscripten_glClearDepthf.sig = 'vf'; + + var _emscripten_glClearStencil = (x0) => GLctx.clearStencil(x0); + _emscripten_glClearStencil.sig = 'vi'; + + var _emscripten_glClipControlEXT = (origin, depth) => { + GLctx.extClipControl['clipControlEXT'](origin, depth); + }; + _emscripten_glClipControlEXT.sig = 'vii'; + + var _emscripten_glColorMask = (red, green, blue, alpha) => { + GLctx.colorMask(!!red, !!green, !!blue, !!alpha); + }; + _emscripten_glColorMask.sig = 'viiii'; + + var _emscripten_glCompileShader = (shader) => { + GLctx.compileShader(GL.shaders[shader]); + }; + _emscripten_glCompileShader.sig = 'vi'; + + var _emscripten_glCompressedTexImage2D = (target, level, internalFormat, width, height, border, imageSize, data) => { + // `data` may be null here, which means "allocate uniniitalized space but + // don't upload" in GLES parlance, but `compressedTexImage2D` requires the + // final data parameter, so we simply pass a heap view starting at zero + // effectively uploading whatever happens to be near address zero. See + // https://github.com/emscripten-core/emscripten/issues/19300. + GLctx.compressedTexImage2D(target, level, internalFormat, width, height, border, HEAPU8.subarray((data), data+imageSize)); + }; + _emscripten_glCompressedTexImage2D.sig = 'viiiiiiip'; + + var _emscripten_glCompressedTexSubImage2D = (target, level, xoffset, yoffset, width, height, format, imageSize, data) => { + GLctx.compressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, HEAPU8.subarray((data), data+imageSize)); + }; + _emscripten_glCompressedTexSubImage2D.sig = 'viiiiiiiip'; + + var _emscripten_glCopyTexImage2D = (x0, x1, x2, x3, x4, x5, x6, x7) => GLctx.copyTexImage2D(x0, x1, x2, x3, x4, x5, x6, x7); + _emscripten_glCopyTexImage2D.sig = 'viiiiiiii'; + + var _emscripten_glCopyTexSubImage2D = (x0, x1, x2, x3, x4, x5, x6, x7) => GLctx.copyTexSubImage2D(x0, x1, x2, x3, x4, x5, x6, x7); + _emscripten_glCopyTexSubImage2D.sig = 'viiiiiiii'; + + var _emscripten_glCreateProgram = () => { + var id = GL.getNewId(GL.programs); + var program = GLctx.createProgram(); + // Store additional information needed for each shader program: + program.name = id; + // Lazy cache results of + // glGetProgramiv(GL_ACTIVE_UNIFORM_MAX_LENGTH/GL_ACTIVE_ATTRIBUTE_MAX_LENGTH/GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH) + program.maxUniformLength = program.maxAttributeLength = program.maxUniformBlockNameLength = 0; + program.uniformIdCounter = 1; + GL.programs[id] = program; + return id; + }; + _emscripten_glCreateProgram.sig = 'i'; + + var _emscripten_glCreateShader = (shaderType) => { + var id = GL.getNewId(GL.shaders); + GL.shaders[id] = GLctx.createShader(shaderType); + + return id; + }; + _emscripten_glCreateShader.sig = 'ii'; + + var _emscripten_glCullFace = (x0) => GLctx.cullFace(x0); + _emscripten_glCullFace.sig = 'vi'; + + var _emscripten_glDeleteBuffers = (n, buffers) => { + for (var i = 0; i < n; i++) { + var id = HEAP32[(((buffers)+(i*4))>>2)]; + var buffer = GL.buffers[id]; + + // From spec: "glDeleteBuffers silently ignores 0's and names that do not + // correspond to existing buffer objects." + if (!buffer) continue; + + GLctx.deleteBuffer(buffer); + buffer.name = 0; + GL.buffers[id] = null; + + } + }; + _emscripten_glDeleteBuffers.sig = 'vip'; + + var _emscripten_glDeleteFramebuffers = (n, framebuffers) => { + for (var i = 0; i < n; ++i) { + var id = HEAP32[(((framebuffers)+(i*4))>>2)]; + var framebuffer = GL.framebuffers[id]; + if (!framebuffer) continue; // GL spec: "glDeleteFramebuffers silently ignores 0s and names that do not correspond to existing framebuffer objects". + GLctx.deleteFramebuffer(framebuffer); + framebuffer.name = 0; + GL.framebuffers[id] = null; + } + }; + _emscripten_glDeleteFramebuffers.sig = 'vip'; + + var _emscripten_glDeleteProgram = (id) => { + if (!id) return; + var program = GL.programs[id]; + if (!program) { + // glDeleteProgram actually signals an error when deleting a nonexisting + // object, unlike some other GL delete functions. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + GLctx.deleteProgram(program); + program.name = 0; + GL.programs[id] = null; + }; + _emscripten_glDeleteProgram.sig = 'vi'; + + var _emscripten_glDeleteQueriesEXT = (n, ids) => { + for (var i = 0; i < n; i++) { + var id = HEAP32[(((ids)+(i*4))>>2)]; + var query = GL.queries[id]; + if (!query) continue; // GL spec: "unused names in ids are ignored, as is the name zero." + GLctx.disjointTimerQueryExt['deleteQueryEXT'](query); + GL.queries[id] = null; + } + }; + _emscripten_glDeleteQueriesEXT.sig = 'vip'; + + var _emscripten_glDeleteRenderbuffers = (n, renderbuffers) => { + for (var i = 0; i < n; i++) { + var id = HEAP32[(((renderbuffers)+(i*4))>>2)]; + var renderbuffer = GL.renderbuffers[id]; + if (!renderbuffer) continue; // GL spec: "glDeleteRenderbuffers silently ignores 0s and names that do not correspond to existing renderbuffer objects". + GLctx.deleteRenderbuffer(renderbuffer); + renderbuffer.name = 0; + GL.renderbuffers[id] = null; + } + }; + _emscripten_glDeleteRenderbuffers.sig = 'vip'; + + var _emscripten_glDeleteShader = (id) => { + if (!id) return; + var shader = GL.shaders[id]; + if (!shader) { + // glDeleteShader actually signals an error when deleting a nonexisting + // object, unlike some other GL delete functions. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + GLctx.deleteShader(shader); + GL.shaders[id] = null; + }; + _emscripten_glDeleteShader.sig = 'vi'; + + var _emscripten_glDeleteTextures = (n, textures) => { + for (var i = 0; i < n; i++) { + var id = HEAP32[(((textures)+(i*4))>>2)]; + var texture = GL.textures[id]; + // GL spec: "glDeleteTextures silently ignores 0s and names that do not + // correspond to existing textures". + if (!texture) continue; + GLctx.deleteTexture(texture); + texture.name = 0; + GL.textures[id] = null; + } + }; + _emscripten_glDeleteTextures.sig = 'vip'; + + + var _emscripten_glDeleteVertexArrays = (n, vaos) => { + for (var i = 0; i < n; i++) { + var id = HEAP32[(((vaos)+(i*4))>>2)]; + GLctx.deleteVertexArray(GL.vaos[id]); + GL.vaos[id] = null; + } + }; + _emscripten_glDeleteVertexArrays.sig = 'vip'; + var _emscripten_glDeleteVertexArraysOES = _emscripten_glDeleteVertexArrays; + _emscripten_glDeleteVertexArraysOES.sig = 'vip'; + + var _emscripten_glDepthFunc = (x0) => GLctx.depthFunc(x0); + _emscripten_glDepthFunc.sig = 'vi'; + + var _emscripten_glDepthMask = (flag) => { + GLctx.depthMask(!!flag); + }; + _emscripten_glDepthMask.sig = 'vi'; + + var _emscripten_glDepthRangef = (x0, x1) => GLctx.depthRange(x0, x1); + _emscripten_glDepthRangef.sig = 'vff'; + + var _emscripten_glDetachShader = (program, shader) => { + GLctx.detachShader(GL.programs[program], GL.shaders[shader]); + }; + _emscripten_glDetachShader.sig = 'vii'; + + var _emscripten_glDisable = (x0) => GLctx.disable(x0); + _emscripten_glDisable.sig = 'vi'; + + var _emscripten_glDisableVertexAttribArray = (index) => { + GLctx.disableVertexAttribArray(index); + }; + _emscripten_glDisableVertexAttribArray.sig = 'vi'; + + var _emscripten_glDrawArrays = (mode, first, count) => { + + GLctx.drawArrays(mode, first, count); + + }; + _emscripten_glDrawArrays.sig = 'viii'; + + + var _emscripten_glDrawArraysInstanced = (mode, first, count, primcount) => { + GLctx.drawArraysInstanced(mode, first, count, primcount); + }; + _emscripten_glDrawArraysInstanced.sig = 'viiii'; + var _emscripten_glDrawArraysInstancedANGLE = _emscripten_glDrawArraysInstanced; + + + var tempFixedLengthArray = []; + + var _emscripten_glDrawBuffers = (n, bufs) => { + + var bufArray = tempFixedLengthArray[n]; + for (var i = 0; i < n; i++) { + bufArray[i] = HEAP32[(((bufs)+(i*4))>>2)]; + } + + GLctx.drawBuffers(bufArray); + }; + _emscripten_glDrawBuffers.sig = 'vip'; + var _emscripten_glDrawBuffersWEBGL = _emscripten_glDrawBuffers; + + var _emscripten_glDrawElements = (mode, count, type, indices) => { + + GLctx.drawElements(mode, count, type, indices); + + }; + _emscripten_glDrawElements.sig = 'viiip'; + + + var _emscripten_glDrawElementsInstanced = (mode, count, type, indices, primcount) => { + GLctx.drawElementsInstanced(mode, count, type, indices, primcount); + }; + _emscripten_glDrawElementsInstanced.sig = 'viiipi'; + var _emscripten_glDrawElementsInstancedANGLE = _emscripten_glDrawElementsInstanced; + + var _emscripten_glEnable = (x0) => GLctx.enable(x0); + _emscripten_glEnable.sig = 'vi'; + + var _emscripten_glEnableVertexAttribArray = (index) => { + GLctx.enableVertexAttribArray(index); + }; + _emscripten_glEnableVertexAttribArray.sig = 'vi'; + + var _emscripten_glEndQueryEXT = (target) => { + GLctx.disjointTimerQueryExt['endQueryEXT'](target); + }; + _emscripten_glEndQueryEXT.sig = 'vi'; + + var _emscripten_glFinish = () => GLctx.finish(); + _emscripten_glFinish.sig = 'v'; + + var _emscripten_glFlush = () => GLctx.flush(); + _emscripten_glFlush.sig = 'v'; + + var _emscripten_glFramebufferRenderbuffer = (target, attachment, renderbuffertarget, renderbuffer) => { + GLctx.framebufferRenderbuffer(target, attachment, renderbuffertarget, + GL.renderbuffers[renderbuffer]); + }; + _emscripten_glFramebufferRenderbuffer.sig = 'viiii'; + + var _emscripten_glFramebufferTexture2D = (target, attachment, textarget, texture, level) => { + GLctx.framebufferTexture2D(target, attachment, textarget, + GL.textures[texture], level); + }; + _emscripten_glFramebufferTexture2D.sig = 'viiiii'; + + var _emscripten_glFrontFace = (x0) => GLctx.frontFace(x0); + _emscripten_glFrontFace.sig = 'vi'; + + var _emscripten_glGenBuffers = (n, buffers) => { + GL.genObject(n, buffers, 'createBuffer', GL.buffers + ); + }; + _emscripten_glGenBuffers.sig = 'vip'; + + var _emscripten_glGenFramebuffers = (n, ids) => { + GL.genObject(n, ids, 'createFramebuffer', GL.framebuffers + ); + }; + _emscripten_glGenFramebuffers.sig = 'vip'; + + var _emscripten_glGenQueriesEXT = (n, ids) => { + for (var i = 0; i < n; i++) { + var query = GLctx.disjointTimerQueryExt['createQueryEXT'](); + if (!query) { + GL.recordError(0x502 /* GL_INVALID_OPERATION */); + while (i < n) HEAP32[(((ids)+(i++*4))>>2)] = 0; + return; + } + var id = GL.getNewId(GL.queries); + query.name = id; + GL.queries[id] = query; + HEAP32[(((ids)+(i*4))>>2)] = id; + } + }; + _emscripten_glGenQueriesEXT.sig = 'vip'; + + var _emscripten_glGenRenderbuffers = (n, renderbuffers) => { + GL.genObject(n, renderbuffers, 'createRenderbuffer', GL.renderbuffers + ); + }; + _emscripten_glGenRenderbuffers.sig = 'vip'; + + var _emscripten_glGenTextures = (n, textures) => { + GL.genObject(n, textures, 'createTexture', GL.textures + ); + }; + _emscripten_glGenTextures.sig = 'vip'; + + + var _emscripten_glGenVertexArrays = (n, arrays) => { + GL.genObject(n, arrays, 'createVertexArray', GL.vaos + ); + }; + _emscripten_glGenVertexArrays.sig = 'vip'; + var _emscripten_glGenVertexArraysOES = _emscripten_glGenVertexArrays; + _emscripten_glGenVertexArraysOES.sig = 'vip'; + + var _emscripten_glGenerateMipmap = (x0) => GLctx.generateMipmap(x0); + _emscripten_glGenerateMipmap.sig = 'vi'; + + + var __glGetActiveAttribOrUniform = (funcName, program, index, bufSize, length, size, type, name) => { + program = GL.programs[program]; + var info = GLctx[funcName](program, index); + if (info) { + // If an error occurs, nothing will be written to length, size and type and name. + var numBytesWrittenExclNull = name && stringToUTF8(info.name, name, bufSize); + if (length) HEAP32[((length)>>2)] = numBytesWrittenExclNull; + if (size) HEAP32[((size)>>2)] = info.size; + if (type) HEAP32[((type)>>2)] = info.type; + } + }; + + var _emscripten_glGetActiveAttrib = (program, index, bufSize, length, size, type, name) => + __glGetActiveAttribOrUniform('getActiveAttrib', program, index, bufSize, length, size, type, name); + _emscripten_glGetActiveAttrib.sig = 'viiipppp'; + + + var _emscripten_glGetActiveUniform = (program, index, bufSize, length, size, type, name) => + __glGetActiveAttribOrUniform('getActiveUniform', program, index, bufSize, length, size, type, name); + _emscripten_glGetActiveUniform.sig = 'viiipppp'; + + var _emscripten_glGetAttachedShaders = (program, maxCount, count, shaders) => { + var result = GLctx.getAttachedShaders(GL.programs[program]); + var len = result.length; + if (len > maxCount) { + len = maxCount; + } + HEAP32[((count)>>2)] = len; + for (var i = 0; i < len; ++i) { + var id = GL.shaders.indexOf(result[i]); + HEAP32[(((shaders)+(i*4))>>2)] = id; + } + }; + _emscripten_glGetAttachedShaders.sig = 'viipp'; + + + var _emscripten_glGetAttribLocation = (program, name) => + GLctx.getAttribLocation(GL.programs[program], UTF8ToString(name)); + _emscripten_glGetAttribLocation.sig = 'iip'; + + var writeI53ToI64 = (ptr, num) => { + HEAPU32[((ptr)>>2)] = num; + var lower = HEAPU32[((ptr)>>2)]; + HEAPU32[(((ptr)+(4))>>2)] = (num - lower)/4294967296; + }; + + var emscriptenWebGLGet = (name_, p, type) => { + // Guard against user passing a null pointer. + // Note that GLES2 spec does not say anything about how passing a null + // pointer should be treated. Testing on desktop core GL 3, the application + // crashes on glGetIntegerv to a null pointer, but better to report an error + // instead of doing anything random. + if (!p) { + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + var ret = undefined; + switch (name_) { // Handle a few trivial GLES values + case 0x8DFA: // GL_SHADER_COMPILER + ret = 1; + break; + case 0x8DF8: // GL_SHADER_BINARY_FORMATS + if (type != 0 && type != 1) { + GL.recordError(0x500); // GL_INVALID_ENUM + } + // Do not write anything to the out pointer, since no binary formats are + // supported. + return; + case 0x8DF9: // GL_NUM_SHADER_BINARY_FORMATS + ret = 0; + break; + case 0x86A2: // GL_NUM_COMPRESSED_TEXTURE_FORMATS + // WebGL doesn't have GL_NUM_COMPRESSED_TEXTURE_FORMATS (it's obsolete + // since GL_COMPRESSED_TEXTURE_FORMATS returns a JS array that can be + // queried for length), so implement it ourselves to allow C++ GLES2 + // code get the length. + var formats = GLctx.getParameter(0x86A3 /*GL_COMPRESSED_TEXTURE_FORMATS*/); + ret = formats ? formats.length : 0; + break; + + } + + if (ret === undefined) { + var result = GLctx.getParameter(name_); + switch (typeof result) { + case "number": + ret = result; + break; + case "boolean": + ret = result ? 1 : 0; + break; + case "string": + GL.recordError(0x500); // GL_INVALID_ENUM + return; + case "object": + if (result === null) { + // null is a valid result for some (e.g., which buffer is bound - + // perhaps nothing is bound), but otherwise can mean an invalid + // name_, which we need to report as an error + switch (name_) { + case 0x8894: // ARRAY_BUFFER_BINDING + case 0x8B8D: // CURRENT_PROGRAM + case 0x8895: // ELEMENT_ARRAY_BUFFER_BINDING + case 0x8CA6: // FRAMEBUFFER_BINDING or DRAW_FRAMEBUFFER_BINDING + case 0x8CA7: // RENDERBUFFER_BINDING + case 0x8069: // TEXTURE_BINDING_2D + case 0x85B5: // WebGL 2 GL_VERTEX_ARRAY_BINDING, or WebGL 1 extension OES_vertex_array_object GL_VERTEX_ARRAY_BINDING_OES + case 0x8514: { // TEXTURE_BINDING_CUBE_MAP + ret = 0; + break; + } + default: { + GL.recordError(0x500); // GL_INVALID_ENUM + return; + } + } + } else if (result instanceof Float32Array || + result instanceof Uint32Array || + result instanceof Int32Array || + result instanceof Array) { + for (var i = 0; i < result.length; ++i) { + switch (type) { + case 0: HEAP32[(((p)+(i*4))>>2)] = result[i]; break; + case 2: HEAPF32[(((p)+(i*4))>>2)] = result[i]; break; + case 4: HEAP8[(p)+(i)] = result[i] ? 1 : 0; break; + } + } + return; + } else { + try { + ret = result.name | 0; + } catch(e) { + GL.recordError(0x500); // GL_INVALID_ENUM + err(`GL_INVALID_ENUM in glGet${type}v: Unknown object returned from WebGL getParameter(${name_})! (error: ${e})`); + return; + } + } + break; + default: + GL.recordError(0x500); // GL_INVALID_ENUM + err(`GL_INVALID_ENUM in glGet${type}v: Native code calling glGet${type}v(${name_}) and it returns ${result} of type ${typeof(result)}!`); + return; + } + } + + switch (type) { + case 1: writeI53ToI64(p, ret); break; + case 0: HEAP32[((p)>>2)] = ret; break; + case 2: HEAPF32[((p)>>2)] = ret; break; + case 4: HEAP8[p] = ret ? 1 : 0; break; + } + }; + + var _emscripten_glGetBooleanv = (name_, p) => emscriptenWebGLGet(name_, p, 4); + _emscripten_glGetBooleanv.sig = 'vip'; + + var _emscripten_glGetBufferParameteriv = (target, value, data) => { + if (!data) { + // GLES2 specification does not specify how to behave if data is a null + // pointer. Since calling this function does not make sense if data == + // null, issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + HEAP32[((data)>>2)] = GLctx.getBufferParameter(target, value); + }; + _emscripten_glGetBufferParameteriv.sig = 'viip'; + + var _emscripten_glGetError = () => { + var error = GLctx.getError() || GL.lastError; + GL.lastError = 0/*GL_NO_ERROR*/; + return error; + }; + _emscripten_glGetError.sig = 'i'; + + + var _emscripten_glGetFloatv = (name_, p) => emscriptenWebGLGet(name_, p, 2); + _emscripten_glGetFloatv.sig = 'vip'; + + var _emscripten_glGetFramebufferAttachmentParameteriv = (target, attachment, pname, params) => { + var result = GLctx.getFramebufferAttachmentParameter(target, attachment, pname); + if (result instanceof WebGLRenderbuffer || + result instanceof WebGLTexture) { + result = result.name | 0; + } + HEAP32[((params)>>2)] = result; + }; + _emscripten_glGetFramebufferAttachmentParameteriv.sig = 'viiip'; + + + var _emscripten_glGetIntegerv = (name_, p) => emscriptenWebGLGet(name_, p, 0); + _emscripten_glGetIntegerv.sig = 'vip'; + + var _emscripten_glGetProgramInfoLog = (program, maxLength, length, infoLog) => { + var log = GLctx.getProgramInfoLog(GL.programs[program]); + if (log === null) log = '(unknown error)'; + var numBytesWrittenExclNull = (maxLength > 0 && infoLog) ? stringToUTF8(log, infoLog, maxLength) : 0; + if (length) HEAP32[((length)>>2)] = numBytesWrittenExclNull; + }; + _emscripten_glGetProgramInfoLog.sig = 'viipp'; + + var _emscripten_glGetProgramiv = (program, pname, p) => { + if (!p) { + // GLES2 specification does not specify how to behave if p is a null + // pointer. Since calling this function does not make sense if p == null, + // issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + + if (program >= GL.counter) { + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + + program = GL.programs[program]; + + if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH + var log = GLctx.getProgramInfoLog(program); + if (log === null) log = '(unknown error)'; + HEAP32[((p)>>2)] = log.length + 1; + } else if (pname == 0x8B87 /* GL_ACTIVE_UNIFORM_MAX_LENGTH */) { + if (!program.maxUniformLength) { + var numActiveUniforms = GLctx.getProgramParameter(program, 0x8B86/*GL_ACTIVE_UNIFORMS*/); + for (var i = 0; i < numActiveUniforms; ++i) { + program.maxUniformLength = Math.max(program.maxUniformLength, GLctx.getActiveUniform(program, i).name.length+1); + } + } + HEAP32[((p)>>2)] = program.maxUniformLength; + } else if (pname == 0x8B8A /* GL_ACTIVE_ATTRIBUTE_MAX_LENGTH */) { + if (!program.maxAttributeLength) { + var numActiveAttributes = GLctx.getProgramParameter(program, 0x8B89/*GL_ACTIVE_ATTRIBUTES*/); + for (var i = 0; i < numActiveAttributes; ++i) { + program.maxAttributeLength = Math.max(program.maxAttributeLength, GLctx.getActiveAttrib(program, i).name.length+1); + } + } + HEAP32[((p)>>2)] = program.maxAttributeLength; + } else if (pname == 0x8A35 /* GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH */) { + if (!program.maxUniformBlockNameLength) { + var numActiveUniformBlocks = GLctx.getProgramParameter(program, 0x8A36/*GL_ACTIVE_UNIFORM_BLOCKS*/); + for (var i = 0; i < numActiveUniformBlocks; ++i) { + program.maxUniformBlockNameLength = Math.max(program.maxUniformBlockNameLength, GLctx.getActiveUniformBlockName(program, i).length+1); + } + } + HEAP32[((p)>>2)] = program.maxUniformBlockNameLength; + } else { + HEAP32[((p)>>2)] = GLctx.getProgramParameter(program, pname); + } + }; + _emscripten_glGetProgramiv.sig = 'viip'; + + + var _emscripten_glGetQueryObjecti64vEXT = (id, pname, params) => { + if (!params) { + // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense + // if p == null, issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + var query = GL.queries[id]; + var param; + { + param = GLctx.disjointTimerQueryExt['getQueryObjectEXT'](query, pname); + } + var ret; + if (typeof param == 'boolean') { + ret = param ? 1 : 0; + } else { + ret = param; + } + writeI53ToI64(params, ret); + }; + _emscripten_glGetQueryObjecti64vEXT.sig = 'viip'; + + var _emscripten_glGetQueryObjectivEXT = (id, pname, params) => { + if (!params) { + // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense + // if p == null, issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + var query = GL.queries[id]; + var param = GLctx.disjointTimerQueryExt['getQueryObjectEXT'](query, pname); + var ret; + if (typeof param == 'boolean') { + ret = param ? 1 : 0; + } else { + ret = param; + } + HEAP32[((params)>>2)] = ret; + }; + _emscripten_glGetQueryObjectivEXT.sig = 'viip'; + + + var _emscripten_glGetQueryObjectui64vEXT = _emscripten_glGetQueryObjecti64vEXT; + + + var _emscripten_glGetQueryObjectuivEXT = _emscripten_glGetQueryObjectivEXT; + + var _emscripten_glGetQueryivEXT = (target, pname, params) => { + if (!params) { + // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense + // if p == null, issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + HEAP32[((params)>>2)] = GLctx.disjointTimerQueryExt['getQueryEXT'](target, pname); + }; + _emscripten_glGetQueryivEXT.sig = 'viip'; + + var _emscripten_glGetRenderbufferParameteriv = (target, pname, params) => { + if (!params) { + // GLES2 specification does not specify how to behave if params is a null pointer. Since calling this function does not make sense + // if params == null, issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + HEAP32[((params)>>2)] = GLctx.getRenderbufferParameter(target, pname); + }; + _emscripten_glGetRenderbufferParameteriv.sig = 'viip'; + + + var _emscripten_glGetShaderInfoLog = (shader, maxLength, length, infoLog) => { + var log = GLctx.getShaderInfoLog(GL.shaders[shader]); + if (log === null) log = '(unknown error)'; + var numBytesWrittenExclNull = (maxLength > 0 && infoLog) ? stringToUTF8(log, infoLog, maxLength) : 0; + if (length) HEAP32[((length)>>2)] = numBytesWrittenExclNull; + }; + _emscripten_glGetShaderInfoLog.sig = 'viipp'; + + var _emscripten_glGetShaderPrecisionFormat = (shaderType, precisionType, range, precision) => { + var result = GLctx.getShaderPrecisionFormat(shaderType, precisionType); + HEAP32[((range)>>2)] = result.rangeMin; + HEAP32[(((range)+(4))>>2)] = result.rangeMax; + HEAP32[((precision)>>2)] = result.precision; + }; + _emscripten_glGetShaderPrecisionFormat.sig = 'viipp'; + + var _emscripten_glGetShaderSource = (shader, bufSize, length, source) => { + var result = GLctx.getShaderSource(GL.shaders[shader]); + if (!result) return; // If an error occurs, nothing will be written to length or source. + var numBytesWrittenExclNull = (bufSize > 0 && source) ? stringToUTF8(result, source, bufSize) : 0; + if (length) HEAP32[((length)>>2)] = numBytesWrittenExclNull; + }; + _emscripten_glGetShaderSource.sig = 'viipp'; + + var _emscripten_glGetShaderiv = (shader, pname, p) => { + if (!p) { + // GLES2 specification does not specify how to behave if p is a null + // pointer. Since calling this function does not make sense if p == null, + // issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + if (pname == 0x8B84) { // GL_INFO_LOG_LENGTH + var log = GLctx.getShaderInfoLog(GL.shaders[shader]); + if (log === null) log = '(unknown error)'; + // The GLES2 specification says that if the shader has an empty info log, + // a value of 0 is returned. Otherwise the log has a null char appended. + // (An empty string is falsey, so we can just check that instead of + // looking at log.length.) + var logLength = log ? log.length + 1 : 0; + HEAP32[((p)>>2)] = logLength; + } else if (pname == 0x8B88) { // GL_SHADER_SOURCE_LENGTH + var source = GLctx.getShaderSource(GL.shaders[shader]); + // source may be a null, or the empty string, both of which are falsey + // values that we report a 0 length for. + var sourceLength = source ? source.length + 1 : 0; + HEAP32[((p)>>2)] = sourceLength; + } else { + HEAP32[((p)>>2)] = GLctx.getShaderParameter(GL.shaders[shader], pname); + } + }; + _emscripten_glGetShaderiv.sig = 'viip'; + + + + var webglGetExtensions = () => { + var exts = getEmscriptenSupportedExtensions(GLctx); + exts = exts.concat(exts.map((e) => "GL_" + e)); + return exts; + }; + + var _emscripten_glGetString = (name_) => { + var ret = GL.stringCache[name_]; + if (!ret) { + switch (name_) { + case 0x1F03 /* GL_EXTENSIONS */: + ret = stringToNewUTF8(webglGetExtensions().join(' ')); + break; + case 0x1F00 /* GL_VENDOR */: + case 0x1F01 /* GL_RENDERER */: + case 0x9245 /* UNMASKED_VENDOR_WEBGL */: + case 0x9246 /* UNMASKED_RENDERER_WEBGL */: + var s = GLctx.getParameter(name_); + if (!s) { + GL.recordError(0x500/*GL_INVALID_ENUM*/); + } + ret = s ? stringToNewUTF8(s) : 0; + break; + + case 0x1F02 /* GL_VERSION */: + var webGLVersion = GLctx.getParameter(0x1F02 /*GL_VERSION*/); + // return GLES version string corresponding to the version of the WebGL context + var glVersion = `OpenGL ES 2.0 (${webGLVersion})`; + ret = stringToNewUTF8(glVersion); + break; + case 0x8B8C /* GL_SHADING_LANGUAGE_VERSION */: + var glslVersion = GLctx.getParameter(0x8B8C /*GL_SHADING_LANGUAGE_VERSION*/); + // extract the version number 'N.M' from the string 'WebGL GLSL ES N.M ...' + var ver_re = /^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/; + var ver_num = glslVersion.match(ver_re); + if (ver_num !== null) { + if (ver_num[1].length == 3) ver_num[1] = ver_num[1] + '0'; // ensure minor version has 2 digits + glslVersion = `OpenGL ES GLSL ES ${ver_num[1]} (${glslVersion})`; + } + ret = stringToNewUTF8(glslVersion); + break; + default: + GL.recordError(0x500/*GL_INVALID_ENUM*/); + // fall through + } + GL.stringCache[name_] = ret; + } + return ret; + }; + _emscripten_glGetString.sig = 'pi'; + + var _emscripten_glGetTexParameterfv = (target, pname, params) => { + if (!params) { + // GLES2 specification does not specify how to behave if params is a null + // pointer. Since calling this function does not make sense if p == null, + // issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + HEAPF32[((params)>>2)] = GLctx.getTexParameter(target, pname); + }; + _emscripten_glGetTexParameterfv.sig = 'viip'; + + var _emscripten_glGetTexParameteriv = (target, pname, params) => { + if (!params) { + // GLES2 specification does not specify how to behave if params is a null + // pointer. Since calling this function does not make sense if p == null, + // issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + HEAP32[((params)>>2)] = GLctx.getTexParameter(target, pname); + }; + _emscripten_glGetTexParameteriv.sig = 'viip'; + + /** @suppress {checkTypes} */ + var jstoi_q = (str) => parseInt(str); + + /** @noinline */ + var webglGetLeftBracePos = (name) => name.slice(-1) == ']' && name.lastIndexOf('['); + + var webglPrepareUniformLocationsBeforeFirstUse = (program) => { + var uniformLocsById = program.uniformLocsById, // Maps GLuint -> WebGLUniformLocation + uniformSizeAndIdsByName = program.uniformSizeAndIdsByName, // Maps name -> [uniform array length, GLuint] + i, j; + + // On the first time invocation of glGetUniformLocation on this shader program: + // initialize cache data structures and discover which uniforms are arrays. + if (!uniformLocsById) { + // maps GLint integer locations to WebGLUniformLocations + program.uniformLocsById = uniformLocsById = {}; + // maps integer locations back to uniform name strings, so that we can lazily fetch uniform array locations + program.uniformArrayNamesById = {}; + + var numActiveUniforms = GLctx.getProgramParameter(program, 0x8B86/*GL_ACTIVE_UNIFORMS*/); + for (i = 0; i < numActiveUniforms; ++i) { + var u = GLctx.getActiveUniform(program, i); + var nm = u.name; + var sz = u.size; + var lb = webglGetLeftBracePos(nm); + var arrayName = lb > 0 ? nm.slice(0, lb) : nm; + + // Assign a new location. + var id = program.uniformIdCounter; + program.uniformIdCounter += sz; + // Eagerly get the location of the uniformArray[0] base element. + // The remaining indices >0 will be left for lazy evaluation to + // improve performance. Those may never be needed to fetch, if the + // application fills arrays always in full starting from the first + // element of the array. + uniformSizeAndIdsByName[arrayName] = [sz, id]; + + // Store placeholder integers in place that highlight that these + // >0 index locations are array indices pending population. + for (j = 0; j < sz; ++j) { + uniformLocsById[id] = j; + program.uniformArrayNamesById[id++] = arrayName; + } + } + } + }; + + + + var _emscripten_glGetUniformLocation = (program, name) => { + + name = UTF8ToString(name); + + if (program = GL.programs[program]) { + webglPrepareUniformLocationsBeforeFirstUse(program); + var uniformLocsById = program.uniformLocsById; // Maps GLuint -> WebGLUniformLocation + var arrayIndex = 0; + var uniformBaseName = name; + + // Invariant: when populating integer IDs for uniform locations, we must + // maintain the precondition that arrays reside in contiguous addresses, + // i.e. for a 'vec4 colors[10];', colors[4] must be at location + // colors[0]+4. However, user might call glGetUniformLocation(program, + // "colors") for an array, so we cannot discover based on the user input + // arguments whether the uniform we are dealing with is an array. The only + // way to discover which uniforms are arrays is to enumerate over all the + // active uniforms in the program. + var leftBrace = webglGetLeftBracePos(name); + + // If user passed an array accessor "[index]", parse the array index off the accessor. + if (leftBrace > 0) { + arrayIndex = jstoi_q(name.slice(leftBrace + 1)) >>> 0; // "index]", coerce parseInt(']') with >>>0 to treat "foo[]" as "foo[0]" and foo[-1] as unsigned out-of-bounds. + uniformBaseName = name.slice(0, leftBrace); + } + + // Have we cached the location of this uniform before? + // A pair [array length, GLint of the uniform location] + var sizeAndId = program.uniformSizeAndIdsByName[uniformBaseName]; + + // If an uniform with this name exists, and if its index is within the + // array limits (if it's even an array), query the WebGLlocation, or + // return an existing cached location. + if (sizeAndId && arrayIndex < sizeAndId[0]) { + arrayIndex += sizeAndId[1]; // Add the base location of the uniform to the array index offset. + if ((uniformLocsById[arrayIndex] = uniformLocsById[arrayIndex] || GLctx.getUniformLocation(program, name))) { + return arrayIndex; + } + } + } + else { + // N.b. we are currently unable to distinguish between GL program IDs that + // never existed vs GL program IDs that have been deleted, so report + // GL_INVALID_VALUE in both cases. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + } + return -1; + }; + _emscripten_glGetUniformLocation.sig = 'iip'; + + var webglGetUniformLocation = (location) => { + var p = GLctx.currentProgram; + + if (p) { + var webglLoc = p.uniformLocsById[location]; + // p.uniformLocsById[location] stores either an integer, or a + // WebGLUniformLocation. + // If an integer, we have not yet bound the location, so do it now. The + // integer value specifies the array index we should bind to. + if (typeof webglLoc == 'number') { + p.uniformLocsById[location] = webglLoc = GLctx.getUniformLocation(p, p.uniformArrayNamesById[location] + (webglLoc > 0 ? `[${webglLoc}]` : '')); + } + // Else an already cached WebGLUniformLocation, return it. + return webglLoc; + } else { + GL.recordError(0x502/*GL_INVALID_OPERATION*/); + } + }; + + + /** @suppress{checkTypes} */ + var emscriptenWebGLGetUniform = (program, location, params, type) => { + if (!params) { + // GLES2 specification does not specify how to behave if params is a null + // pointer. Since calling this function does not make sense if params == + // null, issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + program = GL.programs[program]; + webglPrepareUniformLocationsBeforeFirstUse(program); + var data = GLctx.getUniform(program, webglGetUniformLocation(location)); + if (typeof data == 'number' || typeof data == 'boolean') { + switch (type) { + case 0: HEAP32[((params)>>2)] = data; break; + case 2: HEAPF32[((params)>>2)] = data; break; + } + } else { + for (var i = 0; i < data.length; i++) { + switch (type) { + case 0: HEAP32[(((params)+(i*4))>>2)] = data[i]; break; + case 2: HEAPF32[(((params)+(i*4))>>2)] = data[i]; break; + } + } + } + }; + + var _emscripten_glGetUniformfv = (program, location, params) => { + emscriptenWebGLGetUniform(program, location, params, 2); + }; + _emscripten_glGetUniformfv.sig = 'viip'; + + + var _emscripten_glGetUniformiv = (program, location, params) => { + emscriptenWebGLGetUniform(program, location, params, 0); + }; + _emscripten_glGetUniformiv.sig = 'viip'; + + var _emscripten_glGetVertexAttribPointerv = (index, pname, pointer) => { + if (!pointer) { + // GLES2 specification does not specify how to behave if pointer is a null + // pointer. Since calling this function does not make sense if pointer == + // null, issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + HEAP32[((pointer)>>2)] = GLctx.getVertexAttribOffset(index, pname); + }; + _emscripten_glGetVertexAttribPointerv.sig = 'viip'; + + /** @suppress{checkTypes} */ + var emscriptenWebGLGetVertexAttrib = (index, pname, params, type) => { + if (!params) { + // GLES2 specification does not specify how to behave if params is a null + // pointer. Since calling this function does not make sense if params == + // null, issue a GL error to notify user about it. + GL.recordError(0x501 /* GL_INVALID_VALUE */); + return; + } + var data = GLctx.getVertexAttrib(index, pname); + if (pname == 0x889F/*VERTEX_ATTRIB_ARRAY_BUFFER_BINDING*/) { + HEAP32[((params)>>2)] = data && data["name"]; + } else if (typeof data == 'number' || typeof data == 'boolean') { + switch (type) { + case 0: HEAP32[((params)>>2)] = data; break; + case 2: HEAPF32[((params)>>2)] = data; break; + case 5: HEAP32[((params)>>2)] = Math.fround(data); break; + } + } else { + for (var i = 0; i < data.length; i++) { + switch (type) { + case 0: HEAP32[(((params)+(i*4))>>2)] = data[i]; break; + case 2: HEAPF32[(((params)+(i*4))>>2)] = data[i]; break; + case 5: HEAP32[(((params)+(i*4))>>2)] = Math.fround(data[i]); break; + } + } + } + }; + + var _emscripten_glGetVertexAttribfv = (index, pname, params) => { + // N.B. This function may only be called if the vertex attribute was + // specified using the function glVertexAttrib*f(), otherwise the results + // are undefined. (GLES3 spec 6.1.12) + emscriptenWebGLGetVertexAttrib(index, pname, params, 2); + }; + _emscripten_glGetVertexAttribfv.sig = 'viip'; + + + var _emscripten_glGetVertexAttribiv = (index, pname, params) => { + // N.B. This function may only be called if the vertex attribute was + // specified using the function glVertexAttrib*f(), otherwise the results + // are undefined. (GLES3 spec 6.1.12) + emscriptenWebGLGetVertexAttrib(index, pname, params, 5); + }; + _emscripten_glGetVertexAttribiv.sig = 'viip'; + + var _emscripten_glHint = (x0, x1) => GLctx.hint(x0, x1); + _emscripten_glHint.sig = 'vii'; + + var _emscripten_glIsBuffer = (buffer) => { + var b = GL.buffers[buffer]; + if (!b) return 0; + return GLctx.isBuffer(b); + }; + _emscripten_glIsBuffer.sig = 'ii'; + + var _emscripten_glIsEnabled = (x0) => GLctx.isEnabled(x0); + _emscripten_glIsEnabled.sig = 'ii'; + + var _emscripten_glIsFramebuffer = (framebuffer) => { + var fb = GL.framebuffers[framebuffer]; + if (!fb) return 0; + return GLctx.isFramebuffer(fb); + }; + _emscripten_glIsFramebuffer.sig = 'ii'; + + var _emscripten_glIsProgram = (program) => { + program = GL.programs[program]; + if (!program) return 0; + return GLctx.isProgram(program); + }; + _emscripten_glIsProgram.sig = 'ii'; + + var _emscripten_glIsQueryEXT = (id) => { + var query = GL.queries[id]; + if (!query) return 0; + return GLctx.disjointTimerQueryExt['isQueryEXT'](query); + }; + _emscripten_glIsQueryEXT.sig = 'ii'; + + var _emscripten_glIsRenderbuffer = (renderbuffer) => { + var rb = GL.renderbuffers[renderbuffer]; + if (!rb) return 0; + return GLctx.isRenderbuffer(rb); + }; + _emscripten_glIsRenderbuffer.sig = 'ii'; + + var _emscripten_glIsShader = (shader) => { + var s = GL.shaders[shader]; + if (!s) return 0; + return GLctx.isShader(s); + }; + _emscripten_glIsShader.sig = 'ii'; + + var _emscripten_glIsTexture = (id) => { + var texture = GL.textures[id]; + if (!texture) return 0; + return GLctx.isTexture(texture); + }; + _emscripten_glIsTexture.sig = 'ii'; + + + var _emscripten_glIsVertexArray = (array) => { + + var vao = GL.vaos[array]; + if (!vao) return 0; + return GLctx.isVertexArray(vao); + }; + _emscripten_glIsVertexArray.sig = 'ii'; + var _emscripten_glIsVertexArrayOES = _emscripten_glIsVertexArray; + _emscripten_glIsVertexArrayOES.sig = 'ii'; + + var _emscripten_glLineWidth = (x0) => GLctx.lineWidth(x0); + _emscripten_glLineWidth.sig = 'vf'; + + var _emscripten_glLinkProgram = (program) => { + program = GL.programs[program]; + GLctx.linkProgram(program); + // Invalidate earlier computed uniform->ID mappings, those have now become stale + program.uniformLocsById = 0; // Mark as null-like so that glGetUniformLocation() knows to populate this again. + program.uniformSizeAndIdsByName = {}; + + }; + _emscripten_glLinkProgram.sig = 'vi'; + + var _emscripten_glPixelStorei = (pname, param) => { + if (pname == 3317) { + GL.unpackAlignment = param; + } else if (pname == 3314) { + GL.unpackRowLength = param; + } + GLctx.pixelStorei(pname, param); + }; + _emscripten_glPixelStorei.sig = 'vii'; + + var _emscripten_glPolygonModeWEBGL = (face, mode) => { + GLctx.webglPolygonMode['polygonModeWEBGL'](face, mode); + }; + _emscripten_glPolygonModeWEBGL.sig = 'vii'; + + var _emscripten_glPolygonOffset = (x0, x1) => GLctx.polygonOffset(x0, x1); + _emscripten_glPolygonOffset.sig = 'vff'; + + var _emscripten_glPolygonOffsetClampEXT = (factor, units, clamp) => { + GLctx.extPolygonOffsetClamp['polygonOffsetClampEXT'](factor, units, clamp); + }; + _emscripten_glPolygonOffsetClampEXT.sig = 'vfff'; + + var _emscripten_glQueryCounterEXT = (id, target) => { + GLctx.disjointTimerQueryExt['queryCounterEXT'](GL.queries[id], target); + }; + _emscripten_glQueryCounterEXT.sig = 'vii'; + + var computeUnpackAlignedImageSize = (width, height, sizePerPixel) => { + function roundedToNextMultipleOf(x, y) { + return (x + y - 1) & -y; + } + var plainRowSize = (GL.unpackRowLength || width) * sizePerPixel; + var alignedRowSize = roundedToNextMultipleOf(plainRowSize, GL.unpackAlignment); + return height * alignedRowSize; + }; + + var colorChannelsInGlTextureFormat = (format) => { + // Micro-optimizations for size: map format to size by subtracting smallest + // enum value (0x1902) from all values first. Also omit the most common + // size value (1) from the list, which is assumed by formats not on the + // list. + var colorChannels = { + // 0x1902 /* GL_DEPTH_COMPONENT */ - 0x1902: 1, + // 0x1906 /* GL_ALPHA */ - 0x1902: 1, + 5: 3, + 6: 4, + // 0x1909 /* GL_LUMINANCE */ - 0x1902: 1, + 8: 2, + 29502: 3, + 29504: 4, + }; + return colorChannels[format - 0x1902]||1; + }; + + var heapObjectForWebGLType = (type) => { + // Micro-optimization for size: Subtract lowest GL enum number (0x1400/* GL_BYTE */) from type to compare + // smaller values for the heap, for shorter generated code size. + // Also the type HEAPU16 is not tested for explicitly, but any unrecognized type will return out HEAPU16. + // (since most types are HEAPU16) + type -= 0x1400; + + if (type == 1) return HEAPU8; + + if (type == 4) return HEAP32; + + if (type == 6) return HEAPF32; + + if (type == 5 + || type == 28922 + ) + return HEAPU32; + + return HEAPU16; + }; + + var toTypedArrayIndex = (pointer, heap) => + pointer >>> (31 - Math.clz32(heap.BYTES_PER_ELEMENT)); + + var emscriptenWebGLGetTexPixelData = (type, format, width, height, pixels, internalFormat) => { + var heap = heapObjectForWebGLType(type); + var sizePerPixel = colorChannelsInGlTextureFormat(format) * heap.BYTES_PER_ELEMENT; + var bytes = computeUnpackAlignedImageSize(width, height, sizePerPixel); + return heap.subarray(toTypedArrayIndex(pixels, heap), toTypedArrayIndex(pixels + bytes, heap)); + }; + + var _emscripten_glReadPixels = (x, y, width, height, format, type, pixels) => { + var pixelData = emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, format); + if (!pixelData) { + GL.recordError(0x500/*GL_INVALID_ENUM*/); + return; + } + GLctx.readPixels(x, y, width, height, format, type, pixelData); + }; + _emscripten_glReadPixels.sig = 'viiiiiip'; + + var _emscripten_glReleaseShaderCompiler = () => { + // NOP (as allowed by GLES 2.0 spec) + }; + _emscripten_glReleaseShaderCompiler.sig = 'v'; + + var _emscripten_glRenderbufferStorage = (x0, x1, x2, x3) => GLctx.renderbufferStorage(x0, x1, x2, x3); + _emscripten_glRenderbufferStorage.sig = 'viiii'; + + var _emscripten_glSampleCoverage = (value, invert) => { + GLctx.sampleCoverage(value, !!invert); + }; + _emscripten_glSampleCoverage.sig = 'vfi'; + + var _emscripten_glScissor = (x0, x1, x2, x3) => GLctx.scissor(x0, x1, x2, x3); + _emscripten_glScissor.sig = 'viiii'; + + var _emscripten_glShaderBinary = (count, shaders, binaryformat, binary, length) => { + GL.recordError(0x500/*GL_INVALID_ENUM*/); + }; + _emscripten_glShaderBinary.sig = 'vipipi'; + + var _emscripten_glShaderSource = (shader, count, string, length) => { + var source = GL.getSource(shader, count, string, length); + + GLctx.shaderSource(GL.shaders[shader], source); + }; + _emscripten_glShaderSource.sig = 'viipp'; + + var _emscripten_glStencilFunc = (x0, x1, x2) => GLctx.stencilFunc(x0, x1, x2); + _emscripten_glStencilFunc.sig = 'viii'; + + var _emscripten_glStencilFuncSeparate = (x0, x1, x2, x3) => GLctx.stencilFuncSeparate(x0, x1, x2, x3); + _emscripten_glStencilFuncSeparate.sig = 'viiii'; + + var _emscripten_glStencilMask = (x0) => GLctx.stencilMask(x0); + _emscripten_glStencilMask.sig = 'vi'; + + var _emscripten_glStencilMaskSeparate = (x0, x1) => GLctx.stencilMaskSeparate(x0, x1); + _emscripten_glStencilMaskSeparate.sig = 'vii'; + + var _emscripten_glStencilOp = (x0, x1, x2) => GLctx.stencilOp(x0, x1, x2); + _emscripten_glStencilOp.sig = 'viii'; + + var _emscripten_glStencilOpSeparate = (x0, x1, x2, x3) => GLctx.stencilOpSeparate(x0, x1, x2, x3); + _emscripten_glStencilOpSeparate.sig = 'viiii'; + + + var _emscripten_glTexImage2D = (target, level, internalFormat, width, height, border, format, type, pixels) => { + var pixelData = pixels ? emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, internalFormat) : null; + GLctx.texImage2D(target, level, internalFormat, width, height, border, format, type, pixelData); + }; + _emscripten_glTexImage2D.sig = 'viiiiiiiip'; + + var _emscripten_glTexParameterf = (x0, x1, x2) => GLctx.texParameterf(x0, x1, x2); + _emscripten_glTexParameterf.sig = 'viif'; + + var _emscripten_glTexParameterfv = (target, pname, params) => { + var param = HEAPF32[((params)>>2)]; + GLctx.texParameterf(target, pname, param); + }; + _emscripten_glTexParameterfv.sig = 'viip'; + + var _emscripten_glTexParameteri = (x0, x1, x2) => GLctx.texParameteri(x0, x1, x2); + _emscripten_glTexParameteri.sig = 'viii'; + + var _emscripten_glTexParameteriv = (target, pname, params) => { + var param = HEAP32[((params)>>2)]; + GLctx.texParameteri(target, pname, param); + }; + _emscripten_glTexParameteriv.sig = 'viip'; + + + var _emscripten_glTexSubImage2D = (target, level, xoffset, yoffset, width, height, format, type, pixels) => { + var pixelData = pixels ? emscriptenWebGLGetTexPixelData(type, format, width, height, pixels, 0) : null; + GLctx.texSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixelData); + }; + _emscripten_glTexSubImage2D.sig = 'viiiiiiiip'; + + + var _emscripten_glUniform1f = (location, v0) => { + GLctx.uniform1f(webglGetUniformLocation(location), v0); + }; + _emscripten_glUniform1f.sig = 'vif'; + + + var miniTempWebGLFloatBuffers = []; + + var _emscripten_glUniform1fv = (location, count, value) => { + + if (count <= 288) { + // avoid allocation when uploading few enough uniforms + var view = miniTempWebGLFloatBuffers[count]; + for (var i = 0; i < count; ++i) { + view[i] = HEAPF32[(((value)+(4*i))>>2)]; + } + } else + { + var view = HEAPF32.subarray((((value)>>2)), ((value+count*4)>>2)); + } + GLctx.uniform1fv(webglGetUniformLocation(location), view); + }; + _emscripten_glUniform1fv.sig = 'viip'; + + + var _emscripten_glUniform1i = (location, v0) => { + GLctx.uniform1i(webglGetUniformLocation(location), v0); + }; + _emscripten_glUniform1i.sig = 'vii'; + + + var miniTempWebGLIntBuffers = []; + + var _emscripten_glUniform1iv = (location, count, value) => { + + if (count <= 288) { + // avoid allocation when uploading few enough uniforms + var view = miniTempWebGLIntBuffers[count]; + for (var i = 0; i < count; ++i) { + view[i] = HEAP32[(((value)+(4*i))>>2)]; + } + } else + { + var view = HEAP32.subarray((((value)>>2)), ((value+count*4)>>2)); + } + GLctx.uniform1iv(webglGetUniformLocation(location), view); + }; + _emscripten_glUniform1iv.sig = 'viip'; + + + var _emscripten_glUniform2f = (location, v0, v1) => { + GLctx.uniform2f(webglGetUniformLocation(location), v0, v1); + }; + _emscripten_glUniform2f.sig = 'viff'; + + + + var _emscripten_glUniform2fv = (location, count, value) => { + + if (count <= 144) { + // avoid allocation when uploading few enough uniforms + count *= 2; + var view = miniTempWebGLFloatBuffers[count]; + for (var i = 0; i < count; i += 2) { + view[i] = HEAPF32[(((value)+(4*i))>>2)]; + view[i+1] = HEAPF32[(((value)+(4*i+4))>>2)]; + } + } else + { + var view = HEAPF32.subarray((((value)>>2)), ((value+count*8)>>2)); + } + GLctx.uniform2fv(webglGetUniformLocation(location), view); + }; + _emscripten_glUniform2fv.sig = 'viip'; + + + var _emscripten_glUniform2i = (location, v0, v1) => { + GLctx.uniform2i(webglGetUniformLocation(location), v0, v1); + }; + _emscripten_glUniform2i.sig = 'viii'; + + + + var _emscripten_glUniform2iv = (location, count, value) => { + + if (count <= 144) { + // avoid allocation when uploading few enough uniforms + count *= 2; + var view = miniTempWebGLIntBuffers[count]; + for (var i = 0; i < count; i += 2) { + view[i] = HEAP32[(((value)+(4*i))>>2)]; + view[i+1] = HEAP32[(((value)+(4*i+4))>>2)]; + } + } else + { + var view = HEAP32.subarray((((value)>>2)), ((value+count*8)>>2)); + } + GLctx.uniform2iv(webglGetUniformLocation(location), view); + }; + _emscripten_glUniform2iv.sig = 'viip'; + + + var _emscripten_glUniform3f = (location, v0, v1, v2) => { + GLctx.uniform3f(webglGetUniformLocation(location), v0, v1, v2); + }; + _emscripten_glUniform3f.sig = 'vifff'; + + + + var _emscripten_glUniform3fv = (location, count, value) => { + + if (count <= 96) { + // avoid allocation when uploading few enough uniforms + count *= 3; + var view = miniTempWebGLFloatBuffers[count]; + for (var i = 0; i < count; i += 3) { + view[i] = HEAPF32[(((value)+(4*i))>>2)]; + view[i+1] = HEAPF32[(((value)+(4*i+4))>>2)]; + view[i+2] = HEAPF32[(((value)+(4*i+8))>>2)]; + } + } else + { + var view = HEAPF32.subarray((((value)>>2)), ((value+count*12)>>2)); + } + GLctx.uniform3fv(webglGetUniformLocation(location), view); + }; + _emscripten_glUniform3fv.sig = 'viip'; + + + var _emscripten_glUniform3i = (location, v0, v1, v2) => { + GLctx.uniform3i(webglGetUniformLocation(location), v0, v1, v2); + }; + _emscripten_glUniform3i.sig = 'viiii'; + + + + var _emscripten_glUniform3iv = (location, count, value) => { + + if (count <= 96) { + // avoid allocation when uploading few enough uniforms + count *= 3; + var view = miniTempWebGLIntBuffers[count]; + for (var i = 0; i < count; i += 3) { + view[i] = HEAP32[(((value)+(4*i))>>2)]; + view[i+1] = HEAP32[(((value)+(4*i+4))>>2)]; + view[i+2] = HEAP32[(((value)+(4*i+8))>>2)]; + } + } else + { + var view = HEAP32.subarray((((value)>>2)), ((value+count*12)>>2)); + } + GLctx.uniform3iv(webglGetUniformLocation(location), view); + }; + _emscripten_glUniform3iv.sig = 'viip'; + + + var _emscripten_glUniform4f = (location, v0, v1, v2, v3) => { + GLctx.uniform4f(webglGetUniformLocation(location), v0, v1, v2, v3); + }; + _emscripten_glUniform4f.sig = 'viffff'; + + + + var _emscripten_glUniform4fv = (location, count, value) => { + + if (count <= 72) { + // avoid allocation when uploading few enough uniforms + var view = miniTempWebGLFloatBuffers[4*count]; + // hoist the heap out of the loop for size and for pthreads+growth. + var heap = HEAPF32; + value = ((value)>>2); + count *= 4; + for (var i = 0; i < count; i += 4) { + var dst = value + i; + view[i] = heap[dst]; + view[i + 1] = heap[dst + 1]; + view[i + 2] = heap[dst + 2]; + view[i + 3] = heap[dst + 3]; + } + } else + { + var view = HEAPF32.subarray((((value)>>2)), ((value+count*16)>>2)); + } + GLctx.uniform4fv(webglGetUniformLocation(location), view); + }; + _emscripten_glUniform4fv.sig = 'viip'; + + + var _emscripten_glUniform4i = (location, v0, v1, v2, v3) => { + GLctx.uniform4i(webglGetUniformLocation(location), v0, v1, v2, v3); + }; + _emscripten_glUniform4i.sig = 'viiiii'; + + + + var _emscripten_glUniform4iv = (location, count, value) => { + + if (count <= 72) { + // avoid allocation when uploading few enough uniforms + count *= 4; + var view = miniTempWebGLIntBuffers[count]; + for (var i = 0; i < count; i += 4) { + view[i] = HEAP32[(((value)+(4*i))>>2)]; + view[i+1] = HEAP32[(((value)+(4*i+4))>>2)]; + view[i+2] = HEAP32[(((value)+(4*i+8))>>2)]; + view[i+3] = HEAP32[(((value)+(4*i+12))>>2)]; + } + } else + { + var view = HEAP32.subarray((((value)>>2)), ((value+count*16)>>2)); + } + GLctx.uniform4iv(webglGetUniformLocation(location), view); + }; + _emscripten_glUniform4iv.sig = 'viip'; + + + + var _emscripten_glUniformMatrix2fv = (location, count, transpose, value) => { + + if (count <= 72) { + // avoid allocation when uploading few enough uniforms + count *= 4; + var view = miniTempWebGLFloatBuffers[count]; + for (var i = 0; i < count; i += 4) { + view[i] = HEAPF32[(((value)+(4*i))>>2)]; + view[i+1] = HEAPF32[(((value)+(4*i+4))>>2)]; + view[i+2] = HEAPF32[(((value)+(4*i+8))>>2)]; + view[i+3] = HEAPF32[(((value)+(4*i+12))>>2)]; + } + } else + { + var view = HEAPF32.subarray((((value)>>2)), ((value+count*16)>>2)); + } + GLctx.uniformMatrix2fv(webglGetUniformLocation(location), !!transpose, view); + }; + _emscripten_glUniformMatrix2fv.sig = 'viiip'; + + + + var _emscripten_glUniformMatrix3fv = (location, count, transpose, value) => { + + if (count <= 32) { + // avoid allocation when uploading few enough uniforms + count *= 9; + var view = miniTempWebGLFloatBuffers[count]; + for (var i = 0; i < count; i += 9) { + view[i] = HEAPF32[(((value)+(4*i))>>2)]; + view[i+1] = HEAPF32[(((value)+(4*i+4))>>2)]; + view[i+2] = HEAPF32[(((value)+(4*i+8))>>2)]; + view[i+3] = HEAPF32[(((value)+(4*i+12))>>2)]; + view[i+4] = HEAPF32[(((value)+(4*i+16))>>2)]; + view[i+5] = HEAPF32[(((value)+(4*i+20))>>2)]; + view[i+6] = HEAPF32[(((value)+(4*i+24))>>2)]; + view[i+7] = HEAPF32[(((value)+(4*i+28))>>2)]; + view[i+8] = HEAPF32[(((value)+(4*i+32))>>2)]; + } + } else + { + var view = HEAPF32.subarray((((value)>>2)), ((value+count*36)>>2)); + } + GLctx.uniformMatrix3fv(webglGetUniformLocation(location), !!transpose, view); + }; + _emscripten_glUniformMatrix3fv.sig = 'viiip'; + + + + var _emscripten_glUniformMatrix4fv = (location, count, transpose, value) => { + + if (count <= 18) { + // avoid allocation when uploading few enough uniforms + var view = miniTempWebGLFloatBuffers[16*count]; + // hoist the heap out of the loop for size and for pthreads+growth. + var heap = HEAPF32; + value = ((value)>>2); + count *= 16; + for (var i = 0; i < count; i += 16) { + var dst = value + i; + view[i] = heap[dst]; + view[i + 1] = heap[dst + 1]; + view[i + 2] = heap[dst + 2]; + view[i + 3] = heap[dst + 3]; + view[i + 4] = heap[dst + 4]; + view[i + 5] = heap[dst + 5]; + view[i + 6] = heap[dst + 6]; + view[i + 7] = heap[dst + 7]; + view[i + 8] = heap[dst + 8]; + view[i + 9] = heap[dst + 9]; + view[i + 10] = heap[dst + 10]; + view[i + 11] = heap[dst + 11]; + view[i + 12] = heap[dst + 12]; + view[i + 13] = heap[dst + 13]; + view[i + 14] = heap[dst + 14]; + view[i + 15] = heap[dst + 15]; + } + } else + { + var view = HEAPF32.subarray((((value)>>2)), ((value+count*64)>>2)); + } + GLctx.uniformMatrix4fv(webglGetUniformLocation(location), !!transpose, view); + }; + _emscripten_glUniformMatrix4fv.sig = 'viiip'; + + var _emscripten_glUseProgram = (program) => { + program = GL.programs[program]; + GLctx.useProgram(program); + // Record the currently active program so that we can access the uniform + // mapping table of that program. + GLctx.currentProgram = program; + }; + _emscripten_glUseProgram.sig = 'vi'; + + var _emscripten_glValidateProgram = (program) => { + GLctx.validateProgram(GL.programs[program]); + }; + _emscripten_glValidateProgram.sig = 'vi'; + + var _emscripten_glVertexAttrib1f = (x0, x1) => GLctx.vertexAttrib1f(x0, x1); + _emscripten_glVertexAttrib1f.sig = 'vif'; + + var _emscripten_glVertexAttrib1fv = (index, v) => { + + GLctx.vertexAttrib1f(index, HEAPF32[v>>2]); + }; + _emscripten_glVertexAttrib1fv.sig = 'vip'; + + var _emscripten_glVertexAttrib2f = (x0, x1, x2) => GLctx.vertexAttrib2f(x0, x1, x2); + _emscripten_glVertexAttrib2f.sig = 'viff'; + + var _emscripten_glVertexAttrib2fv = (index, v) => { + + GLctx.vertexAttrib2f(index, HEAPF32[v>>2], HEAPF32[v+4>>2]); + }; + _emscripten_glVertexAttrib2fv.sig = 'vip'; + + var _emscripten_glVertexAttrib3f = (x0, x1, x2, x3) => GLctx.vertexAttrib3f(x0, x1, x2, x3); + _emscripten_glVertexAttrib3f.sig = 'vifff'; + + var _emscripten_glVertexAttrib3fv = (index, v) => { + + GLctx.vertexAttrib3f(index, HEAPF32[v>>2], HEAPF32[v+4>>2], HEAPF32[v+8>>2]); + }; + _emscripten_glVertexAttrib3fv.sig = 'vip'; + + var _emscripten_glVertexAttrib4f = (x0, x1, x2, x3, x4) => GLctx.vertexAttrib4f(x0, x1, x2, x3, x4); + _emscripten_glVertexAttrib4f.sig = 'viffff'; + + var _emscripten_glVertexAttrib4fv = (index, v) => { + + GLctx.vertexAttrib4f(index, HEAPF32[v>>2], HEAPF32[v+4>>2], HEAPF32[v+8>>2], HEAPF32[v+12>>2]); + }; + _emscripten_glVertexAttrib4fv.sig = 'vip'; + + + var _emscripten_glVertexAttribDivisor = (index, divisor) => { + GLctx.vertexAttribDivisor(index, divisor); + }; + _emscripten_glVertexAttribDivisor.sig = 'vii'; + var _emscripten_glVertexAttribDivisorANGLE = _emscripten_glVertexAttribDivisor; + + var _emscripten_glVertexAttribPointer = (index, size, type, normalized, stride, ptr) => { + GLctx.vertexAttribPointer(index, size, type, !!normalized, stride, ptr); + }; + _emscripten_glVertexAttribPointer.sig = 'viiiiip'; + + var _emscripten_glViewport = (x0, x1, x2, x3) => GLctx.viewport(x0, x1, x2, x3); + _emscripten_glViewport.sig = 'viiii'; + + var _emscripten_out = (str) => out(UTF8ToString(str)); + _emscripten_out.sig = 'vp'; + + class HandleAllocator { + allocated = [undefined]; + freelist = []; + get(id) { + return this.allocated[id]; + } + has(id) { + return this.allocated[id] !== undefined; + } + allocate(handle) { + var id = this.freelist.pop() || this.allocated.length; + this.allocated[id] = handle; + return id; + } + free(id) { + // Set the slot to `undefined` rather than using `delete` here since + // apparently arrays with holes in them can be less efficient. + this.allocated[id] = undefined; + this.freelist.push(id); + } + } + var promiseMap = new HandleAllocator();; + var makePromise = () => { + var promiseInfo = {}; + promiseInfo.promise = new Promise((resolve, reject) => { + promiseInfo.reject = reject; + promiseInfo.resolve = resolve; + }); + promiseInfo.id = promiseMap.allocate(promiseInfo); + return promiseInfo; + }; + var _emscripten_promise_create = () => makePromise().id; + _emscripten_promise_create.sig = 'p'; + + var _emscripten_promise_destroy = (id) => { + promiseMap.free(id); + }; + _emscripten_promise_destroy.sig = 'vp'; + + + var getPromise = (id) => promiseMap.get(id).promise; + + var _emscripten_promise_resolve = (id, result, value) => { + var info = promiseMap.get(id); + switch (result) { + case 0: + info.resolve(value); + return; + case 1: + info.resolve(getPromise(value)); + return; + case 2: + info.resolve(getPromise(value)); + _emscripten_promise_destroy(value); + return; + case 3: + info.reject(value); + return; + } + }; + _emscripten_promise_resolve.sig = 'vpip'; + + + + var growMemory = (size) => { + var oldHeapSize = wasmMemory.buffer.byteLength; + var pages = ((size - oldHeapSize + 65535) / 65536) | 0; + try { + // round size grow request up to wasm page size (fixed 64KB per spec) + wasmMemory.grow(pages); // .grow() takes a delta compared to the previous size + updateMemoryViews(); + return 1 /*success*/; + } catch(e) { + } + // implicit 0 return to save code size (caller will cast "undefined" into 0 + // anyhow) + }; + var _emscripten_resize_heap = (requestedSize) => { + var oldSize = HEAPU8.length; + // With CAN_ADDRESS_2GB or MEMORY64, pointers are already unsigned. + requestedSize >>>= 0; + // With multithreaded builds, races can happen (another thread might increase the size + // in between), so return a failure, and let the caller retry. + + // Memory resize rules: + // 1. Always increase heap size to at least the requested size, rounded up + // to next page multiple. + // 2a. If MEMORY_GROWTH_LINEAR_STEP == -1, excessively resize the heap + // geometrically: increase the heap size according to + // MEMORY_GROWTH_GEOMETRIC_STEP factor (default +20%), At most + // overreserve by MEMORY_GROWTH_GEOMETRIC_CAP bytes (default 96MB). + // 2b. If MEMORY_GROWTH_LINEAR_STEP != -1, excessively resize the heap + // linearly: increase the heap size by at least + // MEMORY_GROWTH_LINEAR_STEP bytes. + // 3. Max size for the heap is capped at 2048MB-WASM_PAGE_SIZE, or by + // MAXIMUM_MEMORY, or by ASAN limit, depending on which is smallest + // 4. If we were unable to allocate as much memory, it may be due to + // over-eager decision to excessively reserve due to (3) above. + // Hence if an allocation fails, cut down on the amount of excess + // growth, in an attempt to succeed to perform a smaller allocation. + + // A limit is set for how much we can grow. We should not exceed that + // (the wasm binary specifies it, so if we tried, we'd fail anyhow). + var maxHeapSize = getHeapMax(); + if (requestedSize > maxHeapSize) { + return false; + } + + // Loop through potential heap size increases. If we attempt a too eager + // reservation that fails, cut down on the attempted size and reserve a + // smaller bump instead. (max 3 times, chosen somewhat arbitrarily) + for (var cutDown = 1; cutDown <= 4; cutDown *= 2) { + var overGrownHeapSize = oldSize * (1 + 0.2 / cutDown); // ensure geometric growth + // but limit overreserving (default to capping at +96MB overgrowth at most) + overGrownHeapSize = Math.min(overGrownHeapSize, requestedSize + 100663296 ); + + var newSize = Math.min(maxHeapSize, alignMemory(Math.max(requestedSize, overGrownHeapSize), 65536)); + + var replacement = growMemory(newSize); + if (replacement) { + + return true; + } + } + return false; + }; + _emscripten_resize_heap.sig = 'ip'; + + var maybeCStringToJsString = (cString) => { + // "cString > 2" checks if the input is a number, and isn't of the special + // values we accept here, EMSCRIPTEN_EVENT_TARGET_* (which map to 0, 1, 2). + // In other words, if cString > 2 then it's a pointer to a valid place in + // memory, and points to a C string. + return cString > 2 ? UTF8ToString(cString) : cString; + }; + + /** @type {Object} */ + var specialHTMLTargets = [0, typeof document != 'undefined' ? document : 0, typeof window != 'undefined' ? window : 0]; + var findEventTarget = (target) => { + target = maybeCStringToJsString(target); + var domElement = specialHTMLTargets[target] || (typeof document != 'undefined' ? document.querySelector(target) : null); + return domElement; + }; + var findCanvasEventTarget = findEventTarget; + var _emscripten_set_canvas_element_size = (target, width, height) => { + var canvas = findCanvasEventTarget(target); + if (!canvas) return -4; + canvas.width = width; + canvas.height = height; + return 0; + }; + _emscripten_set_canvas_element_size.sig = 'ipii'; + + + + /** @param {number=} timeout */ + var safeSetTimeout = (func, timeout) => { + runtimeKeepalivePush(); + return setTimeout(() => { + runtimeKeepalivePop(); + callUserCallback(func); + }, timeout); + }; + var _emscripten_sleep = (ms) => Asyncify.handleSleep((wakeUp) => safeSetTimeout(wakeUp, ms)); + _emscripten_sleep.sig = 'vi'; + _emscripten_sleep.isAsync = true; + + + + var _emscripten_wget_data = (url, pbuffer, pnum, perror) => Asyncify.handleAsync(async () => { + /* no need for run dependency, this is async but will not do any prepare etc. step */ + try { + const byteArray = await asyncLoad(UTF8ToString(url)); + // can only allocate the buffer after the wakeUp, not during an asyncing + var buffer = _malloc(byteArray.length); // must be freed by caller! + HEAPU8.set(byteArray, buffer); + HEAPU32[((pbuffer)>>2)] = buffer; + HEAP32[((pnum)>>2)] = byteArray.length; + HEAP32[((perror)>>2)] = 0; + } catch (err) { + HEAP32[((perror)>>2)] = 1; + } + }); + _emscripten_wget_data.sig = 'vpppp'; + _emscripten_wget_data.isAsync = true; + + var ENV = PHPLoader.ENV || { + }; + + var getEnvStrings = () => { + if (!getEnvStrings.strings) { + // Default values. + // Browser language detection #8751 + var lang = ((typeof navigator == 'object' && navigator.language) || 'C').replace('-', '_') + '.UTF-8'; + var env = { + 'USER': 'web_user', + 'LOGNAME': 'web_user', + 'PATH': '/', + 'PWD': '/', + 'HOME': '/home/web_user', + 'LANG': lang, + '_': getExecutableName() + }; + // Apply the user-provided values, if any. + for (var x in ENV) { + // x is a key in ENV; if ENV[x] is undefined, that means it was + // explicitly set to be so. We allow user code to do that to + // force variables with default values to remain unset. + if (ENV[x] === undefined) delete env[x]; + else env[x] = ENV[x]; + } + var strings = []; + for (var x in env) { + strings.push(`${x}=${env[x]}`); + } + getEnvStrings.strings = strings; + } + return getEnvStrings.strings; + }; + + var _environ_get = (__environ, environ_buf) => { + var bufSize = 0; + var envp = 0; + for (var string of getEnvStrings()) { + var ptr = environ_buf + bufSize; + HEAPU32[(((__environ)+(envp))>>2)] = ptr; + bufSize += stringToUTF8(string, ptr, Infinity) + 1; + envp += 4; + } + return 0; + }; + _environ_get.sig = 'ipp'; + + + var _environ_sizes_get = (penviron_count, penviron_buf_size) => { + var strings = getEnvStrings(); + HEAPU32[((penviron_count)>>2)] = strings.length; + var bufSize = 0; + for (var string of strings) { + bufSize += lengthBytesUTF8(string) + 1; + } + HEAPU32[((penviron_buf_size)>>2)] = bufSize; + return 0; + }; + _environ_sizes_get.sig = 'ipp'; + + + + function _fd_fdstat_get(fd, pbuf) { + try { + + var rightsBase = 0; + var rightsInheriting = 0; + var flags = 0; + { + var stream = SYSCALLS.getStreamFromFD(fd); + // All character devices are terminals (other things a Linux system would + // assume is a character device, like the mouse, we have special APIs for). + var type = stream.tty ? 2 : + FS.isDir(stream.mode) ? 3 : + FS.isLink(stream.mode) ? 7 : + 4; + } + HEAP8[pbuf] = type; + HEAP16[(((pbuf)+(2))>>1)] = flags; + HEAP64[(((pbuf)+(8))>>3)] = BigInt(rightsBase); + HEAP64[(((pbuf)+(16))>>3)] = BigInt(rightsInheriting); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + } + _fd_fdstat_get.sig = 'iip'; + + /** @param {number=} offset */ + var doReadv = (stream, iov, iovcnt, offset) => { + var ret = 0; + for (var i = 0; i < iovcnt; i++) { + var ptr = HEAPU32[((iov)>>2)]; + var len = HEAPU32[(((iov)+(4))>>2)]; + iov += 8; + var curr = FS.read(stream, HEAP8, ptr, len, offset); + if (curr < 0) return -1; + ret += curr; + if (curr < len) break; // nothing more to read + if (typeof offset != 'undefined') { + offset += curr; + } + } + return ret; + }; + + + function _fd_pread(fd, iov, iovcnt, offset, pnum) { + offset = bigintToI53Checked(offset); + + + try { + + if (isNaN(offset)) return 61; + var stream = SYSCALLS.getStreamFromFD(fd) + var num = doReadv(stream, iov, iovcnt, offset); + HEAPU32[((pnum)>>2)] = num; + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + ; + } + _fd_pread.sig = 'iippjp'; + + /** @param {number=} offset */ + var doWritev = (stream, iov, iovcnt, offset) => { + var ret = 0; + for (var i = 0; i < iovcnt; i++) { + var ptr = HEAPU32[((iov)>>2)]; + var len = HEAPU32[(((iov)+(4))>>2)]; + iov += 8; + var curr = FS.write(stream, HEAP8, ptr, len, offset); + if (curr < 0) return -1; + ret += curr; + if (curr < len) { + // No more space to write. + break; + } + if (typeof offset != 'undefined') { + offset += curr; + } + } + return ret; + }; + + + function _fd_pwrite(fd, iov, iovcnt, offset, pnum) { + offset = bigintToI53Checked(offset); + + + try { + + if (isNaN(offset)) return 61; + var stream = SYSCALLS.getStreamFromFD(fd) + var num = doWritev(stream, iov, iovcnt, offset); + HEAPU32[((pnum)>>2)] = num; + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + ; + } + _fd_pwrite.sig = 'iippjp'; + + + function _fd_read(fd, iov, iovcnt, pnum) { + try { + + var stream = SYSCALLS.getStreamFromFD(fd); + var num = doReadv(stream, iov, iovcnt); + HEAPU32[((pnum)>>2)] = num; + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + } + _fd_read.sig = 'iippp'; + + + function _fd_seek(fd, offset, whence, newOffset) { + offset = bigintToI53Checked(offset); + + + try { + + if (isNaN(offset)) return 61; + var stream = SYSCALLS.getStreamFromFD(fd); + FS.llseek(stream, offset, whence); + HEAP64[((newOffset)>>3)] = BigInt(stream.position); + if (stream.getdents && offset === 0 && whence === 0) stream.getdents = null; // reset readdir state + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + ; + } + _fd_seek.sig = 'iijip'; + + var _fd_sync = function (fd) { + try { + + var stream = SYSCALLS.getStreamFromFD(fd); + return Asyncify.handleSleep((wakeUp) => { + var mount = stream.node.mount; + if (!mount.type.syncfs) { + // We write directly to the file system, so there's nothing to do here. + wakeUp(0); + return; + } + mount.type.syncfs(mount, false, (err) => { + wakeUp(err ? 29 : 0); + }); + }); + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + }; + _fd_sync.sig = 'ii'; + _fd_sync.isAsync = true; + + + function _fd_write(fd, iov, iovcnt, pnum) { + try { + + var stream = SYSCALLS.getStreamFromFD(fd); + var num = doWritev(stream, iov, iovcnt); + HEAPU32[((pnum)>>2)] = num; + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + } + _fd_write.sig = 'iippp'; + + + + + + + + + + var _getaddrinfo = (node, service, hint, out) => { + // Note getaddrinfo currently only returns a single addrinfo with ai_next defaulting to NULL. When NULL + // hints are specified or ai_family set to AF_UNSPEC or ai_socktype or ai_protocol set to 0 then we + // really should provide a linked list of suitable addrinfo values. + var addrs = []; + var canon = null; + var addr = 0; + var port = 0; + var flags = 0; + var family = 0; + var type = 0; + var proto = 0; + var ai, last; + + function allocaddrinfo(family, type, proto, canon, addr, port) { + var sa, salen, ai; + var errno; + + salen = family === 10 ? + 28 : + 16; + addr = family === 10 ? + inetNtop6(addr) : + inetNtop4(addr); + sa = _malloc(salen); + errno = writeSockaddr(sa, family, addr, port); + + ai = _malloc(32); + HEAP32[(((ai)+(4))>>2)] = family; + HEAP32[(((ai)+(8))>>2)] = type; + HEAP32[(((ai)+(12))>>2)] = proto; + HEAPU32[(((ai)+(24))>>2)] = canon; + HEAPU32[(((ai)+(20))>>2)] = sa; + if (family === 10) { + HEAP32[(((ai)+(16))>>2)] = 28; + } else { + HEAP32[(((ai)+(16))>>2)] = 16; + } + HEAP32[(((ai)+(28))>>2)] = 0; + + return ai; + } + + if (hint) { + flags = HEAP32[((hint)>>2)]; + family = HEAP32[(((hint)+(4))>>2)]; + type = HEAP32[(((hint)+(8))>>2)]; + proto = HEAP32[(((hint)+(12))>>2)]; + } + if (type && !proto) { + proto = type === 2 ? 17 : 6; + } + if (!type && proto) { + type = proto === 17 ? 2 : 1; + } + + // If type or proto are set to zero in hints we should really be returning multiple addrinfo values, but for + // now default to a TCP STREAM socket so we can at least return a sensible addrinfo given NULL hints. + if (proto === 0) { + proto = 6; + } + if (type === 0) { + type = 1; + } + + if (!node && !service) { + return -2; + } + if (flags & ~(1|2|4| + 1024|8|16|32)) { + return -1; + } + if (hint !== 0 && (HEAP32[((hint)>>2)] & 2) && !node) { + return -1; + } + if (flags & 32) { + // TODO + return -2; + } + if (type !== 0 && type !== 1 && type !== 2) { + return -7; + } + if (family !== 0 && family !== 2 && family !== 10) { + return -6; + } + + if (service) { + service = UTF8ToString(service); + port = parseInt(service, 10); + + if (isNaN(port)) { + if (flags & 1024) { + return -2; + } + // TODO support resolving well-known service names from: + // http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.txt + return -8; + } + } + + if (!node) { + if (family === 0) { + family = 2; + } + if ((flags & 1) === 0) { + if (family === 2) { + addr = _htonl(2130706433); + } else { + addr = [0, 0, 0, _htonl(1)]; + } + } + ai = allocaddrinfo(family, type, proto, null, addr, port); + HEAPU32[((out)>>2)] = ai; + return 0; + } + + // + // try as a numeric address + // + node = UTF8ToString(node); + addr = inetPton4(node); + if (addr !== null) { + // incoming node is a valid ipv4 address + if (family === 0 || family === 2) { + family = 2; + } + else if (family === 10 && (flags & 8)) { + addr = [0, 0, _htonl(0xffff), addr]; + family = 10; + } else { + return -2; + } + } else { + addr = inetPton6(node); + if (addr !== null) { + // incoming node is a valid ipv6 address + if (family === 0 || family === 10) { + family = 10; + } else { + return -2; + } + } + } + if (addr != null) { + ai = allocaddrinfo(family, type, proto, node, addr, port); + HEAPU32[((out)>>2)] = ai; + return 0; + } + if (flags & 4) { + return -2; + } + + // + // try as a hostname + // + // resolve the hostname to a temporary fake address + node = DNS.lookup_name(node); + addr = inetPton4(node); + if (family === 0) { + family = 2; + } else if (family === 10) { + addr = [0, 0, _htonl(0xffff), addr]; + } + ai = allocaddrinfo(family, type, proto, null, addr, port); + HEAPU32[((out)>>2)] = ai; + return 0; + }; + _getaddrinfo.sig = 'ipppp'; + + + + var _getnameinfo = (sa, salen, node, nodelen, serv, servlen, flags) => { + var info = readSockaddr(sa, salen); + if (info.errno) { + return -6; + } + var port = info.port; + var addr = info.addr; + + var overflowed = false; + + if (node && nodelen) { + var lookup; + if ((flags & 1) || !(lookup = DNS.lookup_addr(addr))) { + if (flags & 8) { + return -2; + } + } else { + addr = lookup; + } + var numBytesWrittenExclNull = stringToUTF8(addr, node, nodelen); + + if (numBytesWrittenExclNull+1 >= nodelen) { + overflowed = true; + } + } + + if (serv && servlen) { + port = '' + port; + var numBytesWrittenExclNull = stringToUTF8(port, serv, servlen); + + if (numBytesWrittenExclNull+1 >= servlen) { + overflowed = true; + } + } + + if (overflowed) { + // Note: even when we overflow, getnameinfo() is specced to write out the truncated results. + return -12; + } + + return 0; + }; + _getnameinfo.sig = 'ipipipii'; + + var Protocols = { + list:[], + map:{ + }, + }; + + var stringToAscii = (str, buffer) => { + for (var i = 0; i < str.length; ++i) { + HEAP8[buffer++] = str.charCodeAt(i); + } + // Null-terminate the string + HEAP8[buffer] = 0; + }; + + var _setprotoent = (stayopen) => { + // void setprotoent(int stayopen); + + // Allocate and populate a protoent structure given a name, protocol number and array of aliases + function allocprotoent(name, proto, aliases) { + // write name into buffer + var nameBuf = _malloc(name.length + 1); + stringToAscii(name, nameBuf); + + // write aliases into buffer + var j = 0; + var length = aliases.length; + var aliasListBuf = _malloc((length + 1) * 4); // Use length + 1 so we have space for the terminating NULL ptr. + + for (var i = 0; i < length; i++, j += 4) { + var alias = aliases[i]; + var aliasBuf = _malloc(alias.length + 1); + stringToAscii(alias, aliasBuf); + HEAPU32[(((aliasListBuf)+(j))>>2)] = aliasBuf; + } + HEAPU32[(((aliasListBuf)+(j))>>2)] = 0; // Terminating NULL pointer. + + // generate protoent + var pe = _malloc(12); + HEAPU32[((pe)>>2)] = nameBuf; + HEAPU32[(((pe)+(4))>>2)] = aliasListBuf; + HEAP32[(((pe)+(8))>>2)] = proto; + return pe; + }; + + // Populate the protocol 'database'. The entries are limited to tcp and udp, though it is fairly trivial + // to add extra entries from /etc/protocols if desired - though not sure if that'd actually be useful. + var list = Protocols.list; + var map = Protocols.map; + if (list.length === 0) { + var entry = allocprotoent('tcp', 6, ['TCP']); + list.push(entry); + map['tcp'] = map['6'] = entry; + entry = allocprotoent('udp', 17, ['UDP']); + list.push(entry); + map['udp'] = map['17'] = entry; + } + + _setprotoent.index = 0; + }; + _setprotoent.sig = 'vi'; + + + var _getprotobyname = (name) => { + // struct protoent *getprotobyname(const char *); + name = UTF8ToString(name); + _setprotoent(true); + var result = Protocols.map[name]; + return result; + }; + _getprotobyname.sig = 'pp'; + + + var _getprotobynumber = (number) => { + // struct protoent *getprotobynumber(int proto); + _setprotoent(true); + var result = Protocols.map[number]; + return result; + }; + _getprotobynumber.sig = 'pi'; + + + + + function _js_flock(fd, op) { + _js_wasm_trace('js_flock(%d, %d)', fd, op); + // Emscripten does not expose these constants to JS, so we hardcode them here. + // Based on + // https://github.com/emscripten-core/emscripten/blob/76860cc47cef67f5712a7a03a247bc1baabf7ba4/system/lib/libc/musl/include/sys/file.h#L7-L10 + const emscripten_LOCK_SH = 1; + const emscripten_LOCK_EX = 2; + const emscripten_LOCK_NB = 4; + const emscripten_LOCK_UN = 8; + + const flockToLockOpType = { + [emscripten_LOCK_SH]: 'shared', + [emscripten_LOCK_EX]: 'exclusive', + [emscripten_LOCK_UN]: 'unlocked', + }; + + let vfsPath; + let errno; + + [vfsPath, errno] = locking.get_vfs_path_from_fd(fd); + if (errno !== 0) { + _js_wasm_trace( + 'js_flock(%d, %d) get_vfs_path_from_fd errno %d', + fd, + op, + vfsPath, + errno + ); + return -errno; + } + + if (!locking.is_path_to_shared_fs(vfsPath)) { + _js_wasm_trace( + 'flock(%d, %d) locking is not implemented for non-NodeFS path %s', + fd, + op, + vfsPath + ); + // If not a NodeFS path, we can't lock it. + // Default to succeeding as Emscripten does. + return 0; + } + + errno = locking.check_lock_params(fd, op); + if (errno !== 0) { + _js_wasm_trace( + 'js_flock(%d, %d) check_lock_params errno %d', + fd, + op, + errno + ); + return -errno; + } + + // @TODO: Consider supporting blocking mode of flock() + if (op & (emscripten_LOCK_NB === 0)) { + _js_wasm_trace( + 'js_flock(%d, %d) blocking mode of flock() is not implemented', + fd, + op + ); + // We do not yet support the blocking form of flock(). + // We respond with EINVAL to indicate failure + // because it is a known errno for a failed blocking flock(). + return -ERRNO_CODES.EINVAL; + } + + const maskedOp = + op & + (emscripten_LOCK_SH | emscripten_LOCK_EX | emscripten_LOCK_UN); + + const lockOpType = flockToLockOpType[maskedOp]; + if (lockOpType === undefined) { + _js_wasm_trace( + 'js_flock(%d, %d) invalid flock() operation', + fd, + op + ); + return -ERRNO_CODES.EINVAL; + } + + try { + const nativeFilePath = + locking.get_native_path_from_vfs_path(vfsPath); + const obtainedLock = ( + PHPLoader.fileLockManager.lockWholeFile( + nativeFilePath, + { + type: lockOpType, + pid: PHPLoader.processId, + fd, + } + ) + ); + _js_wasm_trace( + 'js_flock(%d, %d) lockWholeFile %s returned %d', + fd, + op, + vfsPath, + obtainedLock + ); + if (obtainedLock) { + locking.maybeLockedFds.add(fd); + return 0; + } else { + return -ERRNO_CODES.EWOULDBLOCK; + } + } catch (e) { + _js_wasm_trace('js_flock(%d, %d) lockWholeFile error %s', fd, op, e); + return -ERRNO_CODES.EINVAL; + } + } + + + + + function _js_open_process( + command, + argsPtr, + argsLength, + descriptorsPtr, + descriptorsLength, + cwdPtr, + cwdLength, + envPtr, + envLength + ) { + if (!command) { + ___errno_location(ERRNO_CODES.EINVAL); + return -1; + } + + const cmdstr = UTF8ToString(command); + if (!cmdstr.length) { + ___errno_location(ERRNO_CODES.EINVAL); + return -1; + } + + let argsArray = []; + if (argsLength) { + for (var i = 0; i < argsLength; i++) { + const charPointer = argsPtr + i * 4; + argsArray.push(UTF8ToString(HEAPU32[charPointer >> 2])); + } + } + + const cwdstr = cwdPtr ? UTF8ToString(cwdPtr) : FS.cwd(); + let envObject = null; + + if (envLength) { + envObject = {}; + for (var i = 0; i < envLength; i++) { + const envPointer = envPtr + i * 4; + const envEntry = UTF8ToString(HEAPU32[envPointer >> 2]); + const splitAt = envEntry.indexOf('='); + if (splitAt === -1) { + continue; + } + const key = envEntry.substring(0, splitAt); + const value = envEntry.substring(splitAt + 1); + envObject[key] = value; + } + } + + var std = {}; + // Extracts an array of available descriptors that should be dispatched to streams. + // On the C side, the descriptors are expressed as `**int` so we must go read + // each of the `descriptorsLength` `*int` pointers and convert the associated data into + // a JavaScript object { descriptor : { child : fd, parent : fd } }. + for (var i = 0; i < descriptorsLength; i++) { + const descriptorPtr = HEAPU32[(descriptorsPtr + i * 4) >> 2]; + std[HEAPU32[descriptorPtr >> 2]] = { + child: HEAPU32[(descriptorPtr + 4) >> 2], + parent: HEAPU32[(descriptorPtr + 8) >> 2], + }; + // swap parent and child descs until we rebuild PHP 7.4 + if (i === 0) { + HEAPU32[(descriptorPtr + 8) >> 2] = std[HEAPU32[descriptorPtr >> 2]].parent; + HEAPU32[(descriptorPtr + 4) >> 2] = std[HEAPU32[descriptorPtr >> 2]].child; + } + } + + return Asyncify.handleAsync(async () => { + let cp; + try { + const options = {}; + if (cwdstr !== null) { + options.cwd = cwdstr; + } + if (envObject !== null) { + options.env = envObject; + } + cp = PHPWASM.spawnProcess(cmdstr, argsArray, options); + if (cp instanceof Promise) { + cp = await cp; + } + } catch (e) { + if (e.code === 'SPAWN_UNSUPPORTED') { + ___errno_location(ERRNO_CODES.ENOSYS); + return -1; + } + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + ___errno_location(e.code); + return -1; + } + + const ProcInfo = { + pid: cp.pid, + exited: false + }; + PHPWASM.processTable[ProcInfo.pid] = ProcInfo; + + const stdinParentFd = std[0]?.parent, + stdinChildFd = std[0]?.child, + stdoutChildFd = std[1]?.child, + stdoutParentFd = std[1]?.parent, + stderrChildFd = std[2]?.child, + stderrParentFd = std[2]?.parent; + + cp.on('exit', function (code) { + for (const fd of [ + // The child process exited. Let's clean up its output streams: + stdoutChildFd, + stderrChildFd, + stdinChildFd, + + // We won't close these because the PHP already handles that in the parent process: + // stdoutParentFd, + // stderrParentFd, + // stdinParentFd, + ]) { + if (FS.streams[fd] && !FS.isClosed(FS.streams[fd])) { + FS.close(FS.streams[fd]); + } + } + + ProcInfo.exitCode = code; + ProcInfo.exited = true; + }); + + // Pass data from child process's stdout to PHP's end of the stdout pipe. + if (stdoutChildFd) { + const stdoutStream = SYSCALLS.getStreamFromFD( + stdoutChildFd + ); + let stdoutAt = 0; + cp.stdout.on('data', function (data) { + stdoutStream.stream_ops.write( + stdoutStream, + data, + 0, + data.length, + stdoutAt + ); + stdoutAt += data.length; + }); + } + + // Pass data from child process's stderr to PHP's end of the stdout pipe. + if (stderrChildFd) { + const stderrStream = SYSCALLS.getStreamFromFD( + stderrChildFd + ); + let stderrAt = 0; + cp.stderr.on('data', function (data) { + stderrStream.stream_ops.write( + stderrStream, + data, + 0, + data.length, + stderrAt + ); + stderrAt += data.length; + }); + } + + /** + * Wait until the child process has been spawned. + * Unfortunately there is no Node.js API to check whether + * the process has already been spawned. We can only listen + * to the 'spawn' event and if it has already been spawned, + * listen to the 'exit' event. + */ + try { + await new Promise((resolve, reject) => { + /** + * There was no `await` between the `spawnProcess` call + * and the `await` below so the process haven't had a chance + * to run any of the exit-related callbacks yet. + * + * Good. + * + * Let's listen to all the lifecycle events and resolve + * the promise when the process starts or immediately crashes. + */ + let resolved = false; + cp.on('spawn', () => { + if (resolved) return; + resolved = true; + resolve(); + }); + cp.on('error', (e) => { + if (resolved) return; + resolved = true; + reject(e); + }); + cp.on('exit', function (code) { + if (resolved) return; + resolved = true; + if (code === 0) { + resolve(); + } else { + reject( + new Error(`Process exited with code ${code}`) + ); + } + }); + /** + * If the process haven't even started after 5 seconds, something + * is wrong. Perhaps we're missing an event listener, or perhaps + * the `spawnProcess` implementation failed to dispatch the relevant + * event. Either way, let's crash to avoid blocking the proc_open() + * call indefinitely. + */ + setTimeout(() => { + if (resolved) return; + resolved = true; + reject(new Error('Process timed out')); + }, 5000); + }); + } catch (e) { + // Process already started. Even if it exited early, PHP still + // needs to know about the pid and clean up the resources. + console.error(e); + return ProcInfo.pid; + } + + // Now we want to pass data from the STDIN source supplied by PHP + // to the child process. + if (stdinChildFd) { + // We're in a kernel function used instead of fork(). + // + // We are the ones responsible for pumping the data from the stdinChildFd + // into the child process. There is no concurrent task operating on the + // piped data or polling the file descriptors, etc. Nothing will ever + // read from the stdinChildFd if we don't do it here. + // + // Well, let's do it! We'll periodically read from the child end of the + // data pipe and push what we get into the child process. + let stdinStream; + try { + stdinStream = SYSCALLS.getStreamFromFD(stdinChildFd); + } catch (e) { + ___errno_location(ERRNO_CODES.EBADF); + return ProcInfo.pid; + } + if (!stdinStream?.node) { + return ProcInfo.pid; + } + + // Pipe the entire stdinStream to cp.stdin + const CHUNK_SIZE = 1024; + + const iov = _malloc(16); // Space for iovec structure + const pnum = _malloc(4); // Space for number of bytes read + const buffer = _malloc(CHUNK_SIZE); + + // Set up iovec structure pointing to our buffer + HEAPU32[iov >> 2] = buffer; // iov_base + HEAPU32[(iov + 4) >> 2] = CHUNK_SIZE; // iov_len + + function pump() { + try { + while (true) { + if (cp.killed) { + stopPumpingAndCloseStdin(); + return; + } + + const result = js_fd_read( + stdinChildFd, + iov, + 1, + pnum, + false + ); + const bytesRead = HEAPU32[pnum >> 2]; + if (result === 0 && bytesRead > 0) { + const wrote = HEAPU8.subarray( + buffer, + buffer + bytesRead + ); + cp.stdin.write(wrote); + // We've read some data. Let the next iteration decide + // how to break out of the loop. + } else if (result === 0 && bytesRead === 0) { + // result === 0 and bytesRead === 0 means the file descriptor + // is at EOF. Let's close the stdin stream and clean up. + stopPumpingAndCloseStdin(); + break; + } else if (result === ERRNO_CODES.EAGAIN) { + // The file descriptor is not ready for reading. + // Let's break out of the loop. setInterval will invoke + // this function again soon. + break; + } else { + throw new FS.ErrnoError(result); + } + } + } catch (e) { + if ( + typeof FS == 'undefined' || + !(e.name === 'ErrnoError') + ) { + throw e; + } + ___errno_location(e.errno); + stopPumpingAndCloseStdin(); + } + }; + function stopPumpingAndCloseStdin() { + clearInterval(interval); + if (!cp.stdin.closed) { + cp.stdin.end(); + } + _free(buffer); + _free(iov); + _free(pnum); + } + + // pump() can never alter the result of this function. + // Even when it fails, we still return the pid. + // Why? + // Because the process already started. We wouldn't backtrack + // with fork(), we won't backtrack here. Let's give PHP the pid, + // and let it think it's the parent process. It will clean up the + // resources as needed. + + // stdin may be non-blocking – let's check for updates periodically. + // If we exhaust it at any point, pump() will self-terminate. + // + // Note handling any failures, closing the descriptor, etc. will not + // happen synchronously when PHP calls fclose($pipes[0]) or proc_close(). + // It will all happen asynchronously on the next tick. It seems off, + // but there doesn't seem to be a better way: cp.stdin.write() and + // cp.stdin.end() are both async APIs and they both accept onCompleted + // callbacks. + const interval = setInterval(pump, 20); + pump(); + } + + return ProcInfo.pid; + }); + } + + + function _js_process_status(pid, exitCodePtr) { + if (!PHPWASM.processTable[pid]) { + return -1; + } + if (PHPWASM.processTable[pid].exited) { + HEAPU32[exitCodePtr >> 2] = PHPWASM.processTable[pid].exitCode; + return 1; + } + return 0; + } + + + + + function _js_release_file_locks() { + _js_wasm_trace('js_release_file_locks()'); + const pid = PHPLoader.processId; + if (!pid || !PHPLoader.fileLockManager) { + _js_wasm_trace('js_release_file_locks no pid or file lock manager'); + return 0; + } + + try { + PHPLoader.fileLockManager + .releaseLocksForProcess(pid) + _js_wasm_trace('js_release_file_locks succeeded'); + } catch (e) { + _js_wasm_trace('js_release_file_locks error %s', e); + } + } + + + function _js_waitpid(pid, exitCodePtr) { + if (!PHPWASM.processTable[pid]) { + return -1; + } + return Asyncify.handleSleep((wakeUp) => { + const poll = function () { + if (PHPWASM.processTable[pid]?.exited) { + HEAPU32[exitCodePtr >> 2] = + PHPWASM.processTable[pid].exitCode; + wakeUp(pid); + } else { + setTimeout(poll, 50); + } + }; + poll(); + }); + } + + + + function _random_get(buffer, size) { + try { + + randomFill(HEAPU8.subarray(buffer, buffer + size)); + return 0; + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return e.errno; + } + } + _random_get.sig = 'ipp'; + + + var arraySum = (array, index) => { + var sum = 0; + for (var i = 0; i <= index; sum += array[i++]) { + // no-op + } + return sum; + }; + + + var MONTH_DAYS_LEAP = [31,29,31,30,31,30,31,31,30,31,30,31]; + + var MONTH_DAYS_REGULAR = [31,28,31,30,31,30,31,31,30,31,30,31]; + var addDays = (date, days) => { + var newDate = new Date(date.getTime()); + while (days > 0) { + var leap = isLeapYear(newDate.getFullYear()); + var currentMonth = newDate.getMonth(); + var daysInCurrentMonth = (leap ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR)[currentMonth]; + + if (days > daysInCurrentMonth-newDate.getDate()) { + // we spill over to next month + days -= (daysInCurrentMonth-newDate.getDate()+1); + newDate.setDate(1); + if (currentMonth < 11) { + newDate.setMonth(currentMonth+1) + } else { + newDate.setMonth(0); + newDate.setFullYear(newDate.getFullYear()+1); + } + } else { + // we stay in current month + newDate.setDate(newDate.getDate()+days); + return newDate; + } + } + + return newDate; + }; + + + + + var _strptime = (buf, format, tm) => { + // char *strptime(const char *restrict buf, const char *restrict format, struct tm *restrict tm); + // http://pubs.opengroup.org/onlinepubs/009695399/functions/strptime.html + var pattern = UTF8ToString(format); + + // escape special characters + // TODO: not sure we really need to escape all of these in JS regexps + var SPECIAL_CHARS = '\\!@#$^&*()+=-[]/{}|:<>?,.'; + for (var i=0, ii=SPECIAL_CHARS.length; i EQUIVALENT_MATCHERS[c] || m) + .replace(/%(.)/g, (_, c) => { + let pat = DATE_PATTERNS[c]; + if (pat){ + capture.push(c); + return `(${pat})`; + } else { + return c; + } + }) + .replace( // any number of space or tab characters match zero or more spaces + /\s+/g,'\\s*' + ); + + var matches = new RegExp('^'+pattern_out, "i").exec(UTF8ToString(buf)) + + function initDate() { + function fixup(value, min, max) { + return (typeof value != 'number' || isNaN(value)) ? min : (value>=min ? (value<=max ? value: max): min); + }; + return { + year: fixup(HEAP32[(((tm)+(20))>>2)] + 1900 , 1970, 9999), + month: fixup(HEAP32[(((tm)+(16))>>2)], 0, 11), + day: fixup(HEAP32[(((tm)+(12))>>2)], 1, 31), + hour: fixup(HEAP32[(((tm)+(8))>>2)], 0, 23), + min: fixup(HEAP32[(((tm)+(4))>>2)], 0, 59), + sec: fixup(HEAP32[((tm)>>2)], 0, 59), + gmtoff: 0 + }; + }; + + if (matches) { + var date = initDate(); + var value; + + var getMatch = (symbol) => { + var pos = capture.indexOf(symbol); + // check if symbol appears in regexp + if (pos >= 0) { + // return matched value or null (falsy!) for non-matches + return matches[pos+1]; + } + return; + }; + + // seconds + if ((value=getMatch('S'))) { + date.sec = Number(value); + } + + // minutes + if ((value=getMatch('M'))) { + date.min = Number(value); + } + + // hours + if ((value=getMatch('H'))) { + // 24h clock + date.hour = Number(value); + } else if ((value = getMatch('I'))) { + // AM/PM clock + var hour = Number(value); + if ((value=getMatch('p'))) { + hour += value.toUpperCase()[0] === 'P' ? 12 : 0; + } + date.hour = hour; + } + + // year + if ((value=getMatch('Y'))) { + // parse from four-digit year + date.year = Number(value); + } else if ((value=getMatch('y'))) { + // parse from two-digit year... + var year = Number(value); + if ((value=getMatch('C'))) { + // ...and century + year += Number(value)*100; + } else { + // ...and rule-of-thumb + year += year<69 ? 2000 : 1900; + } + date.year = year; + } + + // month + if ((value=getMatch('m'))) { + // parse from month number + date.month = Number(value)-1; + } else if ((value=getMatch('b'))) { + // parse from month name + date.month = MONTH_NUMBERS[value.substring(0,3).toUpperCase()] || 0; + // TODO: derive month from day in year+year, week number+day of week+year + } + + // day + if ((value=getMatch('d'))) { + // get day of month directly + date.day = Number(value); + } else if ((value=getMatch('j'))) { + // get day of month from day of year ... + var day = Number(value); + var leapYear = isLeapYear(date.year); + for (var month=0; month<12; ++month) { + var daysUntilMonth = arraySum(leapYear ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR, month-1); + if (day<=daysUntilMonth+(leapYear ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR)[month]) { + date.day = day-daysUntilMonth; + } + } + } else if ((value=getMatch('a'))) { + // get day of month from weekday ... + var weekDay = value.substring(0,3).toUpperCase(); + if ((value=getMatch('U'))) { + // ... and week number (Sunday being first day of week) + // Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. + // All days in a new year preceding the first Sunday are considered to be in week 0. + var weekDayNumber = DAY_NUMBERS_SUN_FIRST[weekDay]; + var weekNumber = Number(value); + + // January 1st + var janFirst = new Date(date.year, 0, 1); + var endDate; + if (janFirst.getDay() === 0) { + // Jan 1st is a Sunday, and, hence in the 1st CW + endDate = addDays(janFirst, weekDayNumber+7*(weekNumber-1)); + } else { + // Jan 1st is not a Sunday, and, hence still in the 0th CW + endDate = addDays(janFirst, 7-janFirst.getDay()+weekDayNumber+7*(weekNumber-1)); + } + date.day = endDate.getDate(); + date.month = endDate.getMonth(); + } else if ((value=getMatch('W'))) { + // ... and week number (Monday being first day of week) + // Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. + // All days in a new year preceding the first Monday are considered to be in week 0. + var weekDayNumber = DAY_NUMBERS_MON_FIRST[weekDay]; + var weekNumber = Number(value); + + // January 1st + var janFirst = new Date(date.year, 0, 1); + var endDate; + if (janFirst.getDay()===1) { + // Jan 1st is a Monday, and, hence in the 1st CW + endDate = addDays(janFirst, weekDayNumber+7*(weekNumber-1)); + } else { + // Jan 1st is not a Monday, and, hence still in the 0th CW + endDate = addDays(janFirst, 7-janFirst.getDay()+1+weekDayNumber+7*(weekNumber-1)); + } + + date.day = endDate.getDate(); + date.month = endDate.getMonth(); + } + } + + // time zone + if ((value = getMatch('z'))) { + // GMT offset as either 'Z' or +-HH:MM or +-HH or +-HHMM + if (value.toLowerCase() === 'z'){ + date.gmtoff = 0; + } else { + var match = value.match(/^((?:\-|\+)\d\d):?(\d\d)?/); + date.gmtoff = match[1] * 3600; + if (match[2]) { + date.gmtoff += date.gmtoff >0 ? match[2] * 60 : -match[2] * 60 + } + } + } + + /* + tm_sec int seconds after the minute 0-61* + tm_min int minutes after the hour 0-59 + tm_hour int hours since midnight 0-23 + tm_mday int day of the month 1-31 + tm_mon int months since January 0-11 + tm_year int years since 1900 + tm_wday int days since Sunday 0-6 + tm_yday int days since January 1 0-365 + tm_isdst int Daylight Saving Time flag + tm_gmtoff long offset from GMT (seconds) + */ + + var fullDate = new Date(date.year, date.month, date.day, date.hour, date.min, date.sec, 0); + HEAP32[((tm)>>2)] = fullDate.getSeconds(); + HEAP32[(((tm)+(4))>>2)] = fullDate.getMinutes(); + HEAP32[(((tm)+(8))>>2)] = fullDate.getHours(); + HEAP32[(((tm)+(12))>>2)] = fullDate.getDate(); + HEAP32[(((tm)+(16))>>2)] = fullDate.getMonth(); + HEAP32[(((tm)+(20))>>2)] = fullDate.getFullYear()-1900; + HEAP32[(((tm)+(24))>>2)] = fullDate.getDay(); + HEAP32[(((tm)+(28))>>2)] = arraySum(isLeapYear(fullDate.getFullYear()) ? MONTH_DAYS_LEAP : MONTH_DAYS_REGULAR, fullDate.getMonth()-1)+fullDate.getDate()-1; + HEAP32[(((tm)+(32))>>2)] = 0; + HEAP32[(((tm)+(36))>>2)] = date.gmtoff; + + // we need to convert the matched sequence into an integer array to take care of UTF-8 characters > 0x7F + // TODO: not sure that intArrayFromString handles all unicode characters correctly + return buf+lengthBytesUTF8(matches[0]); + } + + return 0; + }; + _strptime.sig = 'pppp'; + + + function _wasm_close(socketd) { + return PHPWASM.shutdownSocket(socketd, 2); + } + + + function _wasm_setsockopt( + socketd, + level, + optionName, + optionValuePtr, + optionLen + ) { + const optionValue = HEAPU8[optionValuePtr]; + const SOL_SOCKET = 1; + const SO_KEEPALIVE = 9; + const IPPROTO_TCP = 6; + const TCP_NODELAY = 1; + const isSupported = + (level === SOL_SOCKET && optionName === SO_KEEPALIVE) || + (level === IPPROTO_TCP && optionName === TCP_NODELAY); + if (!isSupported) { + console.warn( + `Unsupported socket option: ${level}, ${optionName}, ${optionValue}` + ); + return -1; + } + const ws = PHPWASM.getAllWebSockets(socketd)[0]; + if (!ws) { + return -1; + } + ws.setSocketOpt(level, optionName, optionValuePtr); + return 0; + } + + + + + + + var runAndAbortIfError = (func) => { + try { + return func(); + } catch (e) { + abort(e); + } + }; + + + + + + + + var Asyncify = { + instrumentWasmImports(imports) { + var importPattern = /^(invoke_i|invoke_ii|invoke_iii|invoke_iiii|invoke_iiiii|invoke_iiiiii|invoke_iiiiiii|invoke_iiiiiiii|invoke_iiiiiiiii|invoke_iiiiiiiiii|invoke_v|invoke_vi|invoke_vii|invoke_viidii|invoke_viii|invoke_viiii|invoke_viiiii|invoke_viiiiii|invoke_viiiiiii|invoke_viiiiiiiii|invoke_i|invoke_ii|invoke_iii|invoke_iiii|invoke_iiiii|invoke_iiiiii|invoke_iiiiiii|invoke_iiiiiiii|invoke_iiiiiiiiii|invoke_iij|invoke_iiji|invoke_iiij|invoke_iijii|invoke_iijiji|invoke_jii|invoke_jiii|invoke_viijii|invoke_vji|js_open_process|_js_open_process|_asyncjs__js_open_process|js_popen_to_file|_js_popen_to_file|_asyncjs__js_popen_to_file|__syscall_fcntl64|___syscall_fcntl64|_asyncjs___syscall_fcntl64|js_release_file_locks|_js_release_file_locks|_async_js_release_file_locks|js_flock|_js_flock|_async_js_flock|js_fd_read|_js_fd_read|fd_close|_fd_close|_asyncjs__fd_close|close|_close|js_module_onMessage|zend_hash_str_find|_js_module_onMessage|_asyncjs__js_module_onMessage|js_waitpid|_js_waitpid|_asyncjs__js_waitpid|wasm_poll_socket|_wasm_poll_socket|_asyncjs__wasm_poll_socket|_wasm_shutdown|_asyncjs__wasm_shutdown|__asyncjs__.*)$/; + + for (let [x, original] of Object.entries(imports)) { + if (typeof original == 'function') { + let isAsyncifyImport = original.isAsync || importPattern.test(x); + } + } + }, + instrumentFunction(original) { + var wrapper = (...args) => { + Asyncify.exportCallStack.push(original); + try { + return original(...args); + } finally { + if (!ABORT) { + var top = Asyncify.exportCallStack.pop(); + Asyncify.maybeStopUnwind(); + } + } + }; + Asyncify.funcWrappers.set(original, wrapper); + wrapper.orig = original; + return wrapper; + }, + instrumentWasmExports(exports) { + var ret = {}; + for (let [x, original] of Object.entries(exports)) { + if (typeof original == 'function') { + var wrapper = Asyncify.instrumentFunction(original); + ret[x] = wrapper; + + } else { + ret[x] = original; + } + } + return ret; + }, + State:{ + Normal:0, + Unwinding:1, + Rewinding:2, + Disabled:3, + }, + state:0, + StackSize:4096, + currData:null, + handleSleepReturnValue:0, + exportCallStack:[], + callstackFuncToId:new Map, + callStackIdToFunc:new Map, + funcWrappers:new Map, + callStackId:0, + asyncPromiseHandlers:null, + sleepCallbacks:[], + getCallStackId(func) { + if (!Asyncify.callstackFuncToId.has(func)) { + var id = Asyncify.callStackId++; + Asyncify.callstackFuncToId.set(func, id); + Asyncify.callStackIdToFunc.set(id, func); + } + return Asyncify.callstackFuncToId.get(func); + }, + maybeStopUnwind() { + if (Asyncify.currData && + Asyncify.state === Asyncify.State.Unwinding && + Asyncify.exportCallStack.length === 0) { + // We just finished unwinding. + // Be sure to set the state before calling any other functions to avoid + // possible infinite recursion here (For example in debug pthread builds + // the dbg() function itself can call back into WebAssembly to get the + // current pthread_self() pointer). + Asyncify.state = Asyncify.State.Normal; + runtimeKeepalivePush(); + // Keep the runtime alive so that a re-wind can be done later. + runAndAbortIfError(_asyncify_stop_unwind); + if (typeof Fibers != 'undefined') { + Fibers.trampoline(); + } + } + }, + whenDone() { + return new Promise((resolve, reject) => { + Asyncify.asyncPromiseHandlers = { resolve, reject }; + }); + }, + allocateData() { + // An asyncify data structure has three fields: + // 0 current stack pos + // 4 max stack pos + // 8 id of function at bottom of the call stack (callStackIdToFunc[id] == wasm func) + // + // The Asyncify ABI only interprets the first two fields, the rest is for the runtime. + // We also embed a stack in the same memory region here, right next to the structure. + // This struct is also defined as asyncify_data_t in emscripten/fiber.h + var ptr = _malloc(12 + Asyncify.StackSize); + Asyncify.setDataHeader(ptr, ptr + 12, Asyncify.StackSize); + Asyncify.setDataRewindFunc(ptr); + return ptr; + }, + setDataHeader(ptr, stack, stackSize) { + HEAPU32[((ptr)>>2)] = stack; + HEAPU32[(((ptr)+(4))>>2)] = stack + stackSize; + }, + setDataRewindFunc(ptr) { + var bottomOfCallStack = Asyncify.exportCallStack[0]; + var rewindId = Asyncify.getCallStackId(bottomOfCallStack); + HEAP32[(((ptr)+(8))>>2)] = rewindId; + }, + getDataRewindFunc(ptr) { + var id = HEAP32[(((ptr)+(8))>>2)]; + var func = Asyncify.callStackIdToFunc.get(id); + return func; + }, + doRewind(ptr) { + var original = Asyncify.getDataRewindFunc(ptr); + var func = Asyncify.funcWrappers.get(original); + // Once we have rewound and the stack we no longer need to artificially + // keep the runtime alive. + runtimeKeepalivePop(); + return func(); + }, + handleSleep(startAsync) { + if (ABORT) return; + if (Asyncify.state === Asyncify.State.Normal) { + // Prepare to sleep. Call startAsync, and see what happens: + // if the code decided to call our callback synchronously, + // then no async operation was in fact begun, and we don't + // need to do anything. + var reachedCallback = false; + var reachedAfterCallback = false; + startAsync((handleSleepReturnValue = 0) => { + if (ABORT) return; + Asyncify.handleSleepReturnValue = handleSleepReturnValue; + reachedCallback = true; + if (!reachedAfterCallback) { + // We are happening synchronously, so no need for async. + return; + } + Asyncify.state = Asyncify.State.Rewinding; + runAndAbortIfError(() => _asyncify_start_rewind(Asyncify.currData)); + if (typeof MainLoop != 'undefined' && MainLoop.func) { + MainLoop.resume(); + } + var asyncWasmReturnValue, isError = false; + try { + asyncWasmReturnValue = Asyncify.doRewind(Asyncify.currData); + } catch (err) { + asyncWasmReturnValue = err; + isError = true; + } + // Track whether the return value was handled by any promise handlers. + var handled = false; + if (!Asyncify.currData) { + // All asynchronous execution has finished. + // `asyncWasmReturnValue` now contains the final + // return value of the exported async WASM function. + // + // Note: `asyncWasmReturnValue` is distinct from + // `Asyncify.handleSleepReturnValue`. + // `Asyncify.handleSleepReturnValue` contains the return + // value of the last C function to have executed + // `Asyncify.handleSleep()`, where as `asyncWasmReturnValue` + // contains the return value of the exported WASM function + // that may have called C functions that + // call `Asyncify.handleSleep()`. + var asyncPromiseHandlers = Asyncify.asyncPromiseHandlers; + if (asyncPromiseHandlers) { + Asyncify.asyncPromiseHandlers = null; + (isError ? asyncPromiseHandlers.reject : asyncPromiseHandlers.resolve)(asyncWasmReturnValue); + handled = true; + } + } + if (isError && !handled) { + // If there was an error and it was not handled by now, we have no choice but to + // rethrow that error into the global scope where it can be caught only by + // `onerror` or `onunhandledpromiserejection`. + throw asyncWasmReturnValue; + } + }); + reachedAfterCallback = true; + if (!reachedCallback) { + // A true async operation was begun; start a sleep. + Asyncify.state = Asyncify.State.Unwinding; + // TODO: reuse, don't alloc/free every sleep + Asyncify.currData = Asyncify.allocateData(); + if (typeof MainLoop != 'undefined' && MainLoop.func) { + MainLoop.pause(); + } + runAndAbortIfError(() => _asyncify_start_unwind(Asyncify.currData)); + } + } else if (Asyncify.state === Asyncify.State.Rewinding) { + // Stop a resume. + Asyncify.state = Asyncify.State.Normal; + runAndAbortIfError(_asyncify_stop_rewind); + _free(Asyncify.currData); + Asyncify.currData = null; + // Call all sleep callbacks now that the sleep-resume is all done. + Asyncify.sleepCallbacks.forEach(callUserCallback); + } else { + abort(`invalid state: ${Asyncify.state}`); + } + return Asyncify.handleSleepReturnValue; + }, + handleAsync:(startAsync) => Asyncify.handleSleep((wakeUp) => { + // TODO: add error handling as a second param when handleSleep implements it. + startAsync().then(wakeUp); + }), + }; + + var getCFunc = (ident) => { + var func = Module['_' + ident]; // closure exported function + return func; + }; + + var writeArrayToMemory = (array, buffer) => { + HEAP8.set(array, buffer); + }; + + + + + + + + + /** + * @param {string|null=} returnType + * @param {Array=} argTypes + * @param {Array=} args + * @param {Object=} opts + */ + var ccall = (ident, returnType, argTypes, args, opts) => { + // For fast lookup of conversion functions + var toC = { + 'string': (str) => { + var ret = 0; + if (str !== null && str !== undefined && str !== 0) { // null string + ret = stringToUTF8OnStack(str); + } + return ret; + }, + 'array': (arr) => { + var ret = stackAlloc(arr.length); + writeArrayToMemory(arr, ret); + return ret; + } + }; + + function convertReturnValue(ret) { + if (returnType === 'string') { + return UTF8ToString(ret); + } + if (returnType === 'boolean') return Boolean(ret); + return ret; + } + + var func = getCFunc(ident); + var cArgs = []; + var stack = 0; + if (args) { + for (var i = 0; i < args.length; i++) { + var converter = toC[argTypes[i]]; + if (converter) { + if (stack === 0) stack = stackSave(); + cArgs[i] = converter(args[i]); + } else { + cArgs[i] = args[i]; + } + } + } + // Data for a previous async operation that was in flight before us. + var previousAsync = Asyncify.currData; + var ret = func(...cArgs); + function onDone(ret) { + runtimeKeepalivePop(); + if (stack !== 0) stackRestore(stack); + return convertReturnValue(ret); + } + var asyncMode = opts?.async; + + // Keep the runtime alive through all calls. Note that this call might not be + // async, but for simplicity we push and pop in all calls. + runtimeKeepalivePush(); + if (Asyncify.currData != previousAsync) { + // This is a new async operation. The wasm is paused and has unwound its stack. + // We need to return a Promise that resolves the return value + // once the stack is rewound and execution finishes. + return Asyncify.whenDone().then(onDone); + } + + ret = onDone(ret); + // If this is an async ccall, ensure we return a promise + if (asyncMode) return Promise.resolve(ret); + return ret; + }; + + + var FS_createPath = (...args) => FS.createPath(...args); + + + + var FS_unlink = (...args) => FS.unlink(...args); + + var FS_createLazyFile = (...args) => FS.createLazyFile(...args); + + var FS_createDevice = (...args) => FS.createDevice(...args); + + + + + var writeI53ToI64Clamped = (ptr, num) => { + if (num > 0x7FFFFFFFFFFFFFFF) { + HEAPU32[((ptr)>>2)] = 4294967295; + HEAPU32[(((ptr)+(4))>>2)] = 2147483647; + } else if (num < -0x8000000000000000) { + HEAPU32[((ptr)>>2)] = 0; + HEAPU32[(((ptr)+(4))>>2)] = 2147483648; + } else { + writeI53ToI64(ptr, num); + } + }; + + var writeI53ToI64Signaling = (ptr, num) => { + if (num > 0x7FFFFFFFFFFFFFFF || num < -0x8000000000000000) { + throw `RangeError: ${num}`; + } + writeI53ToI64(ptr, num); + }; + + var writeI53ToU64Clamped = (ptr, num) => { + if (num > 0xFFFFFFFFFFFFFFFF) { + HEAPU32[((ptr)>>2)] = 4294967295; + HEAPU32[(((ptr)+(4))>>2)] = 4294967295; + } else if (num < 0) { + HEAPU32[((ptr)>>2)] = 0; + HEAPU32[(((ptr)+(4))>>2)] = 0; + } else { + writeI53ToI64(ptr, num); + } + }; + + var writeI53ToU64Signaling = (ptr, num) => { + if (num < 0 || num > 0xFFFFFFFFFFFFFFFF) { + throw `RangeError: ${num}`; + } + writeI53ToI64(ptr, num); + }; + + + var readI53FromU64 = (ptr) => { + return HEAPU32[((ptr)>>2)] + HEAPU32[(((ptr)+(4))>>2)] * 4294967296; + }; + + var convertI32PairToI53 = (lo, hi) => { + return (lo >>> 0) + hi * 4294967296; + }; + + var convertI32PairToI53Checked = (lo, hi) => { + return ((hi + 0x200000) >>> 0 < 0x400001 - !!lo) ? (lo >>> 0) + hi * 4294967296 : NaN; + }; + + var convertU32PairToI53 = (lo, hi) => { + return (lo >>> 0) + (hi >>> 0) * 4294967296; + }; + + + + + + + + var getTempRet0 = (val) => __emscripten_tempret_get(); + + + var _stackAlloc = stackAlloc; + + var _stackSave = stackSave; + + var _stackRestore = stackSave; + + var _setTempRet0 = setTempRet0; + + var _getTempRet0 = getTempRet0; + + + var ptrToString = (ptr) => { + // Convert to 32-bit unsigned value + ptr >>>= 0; + return '0x' + ptr.toString(16).padStart(8, '0'); + }; + + + + + + + + + var _emscripten_notify_memory_growth = (memoryIndex) => { + updateMemoryViews(); + }; + _emscripten_notify_memory_growth.sig = 'vp'; + + + + + + + + + + + var strError = (errno) => UTF8ToString(_strerror(errno)); + + + + + + + + + + + + + + var _endprotoent = () => { + // void endprotoent(void); + // We're not using a real protocol database so we don't do a real close. + }; + _endprotoent.sig = 'v'; + + + var _getprotoent = (number) => { + // struct protoent *getprotoent(void); + // reads the next entry from the protocols 'database' or return NULL if 'eof' + if (_setprotoent.index === Protocols.list.length) { + return 0; + } + var result = Protocols.list[_setprotoent.index++]; + return result; + }; + _getprotoent.sig = 'p'; + + + + var Sockets = { + BUFFER_SIZE:10240, + MAX_BUFFER_SIZE:10485760, + nextFd:1, + fds:{ + }, + nextport:1, + maxport:65535, + peer:null, + connections:{ + }, + portmap:{ + }, + localAddr:4261412874, + addrPool:[33554442,50331658,67108874,83886090,100663306,117440522,134217738,150994954,167772170,184549386,201326602,218103818,234881034], + }; + + + + + var _emscripten_run_script = (ptr) => { + eval(UTF8ToString(ptr)); + }; + _emscripten_run_script.sig = 'vp'; + + /** @suppress{checkTypes} */ + var _emscripten_run_script_int = (ptr) => { + return eval(UTF8ToString(ptr))|0; + }; + _emscripten_run_script_int.sig = 'ip'; + + + + + var _emscripten_run_script_string = (ptr) => { + var s = eval(UTF8ToString(ptr)); + if (s == null) { + return 0; + } + s += ''; + var me = _emscripten_run_script_string; + me.bufferSize = lengthBytesUTF8(s) + 1; + me.buffer = _realloc(me.buffer ?? 0, me.bufferSize) + stringToUTF8(s, me.buffer, me.bufferSize); + return me.buffer; + }; + _emscripten_run_script_string.sig = 'pp'; + + var _emscripten_random = () => Math.random(); + _emscripten_random.sig = 'f'; + + + var _emscripten_performance_now = () => performance.now(); + _emscripten_performance_now.sig = 'd'; + + + + + var __emscripten_get_now_is_monotonic = () => nowIsMonotonic; + __emscripten_get_now_is_monotonic.sig = 'i'; + + var warnOnce = (text) => { + warnOnce.shown ||= {}; + if (!warnOnce.shown[text]) { + warnOnce.shown[text] = 1; + if (ENVIRONMENT_IS_NODE) text = 'warning: ' + text; + err(text); + } + }; + + + var _emscripten_get_compiler_setting = (name) => abort('You must build with -sRETAIN_COMPILER_SETTINGS for getCompilerSetting or emscripten_get_compiler_setting to work'); + _emscripten_get_compiler_setting.sig = 'pp'; + + var _emscripten_has_asyncify = () => 1; + _emscripten_has_asyncify.sig = 'i'; + + var _emscripten_debugger = () => { debugger }; + _emscripten_debugger.sig = 'v'; + + + var _emscripten_print_double = (x, to, max) => { + var str = x + ''; + if (to) return stringToUTF8(str, to, max); + else return lengthBytesUTF8(str); + }; + _emscripten_print_double.sig = 'idpi'; + + + + + + var _emscripten_asm_const_double = (code, sigPtr, argbuf) => { + return runEmAsmFunction(code, sigPtr, argbuf); + }; + _emscripten_asm_const_double.sig = 'dppp'; + + var _emscripten_asm_const_ptr = (code, sigPtr, argbuf) => { + return runEmAsmFunction(code, sigPtr, argbuf); + }; + _emscripten_asm_const_ptr.sig = 'pppp'; + + var runMainThreadEmAsm = (emAsmAddr, sigPtr, argbuf, sync) => { + var args = readEmAsmArgs(sigPtr, argbuf); + return ASM_CONSTS[emAsmAddr](...args); + }; + + var _emscripten_asm_const_int_sync_on_main_thread = (emAsmAddr, sigPtr, argbuf) => runMainThreadEmAsm(emAsmAddr, sigPtr, argbuf, 1); + _emscripten_asm_const_int_sync_on_main_thread.sig = 'ippp'; + + var _emscripten_asm_const_ptr_sync_on_main_thread = (emAsmAddr, sigPtr, argbuf) => runMainThreadEmAsm(emAsmAddr, sigPtr, argbuf, 1); + _emscripten_asm_const_ptr_sync_on_main_thread.sig = 'pppp'; + + var _emscripten_asm_const_double_sync_on_main_thread = _emscripten_asm_const_int_sync_on_main_thread; + _emscripten_asm_const_double_sync_on_main_thread.sig = 'dppp'; + + var _emscripten_asm_const_async_on_main_thread = (emAsmAddr, sigPtr, argbuf) => runMainThreadEmAsm(emAsmAddr, sigPtr, argbuf, 0); + _emscripten_asm_const_async_on_main_thread.sig = 'vppp'; + + + var __Unwind_Backtrace = (func, arg) => { + var trace = getCallstack(); + var parts = trace.split('\n'); + for (var i = 0; i < parts.length; i++) { + var ret = ((a1, a2) => {} /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(0, arg); + if (ret !== 0) return; + } + }; + __Unwind_Backtrace.sig = 'ipp'; + + var __Unwind_GetIPInfo = (context, ipBefore) => abort('Unwind_GetIPInfo'); + __Unwind_GetIPInfo.sig = 'ppp'; + + var __Unwind_FindEnclosingFunction = (ip) => 0; + __Unwind_FindEnclosingFunction.sig = 'pp'; + + + + var uncaughtExceptionCount = 0; + var ___cxa_throw = (ptr, type, destructor) => { + var info = new ExceptionInfo(ptr); + // Initialize ExceptionInfo content after it was allocated in __cxa_allocate_exception. + info.init(type, destructor); + exceptionLast = ptr; + uncaughtExceptionCount++; + throw exceptionLast; + }; + ___cxa_throw.sig = 'vppp'; + var __Unwind_RaiseException = (ex) => { + err('Warning: _Unwind_RaiseException is not correctly implemented'); + return ___cxa_throw(ex, 0, 0); + }; + __Unwind_RaiseException.sig = 'ip'; + + var __Unwind_DeleteException = (ex) => err('TODO: Unwind_DeleteException'); + __Unwind_DeleteException.sig = 'vp'; + + + + + + var getDynCaller = (sig, ptr, promising = false) => { + return (...args) => dynCall(sig, ptr, args, promising); + }; + + + + + + + var _emscripten_exit_with_live_runtime = () => { + runtimeKeepalivePush(); + throw 'unwind'; + }; + _emscripten_exit_with_live_runtime.sig = 'v'; + + + + var _emscripten_force_exit = (status) => { + __emscripten_runtime_keepalive_clear(); + _exit(status); + }; + _emscripten_force_exit.sig = 'vi'; + + + var _emscripten_outn = (str, len) => out(UTF8ToString(str, len)); + _emscripten_outn.sig = 'vpp'; + + + var _emscripten_errn = (str, len) => err(UTF8ToString(str, len)); + _emscripten_errn.sig = 'vpp'; + + + + + + + var _emscripten_throw_number = (number) => { + throw number; + }; + _emscripten_throw_number.sig = 'vd'; + + var _emscripten_throw_string = (str) => { + throw UTF8ToString(str); + }; + _emscripten_throw_string.sig = 'vp'; + + + + + + + var _emscripten_runtime_keepalive_push = runtimeKeepalivePush; + _emscripten_runtime_keepalive_push.sig = 'v'; + + var _emscripten_runtime_keepalive_pop = runtimeKeepalivePop; + _emscripten_runtime_keepalive_pop.sig = 'v'; + + var _emscripten_runtime_keepalive_check = keepRuntimeAlive; + _emscripten_runtime_keepalive_check.sig = 'i'; + + + + + var asmjsMangle = (x) => { + if (x == '__main_argc_argv') { + x = 'main'; + } + return x.startsWith('dynCall_') ? x : '_' + x; + }; + + + + + + + + var __emscripten_fs_load_embedded_files = (ptr) => { + do { + var name_addr = HEAPU32[((ptr)>>2)]; + ptr += 4; + var len = HEAPU32[((ptr)>>2)]; + ptr += 4; + var content = HEAPU32[((ptr)>>2)]; + ptr += 4; + var name = UTF8ToString(name_addr) + FS.createPath('/', PATH.dirname(name), true, true); + // canOwn this data in the filesystem, it is a slice of wasm memory that will never change + FS.createDataFile(name, null, HEAP8.subarray(content, content + len), true, true, true); + } while (HEAPU32[((ptr)>>2)]); + }; + __emscripten_fs_load_embedded_files.sig = 'vp'; + + + + + + + + + + + + + var onInits = []; + + var addOnInit = (cb) => onInits.push(cb); + + + + var onMains = []; + + var addOnPreMain = (cb) => onMains.push(cb); + + var onExits = []; + + var addOnExit = (cb) => onExits.push(cb); + + + + var STACK_SIZE = 1048576; + + var STACK_ALIGN = 16; + + var POINTER_SIZE = 4; + + var ASSERTIONS = 0; + + + + + + /** + * @param {string=} returnType + * @param {Array=} argTypes + * @param {Object=} opts + */ + var cwrap = (ident, returnType, argTypes, opts) => { + // When the function takes numbers and returns a number, we can just return + // the original function + var numericArgs = !argTypes || argTypes.every((type) => type === 'number' || type === 'boolean'); + var numericRet = returnType !== 'string'; + if (numericRet && numericArgs && !opts) { + return getCFunc(ident); + } + return (...args) => ccall(ident, returnType, argTypes, args, opts); + }; + + + + + + + + + + + + + + + + var removeFunction = (index) => { + functionsInTableMap.delete(getWasmTableEntry(index)); + setWasmTableEntry(index, null); + freeTableIndexes.push(index); + }; + + + + var _emscripten_math_cbrt = Math.cbrt; + _emscripten_math_cbrt.sig = 'dd'; + + var _emscripten_math_pow = Math.pow; + _emscripten_math_pow.sig = 'ddd'; + + var _emscripten_math_random = Math.random; + _emscripten_math_random.sig = 'd'; + + var _emscripten_math_sign = Math.sign; + _emscripten_math_sign.sig = 'dd'; + + var _emscripten_math_sqrt = Math.sqrt; + _emscripten_math_sqrt.sig = 'dd'; + + var _emscripten_math_exp = Math.exp; + _emscripten_math_exp.sig = 'dd'; + + var _emscripten_math_expm1 = Math.expm1; + _emscripten_math_expm1.sig = 'dd'; + + var _emscripten_math_fmod = (x, y) => x % y; + _emscripten_math_fmod.sig = 'ddd'; + + var _emscripten_math_log = Math.log; + _emscripten_math_log.sig = 'dd'; + + var _emscripten_math_log1p = Math.log1p; + _emscripten_math_log1p.sig = 'dd'; + + var _emscripten_math_log10 = Math.log10; + _emscripten_math_log10.sig = 'dd'; + + var _emscripten_math_log2 = Math.log2; + _emscripten_math_log2.sig = 'dd'; + + var _emscripten_math_round = Math.round; + _emscripten_math_round.sig = 'dd'; + + var _emscripten_math_acos = Math.acos; + _emscripten_math_acos.sig = 'dd'; + + var _emscripten_math_acosh = Math.acosh; + _emscripten_math_acosh.sig = 'dd'; + + var _emscripten_math_asin = Math.asin; + _emscripten_math_asin.sig = 'dd'; + + var _emscripten_math_asinh = Math.asinh; + _emscripten_math_asinh.sig = 'dd'; + + var _emscripten_math_atan = Math.atan; + _emscripten_math_atan.sig = 'dd'; + + var _emscripten_math_atanh = Math.atanh; + _emscripten_math_atanh.sig = 'dd'; + + var _emscripten_math_atan2 = Math.atan2; + _emscripten_math_atan2.sig = 'ddd'; + + var _emscripten_math_cos = Math.cos; + _emscripten_math_cos.sig = 'dd'; + + var _emscripten_math_cosh = Math.cosh; + _emscripten_math_cosh.sig = 'dd'; + + var _emscripten_math_hypot = (count, varargs) => { + var args = []; + for (var i = 0; i < count; ++i) { + args.push(HEAPF64[(((varargs)+(i * 8))>>3)]); + } + return Math.hypot(...args); + }; + _emscripten_math_hypot.sig = 'dip'; + + var _emscripten_math_sin = Math.sin; + _emscripten_math_sin.sig = 'dd'; + + var _emscripten_math_sinh = Math.sinh; + _emscripten_math_sinh.sig = 'dd'; + + var _emscripten_math_tan = Math.tan; + _emscripten_math_tan.sig = 'dd'; + + var _emscripten_math_tanh = Math.tanh; + _emscripten_math_tanh.sig = 'dd'; + + + + + + + + + + + + var intArrayToString = (array) => { + var ret = []; + for (var i = 0; i < array.length; i++) { + var chr = array[i]; + if (chr > 0xFF) { + chr &= 0xFF; + } + ret.push(String.fromCharCode(chr)); + } + return ret.join(''); + }; + + var AsciiToString = (ptr) => { + var str = ''; + while (1) { + var ch = HEAPU8[ptr++]; + if (!ch) return str; + str += String.fromCharCode(ch); + } + }; + + + var UTF16Decoder = globalThis.TextDecoder ? new TextDecoder('utf-16le') : undefined;; + + + var UTF16ToString = (ptr, maxBytesToRead, ignoreNul) => { + var idx = ((ptr)>>1); + var endIdx = findStringEnd(HEAPU16, idx, maxBytesToRead / 2, ignoreNul); + + // When using conditional TextDecoder, skip it for short strings as the overhead of the native call is not worth it. + if (endIdx - idx > 16 && UTF16Decoder) + return UTF16Decoder.decode(HEAPU16.subarray(idx, endIdx)); + + // Fallback: decode without UTF16Decoder + var str = ''; + + // If maxBytesToRead is not passed explicitly, it will be undefined, and the + // for-loop's condition will always evaluate to true. The loop is then + // terminated on the first null char. + for (var i = idx; i < endIdx; ++i) { + var codeUnit = HEAPU16[i]; + // fromCharCode constructs a character from a UTF-16 code unit, so we can + // pass the UTF16 string right through. + str += String.fromCharCode(codeUnit); + } + + return str; + }; + + var stringToUTF16 = (str, outPtr, maxBytesToWrite) => { + // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. + maxBytesToWrite ??= 0x7FFFFFFF; + if (maxBytesToWrite < 2) return 0; + maxBytesToWrite -= 2; // Null terminator. + var startPtr = outPtr; + var numCharsToWrite = (maxBytesToWrite < str.length*2) ? (maxBytesToWrite / 2) : str.length; + for (var i = 0; i < numCharsToWrite; ++i) { + // charCodeAt returns a UTF-16 encoded code unit, so it can be directly written to the HEAP. + var codeUnit = str.charCodeAt(i); // possibly a lead surrogate + HEAP16[((outPtr)>>1)] = codeUnit; + outPtr += 2; + } + // Null-terminate the pointer to the HEAP. + HEAP16[((outPtr)>>1)] = 0; + return outPtr - startPtr; + }; + + var lengthBytesUTF16 = (str) => str.length*2; + + var UTF32ToString = (ptr, maxBytesToRead, ignoreNul) => { + var str = ''; + var startIdx = ((ptr)>>2); + // If maxBytesToRead is not passed explicitly, it will be undefined, and this + // will always evaluate to true. This saves on code size. + for (var i = 0; !(i >= maxBytesToRead / 4); i++) { + var utf32 = HEAPU32[startIdx + i]; + if (!utf32 && !ignoreNul) break; + str += String.fromCodePoint(utf32); + } + return str; + }; + + var stringToUTF32 = (str, outPtr, maxBytesToWrite) => { + // Backwards compatibility: if max bytes is not specified, assume unsafe unbounded write is allowed. + maxBytesToWrite ??= 0x7FFFFFFF; + if (maxBytesToWrite < 4) return 0; + var startPtr = outPtr; + var endPtr = startPtr + maxBytesToWrite - 4; + for (var i = 0; i < str.length; ++i) { + var codePoint = str.codePointAt(i); + // Gotcha: if codePoint is over 0xFFFF, it is represented as a surrogate pair in UTF-16. + // We need to manually skip over the second code unit for correct iteration. + if (codePoint > 0xFFFF) { + i++; + } + HEAP32[((outPtr)>>2)] = codePoint; + outPtr += 4; + if (outPtr + 4 > endPtr) break; + } + // Null-terminate the pointer to the HEAP. + HEAP32[((outPtr)>>2)] = 0; + return outPtr - startPtr; + }; + + var lengthBytesUTF32 = (str) => { + var len = 0; + for (var i = 0; i < str.length; ++i) { + var codePoint = str.codePointAt(i); + // Gotcha: if codePoint is over 0xFFFF, it is represented as a surrogate pair in UTF-16. + // We need to manually skip over the second code unit for correct iteration. + if (codePoint > 0xFFFF) { + i++; + } + len += 4; + } + + return len; + }; + + + + + var JSEvents = { + memcpy(target, src, size) { + HEAP8.set(HEAP8.subarray(src, src + size), target); + }, + removeAllEventListeners() { + while (JSEvents.eventHandlers.length) { + JSEvents._removeHandler(JSEvents.eventHandlers.length - 1); + } + JSEvents.deferredCalls = []; + }, + registerRemoveEventListeners() { + if (!JSEvents.removeEventListenersRegistered) { + addOnExit(JSEvents.removeAllEventListeners); + JSEvents.removeEventListenersRegistered = true; + } + }, + inEventHandler:0, + deferredCalls:[], + deferCall(targetFunction, precedence, argsList) { + function arraysHaveEqualContent(arrA, arrB) { + if (arrA.length != arrB.length) return false; + + for (var i in arrA) { + if (arrA[i] != arrB[i]) return false; + } + return true; + } + // Test if the given call was already queued, and if so, don't add it again. + for (var call of JSEvents.deferredCalls) { + if (call.targetFunction == targetFunction && arraysHaveEqualContent(call.argsList, argsList)) { + return; + } + } + JSEvents.deferredCalls.push({ + targetFunction, + precedence, + argsList + }); + + JSEvents.deferredCalls.sort((x,y) => x.precedence < y.precedence); + }, + removeDeferredCalls(targetFunction) { + JSEvents.deferredCalls = JSEvents.deferredCalls.filter((call) => call.targetFunction != targetFunction); + }, + canPerformEventHandlerRequests() { + if (navigator.userActivation) { + // Verify against transient activation status from UserActivation API + // whether it is possible to perform a request here without needing to defer. See + // https://developer.mozilla.org/en-US/docs/Web/Security/User_activation#transient_activation + // and https://caniuse.com/mdn-api_useractivation + // At the time of writing, Firefox does not support this API: https://bugzil.la/1791079 + return navigator.userActivation.isActive; + } + + return JSEvents.inEventHandler && JSEvents.currentEventHandler.allowsDeferredCalls; + }, + runDeferredCalls() { + if (!JSEvents.canPerformEventHandlerRequests()) { + return; + } + var deferredCalls = JSEvents.deferredCalls; + JSEvents.deferredCalls = []; + for (var call of deferredCalls) { + call.targetFunction(...call.argsList); + } + }, + eventHandlers:[], + removeAllHandlersOnTarget:(target, eventTypeString) => { + for (var i = 0; i < JSEvents.eventHandlers.length; ++i) { + if (JSEvents.eventHandlers[i].target == target && + (!eventTypeString || eventTypeString == JSEvents.eventHandlers[i].eventTypeString)) { + JSEvents._removeHandler(i--); + } + } + }, + _removeHandler(i) { + var h = JSEvents.eventHandlers[i]; + h.target.removeEventListener(h.eventTypeString, h.eventListenerFunc, h.useCapture); + JSEvents.eventHandlers.splice(i, 1); + }, + registerOrRemoveHandler(eventHandler) { + if (!eventHandler.target) { + return -4; + } + if (eventHandler.callbackfunc) { + eventHandler.eventListenerFunc = function(event) { + // Increment nesting count for the event handler. + ++JSEvents.inEventHandler; + JSEvents.currentEventHandler = eventHandler; + // Process any old deferred calls the user has placed. + JSEvents.runDeferredCalls(); + // Process the actual event, calls back to user C code handler. + eventHandler.handlerFunc(event); + // Process any new deferred calls that were placed right now from this event handler. + JSEvents.runDeferredCalls(); + // Out of event handler - restore nesting count. + --JSEvents.inEventHandler; + }; + + eventHandler.target.addEventListener(eventHandler.eventTypeString, + eventHandler.eventListenerFunc, + eventHandler.useCapture); + JSEvents.eventHandlers.push(eventHandler); + JSEvents.registerRemoveEventListeners(); + } else { + for (var i = 0; i < JSEvents.eventHandlers.length; ++i) { + if (JSEvents.eventHandlers[i].target == eventHandler.target + && JSEvents.eventHandlers[i].eventTypeString == eventHandler.eventTypeString) { + JSEvents._removeHandler(i--); + } + } + } + return 0; + }, + getNodeNameForTarget(target) { + if (!target) return ''; + if (target == window) return '#window'; + if (target == screen) return '#screen'; + return target?.nodeName || ''; + }, + fullscreenEnabled() { + return document.fullscreenEnabled + ; + }, + }; + + function getFullscreenElement() { + return document.fullscreenElement || document.mozFullScreenElement || + document.webkitFullscreenElement || document.webkitCurrentFullScreenElement || + document.msFullscreenElement; + } + + + + + var registerKeyEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + JSEvents.keyEvent ||= _malloc(160); + + var keyEventHandlerFunc = (e) => { + + var keyEventData = JSEvents.keyEvent; + HEAPF64[((keyEventData)>>3)] = e.timeStamp; + + var idx = ((keyEventData)>>2); + + HEAP32[idx + 2] = e.location; + HEAP8[keyEventData + 12] = e.ctrlKey; + HEAP8[keyEventData + 13] = e.shiftKey; + HEAP8[keyEventData + 14] = e.altKey; + HEAP8[keyEventData + 15] = e.metaKey; + HEAP8[keyEventData + 16] = e.repeat; + HEAP32[idx + 5] = e.charCode; + HEAP32[idx + 6] = e.keyCode; + HEAP32[idx + 7] = e.which; + stringToUTF8(e.key || '', keyEventData + 32, 32); + stringToUTF8(e.code || '', keyEventData + 64, 32); + stringToUTF8(e.char || '', keyEventData + 96, 32); + stringToUTF8(e.locale || '', keyEventData + 128, 32); + + if (((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(eventTypeId, keyEventData, userData)) e.preventDefault(); + }; + + var eventHandler = { + target: findEventTarget(target), + eventTypeString, + callbackfunc, + handlerFunc: keyEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + + + + + var _emscripten_set_keypress_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerKeyEventCallback(target, userData, useCapture, callbackfunc, 1, "keypress", targetThread); + _emscripten_set_keypress_callback_on_thread.sig = 'ippipp'; + + var _emscripten_set_keydown_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerKeyEventCallback(target, userData, useCapture, callbackfunc, 2, "keydown", targetThread); + _emscripten_set_keydown_callback_on_thread.sig = 'ippipp'; + + var _emscripten_set_keyup_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerKeyEventCallback(target, userData, useCapture, callbackfunc, 3, "keyup", targetThread); + _emscripten_set_keyup_callback_on_thread.sig = 'ippipp'; + + var getBoundingClientRect = (e) => specialHTMLTargets.indexOf(e) < 0 ? e.getBoundingClientRect() : {'left':0,'top':0}; + + var fillMouseEventData = (eventStruct, e, target) => { + HEAPF64[((eventStruct)>>3)] = e.timeStamp; + var idx = ((eventStruct)>>2); + HEAP32[idx + 2] = e.screenX; + HEAP32[idx + 3] = e.screenY; + HEAP32[idx + 4] = e.clientX; + HEAP32[idx + 5] = e.clientY; + HEAP8[eventStruct + 24] = e.ctrlKey; + HEAP8[eventStruct + 25] = e.shiftKey; + HEAP8[eventStruct + 26] = e.altKey; + HEAP8[eventStruct + 27] = e.metaKey; + HEAP16[idx*2 + 14] = e.button; + HEAP16[idx*2 + 15] = e.buttons; + + HEAP32[idx + 8] = e["movementX"]; + + HEAP32[idx + 9] = e["movementY"]; + + // Note: rect contains doubles (truncated to placate SAFE_HEAP, which is the same behaviour when writing to HEAP32 anyway) + var rect = getBoundingClientRect(target); + HEAP32[idx + 10] = e.clientX - (rect.left | 0); + HEAP32[idx + 11] = e.clientY - (rect.top | 0); + }; + + + + + var registerMouseEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + JSEvents.mouseEvent ||= _malloc(64); + target = findEventTarget(target); + + var mouseEventHandlerFunc = (e = event) => { + // TODO: Make this access thread safe, or this could update live while app is reading it. + fillMouseEventData(JSEvents.mouseEvent, e, target); + + if (((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(eventTypeId, JSEvents.mouseEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target, + allowsDeferredCalls: eventTypeString != 'mousemove' && eventTypeString != 'mouseenter' && eventTypeString != 'mouseleave', // Mouse move events do not allow fullscreen/pointer lock requests to be handled in them! + eventTypeString, + callbackfunc, + handlerFunc: mouseEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + var _emscripten_set_click_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerMouseEventCallback(target, userData, useCapture, callbackfunc, 4, "click", targetThread); + _emscripten_set_click_callback_on_thread.sig = 'ippipp'; + + var _emscripten_set_mousedown_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerMouseEventCallback(target, userData, useCapture, callbackfunc, 5, "mousedown", targetThread); + _emscripten_set_mousedown_callback_on_thread.sig = 'ippipp'; + + var _emscripten_set_mouseup_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerMouseEventCallback(target, userData, useCapture, callbackfunc, 6, "mouseup", targetThread); + _emscripten_set_mouseup_callback_on_thread.sig = 'ippipp'; + + var _emscripten_set_dblclick_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerMouseEventCallback(target, userData, useCapture, callbackfunc, 7, "dblclick", targetThread); + _emscripten_set_dblclick_callback_on_thread.sig = 'ippipp'; + + var _emscripten_set_mousemove_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerMouseEventCallback(target, userData, useCapture, callbackfunc, 8, "mousemove", targetThread); + _emscripten_set_mousemove_callback_on_thread.sig = 'ippipp'; + + var _emscripten_set_mouseenter_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerMouseEventCallback(target, userData, useCapture, callbackfunc, 33, "mouseenter", targetThread); + _emscripten_set_mouseenter_callback_on_thread.sig = 'ippipp'; + + var _emscripten_set_mouseleave_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerMouseEventCallback(target, userData, useCapture, callbackfunc, 34, "mouseleave", targetThread); + _emscripten_set_mouseleave_callback_on_thread.sig = 'ippipp'; + + var _emscripten_set_mouseover_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerMouseEventCallback(target, userData, useCapture, callbackfunc, 35, "mouseover", targetThread); + _emscripten_set_mouseover_callback_on_thread.sig = 'ippipp'; + + var _emscripten_set_mouseout_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerMouseEventCallback(target, userData, useCapture, callbackfunc, 36, "mouseout", targetThread); + _emscripten_set_mouseout_callback_on_thread.sig = 'ippipp'; + + var _emscripten_get_mouse_status = (mouseState) => { + if (!JSEvents.mouseEvent) return -7; + // HTML5 does not really have a polling API for mouse events, so implement one manually by + // returning the data from the most recently received event. This requires that user has registered + // at least some no-op function as an event handler to any of the mouse function. + JSEvents.memcpy(mouseState, JSEvents.mouseEvent, 64); + return 0; + }; + _emscripten_get_mouse_status.sig = 'ip'; + + + + var registerWheelEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + JSEvents.wheelEvent ||= _malloc(96); + + // The DOM Level 3 events spec event 'wheel' + var wheelHandlerFunc = (e = event) => { + var wheelEvent = JSEvents.wheelEvent; + fillMouseEventData(wheelEvent, e, target); + HEAPF64[(((wheelEvent)+(64))>>3)] = e["deltaX"]; + HEAPF64[(((wheelEvent)+(72))>>3)] = e["deltaY"]; + HEAPF64[(((wheelEvent)+(80))>>3)] = e["deltaZ"]; + HEAP32[(((wheelEvent)+(88))>>2)] = e["deltaMode"]; + if (((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(eventTypeId, wheelEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target, + allowsDeferredCalls: true, + eventTypeString, + callbackfunc, + handlerFunc: wheelHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + + var _emscripten_set_wheel_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => { + target = findEventTarget(target); + if (!target) return -4; + if (typeof target.onwheel != 'undefined') { + return registerWheelEventCallback(target, userData, useCapture, callbackfunc, 9, "wheel", targetThread); + } else { + return -1; + } + }; + _emscripten_set_wheel_callback_on_thread.sig = 'ippipp'; + + + + var registerUiEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + JSEvents.uiEvent ||= _malloc(36); + + target = findEventTarget(target); + + var uiEventHandlerFunc = (e = event) => { + if (e.target != target) { + // Never take ui events such as scroll via a 'bubbled' route, but always from the direct element that + // was targeted. Otherwise e.g. if app logs a message in response to a page scroll, the Emscripten log + // message box could cause to scroll, generating a new (bubbled) scroll message, causing a new log print, + // causing a new scroll, etc.. + return; + } + var b = document.body; // Take document.body to a variable, Closure compiler does not outline access to it on its own. + if (!b) { + // During a page unload 'body' can be null, with "Cannot read property 'clientWidth' of null" being thrown + return; + } + var uiEvent = JSEvents.uiEvent; + HEAP32[((uiEvent)>>2)] = 0; // always zero for resize and scroll + HEAP32[(((uiEvent)+(4))>>2)] = b.clientWidth; + HEAP32[(((uiEvent)+(8))>>2)] = b.clientHeight; + HEAP32[(((uiEvent)+(12))>>2)] = innerWidth; + HEAP32[(((uiEvent)+(16))>>2)] = innerHeight; + HEAP32[(((uiEvent)+(20))>>2)] = outerWidth; + HEAP32[(((uiEvent)+(24))>>2)] = outerHeight; + HEAP32[(((uiEvent)+(28))>>2)] = pageXOffset | 0; // scroll offsets are float + HEAP32[(((uiEvent)+(32))>>2)] = pageYOffset | 0; + if (((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(eventTypeId, uiEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target, + eventTypeString, + callbackfunc, + handlerFunc: uiEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + var _emscripten_set_resize_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerUiEventCallback(target, userData, useCapture, callbackfunc, 10, "resize", targetThread); + _emscripten_set_resize_callback_on_thread.sig = 'ippipp'; + + var _emscripten_set_scroll_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerUiEventCallback(target, userData, useCapture, callbackfunc, 11, "scroll", targetThread); + _emscripten_set_scroll_callback_on_thread.sig = 'ippipp'; + + + + + var registerFocusEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + JSEvents.focusEvent ||= _malloc(256); + + var focusEventHandlerFunc = (e = event) => { + var nodeName = JSEvents.getNodeNameForTarget(e.target); + var id = e.target.id ? e.target.id : ''; + + var focusEvent = JSEvents.focusEvent; + stringToUTF8(nodeName, focusEvent + 0, 128); + stringToUTF8(id, focusEvent + 128, 128); + + if (((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(eventTypeId, focusEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target: findEventTarget(target), + eventTypeString, + callbackfunc, + handlerFunc: focusEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + var _emscripten_set_blur_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerFocusEventCallback(target, userData, useCapture, callbackfunc, 12, "blur", targetThread); + _emscripten_set_blur_callback_on_thread.sig = 'ippipp'; + + var _emscripten_set_focus_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerFocusEventCallback(target, userData, useCapture, callbackfunc, 13, "focus", targetThread); + _emscripten_set_focus_callback_on_thread.sig = 'ippipp'; + + var _emscripten_set_focusin_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerFocusEventCallback(target, userData, useCapture, callbackfunc, 14, "focusin", targetThread); + _emscripten_set_focusin_callback_on_thread.sig = 'ippipp'; + + var _emscripten_set_focusout_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerFocusEventCallback(target, userData, useCapture, callbackfunc, 15, "focusout", targetThread); + _emscripten_set_focusout_callback_on_thread.sig = 'ippipp'; + + var fillDeviceOrientationEventData = (eventStruct, e, target) => { + HEAPF64[((eventStruct)>>3)] = e.alpha; + HEAPF64[(((eventStruct)+(8))>>3)] = e.beta; + HEAPF64[(((eventStruct)+(16))>>3)] = e.gamma; + HEAP8[(eventStruct)+(24)] = e.absolute; + }; + + + + var registerDeviceOrientationEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + JSEvents.deviceOrientationEvent ||= _malloc(32); + + var deviceOrientationEventHandlerFunc = (e = event) => { + fillDeviceOrientationEventData(JSEvents.deviceOrientationEvent, e, target); // TODO: Thread-safety with respect to emscripten_get_deviceorientation_status() + + if (((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(eventTypeId, JSEvents.deviceOrientationEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target: findEventTarget(target), + eventTypeString, + callbackfunc, + handlerFunc: deviceOrientationEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + var _emscripten_set_deviceorientation_callback_on_thread = (userData, useCapture, callbackfunc, targetThread) => { + return registerDeviceOrientationEventCallback(2, userData, useCapture, callbackfunc, 16, "deviceorientation", targetThread); + }; + _emscripten_set_deviceorientation_callback_on_thread.sig = 'ipipp'; + + var _emscripten_get_deviceorientation_status = (orientationState) => { + if (!JSEvents.deviceOrientationEvent) return -7; + // HTML5 does not really have a polling API for device orientation events, so implement one manually by + // returning the data from the most recently received event. This requires that user has registered + // at least some no-op function as an event handler. + JSEvents.memcpy(orientationState, JSEvents.deviceOrientationEvent, 32); + return 0; + }; + _emscripten_get_deviceorientation_status.sig = 'ip'; + + var fillDeviceMotionEventData = (eventStruct, e, target) => { + var supportedFields = 0; + var a = e['acceleration']; + supportedFields |= a && 1; + var ag = e['accelerationIncludingGravity']; + supportedFields |= ag && 2; + var rr = e['rotationRate']; + supportedFields |= rr && 4; + a = a || {}; + ag = ag || {}; + rr = rr || {}; + HEAP32[(((eventStruct)+(72))>>2)] = supportedFields; + HEAPF64[((eventStruct)>>3)] = a["x"]; + HEAPF64[(((eventStruct)+(8))>>3)] = a["y"]; + HEAPF64[(((eventStruct)+(16))>>3)] = a["z"]; + HEAPF64[(((eventStruct)+(24))>>3)] = ag["x"]; + HEAPF64[(((eventStruct)+(32))>>3)] = ag["y"]; + HEAPF64[(((eventStruct)+(40))>>3)] = ag["z"]; + HEAPF64[(((eventStruct)+(48))>>3)] = rr["alpha"]; + HEAPF64[(((eventStruct)+(56))>>3)] = rr["beta"]; + HEAPF64[(((eventStruct)+(64))>>3)] = rr["gamma"]; + }; + + + + + var registerDeviceMotionEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + JSEvents.deviceMotionEvent ||= _malloc(80); + + var deviceMotionEventHandlerFunc = (e = event) => { + fillDeviceMotionEventData(JSEvents.deviceMotionEvent, e, target); // TODO: Thread-safety with respect to emscripten_get_devicemotion_status() + + if (((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(eventTypeId, JSEvents.deviceMotionEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target: findEventTarget(target), + eventTypeString, + callbackfunc, + handlerFunc: deviceMotionEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + var _emscripten_set_devicemotion_callback_on_thread = (userData, useCapture, callbackfunc, targetThread) => + registerDeviceMotionEventCallback(2, userData, useCapture, callbackfunc, 17, "devicemotion", targetThread); + _emscripten_set_devicemotion_callback_on_thread.sig = 'ipipp'; + + var _emscripten_get_devicemotion_status = (motionState) => { + if (!JSEvents.deviceMotionEvent) return -7; + // HTML5 does not really have a polling API for device motion events, so implement one manually by + // returning the data from the most recently received event. This requires that user has registered + // at least some no-op function as an event handler. + JSEvents.memcpy(motionState, JSEvents.deviceMotionEvent, 80); + return 0; + }; + _emscripten_get_devicemotion_status.sig = 'ip'; + + var screenOrientation = () => { + if (!window.screen) return undefined; + return screen.orientation || screen['mozOrientation'] || screen['webkitOrientation']; + }; + + var fillOrientationChangeEventData = (eventStruct) => { + // OrientationType enum + var orientationsType1 = ['portrait-primary', 'portrait-secondary', 'landscape-primary', 'landscape-secondary']; + // alternative selection from OrientationLockType enum + var orientationsType2 = ['portrait', 'portrait', 'landscape', 'landscape']; + + var orientationIndex = 0; + var orientationAngle = 0; + var screenOrientObj = screenOrientation(); + if (typeof screenOrientObj === 'object') { + orientationIndex = orientationsType1.indexOf(screenOrientObj.type); + if (orientationIndex < 0) { + orientationIndex = orientationsType2.indexOf(screenOrientObj.type); + } + if (orientationIndex >= 0) { + orientationIndex = 1 << orientationIndex; + } + orientationAngle = screenOrientObj.angle; + } + + HEAP32[((eventStruct)>>2)] = orientationIndex; + HEAP32[(((eventStruct)+(4))>>2)] = orientationAngle; + }; + + + + var registerOrientationChangeEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + JSEvents.orientationChangeEvent ||= _malloc(8); + + var orientationChangeEventHandlerFunc = (e = event) => { + var orientationChangeEvent = JSEvents.orientationChangeEvent; + + fillOrientationChangeEventData(orientationChangeEvent); + + if (((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(eventTypeId, orientationChangeEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target, + eventTypeString, + callbackfunc, + handlerFunc: orientationChangeEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + var _emscripten_set_orientationchange_callback_on_thread = (userData, useCapture, callbackfunc, targetThread) => { + if (!window.screen || !screen.orientation) return -1; + return registerOrientationChangeEventCallback(screen.orientation, userData, useCapture, callbackfunc, 18, 'change', targetThread); + }; + _emscripten_set_orientationchange_callback_on_thread.sig = 'ipipp'; + + + var _emscripten_get_orientation_status = (orientationChangeEvent) => { + // screenOrientation() resolving standard, window.orientation being the deprecated mobile-only + if (!screenOrientation() && typeof orientation == 'undefined') return -1; + fillOrientationChangeEventData(orientationChangeEvent); + return 0; + }; + _emscripten_get_orientation_status.sig = 'ip'; + + var _emscripten_lock_orientation = (allowedOrientations) => { + var orientations = []; + if (allowedOrientations & 1) orientations.push("portrait-primary"); + if (allowedOrientations & 2) orientations.push("portrait-secondary"); + if (allowedOrientations & 4) orientations.push("landscape-primary"); + if (allowedOrientations & 8) orientations.push("landscape-secondary"); + var succeeded; + if (screen.lockOrientation) { + succeeded = screen.lockOrientation(orientations); + } else if (screen.mozLockOrientation) { + succeeded = screen.mozLockOrientation(orientations); + } else if (screen.webkitLockOrientation) { + succeeded = screen.webkitLockOrientation(orientations); + } else { + return -1; + } + if (succeeded) { + return 0; + } + return -6; + }; + _emscripten_lock_orientation.sig = 'ii'; + + var _emscripten_unlock_orientation = () => { + if (screen.unlockOrientation) { + screen.unlockOrientation(); + } else if (screen.mozUnlockOrientation) { + screen.mozUnlockOrientation(); + } else if (screen.webkitUnlockOrientation) { + screen.webkitUnlockOrientation(); + } else { + return -1; + } + return 0; + }; + _emscripten_unlock_orientation.sig = 'i'; + + + + var fillFullscreenChangeEventData = (eventStruct) => { + var fullscreenElement = getFullscreenElement(); + var isFullscreen = !!fullscreenElement; + // Assigning a boolean to HEAP32 with expected type coercion. + /** @suppress{checkTypes} */ + HEAP8[eventStruct] = isFullscreen; + HEAP8[(eventStruct)+(1)] = JSEvents.fullscreenEnabled(); + // If transitioning to fullscreen, report info about the element that is now fullscreen. + // If transitioning to windowed mode, report info about the element that just was fullscreen. + var reportedElement = isFullscreen ? fullscreenElement : JSEvents.previousFullscreenElement; + var nodeName = JSEvents.getNodeNameForTarget(reportedElement); + var id = reportedElement?.id || ''; + stringToUTF8(nodeName, eventStruct + 2, 128); + stringToUTF8(id, eventStruct + 130, 128); + HEAP32[(((eventStruct)+(260))>>2)] = reportedElement ? reportedElement.clientWidth : 0; + HEAP32[(((eventStruct)+(264))>>2)] = reportedElement ? reportedElement.clientHeight : 0; + HEAP32[(((eventStruct)+(268))>>2)] = screen.width; + HEAP32[(((eventStruct)+(272))>>2)] = screen.height; + if (isFullscreen) { + JSEvents.previousFullscreenElement = fullscreenElement; + } + }; + + + + var registerFullscreenChangeEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + JSEvents.fullscreenChangeEvent ||= _malloc(276); + + var fullscreenChangeEventhandlerFunc = (e = event) => { + var fullscreenChangeEvent = JSEvents.fullscreenChangeEvent; + + fillFullscreenChangeEventData(fullscreenChangeEvent); + + if (((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(eventTypeId, fullscreenChangeEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target, + eventTypeString, + callbackfunc, + handlerFunc: fullscreenChangeEventhandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + + + var _emscripten_set_fullscreenchange_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => { + if (!JSEvents.fullscreenEnabled()) return -1; + target = findEventTarget(target); + if (!target) return -4; + + return registerFullscreenChangeEventCallback(target, userData, useCapture, callbackfunc, 19, "fullscreenchange", targetThread); + }; + _emscripten_set_fullscreenchange_callback_on_thread.sig = 'ippipp'; + + + var _emscripten_get_fullscreen_status = (fullscreenStatus) => { + if (!JSEvents.fullscreenEnabled()) return -1; + fillFullscreenChangeEventData(fullscreenStatus); + return 0; + }; + _emscripten_get_fullscreen_status.sig = 'ip'; + + + var _emscripten_get_canvas_element_size = (target, width, height) => { + var canvas = findCanvasEventTarget(target); + if (!canvas) return -4; + HEAP32[((width)>>2)] = canvas.width; + HEAP32[((height)>>2)] = canvas.height; + }; + _emscripten_get_canvas_element_size.sig = 'ippp'; + + + + var getCanvasElementSize = (target) => { + var sp = stackSave(); + var w = stackAlloc(8); + var h = w + 4; + + var targetInt = stringToUTF8OnStack(target.id); + var ret = _emscripten_get_canvas_element_size(targetInt, w, h); + var size = [HEAP32[((w)>>2)], HEAP32[((h)>>2)]]; + stackRestore(sp); + return size; + }; + + + + + var setCanvasElementSize = (target, width, height) => { + if (!target.controlTransferredOffscreen) { + target.width = width; + target.height = height; + } else { + // This function is being called from high-level JavaScript code instead of asm.js/Wasm, + // and it needs to synchronously proxy over to another thread, so marshal the string onto the heap to do the call. + var sp = stackSave(); + var targetInt = stringToUTF8OnStack(target.id); + _emscripten_set_canvas_element_size(targetInt, width, height); + stackRestore(sp); + } + }; + + var currentFullscreenStrategy = { + }; + var registerRestoreOldStyle = (canvas) => { + var canvasSize = getCanvasElementSize(canvas); + var oldWidth = canvasSize[0]; + var oldHeight = canvasSize[1]; + var oldCssWidth = canvas.style.width; + var oldCssHeight = canvas.style.height; + var oldBackgroundColor = canvas.style.backgroundColor; // Chrome reads color from here. + var oldDocumentBackgroundColor = document.body.style.backgroundColor; // IE11 reads color from here. + // Firefox always has black background color. + var oldPaddingLeft = canvas.style.paddingLeft; // Chrome, FF, Safari + var oldPaddingRight = canvas.style.paddingRight; + var oldPaddingTop = canvas.style.paddingTop; + var oldPaddingBottom = canvas.style.paddingBottom; + var oldMarginLeft = canvas.style.marginLeft; // IE11 + var oldMarginRight = canvas.style.marginRight; + var oldMarginTop = canvas.style.marginTop; + var oldMarginBottom = canvas.style.marginBottom; + var oldDocumentBodyMargin = document.body.style.margin; + var oldDocumentOverflow = document.documentElement.style.overflow; // Chrome, Firefox + var oldDocumentScroll = document.body.scroll; // IE + var oldImageRendering = canvas.style.imageRendering; + + function restoreOldStyle() { + if (!getFullscreenElement()) { + document.removeEventListener('fullscreenchange', restoreOldStyle); + + setCanvasElementSize(canvas, oldWidth, oldHeight); + + canvas.style.width = oldCssWidth; + canvas.style.height = oldCssHeight; + canvas.style.backgroundColor = oldBackgroundColor; // Chrome + // IE11 hack: assigning 'undefined' or an empty string to document.body.style.backgroundColor has no effect, so first assign back the default color + // before setting the undefined value. Setting undefined value is also important, or otherwise we would later treat that as something that the user + // had explicitly set so subsequent fullscreen transitions would not set background color properly. + if (!oldDocumentBackgroundColor) document.body.style.backgroundColor = 'white'; + document.body.style.backgroundColor = oldDocumentBackgroundColor; // IE11 + canvas.style.paddingLeft = oldPaddingLeft; // Chrome, FF, Safari + canvas.style.paddingRight = oldPaddingRight; + canvas.style.paddingTop = oldPaddingTop; + canvas.style.paddingBottom = oldPaddingBottom; + canvas.style.marginLeft = oldMarginLeft; // IE11 + canvas.style.marginRight = oldMarginRight; + canvas.style.marginTop = oldMarginTop; + canvas.style.marginBottom = oldMarginBottom; + document.body.style.margin = oldDocumentBodyMargin; + document.documentElement.style.overflow = oldDocumentOverflow; // Chrome, Firefox + document.body.scroll = oldDocumentScroll; // IE + canvas.style.imageRendering = oldImageRendering; + if (canvas.GLctxObject) canvas.GLctxObject.GLctx.viewport(0, 0, oldWidth, oldHeight); + + if (currentFullscreenStrategy.canvasResizedCallback) { + ((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData); + } + } + } + document.addEventListener('fullscreenchange', restoreOldStyle); + return restoreOldStyle; + }; + + + var setLetterbox = (element, topBottom, leftRight) => { + // Cannot use margin to specify letterboxes in FF or Chrome, since those ignore margins in fullscreen mode. + element.style.paddingLeft = element.style.paddingRight = leftRight + 'px'; + element.style.paddingTop = element.style.paddingBottom = topBottom + 'px'; + }; + + + var JSEvents_resizeCanvasForFullscreen = (target, strategy) => { + var restoreOldStyle = registerRestoreOldStyle(target); + var cssWidth = strategy.softFullscreen ? innerWidth : screen.width; + var cssHeight = strategy.softFullscreen ? innerHeight : screen.height; + var rect = getBoundingClientRect(target); + var windowedCssWidth = rect.width; + var windowedCssHeight = rect.height; + var canvasSize = getCanvasElementSize(target); + var windowedRttWidth = canvasSize[0]; + var windowedRttHeight = canvasSize[1]; + + if (strategy.scaleMode == 3) { + setLetterbox(target, (cssHeight - windowedCssHeight) / 2, (cssWidth - windowedCssWidth) / 2); + cssWidth = windowedCssWidth; + cssHeight = windowedCssHeight; + } else if (strategy.scaleMode == 2) { + if (cssWidth*windowedRttHeight < windowedRttWidth*cssHeight) { + var desiredCssHeight = windowedRttHeight * cssWidth / windowedRttWidth; + setLetterbox(target, (cssHeight - desiredCssHeight) / 2, 0); + cssHeight = desiredCssHeight; + } else { + var desiredCssWidth = windowedRttWidth * cssHeight / windowedRttHeight; + setLetterbox(target, 0, (cssWidth - desiredCssWidth) / 2); + cssWidth = desiredCssWidth; + } + } + + // If we are adding padding, must choose a background color or otherwise Chrome will give the + // padding a default white color. Do it only if user has not customized their own background color. + target.style.backgroundColor ||= 'black'; + // IE11 does the same, but requires the color to be set in the document body. + document.body.style.backgroundColor ||= 'black'; // IE11 + // Firefox always shows black letterboxes independent of style color. + + target.style.width = cssWidth + 'px'; + target.style.height = cssHeight + 'px'; + + if (strategy.filteringMode == 1) { + target.style.imageRendering = 'optimizeSpeed'; + target.style.imageRendering = '-moz-crisp-edges'; + target.style.imageRendering = '-o-crisp-edges'; + target.style.imageRendering = '-webkit-optimize-contrast'; + target.style.imageRendering = 'optimize-contrast'; + target.style.imageRendering = 'crisp-edges'; + target.style.imageRendering = 'pixelated'; + } + + var dpiScale = (strategy.canvasResolutionScaleMode == 2) ? devicePixelRatio : 1; + if (strategy.canvasResolutionScaleMode != 0) { + var newWidth = (cssWidth * dpiScale)|0; + var newHeight = (cssHeight * dpiScale)|0; + setCanvasElementSize(target, newWidth, newHeight); + if (target.GLctxObject) target.GLctxObject.GLctx.viewport(0, 0, newWidth, newHeight); + } + return restoreOldStyle; + }; + var JSEvents_requestFullscreen = (target, strategy) => { + // EMSCRIPTEN_FULLSCREEN_SCALE_DEFAULT + EMSCRIPTEN_FULLSCREEN_CANVAS_SCALE_NONE is a mode where no extra logic is performed to the DOM elements. + if (strategy.scaleMode != 0 || strategy.canvasResolutionScaleMode != 0) { + JSEvents_resizeCanvasForFullscreen(target, strategy); + } + + if (target.requestFullscreen) { + target.requestFullscreen(); + } else { + return JSEvents.fullscreenEnabled() ? -3 : -1; + } + + currentFullscreenStrategy = strategy; + + if (strategy.canvasResizedCallback) { + ((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(37, 0, strategy.canvasResizedCallbackUserData); + } + + return 0; + }; + + + + var hideEverythingExceptGivenElement = (onlyVisibleElement) => { + var child = onlyVisibleElement; + var parent = child.parentNode; + var hiddenElements = []; + while (child != document.body) { + var children = parent.children; + for (var currChild of children) { + if (currChild != child) { + hiddenElements.push({ node: currChild, displayState: currChild.style.display }); + currChild.style.display = 'none'; + } + } + child = parent; + parent = parent.parentNode; + } + return hiddenElements; + }; + + var restoreHiddenElements = (hiddenElements) => { + for (var elem of hiddenElements) { + elem.node.style.display = elem.displayState; + } + }; + + + + var restoreOldWindowedStyle = null; + + + + + + var softFullscreenResizeWebGLRenderTarget = () => { + var dpr = devicePixelRatio; + var inHiDPIFullscreenMode = currentFullscreenStrategy.canvasResolutionScaleMode == 2; + var inAspectRatioFixedFullscreenMode = currentFullscreenStrategy.scaleMode == 2; + var inPixelPerfectFullscreenMode = currentFullscreenStrategy.canvasResolutionScaleMode != 0; + var inCenteredWithoutScalingFullscreenMode = currentFullscreenStrategy.scaleMode == 3; + var screenWidth = inHiDPIFullscreenMode ? Math.round(innerWidth*dpr) : innerWidth; + var screenHeight = inHiDPIFullscreenMode ? Math.round(innerHeight*dpr) : innerHeight; + var w = screenWidth; + var h = screenHeight; + var canvas = currentFullscreenStrategy.target; + var canvasSize = getCanvasElementSize(canvas); + var x = canvasSize[0]; + var y = canvasSize[1]; + var topMargin; + + if (inAspectRatioFixedFullscreenMode) { + if (w*y < x*h) h = (w * y / x) | 0; + else if (w*y > x*h) w = (h * x / y) | 0; + topMargin = ((screenHeight - h) / 2) | 0; + } + + if (inPixelPerfectFullscreenMode) { + setCanvasElementSize(canvas, w, h); + if (canvas.GLctxObject) canvas.GLctxObject.GLctx.viewport(0, 0, w, h); + } + + // Back to CSS pixels. + if (inHiDPIFullscreenMode) { + topMargin /= dpr; + w /= dpr; + h /= dpr; + // Round to nearest 4 digits of precision. + w = Math.round(w*1e4)/1e4; + h = Math.round(h*1e4)/1e4; + topMargin = Math.round(topMargin*1e4)/1e4; + } + + if (inCenteredWithoutScalingFullscreenMode) { + var t = (innerHeight - jstoi_q(canvas.style.height)) / 2; + var b = (innerWidth - jstoi_q(canvas.style.width)) / 2; + setLetterbox(canvas, t, b); + } else { + canvas.style.width = w + 'px'; + canvas.style.height = h + 'px'; + var b = (innerWidth - w) / 2; + setLetterbox(canvas, topMargin, b); + } + + if (!inCenteredWithoutScalingFullscreenMode && currentFullscreenStrategy.canvasResizedCallback) { + ((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(37, 0, currentFullscreenStrategy.canvasResizedCallbackUserData); + } + }; + + + + var doRequestFullscreen = (target, strategy) => { + if (!JSEvents.fullscreenEnabled()) return -1; + target = findEventTarget(target); + if (!target) return -4; + + if (!target.requestFullscreen + ) { + return -3; + } + + // Queue this function call if we're not currently in an event handler and + // the user saw it appropriate to do so. + if (!JSEvents.canPerformEventHandlerRequests()) { + if (strategy.deferUntilInEventHandler) { + JSEvents.deferCall(JSEvents_requestFullscreen, 1 /* priority over pointer lock */, [target, strategy]); + return 1; + } + return -2; + } + + return JSEvents_requestFullscreen(target, strategy); + }; + + var _emscripten_request_fullscreen = (target, deferUntilInEventHandler) => { + var strategy = { + // These options perform no added logic, but just bare request fullscreen. + scaleMode: 0, + canvasResolutionScaleMode: 0, + filteringMode: 0, + deferUntilInEventHandler, + canvasResizedCallbackTargetThread: 2 + }; + return doRequestFullscreen(target, strategy); + }; + _emscripten_request_fullscreen.sig = 'ipi'; + + var _emscripten_request_fullscreen_strategy = (target, deferUntilInEventHandler, fullscreenStrategy) => { + var strategy = { + scaleMode: HEAP32[((fullscreenStrategy)>>2)], + canvasResolutionScaleMode: HEAP32[(((fullscreenStrategy)+(4))>>2)], + filteringMode: HEAP32[(((fullscreenStrategy)+(8))>>2)], + deferUntilInEventHandler, + canvasResizedCallback: HEAP32[(((fullscreenStrategy)+(12))>>2)], + canvasResizedCallbackUserData: HEAP32[(((fullscreenStrategy)+(16))>>2)] + }; + + return doRequestFullscreen(target, strategy); + }; + _emscripten_request_fullscreen_strategy.sig = 'ipip'; + + + + + + + + + var _emscripten_enter_soft_fullscreen = (target, fullscreenStrategy) => { + target = findEventTarget(target); + if (!target) return -4; + + var strategy = { + scaleMode: HEAP32[((fullscreenStrategy)>>2)], + canvasResolutionScaleMode: HEAP32[(((fullscreenStrategy)+(4))>>2)], + filteringMode: HEAP32[(((fullscreenStrategy)+(8))>>2)], + canvasResizedCallback: HEAP32[(((fullscreenStrategy)+(12))>>2)], + canvasResizedCallbackUserData: HEAP32[(((fullscreenStrategy)+(16))>>2)], + target, + softFullscreen: true + }; + + var restoreOldStyle = JSEvents_resizeCanvasForFullscreen(target, strategy); + + document.documentElement.style.overflow = 'hidden'; // Firefox, Chrome + document.body.scroll = "no"; // IE11 + document.body.style.margin = '0px'; // Override default document margin area on all browsers. + + var hiddenElements = hideEverythingExceptGivenElement(target); + + function restoreWindowedState() { + restoreOldStyle(); + restoreHiddenElements(hiddenElements); + removeEventListener('resize', softFullscreenResizeWebGLRenderTarget); + if (strategy.canvasResizedCallback) { + ((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(37, 0, strategy.canvasResizedCallbackUserData); + } + currentFullscreenStrategy = 0; + } + restoreOldWindowedStyle = restoreWindowedState; + currentFullscreenStrategy = strategy; + addEventListener('resize', softFullscreenResizeWebGLRenderTarget); + + // Inform the caller that the canvas size has changed. + if (strategy.canvasResizedCallback) { + ((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(37, 0, strategy.canvasResizedCallbackUserData); + } + + return 0; + }; + _emscripten_enter_soft_fullscreen.sig = 'ipp'; + + var _emscripten_exit_soft_fullscreen = () => { + restoreOldWindowedStyle?.(); + restoreOldWindowedStyle = null; + + return 0; + }; + _emscripten_exit_soft_fullscreen.sig = 'i'; + + + + var _emscripten_exit_fullscreen = () => { + if (!JSEvents.fullscreenEnabled()) return -1; + // Make sure no queued up calls will fire after this. + JSEvents.removeDeferredCalls(JSEvents_requestFullscreen); + + var d = specialHTMLTargets[1]; + if (d.exitFullscreen) { + d.fullscreenElement && d.exitFullscreen(); + } else { + return -1; + } + + return 0; + }; + _emscripten_exit_fullscreen.sig = 'i'; + + + var fillPointerlockChangeEventData = (eventStruct) => { + var pointerLockElement = document.pointerLockElement; + var isPointerlocked = !!pointerLockElement; + // Assigning a boolean to HEAP32 with expected type coercion. + /** @suppress{checkTypes} */ + HEAP8[eventStruct] = isPointerlocked; + var nodeName = JSEvents.getNodeNameForTarget(pointerLockElement); + var id = pointerLockElement?.id || ''; + stringToUTF8(nodeName, eventStruct + 1, 128); + stringToUTF8(id, eventStruct + 129, 128); + }; + + + + var registerPointerlockChangeEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + JSEvents.pointerlockChangeEvent ||= _malloc(257); + + var pointerlockChangeEventHandlerFunc = (e = event) => { + var pointerlockChangeEvent = JSEvents.pointerlockChangeEvent; + fillPointerlockChangeEventData(pointerlockChangeEvent); + + if (((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(eventTypeId, pointerlockChangeEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target, + eventTypeString, + callbackfunc, + handlerFunc: pointerlockChangeEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + + var _emscripten_set_pointerlockchange_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => { + if (!document.body?.requestPointerLock) { + return -1; + } + + target = findEventTarget(target); + if (!target) return -4; + return registerPointerlockChangeEventCallback(target, userData, useCapture, callbackfunc, 20, "pointerlockchange", targetThread); + }; + _emscripten_set_pointerlockchange_callback_on_thread.sig = 'ippipp'; + + var registerPointerlockErrorEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + + var pointerlockErrorEventHandlerFunc = (e = event) => { + if (((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(eventTypeId, 0, userData)) e.preventDefault(); + }; + + var eventHandler = { + target, + eventTypeString, + callbackfunc, + handlerFunc: pointerlockErrorEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + + var _emscripten_set_pointerlockerror_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => { + if (!document.body?.requestPointerLock) { + return -1; + } + + target = findEventTarget(target); + + if (!target) return -4; + return registerPointerlockErrorEventCallback(target, userData, useCapture, callbackfunc, 38, "pointerlockerror", targetThread); + }; + _emscripten_set_pointerlockerror_callback_on_thread.sig = 'ippipp'; + + var _emscripten_get_pointerlock_status = (pointerlockStatus) => { + if (pointerlockStatus) fillPointerlockChangeEventData(pointerlockStatus); + if (!document.body?.requestPointerLock) { + return -1; + } + return 0; + }; + _emscripten_get_pointerlock_status.sig = 'ip'; + + var requestPointerLock = (target) => { + if (target.requestPointerLock) { + target.requestPointerLock(); + } else { + // document.body is known to accept pointer lock, so use that to differentiate if the user passed a bad element, + // or if the whole browser just doesn't support the feature. + if (document.body.requestPointerLock) { + return -3; + } + return -1; + } + return 0; + }; + + + + var _emscripten_request_pointerlock = (target, deferUntilInEventHandler) => { + target = findEventTarget(target); + if (!target) return -4; + if (!target.requestPointerLock) { + return -1; + } + + // Queue this function call if we're not currently in an event handler and + // the user saw it appropriate to do so. + if (!JSEvents.canPerformEventHandlerRequests()) { + if (deferUntilInEventHandler) { + JSEvents.deferCall(requestPointerLock, 2 /* priority below fullscreen */, [target]); + return 1; + } + return -2; + } + + return requestPointerLock(target); + }; + _emscripten_request_pointerlock.sig = 'ipi'; + + + var _emscripten_exit_pointerlock = () => { + // Make sure no queued up calls will fire after this. + JSEvents.removeDeferredCalls(requestPointerLock); + if (!document.exitPointerLock) return -1; + document.exitPointerLock(); + return 0; + }; + _emscripten_exit_pointerlock.sig = 'i'; + + var _emscripten_vibrate = (msecs) => { + if (!navigator.vibrate) return -1; + navigator.vibrate(msecs); + return 0; + }; + _emscripten_vibrate.sig = 'ii'; + + var _emscripten_vibrate_pattern = (msecsArray, numEntries) => { + if (!navigator.vibrate) return -1; + + var vibrateList = []; + for (var i = 0; i < numEntries; ++i) { + var msecs = HEAP32[(((msecsArray)+(i*4))>>2)]; + vibrateList.push(msecs); + } + navigator.vibrate(vibrateList); + return 0; + }; + _emscripten_vibrate_pattern.sig = 'ipi'; + + var fillVisibilityChangeEventData = (eventStruct) => { + var visibilityStates = [ "hidden", "visible", "prerender", "unloaded" ]; + var visibilityState = visibilityStates.indexOf(document.visibilityState); + + // Assigning a boolean to HEAP32 with expected type coercion. + /** @suppress{checkTypes} */ + HEAP8[eventStruct] = document.hidden; + HEAP32[(((eventStruct)+(4))>>2)] = visibilityState; + }; + + + + var registerVisibilityChangeEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + JSEvents.visibilityChangeEvent ||= _malloc(8); + + var visibilityChangeEventHandlerFunc = (e = event) => { + var visibilityChangeEvent = JSEvents.visibilityChangeEvent; + + fillVisibilityChangeEventData(visibilityChangeEvent); + + if (((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(eventTypeId, visibilityChangeEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target, + eventTypeString, + callbackfunc, + handlerFunc: visibilityChangeEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + + var _emscripten_set_visibilitychange_callback_on_thread = (userData, useCapture, callbackfunc, targetThread) => { + if (!specialHTMLTargets[1]) { + return -4; + } + return registerVisibilityChangeEventCallback(specialHTMLTargets[1], userData, useCapture, callbackfunc, 21, "visibilitychange", targetThread); + }; + _emscripten_set_visibilitychange_callback_on_thread.sig = 'ipipp'; + + var _emscripten_get_visibility_status = (visibilityStatus) => { + if (typeof document.visibilityState == 'undefined' && typeof document.hidden == 'undefined') { + return -1; + } + fillVisibilityChangeEventData(visibilityStatus); + return 0; + }; + _emscripten_get_visibility_status.sig = 'ip'; + + + + + var registerTouchEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + JSEvents.touchEvent ||= _malloc(1552); + + target = findEventTarget(target); + + var touchEventHandlerFunc = (e) => { + var t, touches = {}, et = e.touches; + // To ease marshalling different kinds of touches that browser reports (all touches are listed in e.touches, + // only changed touches in e.changedTouches, and touches on target at a.targetTouches), mark a boolean in + // each Touch object so that we can later loop only once over all touches we see to marshall over to Wasm. + + for (let t of et) { + // Browser might recycle the generated Touch objects between each frame (Firefox on Android), so reset any + // changed/target states we may have set from previous frame. + t.isChanged = t.onTarget = 0; + touches[t.identifier] = t; + } + // Mark which touches are part of the changedTouches list. + for (let t of e.changedTouches) { + t.isChanged = 1; + touches[t.identifier] = t; + } + // Mark which touches are part of the targetTouches list. + for (let t of e.targetTouches) { + touches[t.identifier].onTarget = 1; + } + + var touchEvent = JSEvents.touchEvent; + HEAPF64[((touchEvent)>>3)] = e.timeStamp; + HEAP8[touchEvent + 12] = e.ctrlKey; + HEAP8[touchEvent + 13] = e.shiftKey; + HEAP8[touchEvent + 14] = e.altKey; + HEAP8[touchEvent + 15] = e.metaKey; + var idx = touchEvent + 16; + var targetRect = getBoundingClientRect(target); + var numTouches = 0; + for (let t of Object.values(touches)) { + var idx32 = ((idx)>>2); // Pre-shift the ptr to index to HEAP32 to save code size + HEAP32[idx32 + 0] = t.identifier; + HEAP32[idx32 + 1] = t.screenX; + HEAP32[idx32 + 2] = t.screenY; + HEAP32[idx32 + 3] = t.clientX; + HEAP32[idx32 + 4] = t.clientY; + HEAP32[idx32 + 5] = t.pageX; + HEAP32[idx32 + 6] = t.pageY; + HEAP8[idx + 28] = t.isChanged; + HEAP8[idx + 29] = t.onTarget; + HEAP32[idx32 + 8] = t.clientX - (targetRect.left | 0); + HEAP32[idx32 + 9] = t.clientY - (targetRect.top | 0); + + idx += 48; + + if (++numTouches > 31) { + break; + } + } + HEAP32[(((touchEvent)+(8))>>2)] = numTouches; + + if (((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(eventTypeId, touchEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target, + allowsDeferredCalls: eventTypeString == 'touchstart' || eventTypeString == 'touchend', + eventTypeString, + callbackfunc, + handlerFunc: touchEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + var _emscripten_set_touchstart_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerTouchEventCallback(target, userData, useCapture, callbackfunc, 22, "touchstart", targetThread); + _emscripten_set_touchstart_callback_on_thread.sig = 'ippipp'; + + var _emscripten_set_touchend_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerTouchEventCallback(target, userData, useCapture, callbackfunc, 23, "touchend", targetThread); + _emscripten_set_touchend_callback_on_thread.sig = 'ippipp'; + + var _emscripten_set_touchmove_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerTouchEventCallback(target, userData, useCapture, callbackfunc, 24, "touchmove", targetThread); + _emscripten_set_touchmove_callback_on_thread.sig = 'ippipp'; + + var _emscripten_set_touchcancel_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => + registerTouchEventCallback(target, userData, useCapture, callbackfunc, 25, "touchcancel", targetThread); + _emscripten_set_touchcancel_callback_on_thread.sig = 'ippipp'; + + var fillGamepadEventData = (eventStruct, e) => { + HEAPF64[((eventStruct)>>3)] = e.timestamp; + for (var i = 0; i < e.axes.length; ++i) { + HEAPF64[(((eventStruct+i*8)+(16))>>3)] = e.axes[i]; + } + for (var i = 0; i < e.buttons.length; ++i) { + if (typeof e.buttons[i] == 'object') { + HEAPF64[(((eventStruct+i*8)+(528))>>3)] = e.buttons[i].value; + } else { + HEAPF64[(((eventStruct+i*8)+(528))>>3)] = e.buttons[i]; + } + } + for (var i = 0; i < e.buttons.length; ++i) { + if (typeof e.buttons[i] == 'object') { + HEAP8[(eventStruct+i)+(1040)] = e.buttons[i].pressed; + } else { + // Assigning a boolean to HEAP32, that's ok, but Closure would like to warn about it: + /** @suppress {checkTypes} */ + HEAP8[(eventStruct+i)+(1040)] = e.buttons[i] == 1; + } + } + HEAP8[(eventStruct)+(1104)] = e.connected; + HEAP32[(((eventStruct)+(1108))>>2)] = e.index; + HEAP32[(((eventStruct)+(8))>>2)] = e.axes.length; + HEAP32[(((eventStruct)+(12))>>2)] = e.buttons.length; + stringToUTF8(e.id, eventStruct + 1112, 64); + stringToUTF8(e.mapping, eventStruct + 1176, 64); + }; + + + + + var registerGamepadEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + JSEvents.gamepadEvent ||= _malloc(1240); + + var gamepadEventHandlerFunc = (e = event) => { + var gamepadEvent = JSEvents.gamepadEvent; + fillGamepadEventData(gamepadEvent, e["gamepad"]); + + if (((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(eventTypeId, gamepadEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target: findEventTarget(target), + allowsDeferredCalls: true, + eventTypeString, + callbackfunc, + handlerFunc: gamepadEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + + /** @suppress {checkTypes} */ + var _emscripten_sample_gamepad_data = () => { + try { + if (navigator.getGamepads) return (JSEvents.lastGamepadState = navigator.getGamepads()) + ? 0 : -1; + } catch(e) { + navigator.getGamepads = null; // Disable getGamepads() so that it won't be attempted to be used again. + } + return -1; + }; + _emscripten_sample_gamepad_data.sig = 'i'; + var _emscripten_set_gamepadconnected_callback_on_thread = (userData, useCapture, callbackfunc, targetThread) => { + if (_emscripten_sample_gamepad_data()) return -1; + return registerGamepadEventCallback(2, userData, useCapture, callbackfunc, 26, "gamepadconnected", targetThread); + }; + _emscripten_set_gamepadconnected_callback_on_thread.sig = 'ipipp'; + + + var _emscripten_set_gamepaddisconnected_callback_on_thread = (userData, useCapture, callbackfunc, targetThread) => { + if (_emscripten_sample_gamepad_data()) return -1; + return registerGamepadEventCallback(2, userData, useCapture, callbackfunc, 27, "gamepaddisconnected", targetThread); + }; + _emscripten_set_gamepaddisconnected_callback_on_thread.sig = 'ipipp'; + + + var _emscripten_get_num_gamepads = () => { + // N.B. Do not call emscripten_get_num_gamepads() unless having first called emscripten_sample_gamepad_data(), and that has returned EMSCRIPTEN_RESULT_SUCCESS. + // Otherwise the following line will throw an exception. + return JSEvents.lastGamepadState.length; + }; + _emscripten_get_num_gamepads.sig = 'i'; + + + var _emscripten_get_gamepad_status = (index, gamepadState) => { + // INVALID_PARAM is returned on a Gamepad index that never was there. + if (index < 0 || index >= JSEvents.lastGamepadState.length) return -5; + + // NO_DATA is returned on a Gamepad index that was removed. + // For previously disconnected gamepads there should be an empty slot (null/undefined/false) at the index. + // This is because gamepads must keep their original position in the array. + // For example, removing the first of two gamepads produces [null/undefined/false, gamepad]. + if (!JSEvents.lastGamepadState[index]) return -7; + + fillGamepadEventData(gamepadState, JSEvents.lastGamepadState[index]); + return 0; + }; + _emscripten_get_gamepad_status.sig = 'iip'; + + + + var registerBeforeUnloadEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString) => { + var beforeUnloadEventHandlerFunc = (e = event) => { + // Note: This is always called on the main browser thread, since it needs synchronously return a value! + var confirmationMessage = ((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(eventTypeId, 0, userData); + + if (confirmationMessage) { + confirmationMessage = UTF8ToString(confirmationMessage); + } + if (confirmationMessage) { + e.preventDefault(); + e.returnValue = confirmationMessage; + return confirmationMessage; + } + }; + + var eventHandler = { + target: findEventTarget(target), + eventTypeString, + callbackfunc, + handlerFunc: beforeUnloadEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + var _emscripten_set_beforeunload_callback_on_thread = (userData, callbackfunc, targetThread) => { + if (typeof onbeforeunload == 'undefined') return -1; + // beforeunload callback can only be registered on the main browser thread, because the page will go away immediately after returning from the handler, + // and there is no time to start proxying it anywhere. + if (targetThread !== 1) return -5; + return registerBeforeUnloadEventCallback(2, userData, true, callbackfunc, 28, "beforeunload"); + }; + _emscripten_set_beforeunload_callback_on_thread.sig = 'ippp'; + + var fillBatteryEventData = (eventStruct, battery) => { + HEAPF64[((eventStruct)>>3)] = battery.chargingTime; + HEAPF64[(((eventStruct)+(8))>>3)] = battery.dischargingTime; + HEAPF64[(((eventStruct)+(16))>>3)] = battery.level; + HEAP8[(eventStruct)+(24)] = battery.charging; + }; + + var hasBatteryAPI = () => typeof navigator != 'undefined' && navigator.getBattery; + + + + var registerBatteryEventCallback = (battery, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + JSEvents.batteryEvent ||= _malloc(32); + + var batteryEventHandlerFunc = (e = event) => { + var batteryEvent = JSEvents.batteryEvent; + fillBatteryEventData(batteryEvent, battery); + + if (((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(eventTypeId, batteryEvent, userData)) e.preventDefault(); + }; + + var eventHandler = { + target: battery, + eventTypeString, + callbackfunc, + handlerFunc: batteryEventHandlerFunc, + useCapture + }; + return JSEvents.registerOrRemoveHandler(eventHandler); + }; + + + var _emscripten_set_batterychargingchange_callback_on_thread = (userData, callbackfunc, targetThread) => { + if (!hasBatteryAPI()) return -1; + navigator.getBattery().then((b) => { + registerBatteryEventCallback(b, userData, true, callbackfunc, 29, "chargingchange", targetThread); + }); + }; + _emscripten_set_batterychargingchange_callback_on_thread.sig = 'ippp'; + + + var _emscripten_set_batterylevelchange_callback_on_thread = (userData, callbackfunc, targetThread) => { + if (!hasBatteryAPI()) return -1; + navigator.getBattery().then((b) => { + registerBatteryEventCallback(b, userData, true, callbackfunc, 30, "levelchange", targetThread); + }); + }; + _emscripten_set_batterylevelchange_callback_on_thread.sig = 'ippp'; + + var batteryManager; + + + + var _emscripten_get_battery_status = (batteryState) => { + if (!hasBatteryAPI()) return -1; + if (!batteryManager) { + navigator.getBattery().then((b) => { + batteryManager = b; + }); + return -7; + } + fillBatteryEventData(batteryState, batteryManager); + return 0; + }; + _emscripten_get_battery_status.sig = 'ip'; + + + + + + var _emscripten_set_element_css_size = (target, width, height) => { + target = findEventTarget(target); + if (!target) return -4; + + target.style.width = width + "px"; + target.style.height = height + "px"; + + return 0; + }; + _emscripten_set_element_css_size.sig = 'ipdd'; + + + var _emscripten_get_element_css_size = (target, width, height) => { + target = findEventTarget(target); + if (!target) return -4; + + var rect = getBoundingClientRect(target); + HEAPF64[((width)>>3)] = rect.width; + HEAPF64[((height)>>3)] = rect.height; + + return 0; + }; + _emscripten_get_element_css_size.sig = 'ippp'; + + var _emscripten_html5_remove_all_event_listeners = () => JSEvents.removeAllEventListeners(); + _emscripten_html5_remove_all_event_listeners.sig = 'v'; + + var _emscripten_request_animation_frame = (cb, userData) => + requestAnimationFrame((timeStamp) => ((a1, a2) => {} /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(timeStamp, userData)); + _emscripten_request_animation_frame.sig = 'ipp'; + + var _emscripten_cancel_animation_frame = (id) => cancelAnimationFrame(id); + _emscripten_cancel_animation_frame.sig = 'vi'; + + var _emscripten_request_animation_frame_loop = (cb, userData) => { + function tick(timeStamp) { + if (((a1, a2) => {} /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(timeStamp, userData)) { + requestAnimationFrame(tick); + } + } + return requestAnimationFrame(tick); + }; + _emscripten_request_animation_frame_loop.sig = 'vpp'; + + var _emscripten_get_device_pixel_ratio = () => { + return (typeof devicePixelRatio == 'number' && devicePixelRatio) || 1.0; + }; + _emscripten_get_device_pixel_ratio.sig = 'd'; + + + + + + var _emscripten_get_callstack = (flags, str, maxbytes) => { + var callstack = getCallstack(flags); + // User can query the required amount of bytes to hold the callstack. + if (!str || maxbytes <= 0) { + return lengthBytesUTF8(callstack)+1; + } + // Output callstack string as C string to HEAP. + var bytesWrittenExcludingNull = stringToUTF8(callstack, str, maxbytes); + + // Return number of bytes written, including null. + return bytesWrittenExcludingNull+1; + }; + _emscripten_get_callstack.sig = 'iipi'; + + /** @returns {number} */ + var convertFrameToPC = (frame) => { + var match; + + if (match = /\bwasm-function\[\d+\]:(0x[0-9a-f]+)/.exec(frame)) { + // Wasm engines give the binary offset directly, so we use that as return address + return +match[1]; + } else if (match = /:(\d+):\d+(?:\)|$)/.exec(frame)) { + // If we are in js, we can use the js line number as the "return address". + // This should work for wasm2js. We tag the high bit to distinguish this + // from wasm addresses. + return 0x80000000 | +match[1]; + } + // return 0 if we can't find any + return 0; + }; + + + var _emscripten_return_address = (level) => { + var callstack = jsStackTrace().split('\n'); + if (callstack[0] == 'Error') { + callstack.shift(); + } + // skip this function and the caller to get caller's return address + var caller = callstack[level + 3]; + return convertFrameToPC(caller); + }; + _emscripten_return_address.sig = 'pi'; + + var UNWIND_CACHE = { + }; + + + + + var saveInUnwindCache = (callstack) => { + for (var line of callstack) { + var pc = convertFrameToPC(line); + if (pc) { + UNWIND_CACHE[pc] = line; + } + } + }; + + var _emscripten_stack_snapshot = () => { + var callstack = jsStackTrace().split('\n'); + if (callstack[0] == 'Error') { + callstack.shift(); + } + saveInUnwindCache(callstack); + + // Caches the stack snapshot so that emscripten_stack_unwind_buffer() can + // unwind from this spot. + UNWIND_CACHE.last_addr = convertFrameToPC(callstack[3]); + UNWIND_CACHE.last_stack = callstack; + return UNWIND_CACHE.last_addr; + }; + _emscripten_stack_snapshot.sig = 'p'; + + + + + + var _emscripten_stack_unwind_buffer = (addr, buffer, count) => { + var stack; + if (UNWIND_CACHE.last_addr == addr) { + stack = UNWIND_CACHE.last_stack; + } else { + stack = jsStackTrace().split('\n'); + if (stack[0] == 'Error') { + stack.shift(); + } + saveInUnwindCache(stack); + } + + var offset = 3; + while (stack[offset] && convertFrameToPC(stack[offset]) != addr) { + ++offset; + } + + for (var i = 0; i < count && stack[i+offset]; ++i) { + HEAP32[(((buffer)+(i*4))>>2)] = convertFrameToPC(stack[i + offset]); + } + return i; + }; + _emscripten_stack_unwind_buffer.sig = 'ippi'; + + + + + var _emscripten_pc_get_function = (pc) => { + var frame = UNWIND_CACHE[pc]; + if (!frame) return 0; + + var name; + var match; + // First try to match foo.wasm.sym files explcitly. e.g. + // + // at test_return_address.wasm.main (wasm://wasm/test_return_address.wasm-0012cc2a:wasm-function[26]:0x9f3 + // + // Then match JS symbols which don't include that module name: + // + // at invokeEntryPoint (.../test_return_address.js:1500:42) + // + // Finally match firefox format: + // + // Object._main@http://server.com:4324:12' + if (match = /^\s+at .*\.wasm\.(.*) \(.*\)$/.exec(frame)) { + name = match[1]; + } else if (match = /^\s+at (.*) \(.*\)$/.exec(frame)) { + name = match[1]; + } else if (match = /^(.+?)@/.exec(frame)) { + name = match[1]; + } else { + return 0; + } + + _free(_emscripten_pc_get_function.ret ?? 0); + _emscripten_pc_get_function.ret = stringToNewUTF8(name); + return _emscripten_pc_get_function.ret; + }; + _emscripten_pc_get_function.sig = 'pp'; + + var convertPCtoSourceLocation = (pc) => { + if (UNWIND_CACHE.last_get_source_pc == pc) return UNWIND_CACHE.last_source; + + var match; + var source; + + if (!source) { + var frame = UNWIND_CACHE[pc]; + if (!frame) return null; + // Example: at callMain (a.out.js:6335:22) + if (match = /\((.*):(\d+):(\d+)\)$/.exec(frame)) { + source = {file: match[1], line: match[2], column: match[3]}; + // Example: main@a.out.js:1337:42 + } else if (match = /@(.*):(\d+):(\d+)/.exec(frame)) { + source = {file: match[1], line: match[2], column: match[3]}; + } + } + UNWIND_CACHE.last_get_source_pc = pc; + UNWIND_CACHE.last_source = source; + return source; + }; + + + + var _emscripten_pc_get_file = (pc) => { + var result = convertPCtoSourceLocation(pc); + if (!result) return 0; + + _free(_emscripten_pc_get_file.ret ?? 0); + _emscripten_pc_get_file.ret = stringToNewUTF8(result.file); + return _emscripten_pc_get_file.ret; + }; + _emscripten_pc_get_file.sig = 'pp'; + + var _emscripten_pc_get_line = (pc) => { + var result = convertPCtoSourceLocation(pc); + return result ? result.line : 0; + }; + _emscripten_pc_get_line.sig = 'ip'; + + var _emscripten_pc_get_column = (pc) => { + var result = convertPCtoSourceLocation(pc); + return result ? result.column || 0 : 0; + }; + _emscripten_pc_get_column.sig = 'ip'; + + + + var _sched_yield = () => 0; + _sched_yield.sig = 'i'; + + + + + + + + + + + + + + + + var wasiRightsToMuslOFlags = (rights) => { + if ((rights & 2) && (rights & 64)) { + return 2; + } + if (rights & 2) { + return 0; + } + if (rights & 64) { + return 1; + } + throw new FS.ErrnoError(28); + }; + + var wasiOFlagsToMuslOFlags = (oflags) => { + var musl_oflags = 0; + if (oflags & 1) { + musl_oflags |= 64; + } + if (oflags & 8) { + musl_oflags |= 512; + } + if (oflags & 2) { + musl_oflags |= 65536; + } + if (oflags & 4) { + musl_oflags |= 128; + } + return musl_oflags; + }; + + + + + + + var _emscripten_unwind_to_js_event_loop = () => { + throw 'unwind'; + }; + _emscripten_unwind_to_js_event_loop.sig = 'v'; + + + var setImmediateWrapped = (func) => { + setImmediateWrapped.mapping ||= []; + var id = setImmediateWrapped.mapping.length; + setImmediateWrapped.mapping[id] = setImmediate(() => { + setImmediateWrapped.mapping[id] = undefined; + func(); + }); + return id; + }; + + + + var safeRequestAnimationFrame = (func) => { + runtimeKeepalivePush(); + return MainLoop.requestAnimationFrame(() => { + runtimeKeepalivePop(); + callUserCallback(func); + }); + }; + + var clearImmediateWrapped = (id) => { + clearImmediate(setImmediateWrapped.mapping[id]); + setImmediateWrapped.mapping[id] = undefined; + }; + + + + var emClearImmediate; + var emSetImmediate; + + var emClearImmediate_deps = ["$emSetImmediate"]; + + + + + + var _emscripten_set_immediate = (cb, userData) => { + runtimeKeepalivePush(); + return emSetImmediate(() => { + runtimeKeepalivePop(); + callUserCallback(() => ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(userData)); + }); + }; + _emscripten_set_immediate.sig = 'ipp'; + + + var _emscripten_clear_immediate = (id) => { + runtimeKeepalivePop(); + emClearImmediate(id); + }; + _emscripten_clear_immediate.sig = 'vi'; + + + + + var _emscripten_set_immediate_loop = (cb, userData) => { + function tick() { + callUserCallback(() => { + if (((a1) => {} /* a dynamic function call to signature ii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(userData)) { + emSetImmediate(tick); + } else { + runtimeKeepalivePop(); + } + }); + } + runtimeKeepalivePush(); + emSetImmediate(tick); + }; + _emscripten_set_immediate_loop.sig = 'vpp'; + + var _emscripten_set_timeout = (cb, msecs, userData) => + safeSetTimeout(() => ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(userData), msecs); + _emscripten_set_timeout.sig = 'ipdp'; + + var _emscripten_clear_timeout = clearTimeout; + _emscripten_clear_timeout.sig = 'vi'; + + + + + var _emscripten_set_timeout_loop = (cb, msecs, userData) => { + function tick() { + var t = _emscripten_get_now(); + var n = t + msecs; + runtimeKeepalivePop(); + callUserCallback(() => { + if (((a1, a2) => {} /* a dynamic function call to signature idi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(t, userData)) { + runtimeKeepalivePush(); + // Save a little bit of code space: modern browsers should treat + // negative setTimeout as timeout of 0 + // (https://stackoverflow.com/questions/8430966/is-calling-settimeout-with-a-negative-delay-ok) + var remaining = n - _emscripten_get_now(); + // Recent revsions of node, however, give TimeoutNegativeWarning + remaining = Math.max(0, remaining); + setTimeout(tick, remaining); + } + }); + } + runtimeKeepalivePush(); + return setTimeout(tick, 0); + }; + _emscripten_set_timeout_loop.sig = 'vpdp'; + + + var _emscripten_set_interval = (cb, msecs, userData) => { + runtimeKeepalivePush(); + return setInterval(() => { + callUserCallback(() => ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(userData)); + }, msecs); + }; + _emscripten_set_interval.sig = 'ipdp'; + + var _emscripten_clear_interval = (id) => { + runtimeKeepalivePop(); + clearInterval(id); + }; + _emscripten_clear_interval.sig = 'vi'; + + + var _emscripten_async_call = (func, arg, millis) => { + var wrapper = () => ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(arg); + + if (millis >= 0 + // node does not support requestAnimationFrame + || ENVIRONMENT_IS_NODE + ) { + safeSetTimeout(wrapper, millis); + } else { + safeRequestAnimationFrame(wrapper); + } + }; + _emscripten_async_call.sig = 'vppi'; + + var registerPostMainLoop = (f) => { + // Does nothing unless $MainLoop is included/used. + typeof MainLoop != 'undefined' && MainLoop.postMainLoop.push(f); + }; + + var registerPreMainLoop = (f) => { + // Does nothing unless $MainLoop is included/used. + typeof MainLoop != 'undefined' && MainLoop.preMainLoop.push(f); + }; + + + var _emscripten_get_main_loop_timing = (mode, value) => { + if (mode) HEAP32[((mode)>>2)] = MainLoop.timingMode; + if (value) HEAP32[((value)>>2)] = MainLoop.timingValue; + }; + _emscripten_get_main_loop_timing.sig = 'vpp'; + + + var _emscripten_set_main_loop = (func, fps, simulateInfiniteLoop) => { + var iterFunc = (() => {} /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */); + setMainLoop(iterFunc, fps, simulateInfiniteLoop); + }; + _emscripten_set_main_loop.sig = 'vpii'; + + + var _emscripten_set_main_loop_arg = (func, arg, fps, simulateInfiniteLoop) => { + var iterFunc = () => ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(arg); + setMainLoop(iterFunc, fps, simulateInfiniteLoop, arg); + }; + _emscripten_set_main_loop_arg.sig = 'vppii'; + + var _emscripten_cancel_main_loop = () => { + MainLoop.pause(); + MainLoop.func = null; + }; + _emscripten_cancel_main_loop.sig = 'v'; + + var _emscripten_pause_main_loop = () => MainLoop.pause(); + _emscripten_pause_main_loop.sig = 'v'; + + var _emscripten_resume_main_loop = () => MainLoop.resume(); + _emscripten_resume_main_loop.sig = 'v'; + + + var __emscripten_push_main_loop_blocker = (func, arg, name) => { + MainLoop.queue.push({ func: () => { + ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(arg); + }, name: UTF8ToString(name), counted: true }); + MainLoop.updateStatus(); + }; + __emscripten_push_main_loop_blocker.sig = 'vppp'; + + + var __emscripten_push_uncounted_main_loop_blocker = (func, arg, name) => { + MainLoop.queue.push({ func: () => { + ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(arg); + }, name: UTF8ToString(name), counted: false }); + MainLoop.updateStatus(); + }; + __emscripten_push_uncounted_main_loop_blocker.sig = 'vppp'; + + var _emscripten_set_main_loop_expected_blockers = (num) => { + MainLoop.expectedBlockers = num; + MainLoop.remainingBlockers = num; + MainLoop.updateStatus(); + }; + _emscripten_set_main_loop_expected_blockers.sig = 'vi'; + + + + + var idsToPromises = (idBuf, size) => { + var promises = []; + for (var i = 0; i < size; i++) { + var id = HEAP32[(((idBuf)+(i*4))>>2)]; + promises[i] = getPromise(id); + } + return promises; + }; + + + + + + + + + + + var makePromiseCallback = (callback, userData) => { + return (value) => { + runtimeKeepalivePop();; + var stack = stackSave(); + // Allocate space for the result value and initialize it to NULL. + var resultPtr = stackAlloc(POINTER_SIZE); + HEAPU32[((resultPtr)>>2)] = 0; + try { + var result = + ((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(resultPtr, userData, value); + var resultVal = HEAPU32[((resultPtr)>>2)]; + } catch (e) { + // If the thrown value is potentially a valid pointer, use it as the + // rejection reason. Otherwise use a null pointer as the reason. If we + // allow arbitrary objects to be thrown here, we will get a TypeError in + // MEMORY64 mode when they are later converted to void* rejection + // values. + if (typeof e != 'number') { + throw 0; + } + throw e; + } finally { + // Thrown errors will reject the promise, but at least we will restore + // the stack first. + stackRestore(stack); + } + switch (result) { + case 0: + return resultVal; + case 1: + return getPromise(resultVal); + case 2: + var ret = getPromise(resultVal); + _emscripten_promise_destroy(resultVal); + return ret; + case 3: + throw resultVal; + } + }; + }; + + + + + var _emscripten_promise_then = (id, onFulfilled, onRejected, userData) => { + runtimeKeepalivePush();; + var promise = getPromise(id); + var newId = promiseMap.allocate({ + promise: promise.then(makePromiseCallback(onFulfilled, userData), + makePromiseCallback(onRejected, userData)) + }); + return newId; + }; + _emscripten_promise_then.sig = 'ppppp'; + + + var _emscripten_promise_all = (idBuf, resultBuf, size) => { + var promises = idsToPromises(idBuf, size); + var id = promiseMap.allocate({ + promise: Promise.all(promises).then((results) => { + if (resultBuf) { + for (var i = 0; i < size; i++) { + var result = results[i]; + HEAPU32[(((resultBuf)+(i*4))>>2)] = result; + } + } + return resultBuf; + }) + }); + return id; + }; + _emscripten_promise_all.sig = 'pppp'; + + var setPromiseResult = (ptr, fulfill, value) => { + var result = fulfill ? 0 : 3 + HEAP32[((ptr)>>2)] = result; + HEAPU32[(((ptr)+(4))>>2)] = value; + }; + + + + var _emscripten_promise_all_settled = (idBuf, resultBuf, size) => { + var promises = idsToPromises(idBuf, size); + var id = promiseMap.allocate({ + promise: Promise.allSettled(promises).then((results) => { + if (resultBuf) { + var offset = resultBuf; + for (var i = 0; i < size; i++, offset += 8) { + if (results[i].status === 'fulfilled') { + setPromiseResult(offset, true, results[i].value); + } else { + setPromiseResult(offset, false, results[i].reason); + } + } + } + return resultBuf; + }) + }); + return id; + }; + _emscripten_promise_all_settled.sig = 'pppp'; + + + var _emscripten_promise_any = (idBuf, errorBuf, size) => { + var promises = idsToPromises(idBuf, size); + var id = promiseMap.allocate({ + promise: Promise.any(promises).catch((err) => { + if (errorBuf) { + for (var i = 0; i < size; i++) { + HEAPU32[(((errorBuf)+(i*4))>>2)] = err.errors[i]; + } + } + throw errorBuf; + }) + }); + return id; + }; + _emscripten_promise_any.sig = 'pppp'; + + + var _emscripten_promise_race = (idBuf, size) => { + var promises = idsToPromises(idBuf, size); + var id = promiseMap.allocate({ + promise: Promise.race(promises) + }); + return id; + }; + _emscripten_promise_race.sig = 'ppp'; + + + var _emscripten_promise_await = (returnValuePtr, id) => { + return Asyncify.handleAsync(() => getPromise(id).then( + value => setPromiseResult(returnValuePtr, true, value), + error => setPromiseResult(returnValuePtr, false, error) + )); + }; + _emscripten_promise_await.sig = 'vpp'; + _emscripten_promise_await.isAsync = true; + + + var ___cxa_find_matching_catch_3 = (arg0) => findMatchingCatch([arg0]); + ___cxa_find_matching_catch_3.sig = 'pp'; + + var ___cxa_find_matching_catch_4 = (arg0,arg1) => findMatchingCatch([arg0,arg1]); + ___cxa_find_matching_catch_4.sig = 'ppp'; + + + + var exceptionCaught = []; + + + + + + var ___cxa_rethrow = () => { + var info = exceptionCaught.pop(); + if (!info) { + abort('no exception to throw'); + } + var ptr = info.excPtr; + if (!info.get_rethrown()) { + // Only pop if the corresponding push was through rethrow_primary_exception + exceptionCaught.push(info); + info.set_rethrown(true); + info.set_caught(false); + uncaughtExceptionCount++; + } + exceptionLast = ptr; + throw exceptionLast; + }; + ___cxa_rethrow.sig = 'v'; + + var _llvm_eh_typeid_for = (type) => type; + _llvm_eh_typeid_for.sig = 'vp'; + + + + + var ___cxa_begin_catch = (ptr) => { + var info = new ExceptionInfo(ptr); + if (!info.get_caught()) { + info.set_caught(true); + uncaughtExceptionCount--; + } + info.set_rethrown(false); + exceptionCaught.push(info); + ___cxa_increment_exception_refcount(ptr); + return ___cxa_get_exception_ptr(ptr); + }; + ___cxa_begin_catch.sig = 'pp'; + + + + + var ___cxa_end_catch = () => { + // Clear state flag. + _setThrew(0, 0); + // Call destructor if one is registered then clear it. + var info = exceptionCaught.pop(); + + ___cxa_decrement_exception_refcount(info.excPtr); + exceptionLast = 0; // XXX in decRef? + }; + ___cxa_end_catch.sig = 'v'; + + var ___cxa_uncaught_exceptions = () => uncaughtExceptionCount; + ___cxa_uncaught_exceptions.sig = 'i'; + + var ___cxa_call_unexpected = (exception) => abort('Unexpected exception thrown, this is not properly supported - aborting'); + ___cxa_call_unexpected.sig = 'vp'; + + + var ___cxa_current_primary_exception = () => { + if (!exceptionCaught.length) { + return 0; + } + var info = exceptionCaught[exceptionCaught.length - 1]; + ___cxa_increment_exception_refcount(info.excPtr); + return info.excPtr; + }; + ___cxa_current_primary_exception.sig = 'p'; + + function ___cxa_current_exception_type() { + if (!exceptionCaught.length) { + return 0; + } + var info = exceptionCaught[exceptionCaught.length - 1]; + return info.get_type(); + } + ___cxa_current_exception_type.sig = 'p'; + + + + var ___cxa_rethrow_primary_exception = (ptr) => { + if (!ptr) return; + var info = new ExceptionInfo(ptr); + exceptionCaught.push(info); + info.set_rethrown(true); + ___cxa_rethrow(); + }; + ___cxa_rethrow_primary_exception.sig = 'vp'; + + + + + + + + + + var Browser = { + useWebGL:false, + isFullscreen:false, + pointerLock:false, + moduleContextCreatedCallbacks:[], + workers:[], + preloadedImages:{ + }, + preloadedAudios:{ + }, + getCanvas:() => Module['canvas'], + init() { + if (Browser.initted) return; + Browser.initted = true; + + // Support for plugins that can process preloaded files. You can add more of these to + // your app by creating and appending to preloadPlugins. + // + // Each plugin is asked if it can handle a file based on the file's name. If it can, + // it is given the file's raw data. When it is done, it calls a callback with the file's + // (possibly modified) data. For example, a plugin might decompress a file, or it + // might create some side data structure for use later (like an Image element, etc.). + + var imagePlugin = {}; + imagePlugin['canHandle'] = function imagePlugin_canHandle(name) { + return !Module['noImageDecoding'] && /\.(jpg|jpeg|png|bmp|webp)$/i.test(name); + }; + imagePlugin['handle'] = async function imagePlugin_handle(byteArray, name) { + var b = new Blob([byteArray], { type: Browser.getMimetype(name) }); + if (b.size !== byteArray.length) { // Safari bug #118630 + // Safari's Blob can only take an ArrayBuffer + b = new Blob([(new Uint8Array(byteArray)).buffer], { type: Browser.getMimetype(name) }); + } + var url = URL.createObjectURL(b); + return new Promise((resolve, reject) => { + var img = new Image(); + img.onload = () => { + var canvas = /** @type {!HTMLCanvasElement} */ (document.createElement('canvas')); + canvas.width = img.width; + canvas.height = img.height; + var ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0); + Browser.preloadedImages[name] = canvas; + URL.revokeObjectURL(url); + resolve(byteArray); + }; + img.onerror = (event) => { + err(`Image ${url} could not be decoded`); + reject(); + }; + img.src = url; + }); + }; + preloadPlugins.push(imagePlugin); + + var audioPlugin = {}; + audioPlugin['canHandle'] = function audioPlugin_canHandle(name) { + return !Module['noAudioDecoding'] && name.slice(-4) in { '.ogg': 1, '.wav': 1, '.mp3': 1 }; + }; + audioPlugin['handle'] = async function audioPlugin_handle(byteArray, name) { + return new Promise((resolve, reject) => { + var done = false; + function finish(audio) { + if (done) return; + done = true; + Browser.preloadedAudios[name] = audio; + resolve(byteArray); + } + var b = new Blob([byteArray], { type: Browser.getMimetype(name) }); + var url = URL.createObjectURL(b); // XXX we never revoke this! + var audio = new Audio(); + audio.addEventListener('canplaythrough', () => finish(audio), false); // use addEventListener due to chromium bug 124926 + audio.onerror = function audio_onerror(event) { + if (done) return; + err(`warning: browser could not fully decode audio ${name}, trying slower base64 approach`); + function encode64(data) { + var BASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + var PAD = '='; + var ret = ''; + var leftchar = 0; + var leftbits = 0; + for (var i = 0; i < data.length; i++) { + leftchar = (leftchar << 8) | data[i]; + leftbits += 8; + while (leftbits >= 6) { + var curr = (leftchar >> (leftbits-6)) & 0x3f; + leftbits -= 6; + ret += BASE[curr]; + } + } + if (leftbits == 2) { + ret += BASE[(leftchar&3) << 4]; + ret += PAD + PAD; + } else if (leftbits == 4) { + ret += BASE[(leftchar&0xf) << 2]; + ret += PAD; + } + return ret; + } + audio.src = 'data:audio/x-' + name.slice(-3) + ';base64,' + encode64(byteArray); + finish(audio); // we don't wait for confirmation this worked - but it's worth trying + }; + audio.src = url; + // workaround for chrome bug 124926 - we do not always get oncanplaythrough or onerror + safeSetTimeout(() => { + finish(audio); // try to use it even though it is not necessarily ready to play + }, 10000); + }); + }; + preloadPlugins.push(audioPlugin); + + // Canvas event setup + + function pointerLockChange() { + var canvas = Browser.getCanvas(); + Browser.pointerLock = document.pointerLockElement === canvas; + } + var canvas = Browser.getCanvas(); + if (canvas) { + // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module + // Module['forcedAspectRatio'] = 4 / 3; + + document.addEventListener('pointerlockchange', pointerLockChange, false); + + if (Module['elementPointerLock']) { + canvas.addEventListener("click", (ev) => { + if (!Browser.pointerLock && Browser.getCanvas().requestPointerLock) { + Browser.getCanvas().requestPointerLock(); + ev.preventDefault(); + } + }, false); + } + } + }, + createContext(/** @type {HTMLCanvasElement} */ canvas, useWebGL, setInModule, webGLContextAttributes) { + if (useWebGL && Module['ctx'] && canvas == Browser.getCanvas()) return Module['ctx']; // no need to recreate GL context if it's already been created for this canvas. + + var ctx; + var contextHandle; + if (useWebGL) { + // For GLES2/desktop GL compatibility, adjust a few defaults to be different to WebGL defaults, so that they align better with the desktop defaults. + var contextAttributes = { + antialias: false, + alpha: false, + majorVersion: 1, + }; + + if (webGLContextAttributes) { + for (var attribute in webGLContextAttributes) { + contextAttributes[attribute] = webGLContextAttributes[attribute]; + } + } + + // This check of existence of GL is here to satisfy Closure compiler, which yells if variable GL is referenced below but GL object is not + // actually compiled in because application is not doing any GL operations. TODO: Ideally if GL is not being used, this function + // Browser.createContext() should not even be emitted. + if (typeof GL != 'undefined') { + contextHandle = GL.createContext(canvas, contextAttributes); + if (contextHandle) { + ctx = GL.getContext(contextHandle).GLctx; + } + } + } else { + ctx = canvas.getContext('2d'); + } + + if (!ctx) return null; + + if (setInModule) { + Module['ctx'] = ctx; + if (useWebGL) GL.makeContextCurrent(contextHandle); + Browser.useWebGL = useWebGL; + Browser.moduleContextCreatedCallbacks.forEach((callback) => callback()); + Browser.init(); + } + return ctx; + }, + fullscreenHandlersInstalled:false, + lockPointer:undefined, + resizeCanvas:undefined, + requestFullscreen(lockPointer, resizeCanvas) { + Browser.lockPointer = lockPointer; + Browser.resizeCanvas = resizeCanvas; + if (typeof Browser.lockPointer == 'undefined') Browser.lockPointer = true; + if (typeof Browser.resizeCanvas == 'undefined') Browser.resizeCanvas = false; + + var canvas = Browser.getCanvas(); + function fullscreenChange() { + Browser.isFullscreen = false; + var canvasContainer = canvas.parentNode; + if (getFullscreenElement() === canvasContainer) { + canvas.exitFullscreen = Browser.exitFullscreen; + if (Browser.lockPointer) canvas.requestPointerLock(); + Browser.isFullscreen = true; + if (Browser.resizeCanvas) { + Browser.setFullscreenCanvasSize(); + } else { + Browser.updateCanvasDimensions(canvas); + } + } else { + // remove the full screen specific parent of the canvas again to restore the HTML structure from before going full screen + canvasContainer.parentNode.insertBefore(canvas, canvasContainer); + canvasContainer.parentNode.removeChild(canvasContainer); + + if (Browser.resizeCanvas) { + Browser.setWindowedCanvasSize(); + } else { + Browser.updateCanvasDimensions(canvas); + } + } + Module['onFullScreen']?.(Browser.isFullscreen); + Module['onFullscreen']?.(Browser.isFullscreen); + } + + if (!Browser.fullscreenHandlersInstalled) { + Browser.fullscreenHandlersInstalled = true; + document.addEventListener('fullscreenchange', fullscreenChange, false); + document.addEventListener('mozfullscreenchange', fullscreenChange, false); + document.addEventListener('webkitfullscreenchange', fullscreenChange, false); + document.addEventListener('MSFullscreenChange', fullscreenChange, false); + } + + // create a new parent to ensure the canvas has no siblings. this allows browsers to optimize full screen performance when its parent is the full screen root + var canvasContainer = document.createElement("div"); + canvas.parentNode.insertBefore(canvasContainer, canvas); + canvasContainer.appendChild(canvas); + + // use parent of canvas as full screen root to allow aspect ratio correction (Firefox stretches the root to screen size) + canvasContainer.requestFullscreen = canvasContainer['requestFullscreen'] || + canvasContainer['mozRequestFullScreen'] || + canvasContainer['msRequestFullscreen'] || + (canvasContainer['webkitRequestFullscreen'] ? () => canvasContainer['webkitRequestFullscreen'](Element['ALLOW_KEYBOARD_INPUT']) : null) || + (canvasContainer['webkitRequestFullScreen'] ? () => canvasContainer['webkitRequestFullScreen'](Element['ALLOW_KEYBOARD_INPUT']) : null); + + canvasContainer.requestFullscreen(); + }, + exitFullscreen() { + // This is workaround for chrome. Trying to exit from fullscreen + // not in fullscreen state will cause "TypeError: Document not active" + // in chrome. See https://github.com/emscripten-core/emscripten/pull/8236 + if (!Browser.isFullscreen) { + return false; + } + + var CFS = document['exitFullscreen'] || + document['cancelFullScreen'] || + document['mozCancelFullScreen'] || + document['msExitFullscreen'] || + document['webkitCancelFullScreen'] || + (() => {}); + CFS.apply(document, []); + return true; + }, + safeSetTimeout(func, timeout) { + // Legacy function, this is used by the SDL2 port so we need to keep it + // around at least until that is updated. + // See https://github.com/libsdl-org/SDL/pull/6304 + return safeSetTimeout(func, timeout); + }, + getMimetype(name) { + return { + 'jpg': 'image/jpeg', + 'jpeg': 'image/jpeg', + 'png': 'image/png', + 'bmp': 'image/bmp', + 'ogg': 'audio/ogg', + 'wav': 'audio/wav', + 'mp3': 'audio/mpeg' + }[name.slice(name.lastIndexOf('.')+1)]; + }, + getUserMedia(func) { + window.getUserMedia ||= navigator['getUserMedia'] || + navigator['mozGetUserMedia']; + window.getUserMedia(func); + }, + getMovementX(event) { + return event['movementX'] || + event['mozMovementX'] || + event['webkitMovementX'] || + 0; + }, + getMovementY(event) { + return event['movementY'] || + event['mozMovementY'] || + event['webkitMovementY'] || + 0; + }, + getMouseWheelDelta(event) { + var delta = 0; + switch (event.type) { + case 'DOMMouseScroll': + // 3 lines make up a step + delta = event.detail / 3; + break; + case 'mousewheel': + // 120 units make up a step + delta = event.wheelDelta / 120; + break; + case 'wheel': + delta = event.deltaY + switch (event.deltaMode) { + case 0: + // DOM_DELTA_PIXEL: 100 pixels make up a step + delta /= 100; + break; + case 1: + // DOM_DELTA_LINE: 3 lines make up a step + delta /= 3; + break; + case 2: + // DOM_DELTA_PAGE: A page makes up 80 steps + delta *= 80; + break; + default: + abort('unrecognized mouse wheel delta mode: ' + event.deltaMode); + } + break; + default: + abort('unrecognized mouse wheel event: ' + event.type); + } + return delta; + }, + mouseX:0, + mouseY:0, + mouseMovementX:0, + mouseMovementY:0, + touches:{ + }, + lastTouches:{ + }, + calculateMouseCoords(pageX, pageY) { + // Calculate the movement based on the changes + // in the coordinates. + var canvas = Browser.getCanvas(); + var rect = canvas.getBoundingClientRect(); + + // Neither .scrollX or .pageXOffset are defined in a spec, but + // we prefer .scrollX because it is currently in a spec draft. + // (see: http://www.w3.org/TR/2013/WD-cssom-view-20131217/) + var scrollX = ((typeof window.scrollX != 'undefined') ? window.scrollX : window.pageXOffset); + var scrollY = ((typeof window.scrollY != 'undefined') ? window.scrollY : window.pageYOffset); + var adjustedX = pageX - (scrollX + rect.left); + var adjustedY = pageY - (scrollY + rect.top); + + // the canvas might be CSS-scaled compared to its backbuffer; + // SDL-using content will want mouse coordinates in terms + // of backbuffer units. + adjustedX = adjustedX * (canvas.width / rect.width); + adjustedY = adjustedY * (canvas.height / rect.height); + + return { x: adjustedX, y: adjustedY }; + }, + setMouseCoords(pageX, pageY) { + const {x, y} = Browser.calculateMouseCoords(pageX, pageY); + Browser.mouseMovementX = x - Browser.mouseX; + Browser.mouseMovementY = y - Browser.mouseY; + Browser.mouseX = x; + Browser.mouseY = y; + }, + calculateMouseEvent(event) { // event should be mousemove, mousedown or mouseup + if (Browser.pointerLock) { + // When the pointer is locked, calculate the coordinates + // based on the movement of the mouse. + // Workaround for Firefox bug 764498 + if (event.type != 'mousemove' && + ('mozMovementX' in event)) { + Browser.mouseMovementX = Browser.mouseMovementY = 0; + } else { + Browser.mouseMovementX = Browser.getMovementX(event); + Browser.mouseMovementY = Browser.getMovementY(event); + } + + // add the mouse delta to the current absolute mouse position + Browser.mouseX += Browser.mouseMovementX; + Browser.mouseY += Browser.mouseMovementY; + } else { + if (event.type === 'touchstart' || event.type === 'touchend' || event.type === 'touchmove') { + var touch = event.touch; + if (touch === undefined) { + return; // the "touch" property is only defined in SDL + + } + var coords = Browser.calculateMouseCoords(touch.pageX, touch.pageY); + + if (event.type === 'touchstart') { + Browser.lastTouches[touch.identifier] = coords; + Browser.touches[touch.identifier] = coords; + } else if (event.type === 'touchend' || event.type === 'touchmove') { + var last = Browser.touches[touch.identifier]; + last ||= coords; + Browser.lastTouches[touch.identifier] = last; + Browser.touches[touch.identifier] = coords; + } + return; + } + + Browser.setMouseCoords(event.pageX, event.pageY); + } + }, + resizeListeners:[], + updateResizeListeners() { + var canvas = Browser.getCanvas(); + Browser.resizeListeners.forEach((listener) => listener(canvas.width, canvas.height)); + }, + setCanvasSize(width, height, noUpdates) { + var canvas = Browser.getCanvas(); + Browser.updateCanvasDimensions(canvas, width, height); + if (!noUpdates) Browser.updateResizeListeners(); + }, + windowedWidth:0, + windowedHeight:0, + setFullscreenCanvasSize() { + // check if SDL is available + if (typeof SDL != "undefined") { + var flags = HEAPU32[((SDL.screen)>>2)]; + flags = flags | 0x00800000; // set SDL_FULLSCREEN flag + HEAP32[((SDL.screen)>>2)] = flags; + } + Browser.updateCanvasDimensions(Browser.getCanvas()); + Browser.updateResizeListeners(); + }, + setWindowedCanvasSize() { + // check if SDL is available + if (typeof SDL != "undefined") { + var flags = HEAPU32[((SDL.screen)>>2)]; + flags = flags & ~0x00800000; // clear SDL_FULLSCREEN flag + HEAP32[((SDL.screen)>>2)] = flags; + } + Browser.updateCanvasDimensions(Browser.getCanvas()); + Browser.updateResizeListeners(); + }, + updateCanvasDimensions(canvas, wNative, hNative) { + if (wNative && hNative) { + canvas.widthNative = wNative; + canvas.heightNative = hNative; + } else { + wNative = canvas.widthNative; + hNative = canvas.heightNative; + } + var w = wNative; + var h = hNative; + if (Module['forcedAspectRatio'] > 0) { + if (w/h < Module['forcedAspectRatio']) { + w = Math.round(h * Module['forcedAspectRatio']); + } else { + h = Math.round(w / Module['forcedAspectRatio']); + } + } + if ((getFullscreenElement() === canvas.parentNode) && (typeof screen != 'undefined')) { + var factor = Math.min(screen.width / w, screen.height / h); + w = Math.round(w * factor); + h = Math.round(h * factor); + } + if (Browser.resizeCanvas) { + if (canvas.width != w) canvas.width = w; + if (canvas.height != h) canvas.height = h; + if (typeof canvas.style != 'undefined') { + canvas.style.removeProperty( "width"); + canvas.style.removeProperty("height"); + } + } else { + if (canvas.width != wNative) canvas.width = wNative; + if (canvas.height != hNative) canvas.height = hNative; + if (typeof canvas.style != 'undefined') { + if (w != wNative || h != hNative) { + canvas.style.setProperty( "width", w + "px", "important"); + canvas.style.setProperty("height", h + "px", "important"); + } else { + canvas.style.removeProperty( "width"); + canvas.style.removeProperty("height"); + } + } + } + }, + }; + + var requestFullscreen = Browser.requestFullscreen; + + var setCanvasSize = Browser.setCanvasSize; + + var getUserMedia = Browser.getUserMedia; + + var createContext = Browser.createContext; + + + + + + var _emscripten_run_preload_plugins = (file, onload, onerror) => { + runtimeKeepalivePush(); + + var _file = UTF8ToString(file); + var data = FS.analyzePath(_file); + if (!data.exists) return -1; + FS.createPreloadedFile( + PATH.dirname(_file), + PATH.basename(_file), + // TODO: This copy is not needed if the contents are already a Uint8Array, + // which they often are (and always are in WasmFS). + new Uint8Array(data.object.contents), true, true, + () => { + runtimeKeepalivePop(); + if (onload) ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(file); + }, + () => { + runtimeKeepalivePop(); + if (onerror) ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(file); + }, + true // don'tCreateFile - it's already there + ); + return 0; + }; + _emscripten_run_preload_plugins.sig = 'ippp'; + + var Browser_asyncPrepareDataCounter = 0; + + + + + + + var _emscripten_run_preload_plugins_data = (data, size, suffix, arg, onload, onerror) => { + runtimeKeepalivePush(); + + var _suffix = UTF8ToString(suffix); + var name = 'prepare_data_' + (Browser_asyncPrepareDataCounter++) + '.' + _suffix; + var cname = stringToNewUTF8(name); + FS.createPreloadedFile( + '/', + name, + HEAPU8.subarray((data), data + size), + true, true, + () => { + runtimeKeepalivePop(); + if (onload) ((a1, a2) => {} /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(arg, cname); + }, + () => { + runtimeKeepalivePop(); + if (onerror) ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(arg); + }, + true // don'tCreateFile - it's already there + ); + }; + _emscripten_run_preload_plugins_data.sig = 'vpipppp'; + + + + var _emscripten_async_run_script = (script, millis) => { + // TODO: cache these to avoid generating garbage + safeSetTimeout(() => _emscripten_run_script(script), millis); + }; + _emscripten_async_run_script.sig = 'vpi'; + + + + + + var _emscripten_async_load_script = async (url, onload, onerror) => { + url = UTF8ToString(url); + runtimeKeepalivePush(); + + var loadDone = () => { + runtimeKeepalivePop(); + if (onload) { + var onloadCallback = () => callUserCallback((() => {} /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)); + if (runDependencies > 0) { + dependenciesFulfilled = onloadCallback; + } else { + onloadCallback(); + } + } + } + + var loadError = () => { + runtimeKeepalivePop(); + if (onerror) { + callUserCallback((() => {} /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)); + } + }; + + if (ENVIRONMENT_IS_NODE) { + try { + var data = await readAsync(url, false); + eval(data); + loadDone(); + } catch (e) { + err(e); + loadError(); + } + return; + } + + var script = document.createElement('script'); + script.onload = loadDone; + script.onerror = loadError; + script.src = url; + document.body.appendChild(script); + }; + _emscripten_async_load_script.sig = 'vppp'; + + var _emscripten_get_window_title = () => { + var buflen = 256; + + if (!_emscripten_get_window_title.buffer) { + _emscripten_get_window_title.buffer = _malloc(buflen); + } + + stringToUTF8(document.title, _emscripten_get_window_title.buffer, buflen); + + return _emscripten_get_window_title.buffer; + }; + _emscripten_get_window_title.sig = 'p'; + + + var _emscripten_set_window_title = (title) => document.title = UTF8ToString(title); + _emscripten_set_window_title.sig = 'vp'; + + var _emscripten_get_screen_size = (width, height) => { + HEAP32[((width)>>2)] = screen.width; + HEAP32[((height)>>2)] = screen.height; + }; + _emscripten_get_screen_size.sig = 'vpp'; + + var _emscripten_hide_mouse = () => { + var styleSheet = document.styleSheets[0]; + var rules = styleSheet.cssRules; + for (var i = 0; i < rules.length; i++) { + if (rules[i].cssText.startsWith('canvas')) { + styleSheet.deleteRule(i); + i--; + } + } + styleSheet.insertRule('canvas.emscripten { border: 1px solid black; cursor: none; }', 0); + }; + _emscripten_hide_mouse.sig = 'v'; + + var _emscripten_set_canvas_size = (width, height) => Browser.setCanvasSize(width, height); + _emscripten_set_canvas_size.sig = 'vii'; + + var _emscripten_get_canvas_size = (width, height, isFullscreen) => { + var canvas = Browser.getCanvas(); + HEAP32[((width)>>2)] = canvas.width; + HEAP32[((height)>>2)] = canvas.height; + HEAP32[((isFullscreen)>>2)] = Browser.isFullscreen ? 1 : 0; + }; + _emscripten_get_canvas_size.sig = 'vppp'; + + + + + + var _emscripten_create_worker = (url) => { + url = UTF8ToString(url); + var id = Browser.workers.length; + var info = { + worker: new Worker(url), + callbacks: [], + awaited: 0, + buffer: 0, + }; + info.worker.onmessage = function info_worker_onmessage(msg) { + if (ABORT) return; + var info = Browser.workers[id]; + if (!info) return; // worker was destroyed meanwhile + var callbackId = msg.data['callbackId']; + var callbackInfo = info.callbacks[callbackId]; + if (!callbackInfo) return; // no callback or callback removed meanwhile + // Don't trash our callback state if we expect additional calls. + if (msg.data['finalResponse']) { + info.awaited--; + info.callbacks[callbackId] = null; // TODO: reuse callbackIds, compress this + runtimeKeepalivePop(); + } + var data = msg.data['data']; + if (data) { + if (!data.byteLength) data = new Uint8Array(data); + info.buffer = _realloc(info.buffer, data.length); + HEAPU8.set(data, info.buffer); + callbackInfo.func(info.buffer, data.length, callbackInfo.arg); + } else { + callbackInfo.func(0, 0, callbackInfo.arg); + } + }; + Browser.workers.push(info); + return id; + }; + _emscripten_create_worker.sig = 'ip'; + + + var _emscripten_destroy_worker = (id) => { + var info = Browser.workers[id]; + info.worker.terminate(); + _free(info.buffer); + Browser.workers[id] = null; + }; + _emscripten_destroy_worker.sig = 'vi'; + + + + var _emscripten_call_worker = (id, funcName, data, size, callback, arg) => { + funcName = UTF8ToString(funcName); + var info = Browser.workers[id]; + var callbackId = -1; + if (callback) { + // If we are waiting for a response from the worker we need to keep + // the runtime alive at least long enough to receive it. + // The corresponding runtimeKeepalivePop is in the `finalResponse` + // handler above. + runtimeKeepalivePush(); + callbackId = info.callbacks.length; + info.callbacks.push({ + func: ((a1, a2, a3) => {} /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */), + arg + }); + info.awaited++; + } + var transferObject = { + 'funcName': funcName, + 'callbackId': callbackId, + 'data': data ? new Uint8Array(HEAPU8.subarray((data), data + size)) : 0 + }; + if (data) { + info.worker.postMessage(transferObject, [transferObject.data.buffer]); + } else { + info.worker.postMessage(transferObject); + } + }; + _emscripten_call_worker.sig = 'vippipp'; + + var _emscripten_get_worker_queue_size = (id) => { + var info = Browser.workers[id]; + if (!info) return -1; + return info.awaited; + }; + _emscripten_get_worker_queue_size.sig = 'ii'; + + var getPreloadedImageData = (path, w, h) => { + path = PATH_FS.resolve(path); + + var canvas = /** @type {HTMLCanvasElement} */(Browser.preloadedImages[path]); + if (!canvas) return 0; + + var ctx = canvas.getContext("2d"); + var image = ctx.getImageData(0, 0, canvas.width, canvas.height); + var buf = _malloc(canvas.width * canvas.height * 4); + + HEAPU8.set(image.data, buf); + + HEAP32[((w)>>2)] = canvas.width; + HEAP32[((h)>>2)] = canvas.height; + return buf; + }; + + + + var _emscripten_get_preloaded_image_data = (path, w, h) => getPreloadedImageData(UTF8ToString(path), w, h); + _emscripten_get_preloaded_image_data.sig = 'pppp'; + + var getPreloadedImageData__data = ["$PATH_FS","malloc"]; + + + + + var _emscripten_get_preloaded_image_data_from_FILE = (file, w, h) => { + var fd = _fileno(file); + var stream = FS.getStream(fd); + if (stream) { + return getPreloadedImageData(stream.path, w, h); + } + + return 0; + }; + _emscripten_get_preloaded_image_data_from_FILE.sig = 'pppp'; + + var wget = { + wgetRequests:{ + }, + nextWgetRequestHandle:0, + getNextWgetRequestHandle() { + var handle = wget.nextWgetRequestHandle; + wget.nextWgetRequestHandle++; + return handle; + }, + }; + + + + + + + + /** + * @param {number=} mode Optionally, the mode to create in. Uses mkdir's + * default if not set. + */ + var FS_mkdirTree = (path, mode) => FS.mkdirTree(path, mode); + + + + + + var _emscripten_async_wget = (url, file, onload, onerror) => { + runtimeKeepalivePush(); + + var _url = UTF8ToString(url); + var _file = UTF8ToString(file); + _file = PATH_FS.resolve(_file); + function doCallback(callback) { + if (callback) { + runtimeKeepalivePop(); + callUserCallback(() => withStackSave(() => ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(stringToUTF8OnStack(_file)))); + } + } + var destinationDirectory = PATH.dirname(_file); + FS_preloadFile( + destinationDirectory, + PATH.basename(_file), + _url, true, true, + false, // dontCreateFile + false, // canOwn + () => { // preFinish + // if a file exists there, we overwrite it + try { + FS_unlink(_file); + } catch (e) {} + // if the destination directory does not yet exist, create it + FS_mkdirTree(destinationDirectory); + } + ).then(() => doCallback(onload)).catch(() => doCallback(onerror)); + }; + _emscripten_async_wget.sig = 'vpppp'; + + + + + + + + var _emscripten_async_wget_data = async (url, userdata, onload, onerror) => { + runtimeKeepalivePush(); + /* no need for run dependency, this is async but will not do any prepare etc. step */ + try { + var byteArray = await asyncLoad(UTF8ToString(url)); + runtimeKeepalivePop(); + callUserCallback(() => { + var buffer = _malloc(byteArray.length); + HEAPU8.set(byteArray, buffer); + ((a1, a2, a3) => {} /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(userdata, buffer, byteArray.length); + _free(buffer); + }); + } catch (e) { + if (onerror) { + runtimeKeepalivePop(); + callUserCallback(() => { + ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(userdata); + }); + } + } + }; + _emscripten_async_wget_data.sig = 'vpppp'; + + + + + + + + var _emscripten_async_wget2 = (url, file, request, param, userdata, onload, onerror, onprogress) => { + runtimeKeepalivePush(); + + var _url = UTF8ToString(url); + var _file = UTF8ToString(file); + _file = PATH_FS.resolve(_file); + var _request = UTF8ToString(request); + var _param = UTF8ToString(param); + var index = _file.lastIndexOf('/'); + + var http = new XMLHttpRequest(); + http.open(_request, _url, true); + http.responseType = 'arraybuffer'; + + var handle = wget.getNextWgetRequestHandle(); + + var destinationDirectory = PATH.dirname(_file); + + // LOAD + http.onload = (e) => { + runtimeKeepalivePop(); + if (http.status >= 200 && http.status < 300) { + // if a file exists there, we overwrite it + try { + FS.unlink(_file); + } catch (e) {} + // if the destination directory does not yet exist, create it + FS.mkdirTree(destinationDirectory); + + FS.createDataFile( _file.slice(0, index), _file.slice(index + 1), new Uint8Array(/** @type{ArrayBuffer}*/(http.response)), true, true, false); + if (onload) { + var sp = stackSave(); + ((a1, a2, a3) => {} /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(handle, userdata, stringToUTF8OnStack(_file)); + stackRestore(sp); + } + } else { + if (onerror) ((a1, a2, a3) => {} /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(handle, userdata, http.status); + } + + delete wget.wgetRequests[handle]; + }; + + // ERROR + http.onerror = (e) => { + runtimeKeepalivePop(); + if (onerror) ((a1, a2, a3) => {} /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(handle, userdata, http.status); + delete wget.wgetRequests[handle]; + }; + + // PROGRESS + http.onprogress = (e) => { + if (e.lengthComputable || (e.lengthComputable === undefined && e.total != 0)) { + var percentComplete = (e.loaded / e.total)*100; + if (onprogress) ((a1, a2, a3) => {} /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(handle, userdata, percentComplete); + } + }; + + // ABORT + http.onabort = (e) => { + runtimeKeepalivePop(); + delete wget.wgetRequests[handle]; + }; + + if (_request == "POST") { + //Send the proper header information along with the request + http.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + http.send(_param); + } else { + http.send(null); + } + + wget.wgetRequests[handle] = http; + + return handle; + }; + _emscripten_async_wget2.sig = 'ipppppppp'; + + + + + + var _emscripten_async_wget2_data = (url, request, param, userdata, free, onload, onerror, onprogress) => { + var _url = UTF8ToString(url); + var _request = UTF8ToString(request); + var _param = UTF8ToString(param); + + var http = new XMLHttpRequest(); + http.open(_request, _url, true); + http.responseType = 'arraybuffer'; + + var handle = wget.getNextWgetRequestHandle(); + + function onerrorjs() { + if (onerror) { + var sp = stackSave(); + var statusText = 0; + if (http.statusText) { + statusText = stringToUTF8OnStack(http.statusText); + } + ((a1, a2, a3, a4) => {} /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(handle, userdata, http.status, statusText); + stackRestore(sp); + } + } + + // LOAD + http.onload = (e) => { + if (http.status >= 200 && http.status < 300 || (http.status === 0 && _url.slice(0, 4).toLowerCase() != "http")) { + var byteArray = new Uint8Array(/** @type{ArrayBuffer} */(http.response)); + var buffer = _malloc(byteArray.length); + HEAPU8.set(byteArray, buffer); + if (onload) ((a1, a2, a3, a4) => {} /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(handle, userdata, buffer, byteArray.length); + if (free) _free(buffer); + } else { + onerrorjs(); + } + delete wget.wgetRequests[handle]; + }; + + // ERROR + http.onerror = (e) => { + onerrorjs(); + delete wget.wgetRequests[handle]; + }; + + // PROGRESS + http.onprogress = (e) => { + if (onprogress) ((a1, a2, a3, a4) => {} /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(handle, userdata, e.loaded, e.lengthComputable || e.lengthComputable === undefined ? e.total : 0); + }; + + // ABORT + http.onabort = (e) => { + delete wget.wgetRequests[handle]; + }; + + if (_request == "POST") { + //Send the proper header information along with the request + http.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); + http.send(_param); + } else { + http.send(null); + } + + wget.wgetRequests[handle] = http; + + return handle; + }; + _emscripten_async_wget2_data.sig = 'ippppippp'; + + var _emscripten_async_wget2_abort = (handle) => { + var http = wget.wgetRequests[handle]; + http?.abort(); + }; + _emscripten_async_wget2_abort.sig = 'vi'; + + + + + + var ___asctime_r = (tmPtr, buf) => { + var date = { + tm_sec: HEAP32[((tmPtr)>>2)], + tm_min: HEAP32[(((tmPtr)+(4))>>2)], + tm_hour: HEAP32[(((tmPtr)+(8))>>2)], + tm_mday: HEAP32[(((tmPtr)+(12))>>2)], + tm_mon: HEAP32[(((tmPtr)+(16))>>2)], + tm_year: HEAP32[(((tmPtr)+(20))>>2)], + tm_wday: HEAP32[(((tmPtr)+(24))>>2)] + }; + var days = [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ]; + var months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ]; + var s = days[date.tm_wday] + ' ' + months[date.tm_mon] + + (date.tm_mday < 10 ? ' ' : ' ') + date.tm_mday + + (date.tm_hour < 10 ? ' 0' : ' ') + date.tm_hour + + (date.tm_min < 10 ? ':0' : ':') + date.tm_min + + (date.tm_sec < 10 ? ':0' : ':') + date.tm_sec + + ' ' + (1900 + date.tm_year) + "\n"; + + // asctime_r is specced to behave in an undefined manner if the algorithm would attempt + // to write out more than 26 bytes (including the null terminator). + // See http://pubs.opengroup.org/onlinepubs/9699919799/functions/asctime.html + // Our undefined behavior is to truncate the write to at most 26 bytes, including null terminator. + stringToUTF8(s, buf, 26); + return buf; + }; + ___asctime_r.sig = 'ppp'; + + + + + + + + + + + + var _strptime_l = (buf, format, tm, locale) => _strptime(buf, format, tm); + _strptime_l.sig = 'ppppp'; + + + + + + + + + + + + + + + + + + + + function ___syscall_shutdown(fd, how) { + try { + + getSocketFromFD(fd); + return -52; // unsupported feature + } catch (e) { + if (typeof FS == 'undefined' || !(e.name === 'ErrnoError')) throw e; + return -e.errno; + } + } + ___syscall_shutdown.sig = 'iiiiiii'; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + var __dlsym_catchup_js = (handle, symbolIndex) => { + var lib = LDSO.loadedLibsByHandle[handle]; + var symDict = lib.exports; + var symName = Object.keys(symDict)[symbolIndex]; + var sym = symDict[symName]; + var result = addFunction(sym, sym.sig); + return result; + }; + __dlsym_catchup_js.sig = 'ppi'; + + + + + + + + + + + + + + var FS_readFile = (...args) => FS.readFile(...args); + + + + var FS_root = (...args) => FS.root(...args); + + var FS_mounts = (...args) => FS.mounts(...args); + + var FS_devices = (...args) => FS.devices(...args); + + var FS_streams = (...args) => FS.streams(...args); + + var FS_nextInode = (...args) => FS.nextInode(...args); + + var FS_nameTable = (...args) => FS.nameTable(...args); + + var FS_currentPath = (...args) => FS.currentPath(...args); + + var FS_initialized = (...args) => FS.initialized(...args); + + var FS_ignorePermissions = (...args) => FS.ignorePermissions(...args); + + var FS_filesystems = (...args) => FS.filesystems(...args); + + var FS_syncFSRequests = (...args) => FS.syncFSRequests(...args); + + var FS_readFiles = (...args) => FS.readFiles(...args); + + var FS_lookupPath = (...args) => FS.lookupPath(...args); + + var FS_getPath = (...args) => FS.getPath(...args); + + var FS_hashName = (...args) => FS.hashName(...args); + + var FS_hashAddNode = (...args) => FS.hashAddNode(...args); + + var FS_hashRemoveNode = (...args) => FS.hashRemoveNode(...args); + + var FS_lookupNode = (...args) => FS.lookupNode(...args); + + var FS_createNode = (...args) => FS.createNode(...args); + + var FS_destroyNode = (...args) => FS.destroyNode(...args); + + var FS_isRoot = (...args) => FS.isRoot(...args); + + var FS_isMountpoint = (...args) => FS.isMountpoint(...args); + + var FS_isFile = (...args) => FS.isFile(...args); + + var FS_isDir = (...args) => FS.isDir(...args); + + var FS_isLink = (...args) => FS.isLink(...args); + + var FS_isChrdev = (...args) => FS.isChrdev(...args); + + var FS_isBlkdev = (...args) => FS.isBlkdev(...args); + + var FS_isFIFO = (...args) => FS.isFIFO(...args); + + var FS_isSocket = (...args) => FS.isSocket(...args); + + var FS_flagsToPermissionString = (...args) => FS.flagsToPermissionString(...args); + + var FS_nodePermissions = (...args) => FS.nodePermissions(...args); + + var FS_mayLookup = (...args) => FS.mayLookup(...args); + + var FS_mayCreate = (...args) => FS.mayCreate(...args); + + var FS_mayDelete = (...args) => FS.mayDelete(...args); + + var FS_mayOpen = (...args) => FS.mayOpen(...args); + + var FS_checkOpExists = (...args) => FS.checkOpExists(...args); + + var FS_nextfd = (...args) => FS.nextfd(...args); + + var FS_getStreamChecked = (...args) => FS.getStreamChecked(...args); + + var FS_getStream = (...args) => FS.getStream(...args); + + var FS_createStream = (...args) => FS.createStream(...args); + + var FS_closeStream = (...args) => FS.closeStream(...args); + + var FS_dupStream = (...args) => FS.dupStream(...args); + + var FS_doSetAttr = (...args) => FS.doSetAttr(...args); + + var FS_chrdev_stream_ops = (...args) => FS.chrdev_stream_ops(...args); + + var FS_major = (...args) => FS.major(...args); + + var FS_minor = (...args) => FS.minor(...args); + + var FS_makedev = (...args) => FS.makedev(...args); + + var FS_registerDevice = (...args) => FS.registerDevice(...args); + + var FS_getDevice = (...args) => FS.getDevice(...args); + + var FS_getMounts = (...args) => FS.getMounts(...args); + + var FS_syncfs = (...args) => FS.syncfs(...args); + + var FS_mount = (...args) => FS.mount(...args); + + var FS_unmount = (...args) => FS.unmount(...args); + + var FS_lookup = (...args) => FS.lookup(...args); + + var FS_mknod = (...args) => FS.mknod(...args); + + var FS_statfs = (...args) => FS.statfs(...args); + + var FS_statfsStream = (...args) => FS.statfsStream(...args); + + var FS_statfsNode = (...args) => FS.statfsNode(...args); + + var FS_create = (...args) => FS.create(...args); + + var FS_mkdir = (...args) => FS.mkdir(...args); + + var FS_mkdev = (...args) => FS.mkdev(...args); + + var FS_symlink = (...args) => FS.symlink(...args); + + var FS_rename = (...args) => FS.rename(...args); + + var FS_rmdir = (...args) => FS.rmdir(...args); + + var FS_readdir = (...args) => FS.readdir(...args); + + var FS_readlink = (...args) => FS.readlink(...args); + + var FS_stat = (...args) => FS.stat(...args); + + var FS_fstat = (...args) => FS.fstat(...args); + + var FS_lstat = (...args) => FS.lstat(...args); + + var FS_doChmod = (...args) => FS.doChmod(...args); + + var FS_chmod = (...args) => FS.chmod(...args); + + var FS_lchmod = (...args) => FS.lchmod(...args); + + var FS_fchmod = (...args) => FS.fchmod(...args); + + var FS_doChown = (...args) => FS.doChown(...args); + + var FS_chown = (...args) => FS.chown(...args); + + var FS_lchown = (...args) => FS.lchown(...args); + + var FS_fchown = (...args) => FS.fchown(...args); + + var FS_doTruncate = (...args) => FS.doTruncate(...args); + + var FS_truncate = (...args) => FS.truncate(...args); + + var FS_ftruncate = (...args) => FS.ftruncate(...args); + + var FS_utime = (...args) => FS.utime(...args); + + var FS_open = (...args) => FS.open(...args); + + var FS_close = (...args) => FS.close(...args); + + var FS_isClosed = (...args) => FS.isClosed(...args); + + var FS_llseek = (...args) => FS.llseek(...args); + + var FS_read = (...args) => FS.read(...args); + + var FS_write = (...args) => FS.write(...args); + + var FS_mmap = (...args) => FS.mmap(...args); + + var FS_msync = (...args) => FS.msync(...args); + + var FS_ioctl = (...args) => FS.ioctl(...args); + + var FS_writeFile = (...args) => FS.writeFile(...args); + + var FS_cwd = (...args) => FS.cwd(...args); + + var FS_chdir = (...args) => FS.chdir(...args); + + var FS_createDefaultDirectories = (...args) => FS.createDefaultDirectories(...args); + + var FS_createDefaultDevices = (...args) => FS.createDefaultDevices(...args); + + var FS_createSpecialDirectories = (...args) => FS.createSpecialDirectories(...args); + + var FS_createStandardStreams = (...args) => FS.createStandardStreams(...args); + + var FS_staticInit = (...args) => FS.staticInit(...args); + + var FS_init = (...args) => FS.init(...args); + + var FS_quit = (...args) => FS.quit(...args); + + var FS_findObject = (...args) => FS.findObject(...args); + + var FS_analyzePath = (...args) => FS.analyzePath(...args); + + var FS_createFile = (...args) => FS.createFile(...args); + + + var FS_forceLoadFile = (...args) => FS.forceLoadFile(...args); + + + + + + + + + + var _setNetworkCallback = (event, userData, callback) => { + function _callback(data) { + callUserCallback(() => { + if (event === 'error') { + withStackSave(() => { + var msg = stringToUTF8OnStack(data[2]); + ((a1, a2, a3, a4) => {} /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(data[0], data[1], msg, userData); + }); + } else { + ((a1, a2) => {} /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(data, userData); + } + }); + }; + + // FIXME(sbc): This has no corresponding Pop so will currently keep the + // runtime alive indefinitely. + runtimeKeepalivePush(); + SOCKFS.on(event, callback ? _callback : null); + }; + + var _emscripten_set_socket_error_callback = (userData, callback) => + _setNetworkCallback('error', userData, callback); + _emscripten_set_socket_error_callback.sig = 'vpp'; + + var _emscripten_set_socket_open_callback = (userData, callback) => + _setNetworkCallback('open', userData, callback); + _emscripten_set_socket_open_callback.sig = 'vpp'; + + var _emscripten_set_socket_listen_callback = (userData, callback) => + _setNetworkCallback('listen', userData, callback); + _emscripten_set_socket_listen_callback.sig = 'vpp'; + + var _emscripten_set_socket_connection_callback = (userData, callback) => + _setNetworkCallback('connection', userData, callback); + _emscripten_set_socket_connection_callback.sig = 'vpp'; + + var _emscripten_set_socket_message_callback = (userData, callback) => + _setNetworkCallback('message', userData, callback); + _emscripten_set_socket_message_callback.sig = 'vpp'; + + var _emscripten_set_socket_close_callback = (userData, callback) => + _setNetworkCallback('close', userData, callback); + _emscripten_set_socket_close_callback.sig = 'vpp'; + + + + + + + + + var _emscripten_webgl_enable_ANGLE_instanced_arrays = (ctx) => webgl_enable_ANGLE_instanced_arrays(GL.contexts[ctx].GLctx); + _emscripten_webgl_enable_ANGLE_instanced_arrays.sig = 'ip'; + + + + var _emscripten_webgl_enable_OES_vertex_array_object = (ctx) => webgl_enable_OES_vertex_array_object(GL.contexts[ctx].GLctx); + _emscripten_webgl_enable_OES_vertex_array_object.sig = 'ip'; + + + + var _emscripten_webgl_enable_WEBGL_draw_buffers = (ctx) => webgl_enable_WEBGL_draw_buffers(GL.contexts[ctx].GLctx); + _emscripten_webgl_enable_WEBGL_draw_buffers.sig = 'ip'; + + + + var _emscripten_webgl_enable_WEBGL_multi_draw = (ctx) => webgl_enable_WEBGL_multi_draw(GL.contexts[ctx].GLctx); + _emscripten_webgl_enable_WEBGL_multi_draw.sig = 'ip'; + + + + var _emscripten_webgl_enable_EXT_polygon_offset_clamp = (ctx) => webgl_enable_EXT_polygon_offset_clamp(GL.contexts[ctx].GLctx); + _emscripten_webgl_enable_EXT_polygon_offset_clamp.sig = 'ip'; + + + + var _emscripten_webgl_enable_EXT_clip_control = (ctx) => webgl_enable_EXT_clip_control(GL.contexts[ctx].GLctx); + _emscripten_webgl_enable_EXT_clip_control.sig = 'ip'; + + + + var _emscripten_webgl_enable_WEBGL_polygon_mode = (ctx) => webgl_enable_WEBGL_polygon_mode(GL.contexts[ctx].GLctx); + _emscripten_webgl_enable_WEBGL_polygon_mode.sig = 'ip'; + + + + + + + + + + + + + + + + + var _glPixelStorei = _emscripten_glPixelStorei; + _glPixelStorei.sig = 'vii'; + + + var _glGetString = _emscripten_glGetString; + _glGetString.sig = 'pi'; + + + var _glGetIntegerv = _emscripten_glGetIntegerv; + _glGetIntegerv.sig = 'vip'; + + + var _glGetFloatv = _emscripten_glGetFloatv; + _glGetFloatv.sig = 'vip'; + + + var _glGetBooleanv = _emscripten_glGetBooleanv; + _glGetBooleanv.sig = 'vip'; + + + var _glDeleteTextures = _emscripten_glDeleteTextures; + _glDeleteTextures.sig = 'vip'; + + + var _glCompressedTexImage2D = _emscripten_glCompressedTexImage2D; + _glCompressedTexImage2D.sig = 'viiiiiiip'; + + + var _glCompressedTexSubImage2D = _emscripten_glCompressedTexSubImage2D; + _glCompressedTexSubImage2D.sig = 'viiiiiiiip'; + + + var _glTexImage2D = _emscripten_glTexImage2D; + _glTexImage2D.sig = 'viiiiiiiip'; + + + var _glTexSubImage2D = _emscripten_glTexSubImage2D; + _glTexSubImage2D.sig = 'viiiiiiiip'; + + + var _glReadPixels = _emscripten_glReadPixels; + _glReadPixels.sig = 'viiiiiip'; + + + var _glBindTexture = _emscripten_glBindTexture; + _glBindTexture.sig = 'vii'; + + + var _glGetTexParameterfv = _emscripten_glGetTexParameterfv; + _glGetTexParameterfv.sig = 'viip'; + + + var _glGetTexParameteriv = _emscripten_glGetTexParameteriv; + _glGetTexParameteriv.sig = 'viip'; + + + var _glTexParameterfv = _emscripten_glTexParameterfv; + _glTexParameterfv.sig = 'viip'; + + + var _glTexParameteriv = _emscripten_glTexParameteriv; + _glTexParameteriv.sig = 'viip'; + + + var _glIsTexture = _emscripten_glIsTexture; + _glIsTexture.sig = 'ii'; + + + var _glGenBuffers = _emscripten_glGenBuffers; + _glGenBuffers.sig = 'vip'; + + + var _glGenTextures = _emscripten_glGenTextures; + _glGenTextures.sig = 'vip'; + + + var _glDeleteBuffers = _emscripten_glDeleteBuffers; + _glDeleteBuffers.sig = 'vip'; + + + var _glGetBufferParameteriv = _emscripten_glGetBufferParameteriv; + _glGetBufferParameteriv.sig = 'viip'; + + + var _glBufferData = _emscripten_glBufferData; + _glBufferData.sig = 'vippi'; + + + var _glBufferSubData = _emscripten_glBufferSubData; + _glBufferSubData.sig = 'vippp'; + + + var _glGenQueriesEXT = _emscripten_glGenQueriesEXT; + + + var _glDeleteQueriesEXT = _emscripten_glDeleteQueriesEXT; + + + var _glIsQueryEXT = _emscripten_glIsQueryEXT; + + + var _glBeginQueryEXT = _emscripten_glBeginQueryEXT; + + + var _glEndQueryEXT = _emscripten_glEndQueryEXT; + + + var _glQueryCounterEXT = _emscripten_glQueryCounterEXT; + + + var _glGetQueryivEXT = _emscripten_glGetQueryivEXT; + + + var _glGetQueryObjectivEXT = _emscripten_glGetQueryObjectivEXT; + + + var _glGetQueryObjectuivEXT = _emscripten_glGetQueryObjectivEXT; + + + var _glGetQueryObjecti64vEXT = _emscripten_glGetQueryObjecti64vEXT; + + + var _glGetQueryObjectui64vEXT = _emscripten_glGetQueryObjecti64vEXT; + + + var _glIsBuffer = _emscripten_glIsBuffer; + _glIsBuffer.sig = 'ii'; + + + var _glGenRenderbuffers = _emscripten_glGenRenderbuffers; + _glGenRenderbuffers.sig = 'vip'; + + + var _glDeleteRenderbuffers = _emscripten_glDeleteRenderbuffers; + _glDeleteRenderbuffers.sig = 'vip'; + + + var _glBindRenderbuffer = _emscripten_glBindRenderbuffer; + _glBindRenderbuffer.sig = 'vii'; + + + var _glGetRenderbufferParameteriv = _emscripten_glGetRenderbufferParameteriv; + _glGetRenderbufferParameteriv.sig = 'viip'; + + + var _glIsRenderbuffer = _emscripten_glIsRenderbuffer; + _glIsRenderbuffer.sig = 'ii'; + + + var _glGetUniformfv = _emscripten_glGetUniformfv; + _glGetUniformfv.sig = 'viip'; + + + var _glGetUniformiv = _emscripten_glGetUniformiv; + _glGetUniformiv.sig = 'viip'; + + + var _glGetUniformLocation = _emscripten_glGetUniformLocation; + _glGetUniformLocation.sig = 'iip'; + + + var _glGetVertexAttribfv = _emscripten_glGetVertexAttribfv; + _glGetVertexAttribfv.sig = 'viip'; + + + var _glGetVertexAttribiv = _emscripten_glGetVertexAttribiv; + _glGetVertexAttribiv.sig = 'viip'; + + + var _glGetVertexAttribPointerv = _emscripten_glGetVertexAttribPointerv; + _glGetVertexAttribPointerv.sig = 'viip'; + + + var _glUniform1f = _emscripten_glUniform1f; + _glUniform1f.sig = 'vif'; + + + var _glUniform2f = _emscripten_glUniform2f; + _glUniform2f.sig = 'viff'; + + + var _glUniform3f = _emscripten_glUniform3f; + _glUniform3f.sig = 'vifff'; + + + var _glUniform4f = _emscripten_glUniform4f; + _glUniform4f.sig = 'viffff'; + + + var _glUniform1i = _emscripten_glUniform1i; + _glUniform1i.sig = 'vii'; + + + var _glUniform2i = _emscripten_glUniform2i; + _glUniform2i.sig = 'viii'; + + + var _glUniform3i = _emscripten_glUniform3i; + _glUniform3i.sig = 'viiii'; + + + var _glUniform4i = _emscripten_glUniform4i; + _glUniform4i.sig = 'viiiii'; + + + var _glUniform1iv = _emscripten_glUniform1iv; + _glUniform1iv.sig = 'viip'; + + + var _glUniform2iv = _emscripten_glUniform2iv; + _glUniform2iv.sig = 'viip'; + + + var _glUniform3iv = _emscripten_glUniform3iv; + _glUniform3iv.sig = 'viip'; + + + var _glUniform4iv = _emscripten_glUniform4iv; + _glUniform4iv.sig = 'viip'; + + + var _glUniform1fv = _emscripten_glUniform1fv; + _glUniform1fv.sig = 'viip'; + + + var _glUniform2fv = _emscripten_glUniform2fv; + _glUniform2fv.sig = 'viip'; + + + var _glUniform3fv = _emscripten_glUniform3fv; + _glUniform3fv.sig = 'viip'; + + + var _glUniform4fv = _emscripten_glUniform4fv; + _glUniform4fv.sig = 'viip'; + + + var _glUniformMatrix2fv = _emscripten_glUniformMatrix2fv; + _glUniformMatrix2fv.sig = 'viiip'; + + + var _glUniformMatrix3fv = _emscripten_glUniformMatrix3fv; + _glUniformMatrix3fv.sig = 'viiip'; + + + var _glUniformMatrix4fv = _emscripten_glUniformMatrix4fv; + _glUniformMatrix4fv.sig = 'viiip'; + + + var _glBindBuffer = _emscripten_glBindBuffer; + _glBindBuffer.sig = 'vii'; + + + var _glVertexAttrib1fv = _emscripten_glVertexAttrib1fv; + _glVertexAttrib1fv.sig = 'vip'; + + + var _glVertexAttrib2fv = _emscripten_glVertexAttrib2fv; + _glVertexAttrib2fv.sig = 'vip'; + + + var _glVertexAttrib3fv = _emscripten_glVertexAttrib3fv; + _glVertexAttrib3fv.sig = 'vip'; + + + var _glVertexAttrib4fv = _emscripten_glVertexAttrib4fv; + _glVertexAttrib4fv.sig = 'vip'; + + + var _glGetAttribLocation = _emscripten_glGetAttribLocation; + _glGetAttribLocation.sig = 'iip'; + + + var _glGetActiveAttrib = _emscripten_glGetActiveAttrib; + _glGetActiveAttrib.sig = 'viiipppp'; + + + var _glGetActiveUniform = _emscripten_glGetActiveUniform; + _glGetActiveUniform.sig = 'viiipppp'; + + + var _glCreateShader = _emscripten_glCreateShader; + _glCreateShader.sig = 'ii'; + + + var _glDeleteShader = _emscripten_glDeleteShader; + _glDeleteShader.sig = 'vi'; + + + var _glGetAttachedShaders = _emscripten_glGetAttachedShaders; + _glGetAttachedShaders.sig = 'viipp'; + + + var _glShaderSource = _emscripten_glShaderSource; + _glShaderSource.sig = 'viipp'; + + + var _glGetShaderSource = _emscripten_glGetShaderSource; + _glGetShaderSource.sig = 'viipp'; + + + var _glCompileShader = _emscripten_glCompileShader; + _glCompileShader.sig = 'vi'; + + + var _glGetShaderInfoLog = _emscripten_glGetShaderInfoLog; + _glGetShaderInfoLog.sig = 'viipp'; + + + var _glGetShaderiv = _emscripten_glGetShaderiv; + _glGetShaderiv.sig = 'viip'; + + + var _glGetProgramiv = _emscripten_glGetProgramiv; + _glGetProgramiv.sig = 'viip'; + + + var _glIsShader = _emscripten_glIsShader; + _glIsShader.sig = 'ii'; + + + var _glCreateProgram = _emscripten_glCreateProgram; + _glCreateProgram.sig = 'i'; + + + var _glDeleteProgram = _emscripten_glDeleteProgram; + _glDeleteProgram.sig = 'vi'; + + + var _glAttachShader = _emscripten_glAttachShader; + _glAttachShader.sig = 'vii'; + + + var _glDetachShader = _emscripten_glDetachShader; + _glDetachShader.sig = 'vii'; + + + var _glGetShaderPrecisionFormat = _emscripten_glGetShaderPrecisionFormat; + _glGetShaderPrecisionFormat.sig = 'viipp'; + + + var _glLinkProgram = _emscripten_glLinkProgram; + _glLinkProgram.sig = 'vi'; + + + var _glGetProgramInfoLog = _emscripten_glGetProgramInfoLog; + _glGetProgramInfoLog.sig = 'viipp'; + + + var _glUseProgram = _emscripten_glUseProgram; + _glUseProgram.sig = 'vi'; + + + var _glValidateProgram = _emscripten_glValidateProgram; + _glValidateProgram.sig = 'vi'; + + + var _glIsProgram = _emscripten_glIsProgram; + _glIsProgram.sig = 'ii'; + + + var _glBindAttribLocation = _emscripten_glBindAttribLocation; + _glBindAttribLocation.sig = 'viip'; + - var _emscripten_set_socket_message_callback = (userData, callback) => - _setNetworkCallback('message', userData, callback); - _emscripten_set_socket_message_callback.sig = 'vpp'; + var _glBindFramebuffer = _emscripten_glBindFramebuffer; + _glBindFramebuffer.sig = 'vii'; - var _emscripten_set_socket_close_callback = (userData, callback) => - _setNetworkCallback('close', userData, callback); - _emscripten_set_socket_close_callback.sig = 'vpp'; - var _emscripten_webgl_enable_ANGLE_instanced_arrays = (ctx) => - webgl_enable_ANGLE_instanced_arrays(GL.contexts[ctx].GLctx); - _emscripten_webgl_enable_ANGLE_instanced_arrays.sig = 'ip'; + var _glGenFramebuffers = _emscripten_glGenFramebuffers; + _glGenFramebuffers.sig = 'vip'; - var _emscripten_webgl_enable_OES_vertex_array_object = (ctx) => - webgl_enable_OES_vertex_array_object(GL.contexts[ctx].GLctx); - _emscripten_webgl_enable_OES_vertex_array_object.sig = 'ip'; - var _emscripten_webgl_enable_WEBGL_draw_buffers = (ctx) => - webgl_enable_WEBGL_draw_buffers(GL.contexts[ctx].GLctx); - _emscripten_webgl_enable_WEBGL_draw_buffers.sig = 'ip'; + var _glDeleteFramebuffers = _emscripten_glDeleteFramebuffers; + _glDeleteFramebuffers.sig = 'vip'; - var _emscripten_webgl_enable_WEBGL_multi_draw = (ctx) => - webgl_enable_WEBGL_multi_draw(GL.contexts[ctx].GLctx); - _emscripten_webgl_enable_WEBGL_multi_draw.sig = 'ip'; - var _emscripten_webgl_enable_EXT_polygon_offset_clamp = (ctx) => - webgl_enable_EXT_polygon_offset_clamp(GL.contexts[ctx].GLctx); - _emscripten_webgl_enable_EXT_polygon_offset_clamp.sig = 'ip'; + var _glFramebufferRenderbuffer = _emscripten_glFramebufferRenderbuffer; + _glFramebufferRenderbuffer.sig = 'viiii'; - var _emscripten_webgl_enable_EXT_clip_control = (ctx) => - webgl_enable_EXT_clip_control(GL.contexts[ctx].GLctx); - _emscripten_webgl_enable_EXT_clip_control.sig = 'ip'; - var _emscripten_webgl_enable_WEBGL_polygon_mode = (ctx) => - webgl_enable_WEBGL_polygon_mode(GL.contexts[ctx].GLctx); - _emscripten_webgl_enable_WEBGL_polygon_mode.sig = 'ip'; + var _glFramebufferTexture2D = _emscripten_glFramebufferTexture2D; + _glFramebufferTexture2D.sig = 'viiiii'; - var _glPixelStorei = _emscripten_glPixelStorei; - _glPixelStorei.sig = 'vii'; - var _glGetString = _emscripten_glGetString; - _glGetString.sig = 'pi'; + var _glGetFramebufferAttachmentParameteriv = _emscripten_glGetFramebufferAttachmentParameteriv; + _glGetFramebufferAttachmentParameteriv.sig = 'viiip'; - var _glGetIntegerv = _emscripten_glGetIntegerv; - _glGetIntegerv.sig = 'vip'; - var _glGetFloatv = _emscripten_glGetFloatv; - _glGetFloatv.sig = 'vip'; + var _glIsFramebuffer = _emscripten_glIsFramebuffer; + _glIsFramebuffer.sig = 'ii'; - var _glGetBooleanv = _emscripten_glGetBooleanv; - _glGetBooleanv.sig = 'vip'; - var _glDeleteTextures = _emscripten_glDeleteTextures; - _glDeleteTextures.sig = 'vip'; + var _glGenVertexArrays = _emscripten_glGenVertexArrays; + _glGenVertexArrays.sig = 'vip'; - var _glCompressedTexImage2D = _emscripten_glCompressedTexImage2D; - _glCompressedTexImage2D.sig = 'viiiiiiip'; - var _glCompressedTexSubImage2D = _emscripten_glCompressedTexSubImage2D; - _glCompressedTexSubImage2D.sig = 'viiiiiiiip'; + var _glDeleteVertexArrays = _emscripten_glDeleteVertexArrays; + _glDeleteVertexArrays.sig = 'vip'; - var _glTexImage2D = _emscripten_glTexImage2D; - _glTexImage2D.sig = 'viiiiiiiip'; - var _glTexSubImage2D = _emscripten_glTexSubImage2D; - _glTexSubImage2D.sig = 'viiiiiiiip'; + var _glBindVertexArray = _emscripten_glBindVertexArray; + _glBindVertexArray.sig = 'vi'; - var _glReadPixels = _emscripten_glReadPixels; - _glReadPixels.sig = 'viiiiiip'; - var _glBindTexture = _emscripten_glBindTexture; - _glBindTexture.sig = 'vii'; + var _glIsVertexArray = _emscripten_glIsVertexArray; + _glIsVertexArray.sig = 'ii'; - var _glGetTexParameterfv = _emscripten_glGetTexParameterfv; - _glGetTexParameterfv.sig = 'viip'; + var _emscripten_glVertexPointer = (size, type, stride, ptr) => + abort('Legacy GL function (glVertexPointer) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation.'); + _emscripten_glVertexPointer.sig = 'viiip'; - var _glGetTexParameteriv = _emscripten_glGetTexParameteriv; - _glGetTexParameteriv.sig = 'viip'; + var _glVertexPointer = _emscripten_glVertexPointer; + _glVertexPointer.sig = 'viiip'; - var _glTexParameterfv = _emscripten_glTexParameterfv; - _glTexParameterfv.sig = 'viip'; + var _emscripten_glMatrixMode = () => + abort('Legacy GL function (glMatrixMode) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation.'); + _emscripten_glMatrixMode.sig = 'vi'; - var _glTexParameteriv = _emscripten_glTexParameteriv; - _glTexParameteriv.sig = 'viip'; + var _glMatrixMode = _emscripten_glMatrixMode; + _glMatrixMode.sig = 'vi'; - var _glIsTexture = _emscripten_glIsTexture; - _glIsTexture.sig = 'ii'; + var _emscripten_glBegin = () => + abort('Legacy GL function (glBegin) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation.'); + _emscripten_glBegin.sig = 'vi'; - var _glGenBuffers = _emscripten_glGenBuffers; - _glGenBuffers.sig = 'vip'; + var _glBegin = _emscripten_glBegin; + _glBegin.sig = 'vi'; - var _glGenTextures = _emscripten_glGenTextures; - _glGenTextures.sig = 'vip'; + var _emscripten_glLoadIdentity = () => + abort('Legacy GL function (glLoadIdentity) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation.'); + _emscripten_glLoadIdentity.sig = 'v'; - var _glDeleteBuffers = _emscripten_glDeleteBuffers; - _glDeleteBuffers.sig = 'vip'; + var _glLoadIdentity = _emscripten_glLoadIdentity; + _glLoadIdentity.sig = 'v'; - var _glGetBufferParameteriv = _emscripten_glGetBufferParameteriv; - _glGetBufferParameteriv.sig = 'viip'; - var _glBufferData = _emscripten_glBufferData; - _glBufferData.sig = 'vippi'; + var _glGenVertexArraysOES = _emscripten_glGenVertexArrays; + _glGenVertexArraysOES.sig = 'vip'; - var _glBufferSubData = _emscripten_glBufferSubData; - _glBufferSubData.sig = 'vippp'; - var _glGenQueriesEXT = _emscripten_glGenQueriesEXT; + var _glDeleteVertexArraysOES = _emscripten_glDeleteVertexArrays; + _glDeleteVertexArraysOES.sig = 'vip'; - var _glDeleteQueriesEXT = _emscripten_glDeleteQueriesEXT; - var _glIsQueryEXT = _emscripten_glIsQueryEXT; + var _glBindVertexArrayOES = _emscripten_glBindVertexArray; + _glBindVertexArrayOES.sig = 'vi'; - var _glBeginQueryEXT = _emscripten_glBeginQueryEXT; - var _glEndQueryEXT = _emscripten_glEndQueryEXT; + var _glIsVertexArrayOES = _emscripten_glIsVertexArray; + _glIsVertexArrayOES.sig = 'ii'; - var _glQueryCounterEXT = _emscripten_glQueryCounterEXT; - var _glGetQueryivEXT = _emscripten_glGetQueryivEXT; + var _glVertexAttribPointer = _emscripten_glVertexAttribPointer; + _glVertexAttribPointer.sig = 'viiiiip'; - var _glGetQueryObjectivEXT = _emscripten_glGetQueryObjectivEXT; - var _glGetQueryObjectuivEXT = _emscripten_glGetQueryObjectivEXT; + var _glEnableVertexAttribArray = _emscripten_glEnableVertexAttribArray; + _glEnableVertexAttribArray.sig = 'vi'; - var _glGetQueryObjecti64vEXT = _emscripten_glGetQueryObjecti64vEXT; - var _glGetQueryObjectui64vEXT = _emscripten_glGetQueryObjecti64vEXT; + var _glDisableVertexAttribArray = _emscripten_glDisableVertexAttribArray; + _glDisableVertexAttribArray.sig = 'vi'; - var _glIsBuffer = _emscripten_glIsBuffer; - _glIsBuffer.sig = 'ii'; - var _glGenRenderbuffers = _emscripten_glGenRenderbuffers; - _glGenRenderbuffers.sig = 'vip'; + var _glDrawArrays = _emscripten_glDrawArrays; + _glDrawArrays.sig = 'viii'; - var _glDeleteRenderbuffers = _emscripten_glDeleteRenderbuffers; - _glDeleteRenderbuffers.sig = 'vip'; - var _glBindRenderbuffer = _emscripten_glBindRenderbuffer; - _glBindRenderbuffer.sig = 'vii'; + var _glDrawElements = _emscripten_glDrawElements; + _glDrawElements.sig = 'viiip'; - var _glGetRenderbufferParameteriv = - _emscripten_glGetRenderbufferParameteriv; - _glGetRenderbufferParameteriv.sig = 'viip'; - var _glIsRenderbuffer = _emscripten_glIsRenderbuffer; - _glIsRenderbuffer.sig = 'ii'; + var _glShaderBinary = _emscripten_glShaderBinary; + _glShaderBinary.sig = 'vipipi'; - var _glGetUniformfv = _emscripten_glGetUniformfv; - _glGetUniformfv.sig = 'viip'; - var _glGetUniformiv = _emscripten_glGetUniformiv; - _glGetUniformiv.sig = 'viip'; + var _glReleaseShaderCompiler = _emscripten_glReleaseShaderCompiler; + _glReleaseShaderCompiler.sig = 'v'; - var _glGetUniformLocation = _emscripten_glGetUniformLocation; - _glGetUniformLocation.sig = 'iip'; - var _glGetVertexAttribfv = _emscripten_glGetVertexAttribfv; - _glGetVertexAttribfv.sig = 'viip'; + var _glGetError = _emscripten_glGetError; + _glGetError.sig = 'i'; - var _glGetVertexAttribiv = _emscripten_glGetVertexAttribiv; - _glGetVertexAttribiv.sig = 'viip'; - var _glGetVertexAttribPointerv = _emscripten_glGetVertexAttribPointerv; - _glGetVertexAttribPointerv.sig = 'viip'; + var _glVertexAttribDivisor = _emscripten_glVertexAttribDivisor; + _glVertexAttribDivisor.sig = 'vii'; - var _glUniform1f = _emscripten_glUniform1f; - _glUniform1f.sig = 'vif'; - var _glUniform2f = _emscripten_glUniform2f; - _glUniform2f.sig = 'viff'; + var _glDrawArraysInstanced = _emscripten_glDrawArraysInstanced; + _glDrawArraysInstanced.sig = 'viiii'; - var _glUniform3f = _emscripten_glUniform3f; - _glUniform3f.sig = 'vifff'; - var _glUniform4f = _emscripten_glUniform4f; - _glUniform4f.sig = 'viffff'; + var _glDrawElementsInstanced = _emscripten_glDrawElementsInstanced; + _glDrawElementsInstanced.sig = 'viiipi'; - var _glUniform1i = _emscripten_glUniform1i; - _glUniform1i.sig = 'vii'; + + var _emscripten_glVertexAttribDivisorNV = _emscripten_glVertexAttribDivisor; - var _glUniform2i = _emscripten_glUniform2i; - _glUniform2i.sig = 'viii'; + var _glVertexAttribDivisorNV = _emscripten_glVertexAttribDivisor; - var _glUniform3i = _emscripten_glUniform3i; - _glUniform3i.sig = 'viiii'; + + var _emscripten_glDrawArraysInstancedNV = _emscripten_glDrawArraysInstanced; - var _glUniform4i = _emscripten_glUniform4i; - _glUniform4i.sig = 'viiiii'; + var _glDrawArraysInstancedNV = _emscripten_glDrawArraysInstanced; - var _glUniform1iv = _emscripten_glUniform1iv; - _glUniform1iv.sig = 'viip'; + + var _emscripten_glDrawElementsInstancedNV = _emscripten_glDrawElementsInstanced; - var _glUniform2iv = _emscripten_glUniform2iv; - _glUniform2iv.sig = 'viip'; + var _glDrawElementsInstancedNV = _emscripten_glDrawElementsInstanced; - var _glUniform3iv = _emscripten_glUniform3iv; - _glUniform3iv.sig = 'viip'; + + var _emscripten_glVertexAttribDivisorEXT = _emscripten_glVertexAttribDivisor; - var _glUniform4iv = _emscripten_glUniform4iv; - _glUniform4iv.sig = 'viip'; + var _glVertexAttribDivisorEXT = _emscripten_glVertexAttribDivisor; - var _glUniform1fv = _emscripten_glUniform1fv; - _glUniform1fv.sig = 'viip'; + + var _emscripten_glDrawArraysInstancedEXT = _emscripten_glDrawArraysInstanced; - var _glUniform2fv = _emscripten_glUniform2fv; - _glUniform2fv.sig = 'viip'; + var _glDrawArraysInstancedEXT = _emscripten_glDrawArraysInstanced; - var _glUniform3fv = _emscripten_glUniform3fv; - _glUniform3fv.sig = 'viip'; + + var _emscripten_glDrawElementsInstancedEXT = _emscripten_glDrawElementsInstanced; - var _glUniform4fv = _emscripten_glUniform4fv; - _glUniform4fv.sig = 'viip'; + var _glDrawElementsInstancedEXT = _emscripten_glDrawElementsInstanced; - var _glUniformMatrix2fv = _emscripten_glUniformMatrix2fv; - _glUniformMatrix2fv.sig = 'viiip'; + + var _emscripten_glVertexAttribDivisorARB = _emscripten_glVertexAttribDivisor; - var _glUniformMatrix3fv = _emscripten_glUniformMatrix3fv; - _glUniformMatrix3fv.sig = 'viiip'; + var _glVertexAttribDivisorARB = _emscripten_glVertexAttribDivisor; - var _glUniformMatrix4fv = _emscripten_glUniformMatrix4fv; - _glUniformMatrix4fv.sig = 'viiip'; + + var _emscripten_glDrawArraysInstancedARB = _emscripten_glDrawArraysInstanced; - var _glBindBuffer = _emscripten_glBindBuffer; - _glBindBuffer.sig = 'vii'; + var _glDrawArraysInstancedARB = _emscripten_glDrawArraysInstanced; - var _glVertexAttrib1fv = _emscripten_glVertexAttrib1fv; - _glVertexAttrib1fv.sig = 'vip'; + + var _emscripten_glDrawElementsInstancedARB = _emscripten_glDrawElementsInstanced; - var _glVertexAttrib2fv = _emscripten_glVertexAttrib2fv; - _glVertexAttrib2fv.sig = 'vip'; + var _glDrawElementsInstancedARB = _emscripten_glDrawElementsInstanced; - var _glVertexAttrib3fv = _emscripten_glVertexAttrib3fv; - _glVertexAttrib3fv.sig = 'vip'; - var _glVertexAttrib4fv = _emscripten_glVertexAttrib4fv; - _glVertexAttrib4fv.sig = 'vip'; + var _glVertexAttribDivisorANGLE = _emscripten_glVertexAttribDivisor; - var _glGetAttribLocation = _emscripten_glGetAttribLocation; - _glGetAttribLocation.sig = 'iip'; - var _glGetActiveAttrib = _emscripten_glGetActiveAttrib; - _glGetActiveAttrib.sig = 'viiipppp'; + var _glDrawArraysInstancedANGLE = _emscripten_glDrawArraysInstanced; - var _glGetActiveUniform = _emscripten_glGetActiveUniform; - _glGetActiveUniform.sig = 'viiipppp'; - var _glCreateShader = _emscripten_glCreateShader; - _glCreateShader.sig = 'ii'; + var _glDrawElementsInstancedANGLE = _emscripten_glDrawElementsInstanced; - var _glDeleteShader = _emscripten_glDeleteShader; - _glDeleteShader.sig = 'vi'; - var _glGetAttachedShaders = _emscripten_glGetAttachedShaders; - _glGetAttachedShaders.sig = 'viipp'; + var _glDrawBuffers = _emscripten_glDrawBuffers; + _glDrawBuffers.sig = 'vip'; - var _glShaderSource = _emscripten_glShaderSource; - _glShaderSource.sig = 'viipp'; + + var _emscripten_glDrawBuffersEXT = _emscripten_glDrawBuffers; - var _glGetShaderSource = _emscripten_glGetShaderSource; - _glGetShaderSource.sig = 'viipp'; + var _glDrawBuffersEXT = _emscripten_glDrawBuffers; - var _glCompileShader = _emscripten_glCompileShader; - _glCompileShader.sig = 'vi'; - var _glGetShaderInfoLog = _emscripten_glGetShaderInfoLog; - _glGetShaderInfoLog.sig = 'viipp'; + var _glDrawBuffersWEBGL = _emscripten_glDrawBuffers; - var _glGetShaderiv = _emscripten_glGetShaderiv; - _glGetShaderiv.sig = 'viip'; - var _glGetProgramiv = _emscripten_glGetProgramiv; - _glGetProgramiv.sig = 'viip'; + var _glColorMask = _emscripten_glColorMask; + _glColorMask.sig = 'viiii'; - var _glIsShader = _emscripten_glIsShader; - _glIsShader.sig = 'ii'; - var _glCreateProgram = _emscripten_glCreateProgram; - _glCreateProgram.sig = 'i'; + var _glDepthMask = _emscripten_glDepthMask; + _glDepthMask.sig = 'vi'; - var _glDeleteProgram = _emscripten_glDeleteProgram; - _glDeleteProgram.sig = 'vi'; - var _glAttachShader = _emscripten_glAttachShader; - _glAttachShader.sig = 'vii'; + var _glSampleCoverage = _emscripten_glSampleCoverage; + _glSampleCoverage.sig = 'vfi'; - var _glDetachShader = _emscripten_glDetachShader; - _glDetachShader.sig = 'vii'; + + var _emscripten_glMultiDrawArraysWEBGL = (mode, firsts, counts, drawcount) => { + GLctx.multiDrawWebgl['multiDrawArraysWEBGL']( + mode, + HEAP32, + ((firsts)>>2), + HEAP32, + ((counts)>>2), + drawcount); + }; + _emscripten_glMultiDrawArraysWEBGL.sig = 'vippi'; + var _emscripten_glMultiDrawArrays = _emscripten_glMultiDrawArraysWEBGL; + _emscripten_glMultiDrawArrays.sig = 'vippi'; - var _glGetShaderPrecisionFormat = _emscripten_glGetShaderPrecisionFormat; - _glGetShaderPrecisionFormat.sig = 'viipp'; + var _glMultiDrawArrays = _emscripten_glMultiDrawArraysWEBGL; + _glMultiDrawArrays.sig = 'vippi'; - var _glLinkProgram = _emscripten_glLinkProgram; - _glLinkProgram.sig = 'vi'; + + var _emscripten_glMultiDrawArraysANGLE = _emscripten_glMultiDrawArraysWEBGL; - var _glGetProgramInfoLog = _emscripten_glGetProgramInfoLog; - _glGetProgramInfoLog.sig = 'viipp'; + var _glMultiDrawArraysANGLE = _emscripten_glMultiDrawArraysWEBGL; - var _glUseProgram = _emscripten_glUseProgram; - _glUseProgram.sig = 'vi'; - var _glValidateProgram = _emscripten_glValidateProgram; - _glValidateProgram.sig = 'vi'; + var _glMultiDrawArraysWEBGL = _emscripten_glMultiDrawArraysWEBGL; - var _glIsProgram = _emscripten_glIsProgram; - _glIsProgram.sig = 'ii'; + + var _emscripten_glMultiDrawArraysInstancedWEBGL = (mode, firsts, counts, instanceCounts, drawcount) => { + GLctx.multiDrawWebgl['multiDrawArraysInstancedWEBGL']( + mode, + HEAP32, + ((firsts)>>2), + HEAP32, + ((counts)>>2), + HEAP32, + ((instanceCounts)>>2), + drawcount); + }; + _emscripten_glMultiDrawArraysInstancedWEBGL.sig = 'vipppi'; + var _emscripten_glMultiDrawArraysInstancedANGLE = _emscripten_glMultiDrawArraysInstancedWEBGL; - var _glBindAttribLocation = _emscripten_glBindAttribLocation; - _glBindAttribLocation.sig = 'viip'; + var _glMultiDrawArraysInstancedANGLE = _emscripten_glMultiDrawArraysInstancedWEBGL; - var _glBindFramebuffer = _emscripten_glBindFramebuffer; - _glBindFramebuffer.sig = 'vii'; - var _glGenFramebuffers = _emscripten_glGenFramebuffers; - _glGenFramebuffers.sig = 'vip'; + var _glMultiDrawArraysInstancedWEBGL = _emscripten_glMultiDrawArraysInstancedWEBGL; - var _glDeleteFramebuffers = _emscripten_glDeleteFramebuffers; - _glDeleteFramebuffers.sig = 'vip'; + + var _emscripten_glMultiDrawElementsWEBGL = (mode, counts, type, offsets, drawcount) => { + GLctx.multiDrawWebgl['multiDrawElementsWEBGL']( + mode, + HEAP32, + ((counts)>>2), + type, + HEAP32, + ((offsets)>>2), + drawcount); + }; + _emscripten_glMultiDrawElementsWEBGL.sig = 'vipipi'; + var _emscripten_glMultiDrawElements = _emscripten_glMultiDrawElementsWEBGL; + _emscripten_glMultiDrawElements.sig = 'vipipi'; - var _glFramebufferRenderbuffer = _emscripten_glFramebufferRenderbuffer; - _glFramebufferRenderbuffer.sig = 'viiii'; + var _glMultiDrawElements = _emscripten_glMultiDrawElementsWEBGL; + _glMultiDrawElements.sig = 'vipipi'; - var _glFramebufferTexture2D = _emscripten_glFramebufferTexture2D; - _glFramebufferTexture2D.sig = 'viiiii'; + + var _emscripten_glMultiDrawElementsANGLE = _emscripten_glMultiDrawElementsWEBGL; - var _glGetFramebufferAttachmentParameteriv = - _emscripten_glGetFramebufferAttachmentParameteriv; - _glGetFramebufferAttachmentParameteriv.sig = 'viiip'; + var _glMultiDrawElementsANGLE = _emscripten_glMultiDrawElementsWEBGL; - var _glIsFramebuffer = _emscripten_glIsFramebuffer; - _glIsFramebuffer.sig = 'ii'; - var _glGenVertexArrays = _emscripten_glGenVertexArrays; - _glGenVertexArrays.sig = 'vip'; + var _glMultiDrawElementsWEBGL = _emscripten_glMultiDrawElementsWEBGL; - var _glDeleteVertexArrays = _emscripten_glDeleteVertexArrays; - _glDeleteVertexArrays.sig = 'vip'; + + var _emscripten_glMultiDrawElementsInstancedWEBGL = (mode, counts, type, offsets, instanceCounts, drawcount) => { + GLctx.multiDrawWebgl['multiDrawElementsInstancedWEBGL']( + mode, + HEAP32, + ((counts)>>2), + type, + HEAP32, + ((offsets)>>2), + HEAP32, + ((instanceCounts)>>2), + drawcount); + }; + _emscripten_glMultiDrawElementsInstancedWEBGL.sig = 'vipippi'; + var _emscripten_glMultiDrawElementsInstancedANGLE = _emscripten_glMultiDrawElementsInstancedWEBGL; - var _glBindVertexArray = _emscripten_glBindVertexArray; - _glBindVertexArray.sig = 'vi'; + var _glMultiDrawElementsInstancedANGLE = _emscripten_glMultiDrawElementsInstancedWEBGL; - var _glIsVertexArray = _emscripten_glIsVertexArray; - _glIsVertexArray.sig = 'ii'; - var _emscripten_glVertexPointer = (size, type, stride, ptr) => - abort( - 'Legacy GL function (glVertexPointer) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation.' - ); - _emscripten_glVertexPointer.sig = 'viiip'; + var _glMultiDrawElementsInstancedWEBGL = _emscripten_glMultiDrawElementsInstancedWEBGL; - var _glVertexPointer = _emscripten_glVertexPointer; - _glVertexPointer.sig = 'viiip'; - var _emscripten_glMatrixMode = () => - abort( - 'Legacy GL function (glMatrixMode) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation.' - ); - _emscripten_glMatrixMode.sig = 'vi'; + var _glPolygonOffsetClampEXT = _emscripten_glPolygonOffsetClampEXT; - var _glMatrixMode = _emscripten_glMatrixMode; - _glMatrixMode.sig = 'vi'; - var _emscripten_glBegin = () => - abort( - 'Legacy GL function (glBegin) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation.' - ); - _emscripten_glBegin.sig = 'vi'; + var _glClipControlEXT = _emscripten_glClipControlEXT; + + + var _glPolygonModeWEBGL = _emscripten_glPolygonModeWEBGL; + + + var _glFinish = _emscripten_glFinish; + _glFinish.sig = 'v'; + + + var _glFlush = _emscripten_glFlush; + _glFlush.sig = 'v'; + + var _emscripten_glClearDepth = (x0) => GLctx.clearDepth(x0); + _emscripten_glClearDepth.sig = 'vd'; + + var _glClearDepth = _emscripten_glClearDepth; + _glClearDepth.sig = 'vd'; + + + var _glClearDepthf = _emscripten_glClearDepthf; + _glClearDepthf.sig = 'vf'; + + + var _glDepthFunc = _emscripten_glDepthFunc; + _glDepthFunc.sig = 'vi'; + + + var _glEnable = _emscripten_glEnable; + _glEnable.sig = 'vi'; + + + var _glDisable = _emscripten_glDisable; + _glDisable.sig = 'vi'; + + + var _glFrontFace = _emscripten_glFrontFace; + _glFrontFace.sig = 'vi'; + + + var _glCullFace = _emscripten_glCullFace; + _glCullFace.sig = 'vi'; + + + var _glClear = _emscripten_glClear; + _glClear.sig = 'vi'; + + + var _glLineWidth = _emscripten_glLineWidth; + _glLineWidth.sig = 'vf'; + + + var _glClearStencil = _emscripten_glClearStencil; + _glClearStencil.sig = 'vi'; + + + var _glStencilMask = _emscripten_glStencilMask; + _glStencilMask.sig = 'vi'; + + + var _glCheckFramebufferStatus = _emscripten_glCheckFramebufferStatus; + _glCheckFramebufferStatus.sig = 'ii'; + + + var _glGenerateMipmap = _emscripten_glGenerateMipmap; + _glGenerateMipmap.sig = 'vi'; + + + var _glActiveTexture = _emscripten_glActiveTexture; + _glActiveTexture.sig = 'vi'; + + + var _glBlendEquation = _emscripten_glBlendEquation; + _glBlendEquation.sig = 'vi'; + + + var _glIsEnabled = _emscripten_glIsEnabled; + _glIsEnabled.sig = 'ii'; + + + var _glBlendFunc = _emscripten_glBlendFunc; + _glBlendFunc.sig = 'vii'; + + + var _glBlendEquationSeparate = _emscripten_glBlendEquationSeparate; + _glBlendEquationSeparate.sig = 'vii'; + + var _emscripten_glDepthRange = (x0, x1) => GLctx.depthRange(x0, x1); + _emscripten_glDepthRange.sig = 'vdd'; + + var _glDepthRange = _emscripten_glDepthRange; + _glDepthRange.sig = 'vdd'; + + + var _glDepthRangef = _emscripten_glDepthRangef; + _glDepthRangef.sig = 'vff'; + + + var _glStencilMaskSeparate = _emscripten_glStencilMaskSeparate; + _glStencilMaskSeparate.sig = 'vii'; + + + var _glHint = _emscripten_glHint; + _glHint.sig = 'vii'; + + + var _glPolygonOffset = _emscripten_glPolygonOffset; + _glPolygonOffset.sig = 'vff'; + + + var _glVertexAttrib1f = _emscripten_glVertexAttrib1f; + _glVertexAttrib1f.sig = 'vif'; + + + var _glTexParameteri = _emscripten_glTexParameteri; + _glTexParameteri.sig = 'viii'; + + + var _glTexParameterf = _emscripten_glTexParameterf; + _glTexParameterf.sig = 'viif'; + + + var _glVertexAttrib2f = _emscripten_glVertexAttrib2f; + _glVertexAttrib2f.sig = 'viff'; + + + var _glStencilFunc = _emscripten_glStencilFunc; + _glStencilFunc.sig = 'viii'; + + + var _glStencilOp = _emscripten_glStencilOp; + _glStencilOp.sig = 'viii'; + + + var _glViewport = _emscripten_glViewport; + _glViewport.sig = 'viiii'; + + + var _glClearColor = _emscripten_glClearColor; + _glClearColor.sig = 'vffff'; + + + var _glScissor = _emscripten_glScissor; + _glScissor.sig = 'viiii'; + + + var _glVertexAttrib3f = _emscripten_glVertexAttrib3f; + _glVertexAttrib3f.sig = 'vifff'; + + + var _glRenderbufferStorage = _emscripten_glRenderbufferStorage; + _glRenderbufferStorage.sig = 'viiii'; + + + var _glBlendFuncSeparate = _emscripten_glBlendFuncSeparate; + _glBlendFuncSeparate.sig = 'viiii'; + + + var _glBlendColor = _emscripten_glBlendColor; + _glBlendColor.sig = 'vffff'; + + + var _glStencilFuncSeparate = _emscripten_glStencilFuncSeparate; + _glStencilFuncSeparate.sig = 'viiii'; + + + var _glStencilOpSeparate = _emscripten_glStencilOpSeparate; + _glStencilOpSeparate.sig = 'viiii'; + + + var _glVertexAttrib4f = _emscripten_glVertexAttrib4f; + _glVertexAttrib4f.sig = 'viffff'; + + + var _glCopyTexImage2D = _emscripten_glCopyTexImage2D; + _glCopyTexImage2D.sig = 'viiiiiiii'; + + + var _glCopyTexSubImage2D = _emscripten_glCopyTexSubImage2D; + _glCopyTexSubImage2D.sig = 'viiiiiiii'; + + var writeGLArray = (arr, dst, dstLength, heapType) => { + var len = arr.length; + var writeLength = dstLength < len ? dstLength : len; + var heap = heapType ? HEAPF32 : HEAP32; + // Works because HEAPF32 and HEAP32 have the same bytes-per-element + dst = ((dst)>>2); + for (var i = 0; i < writeLength; ++i) { + heap[dst + i] = arr[i]; + } + return len; + }; + + var webglPowerPreferences = ["default","low-power","high-performance"]; + + + + + var _emscripten_webgl_do_create_context = (target, attributes) => { + var attr32 = ((attributes)>>2); + var powerPreference = HEAP32[attr32 + (8>>2)]; + var contextAttributes = { + 'alpha': !!HEAP8[attributes + 0], + 'depth': !!HEAP8[attributes + 1], + 'stencil': !!HEAP8[attributes + 2], + 'antialias': !!HEAP8[attributes + 3], + 'premultipliedAlpha': !!HEAP8[attributes + 4], + 'preserveDrawingBuffer': !!HEAP8[attributes + 5], + 'powerPreference': webglPowerPreferences[powerPreference], + 'failIfMajorPerformanceCaveat': !!HEAP8[attributes + 12], + // The following are not predefined WebGL context attributes in the WebGL specification, so the property names can be minified by Closure. + majorVersion: HEAP32[attr32 + (16>>2)], + minorVersion: HEAP32[attr32 + (20>>2)], + enableExtensionsByDefault: HEAP8[attributes + 24], + explicitSwapControl: HEAP8[attributes + 25], + proxyContextToMainThread: HEAP32[attr32 + (28>>2)], + renderViaOffscreenBackBuffer: HEAP8[attributes + 32] + }; + + var canvas = findCanvasEventTarget(target); + + if (!canvas) { + return 0; + } + + if (contextAttributes.explicitSwapControl) { + return 0; + } + + var contextHandle = GL.createContext(canvas, contextAttributes); + return contextHandle; + }; + _emscripten_webgl_do_create_context.sig = 'ppp'; + var _emscripten_webgl_create_context = _emscripten_webgl_do_create_context; + _emscripten_webgl_create_context.sig = 'ppp'; + + + var _emscripten_webgl_do_get_current_context = () => GL.currentContext ? GL.currentContext.handle : 0; + _emscripten_webgl_do_get_current_context.sig = 'p'; + var _emscripten_webgl_get_current_context = _emscripten_webgl_do_get_current_context; + _emscripten_webgl_get_current_context.sig = 'p'; + + + var _emscripten_webgl_do_commit_frame = () => { + if (!GL.currentContext || !GL.currentContext.GLctx) { + return -3; + } + + if (!GL.currentContext.attributes.explicitSwapControl) { + return -3; + } + // We would do GL.currentContext.GLctx.commit(); here, but the current implementation + // in browsers has removed it - swap is implicit, so this function is a no-op for now + // (until/unless the spec changes). + return 0; + }; + _emscripten_webgl_do_commit_frame.sig = 'i'; + var _emscripten_webgl_commit_frame = _emscripten_webgl_do_commit_frame; + _emscripten_webgl_commit_frame.sig = 'i'; + + + var _emscripten_webgl_make_context_current = (contextHandle) => { + var success = GL.makeContextCurrent(contextHandle); + return success ? 0 : -5; + }; + _emscripten_webgl_make_context_current.sig = 'ip'; + + + var _emscripten_webgl_get_drawing_buffer_size = (contextHandle, width, height) => { + var GLContext = GL.getContext(contextHandle); + + if (!GLContext || !GLContext.GLctx || !width || !height) { + return -5; + } + HEAP32[((width)>>2)] = GLContext.GLctx.drawingBufferWidth; + HEAP32[((height)>>2)] = GLContext.GLctx.drawingBufferHeight; + return 0; + }; + _emscripten_webgl_get_drawing_buffer_size.sig = 'ippp'; + + + + var _emscripten_webgl_get_context_attributes = (c, a) => { + if (!a) return -5; + c = GL.contexts[c]; + if (!c) return -3; + var t = c.GLctx?.getContextAttributes(); + if (!t) return -3; + + HEAP8[a] = t.alpha; + HEAP8[(a)+(1)] = t.depth; + HEAP8[(a)+(2)] = t.stencil; + HEAP8[(a)+(3)] = t.antialias; + HEAP8[(a)+(4)] = t.premultipliedAlpha; + HEAP8[(a)+(5)] = t.preserveDrawingBuffer; + var power = t['powerPreference'] && webglPowerPreferences.indexOf(t['powerPreference']); + HEAP32[(((a)+(8))>>2)] = power; + HEAP8[(a)+(12)] = t.failIfMajorPerformanceCaveat; + HEAP32[(((a)+(16))>>2)] = c.version; + HEAP32[(((a)+(20))>>2)] = 0; + HEAP8[(a)+(24)] = c.attributes.enableExtensionsByDefault; + return 0; + }; + _emscripten_webgl_get_context_attributes.sig = 'ipp'; + + var _emscripten_webgl_destroy_context = (contextHandle) => { + if (GL.currentContext == contextHandle) GL.currentContext = 0; + GL.deleteContext(contextHandle); + }; + _emscripten_webgl_destroy_context.sig = 'ip'; + + + + + + + + + + var _emscripten_webgl_enable_extension = (contextHandle, extension) => { + var context = GL.getContext(contextHandle); + var extString = UTF8ToString(extension); + if (extString.startsWith('GL_')) extString = extString.slice(3); // Allow enabling extensions both with "GL_" prefix and without. + + // Switch-board that pulls in code for all GL extensions, even if those are not used :/ + // Build with -sGL_SUPPORT_SIMPLE_ENABLE_EXTENSIONS=0 to avoid this. + + // Obtain function entry points to WebGL 1 extension related functions. + if (extString == 'ANGLE_instanced_arrays') webgl_enable_ANGLE_instanced_arrays(GLctx); + if (extString == 'OES_vertex_array_object') webgl_enable_OES_vertex_array_object(GLctx); + if (extString == 'WEBGL_draw_buffers') webgl_enable_WEBGL_draw_buffers(GLctx); + + if (extString == 'WEBGL_multi_draw') webgl_enable_WEBGL_multi_draw(GLctx); + if (extString == 'EXT_polygon_offset_clamp') webgl_enable_EXT_polygon_offset_clamp(GLctx); + if (extString == 'EXT_clip_control') webgl_enable_EXT_clip_control(GLctx); + if (extString == 'WEBGL_polygon_mode') webgl_enable_WEBGL_polygon_mode(GLctx); + + var ext = context.GLctx.getExtension(extString); + return !!ext; + }; + _emscripten_webgl_enable_extension.sig = 'ipp'; + + var _emscripten_supports_offscreencanvas = () => + // TODO: Add a new build mode, e.g. OFFSCREENCANVAS_SUPPORT=2, which + // necessitates OffscreenCanvas support at build time, and "return 1;" here in that build mode. + 0; + _emscripten_supports_offscreencanvas.sig = 'i'; + + + + var registerWebGlEventCallback = (target, userData, useCapture, callbackfunc, eventTypeId, eventTypeString, targetThread) => { + + var webGlEventHandlerFunc = (e = event) => { + if (((a1, a2, a3) => {} /* a dynamic function call to signature iiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(eventTypeId, 0, userData)) e.preventDefault(); + }; + + var eventHandler = { + target: findEventTarget(target), + eventTypeString, + callbackfunc, + handlerFunc: webGlEventHandlerFunc, + useCapture + }; + JSEvents.registerOrRemoveHandler(eventHandler); + }; + + + var _emscripten_set_webglcontextlost_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => { + registerWebGlEventCallback(target, userData, useCapture, callbackfunc, 31, "webglcontextlost", targetThread); + return 0; + }; + _emscripten_set_webglcontextlost_callback_on_thread.sig = 'ippipp'; + + + var _emscripten_set_webglcontextrestored_callback_on_thread = (target, userData, useCapture, callbackfunc, targetThread) => { + registerWebGlEventCallback(target, userData, useCapture, callbackfunc, 32, "webglcontextrestored", targetThread); + return 0; + }; + _emscripten_set_webglcontextrestored_callback_on_thread.sig = 'ippipp'; + + var _emscripten_is_webgl_context_lost = (contextHandle) => + !GL.contexts[contextHandle] || GL.contexts[contextHandle].GLctx.isContextLost(); + _emscripten_is_webgl_context_lost.sig = 'ip'; + + + var _emscripten_webgl_get_supported_extensions = () => + stringToNewUTF8(GLctx.getSupportedExtensions().join(' ')); + _emscripten_webgl_get_supported_extensions.sig = 'p'; + + var _emscripten_webgl_get_program_parameter_d = (program, param) => + GLctx.getProgramParameter(GL.programs[program], param); + _emscripten_webgl_get_program_parameter_d.sig = 'dii'; + + + var _emscripten_webgl_get_program_info_log_utf8 = (program) => + stringToNewUTF8(GLctx.getProgramInfoLog(GL.programs[program])); + _emscripten_webgl_get_program_info_log_utf8.sig = 'pi'; + + var _emscripten_webgl_get_shader_parameter_d = (shader, param) => + GLctx.getShaderParameter(GL.shaders[shader], param); + _emscripten_webgl_get_shader_parameter_d.sig = 'dii'; + + + var _emscripten_webgl_get_shader_info_log_utf8 = (shader) => + stringToNewUTF8(GLctx.getShaderInfoLog(GL.shaders[shader])); + _emscripten_webgl_get_shader_info_log_utf8.sig = 'pi'; + + + var _emscripten_webgl_get_shader_source_utf8 = (shader) => + stringToNewUTF8(GLctx.getShaderSource(GL.shaders[shader])); + _emscripten_webgl_get_shader_source_utf8.sig = 'pi'; + + var _emscripten_webgl_get_vertex_attrib_d = (index, param) => + GLctx.getVertexAttrib(index, param); + _emscripten_webgl_get_vertex_attrib_d.sig = 'dii'; + + var _emscripten_webgl_get_vertex_attrib_o = (index, param) => { + var obj = GLctx.getVertexAttrib(index, param); + return obj?.name; + }; + _emscripten_webgl_get_vertex_attrib_o.sig = 'iii'; + + + var _emscripten_webgl_get_vertex_attrib_v = (index, param, dst, dstLength, dstType) => + writeGLArray(GLctx.getVertexAttrib(index, param), dst, dstLength, dstType); + _emscripten_webgl_get_vertex_attrib_v.sig = 'iiipii'; + + + var _emscripten_webgl_get_uniform_d = (program, location) => + GLctx.getUniform(GL.programs[program], webglGetUniformLocation(location)); + _emscripten_webgl_get_uniform_d.sig = 'dii'; + + + + var _emscripten_webgl_get_uniform_v = (program, location, dst, dstLength, dstType) => + writeGLArray(GLctx.getUniform(GL.programs[program], webglGetUniformLocation(location)), dst, dstLength, dstType); + _emscripten_webgl_get_uniform_v.sig = 'iiipii'; + + + var _emscripten_webgl_get_parameter_v = (param, dst, dstLength, dstType) => + writeGLArray(GLctx.getParameter(param), dst, dstLength, dstType); + _emscripten_webgl_get_parameter_v.sig = 'iipii'; + + var _emscripten_webgl_get_parameter_d = (param) => GLctx.getParameter(param); + _emscripten_webgl_get_parameter_d.sig = 'di'; + + var _emscripten_webgl_get_parameter_o = (param) => { + var obj = GLctx.getParameter(param); + return obj?.name; + }; + _emscripten_webgl_get_parameter_o.sig = 'ii'; + + + var _emscripten_webgl_get_parameter_utf8 = (param) => stringToNewUTF8(GLctx.getParameter(param)); + _emscripten_webgl_get_parameter_utf8.sig = 'pi'; + + + var _emscripten_webgl_get_parameter_i64v = (param, dst) => writeI53ToI64(dst, GLctx.getParameter(param)); + _emscripten_webgl_get_parameter_i64v.sig = 'vip'; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + var _glutPostRedisplay = () => { + if (GLUT.displayFunc && !GLUT.requestedAnimationFrame) { + GLUT.requestedAnimationFrame = true; + MainLoop.requestAnimationFrame(() => { + GLUT.requestedAnimationFrame = false; + MainLoop.runIter(() => (() => {} /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)()); + }); + } + }; + _glutPostRedisplay.sig = 'v'; + + var GLUT = { + initTime:null, + idleFunc:null, + displayFunc:null, + keyboardFunc:null, + keyboardUpFunc:null, + specialFunc:null, + specialUpFunc:null, + reshapeFunc:null, + motionFunc:null, + passiveMotionFunc:null, + mouseFunc:null, + buttons:0, + modifiers:0, + initWindowWidth:256, + initWindowHeight:256, + initDisplayMode:18, + windowX:0, + windowY:0, + windowWidth:0, + windowHeight:0, + requestedAnimationFrame:false, + saveModifiers:(event) => { + GLUT.modifiers = 0; + if (event['shiftKey']) + GLUT.modifiers += 1; /* GLUT_ACTIVE_SHIFT */ + if (event['ctrlKey']) + GLUT.modifiers += 2; /* GLUT_ACTIVE_CTRL */ + if (event['altKey']) + GLUT.modifiers += 4; /* GLUT_ACTIVE_ALT */ + }, + onMousemove:(event) => { + /* Send motion event only if the motion changed, prevents + * spamming our app with uncessary callback call. It does happen in + * Chrome on Windows. + */ + var lastX = Browser.mouseX; + var lastY = Browser.mouseY; + Browser.calculateMouseEvent(event); + var newX = Browser.mouseX; + var newY = Browser.mouseY; + if (newX == lastX && newY == lastY) return; + + if (GLUT.buttons == 0 && event.target == Browser.getCanvas() && GLUT.passiveMotionFunc) { + event.preventDefault(); + GLUT.saveModifiers(event); + ((a1, a2) => {} /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(lastX, lastY); + } else if (GLUT.buttons != 0 && GLUT.motionFunc) { + event.preventDefault(); + GLUT.saveModifiers(event); + ((a1, a2) => {} /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(lastX, lastY); + } + }, + getSpecialKey:(keycode) => { + var key = null; + switch (keycode) { + case 8: key = 120 /* backspace */; break; + case 46: key = 111 /* delete */; break; + + case 0x70 /*DOM_VK_F1*/: key = 1 /* GLUT_KEY_F1 */; break; + case 0x71 /*DOM_VK_F2*/: key = 2 /* GLUT_KEY_F2 */; break; + case 0x72 /*DOM_VK_F3*/: key = 3 /* GLUT_KEY_F3 */; break; + case 0x73 /*DOM_VK_F4*/: key = 4 /* GLUT_KEY_F4 */; break; + case 0x74 /*DOM_VK_F5*/: key = 5 /* GLUT_KEY_F5 */; break; + case 0x75 /*DOM_VK_F6*/: key = 6 /* GLUT_KEY_F6 */; break; + case 0x76 /*DOM_VK_F7*/: key = 7 /* GLUT_KEY_F7 */; break; + case 0x77 /*DOM_VK_F8*/: key = 8 /* GLUT_KEY_F8 */; break; + case 0x78 /*DOM_VK_F9*/: key = 9 /* GLUT_KEY_F9 */; break; + case 0x79 /*DOM_VK_F10*/: key = 10 /* GLUT_KEY_F10 */; break; + case 0x7a /*DOM_VK_F11*/: key = 11 /* GLUT_KEY_F11 */; break; + case 0x7b /*DOM_VK_F12*/: key = 12 /* GLUT_KEY_F12 */; break; + case 0x25 /*DOM_VK_LEFT*/: key = 100 /* GLUT_KEY_LEFT */; break; + case 0x26 /*DOM_VK_UP*/: key = 101 /* GLUT_KEY_UP */; break; + case 0x27 /*DOM_VK_RIGHT*/: key = 102 /* GLUT_KEY_RIGHT */; break; + case 0x28 /*DOM_VK_DOWN*/: key = 103 /* GLUT_KEY_DOWN */; break; + case 0x21 /*DOM_VK_PAGE_UP*/: key = 104 /* GLUT_KEY_PAGE_UP */; break; + case 0x22 /*DOM_VK_PAGE_DOWN*/: key = 105 /* GLUT_KEY_PAGE_DOWN */; break; + case 0x24 /*DOM_VK_HOME*/: key = 106 /* GLUT_KEY_HOME */; break; + case 0x23 /*DOM_VK_END*/: key = 107 /* GLUT_KEY_END */; break; + case 0x2d /*DOM_VK_INSERT*/: key = 108 /* GLUT_KEY_INSERT */; break; + + case 16 /*DOM_VK_SHIFT*/: + case 0x05 /*DOM_VK_LEFT_SHIFT*/: + key = 112 /* GLUT_KEY_SHIFT_L */; + break; + case 0x06 /*DOM_VK_RIGHT_SHIFT*/: + key = 113 /* GLUT_KEY_SHIFT_R */; + break; + + case 17 /*DOM_VK_CONTROL*/: + case 0x03 /*DOM_VK_LEFT_CONTROL*/: + key = 114 /* GLUT_KEY_CONTROL_L */; + break; + case 0x04 /*DOM_VK_RIGHT_CONTROL*/: + key = 115 /* GLUT_KEY_CONTROL_R */; + break; + + case 18 /*DOM_VK_ALT*/: + case 0x02 /*DOM_VK_LEFT_ALT*/: + key = 116 /* GLUT_KEY_ALT_L */; + break; + case 0x01 /*DOM_VK_RIGHT_ALT*/: + key = 117 /* GLUT_KEY_ALT_R */; + break; + }; + return key; + }, + getASCIIKey:(event) => { + if (event['ctrlKey'] || event['altKey'] || event['metaKey']) return null; + + var keycode = event['keyCode']; + + /* The exact list is soooo hard to find in a canonical place! */ + + if (48 <= keycode && keycode <= 57) + return keycode; // numeric TODO handle shift? + if (65 <= keycode && keycode <= 90) + return event['shiftKey'] ? keycode : keycode + 32; + if (96 <= keycode && keycode <= 105) + return keycode - 48; // numpad numbers + if (106 <= keycode && keycode <= 111) + return keycode - 106 + 42; // *,+-./ TODO handle shift? + + switch (keycode) { + case 9: // tab key + case 13: // return key + case 27: // escape + case 32: // space + case 61: // equal + return keycode; + } + + var s = event['shiftKey']; + switch (keycode) { + case 186: return s ? 58 : 59; // colon / semi-colon + case 187: return s ? 43 : 61; // add / equal (these two may be wrong) + case 188: return s ? 60 : 44; // less-than / comma + case 189: return s ? 95 : 45; // dash + case 190: return s ? 62 : 46; // greater-than / period + case 191: return s ? 63 : 47; // forward slash + case 219: return s ? 123 : 91; // open bracket + case 220: return s ? 124 : 47; // back slash + case 221: return s ? 125 : 93; // close bracket + case 222: return s ? 34 : 39; // single quote + } + + return null; + }, + onKeydown:(event) => { + if (GLUT.specialFunc || GLUT.keyboardFunc) { + var key = GLUT.getSpecialKey(event['keyCode']); + if (key !== null) { + if (GLUT.specialFunc) { + event.preventDefault(); + GLUT.saveModifiers(event); + ((a1, a2, a3) => {} /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(key, Browser.mouseX, Browser.mouseY); + } + } else { + key = GLUT.getASCIIKey(event); + if (key !== null && GLUT.keyboardFunc) { + event.preventDefault(); + GLUT.saveModifiers(event); + ((a1, a2, a3) => {} /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(key, Browser.mouseX, Browser.mouseY); + } + } + } + }, + onKeyup:(event) => { + if (GLUT.specialUpFunc || GLUT.keyboardUpFunc) { + var key = GLUT.getSpecialKey(event['keyCode']); + if (key !== null) { + if (GLUT.specialUpFunc) { + event.preventDefault (); + GLUT.saveModifiers(event); + ((a1, a2, a3) => {} /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(key, Browser.mouseX, Browser.mouseY); + } + } else { + key = GLUT.getASCIIKey(event); + if (key !== null && GLUT.keyboardUpFunc) { + event.preventDefault (); + GLUT.saveModifiers(event); + ((a1, a2, a3) => {} /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(key, Browser.mouseX, Browser.mouseY); + } + } + } + }, + touchHandler:(event) => { + if (event.target != Browser.getCanvas()) { + return; + } + + var touches = event.changedTouches, + main = touches[0], + type = ""; + + switch (event.type) { + case "touchstart": type = "mousedown"; break; + case "touchmove": type = "mousemove"; break; + case "touchend": type = "mouseup"; break; + default: return; + } + + var simulatedEvent = document.createEvent("MouseEvent"); + simulatedEvent.initMouseEvent(type, true, true, window, 1, + main.screenX, main.screenY, + main.clientX, main.clientY, false, + false, false, false, 0/*main*/, null); + + main.target.dispatchEvent(simulatedEvent); + event.preventDefault(); + }, + onMouseButtonDown:(event) => { + Browser.calculateMouseEvent(event); + + GLUT.buttons |= (1 << event['button']); + + if (event.target == Browser.getCanvas() && GLUT.mouseFunc) { + try { + event.target.setCapture(); + } catch (e) {} + event.preventDefault(); + GLUT.saveModifiers(event); + ((a1, a2, a3, a4) => {} /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(event['button'], 0/*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY); + } + }, + onMouseButtonUp:(event) => { + Browser.calculateMouseEvent(event); + + GLUT.buttons &= ~(1 << event['button']); + + if (GLUT.mouseFunc) { + event.preventDefault(); + GLUT.saveModifiers(event); + ((a1, a2, a3, a4) => {} /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(event['button'], 1/*GLUT_UP*/, Browser.mouseX, Browser.mouseY); + } + }, + onMouseWheel:(event) => { + Browser.calculateMouseEvent(event); + + // cross-browser wheel delta + var e = window.event || event; // old IE support + // Note the minus sign that flips browser wheel direction (positive direction scrolls page down) to native wheel direction (positive direction is mouse wheel up) + var delta = -Browser.getMouseWheelDelta(event); + delta = (delta == 0) ? 0 : (delta > 0 ? Math.max(delta, 1) : Math.min(delta, -1)); // Quantize to integer so that minimum scroll is at least +/- 1. + + var button = 3; // wheel up + if (delta < 0) { + button = 4; // wheel down + } + + if (GLUT.mouseFunc) { + event.preventDefault(); + GLUT.saveModifiers(event); + ((a1, a2, a3, a4) => {} /* a dynamic function call to signature viiii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(button, 0/*GLUT_DOWN*/, Browser.mouseX, Browser.mouseY); + } + }, + onFullscreenEventChange:(event) => { + var width; + var height; + if (getFullscreenElement()) { + width = screen["width"]; + height = screen["height"]; + } else { + width = GLUT.windowWidth; + height = GLUT.windowHeight; + // TODO set position + document.removeEventListener('fullscreenchange', GLUT.onFullscreenEventChange, true); + document.removeEventListener('mozfullscreenchange', GLUT.onFullscreenEventChange, true); + document.removeEventListener('webkitfullscreenchange', GLUT.onFullscreenEventChange, true); + } + Browser.setCanvasSize(width, height, true); // N.B. GLUT.reshapeFunc is also registered as a canvas resize callback. + // Just call it once here. + /* Can't call _glutReshapeWindow as that requests cancelling fullscreen. */ + if (GLUT.reshapeFunc) { + // out("GLUT.reshapeFunc (from FS): " + width + ", " + height); + ((a1, a2) => {} /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(width, height); + } + _glutPostRedisplay(); + }, + onResize:() => { + // Update canvas size to clientWidth and clientHeight, which include CSS scaling + var canvas = Browser.getCanvas(); + Browser.setCanvasSize(canvas.clientWidth, canvas.clientHeight, /*noUpdates*/false); + }, + }; + + var _glutGetModifiers = () => GLUT.modifiers; + _glutGetModifiers.sig = 'i'; + + + + var _glutInit = (argcp, argv) => { + // Ignore arguments + GLUT.initTime = Date.now(); + + var isTouchDevice = 'ontouchstart' in document.documentElement; + if (isTouchDevice) { + // onMouseButtonDown, onMouseButtonUp and onMousemove handlers + // depend on Browser.mouseX / Browser.mouseY fields. Those fields + // don't get updated by touch events. So register a touchHandler + // function that translates the touch events to mouse events. + + // GLUT doesn't support touch, mouse only, so from touch events we + // are only looking at single finger touches to emulate left click, + // so we can use workaround and convert all touch events in mouse + // events. See touchHandler. + window.addEventListener('touchmove', GLUT.touchHandler, true); + window.addEventListener('touchstart', GLUT.touchHandler, true); + window.addEventListener('touchend', GLUT.touchHandler, true); + } + + window.addEventListener('keydown', GLUT.onKeydown, true); + window.addEventListener('keyup', GLUT.onKeyup, true); + window.addEventListener('mousemove', GLUT.onMousemove, true); + window.addEventListener('mousedown', GLUT.onMouseButtonDown, true); + window.addEventListener('mouseup', GLUT.onMouseButtonUp, true); + // IE9, Chrome, Safari, Opera + window.addEventListener('mousewheel', GLUT.onMouseWheel, true); + // Firefox + window.addEventListener('DOMMouseScroll', GLUT.onMouseWheel, true); + + // Resize callback stage 1: update canvas which notifies resizeListeners + window.addEventListener('resize', GLUT.onResize, true); + + // Resize callback stage 2: updateResizeListeners notifies reshapeFunc + Browser.resizeListeners.push((width, height) => { + if (GLUT.reshapeFunc) { + ((a1, a2) => {} /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(width, height); + } + }); + + addOnExit(() => { + if (isTouchDevice) { + window.removeEventListener('touchmove', GLUT.touchHandler, true); + window.removeEventListener('touchstart', GLUT.touchHandler, true); + window.removeEventListener('touchend', GLUT.touchHandler, true); + } + + window.removeEventListener('keydown', GLUT.onKeydown, true); + window.removeEventListener('keyup', GLUT.onKeyup, true); + window.removeEventListener('mousemove', GLUT.onMousemove, true); + window.removeEventListener('mousedown', GLUT.onMouseButtonDown, true); + window.removeEventListener('mouseup', GLUT.onMouseButtonUp, true); + // IE9, Chrome, Safari, Opera + window.removeEventListener('mousewheel', GLUT.onMouseWheel, true); + // Firefox + window.removeEventListener('DOMMouseScroll', GLUT.onMouseWheel, true); + + window.removeEventListener('resize', GLUT.onResize, true); + + var canvas = Browser.getCanvas(); + canvas.width = canvas.height = 1; + }); + }; + _glutInit.sig = 'vpp'; + + var _glutInitWindowSize = (width, height) => { + Browser.setCanvasSize( GLUT.initWindowWidth = width, + GLUT.initWindowHeight = height ); + }; + _glutInitWindowSize.sig = 'vii'; + + var _glutInitWindowPosition = (x, y) => {}; + _glutInitWindowPosition.sig = 'vii'; + + var _glutGet = (type) => { + switch (type) { + case 100: /* GLUT_WINDOW_X */ + return 0; /* TODO */ + case 101: /* GLUT_WINDOW_Y */ + return 0; /* TODO */ + case 102: /* GLUT_WINDOW_WIDTH */ + return Browser.getCanvas().width; + case 103: /* GLUT_WINDOW_HEIGHT */ + return Browser.getCanvas().height; + case 200: /* GLUT_SCREEN_WIDTH */ + return Browser.getCanvas().width; + case 201: /* GLUT_SCREEN_HEIGHT */ + return Browser.getCanvas().height; + case 500: /* GLUT_INIT_WINDOW_X */ + return 0; /* TODO */ + case 501: /* GLUT_INIT_WINDOW_Y */ + return 0; /* TODO */ + case 502: /* GLUT_INIT_WINDOW_WIDTH */ + return GLUT.initWindowWidth; + case 503: /* GLUT_INIT_WINDOW_HEIGHT */ + return GLUT.initWindowHeight; + case 700: /* GLUT_ELAPSED_TIME */ + var now = Date.now(); + return now - GLUT.initTime; + case 0x0069: /* GLUT_WINDOW_STENCIL_SIZE */ + return GLctx.getContextAttributes().stencil ? 8 : 0; + case 0x006A: /* GLUT_WINDOW_DEPTH_SIZE */ + return GLctx.getContextAttributes().depth ? 8 : 0; + case 0x006E: /* GLUT_WINDOW_ALPHA_SIZE */ + return GLctx.getContextAttributes().alpha ? 8 : 0; + case 0x0078: /* GLUT_WINDOW_NUM_SAMPLES */ + return GLctx.getContextAttributes().antialias ? 1 : 0; + + default: + abort("glutGet(" + type + ") not implemented yet"); + } + }; + _glutGet.sig = 'ii'; + + + var _glutIdleFunc = (func) => { + function callback() { + if (GLUT.idleFunc) { + (() => {} /* a dynamic function call to signature v, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(); + safeSetTimeout(callback, 4); // HTML spec specifies a 4ms minimum delay on the main thread; workers might get more, but we standardize here + } + } + if (!GLUT.idleFunc) { + safeSetTimeout(callback, 0); + } + GLUT.idleFunc = func; + }; + _glutIdleFunc.sig = 'vp'; + + + var _glutTimerFunc = (msec, func, value) => + safeSetTimeout(() => ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(value), msec); + _glutTimerFunc.sig = 'vipi'; + + var _glutDisplayFunc = (func) => { + GLUT.displayFunc = func; + }; + _glutDisplayFunc.sig = 'vp'; + + var _glutKeyboardFunc = (func) => { + GLUT.keyboardFunc = func; + }; + _glutKeyboardFunc.sig = 'vp'; + + var _glutKeyboardUpFunc = (func) => { + GLUT.keyboardUpFunc = func; + }; + _glutKeyboardUpFunc.sig = 'vp'; + + var _glutSpecialFunc = (func) => { + GLUT.specialFunc = func; + }; + _glutSpecialFunc.sig = 'vp'; + + var _glutSpecialUpFunc = (func) => { + GLUT.specialUpFunc = func; + }; + _glutSpecialUpFunc.sig = 'vp'; + + var _glutReshapeFunc = (func) => { + GLUT.reshapeFunc = func; + }; + _glutReshapeFunc.sig = 'vp'; + + var _glutMotionFunc = (func) => { + GLUT.motionFunc = func; + }; + _glutMotionFunc.sig = 'vp'; + + var _glutPassiveMotionFunc = (func) => { + GLUT.passiveMotionFunc = func; + }; + _glutPassiveMotionFunc.sig = 'vp'; + + var _glutMouseFunc = (func) => { + GLUT.mouseFunc = func; + }; + _glutMouseFunc.sig = 'vp'; + + var _glutSetCursor = (cursor) => { + var cursorStyle = 'auto'; + switch (cursor) { + case 0x0000: /* GLUT_CURSOR_RIGHT_ARROW */ + // No equivalent css cursor style, fallback to 'auto' + break; + case 0x0001: /* GLUT_CURSOR_LEFT_ARROW */ + // No equivalent css cursor style, fallback to 'auto' + break; + case 0x0002: /* GLUT_CURSOR_INFO */ + cursorStyle = 'pointer'; + break; + case 0x0003: /* GLUT_CURSOR_DESTROY */ + // No equivalent css cursor style, fallback to 'auto' + break; + case 0x0004: /* GLUT_CURSOR_HELP */ + cursorStyle = 'help'; + break; + case 0x0005: /* GLUT_CURSOR_CYCLE */ + // No equivalent css cursor style, fallback to 'auto' + break; + case 0x0006: /* GLUT_CURSOR_SPRAY */ + // No equivalent css cursor style, fallback to 'auto' + break; + case 0x0007: /* GLUT_CURSOR_WAIT */ + cursorStyle = 'wait'; + break; + case 0x0008: /* GLUT_CURSOR_TEXT */ + cursorStyle = 'text'; + break; + case 0x0009: /* GLUT_CURSOR_CROSSHAIR */ + case 0x0066: /* GLUT_CURSOR_FULL_CROSSHAIR */ + cursorStyle = 'crosshair'; + break; + case 0x000A: /* GLUT_CURSOR_UP_DOWN */ + cursorStyle = 'ns-resize'; + break; + case 0x000B: /* GLUT_CURSOR_LEFT_RIGHT */ + cursorStyle = 'ew-resize'; + break; + case 0x000C: /* GLUT_CURSOR_TOP_SIDE */ + cursorStyle = 'n-resize'; + break; + case 0x000D: /* GLUT_CURSOR_BOTTOM_SIDE */ + cursorStyle = 's-resize'; + break; + case 0x000E: /* GLUT_CURSOR_LEFT_SIDE */ + cursorStyle = 'w-resize'; + break; + case 0x000F: /* GLUT_CURSOR_RIGHT_SIDE */ + cursorStyle = 'e-resize'; + break; + case 0x0010: /* GLUT_CURSOR_TOP_LEFT_CORNER */ + cursorStyle = 'nw-resize'; + break; + case 0x0011: /* GLUT_CURSOR_TOP_RIGHT_CORNER */ + cursorStyle = 'ne-resize'; + break; + case 0x0012: /* GLUT_CURSOR_BOTTOM_RIGHT_CORNER */ + cursorStyle = 'se-resize'; + break; + case 0x0013: /* GLUT_CURSOR_BOTTOM_LEFT_CORNER */ + cursorStyle = 'sw-resize'; + break; + case 0x0064: /* GLUT_CURSOR_INHERIT */ + break; + case 0x0065: /* GLUT_CURSOR_NONE */ + cursorStyle = 'none'; + break; + default: + abort("glutSetCursor: Unknown cursor type: " + cursor); + } + Browser.getCanvas().style.cursor = cursorStyle; + }; + _glutSetCursor.sig = 'vi'; + + + var _glutCreateWindow = (name) => { + var contextAttributes = { + antialias: ((GLUT.initDisplayMode & 0x0080 /*GLUT_MULTISAMPLE*/) != 0), + depth: ((GLUT.initDisplayMode & 0x0010 /*GLUT_DEPTH*/) != 0), + stencil: ((GLUT.initDisplayMode & 0x0020 /*GLUT_STENCIL*/) != 0), + alpha: ((GLUT.initDisplayMode & 0x0008 /*GLUT_ALPHA*/) != 0) + }; + if (!Browser.createContext(Browser.getCanvas(), /*useWebGL=*/true, /*setInModule=*/true, contextAttributes)) { + return 0; // failure + } + return 1; // a new GLUT window ID for the created context + }; + _glutCreateWindow.sig = 'ip'; + + + var _glutDestroyWindow = (name) => { + delete Module['ctx']; + return 1; + }; + _glutDestroyWindow.sig = 'vi'; + + + + var _glutReshapeWindow = (width, height) => { + Browser.exitFullscreen(); + Browser.setCanvasSize(width, height, true); // N.B. GLUT.reshapeFunc is also registered as a canvas resize callback. + // Just call it once here. + if (GLUT.reshapeFunc) { + ((a1, a2) => {} /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(width, height); + } + _glutPostRedisplay(); + }; + _glutReshapeWindow.sig = 'vii'; + + + + var _glutPositionWindow = (x, y) => { + Browser.exitFullscreen(); + /* TODO */ + _glutPostRedisplay(); + }; + _glutPositionWindow.sig = 'vii'; + + + var _glutFullScreen = () => { + GLUT.windowX = 0; // TODO + GLUT.windowY = 0; // TODO + var canvas = Browser.getCanvas(); + GLUT.windowWidth = canvas.width; + GLUT.windowHeight = canvas.height; + document.addEventListener('fullscreenchange', GLUT.onFullscreenEventChange, true); + document.addEventListener('mozfullscreenchange', GLUT.onFullscreenEventChange, true); + document.addEventListener('webkitfullscreenchange', GLUT.onFullscreenEventChange, true); + Browser.requestFullscreen(/*lockPointer=*/false, /*resizeCanvas=*/false); + }; + _glutFullScreen.sig = 'v'; + + var _glutInitDisplayMode = (mode) => GLUT.initDisplayMode = mode; + _glutInitDisplayMode.sig = 'vi'; + + var _glutSwapBuffers = () => {}; + _glutSwapBuffers.sig = 'v'; + + + + + var _glutMainLoop = () => { + // Do an initial resize, since there's no window resize event on startup + GLUT.onResize(); + _glutPostRedisplay(); + throw 'unwind'; + }; + _glutMainLoop.sig = 'v'; + + var _XOpenDisplay = (name) => 1; + _XOpenDisplay.sig = 'pp'; + + var _XCreateWindow = (display, parent, x, y, width, height, border_width, depth, class_, visual, valuemask, attributes) => { + // All we can do is set the width and height + Browser.setCanvasSize(width, height); + return 2; + }; + _XCreateWindow.sig = 'pppiiiiiiippp'; + + var _XChangeWindowAttributes = (display, window, valuemask, attributes) => {}; + _XChangeWindowAttributes.sig = 'ipppp'; + + var _XSetWMHints = (display, win, hints) => {}; + _XSetWMHints.sig = 'ippp'; + + var _XMapWindow = (display, win) => {}; + _XMapWindow.sig = 'ipp'; + + var _XStoreName = (display, win, name) => {}; + _XStoreName.sig = 'ippp'; + + var _XInternAtom = (display, name_, hmm) => 0; + _XInternAtom.sig = 'pppi'; + + var _XSendEvent = (display, win, propagate, event_mask, even_send) => {}; + _XSendEvent.sig = 'ippipp'; + + var _XPending = (display) => 0; + _XPending.sig = 'ip'; + + + var EGL = { + errorCode:12288, + defaultDisplayInitialized:false, + currentContext:0, + currentReadSurface:0, + currentDrawSurface:0, + contextAttributes:{ + alpha:false, + depth:false, + stencil:false, + antialias:false, + }, + stringCache:{ + }, + setErrorCode(code) { + EGL.errorCode = code; + }, + chooseConfig(display, attribList, config, config_size, numConfigs) { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + + if (attribList) { + // read attribList if it is non-null + for (;;) { + var param = HEAP32[((attribList)>>2)]; + if (param == 0x3021 /*EGL_ALPHA_SIZE*/) { + var alphaSize = HEAP32[(((attribList)+(4))>>2)]; + EGL.contextAttributes.alpha = (alphaSize > 0); + } else if (param == 0x3025 /*EGL_DEPTH_SIZE*/) { + var depthSize = HEAP32[(((attribList)+(4))>>2)]; + EGL.contextAttributes.depth = (depthSize > 0); + } else if (param == 0x3026 /*EGL_STENCIL_SIZE*/) { + var stencilSize = HEAP32[(((attribList)+(4))>>2)]; + EGL.contextAttributes.stencil = (stencilSize > 0); + } else if (param == 0x3031 /*EGL_SAMPLES*/) { + var samples = HEAP32[(((attribList)+(4))>>2)]; + EGL.contextAttributes.antialias = (samples > 0); + } else if (param == 0x3032 /*EGL_SAMPLE_BUFFERS*/) { + var samples = HEAP32[(((attribList)+(4))>>2)]; + EGL.contextAttributes.antialias = (samples == 1); + } else if (param == 0x3100 /*EGL_CONTEXT_PRIORITY_LEVEL_IMG*/) { + var requestedPriority = HEAP32[(((attribList)+(4))>>2)]; + EGL.contextAttributes.lowLatency = (requestedPriority != 0x3103 /*EGL_CONTEXT_PRIORITY_LOW_IMG*/); + } else if (param == 0x3038 /*EGL_NONE*/) { + break; + } + attribList += 8; + } + } + + if ((!config || !config_size) && !numConfigs) { + EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); + return 0; + } + if (numConfigs) { + HEAP32[((numConfigs)>>2)] = 1; // Total number of supported configs: 1. + } + if (config && config_size > 0) { + HEAPU32[((config)>>2)] = 62002; + } + + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1; + }, + }; + + var _eglGetDisplay = (nativeDisplayType) => { + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + // Emscripten EGL implementation "emulates" X11, and eglGetDisplay is + // expected to accept/receive a pointer to an X11 Display object (or + // EGL_DEFAULT_DISPLAY). + if (nativeDisplayType != 0 /* EGL_DEFAULT_DISPLAY */ && nativeDisplayType != 1 /* see library_xlib.js */) { + return 0; // EGL_NO_DISPLAY + } + return 62000; + }; + _eglGetDisplay.sig = 'pp'; + + var _eglInitialize = (display, majorVersion, minorVersion) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + if (majorVersion) { + HEAP32[((majorVersion)>>2)] = 1; // Advertise EGL Major version: '1' + } + if (minorVersion) { + HEAP32[((minorVersion)>>2)] = 4; // Advertise EGL Minor version: '4' + } + EGL.defaultDisplayInitialized = true; + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1; + }; + _eglInitialize.sig = 'ippp'; + + var _eglTerminate = (display) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + EGL.currentContext = 0; + EGL.currentReadSurface = 0; + EGL.currentDrawSurface = 0; + EGL.defaultDisplayInitialized = false; + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1; + }; + _eglTerminate.sig = 'ip'; + + var _eglGetConfigs = (display, configs, config_size, numConfigs) => + EGL.chooseConfig(display, 0, configs, config_size, numConfigs); + _eglGetConfigs.sig = 'ippip'; + + var _eglChooseConfig = (display, attrib_list, configs, config_size, numConfigs) => + EGL.chooseConfig(display, attrib_list, configs, config_size, numConfigs); + _eglChooseConfig.sig = 'ipppip'; + + var _eglGetConfigAttrib = (display, config, attribute, value) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + if (config != 62002) { + EGL.setErrorCode(0x3005 /* EGL_BAD_CONFIG */); + return 0; + } + if (!value) { + EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); + return 0; + } + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + switch (attribute) { + case 0x3020: // EGL_BUFFER_SIZE + HEAP32[((value)>>2)] = EGL.contextAttributes.alpha ? 32 : 24; + return 1; + case 0x3021: // EGL_ALPHA_SIZE + HEAP32[((value)>>2)] = EGL.contextAttributes.alpha ? 8 : 0; + return 1; + case 0x3022: // EGL_BLUE_SIZE + HEAP32[((value)>>2)] = 8; + return 1; + case 0x3023: // EGL_GREEN_SIZE + HEAP32[((value)>>2)] = 8; + return 1; + case 0x3024: // EGL_RED_SIZE + HEAP32[((value)>>2)] = 8; + return 1; + case 0x3025: // EGL_DEPTH_SIZE + HEAP32[((value)>>2)] = EGL.contextAttributes.depth ? 24 : 0; + return 1; + case 0x3026: // EGL_STENCIL_SIZE + HEAP32[((value)>>2)] = EGL.contextAttributes.stencil ? 8 : 0; + return 1; + case 0x3027: // EGL_CONFIG_CAVEAT + // We can return here one of EGL_NONE (0x3038), EGL_SLOW_CONFIG (0x3050) or EGL_NON_CONFORMANT_CONFIG (0x3051). + HEAP32[((value)>>2)] = 0x3038; + return 1; + case 0x3028: // EGL_CONFIG_ID + HEAP32[((value)>>2)] = 62002; + return 1; + case 0x3029: // EGL_LEVEL + HEAP32[((value)>>2)] = 0; + return 1; + case 0x302A: // EGL_MAX_PBUFFER_HEIGHT + HEAP32[((value)>>2)] = 4096; + return 1; + case 0x302B: // EGL_MAX_PBUFFER_PIXELS + HEAP32[((value)>>2)] = 16777216; + return 1; + case 0x302C: // EGL_MAX_PBUFFER_WIDTH + HEAP32[((value)>>2)] = 4096; + return 1; + case 0x302D: // EGL_NATIVE_RENDERABLE + HEAP32[((value)>>2)] = 0; + return 1; + case 0x302E: // EGL_NATIVE_VISUAL_ID + HEAP32[((value)>>2)] = 0; + return 1; + case 0x302F: // EGL_NATIVE_VISUAL_TYPE + HEAP32[((value)>>2)] = 0x3038; + return 1; + case 0x3031: // EGL_SAMPLES + HEAP32[((value)>>2)] = EGL.contextAttributes.antialias ? 4 : 0; + return 1; + case 0x3032: // EGL_SAMPLE_BUFFERS + HEAP32[((value)>>2)] = EGL.contextAttributes.antialias ? 1 : 0; + return 1; + case 0x3033: // EGL_SURFACE_TYPE + HEAP32[((value)>>2)] = 0x4; + return 1; + case 0x3034: // EGL_TRANSPARENT_TYPE + // If this returns EGL_TRANSPARENT_RGB (0x3052), transparency is used through color-keying. No such thing applies to Emscripten canvas. + HEAP32[((value)>>2)] = 0x3038; + return 1; + case 0x3035: // EGL_TRANSPARENT_BLUE_VALUE + case 0x3036: // EGL_TRANSPARENT_GREEN_VALUE + case 0x3037: // EGL_TRANSPARENT_RED_VALUE + // "If EGL_TRANSPARENT_TYPE is EGL_NONE, then the values for EGL_TRANSPARENT_RED_VALUE, EGL_TRANSPARENT_GREEN_VALUE, and EGL_TRANSPARENT_BLUE_VALUE are undefined." + HEAP32[((value)>>2)] = -1; + return 1; + case 0x3039: // EGL_BIND_TO_TEXTURE_RGB + case 0x303A: // EGL_BIND_TO_TEXTURE_RGBA + HEAP32[((value)>>2)] = 0; + return 1; + case 0x303B: // EGL_MIN_SWAP_INTERVAL + HEAP32[((value)>>2)] = 0; + return 1; + case 0x303C: // EGL_MAX_SWAP_INTERVAL + HEAP32[((value)>>2)] = 1; + return 1; + case 0x303D: // EGL_LUMINANCE_SIZE + case 0x303E: // EGL_ALPHA_MASK_SIZE + HEAP32[((value)>>2)] = 0; + return 1; + case 0x303F: // EGL_COLOR_BUFFER_TYPE + // EGL has two types of buffers: EGL_RGB_BUFFER and EGL_LUMINANCE_BUFFER. + HEAP32[((value)>>2)] = 0x308E; + return 1; + case 0x3040: // EGL_RENDERABLE_TYPE + // A bit combination of EGL_OPENGL_ES_BIT,EGL_OPENVG_BIT,EGL_OPENGL_ES2_BIT and EGL_OPENGL_BIT. + HEAP32[((value)>>2)] = 0x4; + return 1; + case 0x3042: // EGL_CONFORMANT + // "EGL_CONFORMANT is a mask indicating if a client API context created with respect to the corresponding EGLConfig will pass the required conformance tests for that API." + HEAP32[((value)>>2)] = 0; + return 1; + default: + EGL.setErrorCode(0x3004 /* EGL_BAD_ATTRIBUTE */); + return 0; + } + }; + _eglGetConfigAttrib.sig = 'ippip'; + + var _eglCreateWindowSurface = (display, config, win, attrib_list) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + if (config != 62002) { + EGL.setErrorCode(0x3005 /* EGL_BAD_CONFIG */); + return 0; + } + // TODO: Examine attrib_list! Parameters that can be present there are: + // - EGL_RENDER_BUFFER (must be EGL_BACK_BUFFER) + // - EGL_VG_COLORSPACE (can't be set) + // - EGL_VG_ALPHA_FORMAT (can't be set) + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 62006; /* Magic ID for Emscripten 'default surface' */ + }; + _eglCreateWindowSurface.sig = 'pppip'; + + var _eglDestroySurface = (display, surface) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + if (surface != 62006 /* Magic ID for the only EGLSurface supported by Emscripten */) { + EGL.setErrorCode(0x300D /* EGL_BAD_SURFACE */); + return 1; + } + if (EGL.currentReadSurface == surface) { + EGL.currentReadSurface = 0; + } + if (EGL.currentDrawSurface == surface) { + EGL.currentDrawSurface = 0; + } + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1; /* Magic ID for Emscripten 'default surface' */ + }; + _eglDestroySurface.sig = 'ipp'; + + + var _eglCreateContext = (display, config, hmm, contextAttribs) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + + // EGL 1.4 spec says default EGL_CONTEXT_CLIENT_VERSION is GLES1, but this is not supported by Emscripten. + // So user must pass EGL_CONTEXT_CLIENT_VERSION == 2 to initialize EGL. + var glesContextVersion = 1; + for (;;) { + var param = HEAP32[((contextAttribs)>>2)]; + if (param == 0x3098 /*EGL_CONTEXT_CLIENT_VERSION*/) { + glesContextVersion = HEAP32[(((contextAttribs)+(4))>>2)]; + } else if (param == 0x3038 /*EGL_NONE*/) { + break; + } else { + /* EGL1.4 specifies only EGL_CONTEXT_CLIENT_VERSION as supported attribute */ + EGL.setErrorCode(0x3004 /*EGL_BAD_ATTRIBUTE*/); + return 0; + } + contextAttribs += 8; + } + if (glesContextVersion != 2) { + EGL.setErrorCode(0x3005 /* EGL_BAD_CONFIG */); + return 0; /* EGL_NO_CONTEXT */ + } + + EGL.contextAttributes.majorVersion = glesContextVersion - 1; // WebGL 1 is GLES 2, WebGL2 is GLES3 + EGL.contextAttributes.minorVersion = 0; + + EGL.context = GL.createContext(Browser.getCanvas(), EGL.contextAttributes); + + if (EGL.context != 0) { + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + + // Run callbacks so that GL emulation works + GL.makeContextCurrent(EGL.context); + Browser.useWebGL = true; + Browser.moduleContextCreatedCallbacks.forEach((callback) => callback()); + + // Note: This function only creates a context, but it shall not make it active. + GL.makeContextCurrent(null); + return 62004; + } else { + EGL.setErrorCode(0x3009 /* EGL_BAD_MATCH */); // By the EGL 1.4 spec, an implementation that does not support GLES2 (WebGL in this case), this error code is set. + return 0; /* EGL_NO_CONTEXT */ + } + }; + _eglCreateContext.sig = 'ppppp'; - var _glBegin = _emscripten_glBegin; - _glBegin.sig = 'vi'; + + var _eglDestroyContext = (display, context) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + if (context != 62004) { + EGL.setErrorCode(0x3006 /* EGL_BAD_CONTEXT */); + return 0; + } + + GL.deleteContext(EGL.context); + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + if (EGL.currentContext == context) { + EGL.currentContext = 0; + } + return 1 /* EGL_TRUE */; + }; + _eglDestroyContext.sig = 'ipp'; - var _emscripten_glLoadIdentity = () => - abort( - 'Legacy GL function (glLoadIdentity) called. If you want legacy GL emulation, you need to compile with -sLEGACY_GL_EMULATION to enable legacy GL emulation.' - ); - _emscripten_glLoadIdentity.sig = 'v'; + var _eglQuerySurface = (display, surface, attribute, value) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + if (surface != 62006 /* Magic ID for Emscripten 'default surface' */) { + EGL.setErrorCode(0x300D /* EGL_BAD_SURFACE */); + return 0; + } + if (!value) { + EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); + return 0; + } + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + switch (attribute) { + case 0x3028: // EGL_CONFIG_ID + HEAP32[((value)>>2)] = 62002; + return 1; + case 0x3058: // EGL_LARGEST_PBUFFER + // Odd EGL API: If surface is not a pbuffer surface, 'value' should not be written to. It's not specified as an error, so true should(?) be returned. + // Existing Android implementation seems to do so at least. + return 1; + case 0x3057: // EGL_WIDTH + HEAP32[((value)>>2)] = Browser.getCanvas().width; + return 1; + case 0x3056: // EGL_HEIGHT + HEAP32[((value)>>2)] = Browser.getCanvas().height; + return 1; + case 0x3090: // EGL_HORIZONTAL_RESOLUTION + HEAP32[((value)>>2)] = -1; + return 1; + case 0x3091: // EGL_VERTICAL_RESOLUTION + HEAP32[((value)>>2)] = -1; + return 1; + case 0x3092: // EGL_PIXEL_ASPECT_RATIO + HEAP32[((value)>>2)] = -1; + return 1; + case 0x3086: // EGL_RENDER_BUFFER + // The main surface is bound to the visible canvas window - it's always backbuffered. + // Alternative to EGL_BACK_BUFFER would be EGL_SINGLE_BUFFER. + HEAP32[((value)>>2)] = 0x3084; + return 1; + case 0x3099: // EGL_MULTISAMPLE_RESOLVE + HEAP32[((value)>>2)] = 0x309A; + return 1; + case 0x3093: // EGL_SWAP_BEHAVIOR + // The two possibilities are EGL_BUFFER_PRESERVED and EGL_BUFFER_DESTROYED. Slightly unsure which is the + // case for browser environment, but advertise the 'weaker' behavior to be sure. + HEAP32[((value)>>2)] = 0x3095; + return 1; + case 0x3080: // EGL_TEXTURE_FORMAT + case 0x3081: // EGL_TEXTURE_TARGET + case 0x3082: // EGL_MIPMAP_TEXTURE + case 0x3083: // EGL_MIPMAP_LEVEL + // This is a window surface, not a pbuffer surface. Spec: + // "Querying EGL_TEXTURE_FORMAT, EGL_TEXTURE_TARGET, EGL_MIPMAP_TEXTURE, or EGL_MIPMAP_LEVEL for a non-pbuffer surface is not an error, but value is not modified." + // So pass-through. + return 1; + default: + EGL.setErrorCode(0x3004 /* EGL_BAD_ATTRIBUTE */); + return 0; + } + }; + _eglQuerySurface.sig = 'ippip'; - var _glLoadIdentity = _emscripten_glLoadIdentity; - _glLoadIdentity.sig = 'v'; + var _eglQueryContext = (display, context, attribute, value) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + //\todo An EGL_NOT_INITIALIZED error is generated if EGL is not initialized for dpy. + if (context != 62004) { + EGL.setErrorCode(0x3006 /* EGL_BAD_CONTEXT */); + return 0; + } + if (!value) { + EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); + return 0; + } + + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + switch (attribute) { + case 0x3028: // EGL_CONFIG_ID + HEAP32[((value)>>2)] = 62002; + return 1; + case 0x3097: // EGL_CONTEXT_CLIENT_TYPE + HEAP32[((value)>>2)] = 0x30A0; + return 1; + case 0x3098: // EGL_CONTEXT_CLIENT_VERSION + HEAP32[((value)>>2)] = EGL.contextAttributes.majorVersion + 1; + return 1; + case 0x3086: // EGL_RENDER_BUFFER + // The context is bound to the visible canvas window - it's always backbuffered. + // Alternative to EGL_BACK_BUFFER would be EGL_SINGLE_BUFFER. + HEAP32[((value)>>2)] = 0x3084; + return 1; + default: + EGL.setErrorCode(0x3004 /* EGL_BAD_ATTRIBUTE */); + return 0; + } + }; + _eglQueryContext.sig = 'ippip'; - var _glGenVertexArraysOES = _emscripten_glGenVertexArrays; - _glGenVertexArraysOES.sig = 'vip'; + var _eglGetError = () => EGL.errorCode; + _eglGetError.sig = 'i'; - var _glDeleteVertexArraysOES = _emscripten_glDeleteVertexArrays; - _glDeleteVertexArraysOES.sig = 'vip'; + + var _eglQueryString = (display, name) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + //\todo An EGL_NOT_INITIALIZED error is generated if EGL is not initialized for dpy. + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + if (EGL.stringCache[name]) return EGL.stringCache[name]; + var ret; + switch (name) { + case 0x3053 /* EGL_VENDOR */: ret = stringToNewUTF8("Emscripten"); break; + case 0x3054 /* EGL_VERSION */: ret = stringToNewUTF8("1.4 Emscripten EGL"); break; + case 0x3055 /* EGL_EXTENSIONS */: ret = stringToNewUTF8(""); break; // Currently not supporting any EGL extensions. + case 0x308D /* EGL_CLIENT_APIS */: ret = stringToNewUTF8("OpenGL_ES"); break; + default: + EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); + return 0; + } + EGL.stringCache[name] = ret; + return ret; + }; + _eglQueryString.sig = 'ppi'; + + var _eglBindAPI = (api) => { + if (api == 0x30A0 /* EGL_OPENGL_ES_API */) { + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1; + } + // if (api == 0x30A1 /* EGL_OPENVG_API */ || api == 0x30A2 /* EGL_OPENGL_API */) { + EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); + return 0; + }; + _eglBindAPI.sig = 'ii'; + + var _eglQueryAPI = () => { + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 0x30A0; // EGL_OPENGL_ES_API + }; + _eglQueryAPI.sig = 'i'; + + var _eglWaitClient = () => { + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1; + }; + _eglWaitClient.sig = 'i'; + + var _eglWaitNative = (nativeEngineId) => { + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1; + }; + _eglWaitNative.sig = 'ii'; + + + var _eglWaitGL = _eglWaitClient; + _eglWaitGL.sig = 'i'; + + + var _eglSwapInterval = (display, interval) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0; + } + if (interval == 0) _emscripten_set_main_loop_timing(0, 0); + else _emscripten_set_main_loop_timing(1, interval); + + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1; + }; + _eglSwapInterval.sig = 'ipi'; + + + var _eglMakeCurrent = (display, draw, read, context) => { + if (display != 62000) { + EGL.setErrorCode(0x3008 /* EGL_BAD_DISPLAY */); + return 0 /* EGL_FALSE */; + } + //\todo An EGL_NOT_INITIALIZED error is generated if EGL is not initialized for dpy. + if (context != 0 && context != 62004) { + EGL.setErrorCode(0x3006 /* EGL_BAD_CONTEXT */); + return 0; + } + if ((read != 0 && read != 62006) || (draw != 0 && draw != 62006 /* Magic ID for Emscripten 'default surface' */)) { + EGL.setErrorCode(0x300D /* EGL_BAD_SURFACE */); + return 0; + } + + GL.makeContextCurrent(context ? EGL.context : null); + + EGL.currentContext = context; + EGL.currentDrawSurface = draw; + EGL.currentReadSurface = read; + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1 /* EGL_TRUE */; + }; + _eglMakeCurrent.sig = 'ipppp'; + + var _eglGetCurrentContext = () => EGL.currentContext; + _eglGetCurrentContext.sig = 'p'; + + var _eglGetCurrentSurface = (readdraw) => { + if (readdraw == 0x305A /* EGL_READ */) { + return EGL.currentReadSurface; + } else if (readdraw == 0x3059 /* EGL_DRAW */) { + return EGL.currentDrawSurface; + } else { + EGL.setErrorCode(0x300C /* EGL_BAD_PARAMETER */); + return 0 /* EGL_NO_SURFACE */; + } + }; + _eglGetCurrentSurface.sig = 'pi'; + + var _eglGetCurrentDisplay = () => EGL.currentContext ? 62000 : 0; + _eglGetCurrentDisplay.sig = 'p'; + + + var _eglSwapBuffers = (dpy, surface) => { + + if (!EGL.defaultDisplayInitialized) { + EGL.setErrorCode(0x3001 /* EGL_NOT_INITIALIZED */); + } else if (!GLctx) { + EGL.setErrorCode(0x3002 /* EGL_BAD_ACCESS */); + } else if (GLctx.isContextLost()) { + EGL.setErrorCode(0x300E /* EGL_CONTEXT_LOST */); + } else { + // According to documentation this does an implicit flush. + // Due to discussion at https://github.com/emscripten-core/emscripten/pull/1871 + // the flush was removed since this _may_ result in slowing code down. + //_glFlush(); + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1 /* EGL_TRUE */; + } + return 0 /* EGL_FALSE */; + }; + _eglSwapBuffers.sig = 'ipp'; + + var _eglReleaseThread = () => { + // Equivalent to eglMakeCurrent with EGL_NO_CONTEXT and EGL_NO_SURFACE. + EGL.currentContext = 0; + EGL.currentReadSurface = 0; + EGL.currentDrawSurface = 0; + // EGL spec v1.4 p.55: + // "calling eglGetError immediately following a successful call to eglReleaseThread should not be done. + // Such a call will return EGL_SUCCESS - but will also result in reallocating per-thread state." + EGL.setErrorCode(0x3000 /* EGL_SUCCESS */); + return 1 /* EGL_TRUE */; + }; + _eglReleaseThread.sig = 'i'; + + var _uuid_clear = (uu) => zeroMemory(uu, 16); + _uuid_clear.sig = 'vp'; + + var _uuid_compare = (uu1, uu2) => _memcmp(uu1, uu2, 16); + _uuid_compare.sig = 'ipp'; + + var _uuid_copy = (dst, src) => _memcpy(dst, src, 16); + _uuid_copy.sig = 'vpp'; + + + var _uuid_generate = (out) => { + // void uuid_generate(uuid_t out); + var uuid = new Uint8Array(16); + randomFill(uuid); + + // Makes uuid compliant to RFC-4122 + uuid[6] = (uuid[6] & 0x0F) | 0x40; // uuid version + uuid[8] = (uuid[8] & 0x3F) | 0x80; // uuid variant + writeArrayToMemory(uuid, out); + }; + _uuid_generate.sig = 'vp'; + + var _uuid_is_null = (uu) => { + // int uuid_is_null(const uuid_t uu); + for (var i = 0; i < 4; i++, uu = (uu+4)|0) { + var val = HEAP32[((uu)>>2)]; + if (val) { + return 0; + } + } + return 1; + }; + _uuid_is_null.sig = 'ip'; + + var _uuid_parse = (inp, uu) => { + // int uuid_parse(const char *in, uuid_t uu); + inp = UTF8ToString(inp); + if (inp.length === 36) { + var i = 0; + var uuid = new Array(16); + inp.toLowerCase().replace(/[0-9a-f]{2}/g, function(byte) { + if (i < 16) { + uuid[i++] = parseInt(byte, 16); + } + }); + + if (i < 16) { + return -1; + } + writeArrayToMemory(uuid, uu); + return 0; + } + return -1; + }; + _uuid_parse.sig = 'ipp'; + + /** @param {number|boolean=} upper */ + var _uuid_unparse = (uu, out, upper) => { + // void uuid_unparse(const uuid_t uu, char *out); + var i = 0; + var uuid = 'xxxx-xx-xx-xx-xxxxxx'.replace(/[x]/g, function(c) { + var r = upper ? (HEAPU8[(uu)+(i)]).toString(16).toUpperCase() : + (HEAPU8[(uu)+(i)]).toString(16); + r = (r.length === 1) ? '0' + r : r; // Zero pad single digit hex values + i++; + return r; + }); + stringToUTF8(uuid, out, 37); // Always fixed 36 bytes of ASCII characters and a trailing \0. + }; + _uuid_unparse.sig = 'vpp'; + + var _uuid_unparse_lower = (uu, out) => { + // void uuid_unparse_lower(const uuid_t uu, char *out); + _uuid_unparse(uu, out); + }; + _uuid_unparse_lower.sig = 'vpp'; + + var _uuid_unparse_upper = (uu, out) => { + // void uuid_unparse_upper(const uuid_t uu, char *out); + _uuid_unparse(uu, out, true); + }; + _uuid_unparse_upper.sig = 'vpp'; + + var _uuid_type = (uu) => 4; + _uuid_type.sig = 'ip'; + + var _uuid_variant = (uu) => 1; + _uuid_variant.sig = 'ip'; + + + + + + var GLEW = { + isLinaroFork:1, + extensions:null, + error:{ + 0:null, + 1:null, + 2:null, + 3:null, + 4:null, + 5:null, + 6:null, + 7:null, + 8:null, + }, + version:{ + 1:null, + 2:null, + 3:null, + 4:null, + }, + errorStringConstantFromCode(error) { + if (GLEW.isLinaroFork) { + switch (error) { + case 4:return "OpenGL ES lib expected, found OpenGL lib"; // GLEW_ERROR_NOT_GLES_VERSION + case 5:return "OpenGL lib expected, found OpenGL ES lib"; // GLEW_ERROR_GLES_VERSION + case 6:return "Missing EGL version"; // GLEW_ERROR_NO_EGL_VERSION + case 7:return "EGL 1.1 and up are supported"; // GLEW_ERROR_EGL_VERSION_10_ONLY + default:break; + } + } + + switch (error) { + case 0:return "No error"; // GLEW_OK || GLEW_NO_ERROR + case 1:return "Missing GL version"; // GLEW_ERROR_NO_GL_VERSION + case 2:return "GL 1.1 and up are supported"; // GLEW_ERROR_GL_VERSION_10_ONLY + case 3:return "GLX 1.2 and up are supported"; // GLEW_ERROR_GLX_VERSION_11_ONLY + default:return null; + } + }, + errorString(error) { + if (!GLEW.error[error]) { + var string = GLEW.errorStringConstantFromCode(error); + if (!string) { + string = "Unknown error"; + error = 8; // prevent array from growing more than this + } + GLEW.error[error] = stringToNewUTF8(string); + } + return GLEW.error[error]; + }, + versionStringConstantFromCode(name) { + switch (name) { + case 1:return "1.10.0"; // GLEW_VERSION + case 2:return "1"; // GLEW_VERSION_MAJOR + case 3:return "10"; // GLEW_VERSION_MINOR + case 4:return "0"; // GLEW_VERSION_MICRO + default:return null; + } + }, + versionString(name) { + if (!GLEW.version[name]) { + var string = GLEW.versionStringConstantFromCode(name); + if (!string) + return 0; + GLEW.version[name] = stringToNewUTF8(string); + } + return GLEW.version[name]; + }, + extensionIsSupported(name) { + GLEW.extensions ||= webglGetExtensions(); + + if (GLEW.extensions.includes(name)) + return 1; + + // extensions from GLEmulations do not come unprefixed + // so, try with prefix + return (GLEW.extensions.includes("GL_" + name)); + }, + }; + + var _glewInit = () => 0; + _glewInit.sig = 'i'; + + + var _glewIsSupported = (name) => { + var exts = UTF8ToString(name).split(' '); + for (var ext of exts) { + if (!GLEW.extensionIsSupported(ext)) return 0; + } + return 1; + }; + _glewIsSupported.sig = 'ip'; + + + var _glewGetExtension = (name) => GLEW.extensionIsSupported(UTF8ToString(name)); + _glewGetExtension.sig = 'ip'; + + var _glewGetErrorString = (error) => GLEW.errorString(error); + _glewGetErrorString.sig = 'pi'; + + var _glewGetString = (name) => GLEW.versionString(name); + _glewGetString.sig = 'pi'; + + var IDBStore = { + indexedDB() { + return indexedDB; + }, + DB_VERSION:22, + DB_STORE_NAME:"FILE_DATA", + dbs:{ + }, + blobs:[0], + getDB(name, callback) { + // check the cache first + var db = IDBStore.dbs[name]; + if (db) { + return callback(null, db); + } + var req; + try { + req = IDBStore.indexedDB().open(name, IDBStore.DB_VERSION); + } catch (e) { + return callback(e); + } + req.onupgradeneeded = (e) => { + var db = /** @type {IDBDatabase} */ (e.target.result); + var transaction = e.target.transaction; + var fileStore; + if (db.objectStoreNames.contains(IDBStore.DB_STORE_NAME)) { + fileStore = transaction.objectStore(IDBStore.DB_STORE_NAME); + } else { + fileStore = db.createObjectStore(IDBStore.DB_STORE_NAME); + } + }; + req.onsuccess = () => { + db = /** @type {IDBDatabase} */ (req.result); + // add to the cache + IDBStore.dbs[name] = db; + callback(null, db); + }; + req.onerror = function(event) { + callback(event.target.error || 'unknown error'); + event.preventDefault(); + }; + }, + getStore(dbName, type, callback) { + IDBStore.getDB(dbName, (error, db) => { + if (error) return callback(error); + var transaction = db.transaction([IDBStore.DB_STORE_NAME], type); + transaction.onerror = (event) => { + callback(event.target.error || 'unknown error'); + event.preventDefault(); + }; + var store = transaction.objectStore(IDBStore.DB_STORE_NAME); + callback(null, store); + }); + }, + getFile(dbName, id, callback) { + IDBStore.getStore(dbName, 'readonly', (err, store) => { + if (err) return callback(err); + var req = store.get(id); + req.onsuccess = (event) => { + var result = event.target.result; + if (!result) { + return callback(`file ${id} not found`); + } + return callback(null, result); + }; + req.onerror = callback; + }); + }, + setFile(dbName, id, data, callback) { + IDBStore.getStore(dbName, 'readwrite', (err, store) => { + if (err) return callback(err); + var req = store.put(data, id); + req.onsuccess = (event) => callback(); + req.onerror = callback; + }); + }, + deleteFile(dbName, id, callback) { + IDBStore.getStore(dbName, 'readwrite', (err, store) => { + if (err) return callback(err); + var req = store.delete(id); + req.onsuccess = (event) => callback(); + req.onerror = callback; + }); + }, + existsFile(dbName, id, callback) { + IDBStore.getStore(dbName, 'readonly', (err, store) => { + if (err) return callback(err); + var req = store.count(id); + req.onsuccess = (event) => callback(null, event.target.result > 0); + req.onerror = callback; + }); + }, + clearStore(dbName, callback) { + IDBStore.getStore(dbName, 'readwrite', (err, store) => { + if (err) return callback(err); + var req = store.clear(); + req.onsuccess = (event) => callback(); + req.onerror = callback; + }); + }, + }; + + + + + + + + + var _emscripten_idb_async_load = (db, id, arg, onload, onerror) => { + runtimeKeepalivePush();; + IDBStore.getFile(UTF8ToString(db), UTF8ToString(id), (error, byteArray) => { + runtimeKeepalivePop(); + callUserCallback(() => { + if (error) { + if (onerror) ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(arg); + return; + } + var buffer = _malloc(byteArray.length); + HEAPU8.set(byteArray, buffer); + ((a1, a2, a3) => {} /* a dynamic function call to signature viii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(arg, buffer, byteArray.length); + _free(buffer); + }); + }); + }; + _emscripten_idb_async_load.sig = 'vppppp'; + + + + + + + var _emscripten_idb_async_store = (db, id, ptr, num, arg, onstore, onerror) => { + // note that we copy the data here, as these are async operatins - changes + // to HEAPU8 meanwhile should not affect us! + runtimeKeepalivePush();; + IDBStore.setFile(UTF8ToString(db), UTF8ToString(id), new Uint8Array(HEAPU8.subarray(ptr, ptr+num)), (error) => { + runtimeKeepalivePop(); + callUserCallback(() => { + if (error) { + if (onerror) ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(arg); + return; + } + if (onstore) ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(arg); + }); + }); + }; + _emscripten_idb_async_store.sig = 'vpppippp'; + + + + + + + var _emscripten_idb_async_delete = (db, id, arg, ondelete, onerror) => { + runtimeKeepalivePush();; + IDBStore.deleteFile(UTF8ToString(db), UTF8ToString(id), (error) => { + runtimeKeepalivePop(); + callUserCallback(() => { + if (error) { + if (onerror) ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(arg); + return; + } + if (ondelete) ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(arg); + }); + }); + }; + _emscripten_idb_async_delete.sig = 'vppppp'; + + + + + + + var _emscripten_idb_async_exists = (db, id, arg, oncheck, onerror) => { + runtimeKeepalivePush();; + IDBStore.existsFile(UTF8ToString(db), UTF8ToString(id), (error, exists) => { + runtimeKeepalivePop(); + callUserCallback(() => { + if (error) { + if (onerror) ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(arg); + return; + } + if (oncheck) ((a1, a2) => {} /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(arg, exists); + }); + }); + }; + _emscripten_idb_async_exists.sig = 'vppppp'; + + + + + + + var _emscripten_idb_async_clear = (db, arg, onclear, onerror) => { + runtimeKeepalivePush();; + IDBStore.clearStore(UTF8ToString(db), (error) => { + runtimeKeepalivePop(); + callUserCallback(() => { + if (error) { + if (onerror) ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(arg); + return; + } + if (onclear) ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(arg); + }); + }); + }; + _emscripten_idb_async_clear.sig = 'vpppp'; + + + + var _emscripten_idb_load = (db, id, pbuffer, pnum, perror) => Asyncify.handleSleep((wakeUp) => { + IDBStore.getFile(UTF8ToString(db), UTF8ToString(id), (error, byteArray) => { + if (error) { + HEAP32[((perror)>>2)] = 1; + wakeUp(); + return; + } + var buffer = _malloc(byteArray.length); // must be freed by the caller! + HEAPU8.set(byteArray, buffer); + HEAPU32[((pbuffer)>>2)] = buffer; + HEAP32[((pnum)>>2)] = byteArray.length; + HEAP32[((perror)>>2)] = 0; + wakeUp(); + }); + }); + _emscripten_idb_load.sig = 'vppppp'; + _emscripten_idb_load.isAsync = true; + + + var _emscripten_idb_store = (db, id, ptr, num, perror) => Asyncify.handleSleep((wakeUp) => { + IDBStore.setFile(UTF8ToString(db), UTF8ToString(id), new Uint8Array(HEAPU8.subarray(ptr, ptr+num)), (error) => { + // Closure warns about storing booleans in TypedArrays. + /** @suppress{checkTypes} */ + HEAP32[((perror)>>2)] = !!error; + wakeUp(); + }); + }); + _emscripten_idb_store.sig = 'vpppip'; + _emscripten_idb_store.isAsync = true; + + + var _emscripten_idb_delete = (db, id, perror) => Asyncify.handleSleep((wakeUp) => { + IDBStore.deleteFile(UTF8ToString(db), UTF8ToString(id), (error) => { + /** @suppress{checkTypes} */ + HEAP32[((perror)>>2)] = !!error; + wakeUp(); + }); + }); + _emscripten_idb_delete.sig = 'vppp'; + _emscripten_idb_delete.isAsync = true; + + + var _emscripten_idb_exists = (db, id, pexists, perror) => Asyncify.handleSleep((wakeUp) => { + IDBStore.existsFile(UTF8ToString(db), UTF8ToString(id), (error, exists) => { + /** @suppress{checkTypes} */ + HEAP32[((pexists)>>2)] = !!exists; + /** @suppress{checkTypes} */ + HEAP32[((perror)>>2)] = !!error; + wakeUp(); + }); + }); + _emscripten_idb_exists.sig = 'vpppp'; + _emscripten_idb_exists.isAsync = true; + + + var _emscripten_idb_clear = (db, perror) => Asyncify.handleSleep((wakeUp) => { + IDBStore.clearStore(UTF8ToString(db), (error) => { + /** @suppress{checkTypes} */ + HEAP32[((perror)>>2)] = !!error; + wakeUp(); + }); + }); + _emscripten_idb_clear.sig = 'vpp'; + _emscripten_idb_clear.isAsync = true; + + + var _emscripten_idb_load_blob = (db, id, pblob, perror) => Asyncify.handleSleep((wakeUp) => { + IDBStore.pending = (msg) => { + IDBStore.pending = null; + var blob = msg.blob; + if (!blob) { + HEAP32[((perror)>>2)] = 1; + wakeUp(); + return; + } + var blobId = IDBStore.blobs.length; + IDBStore.blobs.push(blob); + HEAP32[((pblob)>>2)] = blobId; + wakeUp(); + }; + postMessage({ + target: 'IDBStore', + method: 'loadBlob', + db: UTF8ToString(db), + id: UTF8ToString(id) + }); + }); + _emscripten_idb_load_blob.sig = 'vpppp'; + _emscripten_idb_load_blob.isAsync = true; + + + var _emscripten_idb_store_blob = (db, id, ptr, num, perror) => Asyncify.handleSleep((wakeUp) => { + IDBStore.pending = (msg) => { + IDBStore.pending = null; + HEAP32[((perror)>>2)] = !!msg.error; + wakeUp(); + }; + postMessage({ + target: 'IDBStore', + method: 'storeBlob', + db: UTF8ToString(db), + id: UTF8ToString(id), + blob: new Blob([new Uint8Array(HEAPU8.subarray(ptr, ptr+num))]) + }); + }); + _emscripten_idb_store_blob.sig = 'vpppip'; + _emscripten_idb_store_blob.isAsync = true; + + var _emscripten_idb_read_from_blob = (blobId, start, num, buffer) => { + var blob = IDBStore.blobs[blobId]; + if (!blob) return 1; + if (start+num > blob.size) return 2; + var byteArray = (new FileReaderSync()).readAsArrayBuffer(blob.slice(start, start+num)); + HEAPU8.set(new Uint8Array(byteArray), buffer); + return 0; + }; + _emscripten_idb_read_from_blob.sig = 'viiip'; + + var _emscripten_idb_free_blob = (blobId) => { + IDBStore.blobs[blobId] = null; + }; + _emscripten_idb_free_blob.sig = 'vi'; + + + + + + var _emscripten_scan_registers = (func) => { + return Asyncify.handleSleep((wakeUp) => { + // We must first unwind, so things are spilled to the stack. Then while + // we are pausing we do the actual scan. After that we can resume. Note + // how using a timeout here avoids unbounded call stack growth, which + // could happen if we tried to scan the stack immediately after unwinding. + safeSetTimeout(() => { + var stackBegin = Asyncify.currData + 12; + var stackEnd = HEAPU32[((Asyncify.currData)>>2)]; + ((a1, a2) => {} /* a dynamic function call to signature vii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(stackBegin, stackEnd); + wakeUp(); + }, 0); + }); + }; + _emscripten_scan_registers.sig = 'vp'; + _emscripten_scan_registers.isAsync = true; + + async function __load_secondary_module() { + // Mark the module as loading for the wasm module (so it doesn't try to load it again). + wasmExports['load_secondary_module_status'].value = 1; + var imports = {'primary': wasmRawExports}; + // Replace '.wasm' suffix with '.deferred.wasm'. + var deferred = wasmBinaryFile.slice(0, -5) + '.deferred.wasm'; + await instantiateAsync(null, deferred, imports); + } + __load_secondary_module.sig = 'v'; + __load_secondary_module.isAsync = true; + + + + var Fibers = { + nextFiber:0, + trampolineRunning:false, + trampoline() { + if (!Fibers.trampolineRunning && Fibers.nextFiber) { + Fibers.trampolineRunning = true; + do { + var fiber = Fibers.nextFiber; + Fibers.nextFiber = 0; + Fibers.finishContextSwitch(fiber); + } while (Fibers.nextFiber); + Fibers.trampolineRunning = false; + } + }, + finishContextSwitch(newFiber) { + var stack_base = HEAPU32[((newFiber)>>2)]; + var stack_max = HEAPU32[(((newFiber)+(4))>>2)]; + _emscripten_stack_set_limits(stack_base, stack_max); + + stackRestore(HEAPU32[(((newFiber)+(8))>>2)]); + + var entryPoint = HEAPU32[(((newFiber)+(12))>>2)]; + + if (entryPoint !== 0) { + Asyncify.currData = null; + HEAPU32[(((newFiber)+(12))>>2)] = 0; + + var userData = HEAPU32[(((newFiber)+(16))>>2)]; + ((a1) => {} /* a dynamic function call to signature vi, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(userData); + } else { + var asyncifyData = newFiber + 20; + Asyncify.currData = asyncifyData; + + Asyncify.state = Asyncify.State.Rewinding; + _asyncify_start_rewind(asyncifyData); + Asyncify.doRewind(asyncifyData); + } + }, + }; + + + + var _emscripten_fiber_swap = (oldFiber, newFiber) => { + if (ABORT) return; + if (Asyncify.state === Asyncify.State.Normal) { + Asyncify.state = Asyncify.State.Unwinding; + + var asyncifyData = oldFiber + 20; + Asyncify.setDataRewindFunc(asyncifyData); + Asyncify.currData = asyncifyData; + + _asyncify_start_unwind(asyncifyData); + + var stackTop = stackSave(); + HEAPU32[(((oldFiber)+(8))>>2)] = stackTop; + + Fibers.nextFiber = newFiber; + } else { + Asyncify.state = Asyncify.State.Normal; + _asyncify_stop_rewind(); + Asyncify.currData = null; + } + }; + _emscripten_fiber_swap.sig = 'vpp'; + _emscripten_fiber_swap.isAsync = true; + + + + var _SDL_GetTicks = () => (Date.now() - SDL.startTime)|0; + _SDL_GetTicks.sig = 'i'; + + var _SDL_LockSurface = (surf) => { + var surfData = SDL.surfaces[surf]; + + surfData.locked++; + if (surfData.locked > 1) return 0; + + if (!surfData.buffer) { + surfData.buffer = _malloc(surfData.width * surfData.height * 4); + HEAPU32[(((surf)+(20))>>2)] = surfData.buffer; + } + + // Mark in C/C++-accessible SDL structure + // SDL_Surface has the following fields: Uint32 flags, SDL_PixelFormat *format; int w, h; Uint16 pitch; void *pixels; ... + // So we have fields all of the same size, and 5 of them before us. + // TODO: Use macros like in library.js + HEAPU32[(((surf)+(20))>>2)] = surfData.buffer; + + if (surf == SDL.screen && Module.screenIsReadOnly && surfData.image) return 0; + + if (SDL.defaults.discardOnLock) { + if (!surfData.image) { + surfData.image = surfData.ctx.createImageData(surfData.width, surfData.height); + } + if (!SDL.defaults.opaqueFrontBuffer) return; + } else { + surfData.image = surfData.ctx.getImageData(0, 0, surfData.width, surfData.height); + } + + // Emulate desktop behavior and kill alpha values on the locked surface. (very costly!) Set SDL.defaults.opaqueFrontBuffer = false + // if you don't want this. + if (surf == SDL.screen && SDL.defaults.opaqueFrontBuffer) { + var data = surfData.image.data; + var num = data.length; + for (var i = 0; i < num/4; i++) { + data[i*4+3] = 255; // opacity, as canvases blend alpha + } + } + + if (SDL.defaults.copyOnLock && !SDL.defaults.discardOnLock) { + // Copy pixel data to somewhere accessible to 'C/C++' + if (surfData.isFlagSet(2097152)) { + // If this is needed then + // we should compact the data from 32bpp to 8bpp index. + // I think best way to implement this is use + // additional colorMap hash (color->index). + // Something like this: + // + // var size = surfData.width * surfData.height; + // var data = ''; + // for (var i = 0; i>2)], + y: HEAP32[(((rect)+(4))>>2)], + w: HEAP32[(((rect)+(8))>>2)], + h: HEAP32[(((rect)+(12))>>2)] + }; + }, + updateRect(rect, r) { + HEAP32[((rect)>>2)] = r.x; + HEAP32[(((rect)+(4))>>2)] = r.y; + HEAP32[(((rect)+(8))>>2)] = r.w; + HEAP32[(((rect)+(12))>>2)] = r.h; + }, + intersectionOfRects(first, second) { + var leftX = Math.max(first.x, second.x); + var leftY = Math.max(first.y, second.y); + var rightX = Math.min(first.x + first.w, second.x + second.w); + var rightY = Math.min(first.y + first.h, second.y + second.h); + + return { + x: leftX, + y: leftY, + w: Math.max(leftX, rightX) - leftX, + h: Math.max(leftY, rightY) - leftY + } + }, + checkPixelFormat(fmt) { + }, + loadColorToCSSRGB(color) { + var rgba = HEAP32[((color)>>2)]; + return 'rgb(' + (rgba&255) + ',' + ((rgba >> 8)&255) + ',' + ((rgba >> 16)&255) + ')'; + }, + loadColorToCSSRGBA(color) { + var rgba = HEAP32[((color)>>2)]; + return 'rgba(' + (rgba&255) + ',' + ((rgba >> 8)&255) + ',' + ((rgba >> 16)&255) + ',' + (((rgba >> 24)&255)/255) + ')'; + }, + translateColorToCSSRGBA:(rgba) => + 'rgba(' + (rgba&0xff) + ',' + (rgba>>8 & 0xff) + ',' + (rgba>>16 & 0xff) + ',' + (rgba>>>24)/0xff + ')', + translateRGBAToCSSRGBA:(r, g, b, a) => + 'rgba(' + (r&0xff) + ',' + (g&0xff) + ',' + (b&0xff) + ',' + (a&0xff)/255 + ')', + translateRGBAToColor:(r, g, b, a) => r | g << 8 | b << 16 | a << 24, + makeSurface(width, height, flags, usePageCanvas, source, rmask, gmask, bmask, amask) { + var is_SDL_HWSURFACE = flags & 134217729; + var is_SDL_HWPALETTE = flags & 2097152; + var is_SDL_OPENGL = flags & 67108864; + + var surf = _malloc(60); + var pixelFormat = _malloc(44); + // surface with SDL_HWPALETTE flag is 8bpp surface (1 byte) + var bpp = is_SDL_HWPALETTE ? 1 : 4; + var buffer = 0; + + // preemptively initialize this for software surfaces, + // otherwise it will be lazily initialized inside of SDL_LockSurface + if (!is_SDL_HWSURFACE && !is_SDL_OPENGL) { + buffer = _malloc(width * height * 4); + } + + HEAP32[((surf)>>2)] = flags; + HEAPU32[(((surf)+(4))>>2)] = pixelFormat; + HEAP32[(((surf)+(8))>>2)] = width; + HEAP32[(((surf)+(12))>>2)] = height; + HEAP32[(((surf)+(16))>>2)] = width * bpp; // assuming RGBA or indexed for now, + // since that is what ImageData gives us in browsers + HEAPU32[(((surf)+(20))>>2)] = buffer; + + var canvas = Browser.getCanvas(); + HEAP32[(((surf)+(36))>>2)] = 0; + HEAP32[(((surf)+(40))>>2)] = 0; + HEAP32[(((surf)+(44))>>2)] = canvas.width; + HEAP32[(((surf)+(48))>>2)] = canvas.height; + + HEAP32[(((surf)+(56))>>2)] = 1; + + HEAP32[((pixelFormat)>>2)] = -2042224636; + HEAP32[(((pixelFormat)+(4))>>2)] = 0;// TODO + HEAP8[(pixelFormat)+(8)] = bpp * 8; + HEAP8[(pixelFormat)+(9)] = bpp; + + HEAP32[(((pixelFormat)+(12))>>2)] = rmask || 0x000000ff; + HEAP32[(((pixelFormat)+(16))>>2)] = gmask || 0x0000ff00; + HEAP32[(((pixelFormat)+(20))>>2)] = bmask || 0x00ff0000; + HEAP32[(((pixelFormat)+(24))>>2)] = amask || 0xff000000; + + // Decide if we want to use WebGL or not + SDL.GL = SDL.GL || is_SDL_OPENGL; + if (!usePageCanvas) { + if (SDL.canvasPool.length > 0) { + canvas = SDL.canvasPool.pop(); + } else { + canvas = document.createElement('canvas'); + } + canvas.width = width; + canvas.height = height; + } + + var webGLContextAttributes = { + antialias: ((SDL.glAttributes[13] != 0) && (SDL.glAttributes[14] > 1)), + depth: (SDL.glAttributes[6] > 0), + stencil: (SDL.glAttributes[7] > 0), + alpha: (SDL.glAttributes[3] > 0) + }; + + var ctx = Browser.createContext(canvas, is_SDL_OPENGL, usePageCanvas, webGLContextAttributes); + + SDL.surfaces[surf] = { + width, + height, + canvas, + ctx, + surf, + buffer, + pixelFormat, + alpha: 255, + flags, + locked: 0, + usePageCanvas, + source, + + isFlagSet: (flag) => flags & flag + }; + + return surf; + }, + copyIndexedColorData(surfData, rX, rY, rW, rH) { + // HWPALETTE works with palette + // set by SDL_SetColors + if (!surfData.colors) { + return; + } + + var canvas = Browser.getCanvas(); + var fullWidth = canvas.width; + var fullHeight = canvas.height; + + var startX = rX || 0; + var startY = rY || 0; + var endX = (rW || (fullWidth - startX)) + startX; + var endY = (rH || (fullHeight - startY)) + startY; + + var buffer = surfData.buffer; + + if (!surfData.image.data32) { + surfData.image.data32 = new Uint32Array(surfData.image.data.buffer); + } + var data32 = surfData.image.data32; + + var colors32 = surfData.colors32; + + for (var y = startY; y < endY; ++y) { + var base = y * fullWidth; + for (var x = startX; x < endX; ++x) { + data32[base + x] = colors32[HEAPU8[(buffer)+(base + x)]]; + } + } + }, + freeSurface(surf) { + var refcountPointer = surf + 56; + var refcount = HEAP32[((refcountPointer)>>2)]; + if (refcount > 1) { + HEAP32[((refcountPointer)>>2)] = refcount - 1; + return; + } + + var info = SDL.surfaces[surf]; + if (!info.usePageCanvas && info.canvas) SDL.canvasPool.push(info.canvas); + _free(info.buffer); + _free(info.pixelFormat); + _free(surf); + SDL.surfaces[surf] = null; + + if (surf === SDL.screen) { + SDL.screen = null; + } + }, + blitSurface(src, srcrect, dst, dstrect, scale) { + var srcData = SDL.surfaces[src]; + var dstData = SDL.surfaces[dst]; + var sr, dr; + if (srcrect) { + sr = SDL.loadRect(srcrect); + } else { + sr = { x: 0, y: 0, w: srcData.width, h: srcData.height }; + } + if (dstrect) { + dr = SDL.loadRect(dstrect); + } else { + dr = { x: 0, y: 0, w: srcData.width, h: srcData.height }; + } + if (dstData.clipRect) { + var widthScale = (!scale || sr.w === 0) ? 1 : sr.w / dr.w; + var heightScale = (!scale || sr.h === 0) ? 1 : sr.h / dr.h; + + dr = SDL.intersectionOfRects(dstData.clipRect, dr); + + sr.w = dr.w * widthScale; + sr.h = dr.h * heightScale; + + if (dstrect) { + SDL.updateRect(dstrect, dr); + } + } + var blitw, blith; + if (scale) { + blitw = dr.w; blith = dr.h; + } else { + blitw = sr.w; blith = sr.h; + } + if (sr.w === 0 || sr.h === 0 || blitw === 0 || blith === 0) { + return 0; + } + var oldAlpha = dstData.ctx.globalAlpha; + dstData.ctx.globalAlpha = srcData.alpha/255; + dstData.ctx.drawImage(srcData.canvas, sr.x, sr.y, sr.w, sr.h, dr.x, dr.y, blitw, blith); + dstData.ctx.globalAlpha = oldAlpha; + if (dst != SDL.screen) { + // XXX As in IMG_Load, for compatibility we write out |pixels| + warnOnce('WARNING: copying canvas data to memory for compatibility'); + _SDL_LockSurface(dst); + dstData.locked--; // The surface is not actually locked in this hack + } + return 0; + }, + downFingers:{ + }, + savedKeydown:null, + receiveEvent(event) { + function unpressAllPressedKeys() { + // Un-press all pressed keys: TODO + for (var keyCode of Object.values(SDL.keyboardMap)) { + SDL.events.push({ + type: 'keyup', + keyCode, + }); + } + }; + switch (event.type) { + case 'touchstart': + case 'touchmove': { + event.preventDefault(); + + var touches = []; + + // Clear out any touchstart events that we've already processed + if (event.type === 'touchstart') { + for (var touch of event.touches) { + if (SDL.downFingers[touch.identifier] != true) { + SDL.downFingers[touch.identifier] = true; + touches.push(touch); + } + } + } else { + touches = event.touches; + } + + var firstTouch = touches[0]; + if (firstTouch) { + if (event.type == 'touchstart') { + SDL.DOMButtons[0] = 1; + } + var mouseEventType; + switch (event.type) { + case 'touchstart': mouseEventType = 'mousedown'; break; + case 'touchmove': mouseEventType = 'mousemove'; break; + } + var mouseEvent = { + type: mouseEventType, + button: 0, + pageX: firstTouch.clientX, + pageY: firstTouch.clientY + }; + SDL.events.push(mouseEvent); + } + + for (var touch of touches) { + SDL.events.push({ + type: event.type, + touch + }); + }; + break; + } + case 'touchend': { + event.preventDefault(); + + // Remove the entry in the SDL.downFingers hash + // because the finger is no longer down. + for (var touch of event.changedTouches) { + if (SDL.downFingers[touch.identifier] === true) { + delete SDL.downFingers[touch.identifier]; + } + } + + var mouseEvent = { + type: 'mouseup', + button: 0, + pageX: event.changedTouches[0].clientX, + pageY: event.changedTouches[0].clientY + }; + SDL.DOMButtons[0] = 0; + SDL.events.push(mouseEvent); + + for (var touch of event.changedTouches) { + SDL.events.push({ + type: 'touchend', + touch + }); + }; + break; + } + case 'DOMMouseScroll': + case 'mousewheel': + case 'wheel': + // Flip the wheel direction to translate from browser wheel direction + // (+:down) to SDL direction (+:up) + var delta = -Browser.getMouseWheelDelta(event); + // Quantize to integer so that minimum scroll is at least +/- 1. + delta = (delta == 0) ? 0 : (delta > 0 ? Math.max(delta, 1) : Math.min(delta, -1)); + + // Simulate old-style SDL events representing mouse wheel input as buttons + // Subtract one since JS->C marshalling is defined to add one back. + var button = (delta > 0 ? 4 : 5) - 1; + SDL.events.push({ type: 'mousedown', button, pageX: event.pageX, pageY: event.pageY }); + SDL.events.push({ type: 'mouseup', button, pageX: event.pageX, pageY: event.pageY }); + + // Pass a delta motion event. + SDL.events.push({ type: 'wheel', deltaX: 0, deltaY: delta }); + // If we don't prevent this, then 'wheel' event will be sent again by + // the browser as 'DOMMouseScroll' and we will receive this same event + // the second time. + event.preventDefault(); + break; + case 'mousemove': + if (SDL.DOMButtons[0] === 1) { + SDL.events.push({ + type: 'touchmove', + touch: { + identifier: 0, + deviceID: -1, + pageX: event.pageX, + pageY: event.pageY + } + }); + } + if (Browser.pointerLock) { + // workaround for firefox bug 750111 + if ('mozMovementX' in event) { + event['movementX'] = event['mozMovementX']; + event['movementY'] = event['mozMovementY']; + } + // workaround for Firefox bug 782777 + if (event['movementX'] == 0 && event['movementY'] == 0) { + // ignore a mousemove event if it doesn't contain any movement info + // (without pointer lock, we infer movement from pageX/pageY, so this check is unnecessary) + event.preventDefault(); + return; + } + } + // fall through + case 'keydown': + case 'keyup': + case 'keypress': + case 'mousedown': + case 'mouseup': + // If we preventDefault on keydown events, the subsequent keypress events + // won't fire. However, it's fine (and in some cases necessary) to + // preventDefault for keys that don't generate a character. Otherwise, + // preventDefault is the right thing to do in general. + if (event.type !== 'keydown' || (!SDL.unicode && !SDL.textInput) || (event.key == 'Backspace' || event.key == 'Tab')) { + event.preventDefault(); + } + + if (event.type == 'mousedown') { + SDL.DOMButtons[event.button] = 1; + SDL.events.push({ + type: 'touchstart', + touch: { + identifier: 0, + deviceID: -1, + pageX: event.pageX, + pageY: event.pageY + } + }); + } else if (event.type == 'mouseup') { + // ignore extra ups, can happen if we leave the canvas while pressing down, then return, + // since we add a mouseup in that case + if (!SDL.DOMButtons[event.button]) { + return; + } + + SDL.events.push({ + type: 'touchend', + touch: { + identifier: 0, + deviceID: -1, + pageX: event.pageX, + pageY: event.pageY + } + }); + SDL.DOMButtons[event.button] = 0; + } + + // We can only request fullscreen as the result of user input. + // Due to this limitation, we toggle a boolean on keydown which + // SDL_WM_ToggleFullScreen will check and subsequently set another + // flag indicating for us to request fullscreen on the following + // keyup. This isn't perfect, but it enables SDL_WM_ToggleFullScreen + // to work as the result of a keypress (which is an extremely + // common use case). + if (event.type === 'keydown' || event.type === 'mousedown') { + SDL.canRequestFullscreen = true; + } else if (event.type === 'keyup' || event.type === 'mouseup') { + if (SDL.isRequestingFullscreen) { + Module['requestFullscreen'](/*lockPointer=*/true, /*resizeCanvas=*/true); + SDL.isRequestingFullscreen = false; + } + SDL.canRequestFullscreen = false; + } + + // SDL expects a unicode character to be passed to its keydown events. + // Unfortunately, the browser APIs only provide a charCode property on + // keypress events, so we must backfill in keydown events with their + // subsequent keypress event's charCode. + if (event.type === 'keypress' && SDL.savedKeydown) { + // charCode is read-only + SDL.savedKeydown.keypressCharCode = event.charCode; + SDL.savedKeydown = null; + } else if (event.type === 'keydown') { + SDL.savedKeydown = event; + } + + // Don't push keypress events unless SDL_StartTextInput has been called. + if (event.type !== 'keypress' || SDL.textInput) { + SDL.events.push(event); + } + break; + case 'mouseout': + // Un-press all pressed mouse buttons, because we might miss the release outside of the canvas + for (var i = 0; i < 3; i++) { + if (SDL.DOMButtons[i]) { + SDL.events.push({ + type: 'mouseup', + button: i, + pageX: event.pageX, + pageY: event.pageY + }); + SDL.DOMButtons[i] = 0; + } + } + event.preventDefault(); + break; + case 'focus': + SDL.events.push(event); + event.preventDefault(); + break; + case 'blur': + SDL.events.push(event); + unpressAllPressedKeys(); + event.preventDefault(); + break; + case 'visibilitychange': + SDL.events.push({ + type: 'visibilitychange', + visible: !document.hidden + }); + unpressAllPressedKeys(); + event.preventDefault(); + break; + case 'unload': + if (MainLoop.runner) { + SDL.events.push(event); + // Force-run a main event loop, since otherwise this event will never be caught! + MainLoop.runner(); + } + return; + case 'resize': + SDL.events.push(event); + // manually triggered resize event doesn't have a preventDefault member + if (event.preventDefault) { + event.preventDefault(); + } + break; + } + if (SDL.events.length >= 10000) { + err('SDL event queue full, dropping events'); + SDL.events = SDL.events.slice(0, 10000); + } + // If we have a handler installed, this will push the events to the app + // instead of the app polling for them. + SDL.flushEventsToHandler(); + return; + }, + lookupKeyCodeForEvent(event) { + var code = event.keyCode; + if (code >= 65 && code <= 90) { // ASCII A-Z + code += 32; // make lowercase for SDL + } else { + // Look up DOM code in the keyCodes table with fallback for ASCII codes + // which can match between DOM codes and SDL keycodes (allows keyCodes + // to be smaller). + code = SDL.keyCodes[code] || (code < 128 ? code : 0); + // If this is one of the modifier keys (224 | 1<<10 - 227 | 1<<10), and the event specifies that it is + // a right key, add 4 to get the right key SDL key code. + if (event.location === 2 /*KeyboardEvent.DOM_KEY_LOCATION_RIGHT*/ && code >= (224 | 1<<10) && code <= (227 | 1<<10)) { + code += 4; + } + } + return code; + }, + handleEvent(event) { + if (event.handled) return; + event.handled = true; + + switch (event.type) { + case 'touchstart': + case 'touchend': + case 'touchmove': { + Browser.calculateMouseEvent(event); + break; + } + case 'keydown': + case 'keyup': { + var down = event.type === 'keydown'; + var code = SDL.lookupKeyCodeForEvent(event); + // Ignore key events that we don't (yet) map to SDL keys + if (!code) return; + // Assigning a boolean to HEAP8, that's alright but Closure would like to warn about it. + // TODO(https://github.com/emscripten-core/emscripten/issues/16311): + // This is kind of ugly hack. Perhaps we can find a better way? + /** @suppress{checkTypes} */ + HEAP8[(SDL.keyboardState)+(code)] = down; + // TODO: lmeta, rmeta, numlock, capslock, KMOD_MODE, KMOD_RESERVED + SDL.modState = + (HEAP8[(SDL.keyboardState)+(1248)] ? 64 : 0) | + (HEAP8[(SDL.keyboardState)+(1249)] ? 1 : 0) | + (HEAP8[(SDL.keyboardState)+(1250)] ? 256 : 0) | + (HEAP8[(SDL.keyboardState)+(1252)] ? 128 : 0) | + (HEAP8[(SDL.keyboardState)+(1253)] ? 2 : 0) | + (HEAP8[(SDL.keyboardState)+(1254)] ? 512 : 0); + if (down) { + SDL.keyboardMap[code] = event.keyCode; // save the DOM input, which we can use to unpress it during blur + } else { + delete SDL.keyboardMap[code]; + } + + break; + } + case 'mousedown': + case 'mouseup': + if (event.type == 'mousedown') { + // SDL_BUTTON(x) is defined as (1 << ((x)-1)). SDL buttons are 1-3, + // and DOM buttons are 0-2, so this means that the below formula is + // correct. + SDL.buttonState |= 1 << event.button; + } else if (event.type == 'mouseup') { + SDL.buttonState &= ~(1 << event.button); + } + // fall through + case 'mousemove': { + Browser.calculateMouseEvent(event); + break; + } + } + }, + flushEventsToHandler() { + if (!SDL.eventHandler) return; + + while (SDL.pollEvent(SDL.eventHandlerTemp)) { + ((a1, a2) => {} /* a dynamic function call to signature iii, but there are no exported function pointers with that signature, so this path should never be taken. Build with ASSERTIONS enabled to validate. */)(SDL.eventHandlerContext, SDL.eventHandlerTemp); + } + }, + pollEvent(ptr) { + if (SDL.initFlags & 512 && SDL.joystickEventState) { + // If SDL_INIT_JOYSTICK was supplied AND the joystick system is configured + // to automatically query for events, query for joystick events. + SDL.queryJoysticks(); + } + if (ptr) { + while (SDL.events.length > 0) { + if (SDL.makeCEvent(SDL.events.shift(), ptr) !== false) return 1; + } + return 0; + } + // XXX: somewhat risky in that we do not check if the event is real or not + // (makeCEvent returns false) if no pointer supplied + return SDL.events.length > 0; + }, + makeCEvent(event, ptr) { + if (typeof event == 'number') { + // This is a pointer to a copy of a native C event that was SDL_PushEvent'ed + _memcpy(ptr, event, 28); + _free(event); // the copy is no longer needed + return; + } + + SDL.handleEvent(event); + + switch (event.type) { + case 'keydown': case 'keyup': { + var down = event.type === 'keydown'; + var key = SDL.lookupKeyCodeForEvent(event); + // Ignore key events that we don't (yet) map to SDL keys + if (!key) return false; + var scan; + if (key >= 1024) { + scan = key - 1024; + } else { + scan = SDL.scanCodes[key] || key; + } + + HEAP32[((ptr)>>2)] = SDL.DOMEventToSDLEvent[event.type]; + HEAP8[(ptr)+(8)] = down ? 1 : 0; + HEAP8[(ptr)+(9)] = 0; // TODO + HEAP32[(((ptr)+(12))>>2)] = scan; + HEAP32[(((ptr)+(16))>>2)] = key; + HEAP16[(((ptr)+(20))>>1)] = SDL.modState; + // some non-character keys (e.g. backspace and tab) won't have keypressCharCode set, fill in with the keyCode. + HEAP32[(((ptr)+(24))>>2)] = event.keypressCharCode || key; + + break; + } + case 'keypress': { + HEAP32[((ptr)>>2)] = SDL.DOMEventToSDLEvent[event.type]; + // Not filling in windowID for now + stringToUTF8(String.fromCharCode(event.charCode), ptr + 8, 4); + break; + } + case 'mousedown': case 'mouseup': case 'mousemove': { + if (event.type != 'mousemove') { + var down = event.type === 'mousedown'; + HEAP32[((ptr)>>2)] = SDL.DOMEventToSDLEvent[event.type]; + HEAP32[(((ptr)+(4))>>2)] = 0; + HEAP32[(((ptr)+(8))>>2)] = 0; + HEAP32[(((ptr)+(12))>>2)] = 0; + HEAP8[(ptr)+(16)] = event.button+1; // DOM buttons are 0-2, SDL 1-3 + HEAP8[(ptr)+(17)] = down ? 1 : 0; + HEAP32[(((ptr)+(20))>>2)] = Browser.mouseX; + HEAP32[(((ptr)+(24))>>2)] = Browser.mouseY; + } else { + HEAP32[((ptr)>>2)] = SDL.DOMEventToSDLEvent[event.type]; + HEAP32[(((ptr)+(4))>>2)] = 0; + HEAP32[(((ptr)+(8))>>2)] = 0; + HEAP32[(((ptr)+(12))>>2)] = 0; + HEAP32[(((ptr)+(16))>>2)] = SDL.buttonState; + HEAP32[(((ptr)+(20))>>2)] = Browser.mouseX; + HEAP32[(((ptr)+(24))>>2)] = Browser.mouseY; + HEAP32[(((ptr)+(28))>>2)] = Browser.mouseMovementX; + HEAP32[(((ptr)+(32))>>2)] = Browser.mouseMovementY; + } + break; + } + case 'wheel': { + HEAP32[((ptr)>>2)] = SDL.DOMEventToSDLEvent[event.type]; + HEAP32[(((ptr)+(16))>>2)] = event.deltaX; + HEAP32[(((ptr)+(20))>>2)] = event.deltaY; + break; + } + case 'touchstart': case 'touchend': case 'touchmove': { + var touch = event.touch; + if (!Browser.touches[touch.identifier]) break; + var canvas = Browser.getCanvas(); + var x = Browser.touches[touch.identifier].x / canvas.width; + var y = Browser.touches[touch.identifier].y / canvas.height; + var lx = Browser.lastTouches[touch.identifier].x / canvas.width; + var ly = Browser.lastTouches[touch.identifier].y / canvas.height; + var dx = x - lx; + var dy = y - ly; + if (touch['deviceID'] === undefined) touch.deviceID = SDL.TOUCH_DEFAULT_ID; + if (dx === 0 && dy === 0 && event.type === 'touchmove') return false; // don't send these if nothing happened + HEAP32[((ptr)>>2)] = SDL.DOMEventToSDLEvent[event.type]; + HEAP32[(((ptr)+(4))>>2)] = _SDL_GetTicks(); + HEAP64[(((ptr)+(8))>>3)] = BigInt(touch.deviceID); + HEAP64[(((ptr)+(16))>>3)] = BigInt(touch.identifier); + HEAPF32[(((ptr)+(24))>>2)] = x; + HEAPF32[(((ptr)+(28))>>2)] = y; + HEAPF32[(((ptr)+(32))>>2)] = dx; + HEAPF32[(((ptr)+(36))>>2)] = dy; + if (touch.force !== undefined) { + HEAPF32[(((ptr)+(40))>>2)] = touch.force; + } else { // No pressure data, send a digital 0/1 pressure. + HEAPF32[(((ptr)+(40))>>2)] = event.type == "touchend" ? 0 : 1; + } + break; + } + case 'unload': { + HEAP32[((ptr)>>2)] = SDL.DOMEventToSDLEvent[event.type]; + break; + } + case 'resize': { + HEAP32[((ptr)>>2)] = SDL.DOMEventToSDLEvent[event.type]; + HEAP32[(((ptr)+(4))>>2)] = event.w; + HEAP32[(((ptr)+(8))>>2)] = event.h; + break; + } + case 'joystick_button_up': case 'joystick_button_down': { + var state = event.type === 'joystick_button_up' ? 0 : 1; + HEAP32[((ptr)>>2)] = SDL.DOMEventToSDLEvent[event.type]; + HEAP8[(ptr)+(4)] = event.index; + HEAP8[(ptr)+(5)] = event.button; + HEAP8[(ptr)+(6)] = state; + break; + } + case 'joystick_axis_motion': { + HEAP32[((ptr)>>2)] = SDL.DOMEventToSDLEvent[event.type]; + HEAP8[(ptr)+(4)] = event.index; + HEAP8[(ptr)+(5)] = event.axis; + HEAP32[(((ptr)+(8))>>2)] = SDL.joystickAxisValueConversion(event.value); + break; + } + case 'focus': { + HEAP32[((ptr)>>2)] = SDL.DOMEventToSDLEvent[event.type]; + HEAP32[(((ptr)+(4))>>2)] = 0; + HEAP8[(ptr)+(8)] = 12; + break; + } + case 'blur': { + HEAP32[((ptr)>>2)] = SDL.DOMEventToSDLEvent[event.type]; + HEAP32[(((ptr)+(4))>>2)] = 0; + HEAP8[(ptr)+(8)] = 13; + break; + } + case 'visibilitychange': { + var visibilityEventID = event.visible ? 1 : 2; + HEAP32[((ptr)>>2)] = SDL.DOMEventToSDLEvent[event.type]; + HEAP32[(((ptr)+(4))>>2)] = 0; + HEAP8[(ptr)+(8)] = visibilityEventID; + break; + } + default: abort('Unhandled SDL event: ' + event.type); + } + }, + makeFontString(height, fontName) { + if (fontName.charAt(0) != "'" && fontName.charAt(0) != '"') { + // https://developer.mozilla.org/ru/docs/Web/CSS/font-family + // Font family names containing whitespace should be quoted. + // BTW, quote all font names is easier than searching spaces + fontName = '"' + fontName + '"'; + } + return height + 'px ' + fontName + ', serif'; + }, + estimateTextWidth(fontData, text) { + var h = fontData.size; + var fontString = SDL.makeFontString(h, fontData.name); + var tempCtx = SDL.ttfContext; + tempCtx.font = fontString; + var ret = tempCtx.measureText(text).width | 0; + return ret; + }, + allocateChannels(num) { // called from Mix_AllocateChannels and init + if (SDL.numChannels >= num && num != 0) return; + SDL.numChannels = num; + SDL.channels = []; + for (var i = 0; i < num; i++) { + SDL.channels[i] = { + audio: null, + volume: 1.0 + }; + } + }, + setGetVolume(info, volume) { + if (!info) return 0; + var ret = info.volume * 128; // MIX_MAX_VOLUME + if (volume != -1) { + info.volume = Math.min(Math.max(volume, 0), 128) / 128; + if (info.audio) { + try { + info.audio.volume = info.volume; // For