Esempio n. 1
0
        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}");
            }
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        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));
                }
            }
        }
Esempio n. 4
0
 /// <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"
     );
 }
Esempio n. 5
0
        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).");
            }
        }
Esempio n. 6
0
 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();
         }
     }
 }
Esempio n. 7
0
        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;
            }
        }
Esempio n. 8
0
        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);
            }
        }
Esempio n. 9
0
        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());
        }
Esempio n. 10
0
        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);
        }
Esempio n. 11
0
        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();
        }
Esempio n. 12
0
 private void AddNode(int i)
 {
     treeView1.Nodes[0].Nodes.Add("$" + Asar.PcToSnes(i).ToString());
 }
Esempio n. 13
0
        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();
             */
        }
Esempio n. 14
0
        /// <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);
            }
        }