Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
f771d8f
Merge pull request #572 from AlamoEngine-Tools/develop
AnakinRaW Dec 8, 2025
79e811e
fix grammar
AnakinRaW Jan 24, 2026
c505db4
add file size check when constructing
AnakinRaW Jan 24, 2026
82a586f
formatting
AnakinRaW Jan 24, 2026
e3173a9
update .gitignore to exclude /.idea
AnakinRaW Jan 25, 2026
5524ba4
reduce validation logic when reading meg archives
AnakinRaW Jan 25, 2026
e9568ef
implement missing methods
AnakinRaW Jan 25, 2026
fc72e91
new validation tests
AnakinRaW Jan 25, 2026
547ff62
namepssaces
AnakinRaW Jan 25, 2026
2ce6db5
add TryGetFilePath overloads and update StreamExtensions to improve p…
AnakinRaW Jan 25, 2026
ca20891
update IMegFileBinaryReader and fix method usage in MegThrowHelper fo…
AnakinRaW Jan 25, 2026
b963df0
add large file handling tests and improve binary reader validation
AnakinRaW Jan 25, 2026
64c188e
update test method names and add null argument checks in factory methods
AnakinRaW Jan 25, 2026
b45ab7a
add ExpectedMaxEntryFileSize override and update base test class with…
AnakinRaW Jan 25, 2026
cfa6512
update test to throw IndexOutOfRangeException instead of ArgumentOutO…
AnakinRaW Jan 25, 2026
3fe13d5
add MegServiceContributionTest to validate service registrations
AnakinRaW Jan 25, 2026
9bc6183
expand MegFileDataStreamTest to include additional ObjectDisposedExce…
AnakinRaW Jan 25, 2026
913b47b
extend enumerator tests to include IEnumerator.Current assertions
AnakinRaW Jan 25, 2026
75c4600
update NotImplementedException messages in MegBinaryServiceFactory to…
AnakinRaW Jan 25, 2026
7e03020
extract NonSeekableStream to MegTestConstants and enhance ObjectDispo…
AnakinRaW Jan 25, 2026
097cba5
extend validator tests with additional null and encryption scenarios,…
AnakinRaW Jan 25, 2026
269ad98
Merge branch 'master' into meg-max-file-size-2gb
AnakinRaW Jan 25, 2026
8a55dd1
Revert "Merge branch 'master' into meg-max-file-size-2gb"
AnakinRaW Jan 25, 2026
9b4a8e8
Reapply "Merge branch 'master' into meg-max-file-size-2gb"
AnakinRaW Jan 25, 2026
5f074cc
update test to throw IndexOutOfRangeException instead of ArgumentOutO…
AnakinRaW Jan 25, 2026
807c1da
add support for file size validation and corresponding unit tests for…
AnakinRaW Jan 25, 2026
c360565
start implementing meg splitting
AnakinRaW Jan 28, 2026
8910134
implement size calculation and validation
AnakinRaW Feb 1, 2026
4a1f5cb
rename type and remove some obsolete types
AnakinRaW Feb 2, 2026
59a1847
fix doc
AnakinRaW Feb 7, 2026
03254b8
implement binary size constraints and simplified public API
AnakinRaW Feb 7, 2026
546c1e0
fix lib compile
AnakinRaW Feb 7, 2026
617116a
update deps
AnakinRaW Feb 7, 2026
a2e9b76
remove benchmark
AnakinRaW Feb 7, 2026
68e02fa
fix MEG exception and data tests
AnakinRaW Feb 7, 2026
6a16907
rename type
AnakinRaW Feb 7, 2026
f6618bd
to common test cases
AnakinRaW Feb 7, 2026
ccb0bf0
rename variables
AnakinRaW Feb 7, 2026
d0422cc
reactivate construction tests
AnakinRaW Feb 7, 2026
9c774cf
fix stream tests
AnakinRaW Feb 7, 2026
d7e632b
add constant tests
AnakinRaW Feb 7, 2026
b9cbf1f
delete dead code
AnakinRaW Feb 7, 2026
e53347e
fix MEG validation and reader tests
AnakinRaW Feb 7, 2026
5c521dc
add test for unsorted CRC32 and update MEG validation logic
AnakinRaW Feb 7, 2026
65e6e9c
add test for unordered MEG files and update file handling logic
AnakinRaW Feb 7, 2026
fe2d582
fix copyright typo in documentation headers
AnakinRaW Feb 8, 2026
518f80d
update MEG validation and reader tests, add new corruption scenarios
AnakinRaW Feb 8, 2026
e87413c
add test for filename table order differing from file table order
AnakinRaW Feb 8, 2026
d91942f
fix swapped MaxEntrySize and MaxFileSize assignments in MaxMegSizePro…
AnakinRaW Feb 8, 2026
35e697c
add tests for MaxMegSizeProvider methods and validation scenarios
AnakinRaW Feb 8, 2026
cbc9521
add encryption check to MegV1SizeCalculator and MegV2SizeCalculator
AnakinRaW Feb 8, 2026
b5bc7ce
rename `LargeFileInfo` to `FakeFileInfo` in test constants and update…
AnakinRaW Feb 8, 2026
6878bcf
add encryption support for filename table in MegV3SizeCalculator and …
AnakinRaW Feb 8, 2026
20dc76a
refactor `GetMegSizeCalculator` with switch expression and add compre…
AnakinRaW Feb 8, 2026
32c934d
rename and refactor test base classes for data entry path normalizers…
AnakinRaW Feb 8, 2026
d7a8c4a
rename and update test method and data source for large MEGs to impro…
AnakinRaW Feb 8, 2026
cf43d75
minor cleanup: adjust XML doc formatting in `EmpireAtWarMegDataEntryV…
AnakinRaW Feb 8, 2026
71834e6
refactor: remove obsolete validator tests and introduce new structure…
AnakinRaW Feb 8, 2026
ae81250
refactor: migrate and restructure MEG file information validator test…
AnakinRaW Feb 8, 2026
525c052
refactor: enhance error handling in `IMegBuilder` and `MegBuilderBase…
AnakinRaW Feb 8, 2026
33bfe7d
refactor: add new test cases for `CreateMegArchive` to validate `Inva…
AnakinRaW Feb 8, 2026
ad9546d
refactor: replace hardcoded file creation with `FileSystem.FileInfo.N…
AnakinRaW Feb 8, 2026
69cc332
refactor: remove `NormalizingMegBuilderTest` and associated test logic
AnakinRaW Feb 8, 2026
b84771e
add MIT license header to all source files in the PG.StarWarsGame.Fil…
AnakinRaW Feb 8, 2026
cd09d56
Merge branch 'develop' into meg-max-file-size-2gb
AnakinRaW Feb 8, 2026
53f2a02
Merge branch 'develop' into meg-max-file-size-2gb
AnakinRaW Feb 8, 2026
2d554f7
remove warnings
AnakinRaW Feb 9, 2026
e795882
do not throw ANE for equality comparer
AnakinRaW Feb 9, 2026
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -400,3 +400,4 @@ Thumbs.db
Desktop.ini
.DS_Store
/testEnvironments.json
/.idea
62 changes: 0 additions & 62 deletions PG.Benchmarks/EmpireAtWarValidatorBenchmark.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public override bool Equals(object? obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
if (obj.GetType() != GetType()) return false;
return Equals((HasCrcClass)obj);
}

