diff --git a/Aaru.Core/Image/Merge/Calculator.cs b/Aaru.Core/Image/Merge/Calculator.cs
index 4ebca9b0e..e084f6908 100644
--- a/Aaru.Core/Image/Merge/Calculator.cs
+++ b/Aaru.Core/Image/Merge/Calculator.cs
@@ -9,6 +9,24 @@ namespace Aaru.Core.Image;
public sealed partial class Merger
{
+ ///
+ /// Single extent covering sectors 0 .. sectorCount - 1, or an empty list when
+ /// is zero (avoids 0 - 1 unsigned underflow in callers).
+ ///
+ static List CreateDefaultDumpExtents(ulong sectorCount)
+ {
+ if(sectorCount == 0) return new List();
+
+ return new List
+ {
+ new Extent
+ {
+ Start = 0,
+ End = sectorCount - 1
+ }
+ };
+ }
+
List CalculateSectorsToCopy(IMediaImage primaryImage, IMediaImage secondaryImage, Resume primaryResume,
Resume secondaryResume, List overrideSectorsList)
{
@@ -16,14 +34,7 @@ public sealed partial class Merger
[
new DumpHardware
{
- Extents =
- [
- new Extent
- {
- Start = 0,
- End = primaryImage.Info.Sectors - 1
- }
- ]
+ Extents = CreateDefaultDumpExtents(primaryImage.Info.Sectors)
}
];
@@ -32,14 +43,7 @@ public sealed partial class Merger
[
new DumpHardware
{
- Extents =
- [
- new Extent
- {
- Start = 0,
- End = secondaryImage.Info.Sectors - 1
- }
- ]
+ Extents = CreateDefaultDumpExtents(secondaryImage.Info.Sectors)
}
];
@@ -93,14 +97,7 @@ public sealed partial class Merger
[
new DumpHardware
{
- Extents =
- [
- new Extent
- {
- Start = 0,
- End = primaryImage.Info.Sectors - 1
- }
- ]
+ Extents = CreateDefaultDumpExtents(primaryImage.Info.Sectors)
}
];
@@ -109,14 +106,7 @@ public sealed partial class Merger
[
new DumpHardware
{
- Extents =
- [
- new Extent
- {
- Start = 0,
- End = secondaryImage.Info.Sectors - 1
- }
- ]
+ Extents = CreateDefaultDumpExtents(secondaryImage.Info.Sectors)
}
];
diff --git a/Aaru.Core/Image/Merge/Flux.cs b/Aaru.Core/Image/Merge/Flux.cs
index d3fbd189d..d5efc9a4d 100644
--- a/Aaru.Core/Image/Merge/Flux.cs
+++ b/Aaru.Core/Image/Merge/Flux.cs
@@ -1,52 +1,140 @@
+using System.Collections.Generic;
+using System.Linq;
using Aaru.CommonTypes.Enums;
using Aaru.CommonTypes.Interfaces;
+using Aaru.CommonTypes.Structs;
namespace Aaru.Core.Image;
public sealed partial class Merger
{
- // TODO: Should we return error any time?
- // TODO: Add progress reporting
- ErrorNumber CopyFlux(IFluxImage inputFlux, IWritableFluxImage outputFlux)
+ ErrorNumber MergeFlux(IFluxImage primaryFlux, IFluxImage secondaryFlux, IWritableFluxImage outputFlux)
{
- for(ushort track = 0; track < inputFlux.Info.Cylinders; track++)
+ ErrorNumber error = primaryFlux.GetAllFluxCaptures(out List primaryCaptures);
+
+ if(error != ErrorNumber.NoError) return error;
+
+ if(primaryCaptures is null) primaryCaptures = new List();
+
+ List secondaryCaptures = new List();
+
+ if(secondaryFlux != null)
{
- for(uint head = 0; head < inputFlux.Info.Heads; head++)
+ error = secondaryFlux.GetAllFluxCaptures(out secondaryCaptures);
+
+ if(error != ErrorNumber.NoError) return error;
+
+ if(secondaryCaptures is null) secondaryCaptures = new List();
+ }
+
+ Dictionary<(uint Head, ushort Track, byte SubTrack), List> primaryByLocation =
+ GroupFluxCapturesByLocation(primaryCaptures);
+
+ Dictionary<(uint Head, ushort Track, byte SubTrack), List> secondaryByLocation =
+ GroupFluxCapturesByLocation(secondaryCaptures);
+
+ HashSet<(uint Head, ushort Track, byte SubTrack)> allKeys = new HashSet<(uint Head, ushort Track, byte SubTrack)>();
+
+ foreach((uint Head, ushort Track, byte SubTrack) key in primaryByLocation.Keys) allKeys.Add(key);
+
+ foreach((uint Head, ushort Track, byte SubTrack) key in secondaryByLocation.Keys) allKeys.Add(key);
+
+ List<(uint Head, ushort Track, byte SubTrack)> sortedKeys =
+ allKeys.OrderBy(static k => k.Track).ThenBy(static k => k.Head).ThenBy(static k => k.SubTrack).ToList();
+
+ foreach((uint Head, ushort Track, byte SubTrack) key in sortedKeys)
+ {
+ List primaryGroup =
+ primaryByLocation.TryGetValue(key, out List pg) ? pg : new List();
+
+ List secondaryGroup =
+ secondaryByLocation.TryGetValue(key, out List sg) ? sg : new List();
+
+ primaryGroup.Sort((FluxCapture a, FluxCapture b) => a.CaptureIndex.CompareTo(b.CaptureIndex));
+ secondaryGroup.Sort((FluxCapture a, FluxCapture b) => a.CaptureIndex.CompareTo(b.CaptureIndex));
+
+ uint outputIndex = 0;
+
+ foreach(FluxCapture capture in primaryGroup)
{
- ErrorNumber error = inputFlux.SubTrackLength(head, track, out byte subTrackLen);
+ error = primaryFlux.ReadFluxCapture(capture.Head,
+ capture.Track,
+ capture.SubTrack,
+ capture.CaptureIndex,
+ out ulong indexResolution,
+ out ulong dataResolution,
+ out byte[] indexBuffer,
+ out byte[] dataBuffer);
- if(error != ErrorNumber.NoError) continue;
+ if(error != ErrorNumber.NoError) return error;
- for(byte subTrackIndex = 0; subTrackIndex < subTrackLen; subTrackIndex++)
+ error = outputFlux.WriteFluxCapture(indexResolution,
+ dataResolution,
+ indexBuffer,
+ dataBuffer,
+ capture.Head,
+ capture.Track,
+ capture.SubTrack,
+ outputIndex);
+
+ if(error != ErrorNumber.NoError) return error;
+
+ outputIndex++;
+ }
+
+ if(secondaryFlux != null)
+ {
+ foreach(FluxCapture capture in secondaryGroup)
{
- error = inputFlux.CapturesLength(head, track, subTrackIndex, out uint capturesLen);
+ error = secondaryFlux.ReadFluxCapture(capture.Head,
+ capture.Track,
+ capture.SubTrack,
+ capture.CaptureIndex,
+ out ulong indexResolution,
+ out ulong dataResolution,
+ out byte[] indexBuffer,
+ out byte[] dataBuffer);
- if(error != ErrorNumber.NoError) continue;
+ if(error != ErrorNumber.NoError) return error;
- for(uint captureIndex = 0; captureIndex < capturesLen; captureIndex++)
- {
- inputFlux.ReadFluxCapture(head,
- track,
- subTrackIndex,
- captureIndex,
- out ulong indexResolution,
- out ulong dataResolution,
- out byte[] indexBuffer,
- out byte[] dataBuffer);
+ error = outputFlux.WriteFluxCapture(indexResolution,
+ dataResolution,
+ indexBuffer,
+ dataBuffer,
+ capture.Head,
+ capture.Track,
+ capture.SubTrack,
+ outputIndex);
- outputFlux.WriteFluxCapture(indexResolution,
- dataResolution,
- indexBuffer,
- dataBuffer,
- head,
- track,
- subTrackIndex,
- captureIndex);
- }
+ if(error != ErrorNumber.NoError) return error;
+
+ outputIndex++;
}
}
}
return ErrorNumber.NoError;
}
-}
\ No newline at end of file
+
+ static Dictionary<(uint Head, ushort Track, byte SubTrack), List> GroupFluxCapturesByLocation(
+ List captures)
+ {
+ Dictionary<(uint Head, ushort Track, byte SubTrack), List> result =
+ new Dictionary<(uint Head, ushort Track, byte SubTrack), List>();
+
+ foreach(FluxCapture capture in captures)
+ {
+ (uint Head, ushort Track, byte SubTrack) key = (capture.Head, capture.Track, capture.SubTrack);
+
+ if(!result.TryGetValue(key, out List list))
+ {
+ list = new List();
+ result[key] = list;
+ }
+
+ list.Add(capture);
+ }
+
+ return result;
+ }
+}
diff --git a/Aaru.Core/Image/Merge/Merger.cs b/Aaru.Core/Image/Merge/Merger.cs
index 947818d15..de7693a30 100644
--- a/Aaru.Core/Image/Merge/Merger.cs
+++ b/Aaru.Core/Image/Merge/Merger.cs
@@ -220,12 +220,15 @@ public sealed partial class Merger
InitProgress?.Invoke();
PulseProgress?.Invoke(UI.Calculating_sectors_to_merge);
- List sectorsToCopyFromSecondImage =
- CalculateSectorsToCopy(primaryImage, secondaryImage, primaryResume, secondaryResume, overrideSectorsList);
+ List sectorsToCopyFromSecondImage =
+ CalculateSectorsToCopy(primaryImage, secondaryImage, primaryResume, secondaryResume, overrideSectorsList);
EndProgress?.Invoke();
- if(sectorsToCopyFromSecondImage.Count == 0)
+ // Flux images might contain no decoded data, which results in a sector count of 0. We allow this if the image contains flux.
+ var containsFlux = primaryImage is IFluxImage || secondaryImage is IFluxImage;
+
+ if(sectorsToCopyFromSecondImage.Count == 0 && !containsFlux)
{
StoppingErrorMessage
?.Invoke(UI.No_sectors_to_merge__output_image_will_be_identical_to_primary_image_not_continuing);
@@ -344,10 +347,15 @@ public sealed partial class Merger
if(errno != ErrorNumber.NoError) return errno;
- if(primaryImage is IFluxImage inputFlux && outputFormat is IWritableFluxImage outputFlux)
+ if(primaryImage is IFluxImage primaryFlux && outputFormat is IWritableFluxImage outputFlux)
{
- UpdateStatus?.Invoke(UI.Flux_data_will_be_copied_as_is_from_primary_image);
- errno = CopyFlux(inputFlux, outputFlux);
+ IFluxImage secondaryFlux = secondaryImage as IFluxImage;
+
+ UpdateStatus?.Invoke(secondaryFlux != null
+ ? UI.Flux_merge_primary_then_secondary_appended
+ : UI.Flux_merge_primary_flux_only_secondary_not_flux_image);
+
+ errno = MergeFlux(primaryFlux, secondaryFlux, outputFlux);
if(errno != ErrorNumber.NoError) return errno;
}
diff --git a/Aaru.Localization/UI.Designer.cs b/Aaru.Localization/UI.Designer.cs
index 05a940b97..a56190ee1 100644
--- a/Aaru.Localization/UI.Designer.cs
+++ b/Aaru.Localization/UI.Designer.cs
@@ -5115,6 +5115,24 @@ namespace Aaru.Localization {
return ResourceManager.GetString("Flux_data_will_be_copied_as_is_from_primary_image", resourceCulture);
}
}
+
+ ///
+ /// Looks up localized string similar to Merging flux: primary captures first, then secondary captures appended with renumbered indices...
+ ///
+ public static string Flux_merge_primary_then_secondary_appended {
+ get {
+ return ResourceManager.GetString("Flux_merge_primary_then_secondary_appended", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up localized string similar to Secondary image is not a flux image; copying flux captures from the primary image only...
+ ///
+ public static string Flux_merge_primary_flux_only_secondary_not_flux_image {
+ get {
+ return ResourceManager.GetString("Flux_merge_primary_flux_only_secondary_not_flux_image", resourceCulture);
+ }
+ }
///
/// Looks up a localized string similar to Force geometry, only supported in not tape block media. Specify as C/H/S..
diff --git a/Aaru.Localization/UI.es.resx b/Aaru.Localization/UI.es.resx
index c2b869968..49a56a7b9 100644
--- a/Aaru.Localization/UI.es.resx
+++ b/Aaru.Localization/UI.es.resx
@@ -5452,8 +5452,11 @@ Probadores:
[slateblue1]Se copiarán [teal]{0}[/] sectores de la imagen secundaria.[/]
-
- [slateblue1]Los datos de flujo se copiarán tal cual de la imagen primaria...[/]
+
+ [slateblue1]Combinando flujo: primero capturas de la imagen primaria, luego las de la secundaria con índices renumerados...[/]
+
+
+ [slateblue1]La imagen secundaria no es de flujo; copiando solo las capturas de flujo de la imagen primaria...[/]
[slateblue1]Copiando fichero [lime]{0}[/] de partición [teal]{1}[/]...[/]
diff --git a/Aaru.Localization/UI.resx b/Aaru.Localization/UI.resx
index 962f662de..b0c60dd0f 100644
--- a/Aaru.Localization/UI.resx
+++ b/Aaru.Localization/UI.resx
@@ -5536,8 +5536,11 @@ Do you want to continue?
[slateblue1]Will copy [teal]{0}[/] sectors from secondary image.[/]
-
- [slateblue1]Flux data will be copied as-is from primary image...[/]
+
+ [slateblue1]Merging flux: primary captures first, then secondary captures appended with renumbered indices...[/]
+
+
+ [slateblue1]Secondary image is not a flux image; copying flux captures from the primary image only...[/]
[slateblue1]Copying file [lime]{0}[/] of partition [teal]{1}[/]...[/]