diff --git a/.github/workflows/publish-nuget.yml b/.github/workflows/publish-nuget.yml
index 206ae6f71..8b4ec41c7 100644
--- a/.github/workflows/publish-nuget.yml
+++ b/.github/workflows/publish-nuget.yml
@@ -1,9 +1,7 @@
name: NuGet push (tag)
-on:
- push:
- tags:
- - 'v[0-9]+.[0-9]+.[0-9]+'
+on:
+ workflow_dispatch:
env:
DOTNET_CLI_TELEMETRY_OPTOUT: true
@@ -11,22 +9,20 @@ env:
jobs:
build:
- runs-on: windows-2019
+ runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
+ - uses: actions/checkout@v5
+ - name: Setup .NET Core
+ uses: actions/setup-dotnet@v5
with:
- fetch-depth: 50
- lfs: 'true'
- # We do not need to fetch tags, as we're already at a tagged build - it should be available automatically
+ dotnet-version: 10.0.x
- - name: Setup .NET Core 7.0
- uses: actions/setup-dotnet@v1
- with:
- dotnet-version: '7.0.x'
+ - name: Build
+ run: dotnet build -c Release
- name: Pack
- run: dotnet pack -c Release -o ${{ github.workspace }}/build
+ run: dotnet pack -c Release -o ${{ github.workspace }}/build --no-build
- name: NuGet push
run: dotnet nuget push *.nupkg --skip-duplicate -k ${{secrets.NUGET_KEY}} -s https://api.nuget.org/v3/index.json
diff --git a/.gitignore b/.gitignore
index b207fc71c..7d87a18bc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -386,3 +386,19 @@ artifacts-dotnet-releaser/
# Verify
*.received.*
*#
+
+# Build outputs in Library folder
+Library/net*/
+Library/netstandard*/
+net10.0/
+
+# Build outputs in root
+netstandard*/
+
+# Build outputs in Tests folder
+Tests/net*/
+Tests/netstandard*/
+
+# Build outputs in Utilities folder
+Utilities/net*/
+Utilities/netstandard*/
diff --git a/Directory.Build.props b/Directory.Build.props
index dd0d89387..6429d7843 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -6,18 +6,19 @@
portable
- https://github.com/LTRData/DiscUtils
+ https://github.com/Devedse/DiscUtils
MIT
git
LTR Data
Kenneth Bell;LordMike;Olof Lagerkvist
..\$(Configuration)
- 1.0.72
+ 1.0.102
true
CS1591;CS0649
+ false
diff --git a/DiscUtils.slnx b/DiscUtils.slnx
index 29103d33c..af19f17d9 100644
--- a/DiscUtils.slnx
+++ b/DiscUtils.slnx
@@ -48,6 +48,7 @@
+
diff --git a/Library/Directory.Build.props b/Library/Directory.Build.props
index 15793114e..3c0fe7c12 100644
--- a/Library/Directory.Build.props
+++ b/Library/Directory.Build.props
@@ -5,7 +5,7 @@
netstandard2.0;netstandard2.1;net46;net48;net8.0;net9.0;net10.0
true
- LTRData.$(MSBuildProjectName)
+ Devedse.$(MSBuildProjectName)
$(LocalNuGetPath)
$(FileVersion)
README.md
@@ -26,6 +26,8 @@
$(MSBuildThisFileDirectory)../SigningKey.snk
false
+ false
+ $(BaseIntermediateOutputPath)Generated
false
@@ -37,4 +39,8 @@
+
+
+
+
diff --git a/Library/DiscUtils.Core/DiskImageBuilder.cs b/Library/DiscUtils.Core/DiskImageBuilder.cs
index 73663b373..cf12403f9 100644
--- a/Library/DiscUtils.Core/DiskImageBuilder.cs
+++ b/Library/DiscUtils.Core/DiskImageBuilder.cs
@@ -102,9 +102,18 @@ public static DiskImageBuilder GetBuilder(string type, string variant)
/// 'foo', the files 'foo.vmdk' and 'foo-flat.vmdk' could be returned.
public abstract IEnumerable Build(string baseName);
+ // Set this to true to enable AoT compatiblity
+ public static bool ShouldUseVirtualDiskManagerTypeMap { get; set; }
+
[MemberNotNull(nameof(_typeMap))]
private static void InitializeMaps()
{
+ if (ShouldUseVirtualDiskManagerTypeMap)
+ {
+ _typeMap = VirtualDiskManager.TypeMap;
+ return;
+ }
+
var typeMap = new Dictionary();
foreach (var type in typeof(VirtualDisk).Assembly.GetTypes())
diff --git a/Library/DiscUtils.Core/Partitions/PartitionTable.cs b/Library/DiscUtils.Core/Partitions/PartitionTable.cs
index dd59c5dfb..9def19505 100644
--- a/Library/DiscUtils.Core/Partitions/PartitionTable.cs
+++ b/Library/DiscUtils.Core/Partitions/PartitionTable.cs
@@ -54,11 +54,13 @@ public abstract class PartitionTable
///
public abstract Geometry? DiskGeometry { get; }
+ private static List? _factories;
+
private static List Factories
{
get
{
- if (field == null)
+ if (_factories == null)
{
var factories = new List();
@@ -66,17 +68,25 @@ private static List Factories
{
foreach (var attr in type.GetCustomAttributes(false))
{
- factories.Add((PartitionTableFactory)Activator.CreateInstance(type)!);
+ factories.Add((PartitionTableFactory)Activator.CreateInstance(type, true)!);
}
}
- field = factories;
+ _factories = factories;
}
- return field;
+ return _factories;
+ }
+ }
+
+ internal static void RegisterPartitionTableFactory(PartitionTableFactory factory)
+ {
+ if (_factories == null)
+ {
+ _factories = new List();
}
- set;
+ _factories.Add(factory);
}
///
diff --git a/Library/DiscUtils.Core/VirtualDisk.cs b/Library/DiscUtils.Core/VirtualDisk.cs
index ee4cfe228..9ff177862 100644
--- a/Library/DiscUtils.Core/VirtualDisk.cs
+++ b/Library/DiscUtils.Core/VirtualDisk.cs
@@ -375,12 +375,12 @@ public static VirtualDisk CreateDisk(DiscFileSystem fileSystem, string type, str
var uri = PathToUri(path);
VirtualDisk result;
- if (!VirtualDiskManager.DiskTransports.TryGetValue(uri.Scheme, out var transportType))
+ if (!VirtualDiskManager.DiskTransports.TryGetValue(uri.Scheme, out var transportFactory))
{
throw new FileNotFoundException($"Unable to parse path '{path}'", path);
}
- var transport = (VirtualDiskTransport)Activator.CreateInstance(transportType)!;
+ var transport = transportFactory();
try
{
@@ -499,12 +499,12 @@ public static VirtualDisk CreateDisk(DiscFileSystem fileSystem, string type, str
var uri = PathToUri(path);
VirtualDisk? result = null;
- if (!VirtualDiskManager.DiskTransports.TryGetValue(uri.Scheme, out var transportType))
+ if (!VirtualDiskManager.DiskTransports.TryGetValue(uri.Scheme, out var transportFactory))
{
throw new FileNotFoundException($"Unable to parse path '{uri}'", path);
}
- var transport = (VirtualDiskTransport)Activator.CreateInstance(transportType)!;
+ var transport = transportFactory();
try
{
diff --git a/Library/DiscUtils.Core/VirtualDiskManager.cs b/Library/DiscUtils.Core/VirtualDiskManager.cs
index b6179de34..a25858960 100644
--- a/Library/DiscUtils.Core/VirtualDiskManager.cs
+++ b/Library/DiscUtils.Core/VirtualDiskManager.cs
@@ -1,7 +1,7 @@
-using System;
+using DiscUtils.Internal;
+using System;
using System.Collections.Generic;
using System.Reflection;
-using DiscUtils.Internal;
namespace DiscUtils;
@@ -14,10 +14,10 @@ static VirtualDiskManager()
{
ExtensionMap = new Dictionary(StringComparer.OrdinalIgnoreCase);
TypeMap = new Dictionary(StringComparer.OrdinalIgnoreCase);
- DiskTransports = new Dictionary(StringComparer.OrdinalIgnoreCase);
+ DiskTransports = new Dictionary>(StringComparer.OrdinalIgnoreCase);
}
- internal static Dictionary DiskTransports { get; }
+ internal static Dictionary> DiskTransports { get; }
internal static Dictionary ExtensionMap { get; }
///
@@ -33,7 +33,46 @@ static VirtualDiskManager()
internal static Dictionary TypeMap { get; }
///
- /// Locates VirtualDiskFactory factories attributed with VirtualDiskFactoryAttribute, and types marked with VirtualDiskTransportAttribute, that are able to work with Virtual Disk types.
+ /// Registers a VirtualDiskFactory instance.
+ ///
+ /// The factory to register.
+ public static void RegisterVirtualDiskFactory(VirtualDiskFactory factory)
+ {
+ var type = factory.GetType();
+ var diskFactoryAttribute = type.GetCustomAttribute(false);
+ if (diskFactoryAttribute != null)
+ {
+ if (!TypeMap.ContainsKey(diskFactoryAttribute.Type))
+ {
+ TypeMap.Add(diskFactoryAttribute.Type, factory);
+ }
+
+ foreach (var extension in diskFactoryAttribute.FileExtensions)
+ {
+ if (!ExtensionMap.ContainsKey(extension))
+ {
+ ExtensionMap.Add(extension, factory);
+ }
+ }
+ }
+ }
+
+ ///
+ /// Registers a VirtualDiskTransport factory.
+ ///
+ /// The URI scheme.
+ /// The factory method.
+ internal static void RegisterVirtualDiskTransport(string scheme, Func factory)
+ {
+ if (!DiskTransports.ContainsKey(scheme))
+ {
+ DiskTransports.Add(scheme, factory);
+ }
+ }
+
+ ///
+ /// Locates VirtualDiskFactory factories attributed with VirtualDiskFactoryAttribute, and types marked with VirtualDiskTransportAttribute,
+ /// that are able to work with Virtual Disk types.
///
/// An assembly to scan
public static void RegisterVirtualDiskTypes(Assembly assembly)
@@ -55,7 +94,7 @@ public static void RegisterVirtualDiskTypes(Assembly assembly)
var diskTransportAttribute = type.GetCustomAttribute(false);
if (diskTransportAttribute != null)
{
- DiskTransports.Add(diskTransportAttribute.Scheme, type);
+ DiskTransports.Add(diskTransportAttribute.Scheme, () => (VirtualDiskTransport)Activator.CreateInstance(type)!);
}
}
}
diff --git a/Library/DiscUtils.Core/VolumeManager.cs b/Library/DiscUtils.Core/VolumeManager.cs
index 417f09fc3..90bfa2a5b 100644
--- a/Library/DiscUtils.Core/VolumeManager.cs
+++ b/Library/DiscUtils.Core/VolumeManager.cs
@@ -82,26 +82,45 @@ public VolumeManager(Stream initialDiskContent)
private static readonly object _syncObj = new();
+ private static ConcurrentBag? _logicalVolumeFactories;
+
private static ConcurrentBag LogicalVolumeFactories
{
get
{
- if (field == null)
+ if (_logicalVolumeFactories == null)
{
lock (_syncObj)
{
- if (field == null)
+ if (_logicalVolumeFactories == null)
{
- var factories = new ConcurrentBag(GetLogicalVolumeFactories(_coreAssembly));
- field = factories;
+ _logicalVolumeFactories = new ConcurrentBag(GetLogicalVolumeFactories(_coreAssembly));
}
}
}
- return field;
+ return _logicalVolumeFactories;
+ }
+ }
+
+ ///
+ /// Register a new LogicalVolumeFactory instance.
+ ///
+ /// The factory to register.
+ internal static void RegisterLogicalVolumeFactory(LogicalVolumeFactory factory)
+ {
+ if (_logicalVolumeFactories == null)
+ {
+ lock (_syncObj)
+ {
+ if (_logicalVolumeFactories == null)
+ {
+ _logicalVolumeFactories = new ConcurrentBag();
+ }
+ }
}
- set;
+ _logicalVolumeFactories.Add(factory);
}
private static IEnumerable GetLogicalVolumeFactories(Assembly assembly)
diff --git a/Library/DiscUtils.Registry/Bin.cs b/Library/DiscUtils.Registry/Bin.cs
index 12dcc19a6..e81d9b67a 100644
--- a/Library/DiscUtils.Registry/Bin.cs
+++ b/Library/DiscUtils.Registry/Bin.cs
@@ -152,6 +152,37 @@ public Span ReadRawCellData(int cellIndex, Span maxBytes)
{
var index = cellIndex - _header.FileOffset;
var len = Math.Abs(EndianUtilities.ToInt32LittleEndian(_buffer, index));
+
+ // Check if this is a "big data" cell (signature "db")
+ // Big data cells are used for values larger than ~16KB
+ if (len >= 6 && _buffer[index + 4] == 0x64 && _buffer[index + 5] == 0x62) // "db"
+ {
+ // Big data format:
+ // 0x00: signature "db" (2 bytes)
+ // 0x02: number of segments (2 bytes)
+ // 0x04: offset to list of cell indices (4 bytes)
+ var numSegments = EndianUtilities.ToUInt16LittleEndian(_buffer.AsSpan(index + 6));
+ var listOffset = EndianUtilities.ToInt32LittleEndian(_buffer.AsSpan(index + 8));
+
+ // Read the list of cell indices
+ var listIndex = listOffset - _header.FileOffset;
+ var bytesWritten = 0;
+
+ for (var i = 0; i < numSegments && bytesWritten < maxBytes.Length; i++)
+ {
+ var segmentCellIndex = EndianUtilities.ToInt32LittleEndian(_buffer.AsSpan(listIndex + i * 4));
+ var segmentIndex = segmentCellIndex - _header.FileOffset;
+ var segmentLen = Math.Abs(EndianUtilities.ToInt32LittleEndian(_buffer, segmentIndex)) - 4;
+
+ var bytesToCopy = Math.Min(segmentLen, maxBytes.Length - bytesWritten);
+ _buffer.AsSpan(segmentIndex + 4, bytesToCopy).CopyTo(maxBytes.Slice(bytesWritten));
+ bytesWritten += bytesToCopy;
+ }
+
+ return maxBytes.Slice(0, bytesWritten);
+ }
+
+ // Regular cell data
var result = maxBytes.Slice(0, Math.Min(len - 4, maxBytes.Length));
_buffer.AsSpan(index + 4, result.Length).CopyTo(result);
return result;
diff --git a/Library/DiscUtils.Registry/RegistryKey.cs b/Library/DiscUtils.Registry/RegistryKey.cs
index f8448d54e..553e03c9e 100644
--- a/Library/DiscUtils.Registry/RegistryKey.cs
+++ b/Library/DiscUtils.Registry/RegistryKey.cs
@@ -40,6 +40,8 @@ public enum RegistryValueOptions
///
public sealed class RegistryKey
{
+ internal static readonly char[] RegistryPathSeparators = ['\\'];
+
private readonly KeyNodeCell _cell;
private readonly RegistryHive _hive;
@@ -530,7 +532,7 @@ public RegistryKey CreateSubKey(string subkey)
return this;
}
- var split = subkey.Split(Utilities.PathSeparators, 2, StringSplitOptions.RemoveEmptyEntries);
+ var split = subkey.Split(RegistryPathSeparators, 2, StringSplitOptions.RemoveEmptyEntries);
var cellIndex = FindSubKeyCell(split[0]);
if (cellIndex < 0)
@@ -573,7 +575,7 @@ public RegistryKey OpenSubKey(string path)
return this;
}
- var split = path.Split(Utilities.PathSeparators, 2, StringSplitOptions.RemoveEmptyEntries);
+ var split = path.Split(RegistryPathSeparators, 2, StringSplitOptions.RemoveEmptyEntries);
var cellIndex = FindSubKeyCell(split[0]);
if (cellIndex < 0)
@@ -642,7 +644,7 @@ public bool DeleteSubKey(string subkey, bool throwOnMissingSubKey)
throw new ArgumentException("Invalid SubKey", nameof(subkey));
}
- var split = subkey.Split(Utilities.PathSeparators, 2, StringSplitOptions.RemoveEmptyEntries);
+ var split = subkey.Split(RegistryPathSeparators, 2, StringSplitOptions.RemoveEmptyEntries);
var subkeyCellIndex = FindSubKeyCell(split[0]);
if (subkeyCellIndex < 0)
diff --git a/Library/DiscUtils.SourceGenerator/DiscUtils.SourceGenerator.csproj b/Library/DiscUtils.SourceGenerator/DiscUtils.SourceGenerator.csproj
new file mode 100644
index 000000000..35a9841d6
--- /dev/null
+++ b/Library/DiscUtils.SourceGenerator/DiscUtils.SourceGenerator.csproj
@@ -0,0 +1,22 @@
+
+
+
+
+ netstandard2.0
+
+ true
+ Source Generator for DiscUtils
+ true
+ DiscUtils;SourceGenerator;Analyzer
+ enable
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
diff --git a/Library/DiscUtils.SourceGenerator/FactoryGenerator.cs b/Library/DiscUtils.SourceGenerator/FactoryGenerator.cs
new file mode 100644
index 000000000..c9b57a250
--- /dev/null
+++ b/Library/DiscUtils.SourceGenerator/FactoryGenerator.cs
@@ -0,0 +1,199 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Text;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+
+namespace DiscUtils.SourceGenerator
+{
+ [Generator]
+ public class FactoryGenerator : IIncrementalGenerator
+ {
+ public void Initialize(IncrementalGeneratorInitializationContext context)
+ {
+ // Debugging helper - uncomment to attach debugger
+ // if (!System.Diagnostics.Debugger.IsAttached) System.Diagnostics.Debugger.Launch();
+
+ var classDeclarations = context.SyntaxProvider
+ .CreateSyntaxProvider(
+ predicate: IsSyntaxTargetForGeneration,
+ transform: GetSemanticTargetForGeneration)
+ .Where(m => m != null);
+
+ var compilationAndClasses = context.CompilationProvider.Combine(classDeclarations.Collect());
+
+ context.RegisterSourceOutput(compilationAndClasses, (spc, source) => Execute(spc, source.Left, source.Right));
+ }
+
+ private bool IsSyntaxTargetForGeneration(SyntaxNode node, CancellationToken cancellationToken)
+ {
+ return node is ClassDeclarationSyntax cds && cds.BaseList != null;
+ }
+
+ private INamedTypeSymbol? GetSemanticTargetForGeneration(GeneratorSyntaxContext context, CancellationToken cancellationToken)
+ {
+ var classDeclaration = (ClassDeclarationSyntax)context.Node;
+ var symbol = context.SemanticModel.GetDeclaredSymbol(classDeclaration) as INamedTypeSymbol;
+
+ if (symbol == null) return null;
+
+ if (InheritsFrom(symbol, "DiscUtils.Vfs.VfsFileSystemFactory") ||
+ InheritsFrom(symbol, "DiscUtils.Internal.VirtualDiskFactory") ||
+ InheritsFrom(symbol, "DiscUtils.Internal.LogicalVolumeFactory") ||
+ InheritsFrom(symbol, "DiscUtils.Internal.VirtualDiskTransport") ||
+ InheritsFrom(symbol, "DiscUtils.Partitions.PartitionTableFactory"))
+ {
+ return symbol;
+ }
+
+ return null;
+ }
+
+ private bool InheritsFrom(INamedTypeSymbol symbol, string typeName)
+ {
+ var current = symbol.BaseType;
+ while (current != null)
+ {
+ if (current.ToDisplayString() == typeName)
+ {
+ return true;
+ }
+ current = current.BaseType;
+ }
+ return false;
+ }
+
+ private void Execute(SourceProductionContext context, Compilation compilation, System.Collections.Immutable.ImmutableArray classes)
+ {
+ try
+ {
+ if (classes.IsDefaultOrEmpty && compilation.AssemblyName != "DiscUtils" && compilation.AssemblyName != "LTRData.DiscUtils")
+ {
+ return;
+ }
+
+ var distinctClasses = classes.Where(c => c != null).Distinct(SymbolEqualityComparer.Default).Cast().ToList();
+
+ // Generate AssemblyRegistration for libraries
+ if (distinctClasses.Any())
+ {
+ GenerateAssemblyRegistration(context, compilation, distinctClasses);
+ }
+
+ // If this is the main DiscUtils assembly, generate the aggregator
+ if (compilation.AssemblyName == "DiscUtils" || compilation.AssemblyName == "LTRData.DiscUtils")
+ {
+ GenerateSetupHelper(context, compilation);
+ }
+ }
+ catch (Exception ex)
+ {
+ // Generate a file with the error so we can see it
+ context.AddSource("GeneratorError.g.cs", SourceText.From($"/* Error: {ex.ToString()} */", Encoding.UTF8));
+ }
+ }
+
+ private void GenerateAssemblyRegistration(SourceProductionContext context, Compilation compilation, List classes)
+ {
+ var sb = new StringBuilder();
+ var assemblyName = compilation.AssemblyName?.Replace(".", "_");
+
+ sb.AppendLine("using System;");
+ sb.AppendLine("using DiscUtils.Core;");
+ sb.AppendLine();
+ sb.AppendLine($"namespace {compilation.AssemblyName}");
+ sb.AppendLine("{");
+ sb.AppendLine($" public static class AssemblyRegistration_{assemblyName}");
+ sb.AppendLine(" {");
+ sb.AppendLine(" public static void Register()");
+ sb.AppendLine(" {");
+
+ foreach (var classSymbol in classes)
+ {
+ if (InheritsFrom(classSymbol, "DiscUtils.Vfs.VfsFileSystemFactory"))
+ {
+ sb.AppendLine($" DiscUtils.FileSystemManager.RegisterFileSystems(new {classSymbol.ToDisplayString()}());");
+ }
+ else if (InheritsFrom(classSymbol, "DiscUtils.Internal.VirtualDiskFactory"))
+ {
+ sb.AppendLine($" DiscUtils.VirtualDiskManager.RegisterVirtualDiskFactory(new {classSymbol.ToDisplayString()}());");
+ }
+ else if (InheritsFrom(classSymbol, "DiscUtils.Internal.LogicalVolumeFactory"))
+ {
+ sb.AppendLine($" DiscUtils.VolumeManager.RegisterLogicalVolumeFactory(new {classSymbol.ToDisplayString()}());");
+ }
+ else if (InheritsFrom(classSymbol, "DiscUtils.Partitions.PartitionTableFactory"))
+ {
+ sb.AppendLine($" DiscUtils.Partitions.PartitionTable.RegisterPartitionTableFactory(new {classSymbol.ToDisplayString()}());");
+ }
+ else if (InheritsFrom(classSymbol, "DiscUtils.Internal.VirtualDiskTransport"))
+ {
+ var attributes = classSymbol.GetAttributes().Where(ad => ad.AttributeClass?.ToDisplayString() == "DiscUtils.Internal.VirtualDiskTransportAttribute");
+ foreach(var attr in attributes)
+ {
+ if (attr.ConstructorArguments.Length > 0)
+ {
+ string scheme = attr.ConstructorArguments[0].Value?.ToString();
+ if (!string.IsNullOrEmpty(scheme))
+ {
+ sb.AppendLine($" DiscUtils.VirtualDiskManager.RegisterVirtualDiskTransport(\"{scheme}\", () => new {classSymbol.ToDisplayString()}());");
+ }
+ }
+ }
+ }
+ }
+
+ sb.AppendLine(" }");
+ sb.AppendLine(" }");
+ sb.AppendLine("}");
+
+ context.AddSource($"AssemblyRegistration_{assemblyName}.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
+ }
+
+ private void GenerateSetupHelper(SourceProductionContext context, Compilation compilation)
+ {
+ var sb = new StringBuilder();
+ sb.AppendLine("using System;");
+ sb.AppendLine("using System.Reflection;");
+ sb.AppendLine();
+ sb.AppendLine("namespace DiscUtils.Setup");
+ sb.AppendLine("{");
+ sb.AppendLine(" public static class GeneratedSetupHelper");
+ sb.AppendLine(" {");
+ sb.AppendLine(" public static void RegisterFactories()");
+ sb.AppendLine(" {");
+ sb.AppendLine(" Console.WriteLine(\"GeneratedSetupHelper.RegisterFactories() called.\");");
+
+ foreach (var reference in compilation.References)
+ {
+ if (compilation.GetAssemblyOrModuleSymbol(reference) is IAssemblySymbol assemblySymbol)
+ {
+ var assemblyName = assemblySymbol.Name;
+ if ((assemblyName.StartsWith("DiscUtils.") || assemblyName.StartsWith("LTRData.DiscUtils.")) && !assemblyName.EndsWith("SourceGenerator"))
+ {
+ var safeAssemblyName = assemblyName.Replace(".", "_");
+ var typeName = $"{assemblyName}.AssemblyRegistration_{safeAssemblyName}";
+
+ var typeSymbol = compilation.GetTypeByMetadataName(typeName);
+
+ if (typeSymbol != null)
+ {
+ sb.AppendLine($" Console.WriteLine(\"Calling {typeName}.Register()\");");
+ sb.AppendLine($" {typeName}.Register();");
+ }
+ }
+ }
+ }
+
+ sb.AppendLine(" }");
+ sb.AppendLine(" }");
+ sb.AppendLine("}");
+
+ context.AddSource("GeneratedSetupHelper.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8));
+ }
+ }
+}
+
diff --git a/Library/DiscUtils/SetupHelper.cs b/Library/DiscUtils/SetupHelper.cs
index 9e68e892d..895416adf 100644
--- a/Library/DiscUtils/SetupHelper.cs
+++ b/Library/DiscUtils/SetupHelper.cs
@@ -6,6 +6,7 @@
using DiscUtils.Fat;
using DiscUtils.HfsPlus;
using DiscUtils.Iso9660;
+using DiscUtils.Lvm;
using DiscUtils.Nfs;
using DiscUtils.Ntfs;
using DiscUtils.OpticalDisk;
@@ -53,4 +54,10 @@ public static void SetupComplete()
Setup.SetupHelper.RegisterAssembly(typeof(Xva.Disk).Assembly);
Setup.SetupHelper.RegisterAssembly(typeof(Lvm.LogicalVolumeManager).Assembly);
}
+
+ public static void SetupCompleteAot()
+ {
+ DiskImageBuilder.ShouldUseVirtualDiskManagerTypeMap = true;
+ DiscUtils.Setup.GeneratedSetupHelper.RegisterFactories();
+ }
}
\ No newline at end of file
diff --git a/Tests/LibraryTests/Registry/RegistryKeyTest.cs b/Tests/LibraryTests/Registry/RegistryKeyTest.cs
index 6f099087e..81165c5bf 100644
--- a/Tests/LibraryTests/Registry/RegistryKeyTest.cs
+++ b/Tests/LibraryTests/Registry/RegistryKeyTest.cs
@@ -77,6 +77,34 @@ public void SetLargeValue()
Assert.Equal(0xAD, readVal[5232]);
}
+ [Fact]
+ public void SetVeryLargeValue_BigDataCell()
+ {
+ // Test big data cells (used for values >~16KB)
+ // This mimics real-world scenarios like Windows registry ProductPolicy values
+ var buffer = new byte[80 * 1024]; // 80KB - larger than big data threshold
+
+ // Set some distinctive bytes at various positions
+ buffer[0] = 0x12;
+ buffer[100] = 0x34;
+ buffer[16384] = 0x56; // Past first 16KB boundary
+ buffer[32768] = 0x78; // Past second 16KB boundary
+ buffer[buffer.Length - 1] = 0x9A;
+
+ hive.Root.SetValue("verybigvalue", buffer);
+
+ var readVal = (byte[])hive.Root.GetValue("verybigvalue");
+ Assert.Equal(buffer.Length, readVal.Length);
+ Assert.Equal(0x12, readVal[0]);
+ Assert.Equal(0x34, readVal[100]);
+ Assert.Equal(0x56, readVal[16384]);
+ Assert.Equal(0x78, readVal[32768]);
+ Assert.Equal(0x9A, readVal[buffer.Length - 1]);
+
+ // Verify entire buffer matches
+ Assert.Equal(buffer, readVal);
+ }
+
[Fact]
public void SetLongValue()
{
diff --git a/generate-packages.ps1 b/generate-packages.ps1
new file mode 100644
index 000000000..30b4e2a18
--- /dev/null
+++ b/generate-packages.ps1
@@ -0,0 +1,23 @@
+$outputDir = "C:\XGitPrivate\DevePXEBootStuff\DevePXEBootClean\DiscUtils\nupkgs"
+
+Write-Host "Cleaning output directory: $outputDir"
+if (Test-Path -Path $outputDir) {
+ Get-ChildItem -Path $outputDir -Filter *.nupkg | Remove-Item -Force
+ Get-ChildItem -Path $outputDir -Filter *.snupkg | Remove-Item -Force
+} else {
+ New-Item -ItemType Directory -Path $outputDir | Out-Null
+}
+
+Write-Host "Cleaning solution..."
+dotnet clean --configuration Release
+
+Write-Host "Restoring..."
+dotnet restore
+
+Write-Host "Building..."
+dotnet build --configuration Release
+
+Write-Host "Packing..."
+dotnet pack --configuration Release --no-build --output $outputDir
+
+Write-Host "Done. Packages are in $outputDir"