Expand All @@ -71,7 +71,7 @@ protected override HasCrcClass CreateT(int crc)
public void GetHashCode_NullArgs_Throws()
{
var comparer = CrcBasedEqualityComparer<HasCrcClass>.Instance;
Assert.Throws<ArgumentNullException>(() => comparer.GetHashCode(null!));
Assert.Equal(0, comparer.GetHashCode(null));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ public unsafe void HashData(byte[] inputData, uint expected)

Assert.Equal(sizeof(Crc32), bytesWritten);
var expectedBytes = BitConverter.GetBytes(expected);
Assert.Equal(expectedBytes, destination.Slice(0, bytesWritten).ToArray());
Assert.Equal(expectedBytes.AsSpan(), destination[..bytesWritten]);


bytesWritten = new Crc32HashingProvider().HashData(new MemoryStream(inputData), destination);
Assert.Equal(sizeof(Crc32), bytesWritten);
expectedBytes = BitConverter.GetBytes(expected);
Assert.Equal(expectedBytes, destination.Slice(0, bytesWritten).ToArray());
Assert.Equal(expectedBytes.AsSpan(), destination[..bytesWritten]);
}

[Theory]
Expand All @@ -44,10 +44,11 @@ public unsafe void HashData(byte[] inputData, uint expected)
public async Task HashDataAsync(byte[] inputData, uint expected)
{
var destination = new byte[20];
var bytesWritten = await new Crc32HashingProvider().HashDataAsync(new MemoryStream(inputData), destination);
var bytesWritten = await new Crc32HashingProvider()
.HashDataAsync(new MemoryStream(inputData), destination, TestContext.Current.CancellationToken);

Assert.Equal(4, bytesWritten);
var expectedBytes = BitConverter.GetBytes(expected);
Assert.Equal(expectedBytes, destination.AsSpan().Slice(0, bytesWritten).ToArray());
Assert.Equal(expectedBytes.AsSpan(), destination.AsSpan()[..bytesWritten]);
}
}
2 changes: 1 addition & 1 deletion PG.Commons/PG.Commons.Test/PG.Commons.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
<PackageReference Include="GitHubActionsTestLogger" Version="3.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="xunit.v3.mtp-v2" Version="3.2.2" />
<PackageReference Include="Microsoft.Testing.Platform" Version="2.0.2" />
<PackageReference Include="Microsoft.Testing.Platform" Version="2.1.0" />
<PackageReference Include="IsExternalInit" Version="1.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
51 changes: 41 additions & 10 deletions PG.Commons/PG.Commons.Test/Utilities/StreamExtensionsTest.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System.IO;
using System;
using PG.Commons.Utilities;
using PG.Commons.Utilities;
using PG.Testing;
using System;
using System.IO;
using Testably.Abstractions.Testing;
using Xunit;

Expand All @@ -12,39 +12,70 @@ public class StreamExtensionsTest
[Fact]
public void GetFilePath_FileStream()
{
var expectedPath = "testfile.txt";
const string expectedPath = "testfile.txt";
using var fileStream = new FileStream(expectedPath, FileMode.Create, FileAccess.Write, FileShare.None, 1024, FileOptions.DeleteOnClose);
Assert.True(fileStream.TryGetFilePath(out var path1));
Assert.True(fileStream.TryGetFilePath(out var path2, out var isMeg));
Assert.False(isMeg);
Assert.Equal(Path.GetFullPath(expectedPath), path1);
Assert.Equal(Path.GetFullPath(expectedPath), path2);
Assert.Equal(Path.GetFullPath(expectedPath), fileStream.TryGetFilePath());
Assert.Equal(Path.GetFullPath(expectedPath), fileStream.GetFilePath());
Assert.Equal(Path.GetFullPath(expectedPath), fileStream.GetFilePath(out var isMeg));
Assert.Equal(Path.GetFullPath(expectedPath), fileStream.GetFilePath(out isMeg));
Assert.False(isMeg);
}

[Fact]
public void GetFilePath_FileSystemStream()
{
const string expectedPath = "filesystemfile.txt";
var fs = new MockFileSystem();
var expectedPath = "filesystemfile.txt";
var fileSystemStream = fs.FileStream.New(expectedPath, FileMode.Create);

Assert.True(fileSystemStream.TryGetFilePath(out var path1));
Assert.True(fileSystemStream.TryGetFilePath(out var path2, out var isMeg));
Assert.False(isMeg);
Assert.Equal(fs.Path.GetFullPath(expectedPath), path1);
Assert.Equal(fs.Path.GetFullPath(expectedPath), path2);
Assert.Equal(fs.Path.GetFullPath(expectedPath), fileSystemStream.TryGetFilePath());
Assert.Equal(fs.Path.GetFullPath(expectedPath), fileSystemStream.GetFilePath());
Assert.Equal(fs.Path.GetFullPath(expectedPath), fileSystemStream.GetFilePath(out var isMeg));
Assert.Equal(fs.Path.GetFullPath(expectedPath), fileSystemStream.GetFilePath(out isMeg));
Assert.False(isMeg);
}

