ci: add release workflow + rcedit devdep, fix patch_icon3 for CI
This commit is contained in:
parent
ee59ba8247
commit
023ebae786
4 changed files with 390 additions and 1 deletions
110
patch_icon3.js
Normal file
110
patch_icon3.js
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
'use strict'
|
||||
const { spawnSync } = require('child_process')
|
||||
const fs = require('fs')
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
|
||||
const EXE = path.resolve(__dirname, 'dist', 'bm.exe')
|
||||
const CLEAN = fs.existsSync(path.resolve(__dirname, 'dist', 'bm_clean.exe'))
|
||||
? path.resolve(__dirname, 'dist', 'bm_clean.exe')
|
||||
: EXE
|
||||
const ICON = path.resolve(__dirname, 'icon.ico')
|
||||
|
||||
function findRcedit() {
|
||||
const candidates = [
|
||||
path.join(os.homedir(), 'AppData', 'Roaming', 'npm', 'node_modules', 'rcedit', 'bin', 'rcedit-x64.exe'),
|
||||
]
|
||||
try {
|
||||
const pkgDir = path.dirname(require.resolve('rcedit/package.json'))
|
||||
candidates.unshift(path.join(pkgDir, 'bin', 'rcedit-x64.exe'))
|
||||
} catch {}
|
||||
const fromPath = spawnSync('where', ['rcedit-x64.exe'], { encoding: 'utf8' })
|
||||
if (fromPath.stdout) candidates.unshift(fromPath.stdout.trim().split('\n')[0])
|
||||
return candidates.find(p => { try { return fs.statSync(p).isFile() } catch { return false } })
|
||||
}
|
||||
|
||||
const RCEDIT = findRcedit()
|
||||
if (!RCEDIT) { console.error('rcedit not found'); process.exit(1) }
|
||||
console.log('rcedit:', RCEDIT)
|
||||
|
||||
if (CLEAN === EXE) {
|
||||
const tmp = EXE.replace('.exe', '_clean.exe')
|
||||
fs.copyFileSync(EXE, tmp)
|
||||
}
|
||||
|
||||
const cleanPath = CLEAN === EXE ? EXE.replace('.exe', '_clean.exe') : CLEAN
|
||||
const origBuf = fs.readFileSync(cleanPath)
|
||||
|
||||
// Find pkg position values
|
||||
const kbuf = Buffer.from("var PAYLOAD_POSITION = '", 'ascii')
|
||||
let pos = {}
|
||||
for (let i = 0; i < origBuf.length - 200; i++) {
|
||||
if (origBuf.slice(i, i + kbuf.length).equals(kbuf)) {
|
||||
const block = origBuf.slice(i, i + 400).toString('ascii')
|
||||
const pp = block.match(/PAYLOAD_POSITION = '(\d+)\s*'/)
|
||||
const ps = block.match(/PAYLOAD_SIZE = '(\d+)\s*'/)
|
||||
const pp2 = block.match(/PRELUDE_POSITION = '(\d+)\s*'/)
|
||||
const ps2 = block.match(/PRELUDE_SIZE = '(\d+)\s*'/)
|
||||
if (pp) {
|
||||
pos = {
|
||||
PAYLOAD_POSITION: +pp[1],
|
||||
PAYLOAD_SIZE: +ps[1],
|
||||
PRELUDE_POSITION: +pp2[1],
|
||||
PRELUDE_SIZE: +ps2[1],
|
||||
}
|
||||
console.log('pkg vars:', pos)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!pos.PAYLOAD_POSITION) { console.error('vars not found'); process.exit(1) }
|
||||
|
||||
const cleanBuf = origBuf
|
||||
const overlay = cleanBuf.slice(pos.PAYLOAD_POSITION)
|
||||
const peOnly = cleanBuf.slice(0, pos.PAYLOAD_POSITION)
|
||||
console.log(`overlay: ${overlay.length}b, PE: ${peOnly.length}b`)
|
||||
|
||||
fs.writeFileSync(EXE, peOnly)
|
||||
|
||||
console.log('rcedit...')
|
||||
const r = spawnSync(RCEDIT, [EXE, '--set-icon', ICON], { stdio: 'inherit' })
|
||||
if (r.status !== 0) { process.exit(1) }
|
||||
|
||||
const patchedPE = fs.readFileSync(EXE)
|
||||
const newPP = patchedPE.length
|
||||
const newPRP = newPP + pos.PAYLOAD_SIZE
|
||||
console.log(`new PE: ${patchedPE.length} new PP: ${newPP} new PRP: ${newPRP}`)
|
||||
|
||||
const full = Buffer.from(Buffer.concat([patchedPE, overlay]))
|
||||
|
||||
function replaceNum(buf, oldVal, newVal) {
|
||||
const oldStr = String(oldVal)
|
||||
const newStr = String(newVal)
|
||||
const needle = Buffer.from(`'${oldStr}`, 'ascii')
|
||||
let count = 0
|
||||
let i = 0
|
||||
while ((i = buf.indexOf(needle, i)) !== -1) {
|
||||
let end = i + 1
|
||||
while (buf[end] !== 0x27 && end < i + 30) end++
|
||||
const fieldLen = end - i - 1
|
||||
if (fieldLen < oldStr.length) { i++; continue }
|
||||
const padded = newStr + ' '.repeat(fieldLen - newStr.length)
|
||||
buf.write(padded, i + 1, 'ascii')
|
||||
console.log(` patched '${oldStr}' → '${newStr}' at offset ${i}`)
|
||||
count++
|
||||
i = end
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
let total = 0
|
||||
total += replaceNum(full, pos.PAYLOAD_POSITION, newPP)
|
||||
total += replaceNum(full, pos.PRELUDE_POSITION, newPRP)
|
||||
console.log(`total patches: ${total}`)
|
||||
|
||||
fs.writeFileSync(EXE, full)
|
||||
fs.unlinkSync(EXE + '.notail').catch?.(() => {})
|
||||
try { fs.unlinkSync(CLEAN + '.pe_only') } catch {}
|
||||
|
||||
console.log(`done: ${EXE} = ${full.length} bytes`)
|
||||
Loading…
Add table
Add a link
Reference in a new issue