Files
PhoneViewer/scripts/patch-wasm-memory.mjs
T

87 lines
2.7 KiB
JavaScript
Raw Normal View History

2026-10-26 17:44:44 +08:00
import fs from 'node:fs'
import path from 'node:path'
const source = process.argv[2] ?? 'node_modules/@mlightcad/libredwg-web/wasm/libredwg-web.wasm'
const target = process.argv[3] ?? 'public/vendor/libredwg/wasm/libredwg-web.wasm'
const INITIAL_PAGES = 4096 // 256 MiB; the module can still grow up to its 4 GiB maximum.
const MAX_PAGES = 65536
const buf = fs.readFileSync(source)
if (buf.readUInt32LE(0) !== 0x6d736100 || buf.readUInt32LE(4) !== 1) {
throw new Error('Not a WebAssembly module')
}
function readU32(data, offset) {
let value = 0
let shift = 0
let pos = offset
while (true) {
const byte = data[pos++]
value += (byte & 0x7f) * 2 ** shift
if (!(byte & 0x80)) break
shift += 7
if (shift > 35) throw new Error('Invalid LEB128 value')
}
return [value >>> 0, pos]
}
function encodeU32(value) {
const bytes = []
let v = value >>> 0
do {
let byte = v & 0x7f
v >>>= 7
if (v) byte |= 0x80
bytes.push(byte)
} while (v)
return Buffer.from(bytes)
}
function encodeSection(id, payload) {
return Buffer.concat([Buffer.from([id]), encodeU32(payload.length), payload])
}
const sections = []
let pos = 8
while (pos < buf.length) {
const id = buf[pos++]
const [size, afterSize] = readU32(buf, pos)
const payload = buf.subarray(afterSize, afterSize + size)
sections.push({ id, payload })
pos = afterSize + size
}
let patched = false
const output = []
output.push(buf.subarray(0, 8))
for (const section of sections) {
if (section.id === 5 && !patched) {
const [count, afterCount] = readU32(section.payload, 0)
if (count < 1) throw new Error('Memory section has no memory')
const flags = section.payload[afterCount]
if ((flags & 0x01) === 0) throw new Error('Memory has no maximum; refusing to patch')
const [oldMin, afterMin] = readU32(section.payload, afterCount + 1)
const [oldMax] = readU32(section.payload, afterMin)
if (oldMin !== 16384) throw new Error(`Unexpected initial memory: ${oldMin}`)
const payload = Buffer.concat([
encodeU32(count),
Buffer.from([flags]),
encodeU32(INITIAL_PAGES),
encodeU32(MAX_PAGES),
section.payload.subarray(afterMin + encodeU32(oldMax).length)
])
output.push(encodeSection(5, payload))
patched = true
console.log(
`patched memory: ${oldMin} -> ${INITIAL_PAGES} pages (${Math.round((INITIAL_PAGES * 64) / 1024)} MiB)`
)
} else {
output.push(encodeSection(section.id, section.payload))
}
}
if (!patched) throw new Error('Memory section not found')
fs.mkdirSync(path.dirname(target), { recursive: true })
fs.writeFileSync(target, Buffer.concat(output))
console.log('wrote', target, fs.statSync(target).size, 'bytes')