Advertisement
Guest User

SaltySD Patcher

a guest
Feb 1st, 2016
79
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 4.39 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) {
  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) {
  41.     compilePatches();
  42.   }
  43.  
  44.   patchItUp();
  45.  
  46.   if (buildNewest) cleanUpTemp();
  47.  
  48.   writeln("\nDone! Enjoy the salt!");
  49. }
  50.  
  51. void compilePatches() {
  52.   writeln("Grabbing newest patch files from git...");
  53.   //Download source files and compile
  54.   grabNewestFiles();
  55.  
  56.   writeln("Running make...");
  57.   chdir("temp");
  58.   auto shell = executeShell("make");
  59.   writeln("Make output: ", shell.output);
  60.   chdir("..");
  61. }
  62.  
  63. void grabNewestFiles() {
  64.   mkdir("temp");
  65.  
  66.   auto files = ["Makefile", "datasize.asm", "exist.asm", "find.asm", "hookdatasize.asm",
  67.                 "hookexist.asm", "hookfind.asm", "hooklock.asm", "lock.asm", "sdsound.asm"];
  68.  
  69.   foreach (file; files) {
  70.     writeln("Downloading ", file, "...");
  71.     download("https://github.com/shinyquagsire23/SaltySD/raw/master/smash/" ~ file,
  72.              "temp/" ~ file);
  73.   }
  74. }
  75.  
  76. bool checkFilesValidity() {
  77.   if (!exists(inputFile)) {
  78.     writeln("Looks like that ROM file doesn't exist.");
  79.     return false;
  80.   }
  81.  
  82.   if (buildNewest) return true;
  83.  
  84.   if (!exists(patchesDir)) {
  85.     writeln("Looks like the patch directory doesn't exist.");
  86.   }
  87.  
  88.   auto requiredFiles = ["datasize.bin", "exist.bin", "find.bin", "hookdatasize.bin", "hookexist.bin",
  89.                         "hookfind.bin", "hooklock.bin", "lock.bin", "sdsound.bin"];
  90.  
  91.   foreach (file; requiredFiles) {
  92.     if (!exists(patchesDir ~ "/" ~ file)) {
  93.       writeln("Could not find required file ", file, " in patch directory!");
  94.       return false;
  95.     }
  96.   }
  97.  
  98.   return true;
  99. }
  100.  
  101.  
  102. void cleanUpTemp() {
  103.   foreach (string name; dirEntries("temp", SpanMode.depth)) {
  104.     remove(name);
  105.   }
  106.  
  107.   rmdir("temp");
  108. }
  109.  
  110. alias BytePatch = Tuple!(long, "address", ubyte[], "bytes");
  111.  
  112. void patchItUp() {
  113.   writeln("Patching file ", inputFile, "...");
  114.  
  115.   immutable long[string] insertionPoints = [
  116.     "hookdatasize" : 0x13F4B8,
  117.     "datasize"     : 0xA1C800,
  118.     "hooklock"     : 0x1816CC,
  119.     "lock"         : 0xA1B800,
  120.     "hookexist"    : 0x159E9C,
  121.     "exist"        : 0xA1CD00,
  122.     "hookfind"     : 0x16EFAC,
  123.     "find"         : 0xA1CF00,
  124.     "sdsound"      : 0xA1CB00
  125.   ];
  126.  
  127.   BytePatch[] extraPatches = [
  128.     BytePatch(0x13F4B4, [0x1E, 0xFF, 0x2F, 0xE1]),
  129.     BytePatch(0x140DBC, [0x10, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1]),
  130.     BytePatch(0x159E98, [0x70, 0x40, 0x2D, 0xE9]),
  131.     BytePatch(0x159EF0, [0x70, 0x80, 0xBD, 0xE8]),
  132.     BytePatch(0x7AB5C4, [0x00, 0xCB, 0xA1, 0x00]),
  133.     BytePatch(0x7AB5E0, [0x9B, 0x37, 0xB6, 0x00])
  134.   ];
  135.  
  136.   auto romData = File(inputFile, "r+b");
  137.  
  138.   foreach (binFile; dirEntries(patchesDir, SpanMode.shallow).filter!(x => x.name.endsWith(".bin"))) {
  139.     //read in patch data
  140.     auto patchData = cast(ubyte[]) read(binFile.name);
  141.    
  142.     //chop off ".bin"
  143.     auto patchName = baseName(binFile.name)[0..$-4];
  144.  
  145.     //write the patch
  146.     //also take into account if it needs to be done 0x100000 bytes back (if it's a codebin)
  147.     romData.seek(insertionPoints[patchName] - isCodebin * 0x100000);
  148.     romData.write(patchData);
  149.  
  150.     //extra insertion point needed for hookfind
  151.     if (patchName == "hookfind") {
  152.       romData.seek(0x9E1F58 - isCodebin * 0x100000);
  153.       romData.write(patchData);
  154.     }
  155.   }
  156.  
  157.   //write the extra byte patches
  158.   foreach (patch; extraPatches) {
  159.     romData.seek(patch.address - isCodebin * 0x100000);
  160.     romData.write(patch.bytes);
  161.   }
  162. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement