diff --git a/PCK-Studio/Classes/FileTypes/Bink.cs b/PCK-Studio/Classes/FileTypes/Bink.cs deleted file mode 100644 index db79fafa..00000000 --- a/PCK-Studio/Classes/FileTypes/Bink.cs +++ /dev/null @@ -1,179 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Reflection; -using System.Runtime.InteropServices; - -namespace PckStudio.Classes -{ - internal class Bink - { - [DllImport("kernel32.dll")] - public static extern IntPtr LoadLibrary(string lpFileName); - - [DllImport("kernel32.dll")] - public static extern IntPtr FreeLibrary(IntPtr library); - - public int temp_error_code; - string binka_enc_loc; - string mss32_loc; - string binkawin_loc; - public string working = null; - - public async void WavToBinka(string infile, string outFile, int compression) - { - var process = Process.Start(new ProcessStartInfo - { - FileName = binka_enc_loc, - Arguments = $"\"{infile}\" \"{outFile}\" -s -b{compression}", - UseShellExecute = true, - CreateNoWindow = true, - WindowStyle = ProcessWindowStyle.Hidden - }); - process.WaitForExit(); - temp_error_code = process.ExitCode; - } - - public unsafe void BinkaToWav(string infile, string outFile) - { - string[] array2 = createArg(infile, outFile); - byte[] array3 = File.ReadAllBytes(array2[0]); - Console.WriteLine(array3.Length); - uint num = 0U; - AIL_set_redist_directory("."); - AIL_startup(); - IntPtr intPtr; - // crash happens in AIL_decompress_ASI - if (AIL_decompress_ASI(array3, (uint)array3.Length, ".binka", &intPtr, &num, 0U) == 0) - throw new Exception("AIL ERROR"); - byte[] array4 = new byte[num]; - Marshal.Copy(intPtr, array4, 0, array4.Length); - AIL_mem_free_lock(intPtr); - AIL_shutdown(); - File.WriteAllBytes(array2[1], array4); - } - - public void SetUpBinka() - { - if (working == null) - { - working = (Path.GetTempPath() + "PCKStudio").Replace("\\","/"); - Directory.CreateDirectory(working); - binka_enc_loc = ExtractResource("binka_encode.exe", working); - mss32_loc = ExtractResource("mss32.dll", working); - binkawin_loc = ExtractResource("binkawin.asi", working); - library = LoadLibrary(mss32_loc); - } - else - { - binka_enc_loc = working + "\\binka_encode.exe"; - mss32_loc = working + "\\mss32.dll"; - binkawin_loc = working + "\\binkawin.asi"; - } - } - - public void CleanUpBinka() - { - File.Delete(binka_enc_loc); - File.Delete(binkawin_loc); - while (File.Exists(mss32_loc)) - { - try - { - File.Delete(mss32_loc); - } - catch - { - FreeLibrary(library); - } - } - Directory.Delete(working); - } - - private static string getType(string loc) - { - string a = Path.GetExtension(loc).ToLower(); - bool flag = a == ".binka"; - string result; - if (flag) - { - result = "BINKA"; - } - else - { - bool flag2 = !(a == ".wav"); - if (flag2) - { - throw new Exception("File type not valid. To use MP3 or other audio formats, convert to wav format before using this tool"); - } - result = "WAV"; - } - return result; - } - - private static string[] createArg(string inFile, string outdir = null) - { - string[] array = new string[2]; - array[0] = inFile; - string[] array2 = array; - string type = getType(inFile); - bool flag = type == "BINKA"; - if (flag) - { - array2[1] = ((outdir.Length <= 3) ? Path.GetFullPath(inFile.Replace(".binka", ".wav")) : (outdir + "\\" + Path.GetFileName(inFile.Replace(".binka", ".wav")))); - } - else - { - bool flag2 = type == "WAV"; - if (flag2) - { - array2[1] = ((outdir.Length <= 3) ? Path.GetFullPath(inFile.Replace(".wav", ".binka")) : (outdir + "\\" + Path.GetFileName(inFile.Replace(".wav", ".binka")))); - } - } - bool flag3 = !Directory.Exists(Path.GetDirectoryName(array2[1])); - if (flag3) - { - Directory.CreateDirectory(Path.GetDirectoryName(array2[1])); - } - return array2; - } - - internal static string ExtractResource(string resource, string working) - { - object ob = Properties.Resources.ResourceManager.GetObject(Path.GetFileNameWithoutExtension(resource)); - byte[] myResBytes = (byte[])ob; - if(File.Exists(Path.Combine(working, resource))) File.Delete(Path.Combine(working, resource)); - using (FileStream fsDst = new FileStream(Path.Combine(working, resource), FileMode.CreateNew, FileAccess.Write)) - { - fsDst.Write(myResBytes, 0, myResBytes.Length); - fsDst.Close(); - fsDst.Dispose(); - } - return "\"" + working + "/" + resource + "\""; - } - - [DllImport("mss32.dll", EntryPoint = "_AIL_decompress_ASI@24")] - private unsafe static extern int AIL_decompress_ASI([MarshalAs(UnmanagedType.LPArray)] byte[] indata, uint insize, [MarshalAs(UnmanagedType.LPStr)] string ext, IntPtr* result, uint* resultsize, uint zero); - - [DllImport("mss32.dll", EntryPoint = "_AIL_last_error@0")] - private static extern IntPtr AIL_last_error(); - - [DllImport("mss32.dll", EntryPoint = "_AIL_set_redist_directory@4")] - private static extern IntPtr AIL_set_redist_directory([MarshalAs(UnmanagedType.LPStr)] string redistDir); - - [DllImport("mss32.dll", EntryPoint = "_AIL_mem_free_lock@4")] - private static extern void AIL_mem_free_lock(IntPtr ptr); - - [DllImport("mss32.dll", EntryPoint = "_AIL_startup@0")] - private static extern int AIL_startup(); - - [DllImport("mss32.dll", EntryPoint = "_AIL_shutdown@0")] - private static extern int AIL_shutdown(); - - public Bink() - { - } - - private static IntPtr library; - } -} diff --git a/PCK-Studio/Classes/FileTypes/Binka.cs b/PCK-Studio/Classes/FileTypes/Binka.cs new file mode 100644 index 00000000..8db5f609 --- /dev/null +++ b/PCK-Studio/Classes/FileTypes/Binka.cs @@ -0,0 +1,144 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; + +namespace PckStudio.Classes +{ + internal static class Binka + { + private class LibHandle + { + [DllImport("kernel32.dll")] + public static extern IntPtr LoadLibrary(string lpFileName); + + [DllImport("kernel32.dll")] + public static extern int FreeLibrary(IntPtr library); + + private IntPtr libHandle; + + public IntPtr Handle => libHandle; + + public LibHandle(string libraryPath) + { + libHandle = LoadLibrary(libraryPath); + } + + ~LibHandle() + { + FreeLibrary(libHandle); + } + } + + private static string dataCache = Program.AppDataCache; + + public static uint LastAILErrorCode = 0xffffffff; + + public static int FromWav(string inputFilepath, string outputFilepath, int compressionLevel) + { + var process = Process.Start(new ProcessStartInfo + { + FileName = GetAndCacheResource("binka_encode.exe"), + Arguments = $"\"{inputFilepath}\" \"{outputFilepath}\" -s -b{compressionLevel}", + UseShellExecute = true, + CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden + }); + process.WaitForExit(); + return process.ExitCode; + } + + public static unsafe void ToWav(string inputFilename, string outputFilepath) + { + // handle should be closed when function gets out of scope + LibHandle mss32LibHandle = new LibHandle(GetAndCacheResource("mss32.dll")); + + string ext = Path.GetExtension(inputFilename).ToLower(); + switch (ext) + { + case ".binka": + inputFilename = inputFilename.Replace(".binka", ".wav"); + break; + case ".wav": + inputFilename = inputFilename.Replace(".wav", ".binka"); + break; + default: + throw new NotSupportedException(nameof(ext)+":"+ext); + } + string outputDirectory = Path.GetDirectoryName(outputFilepath); + Directory.CreateDirectory(outputDirectory); + string destinationFilepath = Path.Combine(outputDirectory, Path.GetFileName(inputFilename)); + + byte[] inputFiledata = File.ReadAllBytes(inputFilename); + Debug.WriteLine($"{nameof(inputFiledata)}: {inputFiledata.Length}"); + + AILInternalCalls.SetRedistDirectory("."); + AILInternalCalls.Startup(); // __fastcall + + int resultBufferSize = 0; + IntPtr resultBuffer = new IntPtr(); + // crash happens in AIL_decompress_ASI + LastAILErrorCode = (uint)AILInternalCalls.DecompressASI(inputFiledata, inputFiledata.Length, ".binka", resultBuffer, &resultBufferSize); + Debug.WriteLine("AIL Error Code: " + LastAILErrorCode.ToString()); + + byte[] buffer = new byte[resultBufferSize]; + Marshal.Copy(resultBuffer, buffer, 0, resultBufferSize); + AILInternalCalls.MemFreeLock(resultBuffer); + AILInternalCalls.Shutdown(); + File.WriteAllBytes(destinationFilepath, buffer); + } + + // Move to a cache class ? + private static string GetAndCacheResource(string resourceName) + { + _ = resourceName ?? throw new ArgumentNullException(nameof(resourceName)); + string destinationFilepath = Path.Combine(dataCache, resourceName); + if (!File.Exists(destinationFilepath)) + { + byte[] resourceData = ExtractResource(resourceName); + using (FileStream fsDst = File.OpenWrite(destinationFilepath)) + { + fsDst.Write(resourceData, 0, resourceData.Length); + } + } + return destinationFilepath; + } + + internal static byte[] ExtractResource(string resourceName) + { + byte[] resourceData = (byte[])Properties.Resources.ResourceManager.GetObject(Path.GetFileNameWithoutExtension(resourceName)); + return resourceData; + } + + private class AILInternalCalls + { + public delegate int AIL_decomp_func(); + + [DllImport("mss32.dll", EntryPoint = "_AIL_decompress_ASI@24")] + public unsafe static extern int DecompressASI( + [MarshalAs(UnmanagedType.LPArray)] byte[] indata, + int insize, + [MarshalAs(UnmanagedType.LPStr)] string ext, + IntPtr result, + int *resultSize, + [MarshalAs(UnmanagedType.FunctionPtr)] AIL_decomp_func func = null); + + [DllImport("mss32.dll", EntryPoint = "_AIL_last_error@0")] + [return: MarshalAs(UnmanagedType.LPStr)] + public static extern string LastError(); + + [DllImport("mss32.dll", EntryPoint = "_AIL_set_redist_directory@4")] + [return: MarshalAs(UnmanagedType.LPStr)] + public static extern string SetRedistDirectory([MarshalAs(UnmanagedType.LPStr)] string redistDir); + + [DllImport("mss32.dll", EntryPoint = "_AIL_mem_free_lock@4")] + public static extern void MemFreeLock(IntPtr ptr); + + [DllImport("mss32.dll", EntryPoint = "_AIL_startup@0")] + public static extern int Startup(); + + [DllImport("mss32.dll", EntryPoint = "_AIL_shutdown@0")] + public static extern int Shutdown(); + } + } +} diff --git a/PCK-Studio/Forms/Editor/AudioEditor.cs b/PCK-Studio/Forms/Editor/AudioEditor.cs index 4b38e025..3340a54d 100644 --- a/PCK-Studio/Forms/Editor/AudioEditor.cs +++ b/PCK-Studio/Forms/Editor/AudioEditor.cs @@ -6,6 +6,7 @@ using System.Threading.Tasks; using System.Windows.Forms; using System.Diagnostics; using MetroFramework.Forms; +using PckStudio.Classes; using PckStudio.Classes.FileTypes; using PckStudio.Classes.IO.PCK; using PckStudio.Forms.Additional_Popups.Audio; @@ -18,7 +19,6 @@ namespace PckStudio.Forms.Editor public partial class AudioEditor : MetroForm { public string defaultType = "yes"; - Classes.Bink BINK = new Classes.Bink(); PCKAudioFile audioFile = null; PCKFile.FileData audioPCK; LOCFile loc; @@ -55,8 +55,6 @@ namespace PckStudio.Forms.Editor loc = locFile; _isLittleEndian = isLittleEndian; - BINK.SetUpBinka(); - audioPCK = file; using (var stream = new MemoryStream(file.data)) { @@ -185,7 +183,8 @@ namespace PckStudio.Forms.Editor async void ProcessEntries(string[] FileList) { - foreach (string file in FileList) + int exitCode = 0; + foreach (string file in FileList) { if (Path.GetExtension(file) == ".binka" || Path.GetExtension(file) == ".wav") { @@ -214,14 +213,14 @@ namespace PckStudio.Forms.Editor await Task.Run(() => { - BINK.WavToBinka(file, new_loc, (int)compressionUpDown.Value); + exitCode = Binka.FromWav(file, new_loc, (int)compressionUpDown.Value); }); waitDiag.Close(); waitDiag.Dispose(); Cursor.Current = Cursors.Default; - if (BINK.temp_error_code != 0) continue; + if (exitCode != 0) continue; } else if (!duplicate_song) { @@ -404,7 +403,10 @@ namespace PckStudio.Forms.Editor { if (!parent.CreateDataFolder()) return; - OpenFileDialog ofn = new OpenFileDialog(); + int exitCode = 0; + + + OpenFileDialog ofn = new OpenFileDialog(); ofn.Multiselect = true; ofn.Filter = "Supported audio files (*.binka,*.wav)|*.binka;*.wav"; ofn.Title = "Please choose WAV or BINKA files to replace existing track files"; @@ -436,16 +438,16 @@ namespace PckStudio.Forms.Editor await Task.Run(() => { - BINK.WavToBinka(file, new_loc, (int)compressionUpDown.Value); + exitCode = Binka.FromWav(file, new_loc, (int)compressionUpDown.Value); }); waitDiag.Close(); waitDiag.Dispose(); Cursor.Current = Cursors.Default; - if (BINK.temp_error_code != 0) continue; + if (exitCode != 0) continue; } - else if(file_ext == ".binka") File.Copy(file, Path.Combine(parent.GetDataPath(), Path.GetFileName(file))); + else if(file_ext == ".binka") File.Copy(file, Path.Combine(parent.GetDataPath(), Path.GetFileName(file))); } } @@ -453,7 +455,7 @@ namespace PckStudio.Forms.Editor { if (treeView2.SelectedNode != null && treeView1.SelectedNode.Tag is PCKAudioFile.AudioCategory) { - BINK.BinkaToWav(Path.Combine(parent.GetDataPath(), treeView2.SelectedNode.Text + ".binka"), Path.Combine(parent.GetDataPath())); + Binka.ToWav(Path.Combine(parent.GetDataPath(), treeView2.SelectedNode.Text + ".binka"), Path.Combine(parent.GetDataPath())); } } } diff --git a/PCK-Studio/PckStudio.csproj b/PCK-Studio/PckStudio.csproj index e62d00a1..de59ee2d 100644 --- a/PCK-Studio/PckStudio.csproj +++ b/PCK-Studio/PckStudio.csproj @@ -141,7 +141,7 @@ - +