From 89413d11e46a71649fad6045ea9eb4e006b08149 Mon Sep 17 00:00:00 2001 From: Andy McFadden Date: Sat, 28 Dec 2019 17:14:29 -0800 Subject: [PATCH] Add file concatenation tool Select a list of files and save it. File lengths and CRCs are shown for reference. --- CommonUtil/CRC32.cs | 50 ++-- CommonUtil/FileUtil.cs | 2 +- SourceGen/MainController.cs | 142 +++++----- SourceGen/RuntimeData/Help/index.html | 2 + SourceGen/RuntimeData/Help/tools.html | 7 + SourceGen/Sandbox/PluginDllCache.cs | 8 +- SourceGen/SourceGen.csproj | 7 + SourceGen/Tools/WpfGui/FileConcatenator.xaml | 100 +++++++ .../Tools/WpfGui/FileConcatenator.xaml.cs | 244 ++++++++++++++++++ .../Tools/WpfGui/InstructionChart.xaml.cs | 2 + .../WpfGui/EditProjectProperties.xaml.cs | 6 +- SourceGen/WpfGui/EditVisualizationSet.xaml.cs | 19 +- SourceGen/WpfGui/MainWindow.xaml | 12 +- SourceGen/WpfGui/MainWindow.xaml.cs | 4 + 14 files changed, 492 insertions(+), 113 deletions(-) create mode 100644 SourceGen/Tools/WpfGui/FileConcatenator.xaml create mode 100644 SourceGen/Tools/WpfGui/FileConcatenator.xaml.cs diff --git a/CommonUtil/CRC32.cs b/CommonUtil/CRC32.cs index c492bb7..d45c690 100644 --- a/CommonUtil/CRC32.cs +++ b/CommonUtil/CRC32.cs @@ -47,13 +47,13 @@ namespace CommonUtil { } /// - /// Computes a CRC on part of a buffer of data. + /// Computes a CRC-32 on part of a buffer of data. /// - /// Previously computed CRC value. Initially zero. + /// Previously computed CRC value. Use zero as initial value. /// Data to compute CRC on. /// Start offset within buffer. /// Number of bytes to process. - /// New CRC value. + /// Computed CRC value. public static uint OnBuffer(uint crc, byte[] buffer, int offset, int count) { crc = crc ^ INVERT; while (count-- != 0) { @@ -64,45 +64,37 @@ namespace CommonUtil { } /// - /// Computes a CRC on a buffer of data. + /// Computes a CRC-32 on a buffer of data. /// /// Previously computed CRC value. Initially zero. /// Data to compute CRC on. - /// New CRC value. + /// Computed CRC value. public static uint OnWholeBuffer(uint crc, byte[] buffer) { return OnBuffer(crc, buffer, 0, buffer.Length); } /// - /// Computes a CRC on an entire file. + /// Computes a CRC-32 on an entire file. An exception will be thrown on file errors. /// /// Full path to file to open. - /// Receives the CRC. - /// True on success, false on file error. - public static bool OnWholeFile(string pathName, out uint ocrc) { - try { - using (FileStream fs = File.Open(pathName, FileMode.Open, FileAccess.Read)) { - byte[] buffer = new byte[8192]; - uint crc = 0; - long remain = fs.Length; - while (remain != 0) { - int toRead = (remain < buffer.Length) ? (int)remain : buffer.Length; - int actual = fs.Read(buffer, 0, toRead); - if (toRead != actual) { - throw new IOException("Expected " + toRead + ", got " + actual); - } - - crc = OnBuffer(crc, buffer, 0, toRead); - remain -= toRead; + /// Computed CRC value. + public static uint OnWholeFile(string pathName) { + using (FileStream fs = File.Open(pathName, FileMode.Open, FileAccess.Read)) { + byte[] buffer = new byte[8192]; + uint crc = 0; + long remain = fs.Length; + while (remain != 0) { + int toRead = (remain < buffer.Length) ? (int)remain : buffer.Length; + int actual = fs.Read(buffer, 0, toRead); + if (toRead != actual) { + throw new IOException("Expected " + toRead + ", got " + actual); } - ocrc = crc; - return true; + crc = OnBuffer(crc, buffer, 0, toRead); + remain -= toRead; } - } catch (IOException ioe) { - Debug.WriteLine("Fail: " + ioe); - ocrc = 0; - return false; + + return crc; } } } diff --git a/CommonUtil/FileUtil.cs b/CommonUtil/FileUtil.cs index 3cb0289..823b84a 100644 --- a/CommonUtil/FileUtil.cs +++ b/CommonUtil/FileUtil.cs @@ -125,7 +125,7 @@ namespace CommonUtil { /// File of interest. /// File to compare dates with. /// True if dstFile is missing or older than srcFile. - public static bool FileMissingOrOlder(string dstFile, string srcFile) { + public static bool IsFileMissingOrOlder(string dstFile, string srcFile) { FileInfo fid = new FileInfo(dstFile); if (!fid.Exists) { return true; // not there diff --git a/SourceGen/MainController.cs b/SourceGen/MainController.cs index 61a82bf..ad00dcf 100644 --- a/SourceGen/MainController.cs +++ b/SourceGen/MainController.cs @@ -3117,44 +3117,6 @@ namespace SourceGen { return -1; } - public void ShowFileHexDump() { - OpenFileDialog fileDlg = new OpenFileDialog() { - Filter = Res.Strings.FILE_FILTER_ALL, - FilterIndex = 1 - }; - if (fileDlg.ShowDialog() != true) { - return; - } - string fileName = fileDlg.FileName; - FileInfo fi = new FileInfo(fileName); - if (fi.Length > Tools.WpfGui.HexDumpViewer.MAX_LENGTH) { - string msg = string.Format(Res.Strings.OPEN_DATA_TOO_LARGE_FMT, - fi.Length / 1024, Tools.WpfGui.HexDumpViewer.MAX_LENGTH / 1024); - MessageBox.Show(msg, Res.Strings.OPEN_DATA_FAIL_CAPTION, - MessageBoxButton.OK, MessageBoxImage.Error); - return; - } - byte[] data; - try { - data = File.ReadAllBytes(fileName); - } catch (Exception ex) { - // not expecting this to happen - MessageBox.Show(ex.Message); - return; - } - - // Create the dialog without an owner, and add it to the "unowned" list. - Tools.WpfGui.HexDumpViewer dlg = new Tools.WpfGui.HexDumpViewer(null, - data, mOutputFormatter); - dlg.SetFileName(Path.GetFileName(fileName)); - dlg.Closing += (sender, e) => { - Debug.WriteLine("Window " + dlg + " closed, removing from unowned list"); - mUnownedWindows.Remove(dlg); - }; - mUnownedWindows.Add(dlg); - dlg.Show(); - } - public void ShowHexDump() { if (mHexDumpDialog == null) { // Create and show modeless dialog. This one is "always on top" by default, @@ -3283,34 +3245,6 @@ namespace SourceGen { dlg.ShowDialog(); } - public void ToggleAsciiChart() { - if (mAsciiChartDialog == null) { - // Create without owner so it doesn't have to be in front of main window. - mAsciiChartDialog = new Tools.WpfGui.AsciiChart(null); - mAsciiChartDialog.Closing += (sender, e) => { - Debug.WriteLine("ASCII chart closed"); - mAsciiChartDialog = null; - }; - mAsciiChartDialog.Show(); - } else { - mAsciiChartDialog.Close(); - } - } - - public void ToggleInstructionChart() { - if (mInstructionChartDialog == null) { - // Create without owner so it doesn't have to be in front of main window. - mInstructionChartDialog = new Tools.WpfGui.InstructionChart(null,mOutputFormatter); - mInstructionChartDialog.Closing += (sender, e) => { - Debug.WriteLine("Instruction chart closed"); - mInstructionChartDialog = null; - }; - mInstructionChartDialog.Show(); - } else { - mInstructionChartDialog.Close(); - } - } - public void ToggleDataScan() { ProjectProperties oldProps = mProject.ProjectProps; ProjectProperties newProps = new ProjectProperties(oldProps); @@ -4017,6 +3951,82 @@ namespace SourceGen { #endregion Info panel + #region Tools + + public void ToggleAsciiChart() { + if (mAsciiChartDialog == null) { + // Create without owner so it doesn't have to be in front of main window. + mAsciiChartDialog = new Tools.WpfGui.AsciiChart(null); + mAsciiChartDialog.Closing += (sender, e) => { + Debug.WriteLine("ASCII chart closed"); + mAsciiChartDialog = null; + }; + mAsciiChartDialog.Show(); + } else { + mAsciiChartDialog.Close(); + } + } + + public void ToggleInstructionChart() { + if (mInstructionChartDialog == null) { + // Create without owner so it doesn't have to be in front of main window. + mInstructionChartDialog = new Tools.WpfGui.InstructionChart(null, mOutputFormatter); + mInstructionChartDialog.Closing += (sender, e) => { + Debug.WriteLine("Instruction chart closed"); + mInstructionChartDialog = null; + }; + mInstructionChartDialog.Show(); + } else { + mInstructionChartDialog.Close(); + } + } + + public void ShowFileHexDump() { + OpenFileDialog fileDlg = new OpenFileDialog() { + Filter = Res.Strings.FILE_FILTER_ALL, + FilterIndex = 1 + }; + if (fileDlg.ShowDialog() != true) { + return; + } + string fileName = fileDlg.FileName; + FileInfo fi = new FileInfo(fileName); + if (fi.Length > Tools.WpfGui.HexDumpViewer.MAX_LENGTH) { + string msg = string.Format(Res.Strings.OPEN_DATA_TOO_LARGE_FMT, + fi.Length / 1024, Tools.WpfGui.HexDumpViewer.MAX_LENGTH / 1024); + MessageBox.Show(msg, Res.Strings.OPEN_DATA_FAIL_CAPTION, + MessageBoxButton.OK, MessageBoxImage.Error); + return; + } + byte[] data; + try { + data = File.ReadAllBytes(fileName); + } catch (Exception ex) { + // not expecting this to happen + MessageBox.Show(ex.Message); + return; + } + + // Create the dialog without an owner, and add it to the "unowned" list. + Tools.WpfGui.HexDumpViewer dlg = new Tools.WpfGui.HexDumpViewer(null, + data, mOutputFormatter); + dlg.SetFileName(Path.GetFileName(fileName)); + dlg.Closing += (sender, e) => { + Debug.WriteLine("Window " + dlg + " closed, removing from unowned list"); + mUnownedWindows.Remove(dlg); + }; + mUnownedWindows.Add(dlg); + dlg.Show(); + } + + public void ConcatenateFiles() { + Tools.WpfGui.FileConcatenator concat = + new Tools.WpfGui.FileConcatenator(this.mMainWin); + concat.ShowDialog(); + } + + #endregion Tools + #region Debug features public void Debug_ExtensionScriptInfo() { diff --git a/SourceGen/RuntimeData/Help/index.html b/SourceGen/RuntimeData/Help/index.html index 16980bd..b74081c 100644 --- a/SourceGen/RuntimeData/Help/index.html +++ b/SourceGen/RuntimeData/Help/index.html @@ -138,6 +138,7 @@ and 65816 code. The official web site is
  • Tools
  • @@ -175,6 +176,7 @@ and 65816 code. The official web site is
  • Tutorial #2: Advanced Features
  • Tutorial #3: Address Table Formatting
  • Tutorial #4: Extension Scripts
  • +
  • Tutorial #5: Visualizations
  • diff --git a/SourceGen/RuntimeData/Help/tools.html b/SourceGen/RuntimeData/Help/tools.html index 6a95891..bd9d58c 100644 --- a/SourceGen/RuntimeData/Help/tools.html +++ b/SourceGen/RuntimeData/Help/tools.html @@ -49,6 +49,13 @@ default this box is checked when displaying project data, and not checked for external files.

    +

    File Concatenator

    + +

    The File Concatenator combines multiple files into a single file. +Select the files to add, arrange them in the proper order, then hit +"Save".

    + +

    ASCII Chart

    This opens a window with the ASCII character set. Each character is diff --git a/SourceGen/Sandbox/PluginDllCache.cs b/SourceGen/Sandbox/PluginDllCache.cs index 2d9ec7f..93ad26c 100644 --- a/SourceGen/Sandbox/PluginDllCache.cs +++ b/SourceGen/Sandbox/PluginDllCache.cs @@ -104,7 +104,7 @@ namespace SourceGen.Sandbox { /// Destination directory. private static void CopyIfNewer(string srcDll, string dstDir) { string dstFile = Path.Combine(dstDir, Path.GetFileName(srcDll)); - if (FileUtil.FileMissingOrOlder(dstFile, srcDll)) { + if (FileUtil.IsFileMissingOrOlder(dstFile, srcDll)) { Debug.WriteLine("Copying " + srcDll + " to " + dstFile); File.Copy(srcDll, dstFile, true); } @@ -155,10 +155,10 @@ namespace SourceGen.Sandbox { // the DLLs the app uses, not the copy the plugins use, but earlier we made sure // that they were the same. This test doesn't handle the case where the DLLs // get rolled back, but that's probably not interesting for us.) - bool needCompile = FileUtil.FileMissingOrOlder(destPathName, srcPathName) || - FileUtil.FileMissingOrOlder(destPathName, + bool needCompile = FileUtil.IsFileMissingOrOlder(destPathName, srcPathName) || + FileUtil.IsFileMissingOrOlder(destPathName, typeof(PluginCommon.PluginManager).Assembly.Location) || - FileUtil.FileMissingOrOlder(destPathName, + FileUtil.IsFileMissingOrOlder(destPathName, typeof(CommonUtil.CRC32).Assembly.Location); if (needCompile) { Debug.WriteLine("Compiling " + srcPathName + " to " + destPathName); diff --git a/SourceGen/SourceGen.csproj b/SourceGen/SourceGen.csproj index e0b3755..bf54898 100644 --- a/SourceGen/SourceGen.csproj +++ b/SourceGen/SourceGen.csproj @@ -86,6 +86,9 @@ + + FileConcatenator.xaml + InstructionChart.xaml @@ -262,6 +265,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + MSBuild:Compile Designer diff --git a/SourceGen/Tools/WpfGui/FileConcatenator.xaml b/SourceGen/Tools/WpfGui/FileConcatenator.xaml new file mode 100644 index 0000000..7ef7ceb --- /dev/null +++ b/SourceGen/Tools/WpfGui/FileConcatenator.xaml @@ -0,0 +1,100 @@ + + + + + + File Access Error + Unable to access file: {0} + CRC failed + Select File + + Success + All files were concatenated successfully. Total length is {0}, overall CRC-32 is {1}. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +