private static void PrintWarningsAndErrors(string originalFile) { foreach (var warn in Asar.getwarnings()) { string error = warn.Fullerrdata; if (originalFile != null && !String.IsNullOrEmpty(warn.Filename)) { error = error.Replace(warn.Filename, originalFile); } Console.WriteLine($" {error}"); } foreach (var warn in Asar.geterrors()) { string error = warn.Fullerrdata; if (originalFile != null && !String.IsNullOrEmpty(warn.Filename)) { error = error.Replace(warn.Filename, originalFile); } Console.WriteLine($" {error}"); } }
private static int[] GetPointers(bool load) { var labels = Asar.getlabels(); bool set = false; int[] output = new int[4] { -1, -1, -1, -1 }; foreach (var label in labels) { switch (label.Name.ToLower()) { case "init": output[0] = label.Location; set = true; break; case "main": output[1] = label.Location; set = true; break; case "nmi": output[2] = label.Location; set = true; break; case "load": if (load) { output[3] = label.Location; set = true; } break; } } return(set ? output : null); }
private void textBox1_TextChanged(object sender, EventArgs e) { int addr = 0; if (treeView1.SelectedNode != null && (!treeView1.SelectedNode.Text.Contains(".smc") && !treeView1.SelectedNode.Text.Contains(".sfc"))) { addr = Asar.SnesToPc(Convert.ToInt32(treeView1.SelectedNode.Text.Replace("$", String.Empty))); Regex regex = new Regex(@"^[\dA-F]{2}$"); Match match = regex.Match(textBox1.Text); if (match.Success) { RH.HexWrite(textBox1.Text, (uint)addr, "Main"); treeView1_AfterSelect(new object(), new TreeViewEventArgs(treeView1.SelectedNode)); } } }
/// <summary> /// Applies a Patch to the ROM using Asar /// </summary> /// <param name="patch">Path to Patch</param> /// <param name="caller"></param> public void Patch(string patch, [CallerMemberName] string caller = "") { UR.Do ( () => { Asar.Init(); Asar.Patch(patch, ref _ROM); Asar.Close(); }, () => { // oh god what do i even do here... }, caller == "Main" ); }
static void CleanPreviousRun() { if (config.VerboseMode) { Console.WriteLine("Cleaning previous run..."); } DataCollector collector = new DataCollector(rom); collector.CheckPreviousUberData(); var cleanFile = new StringBuilder(); var result = collector.GetCollectedPointers(); foreach (int cleanPtr in result) { cleanFile.AppendLine($"autoclean ${cleanPtr:X6}"); } File.WriteAllText("asm/work/clean.asm", cleanFile.ToString()); error = !Asar.patch(mainDirectory + "asm/work/clean.asm", ref rom.romData, pathList); PrintWarningsAndErrors(""); if (error) { Console.WriteLine("Some errors occured while applying cleaning the ROM. Process aborted."); Console.WriteLine("Your ROM wasn't modified."); return; } // TODO: freespace leak analysis. if (config.VerboseMode) { Console.WriteLine($"Cleaned {result.Length} label(s)."); } }
private void LoadTreeView() { Asar.Init(); for (int i = 0; i < RH.ROM.Length; i++) { try { var a = treeView1.BeginInvoke(new Deleg(AddNode), i); Thread.Sleep(10); treeView1.EndInvoke(a); } catch { Thread.CurrentThread.Abort(); } } Asar.Close(); foreach (TreeNode node in treeView1.Nodes[0].Nodes) { if (node.Text == "-1") { node.Remove(); } } }
private void treeView1_AfterSelect(object sender, TreeViewEventArgs e) { if (RH != null) { int addr; string val = ""; string pre = ""; if (treeView1.SelectedNode != null && (!treeView1.SelectedNode.Text.Contains(".smc") && !treeView1.SelectedNode.Text.Contains(".sfc"))) { addr = Asar.SnesToPc(Convert.ToInt32(treeView1.SelectedNode.Text.Replace("$", String.Empty))); val = MOLE_Back.Utils.Hex.ByteArrToHexStr(new byte[1] { RH.ROM[addr] }); pre = "#$"; } else { val = "unknown"; } label1.Text = "Value: " + pre + val; textBox1.Text = val; } }
private static void BuildLibrary() { if (config.VerboseMode) { Console.WriteLine("Building external library..."); Console.WriteLine(); } int fileCount = 0; bool binaryMode = false; var files = Directory.GetFiles("library/", "*.asm", SearchOption.AllDirectories); string fullPath = Path.GetFullPath("library/"); repeat: foreach (var asmFile in files) { int start; int end; string baseFolder = Path.GetDirectoryName(asmFile) + "/"; string fileName = Path.GetFileName(asmFile); string fileNameExt = Path.GetFileNameWithoutExtension(asmFile); string fullFilePath = Path.GetFullPath(asmFile); string labelLevel = fullFilePath.Substring(fullPath.Length) .Replace(" ", "_").Replace("/", "_").Replace("\\", "_"); int s = labelLevel.LastIndexOf('.'); if (config.VerboseMode && binaryMode) { Console.WriteLine("Processing binary file '{0}':", fileName); } else if (config.VerboseMode) { Console.WriteLine("Processing file '{0}':", fileName); } if (s != -1) { labelLevel = labelLevel.Substring(0, s); } if (!binaryMode) { if (!CompileFile(File.ReadAllText(asmFile), baseFolder, fileName, "library", false, out start, out end, false, null)) { return; } } else { string baseAssembly = labelLevel + ":\r\nincbin \"" + fileName + "\"\r\n"; if (!CompileFile(baseAssembly, baseFolder, fileName, "library", false, out start, out end, false, null)) { return; } } if (config.VerboseMode) { Console.WriteLine(" Inserted at ${0:X6} (PC: 0x{1:x})", start, SNES.ToPCHeadered(start, rom.containsHeader)); Console.WriteLine(" Insert size: {0} (0x{0:X}) bytes", end - start + 8); } totalInsertSize += end - start + 8; var labels = Asar.getlabels().ToList(); int copyl = 0; for (int i = 0; i < labels.Count; ++i) { if (labels[i].Name != labelLevel) { var copy = labels[i]; copy.Name = labelLevel + "_" + copy.Name; labels[i] = copy; } if (labelList.Any(x => x.Name == labels[i].Name)) { Console.WriteLine(" {0} - error: label redefinition [{1}].", fileName, labels[i].Name); error = true; return; } if (!labels[i].Name.Contains(":")) { labelList.Add(labels[i]); copyl++; } if (labels[i].Location >= end || labels[i].Location < start) { labels.RemoveAt(i); --i; } } if (config.VerboseMode) { if (copyl == 1) { Console.WriteLine(" Processed one label."); } else { Console.WriteLine(" Processed {0} labels.", copyl); } } if (labels.Count == 0) { Console.WriteLine(" {0}: error: file contains no label within freespace area.", fileName); error = true; return; } if (!protPointerList.Contains(labels[0].Location)) { protPointerList.Add(labels[0].Location); } else { Console.WriteLine(" {0}: wtf error: Library included file is already protected.", fileName); error = true; return; } if (config.VerboseMode) { Console.WriteLine(); } fileCount++; } if (!binaryMode) { binaryMode = true; files = Directory.GetFiles("library/", "*.*", SearchOption.AllDirectories) .Where(x => !x.EndsWith(".asm", StringComparison.InvariantCultureIgnoreCase)).ToArray(); goto repeat; } if (fileCount == 0) { return; } if (fileCount == 1 && config.VerboseMode) { Console.WriteLine("Processed one library file."); } else if (config.VerboseMode) { Console.WriteLine("Processed {0} library files.", fileCount); } }
static void BuildOther() { const string temporaryWorkFile = "asm/work/temp.asm"; if (error) { return; } // prepare global file string current = File.ReadAllText(config.GlobalFile); byte[] tempBuffer = new byte[32768]; var temp = current.Insert(0, "lorom\r\norg $108000"); if (!FileUtils.ForceCreate(temporaryWorkFile, temp)) { Console.WriteLine($" Error: access denied while creating temporary file {temporaryWorkFile}."); error = true; return; } Asar.patch(mainDirectory + temporaryWorkFile, ref tempBuffer, pathList); var ptr = GetPointers(false); enableNmi[3] = ptr[2] != -1; current = current.Insert(0, "\r\nnamespace global\r\n"); current += "\r\nnamespace off\r\n"; string global = File.ReadAllText("asm/base/global.asm"); global += current; // build prot list StringBuilder protList = new StringBuilder(); foreach (int protPointer in protPointerList) { protList.AppendFormat("dl ${0:X6}", protPointer); protList.AppendLine(); } InsertTable(ref global, "prot_table", protList.ToString()); File.WriteAllText("asm/work/global.asm", global); // prepare status file current = File.ReadAllText(config.StatusBarFile); current = current.Insert(0, "\r\nnamespace status_bar\r\n"); current += "\r\nnamespace off\r\n"; global = File.ReadAllText("asm/base/statusbar.asm"); global += current; File.WriteAllText("asm/work/statusbar.asm", global); // copy sprites.asm File.Copy("asm/base/sprites.asm", "asm/work/sprites.asm", true); // prepare main file StringBuilder mainFile = new StringBuilder(); mainFile.AppendFormat("incsrc \"{0}\"", labelLibraryFile); mainFile.AppendLine(); mainFile.AppendFormat("incsrc \"../../{0}\"", config.MacroLibraryFile); mainFile.AppendLine(); mainFile.AppendFormat("!level_nmi\t= {0}\r\n", enableNmi[0] ? 1 : 0); mainFile.AppendFormat("!overworld_nmi\t= {0}\r\n", enableNmi[1] ? 1 : 0); mainFile.AppendFormat("!gamemode_nmi\t= {0}\r\n", enableNmi[2] ? 1 : 0); mainFile.AppendFormat("!global_nmi\t= {0}\r\n\r\n", enableNmi[3] ? 1 : 0); mainFile.AppendFormat("!sprite_RAM\t= ${0:X6}\r\n\r\n", GetSpriteRAMValue()); mainFile.AppendLine(); mainFile.Append(File.ReadAllText("asm/base/main.asm")); mainFile.AppendLine(); mainFile.AppendLine("print freespaceuse"); File.WriteAllText("asm/work/main.asm", mainFile.ToString()); }
private static bool PatchSingleFile(string data, string baseFolder, string originalFile, string originFolder, bool library, out int startPc, out int endPc) { startPc = -1; endPc = -1; string realFile = mainDirectory + baseFolder + "__temp.asm"; string compileFile = originalFile; if (!FileUtils.ForceCreate(realFile, GenerateBasefile(data, library, realFile, originFolder))) { Console.WriteLine($" Error: access denied while creating temporary file {realFile}."); error = true; return(false); } bool status = Asar.patch(realFile, ref rom.romData, pathList); if (!FileUtils.ForceDelete(realFile)) { Console.WriteLine($" Warning: could not delete temporary file {realFile}."); } PrintWarningsAndErrors(compileFile); if (!status) { Console.WriteLine(); Console.WriteLine("Some errors occured while running UberASM tool. Process aborted."); Console.WriteLine("Your ROM wasn't modified."); error = true; return(false); } // process prints. prot requests, internal things, tec. string[] prints = Asar.getprints(); bool endl = false; bool startl = false; foreach (string print in prints) { string[] split = print.Trim().Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries); string command = split.Length > 0 ? split[0].ToLower() : ""; string value = split.Length > 1 ? string.Join(" ", split, 1, split.Length - 1) : ""; if (endl) { Console.WriteLine(" {0}: error: unexpected print after end of the file print mark.", originalFile); error = true; return(false); } if (!startl && command != "_startl") { Console.WriteLine(" {0}: error: unexpected print before STARTL command.", originalFile); error = true; return(false); } switch (command) { case "_prot": try { int ptr = Convert.ToInt32(value, 16); if (!protPointerList.Contains(ptr)) { protPointerList.Add(ptr); } break; } catch { Console.WriteLine(" {0}: error: invalid PRINT PROT value.", originalFile); error = true; return(false); } case "_startl": try { startPc = Convert.ToInt32(value, 16); startl = true; break; } catch { Console.WriteLine(" {0}: error: invalid PRINT STARTL value.", originalFile); error = true; return(false); } case "_endl": try { endPc = Convert.ToInt32(value, 16); endl = true; break; } catch { Console.WriteLine(" {0}: error: invalid PRINT ENDL value.", originalFile); error = true; return(false); } default: Console.WriteLine(print); break; } } if (startPc == endPc) { Console.WriteLine(" {0}: error: empty assembled file.", originalFile); error = true; return(false); } return(true); }
static void Main(string[] args) { Directory.SetCurrentDirectory(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); mainDirectory = Environment.CurrentDirectory + "/"; pathList = new string[3]; pathList[0] = mainDirectory; pathList[1] = mainDirectory + "asm/work/"; pathList[2] = mainDirectory + "asm/"; // this is for compatibility with old patches. if (!Asar.init()) { Console.WriteLine("Could not initialize or find asar.dll"); Console.WriteLine("Please redownload the program."); Pause(); return; } if (args.Length == 0 || args.Length > 2) { Console.WriteLine("Usage: UberASMTool [code list] [ROM]"); Console.WriteLine("If ROM is not specified, UberASM Tool will search for the one in the code list."); Console.WriteLine("If code list is not specified, UberASM Tool will try loading 'list.txt'."); Console.WriteLine(); if (args.Length > 2) { Pause(); return; } } UberConfigParser parser = new UberConfigParser(); if (args.Length == 2) { parser.OverrideROM = args[1]; try { parser.LoadListFile(args[0]); } catch (Exception ex) { Console.WriteLine("Can't read {0}: {1}.", args[0], ex.Message); Pause(); return; } } else if (args.Length == 1) { parser.OverrideROM = null; try { parser.LoadListFile(args[0]); } catch (Exception ex) { Console.WriteLine("Can't read {0}: {1}.", args[0], ex.Message); Pause(); return; } } else if (File.Exists("list.txt")) { parser.LoadListFile("list.txt"); } else { Console.WriteLine("list.txt not found."); Pause(); return; } Console.WriteLine(); if (!parser.ParseList()) { Console.WriteLine("Could not parse list file!"); Console.WriteLine(parser.GetLogs()); Pause(); return; } config = parser.Build(); if (config.ROMPath == null) { Console.WriteLine("ROM file not given."); Pause(); return; } try { rom = new ROM(config.ROMPath); rom.Init(); SNES.DetectAddressing(rom.romType & 255); } catch (Exception ex) { Console.WriteLine("Error: {0}", ex.Message); Pause(); return; } CleanPreviousRun(); if (error) { Pause(); return; } BuildLibrary(); if (error) { Pause(); return; } GenerateLibrary(); BuildAsm("overworld", 7, 1, "OW_init_table", "OW_asm_table", "OW_nmi_table", null); BuildAsm("gamemode", 256, 2, "gamemode_init_table", "gamemode_main_table", "gamemode_nmi_table", null); BuildAsm("level", 512, 0, "level_init_table", "level_asm_table", "level_nmi_table", "level_load_table"); BuildOther(); if (error) { Pause(); return; } if (config.VerboseMode) { Console.WriteLine("Total files insert size: {0} (0x{0:X4}) bytes", totalInsertSize); } if (Asar.patch(mainDirectory + "asm/work/main.asm", ref rom.romData, pathList)) { PrintWarningsAndErrors(""); var prints = Asar.getprints(); bool printed = false; for (int i = 0; i < prints.Length; ++i) { if (i + 1 != prints.Length) { Console.WriteLine(prints[i]); } else if (int.TryParse(prints[i], out int insertSize) && config.VerboseMode) { Console.WriteLine("Main patch insert size: {0} (0x{0:X4}) bytes", insertSize); Console.WriteLine(); Console.WriteLine("Total: {0} (0x{0:X4}) bytes", insertSize + totalInsertSize); Console.WriteLine(); printed = true; } } if (config.VerboseMode && !printed) { Console.WriteLine(); } Console.WriteLine("Codes inserted successfully."); rom.Save(); WriteRestoreComment(); } else { PrintWarningsAndErrors(""); Console.WriteLine("Some errors occured while applying main patch. Process aborted."); Console.WriteLine("Your ROM wasn't modified."); } Pause(); }
private void AddNode(int i) { treeView1.Nodes[0].Nodes.Add("$" + Asar.PcToSnes(i).ToString()); }
public void runAsar(string path, string fname = "") { string arg2 = "\\ASM\\Main.asm"; Asar.init(); if (fname == "") { Console.WriteLine("NoError = " + Asar.patch(path + arg2, ref ROM.DATA)); Asarerror[] errors = Asar.geterrors(); foreach (Asarerror e in errors) { Console.WriteLine(e.Rawerrdata); } FileStream fs = new FileStream(path + "//TestROM//working.sfc", FileMode.OpenOrCreate, FileAccess.Write); fs.Write(ROM.DATA, 0, ROM.DATA.Length); fs.Close(); } else { Console.WriteLine("NoError = " + Asar.patch(path + arg2, ref ROM.DATA)); Asarerror[] errors = Asar.geterrors(); foreach (Asarerror e in errors) { Console.WriteLine(e.Rawerrdata); } Console.WriteLine("NoError " + fname); FileStream fs = new FileStream(fname, FileMode.OpenOrCreate, FileAccess.Write); fs.Write(ROM.DATA, 0, ROM.DATA.Length); fs.Close(); } Asar.close(); /*var process = new Process(); * process.StartInfo.FileName = "cmd.exe"; * //Do not create command propmpt window * process.StartInfo.CreateNoWindow = false; * * //Do not use shell execution * process.StartInfo.UseShellExecute = false; * * //Redirects error and output of the process (command prompt). * process.StartInfo.RedirectStandardError = true; * process.StartInfo.RedirectStandardOutput = true; * process.StartInfo.RedirectStandardInput = true; * //start a new process * process.Start(); * string arg1 = "\"xkas.exe\""; * string arg2 = "\"ASM\\Main.asm\""; * string arg3 = "\"TestROM\\working.sfc\""; * process.StandardInput.WriteLine(@"cd " + path); * //WriteLog(@"cd " + path, Color.Black); * process.StandardInput.WriteLine(arg1 + " " + arg2 + " " + arg3); * //process.StandardInput.WriteLine(arg3); * process.StandardInput.WriteLine("exit"); * //wait until process is running * process.WaitForExit(); * * //reads output and error of command prompt to string. * string output = process.StandardOutput.ReadToEnd(); * string error = process.StandardError.ReadToEnd(); */ }
/// <summary> /// Picks a ROM through a <see cref="SaveFileDialog"/> if not specified (or forced) and patch multi_midway.asm. /// </summary> private void PatchRom(bool saveAs = false) { try { // Similar as in ExportAsmTable(): Compress the tables first. CompressTable(); // Now we save the midway points with a fixed name. Midway.ExportAsm(midways, new FileStream(directory + MmpAsm, FileMode.Create)); UnsavedChanges = false; } catch { MessageBox.Show("Cannot create multi_midway_table.asm. Please check the file's permission or whether it's already in use.", "Cannot create " + MmpAsm, MessageBoxButtons.OK, MessageBoxIcon.Error); return; } if (Asar.init()) { Asar.reset(); if (string.IsNullOrEmpty(romName) || saveAs) { if (patchRomDialog.ShowDialog() != DialogResult.OK) { return; } romName = patchRomDialog.FileName; } try { // Remember that Asar expects headerless ROMs. // The code seperates the raw data from the header. byte[] fullRom = File.ReadAllBytes(patchRomDialog.FileName); int lHeader = fullRom.Length & 0x7fff; byte[] header = new byte[lHeader]; byte[] rom = new byte[fullRom.Length - lHeader]; Array.Copy(fullRom, 0, header, 0, lHeader); Array.Copy(fullRom, lHeader, rom, 0, fullRom.Length - lHeader); // Patching starts... if (Asar.patch(directory + "multi_midway.asm", ref rom)) { try { // Now it's time to merge them back. fullRom = new byte[rom.Length + lHeader]; Array.Copy(header, 0, fullRom, 0, lHeader); Array.Copy(rom, 0, fullRom, lHeader, rom.Length); File.WriteAllBytes(patchRomDialog.FileName, fullRom); } catch (IOException ex) { MessageBox.Show("An error appeared when patching Multiple Midway Points: " + ex.Message, "ROM couldn't be written", MessageBoxButtons.OK, MessageBoxIcon.Error); Asar.close(); return; } StringBuilder warningBuilder = new StringBuilder(); foreach (var warning in Asar.getwarnings()) { warningBuilder.AppendLine(warning.Fullerrdata); } string warnings = warningBuilder.ToString(); string fullWarning = !string.IsNullOrEmpty(warnings) ? "The following warnings appeared:\n" + warnings : ""; using (LongMessage message = new LongMessage("Multiple Midway Points has been inserted successfully. It uses " + Asar.getprints()[0] + " bytes of freespace.\n" + fullWarning, "Patching successful")) { message.ShowDialog(this); } } else { MessageBox.Show("An error appeared when patching Multiple Midway Points. See mmp.log for more information.", "ROM couldn't be patched", MessageBoxButtons.OK, MessageBoxIcon.Error); using (FileStream stream = new FileStream("mmp.log", FileMode.Create)) { using (StreamWriter writer = new StreamWriter(stream)) { foreach (var warning in Asar.getwarnings()) { writer.WriteLine(warning.Fullerrdata); } foreach (var error in Asar.geterrors()) { writer.WriteLine(error.Fullerrdata); } } } } } catch (IOException ex) { MessageBox.Show("An error appeared when patching Multiple Midway Points: " + ex.Message, "ROM couldn't be opened", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } finally { Asar.close(); } } else { MessageBox.Show("Asar couldn't be started. (Perhaps asar.dll is missing or a wrong version is used?)", "Couldn't open Asar", MessageBoxButtons.OK, MessageBoxIcon.Error); } }