Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,26 @@ jobs:
if: matrix.build-type == 'framework-dependent'
run: dotnet publish GDeflateGUI/GDeflateGUI.csproj --configuration Release --output ./publish-gui --no-build --self-contained false

- name: Download and copy dependencies
run: |
# Download nvCOMP library for CUDA 12
$nvcompUrl = "https://developer.nvidia.com/downloads/compute/nvcompdx/redist/nvcompdx/cuda12/nvidia-mathdx-25.06.1-cuda12.zip"
$nvcompZip = "nvcomp.zip"
Invoke-WebRequest -Uri $nvcompUrl -OutFile $nvcompZip

# Extract the contents
Expand-Archive -Path $nvcompZip -DestinationPath ./nvcomp_temp

# Copy required DLLs to the publish directory
# Adjust the source path based on the actual structure of the zip file
Copy-Item -Path ./nvcomp_temp/bin/nvcomp.dll -Destination ./publish-gui/
Copy-Item -Path ./nvcomp_temp/bin/cudart64_12.dll -Destination ./publish-gui/

# Clean up downloaded files
Remove-Item $nvcompZip
Remove-Item -Recurse -Force ./nvcomp_temp
shell: pwsh

- name: Create build info
run: |
echo "GDeflate GUI Application - ${{ matrix.build-type }}" > ./publish-gui/BUILD_INFO.txt
Expand Down Expand Up @@ -94,6 +114,27 @@ jobs:
- name: Publish console application (Self-contained)
run: dotnet publish GDeflateConsole/GDeflateConsole.csproj --configuration Release --output ./publish-console --self-contained true --runtime ${{ matrix.runtime }}

- name: Download and copy dependencies (Windows only)
if: matrix.os == 'windows-latest'
run: |
# Download nvCOMP library for CUDA 12
$nvcompUrl = "https://developer.nvidia.com/downloads/compute/nvcompdx/redist/nvcompdx/cuda12/nvidia-mathdx-25.06.1-cuda12.zip"
$nvcompZip = "nvcomp.zip"
Invoke-WebRequest -Uri $nvcompUrl -OutFile $nvcompZip

# Extract the contents
Expand-Archive -Path $nvcompZip -DestinationPath ./nvcomp_temp

# Copy required DLLs to the publish directory
# Adjust the source path based on the actual structure of the zip file
Copy-Item -Path ./nvcomp_temp/bin/nvcomp.dll -Destination ./publish-console/
Copy-Item -Path ./nvcomp_temp/bin/cudart64_12.dll -Destination ./publish-console/

# Clean up downloaded files
Remove-Item $nvcompZip
Remove-Item -Recurse -Force ./nvcomp_temp
shell: pwsh

- name: Create build info (Windows)
if: matrix.os == 'windows-latest'
run: |
Expand Down
67 changes: 45 additions & 22 deletions GDeflateConsole/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -330,29 +330,14 @@ static void TestCompressionDecompression(string testFile, GDeflateProcessor proc
Console.WriteLine($" Decompressed size: {FormatFileSize(decompressedInfo.Length)}");
Console.WriteLine($" Decompression time: {decompressTime.TotalMilliseconds:F2} ms");

// Verify integrity (for simulation mode)
if (processor.IsSimulationMode)
// Verify integrity
Console.WriteLine(" Verifying file integrity...");
bool filesMatch = AreFilesEqual(testFile, decompressedFile);
Console.WriteLine($" Integrity check: {(filesMatch ? "PASSED" : "FAILED")}");

if (!filesMatch)
{
Console.WriteLine($" Integrity check: Simulation mode (basic verification)");
}
else
{
// For real GPU mode, we could do byte-by-byte comparison
bool identical = originalInfo.Length == decompressedInfo.Length;
if (identical && originalInfo.Length < 10 * 1024 * 1024) // Only for files < 10MB
{
var originalBytes = File.ReadAllBytes(testFile);
var decompressedBytes = File.ReadAllBytes(decompressedFile);

for (int i = 0; i < originalBytes.Length && identical; i++)
{
if (originalBytes[i] != decompressedBytes[i])
{
identical = false;
}
}
}
Console.WriteLine($" Integrity check: {(identical ? "PASSED" : "FAILED")}");
throw new Exception("File integrity check failed: decompressed file does not match original.");
}

Console.WriteLine(" Test PASSED");
Expand All @@ -372,6 +357,44 @@ static void TestCompressionDecompression(string testFile, GDeflateProcessor proc
}
}

static bool AreFilesEqual(string path1, string path2)
{
const int bufferSize = 4096;

using (var fs1 = new FileStream(path1, FileMode.Open, FileAccess.Read))
using (var fs2 = new FileStream(path2, FileMode.Open, FileAccess.Read))
{
if (fs1.Length != fs2.Length)
{
return false;
}

var buffer1 = new byte[bufferSize];
var buffer2 = new byte[bufferSize];

while (true)
{
int bytesRead1 = fs1.Read(buffer1, 0, bufferSize);
int bytesRead2 = fs2.Read(buffer2, 0, bufferSize);

if (bytesRead1 != bytesRead2)
{
return false;
}

if (bytesRead1 == 0)
{
return true;
}

if (!buffer1.AsSpan(0, bytesRead1).SequenceEqual(buffer2.AsSpan(0, bytesRead2)))
{
return false;
}
}
}
}

static string FormatFileSize(long bytes)
{
string[] suffixes = { "B", "KB", "MB", "GB", "TB" };
Expand Down
143 changes: 79 additions & 64 deletions GDeflateGUI/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,72 +138,87 @@ await System.Threading.Tasks.Task.Run(() =>

private void btnAddFiles_Click(object? sender, System.EventArgs e)
{
if (!IsWindows)
{
AddFilesAlternativeMethod();
return;
}

try
{
if (IsWindows)
using (var dialog = new OpenFileDialog
{
// Use Windows Forms dialog on Windows
using (var dialog = new OpenFileDialog())
Multiselect = true,
Title = "Select files",
Filter = "All files (*.*)|*.*"
})
{
if (dialog.ShowDialog() == DialogResult.OK)
{
dialog.Multiselect = true;
dialog.Title = "Select files";
dialog.Filter = "All files (*.*)|*.*";
if (dialog.ShowDialog() == DialogResult.OK)
{
foreach (string file in dialog.FileNames)
{
AddFileToList(file);
}
UpdateStatus($"Added {dialog.FileNames.Length} files. Total: {listViewFiles.Items.Count}");
}
AddFilesToList(dialog.FileNames);
}
}
else
{
// Alternative method for non-Windows platforms
AddFilesAlternativeMethod();
}
}
catch (Exception ex)
{
MessageBox.Show($"Error adding files: {ex.Message}\n\nTip: On non-Windows platforms, you can manually enter file paths or use the alternative method.",
"File Selection Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
UpdateStatus("Error occurred while adding files. See message for details.");
ShowError("Error adding files", ex);
}
}

private void btnAddFolder_Click(object? sender, System.EventArgs e)
private async void btnAddFolder_Click(object? sender, System.EventArgs e)
{
if (!IsWindows)
{
AddFolderAlternativeMethod();
return;
}

try
{
if (IsWindows)
using (var dialog = new FolderBrowserDialog
{
Description = "Select a folder to add all its files"
})
{
// Use Windows Forms dialog on Windows
using (var dialog = new FolderBrowserDialog())
if (dialog.ShowDialog() == DialogResult.OK)
{
dialog.Description = "Select a folder to add all its files";
if (dialog.ShowDialog() == DialogResult.OK)
{
var files = Directory.GetFiles(dialog.SelectedPath, "*.*", SearchOption.AllDirectories);
foreach (string file in files)
{
AddFileToList(file);
}
UpdateStatus($"Added {files.Length} files from folder. Total: {listViewFiles.Items.Count}");
}
await AddFolderFilesAsync(dialog.SelectedPath);
}
}
else
{
// Alternative method for non-Windows platforms
AddFolderAlternativeMethod();
}
}
catch (Exception ex)
{
MessageBox.Show($"Error adding folder: {ex.Message}\n\nTip: On non-Windows platforms, you can manually enter folder paths or use the alternative method.",
"Folder Selection Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
UpdateStatus("Error occurred while adding folder. See message for details.");
ShowError("Error adding folder", ex);
}
}

private async System.Threading.Tasks.Task AddFolderFilesAsync(string path)
{
SetUIEnabled(false);
UpdateStatus("Searching for files...");

try
{
var files = await System.Threading.Tasks.Task.Run(() =>
Directory.GetFiles(path, "*.*", SearchOption.AllDirectories)
);
AddFilesToList(files);
}
catch (UnauthorizedAccessException ex)
{
ShowError("Access denied. You may not have permission to access all subdirectories.", ex);
}
catch (IOException ex)
{
ShowError("An I/O error occurred while accessing the folder.", ex);
}
catch (Exception ex)
{
ShowError("An unexpected error occurred while adding folder files.", ex);
}
finally
{
SetUIEnabled(true);
}
}

Expand Down Expand Up @@ -237,16 +252,11 @@ private void AddFilesAlternativeMethod()
.Take(5) // Limit to first 5 files
.ToArray();

foreach (string file in files)
{
AddFileToList(file);
}

UpdateStatus($"Added {files.Length} test files from current directory. Total: {listViewFiles.Items.Count}");
AddFilesToList(files);
}
catch (Exception ex)
{
MessageBox.Show($"Error adding test files: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
ShowError("Error adding test files", ex);
}
}
}
Expand All @@ -271,31 +281,36 @@ private void AddFolderAlternativeMethod()
{
var currentDir = Directory.GetCurrentDirectory();
var files = Directory.GetFiles(currentDir, "*.*", SearchOption.AllDirectories);

foreach (string file in files)
{
AddFileToList(file);
}

UpdateStatus($"Added {files.Length} files from current directory and subdirectories. Total: {listViewFiles.Items.Count}");
AddFilesToList(files);
}
catch (Exception ex)
{
MessageBox.Show($"Error adding files from folder: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
ShowError("Error adding files from folder", ex);
}
}
}

private void AddFileToList(string filePath)
private void AddFilesToList(string[] filePaths)
{
// Check if the file is already in the list to avoid duplicates
if (!listViewFiles.Items.Cast<ListViewItem>().Any(item => item.Text == filePath))
var newItems = filePaths
.Where(filePath => !listViewFiles.Items.Cast<ListViewItem>().Any(item => item.Text == filePath))
.Select(filePath => new ListViewItem(filePath))
.ToArray();

if (newItems.Any())
{
var item = new ListViewItem(filePath);
listViewFiles.Items.Add(item);
listViewFiles.Items.AddRange(newItems);
UpdateStatus($"Added {newItems.Length} files. Total: {listViewFiles.Items.Count}");
}
}

private void ShowError(string title, Exception ex)
{
MessageBox.Show($"{ex.Message}\n\nTip: On non-Windows platforms, you can use the console version for more detailed error information.",
title, MessageBoxButtons.OK, MessageBoxIcon.Warning);
UpdateStatus($"Error: {title}. See message for details.");
}

private void UpdateStatus(string text)
{
statusLabel.Text = text;
Expand Down
Loading