From aaa07f5ad77a17f8f2deb1803897b657b08333cf Mon Sep 17 00:00:00 2001 From: Juan Segura Date: Thu, 26 Feb 2026 01:07:51 +0100 Subject: [PATCH 1/3] Launch MAME from ZXBS --- README.md | 6 +- ZXBSInstaller.Log/ExternalTools.json | 170 +++++++++++++++++++ ZXBSInstaller.Log/Neg/ExternalTool.cs | 5 +- ZXBSInstaller.Log/ServiceLayer.cs | 35 +++- ZXBSInstaller.Log/ZXBSInstaller.Log.csproj | 10 ++ ZXBSInstaller/Assets/hdfmonkey.png | Bin 0 -> 27926 bytes ZXBSInstaller/Assets/mame.png | Bin 0 -> 53044 bytes ZXBSInstaller/Assets/nextsdimage.png | Bin 0 -> 4539 bytes ZXBSInstaller/Assets/tbbluemame.png | Bin 0 -> 16762 bytes ZXBSInstaller/Assets/zxbsmame.png | Bin 0 -> 35925 bytes ZXBSInstaller/Controls/MainControl.axaml | 5 +- ZXBSInstaller/Controls/MainControl.axaml.cs | 67 +++++++- ZXBSInstaller/Controls/ToolItemControl.axaml | 2 +- ZXBSInstaller/ExternalTools.json | 62 ------- ZXBSInstaller/MainWindow.axaml | 2 +- ZXBSInstaller/ZXBSInstaller.csproj | 19 ++- ZXBStudio/Dialogs/ZXOptionsDialog.axaml.cs | 5 +- ZXBStudio/MainWindow.axaml.cs | 127 +++++++++++++- ZXBStudio/ZXBasicStudio.csproj | 2 +- ZXBStudio/version.txt | 2 +- 20 files changed, 425 insertions(+), 94 deletions(-) create mode 100644 ZXBSInstaller.Log/ExternalTools.json create mode 100644 ZXBSInstaller/Assets/hdfmonkey.png create mode 100644 ZXBSInstaller/Assets/mame.png create mode 100644 ZXBSInstaller/Assets/nextsdimage.png create mode 100644 ZXBSInstaller/Assets/tbbluemame.png create mode 100644 ZXBSInstaller/Assets/zxbsmame.png delete mode 100644 ZXBSInstaller/ExternalTools.json diff --git a/README.md b/README.md index 31be994..b1f2a79 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Have fun! ## Credits - Icons from [SVG REPO](https://www.svgrepo.com/): - Blivesta in MIT License - - Dazzle Ui in CC Attribution License + - Dazzle Ui in CC Attribution License - Kde in GPL License - Konstantin Filatov in CC Attribution - Mohamed Raouf in CC Attribution License @@ -45,5 +45,5 @@ Have fun! - Siemens in MIT License - Zest in MIT License - Ananthanath A X Kalaiism in PD License - - + - Siemens in MIT License + - SVG Repo CC0 License diff --git a/ZXBSInstaller.Log/ExternalTools.json b/ZXBSInstaller.Log/ExternalTools.json new file mode 100644 index 0000000..edd5edd --- /dev/null +++ b/ZXBSInstaller.Log/ExternalTools.json @@ -0,0 +1,170 @@ +[ + { + "Id": "zxbsinstaller", + "Enabled": true, + "Name": "ZX Basic Studio Installer", + "Author": "Duefectu", + "Description": "This program, and it is used to download, install and keep all external tools and ZX Basic Studio itself up to date.", + "SupportedOperatingSystems": [ + 1, + 2, + 3 + ], + "SiteUrl": "https://github.com/boriel-basic/ZXBasicStudio", + "LicenseType": "MIT License", + "LicenceUrl": "https://raw.githubusercontent.com/boriel-basic/ZXBasicStudio/refs/heads/master/LICENSE.txt", + "VersionsUrl": "https://github.com/boriel-basic/ZXBasicStudio/releases/", + "LocalPath": "", + "FullLocalPath": null, + "DirectUpdate": true, + "Group": "ZX Basic Studio", + "Order": 0 + }, + { + "Id": "zxbasic", + "Enabled": true, + "Name": "Boriel ZX Basic Compiler", + "Author": "Boriel", + "Description": "ZXBCompiler is a BORIEL BASIC cross compiler tool. It's a required tool.'", + "SupportedOperatingSystems": [ + 1, + 2, + 3 + ], + "SiteUrl": "https://boriel-basic.net", + "LicenseType": "GNU Affero General Public License v3.0", + "LicenceUrl": "https://raw.githubusercontent.com/boriel-basic/zxbasic/refs/heads/main/LICENSE.txt", + "VersionsUrl": "https://boriel.com/files/zxb/", + "LocalPath": "", + "FullLocalPath": "C:\\ZXNext\\zxbasic\\zxbc.exe", + "DirectUpdate": true, + "Group": "ZX Basic Studio", + "Order": 1 + }, + { + "Id": "zxbs", + "Enabled": true, + "Name": "ZX Basic Studio", + "Author": "Dr.Gusman, Boriel, Duefectu, AdolFITO, Hash6Iron and SirRickster", + "Description": "IDE (Integrated Development Environment) with code editor, Assembler, UDGs, fonts, sprites, .tap editor, debugger, emulator, etc.", + "SupportedOperatingSystems": [ + 1, + 2, + 3 + ], + "SiteUrl": "https://github.com/boriel-basic/ZXBasicStudio", + "LicenseType": "MIT License", + "LicenceUrl": "https://raw.githubusercontent.com/boriel-basic/ZXBasicStudio/refs/heads/master/LICENSE.txt", + "VersionsUrl": "https://github.com/boriel-basic/ZXBasicStudio/releases/", + "LocalPath": "", + "FullLocalPath": null, + "DirectUpdate": true, + "Group": "ZX Basic Studio", + "Order": 2 + }, + { + "Id": "mame", + "Enabled": true, + "Name": "M.A.M.E.", + "Author": "MAME Development Team", + "Description": "MAME (Multi Arcade Machione Emulator) is a multi-purpose emulation framework.", + "SupportedOperatingSystems": [ + 1, + 2, + 3 + ], + "SiteUrl": "https://www.mamedev.org/", + "LicenseType": "GPL-2.0 / BSD-3-Clause License", + "LicenceUrl": "https://www.mamedev.org/", + "VersionsUrl": "", + "LocalPath": "", + "FullLocalPath": null, + "DirectUpdate": true, + "Group": "ZX Spectrum Next", + "Order": 3 + }, + { + "Id": "tbbluemame", + "Enabled": true, + "Name": "Next boot ROM", + "Author": "SpectNext Ltd", + "Description": "ZX Basic Studio plugin for MAME. Allows you to debug programmes from ZX Basic Studio.", + "SupportedOperatingSystems": [ + 1, + 2, + 3 + ], + "SiteUrl": "https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA", + "LicenseType": "GPL-3.0", + "LicenceUrl": "https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/-/raw/master/LICENSE?ref_type=heads", + "VersionsUrl": "", + "LocalPath": "", + "FullLocalPath": null, + "DirectUpdate": true, + "Group": "ZX Spectrum Next", + "Order": 4 + }, + { + "Id": "zxbsmame", + "Enabled": true, + "Name": "ZXBS MAME plugin", + "Author": "Duefectu Corp", + "Description": "ZX Basic Studio plugin for MAME. Allows you to debug programmes from ZX Basic Studio.", + "SupportedOperatingSystems": [ + 1, + 2, + 3 + ], + "SiteUrl": "https://github.com/boriel-basic/ZXBasicStudio", + "LicenseType": "MIT License", + "LicenceUrl": "https://raw.githubusercontent.com/boriel-basic/ZXBasicStudio/refs/heads/master/LICENSE.txt", + "VersionsUrl": "", + "LocalPath": "", + "FullLocalPath": null, + "DirectUpdate": true, + "Group": "ZX Spectrum Next", + "Order": 5 + }, + { + "Id": "nextsdimage", + "Enabled": true, + "Name": "ZX Spectrum Next SD image", + "Author": "SpectNext Ltd", + "Description": "ZX Basic Studio plugin for MAME. Allows you to debug programmes from ZX Basic Studio.", + "SupportedOperatingSystems": [ + 1, + 2, + 3 + ], + "SiteUrl": "https://github.com/boriel-basic/ZXBasicStudio", + "LicenseType": "MIT License", + "LicenceUrl": "https://raw.githubusercontent.com/boriel-basic/ZXBasicStudio/refs/heads/master/LICENSE.txt", + "VersionsUrl": "", + "LocalPath": "", + "FullLocalPath": null, + "DirectUpdate": true, + "Group": "ZX Spectrum Next", + "Order": 5 + }, + { + "Id": "hdfmonkey", + "Enabled": true, + "Name": "hdfmonkey - jjjs build", + "Author": "jjjs, gasman, ChaN", + "Description": "A tool for editing the contents of disk images used by ZX Spectrum Next.", + "SupportedOperatingSystems": [ + 1, + 2, + 3 + ], + "SiteUrl": "https://www.specnext.com/forum/viewtopic.php?t=2604", + "LicenseType": "GPL-3.0", + "LicenceUrl": "https://codeberg.org/chwe/hdfmonkey/src/branch/dev-v05x", + "VersionsUrl": "https://zx.duefectucorp.com/tools/hdfmonkey/versions.txt", + "LocalPath": "", + "FullLocalPath": null, + "DirectUpdate": true, + "Group": "ZX Spectrum Next", + "Order": 6 + } +] \ No newline at end of file diff --git a/ZXBSInstaller.Log/Neg/ExternalTool.cs b/ZXBSInstaller.Log/Neg/ExternalTool.cs index 6232d35..b5efb33 100644 --- a/ZXBSInstaller.Log/Neg/ExternalTool.cs +++ b/ZXBSInstaller.Log/Neg/ExternalTool.cs @@ -72,7 +72,10 @@ public class ExternalTool /// Recommended /// public bool Recommended { get; set; } - + /// + /// Tools group + /// + public string Group { get; set; } /// /// Versions of the tool /// diff --git a/ZXBSInstaller.Log/ServiceLayer.cs b/ZXBSInstaller.Log/ServiceLayer.cs index b3cbc07..668272a 100644 --- a/ZXBSInstaller.Log/ServiceLayer.cs +++ b/ZXBSInstaller.Log/ServiceLayer.cs @@ -37,7 +37,7 @@ public static class ServiceLayer /// /// True if the computer is a Mac /// - public static bool IsMac=false; + public static bool IsMac = false; /// /// Used to cancel the current operation. It is set to true when the user clicks the cancel button and it is checked in all long operations to stop them if it is true. /// @@ -307,20 +307,39 @@ public static void OpenUrlInBrowser(string url) /// /// Retrieves all external tools configured for use with the application. /// - /// Json string with the external tools information /// An array of objects representing the available external tools. The array is empty /// if no external tools are configured or can download the config file. - public static ExternalTool[] SetExternalTools(string json) + public static ExternalTool[] GetExternalTools() { try { UpdateStatus?.Invoke("Retrieving external tools information...", 5); - var tools = JsonSerializer.Deserialize(json); - if (tools == null) + // Get external tools list from embded resource + ExternalTool[] tools = null; { - ShowMessage("ERROR, unable to obtain the list of external tools. Download and install a new version of ZXBSInstaller."); - return null; + var assembly = Assembly.GetExecutingAssembly(); + using (Stream? stream = assembly.GetManifestResourceStream("ZXBSInstaller.Log.ExternalTools.json")) + { + if (stream == null) + { + ShowMessage("ERROR, unable to obtain the list of external tools. Download and install a new version of ZXBSInstaller: ERROR #1"); + return null; + } + using StreamReader reader = new StreamReader(stream, Encoding.UTF8); + var json = reader.ReadToEnd(); + if (string.IsNullOrEmpty(json)) + { + ShowMessage("ERROR, unable to obtain the list of external tools. Download and install a new version of ZXBSInstaller: ERROR #2"); + return null; + } + tools = JsonSerializer.Deserialize(json); + if (tools == null) + { + ShowMessage("ERROR, unable to obtain the list of external tools. Download and install a new version of ZXBSInstaller. ERROR #3"); + return null; + } + } } int max = tools.Length; @@ -1089,7 +1108,7 @@ public static void DownloadAndInstallTool(ExternalTool tool, ExternalTools_Versi return; } - if(tool.Id == "zxbsinstaller") + if (tool.Id == "zxbsinstaller") { ShowStatusPanel($"After installing or updating ZXBSInstaller, run this program from {tool.LocalPath}."); } diff --git a/ZXBSInstaller.Log/ZXBSInstaller.Log.csproj b/ZXBSInstaller.Log/ZXBSInstaller.Log.csproj index fa71b7a..e5df59e 100644 --- a/ZXBSInstaller.Log/ZXBSInstaller.Log.csproj +++ b/ZXBSInstaller.Log/ZXBSInstaller.Log.csproj @@ -6,4 +6,14 @@ enable + + + + + + + + + + diff --git a/ZXBSInstaller/Assets/hdfmonkey.png b/ZXBSInstaller/Assets/hdfmonkey.png new file mode 100644 index 0000000000000000000000000000000000000000..e1e115e20740547b9d25bbcd40868493740ad3ff GIT binary patch literal 27926 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 Sw3Ch%Bh$uSR)2%B3i=NTeG0?? literal 0 HcmV?d00001 diff --git a/ZXBSInstaller/Assets/mame.png b/ZXBSInstaller/Assets/mame.png new file mode 100644 index 0000000000000000000000000000000000000000..236131c70ef5c60dd92dd65575cffb1bed055618 GIT binary patch literal 53044 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 z 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 literal 0 HcmV?d00001 diff --git a/ZXBSInstaller/Assets/tbbluemame.png b/ZXBSInstaller/Assets/tbbluemame.png new file mode 100644 index 0000000000000000000000000000000000000000..2978686bf699bf07ad31e79ccafd4289b8484ac6 GIT binary patch literal 16762 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 Z7@Jx6?!PH8#r^jHRYi@v#R`vt{uii(>_-3q literal 0 HcmV?d00001 diff --git a/ZXBSInstaller/Assets/zxbsmame.png b/ZXBSInstaller/Assets/zxbsmame.png new file mode 100644 index 0000000000000000000000000000000000000000..ae4537abedc96e9b8413a9aa329afc2ba4bd97e8 GIT binary patch literal 35925 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 - + + + diff --git a/ZXBSInstaller/Controls/MainControl.axaml.cs b/ZXBSInstaller/Controls/MainControl.axaml.cs index 87c1805..72b95bf 100644 --- a/ZXBSInstaller/Controls/MainControl.axaml.cs +++ b/ZXBSInstaller/Controls/MainControl.axaml.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Data; using System.Linq; +using System.Runtime.CompilerServices; using System.Security.Cryptography; using System.Threading; using ZXBSInstaller.Controls; @@ -109,8 +110,7 @@ private void GetExternalTools() }); // Get tools - var json = UITools.GetTextResource("ExternalTools.json"); - var tools = ServiceLayer.SetExternalTools(json); + var tools = ServiceLayer.GetExternalTools(); HideStatusPanel(); if (tools == null) @@ -136,20 +136,71 @@ private void ShowData() toolItemControls.Clear(); var tools = ServiceLayer.ExternalTools; - pnlTools.Children.Clear(); - foreach (var tool in tools) + mainTools.Children.Clear(); + // ZX Basic Studio { - // Create on ToolItemControl foreach tool - var control = new ToolItemControl(tool, Command_Received); - toolItemControls.Add(control); - pnlTools.Children.Add(control); + var groupTools = tools.Where(t => t.Group == "ZX Basic Studio"); + { + mainTools.Children.Add(new CheckBox() + { + Content = "ZX Basic Studio", + FontSize = 16, + IsChecked = true, + Margin = new Thickness(10, 10, 0, 0), + Foreground = Yellow + }); + mainTools.Children.Add(new Separator() + { + Margin = new Thickness(0), + HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Stretch + }); + } + var pnlTools = new WrapPanel(); + mainTools.Children.Add(pnlTools); + ShowData_AddTools(pnlTools, groupTools); + } + + // Next + { + var groupTools = tools.Where(t => t.Group == "ZX Spectrum Next"); + { + mainTools.Children.Add(new CheckBox() + { + Content = "ZX Spectrum Next", + FontSize = 16, + IsChecked = true, + Margin = new Thickness(10, 10, 0, 0), + Foreground = Yellow + }); + mainTools.Children.Add(new Separator() + { + Margin = new Thickness(0), + HorizontalAlignment = Avalonia.Layout.HorizontalAlignment.Stretch + }); + } + var pnlTools = new WrapPanel(); + mainTools.Children.Add(pnlTools); + ShowData_AddTools(pnlTools, groupTools); } + // Update summary area UpdateSummary(); }); } + private void ShowData_AddTools(WrapPanel panel, IEnumerable tools) + { + foreach (var tool in tools) + { + // Create on ToolItemControl foreach tool + var control = new ToolItemControl(tool, Command_Received); + toolItemControls.Add(control); + panel.Children.Add(control); + } + } + + /// /// Command received from sub-controls /// diff --git a/ZXBSInstaller/Controls/ToolItemControl.axaml b/ZXBSInstaller/Controls/ToolItemControl.axaml index cc46644..f8a0bab 100644 --- a/ZXBSInstaller/Controls/ToolItemControl.axaml +++ b/ZXBSInstaller/Controls/ToolItemControl.axaml @@ -3,7 +3,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:svg="using:Avalonia.Svg.Skia" - Width="360" Height="180" + Width="360" Height="170" x:Class="ZXBSInstaller.Controls.ToolItemControl" FontSize="12"> diff --git a/ZXBSInstaller/ExternalTools.json b/ZXBSInstaller/ExternalTools.json deleted file mode 100644 index 45ffa91..0000000 --- a/ZXBSInstaller/ExternalTools.json +++ /dev/null @@ -1,62 +0,0 @@ -[ - { - "Id": "zxbsinstaller", - "Enabled": true, - "Name": "ZX Basic Studio Installer", - "Author": "Duefectu", - "Description": "This program, and it is used to download, install and keep all external tools and ZX Basic Studio itself up to date.", - "SupportedOperatingSystems": [ - 1, - 2, - 3 - ], - "SiteUrl": "https://github.com/boriel-basic/ZXBasicStudio", - "LicenseType": "MIT License", - "LicenceUrl": "https://raw.githubusercontent.com/boriel-basic/ZXBasicStudio/refs/heads/master/LICENSE.txt", - "VersionsUrl": "https://github.com/boriel-basic/ZXBasicStudio/releases/", - "LocalPath": "", - "FullLocalPath": null, - "DirectUpdate": true, - "Order": 0 - }, - { - "Id": "zxbasic", - "Enabled": true, - "Name": "Boriel ZX Basic Compiler", - "Author": "Boriel", - "Description": "ZXBCompiler is a BORIEL BASIC cross compiler tool. It's a required tool.'", - "SupportedOperatingSystems": [ - 1, - 2, - 3 - ], - "SiteUrl": "https://boriel-basic.net", - "LicenseType": "GNU Affero General Public License v3.0", - "LicenceUrl": "https://raw.githubusercontent.com/boriel-basic/zxbasic/refs/heads/main/LICENSE.txt", - "VersionsUrl": "https://boriel.com/files/zxb/", - "LocalPath": "", - "FullLocalPath": "C:\\ZXNext\\zxbasic\\zxbc.exe", - "DirectUpdate": true, - "Order": 1 - }, - { - "Id": "zxbs", - "Enabled": true, - "Name": "ZX Basic Studio", - "Author": "Dr.Gusman, Boriel, Duefectu, AdolFITO, Hash6Iron and SirRickster", - "Description": "IDE (Integrated Development Environment) with code editor, Assembler, UDGs, fonts, sprites, .tap editor, debugger, emulator, etc.", - "SupportedOperatingSystems": [ - 1, - 2, - 3 - ], - "SiteUrl": "https://github.com/boriel-basic/ZXBasicStudio", - "LicenseType": "MIT License", - "LicenceUrl": "https://raw.githubusercontent.com/boriel-basic/ZXBasicStudio/refs/heads/master/LICENSE.txt", - "VersionsUrl": "https://github.com/boriel-basic/ZXBasicStudio/releases/", - "LocalPath": "", - "FullLocalPath": null, - "DirectUpdate": true, - "Order": 2 - } -] \ No newline at end of file diff --git a/ZXBSInstaller/MainWindow.axaml b/ZXBSInstaller/MainWindow.axaml index 2f9fd7e..2d7eaa8 100644 --- a/ZXBSInstaller/MainWindow.axaml +++ b/ZXBSInstaller/MainWindow.axaml @@ -2,7 +2,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" - Width="1000" Height="600" + Width="1000" Height="650" x:Class="ZXBSInstaller.MainWindow" Title="ZX Basic Studio Installer" WindowStartupLocation="CenterScreen" diff --git a/ZXBSInstaller/ZXBSInstaller.csproj b/ZXBSInstaller/ZXBSInstaller.csproj index fa2d5ea..03df070 100644 --- a/ZXBSInstaller/ZXBSInstaller.csproj +++ b/ZXBSInstaller/ZXBSInstaller.csproj @@ -15,7 +15,6 @@ - @@ -23,8 +22,23 @@ + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + @@ -37,9 +51,6 @@ PreserveNewest - - - diff --git a/ZXBStudio/Dialogs/ZXOptionsDialog.axaml.cs b/ZXBStudio/Dialogs/ZXOptionsDialog.axaml.cs index df860c5..9ab0e4a 100644 --- a/ZXBStudio/Dialogs/ZXOptionsDialog.axaml.cs +++ b/ZXBStudio/Dialogs/ZXOptionsDialog.axaml.cs @@ -94,8 +94,9 @@ private async void BtnSelectNextEmulator_Click(object? sender, Avalonia.Interact Title = "Select Next emulator path...", FileTypeFilter = new[] { - new FilePickerFileType("CSpect") { Patterns = new[] { "CSpect.exe" } }, - new FilePickerFileType("ZEsarUX") { Patterns = new[] { "zesarux.exe" } }, + new FilePickerFileType("MAME") { Patterns = new[] { "mame.exe", "mame" } }, + new FilePickerFileType("CSpect") { Patterns = new[] { "CSpect.exe", "CSpect" } }, + new FilePickerFileType("ZEsarUX") { Patterns = new[] { "zesarux.exe", "zesarux" } }, new FilePickerFileType("All files") { Patterns = new[] { "*", "*.*" } } } }); diff --git a/ZXBStudio/MainWindow.axaml.cs b/ZXBStudio/MainWindow.axaml.cs index 0859a00..21bfb82 100644 --- a/ZXBStudio/MainWindow.axaml.cs +++ b/ZXBStudio/MainWindow.axaml.cs @@ -35,6 +35,7 @@ using System.Resources; using System.Runtime.InteropServices; using System.Runtime.Intrinsics.Arm; +using System.Security.Cryptography; using System.Text; using System.Threading.Tasks; using ZXBasicStudio.BuildSystem; @@ -1500,6 +1501,10 @@ private async void BuildAndRun(object? sender, Avalonia.Interactivity.RoutedEven errorMsg = "Error executing custom emulator launcher."; } } + else if (emulatorName.ToLower() == "mame") + { + errorMsg = BuildAndRun_MAME(emulatorPath, nextDrive, settings, project); + } else if (emulatorName.ToLower() == "cspect") { if (!File.Exists(emulatorPath)) @@ -1549,7 +1554,7 @@ private async void BuildAndRun(object? sender, Avalonia.Interactivity.RoutedEven errorMsg = "Error executing emulator: " + ex.Message + ex.StackTrace; if (ex.InnerException != null) { - var ex2= ex.InnerException; + var ex2 = ex.InnerException; errorMsg += "\r\nInner Exception: " + ex.Message + ex.StackTrace; } } @@ -2507,6 +2512,126 @@ private void MnuReportBug_Click(object? sender, RoutedEventArgs e) #endregion + + #region MAME + + private string BuildAndRun_MAME(string emulatorPath, string nextDrive, ZXBuildSettings settings, ZXProjectManager project) + { + if (!File.Exists(emulatorPath)) + { + return "Emulator not found on: " + emulatorPath; + } + + var basePath =Directory.GetParent(Directory.GetParent(emulatorPath).FullName).FullName; + + // Delete /nextzxos/autoexec.1st + Hdfmonkey("rm ../nextsdimage/nextimage.img /nextzxos/autoexec.1st", basePath); + // Copy /nextzxos/autoexec.bas + if (!Hdfmonkey("put ../nextsdimage/nextimage.img ../nextsdimage/autoexec.bas /nextzxos/autoexec.bas", basePath)) + { + return "Error copying autoexec.bas to the emulator image."; + } + // Empty /zxbsdev folder + // TODO: Sync! + Hdfmonkey("rm ../nextsdimage/nextimage.img /zxbsdev", basePath); + // Create /zxbsdev + Hdfmonkey("mkdir ../nextsdimage/nextimage.img /zxbsdev", basePath); + // Copy nextdrive to /zxbsdev + Hdfmonkey($"putdir ../nextsdimage/nextimage.img \"{nextDrive}\" /zxbsdev/", basePath); + + // Launch mame + { + outLog.Writer.WriteLine("Launching MAME..."); + var parameters = $"-ui_active -nounevenstretch -aspect 2:1 -video bgfx -bgfx_screen_chains unfiltered -window -skip_gameinfo -mouse_device none -confirm_quit tbblue -hard1 ../nextsdimage/nextimage.img -plugin zxbs -debug -debugger none -console"; + var psi = new ProcessStartInfo() + { + FileName = emulatorPath, + Arguments = parameters, + WorkingDirectory = Directory.GetParent(emulatorPath).FullName, + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardOutput = true, + RedirectStandardError = true + }; + var process = new Process() + { + StartInfo = psi + }; + + outLog.Writer.WriteLine($">mame {parameters}"); + + process.OutputDataReceived += MAME_DataReceived; + process.ErrorDataReceived += MAME_ErrorReceived; + + process.Start(); + + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + + process.WaitForExit(); + + process.OutputDataReceived -= MAME_DataReceived; + process.ErrorDataReceived -= MAME_ErrorReceived; + } + return ""; + } + + private bool Hdfmonkey(string parameters, string basePath) + { + var hdfPath = Path.Combine(basePath, "hdfmonkey"); + + outLog.Writer.WriteLine($"> hdfmonkey {parameters}"); + var psi = new ProcessStartInfo() + { + FileName = Path.Combine(hdfPath, "hdfmonkey.exe"), + Arguments = parameters, + WorkingDirectory = hdfPath, + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardOutput = true, + RedirectStandardError = true + }; + var process = new Process() + { + StartInfo = psi + }; + process.Start(); + var output = process.StandardOutput.ReadToEnd(); + var error = process.StandardError.ReadToEnd(); + process.WaitForExit(); + + if (!string.IsNullOrEmpty(error)) + { + outLog.Writer.WriteLine("hdfmonkey ERROR> " + error); + } + if (!string.IsNullOrEmpty(output)) + { + outLog.Writer.WriteLine("hdfmonkey> " + error); + } + + return string.IsNullOrEmpty(error); + } + + private void MAME_ErrorReceived(object sender, DataReceivedEventArgs e) + { + if (e.Data != null) + { + outLog.Writer.WriteLine("MAME ERROR> " + e.Data.ToStringNoNull()); + } + } + + + private void MAME_DataReceived(object sender, DataReceivedEventArgs e) + { + if (e.Data != null) + { + outLog.Writer.WriteLine("MAME> " + e.Data.ToStringNoNull()); + } + } + + + #endregion + } public enum PreferredSourceType diff --git a/ZXBStudio/ZXBasicStudio.csproj b/ZXBStudio/ZXBasicStudio.csproj index 0edf91e..d2ec7a2 100644 --- a/ZXBStudio/ZXBasicStudio.csproj +++ b/ZXBStudio/ZXBasicStudio.csproj @@ -13,7 +13,7 @@ ZX Basic Studio False - 1.7.0.0 + 1.8.0.1 diff --git a/ZXBStudio/version.txt b/ZXBStudio/version.txt index 1f0cf6b..6482d6f 100644 --- a/ZXBStudio/version.txt +++ b/ZXBStudio/version.txt @@ -1 +1 @@ -1.7.0.0 \ No newline at end of file +1.8.0.1 \ No newline at end of file From acfcea338128b5cc5c0b5f6ef3cc9de13a57b3bd Mon Sep 17 00:00:00 2001 From: Juan Segura Date: Fri, 27 Feb 2026 01:47:06 +0100 Subject: [PATCH 2/3] ZXBSInstaller v1.0.1-beta1 Install MAME and complements --- ZXBSInstaller.Log/ExternalTools.json | 36 +- ZXBSInstaller.Log/Neg/ExternalTool.cs | 10 +- .../Neg/ExternalTools_Version.cs | 4 +- ZXBSInstaller.Log/ServiceLayer.cs | 525 +++++++++++++++++- ZXBSInstaller/Controls/MainControl.axaml.cs | 48 +- .../Controls/ToolItemControl.axaml.cs | 36 +- ZXBSInstaller/ZXBSInstaller.csproj | 2 +- ZXBSInstaller/version.txt | 2 +- 8 files changed, 613 insertions(+), 50 deletions(-) diff --git a/ZXBSInstaller.Log/ExternalTools.json b/ZXBSInstaller.Log/ExternalTools.json index edd5edd..ab6b2cd 100644 --- a/ZXBSInstaller.Log/ExternalTools.json +++ b/ZXBSInstaller.Log/ExternalTools.json @@ -15,6 +15,8 @@ "LicenceUrl": "https://raw.githubusercontent.com/boriel-basic/ZXBasicStudio/refs/heads/master/LICENSE.txt", "VersionsUrl": "https://github.com/boriel-basic/ZXBasicStudio/releases/", "LocalPath": "", + "Unzip": true, + "CreateVerFile": false, "FullLocalPath": null, "DirectUpdate": true, "Group": "ZX Basic Studio", @@ -36,6 +38,8 @@ "LicenceUrl": "https://raw.githubusercontent.com/boriel-basic/zxbasic/refs/heads/main/LICENSE.txt", "VersionsUrl": "https://boriel.com/files/zxb/", "LocalPath": "", + "Unzip": true, + "CreateVerFile": false, "FullLocalPath": "C:\\ZXNext\\zxbasic\\zxbc.exe", "DirectUpdate": true, "Group": "ZX Basic Studio", @@ -57,6 +61,8 @@ "LicenceUrl": "https://raw.githubusercontent.com/boriel-basic/ZXBasicStudio/refs/heads/master/LICENSE.txt", "VersionsUrl": "https://github.com/boriel-basic/ZXBasicStudio/releases/", "LocalPath": "", + "Unzip": true, + "CreateVerFile": false, "FullLocalPath": null, "DirectUpdate": true, "Group": "ZX Basic Studio", @@ -73,11 +79,13 @@ 2, 3 ], - "SiteUrl": "https://www.mamedev.org/", + "SiteUrl": "https://github.com/mamedev/mame", "LicenseType": "GPL-2.0 / BSD-3-Clause License", - "LicenceUrl": "https://www.mamedev.org/", - "VersionsUrl": "", + "LicenceUrl": "https://github.com/mamedev/mame?tab=License-1-ov-file", + "VersionsUrl": "https://github.com/mamedev/mame/releases", "LocalPath": "", + "Unzip": true, + "CreateVerFile": false, "FullLocalPath": null, "DirectUpdate": true, "Group": "ZX Spectrum Next", @@ -95,10 +103,12 @@ 3 ], "SiteUrl": "https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA", - "LicenseType": "GPL-3.0", + "LicenseType": "GNU GPLv3", "LicenceUrl": "https://gitlab.com/SpectrumNext/ZX_Spectrum_Next_FPGA/-/raw/master/LICENSE?ref_type=heads", "VersionsUrl": "", - "LocalPath": "", + "LocalPath": "mame\\roms\\tbblue.zip", + "Unzip": false, + "CreateVerFile": true, "FullLocalPath": null, "DirectUpdate": true, "Group": "ZX Spectrum Next", @@ -118,8 +128,10 @@ "SiteUrl": "https://github.com/boriel-basic/ZXBasicStudio", "LicenseType": "MIT License", "LicenceUrl": "https://raw.githubusercontent.com/boriel-basic/ZXBasicStudio/refs/heads/master/LICENSE.txt", - "VersionsUrl": "", - "LocalPath": "", + "VersionsUrl": "https://www.duefectucorp.com/descargas/zxbsmame/Versions.txt", + "LocalPath": "mame\\plugins\\zxbs", + "Unzip": true, + "CreateVerFile": false, "FullLocalPath": null, "DirectUpdate": true, "Group": "ZX Spectrum Next", @@ -136,11 +148,13 @@ 2, 3 ], - "SiteUrl": "https://github.com/boriel-basic/ZXBasicStudio", + "SiteUrl": "https://zxnext.uk/hosted/", "LicenseType": "MIT License", - "LicenceUrl": "https://raw.githubusercontent.com/boriel-basic/ZXBasicStudio/refs/heads/master/LICENSE.txt", + "LicenceUrl": "https://zxnext.uk/hosted/", "VersionsUrl": "", "LocalPath": "", + "Unzip": true, + "CreateVerFile": false, "FullLocalPath": null, "DirectUpdate": true, "Group": "ZX Spectrum Next", @@ -160,8 +174,10 @@ "SiteUrl": "https://www.specnext.com/forum/viewtopic.php?t=2604", "LicenseType": "GPL-3.0", "LicenceUrl": "https://codeberg.org/chwe/hdfmonkey/src/branch/dev-v05x", - "VersionsUrl": "https://zx.duefectucorp.com/tools/hdfmonkey/versions.txt", + "VersionsUrl": "https://www.duefectucorp.com/descargas/hdfmonkey/Versions.txt", "LocalPath": "", + "Unzip": true, + "CreateVerFile": false, "FullLocalPath": null, "DirectUpdate": true, "Group": "ZX Spectrum Next", diff --git a/ZXBSInstaller.Log/Neg/ExternalTool.cs b/ZXBSInstaller.Log/Neg/ExternalTool.cs index b5efb33..37fc327 100644 --- a/ZXBSInstaller.Log/Neg/ExternalTool.cs +++ b/ZXBSInstaller.Log/Neg/ExternalTool.cs @@ -53,7 +53,7 @@ public class ExternalTool /// public string VersionsUrl { get; set; } /// - /// Local path where the tool will be installed without file name + /// If exists Local path where the tool will be installed without file name /// public string LocalPath { get; set; } /// @@ -65,6 +65,14 @@ public class ExternalTool /// public bool DirectUpdate { get; set; } /// + /// If true, tool will be downloaded as a zip file and unzipped in the local path, otherwise it will be downloaded as is + /// + public bool Unzip { get; set; } + /// + /// True, creates a version.txt file in the installation folder + /// + public bool CreateVerFile { get; set; } + /// /// Order in the list /// public int Order { get; set; } diff --git a/ZXBSInstaller.Log/Neg/ExternalTools_Version.cs b/ZXBSInstaller.Log/Neg/ExternalTools_Version.cs index 8041254..eb0c2f7 100644 --- a/ZXBSInstaller.Log/Neg/ExternalTools_Version.cs +++ b/ZXBSInstaller.Log/Neg/ExternalTools_Version.cs @@ -12,11 +12,11 @@ public class ExternalTools_Version /// /// Numer of the Beta version, 0 if not a beta /// - public int BetaNumber { get; set; } + public decimal BetaNumber { get; set; } /// /// Internal version number to order versions /// - public int VersionNumber { get; set; } + public decimal VersionNumber { get; set; } /// /// Download url for this version /// diff --git a/ZXBSInstaller.Log/ServiceLayer.cs b/ZXBSInstaller.Log/ServiceLayer.cs index 668272a..5ad103d 100644 --- a/ZXBSInstaller.Log/ServiceLayer.cs +++ b/ZXBSInstaller.Log/ServiceLayer.cs @@ -5,6 +5,7 @@ using System.IO; using System.IO.Compression; using System.Reflection; +using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; using System.Runtime; using System.Runtime.InteropServices; @@ -268,6 +269,30 @@ private static int ToInteger(object value) } + /// + /// Convert an objet to his decimnal value or 0 if it can't do it + /// + /// Value to convert + /// Numeric value or 0 if can't do it + private static decimal ToDecimal(object value) + { + try + { + if (value == null) + { + return 0; + } + decimal v = 0; + if (decimal.TryParse(value.ToString(), out v)) + { + return v; + } + } + catch { } + return 0; + } + + /// /// Open an url in the default browser. It is used to open the site and license urls of the external tools. It is called from the service layer when the user clicks on the site or license buttons of an external tool. /// @@ -363,7 +388,7 @@ public static ExternalTool[] GetExternalTools() tool.Versions = new ExternalTools_Version[0]; } // Get installed version - tool.InstalledVersion = GetToolVersion(tool.Id); + tool.InstalledVersion = GetToolVersion(tool); // Set latest version if (GeneralConfig.OnlyStableVersions) @@ -379,7 +404,8 @@ public static ExternalTool[] GetExternalTools() else { tool.LatestVersion = tool.Versions. - Where(d => d.OperatingSystem == CurrentOperatingSystem && + Where(d => (d.OperatingSystem == OperatingSystems.All || + d.OperatingSystem == CurrentOperatingSystem) && d.BetaNumber == 0). OrderByDescending(d => d.VersionNumber). FirstOrDefault(); @@ -397,7 +423,8 @@ public static ExternalTool[] GetExternalTools() else { tool.LatestVersion = tool.Versions. - Where(d => d.OperatingSystem == CurrentOperatingSystem). + Where(d => (d.OperatingSystem == OperatingSystems.All || + d.OperatingSystem == CurrentOperatingSystem)). OrderByDescending(d => d.VersionNumber). FirstOrDefault(); } @@ -425,7 +452,14 @@ public static ExternalTool[] GetExternalTools() } } // Set tool local path - tool.LocalPath = Path.Combine(GeneralConfig.BasePath, tool.Id); + if (string.IsNullOrEmpty(tool.LocalPath)) + { + tool.LocalPath = Path.Combine(GeneralConfig.BasePath, tool.Id); + } + else + { + tool.LocalPath = Path.Combine(GeneralConfig.BasePath, tool.LocalPath); + } } // order tools by order property @@ -451,12 +485,12 @@ public static ExternalTool[] GetExternalTools() /// /// Version string /// Item1 = version number, Item2 = beta number - private static (int, int) GetVersionNumber(string versionString) + private static (decimal, decimal) GetVersionNumber(string versionString) { try { - int number = 0; - int betaNumber = 0; + decimal number = 0; + decimal betaNumber = 0; string version = versionString; // If it is a beta version, replace the -beta with . and add the beta number as the fourth value. if (version.Contains("-beta")) @@ -484,7 +518,7 @@ private static (int, int) GetVersionNumber(string versionString) number *= 1000; if (n < versionParts.Length) { - int v = ToInteger(versionParts[n]); + decimal v = ToDecimal(versionParts[n]); if (n == 3) { betaNumber = v; @@ -542,6 +576,19 @@ private static ExternalTools_Version[] GetAvailableToolVersion(ExternalTool tool case "zxbsinstaller": return GetBorielZXBSVersions(tool.VersionsUrl, true); + case "mame": + return GetMAMEVersions(); + + case "tbbluemame": + return GetTBBLueMAMEVersions(); + + case "zxbsmame": + case "hdfmonkey": + return GetDuefectuVersions(tool.VersionsUrl); + + case "nextsdimage": + return GetNextSDImageVersions(); + default: return null; } @@ -848,10 +895,15 @@ private static string[] GetAllLinks(string url, string pattern) /// /// Tool id /// Installed version - public static ExternalTools_Version GetToolVersion(string id) + public static ExternalTools_Version GetToolVersion(ExternalTool tool) { try { + if (tool == null) + { + return null; + } + var id = tool.Id; var dir = Path.Combine(GeneralConfig.BasePath, id); switch (id) @@ -862,11 +914,20 @@ public static ExternalTools_Version GetToolVersion(string id) return GetZXBSVersion(dir); case "zxbsinstaller": return GetZXBSInstallerVersion(dir); + case "mame": + return GetMAMEVersion(dir); + case "tbbluemame": + return GetTBBLueMAMEVersion(Path.Combine(GeneralConfig.BasePath, tool.LocalPath)); + case "zxbsmame": + case "hdfmonkey": + return GetDuefectuVersion(tool); + case "nextsdimage": + return GetNextSDImageVersion(tool); } } catch (Exception ex) { - ShowMessage($"Error retrieving local version for {id}.\r\n{ex.Message}{ex.StackTrace}"); + ShowMessage($"Error retrieving local version for {tool.Id}.\r\n{ex.Message}{ex.StackTrace}"); } return null; } @@ -997,8 +1058,8 @@ private static ExternalTools_Version GetVersionFromParameter(string fileName) } var version = output.Replace("zxbc.py ", "").Replace("\n", "").Replace("\r", "").Replace("v", ""); var v = GetVersionNumber(version); - int number = v.Item1; - int beta = v.Item2; + decimal number = v.Item1; + decimal beta = v.Item2; return new ExternalTools_Version() { @@ -1128,13 +1189,21 @@ public static void DownloadAndInstallTool(ExternalTool tool, ExternalTools_Versi // Get installation path step = "Creating installation path"; - var installationPath = Path.Combine(GeneralConfig.BasePath, tool.Id); + string installationPath = ""; + if (string.IsNullOrEmpty(tool.LocalPath)) + { + installationPath = Path.Combine(GeneralConfig.BasePath, tool.Id); + } + else + { + installationPath = Path.Combine(GeneralConfig.BasePath, tool.LocalPath); + } // Patch for Boriel Basic if (tool.Id == "zxbasic") { installationPath = Directory.GetParent(installationPath).FullName; } - if (!Directory.Exists(installationPath)) + if (tool.Unzip && !Directory.Exists(installationPath)) { step = $"Creating application path [{installationPath}]"; Directory.CreateDirectory(installationPath); @@ -1163,9 +1232,28 @@ public static void DownloadAndInstallTool(ExternalTool tool, ExternalTools_Versi } // Extract file - step = $"Installing {tool.Name}"; - UpdateStatus($"Installing {tool.Name} version {version.Version}...", 50); - ExtractFile(tempFile, installationPath); + if (tool.Unzip) + { + step = $"Installing {tool.Name}"; + UpdateStatus($"Installing {tool.Name} version {version.Version}...", 50); + ExtractFile(tempFile, installationPath); + } + else + { + var dest = Path.Combine(GeneralConfig.BasePath, tool.LocalPath); + if (File.Exists(dest)) + { + File.Delete(dest); + } + File.Move(tempFile, installationPath); + } + + // Create Version.txt file + if (tool.CreateVerFile) + { + var fileName = Path.Combine(GeneralConfig.BasePath, $"{tool.LocalPath}.ver"); + File.WriteAllText(fileName, version.Version); + } // Set ZXBS Options step = "Set ZX Basic Studio options"; @@ -1177,6 +1265,65 @@ public static void DownloadAndInstallTool(ExternalTool tool, ExternalTools_Versi UpdateStatus("Deleting temp files...", 90); File.Delete(tempFile); + // hdfmonkey patch + if (tool.Id == "hdfmonkey") + { + string dest = ""; + string source = ""; + string basePath = Path.Combine(GeneralConfig.BasePath, tool.Id); + switch (CurrentOperatingSystem) + { + case OperatingSystems.Windows: + dest = Path.Combine(basePath, "hdfmonkey.exe"); + source = Path.Combine(basePath, "windows-64", "hdfmonkey.exe"); + break; + case OperatingSystems.Linux: + dest = Path.Combine(basePath, "hdfmonkey"); + source = Path.Combine(basePath, "linux-musl", "hdfmonkey"); + break; + case OperatingSystems.MacOS_x64: + dest = Path.Combine(basePath, "hdfmonkey"); + source = Path.Combine(basePath, "macos-intel", "hdfmonkey"); + break; + case OperatingSystems.MacOS_arm64: + dest = Path.Combine(basePath, "hdfmonkey"); + source = Path.Combine(basePath, "macos-mn", "hdfmonkey"); + break; + + } + if (File.Exists(dest)) + { + File.Delete(dest); + } + File.Move(source, dest); + } + + // Next SD Image patch + if(tool.Id == "nextsdimage") + { + string dir = Path.Combine(GeneralConfig.BasePath, tool.Id,"2gb"); + string source = Path.Combine(dir, "cspect-next-2gb.img"); + string dest=Path.Combine(GeneralConfig.BasePath, tool.Id, "cspect-next-2gb.img"); + if (File.Exists(dest)) + { + File.Delete(dest); + } + File.Move(source, dest); + + source= Path.Combine(dir, "version.txt"); + dest= Path.Combine(GeneralConfig.BasePath, tool.Id, "version.txt"); + if (File.Exists(dest)) + { + File.Delete(dest); + } + File.Move(source, dest); + try + { + Directory.Delete(dir); + } + catch { } + } + UpdateStatus($"{tool.Name} version {version.Version} installed successfully.", 100); } catch (Exception ex) @@ -1318,10 +1465,37 @@ private static void ExtractFile(string archive, string destination) // Extract .zip file System.IO.Compression.ZipFile.ExtractToDirectory(archive, destination, true); } + else if (archive.ToLower().EndsWith(".exe")) + { + var psi = new ProcessStartInfo + { + FileName = archive, + Arguments = $"-o\"{destination}\" -y", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + }; + using var process = Process.Start(psi)!; + + string stdout = process.StandardOutput.ReadToEnd(); + string stderr = process.StandardError.ReadToEnd(); + + process.WaitForExit(); + + if (process.ExitCode != 0) + { + ShowMessage($"Error unpacking file {archive}\r\n{stderr}"); + return; + } + } else if (CurrentOperatingSystem != OperatingSystems.Windows) { // Extract .tar file on Linux and Mac - Directory.CreateDirectory(destination); + if (!Directory.Exists(destination)) + { + Directory.CreateDirectory(destination); + } var psi = new ProcessStartInfo { @@ -1459,5 +1633,320 @@ public static bool RunZXBasicStudio() return false; } } + + + #region MAME + + private static ExternalTools_Version[] GetMAMEVersions() + { + var versions = new List(); + + // Windows + versions.Add(new ExternalTools_Version() + { + BetaNumber = 0, + DownloadUrl = "https://github.com/mamedev/mame/releases/download/mame0285/mame0285b_x64.exe", + OperatingSystem = OperatingSystems.Windows, + Version = "0.285", + VersionNumber = 285 + }); + // Mac_x86 + versions.Add(new ExternalTools_Version() + { + BetaNumber = 0, + DownloadUrl = "https://sdlmame.lngn.net/stable/mame0285-x86.zip", + OperatingSystem = OperatingSystems.MacOS_x64, + Version = "0.285", + VersionNumber = 285 + }); + // Mac_arm64 + versions.Add(new ExternalTools_Version() + { + BetaNumber = 0, + DownloadUrl = "https://sdlmame.lngn.net/stable/mame0285-arm64.zip", + OperatingSystem = OperatingSystems.MacOS_arm64, + Version = "0.285", + VersionNumber = 285 + }); + // Mac_arm64 + versions.Add(new ExternalTools_Version() + { + BetaNumber = 0, + DownloadUrl = "bash -c \"sudo apt install -y mame\"", + OperatingSystem = OperatingSystems.Linux, + Version = "0.285", + VersionNumber = 285 + }); + return versions.ToArray(); + } + + + private static ExternalTools_Version GetMAMEVersion(string exePath) + { + try + { + // Windows fileName + var fileName = Path.Combine(exePath, "mame.exe"); + if (!File.Exists(fileName)) + { + // If not exist, try Linux/Mac fileName + fileName = Path.Combine(exePath, "mame"); + } + if (!File.Exists(fileName)) + { + // Not found + return null; + } + + // Retrieve version executing with -version parameter + ProcessStartInfo psi = new ProcessStartInfo + { + FileName = fileName, + Arguments = "-version", + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true + }; + using Process process = new Process { StartInfo = psi }; + process.Start(); + string output = process.StandardOutput.ReadToEnd(); + string error = process.StandardError.ReadToEnd(); + process.WaitForExit(); + + if (string.IsNullOrEmpty(output)) + { + return null; + } + var parts = output.Split(" "); + var version = parts[0]; + int number = ToInteger(version.Replace("0.", "")); + int beta = 0; + + return new ExternalTools_Version() + { + DownloadUrl = "", + BetaNumber = beta, + OperatingSystem = OperatingSystems.All, + Version = version, + VersionNumber = number + }; + } + catch (Exception ex) + { + ShowMessage($"Error getting local MAME version.\r\n{ex.Message}{ex.StackTrace}"); + return null; + } + } + + #endregion + + + #region Boot ROM Next - tbbluemame + + private static ExternalTools_Version[] GetTBBLueMAMEVersions() + { + var versions = new List(); + + // All versions + var v = new ExternalTools_Version() + { + DownloadUrl = "https://github.com/Threetwosevensixseven/NexCreator/raw/master/bootroms/tbblue.zip", + OperatingSystem = OperatingSystems.All, + Version = "3.02.03", + }; + var vv = GetVersionNumber(v.Version); + v.VersionNumber = vv.Item1; + v.BetaNumber = vv.Item2; + versions.Add(v); + return versions.ToArray(); + } + + + private static ExternalTools_Version GetTBBLueMAMEVersion(string exePath) + { + try + { + // Windows fileName + var fileName = exePath + ".ver"; + if (!File.Exists(fileName)) + { + return null; + } + var version = File.ReadAllText(fileName).Trim(); + // All versions + var v = new ExternalTools_Version() + { + DownloadUrl = "https://github.com/Threetwosevensixseven/NexCreator/raw/master/bootroms/tbblue.zip", + OperatingSystem = OperatingSystems.All, + Version = "3.02.03", + }; + var vv = GetVersionNumber(v.Version); + v.VersionNumber = vv.Item1; + v.BetaNumber = vv.Item2; + return v; + } + catch (Exception ex) + { + ShowMessage($"Error getting local Next boot ROM version.\r\n{ex.Message}{ex.StackTrace}"); + return null; + } + } + + #endregion + + + #region Version.txt based system + + private static ExternalTools_Version[] GetDuefectuVersions(string url) + { + try + { + var versions = new List(); + + // Download versions file + string data = ""; + using (HttpClient client = new HttpClient()) + { + client.Timeout = TimeSpan.FromSeconds(20); + data = client.GetStringAsync(url).GetAwaiter().GetResult(); + } + if (string.IsNullOrEmpty(data)) + { + return null; + } + + var lines = data.Split("\r\n"); + foreach (var line in lines) + { + var parts = line.Split(';'); + if (parts.Length == 2) + { + var v = new ExternalTools_Version() + { + DownloadUrl = parts[1], + OperatingSystem = OperatingSystems.All, + Version = parts[0], + }; + var vv = GetVersionNumber(v.Version); + v.VersionNumber = vv.Item1; + v.BetaNumber = vv.Item2; + versions.Add(v); + } + } + + return versions.ToArray(); + } + catch (Exception ex) + { + return null; + } + } + + + private static ExternalTools_Version GetDuefectuVersion(ExternalTool tool) + { + try + { + string exePath = ""; + if (string.IsNullOrEmpty(tool.LocalPath)) + { + exePath = Path.Combine(GeneralConfig.BasePath, tool.Id); + } + else + { + exePath = Path.Combine(GeneralConfig.BasePath, tool.LocalPath); + } + var fileName = Path.Combine(exePath, "Version.txt"); + if (!File.Exists(fileName)) + { + return null; + } + var versiontxt = File.ReadAllText(fileName).Trim(); + if (string.IsNullOrEmpty(versiontxt)) + { + return null; + } + var v = new ExternalTools_Version() + { + DownloadUrl = "", + OperatingSystem = OperatingSystems.All, + Version = versiontxt, + }; + var vv = GetVersionNumber(v.Version); + v.VersionNumber = vv.Item1; + v.BetaNumber = vv.Item2; + return v; + } + catch (Exception ex) + { + return null; + } + } + + #endregion + + + #region Next SD Image + + private static ExternalTools_Version[] GetNextSDImageVersions() + { + try + { + var versions = new List(); + + var v = new ExternalTools_Version() + { + DownloadUrl = "https://zxnext.uk/hosted/index_files/hdfimages/cspect-next-2gb.zip", + OperatingSystem = OperatingSystems.All, + Version = "2026-02-27", + VersionNumber = 20260227, + BetaNumber = 0 + }; + versions.Add(v); + + return versions.ToArray(); + } + catch (Exception ex) + { + return null; + } + } + + + private static ExternalTools_Version GetNextSDImageVersion(ExternalTool tool) + { + try + { + string fileName = Path.Combine(GeneralConfig.BasePath,tool.Id,"version.txt"); + if (!File.Exists(fileName)) + { + return null; + } + var versiontxt = File.ReadAllText(fileName).Trim(); + if (string.IsNullOrEmpty(versiontxt)) + { + return null; + } + var parts = versiontxt.Split(" "); + + var v = new ExternalTools_Version() + { + DownloadUrl = "", + OperatingSystem = OperatingSystems.All, + Version = parts[0], + BetaNumber = 0, + VersionNumber = ToDecimal(parts[0].Replace("-","")) + }; + return v; + } + catch (Exception ex) + { + return null; + } + } + + #endregion + } } \ No newline at end of file diff --git a/ZXBSInstaller/Controls/MainControl.axaml.cs b/ZXBSInstaller/Controls/MainControl.axaml.cs index 72b95bf..e39225c 100644 --- a/ZXBSInstaller/Controls/MainControl.axaml.cs +++ b/ZXBSInstaller/Controls/MainControl.axaml.cs @@ -33,6 +33,8 @@ public partial class MainControl : UserControl /// private static Brush Yellow = new SolidColorBrush(Colors.Yellow); + private CheckBox chkNextGroup = null; + /// /// Main constructor @@ -164,14 +166,19 @@ private void ShowData() { var groupTools = tools.Where(t => t.Group == "ZX Spectrum Next"); { - mainTools.Children.Add(new CheckBox() + if (chkNextGroup == null) { - Content = "ZX Spectrum Next", - FontSize = 16, - IsChecked = true, - Margin = new Thickness(10, 10, 0, 0), - Foreground = Yellow - }); + chkNextGroup = new CheckBox() + { + Content = "ZX Spectrum Next", + FontSize = 16, + IsChecked = true, + Margin = new Thickness(10, 10, 0, 0), + Foreground = Yellow + }; + chkNextGroup.IsCheckedChanged += ZXNextGropu_Changed; + } + mainTools.Children.Add(chkNextGroup); mainTools.Children.Add(new Separator() { Margin = new Thickness(0), @@ -189,18 +196,33 @@ private void ShowData() } - private void ShowData_AddTools(WrapPanel panel, IEnumerable tools) + private void ZXNextGropu_Changed(object? sender, RoutedEventArgs e) { - foreach (var tool in tools) + foreach(var ctrl in toolItemControls) { - // Create on ToolItemControl foreach tool - var control = new ToolItemControl(tool, Command_Received); - toolItemControls.Add(control); - panel.Children.Add(control); + if (ctrl.ExternalTool.Group == "ZX Spectrum Next") + { + ctrl.IsSelected = chkNextGroup.IsChecked == true; + } } } + private void ShowData_AddTools(WrapPanel panel, IEnumerable tools) + { + Dispatcher.UIThread.Post(() => + { + foreach (var tool in tools) + { + // Create on ToolItemControl foreach tool + var control = new ToolItemControl(tool, Command_Received); + toolItemControls.Add(control); + panel.Children.Add(control); + } + }); + } + + /// /// Command received from sub-controls /// diff --git a/ZXBSInstaller/Controls/ToolItemControl.axaml.cs b/ZXBSInstaller/Controls/ToolItemControl.axaml.cs index 3fb33b0..fbc9afc 100644 --- a/ZXBSInstaller/Controls/ToolItemControl.axaml.cs +++ b/ZXBSInstaller/Controls/ToolItemControl.axaml.cs @@ -2,6 +2,7 @@ using Avalonia.Controls; using Avalonia.Markup.Xaml; using Avalonia.Media; +using Avalonia.Threading; using System; using ZXBSInstaller.Log; using ZXBSInstaller.Log.Neg; @@ -21,7 +22,20 @@ public partial class ToolItemControl : UserControl /// /// Tool selected for installation? /// - public bool IsSelected = false; + public bool IsSelected + { + get + { + return _IsSelected; + } + set + { + _IsSelected = value; + SetSelected(value); + } + } + + private bool _IsSelected = false; // Colors public static SolidColorBrush colorRed = new SolidColorBrush(Colors.Red); @@ -53,6 +67,7 @@ public ToolItemControl(ExternalTool tool, Action callBackCommand txtPath.Text = "Path: " + tool.LocalPath; txtLicense.Text = "Licence: " + tool.LicenseType; txtAuthor.Text = "Author(s): " + tool.Author; + // Set chkSelect status IsSelected = tool.UpdateNeeded; tool.IsSelected = IsSelected; @@ -96,9 +111,7 @@ public ToolItemControl(ExternalTool tool, Action callBackCommand /// private void chkSelect_IsCheckedChanged(object? sender, Avalonia.Interactivity.RoutedEventArgs e) { - IsSelected = chkSelect.IsChecked == true; - ExternalTool.IsSelected = IsSelected; - Command(ExternalTool.Id, "CHECKED"); + SetSelected(chkSelect.IsChecked == true); } @@ -116,4 +129,19 @@ private void btnViewSite_Click(object? sender, Avalonia.Interactivity.RoutedEven { ServiceLayer.OpenUrlInBrowser(ExternalTool.SiteUrl); } + + + private void SetSelected(bool selected) + { + Dispatcher.UIThread.Post(() => + { + _IsSelected = selected; + ExternalTool.IsSelected = _IsSelected; + if (chkSelect.IsChecked != _IsSelected) + { + chkSelect.IsChecked = _IsSelected; + } + Command(ExternalTool.Id, "CHECKED"); + }); + } } \ No newline at end of file diff --git a/ZXBSInstaller/ZXBSInstaller.csproj b/ZXBSInstaller/ZXBSInstaller.csproj index 03df070..e2aff0a 100644 --- a/ZXBSInstaller/ZXBSInstaller.csproj +++ b/ZXBSInstaller/ZXBSInstaller.csproj @@ -6,7 +6,7 @@ app.manifest true zxbs.ico - 1.0.0.0 + 1.0.1.1 diff --git a/ZXBSInstaller/version.txt b/ZXBSInstaller/version.txt index bd2666a..86516d0 100644 --- a/ZXBSInstaller/version.txt +++ b/ZXBSInstaller/version.txt @@ -1 +1 @@ -1.0.0.0 \ No newline at end of file +1.0.1.1 \ No newline at end of file From 84b7ec3f679b55d4f87914ea9b1d6f942c8aeb23 Mon Sep 17 00:00:00 2001 From: Juan Segura Date: Fri, 27 Feb 2026 14:52:28 +0100 Subject: [PATCH 3/3] ZXBS: - Added txt2bas by Yoruguaman - Laundh with custom autoexec.bas file --- README.md | 2 +- ZXBStudio/Common/Txt2Bas/BasConverter.cs | 254 +++++++++++++++++++ ZXBStudio/Common/Txt2Bas/Plus3Dos.cs | 72 ++++++ ZXBStudio/Common/Txt2Bas/SinclairNumber.cs | 44 ++++ ZXBStudio/Common/Txt2Bas/TokenMap.cs | 65 +++++ ZXBStudio/Common/Txt2Bas/Txt2BasConverter.cs | 41 +++ ZXBStudio/Dialogs/ZXAboutDialog.axaml | 2 +- ZXBStudio/MainWindow.axaml.cs | 25 +- 8 files changed, 497 insertions(+), 8 deletions(-) create mode 100644 ZXBStudio/Common/Txt2Bas/BasConverter.cs create mode 100644 ZXBStudio/Common/Txt2Bas/Plus3Dos.cs create mode 100644 ZXBStudio/Common/Txt2Bas/SinclairNumber.cs create mode 100644 ZXBStudio/Common/Txt2Bas/TokenMap.cs create mode 100644 ZXBStudio/Common/Txt2Bas/Txt2BasConverter.cs diff --git a/README.md b/README.md index b1f2a79..acdcbe1 100644 --- a/README.md +++ b/README.md @@ -19,11 +19,11 @@ Have fun! - AdolFITO - HashIron - SirRickster + - Yoruguaman - Testers: - AbenZaX - Pedro Tomás (Pere) - Jose Daniel Fernandez Santos (Fenix) - - Yoruguaman ## Credits - Icons from [SVG REPO](https://www.svgrepo.com/): diff --git a/ZXBStudio/Common/Txt2Bas/BasConverter.cs b/ZXBStudio/Common/Txt2Bas/BasConverter.cs new file mode 100644 index 0000000..c35540a --- /dev/null +++ b/ZXBStudio/Common/Txt2Bas/BasConverter.cs @@ -0,0 +1,254 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace ZXBasicStudio.Common.Txt2Bas +{ + /// + /// Converts plain text into tokenized Spectrum BASIC binary format. + /// Based on Yoruguaman work: https://github.com/Ultrahead/SpeccyNextTools + /// + internal class BasConverter + { + private readonly TokenMap _tokenMap; + private readonly List _sortedKeys; + + /// + /// The Auto-start line number. + /// Defaults to 32768 (No Auto-start). + /// Set only via the #autostart directive in the source file. + /// + public int AutoStartLine { get; private set; } = 32768; + + /// + /// Initializes member variable fields of the class. + /// + public BasConverter() + { + // 1. Initialize the TokenMap dictionary. + // 2. Create a list of keys sorted by Length Descending. + // (This ensures greedy matching: e.g., "DEFPROC" is matched before "DEF"). + + _tokenMap = new TokenMap(); + _sortedKeys = _tokenMap.Map.Keys + .OrderByDescending(k => k.Length) + .ToList(); + } + + /// + /// Reads a text file and converts it to a byte array of tokenized BASIC. + /// + /// Text to convert + /// Byte array representing the BASIC program. + public byte[] ConvertFile(string textData) + { + // 1. Read all lines from the source text file. + // 2. Initialize state variables (auto-line counter, output buffer). + // 3. Iterate through each line: + // a. Skip whitespace-only lines (source code formatting). + // b. Process directive (#autostart) then skip the line. + // c. Skip all other lines starting with # (source code comments). + // d. Parse explicit or implicit line numbers and tokenize content. + // 4. Return the aggregated binary data. + + string[] lines = textData.Split(new[] { "\r\n", "\n" }, StringSplitOptions.None); + var output = new List(); + + int currentLineNum = 10; + + foreach (string line in lines) + { + string text = line.Trim(); + + // 1. Skip Empty Lines completely (do not generate a BASIC line) + if (string.IsNullOrWhiteSpace(text)) continue; + + // 2. Handle Lines starting with # + if (text.StartsWith("#")) + { + // Check for directives + if (text.StartsWith("#autostart", StringComparison.OrdinalIgnoreCase)) + { + var parts = text.Split([' '], StringSplitOptions.RemoveEmptyEntries); + if (parts.Length > 1 && int.TryParse(parts[1], out int autoStartVal)) + { + AutoStartLine = autoStartVal; + } + } + + // Whether it was a directive or a comment, skip it in the output. + continue; + } + + // 3. Handle Standard Lines + int lineNum = currentLineNum; + string restOfLine = text; + + Match match = Regex.Match(text, @"^(\d+)\s+(.*)"); + + if (match.Success) + { + lineNum = int.Parse(match.Groups[1].Value); + restOfLine = match.Groups[2].Value; + currentLineNum = lineNum + 10; + } + else + { + currentLineNum += 10; + } + + byte[] lineBytes = ParseLine(lineNum, restOfLine); + output.AddRange(lineBytes); + } + + return output.ToArray(); + } + + /// + /// Parses a single line of text into binary line format. + /// Structure: [LineNum(BE)] [Length(LE)] [Data...] [0x0D] + /// + /// The line number. + /// The text content of the line. + /// A byte array representing the binary line. + private byte[] ParseLine(int lineNum, string text) + { + // 1. Iterate through the text character by character. + // 2. Detect and process String Literals (preserve exactly). + // 3. Detect and process Numbers (convert to ASCII + 5-byte hidden Sinclair format). + // 4. Detect and process SPECIAL COMMENT (';' after colon or at start). + // 5. Detect and process Keywords (Greedy Match against TokenMap): + // a. If REM found, consume the rest of the line as a comment. + // b. If other keyword found, strip immediately following whitespace. + // 6. Fallback: Add character as literal ASCII. + // 7. Append End-of-Line marker (0x0D). + // 8. Prepend the Line Header (Line Number + Length) and return the byte array. + + List lineData = new List(); + + for (int i = 0; i < text.Length; i++) + { + // String Literals + if (text[i] == '"') + { + int endQuote = text.IndexOf('"', i + 1); + if (endQuote == -1) endQuote = text.Length; + + string literal = text.Substring(i, endQuote - i + 1); + lineData.AddRange(Encoding.ASCII.GetBytes(literal)); + i = endQuote; + continue; + } + + // Numbers + if (char.IsDigit(text[i]) || (text[i] == '.' && i + 1 < text.Length && char.IsDigit(text[i + 1]))) + { + string numStr = ""; + int j = i; + while (j < text.Length && (char.IsDigit(text[j]) || text[j] == '.')) + { + numStr += text[j]; + j++; + } + + if (double.TryParse(numStr, out double val)) + { + lineData.AddRange(Encoding.ASCII.GetBytes(numStr)); + lineData.Add(0x0E); // Hidden Marker + lineData.AddRange(SinclairNumber.Pack(val)); + i = j - 1; + continue; + } + } + + // COMMENT HANDLING: Strict check for ';comment' idiom + // Trigger: Semicolon at start of line OR Semicolon immediately preceded by Colon + if (text[i] == ';') + { + bool isComment = false; + + // Look backwards skipping whitespace to find the context + int back = i - 1; + while (back >= 0 && text[back] == ' ') back--; + + if (back < 0) isComment = true; // Start of line + else if (text[back] == ':') isComment = true; // Preceded by colon + + if (isComment) + { + // Consume the rest of the line as literal text (do not tokenize) + string comment = text.Substring(i); + lineData.AddRange(Encoding.ASCII.GetBytes(comment)); + i = text.Length; + continue; + } + } + + // Keywords + bool matched = false; + foreach (string k in _sortedKeys) + { + if (i + k.Length > text.Length) continue; + + if (string.Compare(text.Substring(i, k.Length), k, StringComparison.OrdinalIgnoreCase) != 0) + continue; + + bool isAlphaToken = char.IsLetter(k[0]); + bool prevCharValid = (i == 0) || !char.IsLetter(text[i - 1]); + bool nextCharValid = (i + k.Length >= text.Length) || !char.IsLetterOrDigit(text[i + k.Length]); + + if (isAlphaToken && (!prevCharValid || !nextCharValid)) continue; + + byte token = _tokenMap.Map[k]; + lineData.Add(token); + i += k.Length; + matched = true; + + // REM handling + if (token == 0xEA) + { + if (i < text.Length) + { + string comment = text.Substring(i); + lineData.AddRange(Encoding.ASCII.GetBytes(comment)); + i = text.Length; + } + } + else + { + // Strip trailing space + while (i < text.Length && text[i] == ' ') i++; + } + + i--; + break; + } + + if (matched) continue; + + // Literal + lineData.Add((byte)text[i]); + } + + lineData.Add(0x0D); + + // Construct Line Header + List finalLine = + [ + (byte)((lineNum >> 8) & 0xFF), + (byte)(lineNum & 0xFF) + ]; + + int length = lineData.Count; + finalLine.Add((byte)(length & 0xFF)); + finalLine.Add((byte)((length >> 8) & 0xFF)); + + finalLine.AddRange(lineData); + + return finalLine.ToArray(); + } + } +} diff --git a/ZXBStudio/Common/Txt2Bas/Plus3Dos.cs b/ZXBStudio/Common/Txt2Bas/Plus3Dos.cs new file mode 100644 index 0000000..0c7f310 --- /dev/null +++ b/ZXBStudio/Common/Txt2Bas/Plus3Dos.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ZXBasicStudio.Common.Txt2Bas +{ + /// + /// Generates the 128-byte +3DOS Header required for Spectrum Next/Plus3 files. + /// Based on Yoruguaman work: https://github.com/Ultrahead/SpeccyNextTools + /// + internal static class Plus3Dos + { + /// + /// Creates a valid +3DOS header. + /// + /// The length of the BASIC program data (excluding header). + /// The line number to auto-run (or 32768 for none). + /// A 128-byte byte array containing the header. + public static byte[] CreateHeader(int basicLength, int autoStartLine) + { + // 1. Allocate a zero-filled 128-byte buffer. + // 2. Write the "PLUS3DOS" signature and Soft EOF (0x1A) to the start. + // 3. Set the Issue (1) and Version (0) bytes. + // 4. Calculate and write Total File Size (Header + BASIC Data) at offset 11. + // 5. Write BASIC-specific metadata (Type, Length, Vars Offset). + // 6. Set the Auto-start line (or 32768 if disabled). + // 7. Calculate the Checksum (Sum of bytes 0-126 modulo 256) and write it at byte 127. + + byte[] header = new byte[128]; + Array.Clear(header, 0, 128); + + // Signature + byte[] sig = Encoding.ASCII.GetBytes("PLUS3DOS"); + Array.Copy(sig, header, sig.Length); + header[8] = 0x1A; + + // Version info + header[9] = 0x01; + header[10] = 0x00; + + // Total File Size (Header + Data) + int totalFileSize = basicLength + 128; + BitConverter.GetBytes(totalFileSize).CopyTo(header, 11); + + // BASIC Header Info + header[15] = 0x00; // Type: Program + BitConverter.GetBytes((ushort)basicLength).CopyTo(header, 16); // Length + + // Auto-start + if (autoStartLine is >= 0 and < 32768) + { + BitConverter.GetBytes((ushort)autoStartLine).CopyTo(header, 18); + } + else + { + BitConverter.GetBytes((ushort)32768).CopyTo(header, 18); + } + + // Vars Offset + BitConverter.GetBytes((ushort)basicLength).CopyTo(header, 20); + + // Checksum + int sum = 0; + for (int i = 0; i < 127; i++) sum += header[i]; + header[127] = (byte)(sum % 256); + + return header; + } + } +} diff --git a/ZXBStudio/Common/Txt2Bas/SinclairNumber.cs b/ZXBStudio/Common/Txt2Bas/SinclairNumber.cs new file mode 100644 index 0000000..6fa6dca --- /dev/null +++ b/ZXBStudio/Common/Txt2Bas/SinclairNumber.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ZXBasicStudio.Common.Txt2Bas +{ + /// + /// Handles the 5-byte floating point format used by Sinclair BASIC. + /// Based on Yoruguaman work: https://github.com/Ultrahead/SpeccyNextTools + /// + internal static class SinclairNumber + { + /// + /// Packs a double into the 5-byte internal format. + /// Currently, supports integer format optimization (00 Sign LSB MSB 00). + /// + /// The number to pack. + /// A 5-byte array representing the Sinclair number format. + public static byte[] Pack(double number) + { + // 1. Check if the number is a small integer (within +/- 65535). + // 2. If yes, create the integer format: 0x00, SignByte, LSB, MSB, 0x00. + // 3. If no, return empty zero bytes (full FP implementation omitted for brevity). + + if (number % 1 == 0 && number is >= -65535 and <= 65535) + { + int val = (int)number; + byte sign = 0; + + if (val < 0) + { + sign = 0xFF; + val = -val; + } + + return [0x00, sign, (byte)(val & 0xFF), (byte)((val >> 8) & 0xFF), 0x00]; + } + + return "\0\0\0\0\0"u8.ToArray(); + } + } +} diff --git a/ZXBStudio/Common/Txt2Bas/TokenMap.cs b/ZXBStudio/Common/Txt2Bas/TokenMap.cs new file mode 100644 index 0000000..86fd474 --- /dev/null +++ b/ZXBStudio/Common/Txt2Bas/TokenMap.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ZXBasicStudio.Common.Txt2Bas +{ + /// + /// Dictionary mapping String Keywords to Byte Tokens. + /// Includes Standard Spectrum and NextBASIC extensions. + /// Based on Yoruguaman work: https://github.com/Ultrahead/SpeccyNextTools + /// + internal class TokenMap + { + /// + /// A dictionary containing the mapping from Keyword string to Byte token. + /// + public readonly Dictionary Map = new Dictionary(StringComparer.OrdinalIgnoreCase); + + /// + /// Initializes the TokenMap with standard and extended Spectrum keywords. + /// + public TokenMap() + { + // 1. Populate the dictionary with NextBASIC extension tokens (0x80 - 0xA2). + // 2. Populate the dictionary with Standard 48K BASIC tokens (0xA3 - 0xFF). + + // === ZX SPECTRUM NEXT EXTENSIONS (0x80 - 0xA2) === + Map["PEEK$"] = 0x87; Map["REG"] = 0x88; Map["DPOKE"] = 0x89; Map["DPEEK"] = 0x8A; + Map["MOD"] = 0x8B; Map["<<"] = 0x8C; Map[">>"] = 0x8D; Map["UNTIL"] = 0x8E; + Map["ERROR"] = 0x8F; Map["ON"] = 0x90; Map["DEFPROC"] = 0x91; Map["ENDPROC"] = 0x92; + Map["PROC"] = 0x93; Map["LOCAL"] = 0x94; Map["DRIVER"] = 0x95; Map["WHILE"] = 0x96; + Map["REPEAT"] = 0x97; Map["ELSE"] = 0x98; Map["REMOUNT"] = 0x99; Map["BANK"] = 0x9A; + Map["TILE"] = 0x9B; Map["LAYER"] = 0x9C; Map["PALETTE"] = 0x9D; Map["SPRITE"] = 0x9E; + Map["PWD"] = 0x9F; Map["CD"] = 0xA0; Map["MKDIR"] = 0xA1; Map["RMDIR"] = 0xA2; + + // === STANDARD ZX SPECTRUM 48K TOKENS (0xA3 - 0xFF) === + Map["SPECTRUM"] = 0xA3; Map["PLAY"] = 0xA4; Map["RND"] = 0xA5; Map["INKEY$"] = 0xA6; + Map["PI"] = 0xA7; Map["FN"] = 0xA8; Map["POINT"] = 0xA9; Map["SCREEN$"] = 0xAA; + Map["ATTR"] = 0xAB; Map["AT"] = 0xAC; Map["TAB"] = 0xAD; Map["VAL$"] = 0xAE; + Map["CODE"] = 0xAF; Map["VAL"] = 0xB0; Map["LEN"] = 0xB1; Map["SIN"] = 0xB2; + Map["COS"] = 0xB3; Map["TAN"] = 0xB4; Map["ASN"] = 0xB5; Map["ACS"] = 0xB6; + Map["ATN"] = 0xB7; Map["LN"] = 0xB8; Map["EXP"] = 0xB9; Map["INT"] = 0xBA; + Map["SQR"] = 0xBB; Map["SGN"] = 0xBC; Map["ABS"] = 0xBD; Map["PEEK"] = 0xBE; + Map["IN"] = 0xBF; Map["USR"] = 0xC0; Map["STR$"] = 0xC1; Map["CHR$"] = 0xC2; + Map["NOT"] = 0xC3; Map["BIN"] = 0xC4; Map["OR"] = 0xC5; Map["AND"] = 0xC6; + Map["<="] = 0xC7; Map[">="] = 0xC8; Map["<>"] = 0xC9; Map["LINE"] = 0xCA; + Map["THEN"] = 0xCB; Map["TO"] = 0xCC; Map["STEP"] = 0xCD; Map["DEF FN"] = 0xCE; + Map["CAT"] = 0xCF; Map["FORMAT"] = 0xD0; Map["MOVE"] = 0xD1; Map["ERASE"] = 0xD2; + Map["OPEN #"] = 0xD3; Map["CLOSE #"] = 0xD4; Map["MERGE"] = 0xD5; Map["VERIFY"] = 0xD6; + Map["BEEP"] = 0xD7; Map["CIRCLE"] = 0xD8; Map["INK"] = 0xD9; Map["PAPER"] = 0xDA; + Map["FLASH"] = 0xDB; Map["BRIGHT"] = 0xDC; Map["INVERSE"] = 0xDD; Map["OVER"] = 0xDE; + Map["OUT"] = 0xDF; Map["LPRINT"] = 0xE0; Map["LLIST"] = 0xE1; Map["STOP"] = 0xE2; + Map["READ"] = 0xE3; Map["DATA"] = 0xE4; Map["RESTORE"] = 0xE5; Map["NEW"] = 0xE6; + Map["BORDER"] = 0xE7; Map["CONTINUE"] = 0xE8; Map["DIM"] = 0xE9; Map["REM"] = 0xEA; + Map["FOR"] = 0xEB; Map["GO TO"] = 0xEC; Map["GOTO"] = 0xEC; Map["GO SUB"] = 0xED; + Map["GOSUB"] = 0xED; Map["INPUT"] = 0xEE; Map["LOAD"] = 0xEF; Map["LIST"] = 0xF0; + Map["LET"] = 0xF1; Map["PAUSE"] = 0xF2; Map["NEXT"] = 0xF3; Map["POKE"] = 0xF4; + Map["PRINT"] = 0xF5; Map["PLOT"] = 0xF6; Map["RUN"] = 0xF7; Map["SAVE"] = 0xF8; + Map["RANDOMIZE"] = 0xF9; Map["IF"] = 0xFA; Map["CLS"] = 0xFB; Map["DRAW"] = 0xFC; + Map["CLEAR"] = 0xFD; Map["RETURN"] = 0xFE; Map["COPY"] = 0xFF; + } + } +} diff --git a/ZXBStudio/Common/Txt2Bas/Txt2BasConverter.cs b/ZXBStudio/Common/Txt2Bas/Txt2BasConverter.cs new file mode 100644 index 0000000..519bc5b --- /dev/null +++ b/ZXBStudio/Common/Txt2Bas/Txt2BasConverter.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace ZXBasicStudio.Common.Txt2Bas +{ + /// + /// Converts plain text to ZX Spectrum .bas format + /// Based on Yoruguaman work: https://github.com/Ultrahead/SpeccyNextTools + /// + public static class Txt2BasConverter + { + + public static byte[] Text2Bas(string text) + { + try + { + BasConverter converter = new BasConverter(); + byte[] basData = converter.ConvertFile(text); + + // Use the explicitly parsed AutoStartLine (defaults to 32768 if no #autostart found) + byte[] header = Plus3Dos.CreateHeader(basData.Length, converter.AutoStartLine); + + var fileData = new List(); + fileData.AddRange(header); + fileData.AddRange(basData); + + return fileData.ToArray(); + } + catch (Exception ex) + { + Console.WriteLine($"Error: {ex.Message}"); + return null; + } + } + } +} diff --git a/ZXBStudio/Dialogs/ZXAboutDialog.axaml b/ZXBStudio/Dialogs/ZXAboutDialog.axaml index 7e43d70..3582e78 100644 --- a/ZXBStudio/Dialogs/ZXAboutDialog.axaml +++ b/ZXBStudio/Dialogs/ZXAboutDialog.axaml @@ -16,7 +16,7 @@ The ZX Basic Studio development team - El Dr. Gusman, Boriel, Duefectu, AdolFITO, Hash6Iron, SirRickster + El Dr. Gusman, Boriel, Duefectu, AdolFITO, Hash6Iron, SirRickster and Yoruguaman Many thanks to Boriel for the ZX Basic compiler and his support to this project. (C) 2023, El Dr. Gusman (C) 2025, Boriel & DuefectuCorp diff --git a/ZXBStudio/MainWindow.axaml.cs b/ZXBStudio/MainWindow.axaml.cs index 21bfb82..b14706b 100644 --- a/ZXBStudio/MainWindow.axaml.cs +++ b/ZXBStudio/MainWindow.axaml.cs @@ -2523,26 +2523,39 @@ private string BuildAndRun_MAME(string emulatorPath, string nextDrive, ZXBuildSe } var basePath =Directory.GetParent(Directory.GetParent(emulatorPath).FullName).FullName; + var sdimagePath= Path.Combine(basePath, "nextsdimage", "cspect-next-2gb.img"); // Delete /nextzxos/autoexec.1st - Hdfmonkey("rm ../nextsdimage/nextimage.img /nextzxos/autoexec.1st", basePath); + Hdfmonkey($"rm \"{sdimagePath}\" /nextzxos/autoexec.1st", basePath); + + // Create autoexec.bas + var nextPath =Path.GetFileNameWithoutExtension(project.GetMainFile()); + string autoexec = $@"#autostart 10 +10 CD ""{nextPath}"" +20 .nexload {nextPath}.nex +"; + var bytes=Common.Txt2Bas.Txt2BasConverter.Text2Bas(autoexec); + var autoexecPath = Path.Combine(basePath, "hdfmonkey", "autoexec.bas"); + File.WriteAllBytes(autoexecPath, bytes); + // Copy /nextzxos/autoexec.bas - if (!Hdfmonkey("put ../nextsdimage/nextimage.img ../nextsdimage/autoexec.bas /nextzxos/autoexec.bas", basePath)) + if (!Hdfmonkey($"put \"{sdimagePath}\" \"{autoexecPath}\" /nextzxos/autoexec.bas", basePath)) { return "Error copying autoexec.bas to the emulator image."; } + // Empty /zxbsdev folder // TODO: Sync! - Hdfmonkey("rm ../nextsdimage/nextimage.img /zxbsdev", basePath); + Hdfmonkey($"rm \"{sdimagePath}\" /{nextPath}", basePath); // Create /zxbsdev - Hdfmonkey("mkdir ../nextsdimage/nextimage.img /zxbsdev", basePath); + Hdfmonkey($"mkdir \"{sdimagePath}\" /{nextPath}", basePath); // Copy nextdrive to /zxbsdev - Hdfmonkey($"putdir ../nextsdimage/nextimage.img \"{nextDrive}\" /zxbsdev/", basePath); + Hdfmonkey($"putdir \"{sdimagePath}\" \"{nextDrive}\" /{nextPath}/", basePath); // Launch mame { outLog.Writer.WriteLine("Launching MAME..."); - var parameters = $"-ui_active -nounevenstretch -aspect 2:1 -video bgfx -bgfx_screen_chains unfiltered -window -skip_gameinfo -mouse_device none -confirm_quit tbblue -hard1 ../nextsdimage/nextimage.img -plugin zxbs -debug -debugger none -console"; + var parameters = $"-ui_active -nounevenstretch -aspect 2:1 -video bgfx -bgfx_screen_chains unfiltered -window -skip_gameinfo -mouse_device none -confirm_quit tbblue -hard1 {sdimagePath} -plugin zxbs -debug -debugger none -console"; var psi = new ProcessStartInfo() { FileName = emulatorPath,