Files
romrepomgr/RomRepoMgr.Core/Workers/Compression.cs

282 lines
9.3 KiB
C#
Raw Normal View History

2020-08-22 21:19:34 +01:00
/******************************************************************************
// RomRepoMgr - ROM repository manager
// ----------------------------------------------------------------------------
//
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// --[ License ] --------------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
2024-11-08 19:13:57 +00:00
// Copyright © 2017-2024 Natalia Portillo
2020-08-22 21:19:34 +01:00
*******************************************************************************/
2020-08-22 05:14:52 +01:00
using System;
2020-08-22 21:19:34 +01:00
using System.Diagnostics;
2020-08-22 05:14:52 +01:00
using System.IO;
using RomRepoMgr.Core.EventArgs;
2020-08-30 03:00:14 +01:00
using RomRepoMgr.Core.Resources;
using RomRepoMgr.Settings;
2020-08-22 05:14:52 +01:00
using SharpCompress.Compressors;
using SharpCompress.Compressors.LZMA;
using ZstdSharp;
using ZstdSharp.Unsafe;
2020-08-22 21:19:34 +01:00
using ErrorEventArgs = RomRepoMgr.Core.EventArgs.ErrorEventArgs;
2020-08-22 05:14:52 +01:00
2024-11-09 01:37:59 +00:00
namespace RomRepoMgr.Core.Workers;
2020-08-22 05:14:52 +01:00
2024-11-09 01:37:59 +00:00
public sealed class Compression
{
const long BUFFER_SIZE = 131072;
2020-08-22 05:14:52 +01:00
2024-11-09 01:37:59 +00:00
public event EventHandler<ProgressBoundsEventArgs> SetProgressBounds;
public event EventHandler<ProgressEventArgs> SetProgress;
public event EventHandler<MessageEventArgs> FinishedWithText;
public event EventHandler<ErrorEventArgs> FailedWithText;
2020-08-22 05:14:52 +01:00
2024-11-09 01:37:59 +00:00
public void CompressFile(string source, string destination)
{
var inFs = new FileStream(source, FileMode.Open, FileAccess.Read);
var outFs = new FileStream(destination, FileMode.CreateNew, FileAccess.Write);
2020-08-22 05:14:52 +01:00
Stream zStream;
switch(Settings.Settings.Current.Compression)
{
case CompressionType.Zstd:
{
var zstdStream = new CompressionStream(outFs, 15);
zstdStream.SetParameter(ZSTD_cParameter.ZSTD_c_nbWorkers, Environment.ProcessorCount);
zStream = zstdStream;
break;
}
case CompressionType.None:
zStream = outFs;
break;
default:
zStream = new LZipStream(outFs, CompressionMode.Compress);
break;
}
byte[] buffer = new byte[BUFFER_SIZE];
2020-08-22 05:14:52 +01:00
2024-11-09 01:37:59 +00:00
SetProgressBounds?.Invoke(this,
new ProgressBoundsEventArgs
{
Minimum = 0,
Maximum = inFs.Length
});
2020-08-22 05:14:52 +01:00
2024-11-09 01:37:59 +00:00
while(inFs.Position + BUFFER_SIZE <= inFs.Length)
{
SetProgress?.Invoke(this,
new ProgressEventArgs
{
Value = inFs.Position
});
2020-08-22 05:14:52 +01:00
inFs.ReadExactly(buffer, 0, buffer.Length);
2020-08-22 05:14:52 +01:00
zStream.Write(buffer, 0, buffer.Length);
}
2020-08-22 21:19:34 +01:00
2024-11-09 01:37:59 +00:00
buffer = new byte[inFs.Length - inFs.Position];
2020-08-24 04:01:55 +01:00
2024-11-09 01:37:59 +00:00
SetProgressBounds?.Invoke(this,
new ProgressBoundsEventArgs
{
Minimum = 0,
Maximum = inFs.Length
});
2020-08-24 04:01:55 +01:00
inFs.ReadExactly(buffer, 0, buffer.Length);
2024-11-09 01:37:59 +00:00
zStream.Write(buffer, 0, buffer.Length);
2020-08-24 04:01:55 +01:00
2024-11-09 01:37:59 +00:00
inFs.Close();
zStream.Close();
outFs.Dispose();
}
2020-08-22 21:19:34 +01:00
2024-11-09 01:37:59 +00:00
public void DecompressFile(string source, string destination)
{
var inFs = new FileStream(source, FileMode.Open, FileAccess.Read);
var outFs = new FileStream(destination, FileMode.Create, FileAccess.Write);
Stream zStream;
if(Path.GetExtension(source) == ".zst")
zStream = new DecompressionStream(inFs);
else if(Path.GetExtension(source) == ".lz")
zStream = new LZipStream(inFs, CompressionMode.Decompress);
else if(string.IsNullOrWhiteSpace(Path.GetExtension(source)))
zStream = inFs;
else
throw new ArgumentException($"Invalid compression extension {Path.GetExtension(source)}");
2020-08-22 21:19:34 +01:00
2024-11-09 01:37:59 +00:00
zStream.CopyTo(outFs);
2020-08-22 21:19:34 +01:00
2024-11-09 01:37:59 +00:00
outFs.Close();
zStream.Close();
inFs.Close();
}
2020-08-22 21:19:34 +01:00
2024-11-09 01:37:59 +00:00
public bool CheckUnAr(string unArPath)
{
if(string.IsNullOrWhiteSpace(unArPath))
{
FailedWithText?.Invoke(this,
new ErrorEventArgs
{
Message = Localization.UnArPathNotSet
});
2020-08-22 21:19:34 +01:00
2024-11-09 01:37:59 +00:00
return false;
}
2020-08-22 21:19:34 +01:00
2024-11-09 01:37:59 +00:00
string unarFolder = Path.GetDirectoryName(unArPath);
string extension = Path.GetExtension(unArPath);
string unarfilename = Path.GetFileNameWithoutExtension(unArPath);
string lsarfilename = unarfilename.Replace("unar", "lsar");
string unarPath = Path.Combine(unarFolder, unarfilename + extension);
string lsarPath = Path.Combine(unarFolder, lsarfilename + extension);
2020-08-22 21:19:34 +01:00
2024-11-09 01:37:59 +00:00
if(!File.Exists(unarPath))
{
FailedWithText?.Invoke(this,
new ErrorEventArgs
{
Message = string.Format(Localization.CannotFindUnArAtPath, unarPath)
});
2020-08-22 21:19:34 +01:00
2024-11-09 01:37:59 +00:00
return false;
}
2020-08-22 21:19:34 +01:00
2024-11-09 01:37:59 +00:00
if(!File.Exists(lsarPath))
{
FailedWithText?.Invoke(this,
new ErrorEventArgs
{
Message = Localization.CannotFindLsAr
});
2020-08-22 21:19:34 +01:00
2024-11-09 01:37:59 +00:00
return false;
}
2020-08-22 21:19:34 +01:00
2024-11-09 01:37:59 +00:00
string unarOut, lsarOut;
2020-08-22 21:19:34 +01:00
2024-11-09 01:37:59 +00:00
try
{
var unarProcess = new Process
2020-08-22 21:19:34 +01:00
{
2024-11-09 01:37:59 +00:00
StartInfo =
2020-08-22 21:19:34 +01:00
{
2024-11-09 01:37:59 +00:00
FileName = unarPath,
CreateNoWindow = true,
RedirectStandardOutput = true,
UseShellExecute = false
}
};
2020-08-22 21:19:34 +01:00
2024-11-09 01:37:59 +00:00
unarProcess.Start();
unarProcess.WaitForExit();
unarOut = unarProcess.StandardOutput.ReadToEnd();
}
catch
{
FailedWithText?.Invoke(this,
new ErrorEventArgs
{
Message = Localization.CannotRunUnAr
});
2020-08-22 21:19:34 +01:00
2024-11-09 01:37:59 +00:00
return false;
}
2020-08-22 21:19:34 +01:00
2024-11-09 01:37:59 +00:00
try
{
var lsarProcess = new Process
2020-08-22 21:19:34 +01:00
{
StartInfo =
{
2024-11-09 01:37:59 +00:00
FileName = lsarPath,
2020-08-22 21:19:34 +01:00
CreateNoWindow = true,
RedirectStandardOutput = true,
2024-11-09 01:37:59 +00:00
UseShellExecute = false
2020-08-22 21:19:34 +01:00
}
};
2024-11-09 01:37:59 +00:00
lsarProcess.Start();
lsarProcess.WaitForExit();
lsarOut = lsarProcess.StandardOutput.ReadToEnd();
}
catch
{
FailedWithText?.Invoke(this,
new ErrorEventArgs
{
Message = Localization.CannotRunLsAr
});
return false;
}
2020-08-22 21:19:34 +01:00
2024-11-09 01:37:59 +00:00
if(!unarOut.StartsWith("unar ", StringComparison.CurrentCulture))
{
FailedWithText?.Invoke(this,
new ErrorEventArgs
{
Message = Localization.NotCorrectUnAr
});
return false;
}
if(!lsarOut.StartsWith("lsar ", StringComparison.CurrentCulture))
{
FailedWithText?.Invoke(this,
new ErrorEventArgs
{
Message = Localization.NotCorrectLsAr
});
2020-08-23 21:21:55 +01:00
2024-11-09 01:37:59 +00:00
return false;
2020-08-22 21:19:34 +01:00
}
2024-11-09 01:37:59 +00:00
var versionProcess = new Process
{
StartInfo =
{
FileName = unarPath,
CreateNoWindow = true,
RedirectStandardOutput = true,
UseShellExecute = false,
Arguments = "-v"
}
};
versionProcess.Start();
versionProcess.WaitForExit();
FinishedWithText?.Invoke(this,
new MessageEventArgs
{
Message = versionProcess.StandardOutput.ReadToEnd().TrimEnd('\n')
});
return true;
2020-08-22 05:14:52 +01:00
}
}