Advertisement
Guest User

SaltySD Patcher

a guest
Feb 1st, 2016
223
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 4.43 KB | None | 0 0
  1. /*
  2.  * Quick Auto-Patcher for SaltySD
  3.  * written by TheGag96
  4.  * Note: This may not actually work quite yet! Use at your own risk!
  5.  */
  6.  
  7. import std.stdio, std.net.curl, std.file, std.process, std.typecons, std.algorithm, std.path;
  8.  
  9. bool buildNewest = true;
  10. string inputFile;
  11. string patchesDir = "temp";
  12. bool isCodebin = false;
  13.  
  14. void main(string[] args) {
  15.   if (args.length < 2 || args.length > 4) {
  16.     writeln("Usage: saltypatcher <filename> <patches dir> (-codebin)");
  17.     writeln("If <patces dir> is not specified, the files will be downloaded and compiled automatically.");
  18.     writeln("Note that this requires DevkitPro and make to be installed on your machine!");
  19.     return;
  20.   }
  21.   else if (args.length == 3) {
  22.     if (args[2] == "-codebin") {
  23.       isCodebin = true;
  24.     }
  25.     else {
  26.       patchesDir = args[2];
  27.       buildNewest = false;
  28.     }
  29.   }
  30.   else if (args.length == 4) {
  31.     if (args[3] == "-codebin") isCodebin = true;
  32.     patchesDir = args[2];
  33.     buildNewest = false;
  34.   }
  35.  
  36.   inputFile = args[1];
  37.  
  38.   if (!checkFilesValidity()) return;
  39.  
  40.   if (buildNewest) compilePatches();
  41.  
  42.   patchItUp();
  43.  
  44.   if (buildNewest) cleanUpTemp();
  45.  
  46.   writeln("\nDone! Enjoy the salt!");
  47. }
  48.  
  49. void compilePatches() {
  50.   writeln("Grabbing newest patch files from git...");
  51.   //Download source files and compile
  52.   grabNewestFiles();
  53.  
  54.   writeln("Running make...");
  55.   chdir("temp");
  56.   auto shell = executeShell("make");
  57.   writeln("Make output: ", shell.output);
  58.   chdir("..");
  59. }
  60.  
  61. void grabNewestFiles() {
  62.   mkdir("temp");
  63.  
  64.   auto files = ["Makefile", "datasize.asm", "exist.asm", "find.asm", "hookdatasize.asm",
  65.                 "hookexist.asm", "hookfind.asm", "hooklock.asm", "lock.asm", "sdsound.asm"];
  66.  
  67.   foreach (file; files) {
  68.     writeln("Downloading ", file, "...");
  69.     download("https://github.com/shinyquagsire23/SaltySD/raw/master/smash/" ~ file,
  70.              "temp/" ~ file);
  71.   }
  72. }
  73.  
  74. bool checkFilesValidity() {
  75.   if (!exists(inputFile)) {
  76.     writeln("Looks like that ROM file doesn't exist.");
  77.     return false;
  78.   }
  79.  
  80.   if (buildNewest) return true;
  81.  
  82.   if (!exists(patchesDir)) {
  83.     writeln("Looks like the patch directory doesn't exist.");
  84.     return false;
  85.   }
  86.  
  87.   auto requiredFiles = ["datasize.bin", "exist.bin", "find.bin", "hookdatasize.bin", "hookexist.bin",
  88.                         "hookfind.bin", "hooklock.bin", "lock.bin", "sdsound.bin"];
  89.  
  90.   foreach (file; requiredFiles) {
  91.     if (!exists(patchesDir ~ "/" ~ file)) {
  92.       writeln("Could not find required file ", file, " in patch directory!");
  93.       return false;
  94.     }
  95.   }
  96.  
  97.   return true;
  98. }
  99.  
  100.  
  101. void cleanUpTemp() {
  102.   foreach (string name; dirEntries("temp", SpanMode.depth)) {
  103.     remove(name);
  104.   }
  105.  
  106.   rmdir("temp");
  107. }
  108.  
  109. alias BytePatch = Tuple!(long, "address", ubyte[], "bytes");
  110.  
  111. void patchItUp() {
  112.   writeln("Patching file ", inputFile, "...");
  113.  
  114.   immutable long[string] insertionPoints = [
  115.     "hookdatasize" : 0x13F4B8,
  116.     "datasize"     : 0xA1C800,
  117.     "hooklock"     : 0x1816CC,
  118.     "lock"         : 0xA1B800,
  119.     "hookexist"    : 0x159E9C,
  120.     "exist"        : 0xA1CD00,
  121.     "hookfind"     : 0x16EFAC,
  122.     "find"         : 0xA1CF00,
  123.     "sdsound"      : 0xA1CB00
  124.   ];
  125.  
  126.   BytePatch[] extraPatches = [
  127.     BytePatch(0x13F4B4, [0x1E, 0xFF, 0x2F, 0xE1]),
  128.     BytePatch(0x140DBC, [0x10, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1]),
  129.     BytePatch(0x159E98, [0x70, 0x40, 0x2D, 0xE9]),
  130.     BytePatch(0x159EF0, [0x70, 0x80, 0xBD, 0xE8]),
  131.     BytePatch(0x7AB5C4, [0x00, 0xCB, 0xA1, 0x00]),
  132.     BytePatch(0x7AB5E0, [0x9B, 0x37, 0xB6, 0x00])
  133.   ];
  134.  
  135.   auto romData = File(inputFile, "r+b");
  136.  
  137.   foreach (binFile; dirEntries(patchesDir, SpanMode.shallow).filter!(x => x.name.endsWith(".bin"))) {
  138.     //read in patch data
  139.     auto patchData = cast(ubyte[]) read(binFile.name);
  140.    
  141.     //chop off ".bin"
  142.     auto patchName = baseName(binFile.name)[0..$-4];
  143.  
  144.     //write the patch
  145.     //also take into account if it needs to be done 0x100000 bytes back (if it's a codebin)
  146.     romData.seek(insertionPoints[patchName] - isCodebin * 0x100000);
  147.     romData.rawWrite(patchData);
  148.  
  149.     //extra insertion point needed for hookfind
  150.     if (patchName == "hookfind") {
  151.       romData.seek(0x9E1F58 - isCodebin * 0x100000);
  152.       romData.rawWrite(patchData);
  153.     }
  154.   }
  155.  
  156.   //write the extra byte patches
  157.   foreach (patch; extraPatches) {
  158.     romData.seek(patch.address - isCodebin * 0x100000);
  159.     romData.rawWrite(patch.bytes);
  160.   }
  161. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement