{"version":3,"file":"linux.mjs","names":["mkdir","open","stat","writeFile","basename","dirname","ArchiveDir","PathType","createArchiveByFileExtensionOrThrow","linuxProjectorPatch","EM_X86_64","ProjectorSa","concat","ProjectorSaLinux","patchWindowTitle","patchMenuRemove","patchProjectorPath","patchProjectorOffset","constructor","path","extension","getProjectorArchiveNames","_writePlayer","player","isElf","st","isDir","isDirectory","size","d","ArrayBuffer","f","read","Uint8Array","close","DataView","getUint32","archive","isPlayer","name","subpaths","mode","nobrowse","names","Set","n","add","toLowerCase","has","slice","lastIndexOf","patches","_getPatches","extract","entry","dest","type","FILE","data","patch","match","volumePath","Error","buffer","byteOffset","byteLength","modify","recursive","setAttributes","ignoreTimes","playerPath","Promise","all","map","p","after","_getPatchBinary","_getPatchMovie","filter","Boolean","file","movieData","getMovieData","v","_encodeMovieData","getUint16"],"sources":["../../../src/projector/sa/linux.ts"],"sourcesContent":["import {mkdir, open, stat, writeFile} from 'node:fs/promises';\nimport {basename, dirname} from 'node:path';\n\nimport {\n\tArchiveDir,\n\tEntry,\n\tPathType,\n\tcreateArchiveByFileExtensionOrThrow\n} from '@shockpkg/archive-files';\n\nimport {linuxProjectorPatch} from '../../util/linux.ts';\nimport {EM_X86_64} from '../../util/internal/linux/elf.ts';\nimport {IFilePatch, ProjectorSa} from '../sa.ts';\nimport {concat} from '../../util/internal/data.ts';\n\n/**\n * ProjectorSaLinux object.\n */\nexport class ProjectorSaLinux extends ProjectorSa {\n\t/**\n\t * Attempt to patch the window title with a custom title.\n\t * Set to a string to automatically patch the binary if possible.\n\t */\n\tpublic patchWindowTitle: string | null = null;\n\n\t/**\n\t * Attempt to patch out application menu.\n\t * Set to true to automatically patch the code if possible.\n\t */\n\tpublic patchMenuRemove = false;\n\n\t/**\n\t * Attempt to patch the projector path reading code.\n\t * Necessary to work around broken projector path resolving code.\n\t * Set to true to automatically patch the code if possible.\n\t */\n\tpublic patchProjectorPath = false;\n\n\t/**\n\t * Attempt to patch the broken 64-bit projector offset reading code.\n\t * Necessary to work around broken projector logic in standalone players.\n\t * Set to true to automatically patch the code if possible.\n\t */\n\tpublic patchProjectorOffset = false;\n\n\t/**\n\t * ProjectorSaLinux constructor.\n\t *\n\t * @param path Output path.\n\t */\n\tconstructor(path: string) {\n\t\tsuper(path);\n\t}\n\n\t/**\n\t * @inheritdoc\n\t */\n\tpublic get extension() {\n\t\treturn '';\n\t}\n\n\t/**\n\t * Get projector archive names, case insensitive.\n\t *\n\t * @returns List of names known to be used in projectors.\n\t */\n\tpublic getProjectorArchiveNames() {\n\t\treturn ['flashplayer', 'flashplayerdebugger', 'gflashplayer'];\n\t}\n\n\t/**\n\t * @inheritdoc\n\t */\n\tprotected async _writePlayer(player: string) {\n\t\tconst {path} = this;\n\t\tlet isElf = false;\n\t\tconst st = await stat(player);\n\t\tconst isDir = st.isDirectory();\n\t\tif (!isDir && st.size >= 4) {\n\t\t\tconst d = new ArrayBuffer(4);\n\t\t\tconst f = await open(player, 'r');\n\t\t\ttry {\n\t\t\t\tawait f.read(new Uint8Array(d), 0, 4, 0);\n\t\t\t} finally {\n\t\t\t\tawait f.close();\n\t\t\t}\n\t\t\tisElf = new DataView(d).getUint32(0, false) === 0x7f454c46;\n\t\t}\n\n\t\tlet archive;\n\t\tlet isPlayer: (path: string, mode: number | null) => boolean;\n\t\tif (isElf) {\n\t\t\tconst name = basename(player);\n\t\t\tarchive = new ArchiveDir(dirname(player));\n\t\t\tarchive.subpaths = [name];\n\t\t\t// eslint-disable-next-line jsdoc/require-jsdoc\n\t\t\tisPlayer = (path: string, mode: number | null) => path === name;\n\t\t} else {\n\t\t\tarchive = isDir\n\t\t\t\t? new ArchiveDir(player)\n\t\t\t\t: createArchiveByFileExtensionOrThrow(player, {\n\t\t\t\t\t\tnobrowse: this.nobrowse\n\t\t\t\t\t});\n\t\t\tconst names = new Set<string>();\n\t\t\tfor (const n of this.getProjectorArchiveNames()) {\n\t\t\t\tnames.add(n.toLowerCase());\n\t\t\t}\n\t\t\t// eslint-disable-next-line jsdoc/require-jsdoc\n\t\t\tisPlayer = (path: string, mode: number | null) =>\n\t\t\t\t// The file should be user executable, if mode is available.\n\t\t\t\t// eslint-disable-next-line no-bitwise\n\t\t\t\t(mode === null || !!(mode & 0b001000000)) &&\n\t\t\t\tnames.has(path.slice(path.lastIndexOf('/') + 1).toLowerCase());\n\t\t}\n\n\t\tconst patches = await this._getPatches();\n\n\t\t/**\n\t\t * Extract entry, and also apply patches if any.\n\t\t *\n\t\t * @param entry Archive entry.\n\t\t * @param dest Output path.\n\t\t */\n\t\tconst extract = async (entry: Entry, dest: string) => {\n\t\t\tif (entry.type === PathType.FILE) {\n\t\t\t\tlet data: Uint8Array | null = null;\n\t\t\t\tfor (const patch of patches) {\n\t\t\t\t\t// eslint-disable-next-line unicorn/prefer-regexp-test\n\t\t\t\t\tif (patch.match(entry.volumePath)) {\n\t\t\t\t\t\tif (!data) {\n\t\t\t\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\t\t\t\tconst d = await entry.read();\n\t\t\t\t\t\t\tif (!d) {\n\t\t\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t\t\t`Failed to read: ${entry.volumePath}`\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tdata = new Uint8Array(\n\t\t\t\t\t\t\t\td.buffer,\n\t\t\t\t\t\t\t\td.byteOffset,\n\t\t\t\t\t\t\t\td.byteLength\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// eslint-disable-next-line no-await-in-loop\n\t\t\t\t\t\tdata = await patch.modify(data);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (data) {\n\t\t\t\t\tawait mkdir(dirname(dest), {recursive: true});\n\t\t\t\t\tawait writeFile(dest, data);\n\t\t\t\t\tawait entry.setAttributes(dest, null, {\n\t\t\t\t\t\tignoreTimes: true\n\t\t\t\t\t});\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tawait entry.extract(dest);\n\t\t};\n\n\t\tlet playerPath = '';\n\t\tawait archive.read(async entry => {\n\t\t\tconst {volumePath, type, mode} = entry;\n\n\t\t\t// Only looking for regular files, no resource forks.\n\t\t\tif (type !== PathType.FILE) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t// Ignore files that are not the player file.\n\t\t\tif (!isPlayer(volumePath, mode)) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\tif (playerPath) {\n\t\t\t\tthrow new Error(`Found multiple players in: ${player}`);\n\t\t\t}\n\t\t\tplayerPath = volumePath;\n\n\t\t\tawait extract(entry, path);\n\t\t\treturn true;\n\t\t});\n\n\t\tif (!playerPath) {\n\t\t\tthrow new Error(`Failed to locate player in: ${player}`);\n\t\t}\n\n\t\tawait Promise.all(patches.map(async p => p.after()));\n\t}\n\n\t/**\n\t * Get patches to apply.\n\t *\n\t * @returns Patches list.\n\t */\n\tprotected async _getPatches() {\n\t\treturn (\n\t\t\tawait Promise.all([this._getPatchBinary(), this._getPatchMovie()])\n\t\t).filter(Boolean) as IFilePatch[];\n\t}\n\n\t/**\n\t * Get patch for binary.\n\t *\n\t * @returns Patch spec.\n\t */\n\tprotected async _getPatchBinary() {\n\t\tconst {\n\t\t\tpatchWindowTitle,\n\t\t\tpatchMenuRemove,\n\t\t\tpatchProjectorPath,\n\t\t\tpatchProjectorOffset\n\t\t} = this;\n\t\tif (\n\t\t\t!(\n\t\t\t\tpatchWindowTitle !== null ||\n\t\t\t\tpatchMenuRemove ||\n\t\t\t\tpatchProjectorPath ||\n\t\t\t\tpatchProjectorOffset\n\t\t\t)\n\t\t) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst patch: IFilePatch = {\n\t\t\t/**\n\t\t\t * @inheritdoc\n\t\t\t */\n\t\t\tmatch: (file: string) => true,\n\n\t\t\t/**\n\t\t\t * @inheritdoc\n\t\t\t */\n\t\t\tmodify: (data: Uint8Array) =>\n\t\t\t\tlinuxProjectorPatch(data, {\n\t\t\t\t\tpatchWindowTitle,\n\t\t\t\t\tpatchMenuRemove,\n\t\t\t\t\tpatchProjectorPath,\n\t\t\t\t\tpatchProjectorOffset\n\t\t\t\t}),\n\n\t\t\t/**\n\t\t\t * @inheritdoc\n\t\t\t */\n\t\t\tafter: () => {}\n\t\t};\n\t\treturn patch;\n\t}\n\n\t/**\n\t * Get patch for movie.\n\t *\n\t * @returns Patch spec.\n\t */\n\tprotected async _getPatchMovie() {\n\t\tconst movieData = await this.getMovieData();\n\t\tif (!movieData) {\n\t\t\treturn null;\n\t\t}\n\n\t\tconst patch: IFilePatch = {\n\t\t\t/**\n\t\t\t * @inheritdoc\n\t\t\t */\n\t\t\tmatch: (file: string) => true,\n\n\t\t\t/**\n\t\t\t * @inheritdoc\n\t\t\t */\n\t\t\tmodify: (data: Uint8Array) => {\n\t\t\t\tconst v = new DataView(\n\t\t\t\t\tdata.buffer,\n\t\t\t\t\tdata.byteOffset,\n\t\t\t\t\tdata.byteLength\n\t\t\t\t);\n\t\t\t\treturn concat([\n\t\t\t\t\tdata,\n\t\t\t\t\tthis._encodeMovieData(\n\t\t\t\t\t\tmovieData,\n\t\t\t\t\t\tv.getUint16(18, true) === EM_X86_64 ? 'lid' : 'smd'\n\t\t\t\t\t)\n\t\t\t\t]);\n\t\t\t},\n\n\t\t\t/**\n\t\t\t * @inheritdoc\n\t\t\t */\n\t\t\tafter: () => {}\n\t\t};\n\t\treturn patch;\n\t}\n}\n"],"mappings":"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","ignoreList":[]}