Skip to content

Commit

Permalink
Move Snowberry.IO.SingleFile to this repository
Browse files Browse the repository at this point in the history
  • Loading branch information
VNNCC committed Jan 12, 2025
1 parent b60184a commit cb30cb8
Show file tree
Hide file tree
Showing 24 changed files with 1,360 additions and 19 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ writer.BaseStream.Position = 0;
using var reader = new EndianStreamReader(stream);

_ = reader.ReadInt32(EndianType.BIG);
_ = reader.ReadLong(EndianType.BIG);
_ = reader.ReadInt64(EndianType.BIG);
_ = reader.ReadFloat(EndianType.BIG);
_ = reader.ReadUInt32(EndianType.BIG);
_ = reader.ReadDouble(EndianType.BIG);
Expand All @@ -79,8 +79,8 @@ var buffer = new byte[] { ... };
int offset = ...;
var endianType = EndianType.BIG;

_ = BinaryEndianConverter.ToLong(buffer, endianType);
_ = BinaryEndianConverter.ToLong(buffer, offset, endianType);
_ = BinaryEndianConverter.ToInt64(buffer, endianType);
_ = BinaryEndianConverter.ToInt64(buffer, offset, endianType);
```

## Supported data types
Expand Down
4 changes: 2 additions & 2 deletions src/NuGetPackage.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Platforms>AnyCPU;x64;x86</Platforms>

<Authors>Snowberry Software</Authors>
<AssemblyVersion>2.1.0.0</AssemblyVersion>
<AssemblyVersion>3.0.0.0</AssemblyVersion>
<VersionPrefix>$(AssemblyVersion)</VersionPrefix>

<IsPackable>true</IsPackable>
Expand All @@ -14,7 +14,7 @@

<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<IncludeBuildOutput>true</IncludeBuildOutput>
<Copyright>Copyright © 2024 Snowberry Software</Copyright>
<Copyright>Copyright © 2025 Snowberry Software</Copyright>
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
<PackageProjectUrl>https://github.com/snowberry-software/Snowberry.IO</PackageProjectUrl>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public long BitConverter_Int64()
[Benchmark]
public unsafe long BinaryEndianConverter_Int64()
{
return BinaryEndianConverter.ToLong(_data.AsSpan(), EndianType.LITTLE);
return BinaryEndianConverter.ToInt64(_data.AsSpan(), EndianType.LITTLE);
}

[Benchmark]
Expand All @@ -33,7 +33,7 @@ public long BitConverter_Offset_Int64()
[Benchmark]
public unsafe long BinaryEndianConverter_Offset_Int64()
{
return BinaryEndianConverter.ToLong(_data.AsSpan(), 4, EndianType.LITTLE);
return BinaryEndianConverter.ToInt64(_data.AsSpan(), 4, EndianType.LITTLE);
}

[Benchmark]
Expand All @@ -47,7 +47,7 @@ public long BitConverter_BigE_Int64()
[Benchmark]
public unsafe long BinaryEndianConverter_BigE_Int64()
{
return BinaryEndianConverter.ToLong(_data.AsSpan(), EndianType.BIG);
return BinaryEndianConverter.ToInt64(_data.AsSpan(), EndianType.BIG);
}

[Benchmark]
Expand All @@ -61,6 +61,6 @@ public long BitConverter_Offset_BigE_Int64()
[Benchmark]
public unsafe long BinaryEndianConverter_Offset_BigE_Int64()
{
return BinaryEndianConverter.ToLong(_data.AsSpan(), 4, EndianType.BIG);
return BinaryEndianConverter.ToInt64(_data.AsSpan(), 4, EndianType.BIG);
}
}
6 changes: 3 additions & 3 deletions src/Snowberry.IO.Common/BinaryEndianConverter.Offsets.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public static partial class BinaryEndianConverter
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static unsafe long ToLong(Span<byte> data, int offset, EndianType endian)
public static unsafe long ToInt64(Span<byte> data, int offset, EndianType endian)
{
if (endian == EndianType.LITTLE)
return Unsafe.ReadUnaligned<long>(ref data[offset]);
Expand All @@ -23,7 +23,7 @@ public static unsafe long ToLong(Span<byte> data, int offset, EndianType endian)
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization)]
#endif
public static unsafe ulong ToULong(Span<byte> data, int offset, EndianType endian)
public static unsafe ulong ToUInt64(Span<byte> data, int offset, EndianType endian)
{
if (endian == EndianType.LITTLE)
return Unsafe.ReadUnaligned<ulong>(ref data[offset]);
Expand Down Expand Up @@ -137,7 +137,7 @@ public static unsafe double ToDouble(Span<byte> data, int offset, EndianType end
if (endian == EndianType.LITTLE)
return Unsafe.ReadUnaligned<double>(ref data[offset]);

long temp = ToLong(data, offset, EndianType.BIG);
long temp = ToInt64(data, offset, EndianType.BIG);
return BitConverter.Int64BitsToDouble(temp);
}

Expand Down
6 changes: 3 additions & 3 deletions src/Snowberry.IO.Common/BinaryEndianConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,15 @@ public static unsafe double ToDouble(Span<byte> data, EndianType endian)
if (endian == EndianType.LITTLE)
return Unsafe.ReadUnaligned<double>(ref MemoryMarshal.GetReference(data));

long temp = ToLong(data, EndianType.BIG);
long temp = ToInt64(data, EndianType.BIG);
return BitConverter.Int64BitsToDouble(temp);
}

#if NETCOREAPP3_0_OR_GREATER
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
#endif
public static unsafe long ToLong(Span<byte> data, EndianType endian)
public static unsafe long ToInt64(Span<byte> data, EndianType endian)
{
if (endian == EndianType.LITTLE)
return Unsafe.ReadUnaligned<long>(ref MemoryMarshal.GetReference(data));
Expand All @@ -111,7 +111,7 @@ public static unsafe long ToLong(Span<byte> data, EndianType endian)
[SkipLocalsInit]
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
#endif
public static unsafe ulong ToULong(Span<byte> data, EndianType endian)
public static unsafe ulong ToUInt64(Span<byte> data, EndianType endian)
{
if (endian == EndianType.LITTLE)
return Unsafe.ReadUnaligned<ulong>(ref MemoryMarshal.GetReference(data));
Expand Down
12 changes: 12 additions & 0 deletions src/Snowberry.IO.SingleFile.CLI/Options.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using CommandLine;

namespace Snowberry.IO.SingleFile.CLI;

internal class Options
{
[Option('i', "input", Required = true, HelpText = "Sets the input single file path.")]
public string InputFilePath { get; set; } = string.Empty;

[Option('o', "output", Required = false, HelpText = "Sets the output directory.")]
public string OutputDirectory { get; set; } = string.Empty;
}
86 changes: 86 additions & 0 deletions src/Snowberry.IO.SingleFile.CLI/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using CommandLine;
using Serilog;
using Snowberry.IO.SingleFile;
using Snowberry.IO.SingleFile.CLI;

Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.Console()
#if DEBUG
.WriteTo.Debug()
#endif
.CreateLogger();

Parser.Default.ParseArguments<Options>(args)
.WithParsed(o =>
{
if (!File.Exists(o.InputFilePath))
{
Log.Fatal("Could not find input file path: {input}", o.InputFilePath);
Environment.Exit(-1);
}

Log.Information("Processing: {path}", o.InputFilePath);

bool useOutputDirectory = !string.IsNullOrWhiteSpace(o.OutputDirectory);

try
{
using var singleFileBinaryData = SingleFileBinaryData.GetFromFile(o.InputFilePath);

if (singleFileBinaryData == null)
{
Log.Fatal("Specified file is not a published single file!");
Environment.Exit(-1);
}

if (singleFileBinaryData.BundleManifest == null)
return;

var bundleManifest = singleFileBinaryData.BundleManifest;
Log.Information($"{"Bundle ID:",-24} {{id}}", bundleManifest.BundleID);
Log.Information($"{"Bundle Major Version:",-24} {{ver}}", bundleManifest.BundleMajorVersion);
Log.Information($"{"Bundle Minor Version:",-24} {{ver}}", bundleManifest.BundleMinorVersion);
Log.Information($"{"Bundle Flags:",-24} {{flags}}", bundleManifest.Flags);
Log.Information($"{"Bundle File Count:",-24} {{count}}", bundleManifest.FileEntries.Count);
Log.Information("");

string? outputDirectory = useOutputDirectory ? o.OutputDirectory : null;

if (useOutputDirectory && !Directory.Exists(outputDirectory))
Directory.CreateDirectory(outputDirectory!);

for (int i = 0; i < bundleManifest.FileEntries.Count; i++)
{
var fileEntry = bundleManifest.FileEntries[i];

Log.Information("File: {type}/{path}", fileEntry.FileType, fileEntry.RelativePath);

if (useOutputDirectory)
{
using var fileEntryStream = singleFileBinaryData.GetStream(fileEntry);

if (fileEntryStream == null)
{
Log.Fatal(" Could not open stream for file entry!");
Environment.Exit(-1);
}

string filePath = Path.Combine(outputDirectory!, fileEntry.RelativePath);
string? directory = Path.GetDirectoryName(filePath);

if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
Directory.CreateDirectory(directory);

using var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.ReadWrite);
fileEntryStream.CopyTo(fs);
}
}
}
catch (Exception e)
{
Log.Fatal(e, "Could not process file: {input}", o.InputFilePath);
}

Log.Information("Done...");
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"profiles": {
"Snowberry.IO.SingleFile.CLI": {
"commandName": "Project",
"commandLineArgs": ""
}
}
}
22 changes: 22 additions & 0 deletions src/Snowberry.IO.SingleFile.CLI/Snowberry.IO.SingleFile.CLI.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="Serilog" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="Serilog.Sinks.Debug" Version="3.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Snowberry.IO.SingleFile\Snowberry.IO.SingleFile.csproj" />
</ItemGroup>

</Project>
74 changes: 74 additions & 0 deletions src/Snowberry.IO.SingleFile/BinarySearchHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
using System.IO.MemoryMappedFiles;

namespace Snowberry.IO.SingleFile;

public static class BinarySearchHelper
{
public static unsafe int SearchInView(MemoryMappedViewAccessor accessor, byte[] toSearch)
{
var safeBuffer = accessor.SafeMemoryMappedViewHandle;
byte* buffer = (byte*)safeBuffer.DangerousGetHandle();
return SearchInBuffer(buffer, (int)accessor.Capacity, toSearch);
}

public static unsafe int SearchInBuffer(byte* buffer, int length, byte[] toSearch)
{
if (toSearch.Length > length)
return -1;

int[] table = BuildTable(toSearch);

int i = 0;
int j = 0;

while (i + j < length)
{
if (toSearch[j] == buffer[i + j])
{
j++;

if (j == toSearch.Length)
{
return i;
}
}
else
{
i += j - table[j];
j = Math.Max(0, table[j]);
}
}

return -1;
}

private static int[] BuildTable(byte[] toSearch)
{
int[] table = new int[toSearch.Length];
int position = 2;
int candidate = 0;

table[0] = -1;
table[1] = 0;

while (position < toSearch.Length)
{
if (toSearch[position - 1] == toSearch[candidate])
{
table[position++] = ++candidate;
continue;
}

if (candidate > 0)
{
candidate = table[candidate];
continue;
}

table[position++] = 0;
}

return table;
}
}

29 changes: 29 additions & 0 deletions src/Snowberry.IO.SingleFile/BundlerOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System.Text.Json.Serialization;

namespace Snowberry.IO.SingleFile;

/// <summary>
/// The bundler options.
/// </summary>
public class BundlerOptions
{
/// <summary>
/// Gets or sets a value indicating whether to use compression for the files.
/// </summary>
/// <remarks>It depends on the bundle version whether compressing is supported.</remarks>
[JsonPropertyName(nameof(UseCompression))]
public bool UseCompression { get; set; } = true;

/// <summary>
/// Gets or sets the compression threshold.
/// </summary>
/// <remarks>If the compressed size is smaller than the original size multiplied by this value, the compressed data will be used.</remarks>
[JsonPropertyName(nameof(CompressionThreshold))]
public float CompressionThreshold { get; set; } = 0.75F;

/// <summary>
/// Gets or sets a value indicating whether to force compression for the files even if the compressed size exceeds the compression threshold.
/// </summary>
[JsonPropertyName(nameof(ForceCompression))]
public bool ForceCompression { get; set; }
}
Loading

0 comments on commit cb30cb8

Please sign in to comment.