const VK_PATTERN = (new TextEncoder()).encode("vkDestroyInstance"); const YUZU_PATTERN = (new TextEncoder()).encode("yuzu Emulator"); addEventListener("load", () => { const input = document.getElementById("input"); const button = document.getElementById("upload"); input.addEventListener("change", (e) => { if (e.target.files.length) { handleFile(e.target.files[0]); } }); button.addEventListener("click", () => input.click()); button.addEventListener("drop", (e) => { e.preventDefault(); button.classList.remove("dragover"); if (e.dataTransfer.files.length) { handleFile(e.dataTransfer.files[0]); } }); button.addEventListener("dragover", (e) => { e.preventDefault(); button.classList.add("dragover"); }); button.addEventListener("dragleave", (e) => { button.classList.remove("dragover"); }); }); /** * @param {File} file */ function handleFile(file) { const filename = file.name ?? "yuzu.exe"; const reader = new FileReader(); reader.onload = (e) => { const buff = e.target.result; const view = new DataView(buff); const patternLen = VK_PATTERN.byteLength; const buffLen = buff.byteLength; // Find the pattern let foundIndex = -1; for (let i = 0; i <= buffLen - patternLen; i++) { let found = true; for (let j = 0; j < patternLen; j++) { if (view.getUint8(i + j) !== VK_PATTERN[j]) { found = false; break; } } if (found) { foundIndex = i; break; } } if (foundIndex == -1) { console.error("Could not find pattern in file"); alert("Could not find pattern in file"); return; } // Walk backwards until we hit the start of the Emulator string let startIndex = -1; let emuLen = 0; for (let i = foundIndex - 2;; i--) { // skip over first 0 byte right before current index if (view.getUint8(i) == 0) { startIndex = i + 1; break; } emuLen++; } const yuzuLen = YUZU_PATTERN.byteLength; if (emuLen < yuzuLen) { console.error("Cannot patch emulator with smaller default name then yuzu"); alert("Cannot patch emulator with smaller default name then yuzu"); return; } if (emuLen == yuzuLen) { let isYuzu = true; for (let i = 0; i < emuLen; i++) { if (view.getUint8(startIndex + i) != YUZU_PATTERN[i]) { isYuzu = false; break; } } if (isYuzu) { console.error("Either this is an already patched fork or its real yuzu"); alert("Either this is an already patched fork or its real yuzu"); return; } } for (let i = 0; i < emuLen; i++) { view.setUint8(startIndex + i, YUZU_PATTERN[i] || 0); } const blobPatched = new Blob([buff]); saveAs(blobPatched, filename.replace(".exe", "_patched.exe")); } reader.readAsArrayBuffer(file); }