[Fact]
public void GetFilePath_IMegFileDataStream()
{
var expectedPath = "megfiledatafile.txt";
var megFileDataStream = new TestMegDataStream("megfiledatafile.txt", Stream.Null);
const string expectedPath = "megfiledatafile.txt";
var megFileDataStream = new TestMegDataStream(expectedPath, Stream.Null);

Assert.True(megFileDataStream.TryGetFilePath(out var path1));
Assert.True(megFileDataStream.TryGetFilePath(out var path2, out var isMeg));
Assert.True(isMeg);
Assert.Equal(expectedPath, path1);
Assert.Equal(expectedPath, path2);
Assert.Equal(expectedPath, megFileDataStream.TryGetFilePath());
Assert.Equal(expectedPath, megFileDataStream.GetFilePath());
Assert.Equal(expectedPath, megFileDataStream.GetFilePath(out var isMeg));
Assert.Equal(expectedPath, megFileDataStream.GetFilePath(out isMeg));
Assert.True(isMeg);
}

[Fact]
public void GetFilePath_StreamWithoutPath_ThrowsInvalidOperationException()
{
var memoryStream = new MemoryStream();

var isMeg = false;

Assert.Throws<InvalidOperationException>(memoryStream.GetFilePath);
Assert.Throws<InvalidOperationException>(() => memoryStream.GetFilePath(out isMeg));
Assert.False(isMeg);

Assert.Null(memoryStream.TryGetFilePath());
Assert.False(memoryStream.TryGetFilePath(out var path1));
Assert.False(memoryStream.TryGetFilePath(out var path2, out isMeg));
Assert.Null(path1);
Assert.Null(path2);
Assert.False(isMeg);
}
}
6 changes: 2 additions & 4 deletions PG.Commons/PG.Commons/Data/CrcBasedEqualityComparer.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Alamo Engine Tools and contributors. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.

using System;
using System.Collections.Generic;

namespace PG.Commons.Data;
Expand Down Expand Up @@ -72,9 +71,8 @@ public bool Equals(T? x, T? y)
/// <returns>
/// A hash code for the specified object, derived from its <see cref="IHasCrc32.Crc32"/> value.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="obj"/> is <see langword="null"/>.</exception>
public int GetHashCode(T obj)
public int GetHashCode(T? obj)
{
return obj is null ? throw new ArgumentNullException(nameof(obj)) : obj.Crc32.GetHashCode();
return obj?.Crc32.GetHashCode() ?? 0;
}
}
2 changes: 0 additions & 2 deletions PG.Commons/PG.Commons/Utilities/PGFileNameUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ private static bool ContainsInvalidPGChars(ReadOnlySpan<char> value)
{
if (IsInvalidFileCharacter(t))
return true;

}

return false;
}

Expand Down
76 changes: 66 additions & 10 deletions PG.Commons/PG.Commons/Utilities/StreamExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using PG.Commons.Data;
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.IO.Abstractions;

Expand All @@ -21,7 +22,7 @@ public static class StreamExtensions
/// <exception cref="InvalidOperationException"><paramref name="stream"/> does not have path information.</exception>
public static string GetFilePath(this Stream stream)
{
return GetFilePath(stream, out _);
return stream.GetFilePath(out _);
}

/// <summary>
Expand All @@ -32,18 +33,73 @@ public static string GetFilePath(this Stream stream)
/// <returns>The file path of the opened file.</returns>
/// <exception cref="InvalidOperationException"><paramref name="stream"/> does not have path information.</exception>
public static string GetFilePath(this Stream stream, out bool isMegStream)
{
return !stream.TryGetFilePath(out var filePath, out isMegStream)
? throw new InvalidOperationException("Unable to get file path from Stream")
: filePath;
}

