diff --git a/ProjectLighthouse.Tests/ExampleFiles/TestFarc.farc b/ProjectLighthouse.Tests/ExampleFiles/TestFarc.farc new file mode 100644 index 00000000..3a0eae8e --- /dev/null +++ b/ProjectLighthouse.Tests/ExampleFiles/TestFarc.farc @@ -0,0 +1 @@ +FSHbFARC \ No newline at end of file diff --git a/ProjectLighthouse.Tests/ExampleFiles/TestLevel.lvl b/ProjectLighthouse.Tests/ExampleFiles/TestLevel.lvl new file mode 100644 index 00000000..9491cbb5 Binary files /dev/null and b/ProjectLighthouse.Tests/ExampleFiles/TestLevel.lvl differ diff --git a/ProjectLighthouse.Tests/ExampleFiles/TestScript.ff b/ProjectLighthouse.Tests/ExampleFiles/TestScript.ff new file mode 100644 index 00000000..ba1ce0e4 --- /dev/null +++ b/ProjectLighthouse.Tests/ExampleFiles/TestScript.ff @@ -0,0 +1,3 @@ +FSH + +this is not my stuff to upload so its just gonna be a file like this for now :/ \ No newline at end of file diff --git a/ProjectLighthouse.Tests/ExampleFiles/TestTexture.tex b/ProjectLighthouse.Tests/ExampleFiles/TestTexture.tex new file mode 100644 index 00000000..340b4e89 Binary files /dev/null and b/ProjectLighthouse.Tests/ExampleFiles/TestTexture.tex differ diff --git a/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj b/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj index cd72611b..066ada22 100644 --- a/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj +++ b/ProjectLighthouse.Tests/ProjectLighthouse.Tests.csproj @@ -23,7 +23,9 @@ </ItemGroup> <ItemGroup> - <ProjectReference Include="..\ProjectLighthouse\ProjectLighthouse.csproj" /> + <ProjectReference Include="..\ProjectLighthouse\ProjectLighthouse.csproj" /> + <Content Include="ExampleFiles\**"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </Content> </ItemGroup> - </Project> diff --git a/ProjectLighthouse.Tests/Tests/FileTypeTests.cs b/ProjectLighthouse.Tests/Tests/FileTypeTests.cs new file mode 100644 index 00000000..f3484871 --- /dev/null +++ b/ProjectLighthouse.Tests/Tests/FileTypeTests.cs @@ -0,0 +1,53 @@ +using System; +using System.IO; +using System.Net; +using System.Text; +using ProjectLighthouse.Types.Files; +using Xunit; + +namespace ProjectLighthouse.Tests { + public class FileTypeTests { + [Fact] + public void ShouldRecognizeLevel() { + LbpFile file = new(File.ReadAllBytes("ExampleFiles/TestLevel.lvl")); + Assert.True(file.FileType == LbpFileType.Level); + } + + [Fact] + public void ShouldRecognizeScript() { + LbpFile file = new(File.ReadAllBytes("ExampleFiles/TestScript.ff")); + Assert.True(file.FileType == LbpFileType.Script); + } + + [Fact] + public void ShouldRecognizeTexture() { + LbpFile file = new(File.ReadAllBytes("ExampleFiles/TestTexture.tex")); + Assert.True(file.FileType == LbpFileType.Texture); + } + + [Fact] + public void ShouldRecognizeFileArchive() { + LbpFile file = new(File.ReadAllBytes("ExampleFiles/TestFarc.farc")); + Assert.True(file.FileType == LbpFileType.FileArchive); + } + + [Fact] + public void ShouldNotRecognizeFileArchiveAsScript() { + LbpFile file = new(File.ReadAllBytes("ExampleFiles/TestFarc.farc")); + Assert.False(file.FileType == LbpFileType.Script); + Assert.True(file.FileType == LbpFileType.FileArchive); + } + + [Fact] + public void ShouldRecognizeNothingAsUnknown() { + LbpFile file = new(Array.Empty<byte>()); + Assert.True(file.FileType == LbpFileType.Unknown); + } + + [Fact] + public void ShouldRecognizeGarbageAsUnknown() { + LbpFile file = new(Encoding.ASCII.GetBytes("free pc only $900")); + Assert.True(file.FileType == LbpFileType.Unknown); + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Controllers/PublishController.cs b/ProjectLighthouse/Controllers/PublishController.cs index f94e4292..d0839e30 100644 --- a/ProjectLighthouse/Controllers/PublishController.cs +++ b/ProjectLighthouse/Controllers/PublishController.cs @@ -49,6 +49,7 @@ namespace ProjectLighthouse.Controllers { await database.SaveChangesAsync(); slot.LocationId = l.Id; slot.CreatorId = user.UserId; + if(slot.BackgroundHash == null) slot.BackgroundHash = ""; database.Slots.Add(slot); await database.SaveChangesAsync(); diff --git a/ProjectLighthouse/Helpers/BinaryHelper.cs b/ProjectLighthouse/Helpers/BinaryHelper.cs index 6b66ff1c..9d2e18e3 100644 --- a/ProjectLighthouse/Helpers/BinaryHelper.cs +++ b/ProjectLighthouse/Helpers/BinaryHelper.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Text; @@ -21,5 +22,17 @@ namespace ProjectLighthouse.Helpers { readByte = reader.ReadByte(); } while(readByte != byteToReadTo); } + + public static byte[] ReadLastBytes(BinaryReader reader, int count, bool restoreOldPosition = true) { + long oldPosition = reader.BaseStream.Position; + + if(reader.BaseStream.Length < count) return Array.Empty<byte>(); + + reader.BaseStream.Position = reader.BaseStream.Length - count; + byte[] data = reader.ReadBytes(count); + + if(restoreOldPosition) reader.BaseStream.Position = oldPosition; + return data; + } } } \ No newline at end of file diff --git a/ProjectLighthouse/Helpers/FileHelper.cs b/ProjectLighthouse/Helpers/FileHelper.cs new file mode 100644 index 00000000..31fff6eb --- /dev/null +++ b/ProjectLighthouse/Helpers/FileHelper.cs @@ -0,0 +1,38 @@ +using System; +using System.IO; +using System.Text; +using ProjectLighthouse.Types.Files; + +namespace ProjectLighthouse.Helpers { + public static class FileHelper { + public static bool IsFileSafe(LbpFile file) { + if(file.FileType == LbpFileType.Unknown) file.FileType = DetermineFileType(file.Data); + + return file.FileType switch { + LbpFileType.Texture => true, + LbpFileType.Script => false, + LbpFileType.Level => true, + LbpFileType.FileArchive => false, + LbpFileType.Unknown => false, + _ => throw new ArgumentOutOfRangeException(nameof(file), "Unknown file type."), + }; + } + + public static LbpFileType DetermineFileType(byte[] data) { + using MemoryStream ms = new(data); + using BinaryReader reader = new(ms); + + string footer = Encoding.ASCII.GetString(BinaryHelper.ReadLastBytes(reader, 4)); + if(footer == "FARC") return LbpFileType.FileArchive; + + byte[] header = reader.ReadBytes(3); + + return Encoding.ASCII.GetString(header) switch { + "TEX" => LbpFileType.Texture, + "FSH" => LbpFileType.Script, + "LVL" => LbpFileType.Level, + _ => LbpFileType.Unknown, + }; + } + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Types/Files/LbpFile.cs b/ProjectLighthouse/Types/Files/LbpFile.cs new file mode 100644 index 00000000..710f9647 --- /dev/null +++ b/ProjectLighthouse/Types/Files/LbpFile.cs @@ -0,0 +1,22 @@ +using System.IO; +using ProjectLighthouse.Helpers; + +namespace ProjectLighthouse.Types.Files { + public class LbpFile { + public LbpFile(byte[] data) { + this.Data = data; + this.FileType = FileHelper.DetermineFileType(data); + } + + /// <summary> + /// The type of file. + /// </summary> + public LbpFileType FileType; + + /// <summary> + /// A buffer of the file's data. + /// </summary> + public readonly byte[] Data; + + } +} \ No newline at end of file diff --git a/ProjectLighthouse/Types/Files/LbpFileType.cs b/ProjectLighthouse/Types/Files/LbpFileType.cs new file mode 100644 index 00000000..418cb97f --- /dev/null +++ b/ProjectLighthouse/Types/Files/LbpFileType.cs @@ -0,0 +1,9 @@ +namespace ProjectLighthouse.Types.Files { + public enum LbpFileType { + Script, // .ff, FSH + Texture, // TEX + Level, // LVL + FileArchive, // .farc, (ends with FARC) + Unknown, + } +} \ No newline at end of file