Skip to content
Open
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
21 changes: 21 additions & 0 deletions GRF.Tests/GRF.Tests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="xunit" Version="2.6.6" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.6">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\GRF\GRF.csproj" />
</ItemGroup>

</Project>
18 changes: 18 additions & 0 deletions GRF.Tests/GrfThreadExtractTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using GRF.Threading;
using Xunit;

namespace GRF.Tests {
public class GrfThreadExtractTests {
[Fact]
public void IsLuaBytecode_ReturnsTrueForMagicHeader() {
byte[] data = { 0x1b, 0x4c, 0x75, 0x61, 0x00 };
Assert.True(GrfThreadExtract.IsLuaBytecode(data));
}

[Fact]
public void IsLuaBytecode_ReturnsFalseForNonMagicHeader() {
byte[] data = { 0x00, 0x4c, 0x75, 0x61 };
Assert.False(GrfThreadExtract.IsLuaBytecode(data));
}
}
}
3 changes: 3 additions & 0 deletions GRF/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("GRF.Tests")]
1 change: 1 addition & 0 deletions GRF/GrfSystem/Settings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public static class Settings {
public static bool CpuMonitoringEnabled = true;
public static bool LockFiles { get; set; }
public static bool PreserveDirectoryStructure { get; set; }
public static bool DecompileLubOnExtract { get; set; }
public static Action OnSavingFailed;
public static float CpuUsageCritical = 90f;
public static bool AddHashFileForThor = false;
Expand Down
64 changes: 60 additions & 4 deletions GRF/Threading/GrfThreadExtract.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,51 @@
using System.Linq;
using System.Threading;
using GRF.Core;
using GRF.FileFormats.LubFormat;
using GRF.GrfSystem;
using Utilities.Extension;
using Utilities.Services;

namespace GRF.Threading {
/// <summary>
/// This class extracts and copy the files from the GRF from a given range
/// It's used to optimize the data transfer.
/// </summary>
public class GrfThreadExtract : GrfWriterThread<FileEntry> {
private static readonly byte[] _luaBytecodeMagic = { 0x1b, 0x4c, 0x75, 0x61 };
private const int _bufferSize = 8388608;
private readonly StreamReadBlockInfo _srb = new StreamReadBlockInfo(_bufferSize);

internal static bool IsLuaBytecode(byte[] data) {
if (data == null || data.Length < _luaBytecodeMagic.Length)
return false;

for (int i = 0; i < _luaBytecodeMagic.Length; i++) {
if (data[i] != _luaBytecodeMagic[i])
return false;
}

return true;
}

private static bool _shouldDecompileLub(FileEntry entry, byte[] data) {
if (!Settings.DecompileLubOnExtract)
return false;

string extension = entry.RelativePath.GetExtension();
return extension != null && extension.Equals(".lub", StringComparison.OrdinalIgnoreCase) && IsLuaBytecode(data);
}

private static byte[] _tryDecompileLub(byte[] data) {
try {
string text = new Lub(data).Decompile();
return EncodingService.DisplayEncoding.GetBytes(text);
}
catch {
return data;
}
}

public override void Start() {
new Thread(_start) { Name = "GRF - Extract files thread " + StartIndex }.Start();
}
Expand Down Expand Up @@ -73,6 +107,10 @@ private void _start() {
else
dataTmp = Compression.Decompress(dataTmp, entry.SizeDecompressed);

if (_shouldDecompileLub(entry, dataTmp)) {
dataTmp = _tryDecompileLub(dataTmp);
}
Comment thread
jezztify marked this conversation as resolved.

using (FileStream fs = new FileStream(entry.ExtractionFilePath, FileMode.Create, FileAccess.Write, FileShare.Read))
fs.Write(dataTmp, 0, dataTmp.Length);
}
Expand All @@ -96,10 +134,28 @@ private void _start() {
if (IsPaused)
Pause();

if (File.Exists(entryCopy.ExtractionFilePath))
File.Delete(entryCopy.ExtractionFilePath);

File.Copy(entryCopy.SourceFilePath, entryCopy.ExtractionFilePath);
try {
if (File.Exists(entryCopy.ExtractionFilePath))
File.Delete(entryCopy.ExtractionFilePath);

if (Settings.DecompileLubOnExtract) {
byte[] rawData = File.ReadAllBytes(entryCopy.SourceFilePath);
if (_shouldDecompileLub(entryCopy, rawData)) {
rawData = _tryDecompileLub(rawData);
File.WriteAllBytes(entryCopy.ExtractionFilePath, rawData);
}
else {
File.WriteAllBytes(entryCopy.ExtractionFilePath, rawData);
}
}
else {
File.Copy(entryCopy.SourceFilePath, entryCopy.ExtractionFilePath);
}
}
catch (Exception err) {
Error = true;
Exception = new Exception("#File: " + entryCopy.RelativePath, err);
}
}

NumberOfFilesProcessed++;
Expand Down
6 changes: 6 additions & 0 deletions GRFEditor.sln
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GRFEditor", "GRFEditor\GRFE
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GRF", "GRF\GRF.csproj", "{F21476B8-04E5-43EE-AD1B-CF7BD2ED3D4F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GRF.Tests", "GRF.Tests\GRF.Tests.csproj", "{E59F3B21-1C1D-4D68-B137-821E89C2F52D}"
EndProject
Comment thread
jezztify marked this conversation as resolved.
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TokeiLibrary", "TokeiLibrary\TokeiLibrary.csproj", "{812355C7-A277-4E8C-B6A0-306310F8F183}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ExampleProject", "ExampleProject\ExampleProject.csproj", "{8030A7E4-9456-481B-A111-7AF0DB19ABFD}"
Expand Down Expand Up @@ -44,6 +46,10 @@ Global
{F21476B8-04E5-43EE-AD1B-CF7BD2ED3D4F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F21476B8-04E5-43EE-AD1B-CF7BD2ED3D4F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F21476B8-04E5-43EE-AD1B-CF7BD2ED3D4F}.Release|Any CPU.Build.0 = Release|Any CPU
{E59F3B21-1C1D-4D68-B137-821E89C2F52D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E59F3B21-1C1D-4D68-B137-821E89C2F52D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E59F3B21-1C1D-4D68-B137-821E89C2F52D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E59F3B21-1C1D-4D68-B137-821E89C2F52D}.Release|Any CPU.Build.0 = Release|Any CPU
{812355C7-A277-4E8C-B6A0-306310F8F183}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{812355C7-A277-4E8C-B6A0-306310F8F183}.Debug|Any CPU.Build.0 = Debug|Any CPU
{812355C7-A277-4E8C-B6A0-306310F8F183}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down
8 changes: 8 additions & 0 deletions GRFEditor/ApplicationConfiguration/GrfEditorConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,14 @@ public static bool AlwaysOpenAfterExtraction {
set { ConfigAsker["[GRFEditor - ExtractingService - Always open after extraction]"] = value.ToString(); }
}

public static bool DecompileLubOnExtract {
get { return Boolean.Parse(ConfigAsker["[GRFEditor - ExtractingService - Decompile LUB on extract]", false.ToString()]); }
set {
ConfigAsker["[GRFEditor - ExtractingService - Decompile LUB on extract]"] = value.ToString();
Settings.DecompileLubOnExtract = value;
}
}

public static bool AutomaticallyPlaceFiles {
get { return Boolean.Parse(ConfigAsker["[GRFEditor - AutomaticallyPlaceFiles]", false.ToString()]); }
set { ConfigAsker["[GRFEditor - AutomaticallyPlaceFiles]"] = value.ToString(); }
Expand Down
1 change: 1 addition & 0 deletions GRFEditor/EditorMainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ private int _loadBasicSettings() {
Settings.CpuMonitoringEnabled = Configuration.CpuPerformanceManagement;
Settings.LockFiles = Configuration.LockFiles;
Settings.AddHashFileForThor = Configuration.AddHashFileForThor;
Settings.DecompileLubOnExtract = Configuration.DecompileLubOnExtract;
TemporaryFilesManager.ClearTemporaryFiles();
Settings.OnSavingFailed = _onSavingFailed;
return encoding;
Expand Down
1 change: 1 addition & 0 deletions GRFEditor/WPF/SettingsDialog.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ public SettingsDialog(GrfHolder grfData, EditorMainWindow editor)
_add(_gridGeneral, row = 9, "CPU performance management", "This option monitors your CPU usage and it'll be used to dynamically change the number of threads doing work. " +
"The main purpose of this feature is to avoid situations where the CPU could reach 100% usage and hence lagging the entire system.", () => GrfEditorConfiguration.CpuPerformanceManagement, () => Settings.CpuMonitoringEnabled = GrfEditorConfiguration.CpuPerformanceManagement);
_add(_gridGeneral, ++row, "Always open folder after extraction", "Prevents services from showing a file or folder in Windows Explorer after an extraction.", () => GrfEditorConfiguration.AlwaysOpenAfterExtraction, () => OpeningService.Enabled = GrfEditorConfiguration.AlwaysOpenAfterExtraction);
_add(_gridGeneral, ++row, "Decompile LUB on extraction", "If enabled, compiled .lub files will be decompiled to text during extraction while keeping the .lub extension.", () => GrfEditorConfiguration.DecompileLubOnExtract, () => Settings.DecompileLubOnExtract = GrfEditorConfiguration.DecompileLubOnExtract);
_add(_gridGeneral, ++row, "Always reopen latest opened GRF", "Always reopen the most recently opened GRF when starting the application.", () => GrfEditorConfiguration.AlwaysReopenLatestGrf);
//_add(_gridGeneral, ++row, "Use the opened GRF path to extract", "If enabled, the files extraced will be placed in the same folder as the GRF. They will be placed within the working directory of the application otherwise.", () => GrfEditorConfiguration.UseGrfPathToExtract);
_add(_gridGeneral, ++row, "Enable windows ownership", "Makes the windows linked together, resulting in only being able to focus on one at a time. Disabling this features enables you to open multiple windows (as in tools).", () => Configuration.EnableWindowsOwnership);
Expand Down