/// <summary>
/// Attempts to retrieve the file path of the file opened in the specified <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The stream to retrieve the file path from.</param>
/// <returns>
/// The file path of the opened file if the operation was successful; otherwise, <see langword="null"/>.
/// </returns>
public static string? TryGetFilePath(this Stream stream)
{
return stream.TryGetFilePath(out var fileName, out _) ? fileName : null;
}

/// <summary>
/// Attempts to retrieve the file path of the file opened in the specified <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The stream to retrieve the file path from.</param>
/// <param name="fileName">
/// When this method returns, contains the file path of the opened file if the operation was successful;
/// otherwise, <see langword="null"/>. This parameter is passed uninitialized.
/// </param>
/// <returns>
/// <see langword="true"/> if the file path was successfully retrieved; otherwise, <see langword="false"/>.
/// </returns>
public static bool TryGetFilePath(this Stream stream, [NotNullWhen(true)] out string? fileName)
{
return stream.TryGetFilePath(out fileName, out _);
}

/// <summary>
/// Attempts to retrieve the file path of the file opened in the specified <see cref="Stream"/>.
/// </summary>
/// <param name="stream">The stream to retrieve the file path from.</param>
/// <param name="fileName">
/// When this method returns, contains the file path of the opened file if the operation was successful;
/// otherwise, <see langword="null"/>. This parameter is passed uninitialized.
/// </param>
/// <param name="isMegStream">
/// When this method returns, contains a value indicating whether the stream is a MEG file data stream.
/// </param>
/// <returns>
/// <see langword="true"/> if the file path was successfully retrieved; otherwise, <see langword="false"/>.
/// </returns>
public static bool TryGetFilePath(this Stream stream, [NotNullWhen(true)] out string? fileName, out bool isMegStream)
{
isMegStream = false;
if (stream is FileStream fileStream)
return fileStream.Name;
if (stream is FileSystemStream fileSystemStream)
return fileSystemStream.Name;
if (stream is IMegFileDataStream megFileDataStream)
switch (stream)
{
isMegStream = true;
return megFileDataStream.EntryPath;
case FileStream fileStream:
fileName = fileStream.Name;
break;
case FileSystemStream fileSystemStream:
fileName = fileSystemStream.Name;
break;
case IMegFileDataStream megFileDataStream:
isMegStream = true;
fileName = megFileDataStream.EntryPath;
break;
default:
fileName = null;
return false;
}

throw new InvalidOperationException("Unable to get file path from Stream");
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
<PackageReference Include="GitHubActionsTestLogger" Version="3.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageReference Include="xunit.v3.mtp-v2" Version="3.2.2" />
<PackageReference Include="Microsoft.Testing.Platform" Version="2.0.2" />
<PackageReference Include="Microsoft.Testing.Platform" Version="2.1.0" />
<PackageReference Include="coverlet.msbuild" Version="6.0.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public sealed class EmpireAtWarMasterTextBuilder : PetroglyphStarWarsGameDatBuil
/// <summary>
/// Initializes a new instance of the <see cref="EmpireAtWarCreditsTextBuilder"/> class.
/// </summary>
/// <param name="overwriteDuplicates"></param>
/// <param name="overwriteDuplicates">Specifies how the build treats duplicates.</param>
/// <param name="services">The service provider.</param>
public EmpireAtWarMasterTextBuilder(bool overwriteDuplicates, IServiceProvider services)
: base(overwriteDuplicates ? BuilderOverrideKind.Overwrite : BuilderOverrideKind.NoOverwrite, services)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public abstract class DatBuilderBase : FileBuilderBase<IReadOnlyList<DatStringEn
/// <summary>
/// Initializes a new instance of the <see cref="DatBuilderBase"/> class.
/// </summary>
/// <param name="overrideKind"></param>
/// <param name="overrideKind">Specifies how the build treats duplicate entries.</param>
/// <param name="services">The service provider.</param>
protected DatBuilderBase(BuilderOverrideKind overrideKind, IServiceProvider services) : base(services)
{
Expand Down
Loading
Loading