Advertisement
Guest User

Untitled

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