mirror of
https://github.com/aaru-dps/Aaru.git
synced 2026-02-04 00:44:39 +00:00
Merge remote-tracking branch 'origin/fakeshemp/flux' into devel
This commit is contained in:
@@ -36,8 +36,10 @@
|
||||
// Copyright © 2011-2026 Rebecca Wallander
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Aaru.CommonTypes.Enums;
|
||||
using Aaru.CommonTypes.Structs;
|
||||
|
||||
namespace Aaru.CommonTypes.Interfaces;
|
||||
|
||||
@@ -127,4 +129,12 @@ public interface IFluxImage : IBaseImage
|
||||
/// <param name="track">Physical track (position of the heads over the floppy media, 0-based)</param>
|
||||
/// <param name="length">The number of captures</param>
|
||||
ErrorNumber SubTrackLength(uint head, ushort track, out byte length);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of all flux captures in the image. This provides a convenient way to enumerate all captures
|
||||
/// without needing to know the geometry ahead of time.
|
||||
/// </summary>
|
||||
/// <param name="captures">List of all flux captures in the image, or null if an error occurred</param>
|
||||
/// <returns>Error number</returns>
|
||||
ErrorNumber GetAllFluxCaptures(out List<FluxCapture> captures);
|
||||
}
|
||||
@@ -257,4 +257,14 @@ public class LinearMemoryInterleave
|
||||
|
||||
/// <summary>How many bytes in memory to skip every device byte</summary>
|
||||
public uint Value { get; set; }
|
||||
}
|
||||
|
||||
public class FluxCapture
|
||||
{
|
||||
public uint Head { get; set; }
|
||||
public ushort Track { get; set; }
|
||||
public byte SubTrack { get; set; }
|
||||
public uint CaptureIndex { get; set; }
|
||||
public ulong IndexResolution { get; set; }
|
||||
public ulong DataResolution { get; set; }
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Aaru.CommonTypes.Enums;
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
using Aaru.CommonTypes.Structs;
|
||||
|
||||
namespace Aaru.Core.Image;
|
||||
|
||||
@@ -9,42 +11,33 @@ public partial class Convert
|
||||
// TODO: Add progress reporting
|
||||
ErrorNumber ConvertFlux(IFluxImage inputFlux, IWritableFluxImage outputFlux)
|
||||
{
|
||||
for(ushort track = 0; track < inputFlux.Info.Cylinders; track++)
|
||||
ErrorNumber error = inputFlux.GetAllFluxCaptures(out List<FluxCapture> captures);
|
||||
|
||||
if(error != ErrorNumber.NoError) return error;
|
||||
|
||||
if(captures is null || captures.Count == 0) return ErrorNumber.NoError;
|
||||
|
||||
foreach(FluxCapture capture in captures)
|
||||
{
|
||||
for(uint head = 0; head < inputFlux.Info.Heads; head++)
|
||||
{
|
||||
ErrorNumber error = inputFlux.SubTrackLength(head, track, out byte subTrackLen);
|
||||
error = inputFlux.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) continue;
|
||||
|
||||
for(byte subTrackIndex = 0; subTrackIndex < subTrackLen; subTrackIndex++)
|
||||
{
|
||||
error = inputFlux.CapturesLength(head, track, subTrackIndex, out uint capturesLen);
|
||||
|
||||
if(error != ErrorNumber.NoError) continue;
|
||||
|
||||
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);
|
||||
|
||||
outputFlux.WriteFluxCapture(indexResolution,
|
||||
dataResolution,
|
||||
indexBuffer,
|
||||
dataBuffer,
|
||||
head,
|
||||
track,
|
||||
subTrackIndex,
|
||||
captureIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
outputFlux.WriteFluxCapture(indexResolution,
|
||||
dataResolution,
|
||||
indexBuffer,
|
||||
dataBuffer,
|
||||
capture.Head,
|
||||
capture.Track,
|
||||
capture.SubTrack,
|
||||
capture.CaptureIndex);
|
||||
}
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
|
||||
@@ -98,7 +98,7 @@ public static class Partitions
|
||||
}
|
||||
|
||||
// Getting all partitions at start of device
|
||||
if(!checkedLocations.Contains(0))
|
||||
if(!checkedLocations.Contains(0) && image.Info.Sectors > 0)
|
||||
{
|
||||
foreach(IPartition plugin in plugins.Partitions.Values)
|
||||
{
|
||||
|
||||
44
Aaru.Gui/Models/FluxCaptureModel.cs
Normal file
44
Aaru.Gui/Models/FluxCaptureModel.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : FluxCaptureModel.cs
|
||||
// Author(s) : Rebecca Wallander <sakcheen@gmail.com>
|
||||
//
|
||||
// Component : GUI data models.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Contains information about flux captures.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2025 Rebecca Wallander
|
||||
// ****************************************************************************/
|
||||
|
||||
namespace Aaru.Gui.Models;
|
||||
|
||||
public sealed class FluxCaptureModel
|
||||
{
|
||||
public uint Head { get; set; }
|
||||
public ushort Track { get; set; }
|
||||
public byte SubTrack { get; set; }
|
||||
public uint CaptureIndex { get; set; }
|
||||
public ulong IndexResolution { get; set; }
|
||||
public ulong DataResolution { get; set; }
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -38,6 +39,7 @@ using System.Windows.Input;
|
||||
using Aaru.CommonTypes.AaruMetadata;
|
||||
using Aaru.CommonTypes.Enums;
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
using Aaru.CommonTypes.Structs;
|
||||
using Aaru.CommonTypes.Structs.Devices.SCSI;
|
||||
using Aaru.Decoders.CD;
|
||||
using Aaru.Decoders.DVD;
|
||||
@@ -815,6 +817,19 @@ public sealed class ImageInfoViewModel : ViewModelBase
|
||||
}
|
||||
}
|
||||
|
||||
if(imageFormat is IFluxImage fluxImage)
|
||||
{
|
||||
ErrorNumber fluxError = fluxImage.GetAllFluxCaptures(out List<FluxCapture> fluxCaptures);
|
||||
|
||||
if(fluxError == ErrorNumber.NoError && fluxCaptures is { Count: > 0 })
|
||||
{
|
||||
FluxInfo = new FluxInfo
|
||||
{
|
||||
DataContext = new FluxInfoViewModel(fluxCaptures)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if(imageFormat.DumpHardware is null) return;
|
||||
|
||||
foreach(DumpHardware dump in imageFormat.DumpHardware)
|
||||
@@ -845,6 +860,7 @@ public sealed class ImageInfoViewModel : ViewModelBase
|
||||
public XboxInfo XboxInfo { get; }
|
||||
public PcmciaInfo PcmciaInfo { get; }
|
||||
public SdMmcInfo SdMmcInfo { get; }
|
||||
public FluxInfo FluxInfo { get; }
|
||||
public IImage MediaLogo { get; }
|
||||
public string ImagePathText { get; }
|
||||
public string FilterText { get; }
|
||||
|
||||
66
Aaru.Gui/ViewModels/Tabs/FluxInfoViewModel.cs
Normal file
66
Aaru.Gui/ViewModels/Tabs/FluxInfoViewModel.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : FluxInfoViewModel.cs
|
||||
// Author(s) : Rebecca Wallander <sakcheen@gmail.com>
|
||||
//
|
||||
// Component : GUI view models.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// View model and code for the Flux information tab.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2025 Rebecca Wallander
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Aaru.CommonTypes.Structs;
|
||||
using Aaru.Gui.Models;
|
||||
|
||||
namespace Aaru.Gui.ViewModels.Tabs;
|
||||
|
||||
public sealed class FluxInfoViewModel : ViewModelBase
|
||||
{
|
||||
public FluxInfoViewModel(List<FluxCapture> fluxCaptures)
|
||||
{
|
||||
FluxCaptures = [];
|
||||
|
||||
if(fluxCaptures is { Count: > 0 })
|
||||
{
|
||||
foreach(FluxCapture capture in fluxCaptures)
|
||||
{
|
||||
FluxCaptures.Add(new FluxCaptureModel
|
||||
{
|
||||
Head = capture.Head,
|
||||
Track = capture.Track,
|
||||
SubTrack = capture.SubTrack,
|
||||
CaptureIndex = capture.CaptureIndex,
|
||||
IndexResolution = capture.IndexResolution,
|
||||
DataResolution = capture.DataResolution
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<FluxCaptureModel> FluxCaptures { get; }
|
||||
}
|
||||
|
||||
@@ -734,6 +734,13 @@
|
||||
<ContentControl Content="{Binding DvdInfo, Mode=OneWay}"
|
||||
Margin="8" />
|
||||
</TabItem>
|
||||
<TabItem IsVisible="{Binding !!FluxInfo, Mode=OneWay}">
|
||||
<TabItem.Header>
|
||||
<controls:SpectreTextBlock Text="Flux Captures" />
|
||||
</TabItem.Header>
|
||||
<ContentControl Content="{Binding FluxInfo, Mode=OneWay}"
|
||||
Margin="8" />
|
||||
</TabItem>
|
||||
<TabItem IsVisible="{Binding !!DvdWritableInfo, Mode=OneWay}">
|
||||
<TabItem.Header>
|
||||
<StackPanel Orientation="Horizontal"
|
||||
|
||||
156
Aaru.Gui/Views/Tabs/FluxInfo.xaml
Normal file
156
Aaru.Gui/Views/Tabs/FluxInfo.xaml
Normal file
@@ -0,0 +1,156 @@
|
||||
<!--
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
|
||||
//
|
||||
// Filename : FluxInfo.xaml
|
||||
// Author(s) : Rebecca Wallander <sakcheen@gmail.com>
|
||||
//
|
||||
// Component : GUI tabs.
|
||||
//
|
||||
// ‐‐[ Description ] ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
|
||||
//
|
||||
// Flux information tab.
|
||||
//
|
||||
// ‐‐[ License ] ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
|
||||
// Copyright © 2011-2025 Rebecca Wallander
|
||||
// ****************************************************************************/
|
||||
-->
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:tabs="clr-namespace:Aaru.Gui.ViewModels.Tabs"
|
||||
xmlns:localization="clr-namespace:Aaru.Localization;assembly=Aaru.Localization"
|
||||
xmlns:controls="clr-namespace:Aaru.Gui.Controls"
|
||||
mc:Ignorable="d"
|
||||
d:DesignWidth="800"
|
||||
d:DesignHeight="450"
|
||||
x:DataType="tabs:FluxInfoViewModel"
|
||||
x:Class="Aaru.Gui.Views.Tabs.FluxInfo">
|
||||
<Design.DataContext>
|
||||
<tabs:FluxInfoViewModel />
|
||||
</Design.DataContext>
|
||||
<Grid Margin="8">
|
||||
<DataGrid ItemsSource="{Binding FluxCaptures, Mode=OneWay}"
|
||||
IsReadOnly="True"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
AutoGenerateColumns="False">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.HeaderTemplate>
|
||||
<DataTemplate>
|
||||
<controls:SpectreTextBlock Text="Head"
|
||||
Padding="5"
|
||||
VerticalAlignment="Center" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.HeaderTemplate>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Head, Mode=OneWay}"
|
||||
Padding="5"
|
||||
VerticalAlignment="Center" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.HeaderTemplate>
|
||||
<DataTemplate>
|
||||
<controls:SpectreTextBlock Text="{x:Static localization:Core.Title_Track}"
|
||||
Padding="5"
|
||||
VerticalAlignment="Center" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.HeaderTemplate>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Track, Mode=OneWay}"
|
||||
Padding="5"
|
||||
VerticalAlignment="Center" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.HeaderTemplate>
|
||||
<DataTemplate>
|
||||
<controls:SpectreTextBlock Text="SubTrack"
|
||||
Padding="5"
|
||||
VerticalAlignment="Center" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.HeaderTemplate>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding SubTrack, Mode=OneWay}"
|
||||
Padding="5"
|
||||
VerticalAlignment="Center" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.HeaderTemplate>
|
||||
<DataTemplate>
|
||||
<controls:SpectreTextBlock Text="Capture Index"
|
||||
Padding="5"
|
||||
VerticalAlignment="Center" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.HeaderTemplate>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding CaptureIndex, Mode=OneWay}"
|
||||
Padding="5"
|
||||
VerticalAlignment="Center" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.HeaderTemplate>
|
||||
<DataTemplate>
|
||||
<controls:SpectreTextBlock Text="Index Resolution"
|
||||
Padding="5"
|
||||
VerticalAlignment="Center" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.HeaderTemplate>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding IndexResolution, Mode=OneWay}"
|
||||
Padding="5"
|
||||
VerticalAlignment="Center" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
<DataGridTemplateColumn Width="*">
|
||||
<DataGridTemplateColumn.HeaderTemplate>
|
||||
<DataTemplate>
|
||||
<controls:SpectreTextBlock Text="Data Resolution"
|
||||
Padding="5"
|
||||
VerticalAlignment="Center" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.HeaderTemplate>
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding DataResolution, Mode=OneWay}"
|
||||
Padding="5"
|
||||
VerticalAlignment="Center" />
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
|
||||
44
Aaru.Gui/Views/Tabs/FluxInfo.xaml.cs
Normal file
44
Aaru.Gui/Views/Tabs/FluxInfo.xaml.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : FluxInfo.xaml.cs
|
||||
// Author(s) : Rebecca Wallander <sakcheen@gmail.com>
|
||||
//
|
||||
// Component : GUI tabs.
|
||||
//
|
||||
// --[ Description ] ----------------------------------------------------------
|
||||
//
|
||||
// Flux information tab.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2025 Rebecca Wallander
|
||||
// ****************************************************************************/
|
||||
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace Aaru.Gui.Views.Tabs;
|
||||
|
||||
public sealed class FluxInfo : UserControl
|
||||
{
|
||||
public FluxInfo() => InitializeComponent();
|
||||
|
||||
void InitializeComponent() => AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
@@ -39,6 +39,7 @@ using System.Text;
|
||||
using Aaru.CommonTypes;
|
||||
using Aaru.CommonTypes.Enums;
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
using Aaru.CommonTypes.Structs;
|
||||
using Aaru.Helpers;
|
||||
using Aaru.Logging;
|
||||
|
||||
@@ -505,4 +506,37 @@ public sealed partial class A2R
|
||||
|
||||
return _a2RCaptures.FindAll(capture => index == capture.location)[(int)captureIndex];
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber GetAllFluxCaptures(out List<FluxCapture> captures)
|
||||
{
|
||||
captures = [];
|
||||
|
||||
if(_a2RCaptures is { Count: > 0 })
|
||||
{
|
||||
// Group captures by head/track/subtrack to assign capture indices
|
||||
var grouped = _a2RCaptures.GroupBy(c => new { c.head, c.track, c.subTrack })
|
||||
.ToList();
|
||||
|
||||
foreach(var group in grouped)
|
||||
{
|
||||
uint captureIndex = 0;
|
||||
|
||||
foreach(StreamCapture streamCapture in group)
|
||||
{
|
||||
captures.Add(new FluxCapture
|
||||
{
|
||||
Head = streamCapture.head,
|
||||
Track = streamCapture.track,
|
||||
SubTrack = streamCapture.subTrack,
|
||||
CaptureIndex = captureIndex++,
|
||||
IndexResolution = streamCapture.resolution,
|
||||
DataResolution = streamCapture.resolution
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace Aaru.Images;
|
||||
|
||||
/// <inheritdoc cref="Aaru.CommonTypes.Interfaces.IWritableOpticalImage" />
|
||||
/// <summary>Implements reading and writing AaruFormat media images</summary>
|
||||
public sealed partial class AaruFormat : IWritableOpticalImage, IVerifiableImage, IWritableTapeImage, IDisposable
|
||||
public sealed partial class AaruFormat : IWritableOpticalImage, IVerifiableImage, IWritableTapeImage, IWritableFluxImage, IDisposable
|
||||
{
|
||||
const string MODULE_NAME = "Aaru Format plugin";
|
||||
IntPtr _context;
|
||||
|
||||
@@ -40,7 +40,9 @@ public sealed partial class AaruFormat
|
||||
/// <summary>Block containing list of indexes for Compact Disc tracks</summary>
|
||||
CompactDiscIndexesBlock = 0x58494443,
|
||||
/// <summary>Block containing JSON version of Aaru Metadata</summary>
|
||||
AaruMetadataJsonBlock = 0x444D534A
|
||||
AaruMetadataJsonBlock = 0x444D534A,
|
||||
/// <summary>Block containing list of flux captures</summary>
|
||||
FluxCapturesBlock = 0x58554C46
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -211,12 +213,16 @@ public sealed partial class AaruFormat
|
||||
/// <remarks>AARUF_ERROR_METADATA_NOT_PRESENT</remarks>
|
||||
/// </summary>
|
||||
MetadataNotPresent = -30,
|
||||
/// <summary>
|
||||
/// Sector length is too big.
|
||||
/// <remarks>AARUF_ERROR_INVALID_SECTOR_LENGTH</remarks>
|
||||
/// </summary>
|
||||
InvalidSectorLength = -31
|
||||
InvalidSectorLength = -31,
|
||||
/// <summary>
|
||||
/// Requested flux data not present in image.
|
||||
/// <remarks>AARUF_ERROR_FLUX_DATA_NOT_FOUND</remarks>
|
||||
/// </summary>
|
||||
FluxDataNotFound = -32
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
242
Aaru.Images/AaruFormat/Flux.cs
Normal file
242
Aaru.Images/AaruFormat/Flux.cs
Normal file
@@ -0,0 +1,242 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using Aaru.CommonTypes.Enums;
|
||||
using Aaru.CommonTypes.Structs;
|
||||
using Marshal = System.Runtime.InteropServices.Marshal;
|
||||
|
||||
namespace Aaru.Images;
|
||||
|
||||
public sealed partial class AaruFormat
|
||||
{
|
||||
List<FluxCapture> _fluxCaptures;
|
||||
|
||||
#region IWritableFluxImage Members
|
||||
|
||||
/// <inheritdoc />
|
||||
public List<FluxCapture> FluxCaptures
|
||||
{
|
||||
get
|
||||
{
|
||||
if(_fluxCaptures is not null) return _fluxCaptures;
|
||||
|
||||
nuint length = 0;
|
||||
|
||||
Status res = aaruf_get_flux_captures(_context, null, ref length);
|
||||
|
||||
if(res != Status.BufferTooSmall)
|
||||
{
|
||||
ErrorMessage = StatusToErrorMessage(res);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
byte[] buffer = new byte[length];
|
||||
|
||||
res = aaruf_get_flux_captures(_context, buffer, ref length);
|
||||
|
||||
if(res != Status.Ok)
|
||||
{
|
||||
ErrorMessage = StatusToErrorMessage(res);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
int fluxCaptureSize = Marshal.SizeOf<FluxCaptureEntry>();
|
||||
int fluxCaptureCount = (int)length / fluxCaptureSize;
|
||||
|
||||
_fluxCaptures = new List<FluxCapture>(fluxCaptureCount);
|
||||
|
||||
IntPtr ptr = Marshal.AllocHGlobal(fluxCaptureCount * fluxCaptureSize);
|
||||
|
||||
try
|
||||
{
|
||||
Marshal.Copy(buffer, 0, ptr, (int)length);
|
||||
|
||||
for(int i = 0; i < fluxCaptureCount; i++)
|
||||
{
|
||||
nint fluxCapturePtr = IntPtr.Add(ptr, i * fluxCaptureSize);
|
||||
FluxCaptureEntry entry = Marshal.PtrToStructure<FluxCaptureEntry>(fluxCapturePtr);
|
||||
|
||||
var capture = new FluxCapture
|
||||
{
|
||||
Head = entry.Head,
|
||||
Track = entry.Track,
|
||||
SubTrack = entry.SubTrack,
|
||||
CaptureIndex = entry.CaptureIndex,
|
||||
IndexResolution = entry.IndexResolution,
|
||||
DataResolution = entry.DataResolution,
|
||||
};
|
||||
|
||||
_fluxCaptures.Add(capture);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
_fluxCaptures = null;
|
||||
#pragma warning disable ERP022
|
||||
}
|
||||
#pragma warning restore ERP022
|
||||
finally
|
||||
{
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
}
|
||||
|
||||
return _fluxCaptures;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber CapturesLength(uint head, ushort track, byte subTrack, out uint length)
|
||||
{
|
||||
length = (uint)FluxCaptures.FindAll(capture => capture.Head == head && capture.Track == track && capture.SubTrack == subTrack).Count;
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadFluxIndexResolution(uint head, ushort track, byte subTrack, uint captureIndex, out ulong resolution)
|
||||
{
|
||||
FluxCapture capture = FluxCaptures.Find(capture => capture.Head == head && capture.Track == track && capture.SubTrack == subTrack && capture.CaptureIndex == captureIndex);
|
||||
|
||||
resolution = capture.IndexResolution;
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadFluxDataResolution(uint head, ushort track, byte subTrack, uint captureIndex, out ulong resolution)
|
||||
{
|
||||
FluxCapture capture = FluxCaptures.Find(capture => capture.Head == head && capture.Track == track && capture.SubTrack == subTrack && capture.CaptureIndex == captureIndex);
|
||||
|
||||
resolution = capture.DataResolution;
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadFluxResolution(uint head, ushort track, byte subTrack, uint captureIndex, out ulong indexResolution, out ulong dataResolution)
|
||||
{
|
||||
FluxCapture capture = FluxCaptures.Find(capture => capture.Head == head && capture.Track == track && capture.SubTrack == subTrack && capture.CaptureIndex == captureIndex);
|
||||
|
||||
indexResolution = capture.IndexResolution;
|
||||
dataResolution = capture.DataResolution;
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadFluxCapture(uint head, ushort track, byte subTrack, uint captureIndex, out ulong indexResolution, out ulong dataResolution, out byte[] indexBuffer, out byte[] dataBuffer)
|
||||
{
|
||||
FluxCapture capture = FluxCaptures.Find(capture => capture.Head == head && capture.Track == track && capture.SubTrack == subTrack && capture.CaptureIndex == captureIndex);
|
||||
|
||||
nuint indexLength = 0;
|
||||
nuint dataLength = 0;
|
||||
|
||||
Status res = aaruf_read_flux_capture(_context, head, track, subTrack, captureIndex, null, ref indexLength, null, ref dataLength);
|
||||
|
||||
if(res != Status.BufferTooSmall)
|
||||
{
|
||||
indexResolution = 0;
|
||||
dataResolution = 0;
|
||||
indexBuffer = null;
|
||||
dataBuffer = null;
|
||||
return StatusToErrorNumber(res);
|
||||
}
|
||||
|
||||
indexBuffer = new byte[indexLength];
|
||||
dataBuffer = new byte[dataLength];
|
||||
|
||||
res = aaruf_read_flux_capture(_context, head, track, subTrack, captureIndex, indexBuffer, ref indexLength, dataBuffer, ref dataLength);
|
||||
|
||||
if(res != Status.Ok)
|
||||
{
|
||||
indexResolution = 0;
|
||||
dataResolution = 0;
|
||||
indexBuffer = null;
|
||||
dataBuffer = null;
|
||||
return StatusToErrorNumber(res);
|
||||
}
|
||||
|
||||
indexResolution = capture.IndexResolution;
|
||||
dataResolution = capture.DataResolution;
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadFluxIndexCapture(uint head, ushort track, byte subTrack, uint captureIndex, out byte[] buffer)
|
||||
{
|
||||
return ReadFluxCapture(head, track, subTrack, captureIndex, out _, out _, out buffer, out _);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadFluxDataCapture(uint head, ushort track, byte subTrack, uint captureIndex, out byte[] buffer)
|
||||
{
|
||||
return ReadFluxCapture(head, track, subTrack, captureIndex, out _, out _, out _, out buffer);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber SubTrackLength(uint head, ushort track, out byte length)
|
||||
{
|
||||
length = (byte)(FluxCaptures.FindAll(capture => capture.Head == head && capture.Track == track).Max(capture => capture.SubTrack) + 1);
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber GetAllFluxCaptures(out List<FluxCapture> captures)
|
||||
{
|
||||
captures = FluxCaptures;
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteFluxCapture(ulong indexResolution, ulong dataResolution, byte[] indexBuffer, byte[] dataBuffer, uint head, ushort track, byte subTrack, uint captureIndex)
|
||||
{
|
||||
Status res = aaruf_write_flux_capture(_context, head, track, subTrack, captureIndex, dataResolution, indexResolution, dataBuffer, (uint)dataBuffer.Length, indexBuffer, (uint)indexBuffer.Length);
|
||||
|
||||
if(res != Status.Ok) return StatusToErrorNumber(res);
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteFluxIndexCapture(ulong resolution, byte[] index, uint head, ushort track, byte subTrack, uint captureIndex)
|
||||
{
|
||||
return ErrorNumber.NotImplemented;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber WriteFluxDataCapture(ulong resolution, byte[] data, uint head, ushort track, byte subTrack, uint captureIndex)
|
||||
{
|
||||
return ErrorNumber.NotImplemented;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
// AARU_EXPORT int32_t AARU_CALL aaruf_get_flux_captures(void *context, uint8_t *buffer, size_t *length)
|
||||
[LibraryImport("libaaruformat", EntryPoint = "aaruf_get_flux_captures", SetLastError = true)]
|
||||
[UnmanagedCallConv(CallConvs = [typeof(CallConvStdcall)])]
|
||||
private static partial Status aaruf_get_flux_captures(IntPtr context, byte[] buffer, ref nuint length);
|
||||
|
||||
// AARU_EXPORT int32_t AARU_CALL aaruf_read_flux_capture(void *context, uint32_t head, uint16_t track, uint8_t subtrack,
|
||||
// uint8_t capture_index, uint8_t *index_data,
|
||||
// uint32_t *index_length, uint8_t *data_data,
|
||||
// uint32_t *data_length)
|
||||
[LibraryImport("libaaruformat", EntryPoint = "aaruf_read_flux_capture", SetLastError = true)]
|
||||
[UnmanagedCallConv(CallConvs = [typeof(CallConvStdcall)])]
|
||||
private static partial Status aaruf_read_flux_capture(IntPtr context, uint head, ushort track, byte subtrack, uint captureIndex, byte[] indexData, ref nuint indexLength, byte[] dataData, ref nuint dataLength);
|
||||
|
||||
// AARU_EXPORT int32_t AARU_CALL aaruf_write_flux_capture(void *context, uint32_t head, uint16_t track, uint8_t subtrack,
|
||||
// uint16_t capture_index, uint64_t data_resolution,
|
||||
// uint64_t index_resolution, const uint8_t *data,
|
||||
// uint32_t data_length, const uint8_t *index,
|
||||
// uint32_t index_length);
|
||||
[LibraryImport("libaaruformat", EntryPoint = "aaruf_write_flux_capture", SetLastError = true)]
|
||||
[UnmanagedCallConv(CallConvs = [typeof(CallConvStdcall)])]
|
||||
private static partial Status aaruf_write_flux_capture(IntPtr context, uint head, ushort track, byte subtrack, uint captureIndex, ulong dataResolution, ulong indexResolution, byte[] data, uint dataLength, byte[] index, uint indexLength);
|
||||
}
|
||||
@@ -94,6 +94,7 @@ public sealed partial class AaruFormat
|
||||
Status.TapePartitionNotFound => "Requested tape partition is not present in image.",
|
||||
Status.MetadataNotPresent => "Requested metadata is not present in image.",
|
||||
Status.InvalidSectorLength => "Requested sector length is too big.",
|
||||
Status.FluxDataNotFound => "Requested flux data is not present in image.",
|
||||
_ => "Unknown error occurred."
|
||||
};
|
||||
}
|
||||
|
||||
@@ -238,5 +238,20 @@ public sealed partial class AaruFormat
|
||||
public byte Flags;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Nested type: FluxCaptureEntry
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||
struct FluxCaptureEntry
|
||||
{
|
||||
public uint Head;
|
||||
public ushort Track;
|
||||
public byte SubTrack;
|
||||
public uint CaptureIndex;
|
||||
public ulong IndexResolution;
|
||||
public ulong DataResolution;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
@@ -33,9 +33,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Aaru.CommonTypes;
|
||||
using Aaru.CommonTypes.Enums;
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
using Aaru.CommonTypes.Structs;
|
||||
using Aaru.Helpers;
|
||||
using Aaru.Logging;
|
||||
|
||||
@@ -554,6 +556,39 @@ public sealed partial class SuperCardPro
|
||||
return indexCapture;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber GetAllFluxCaptures(out List<FluxCapture> captures)
|
||||
{
|
||||
captures = [];
|
||||
|
||||
if(ScpTracks is { Count: > 0 })
|
||||
{
|
||||
ulong resolution = (ulong)((Header.resolution + 1) * DEFAULT_RESOLUTION);
|
||||
|
||||
captures = [.. ScpTracks.Select(kvp =>
|
||||
{
|
||||
byte scpTrack = kvp.Key;
|
||||
|
||||
// Reverse HeadTrackSubToScpTrack: scpTrack = head + track * 2
|
||||
uint head = (uint)(scpTrack % 2);
|
||||
ushort track = (ushort)(scpTrack / 2);
|
||||
const byte subTrack = 0; // SuperCardPro always has subTrack = 0
|
||||
|
||||
return new FluxCapture
|
||||
{
|
||||
Head = head,
|
||||
Track = track,
|
||||
SubTrack = subTrack,
|
||||
CaptureIndex = 0, // SuperCardPro always has one capture per track
|
||||
IndexResolution = resolution,
|
||||
DataResolution = resolution
|
||||
};
|
||||
})];
|
||||
}
|
||||
|
||||
return ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public ErrorNumber ReadMediaTag(MediaTagType tag, out byte[] buffer)
|
||||
{
|
||||
|
||||
202
Aaru.Tests/Images/A2R.cs
Normal file
202
Aaru.Tests/Images/A2R.cs
Normal file
@@ -0,0 +1,202 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : A2R.cs
|
||||
// Author(s) : Rebecca Wallander <sakcheen+github@gmail.com>
|
||||
//
|
||||
// Component : Aaru unit testing.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2026 Rebecca Wallander
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.IO;
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Aaru.Tests.Images;
|
||||
|
||||
[TestFixture]
|
||||
public class A2R : FluxMediaImageTest
|
||||
{
|
||||
public override string DataFolder => Path.Combine(Consts.TestFilesRoot, "Media image formats", "A2R");
|
||||
public override IMediaImage Plugin => new Aaru.Images.A2R();
|
||||
|
||||
public override FluxImageTestExpected[] Tests =>
|
||||
[
|
||||
new()
|
||||
{
|
||||
TestFile = "The Quest.a2r",
|
||||
FluxCaptureCount = 162,
|
||||
FluxCaptures = [
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 0,
|
||||
Track = 0,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 0,
|
||||
IndexResolution = 62500,
|
||||
DataResolution = 62500
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 0,
|
||||
Track = 0,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 1,
|
||||
IndexResolution = 62500,
|
||||
DataResolution = 62500
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 0,
|
||||
Track = 1,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 0,
|
||||
IndexResolution = 62500,
|
||||
DataResolution = 62500
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 0,
|
||||
Track = 1,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 1,
|
||||
IndexResolution = 62500,
|
||||
DataResolution = 62500
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 0,
|
||||
Track = 1,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 2,
|
||||
IndexResolution = 62500,
|
||||
DataResolution = 62500
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 0,
|
||||
Track = 1,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 3,
|
||||
IndexResolution = 62500,
|
||||
DataResolution = 62500
|
||||
},
|
||||
]
|
||||
},
|
||||
new()
|
||||
{
|
||||
TestFile = "Lotus 1-2-3 v2 - Utility Disk.a2r",
|
||||
FluxCaptureCount = 320,
|
||||
FluxCaptures = [
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 0,
|
||||
Track = 0,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 0,
|
||||
IndexResolution = 62500,
|
||||
DataResolution = 62500
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 0,
|
||||
Track = 0,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 1,
|
||||
IndexResolution = 62500,
|
||||
DataResolution = 62500
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 0,
|
||||
Track = 0,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 2,
|
||||
IndexResolution = 62500,
|
||||
DataResolution = 62500
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 1,
|
||||
Track = 0,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 0,
|
||||
IndexResolution = 62500,
|
||||
DataResolution = 62500
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 1,
|
||||
Track = 0,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 1,
|
||||
IndexResolution = 62500,
|
||||
DataResolution = 62500
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 1,
|
||||
Track = 0,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 2,
|
||||
IndexResolution = 62500,
|
||||
DataResolution = 62500
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 1,
|
||||
Track = 1,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 0,
|
||||
IndexResolution = 62500,
|
||||
DataResolution = 62500
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 0,
|
||||
Track = 2,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 0,
|
||||
IndexResolution = 62500,
|
||||
DataResolution = 62500
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 0,
|
||||
Track = 2,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 1,
|
||||
IndexResolution = 62500,
|
||||
DataResolution = 62500
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 0,
|
||||
Track = 2,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 2,
|
||||
IndexResolution = 62500,
|
||||
DataResolution = 62500
|
||||
},
|
||||
]
|
||||
},
|
||||
];
|
||||
}
|
||||
105
Aaru.Tests/Images/AaruFormat/V2Flux.cs
Normal file
105
Aaru.Tests/Images/AaruFormat/V2Flux.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : V2Flux.cs
|
||||
// Author(s) : Rebecca Wallander <sakcheen+github@gmail.com>
|
||||
//
|
||||
// Component : Aaru unit testing.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2026 Rebecca Wallander
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.IO;
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Aaru.Tests.Images.AaruFormat;
|
||||
|
||||
[TestFixture]
|
||||
public class V2Flux : FluxMediaImageTest
|
||||
{
|
||||
public override string DataFolder => Path.Combine(Consts.TestFilesRoot, "Media image formats", "AaruFormat", "V2", "Flux");
|
||||
public override IMediaImage Plugin => new Aaru.Images.AaruFormat();
|
||||
|
||||
public override FluxImageTestExpected[] Tests =>
|
||||
[
|
||||
new()
|
||||
{
|
||||
TestFile = "dos_1.25_release_a - Disk 1.aif",
|
||||
FluxCaptureCount = 320,
|
||||
FluxCaptures = [
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 0,
|
||||
Track = 0,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 0,
|
||||
IndexResolution = 125000,
|
||||
DataResolution = 125000
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 0,
|
||||
Track = 0,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 1,
|
||||
IndexResolution = 125000,
|
||||
DataResolution = 125000
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 0,
|
||||
Track = 0,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 2,
|
||||
IndexResolution = 125000,
|
||||
DataResolution = 125000
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 1,
|
||||
Track = 0,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 0,
|
||||
IndexResolution = 125000,
|
||||
DataResolution = 125000
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 1,
|
||||
Track = 0,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 1,
|
||||
IndexResolution = 125000,
|
||||
DataResolution = 125000
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 1,
|
||||
Track = 0,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 2,
|
||||
IndexResolution = 125000,
|
||||
DataResolution = 125000
|
||||
},
|
||||
]
|
||||
}
|
||||
];
|
||||
}
|
||||
188
Aaru.Tests/Images/FluxMediaImageTest.cs
Normal file
188
Aaru.Tests/Images/FluxMediaImageTest.cs
Normal file
@@ -0,0 +1,188 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : FluxMediaImageTest.cs
|
||||
// Author(s) : Rebecca Wallander <sakcheen+github@gmail.com>
|
||||
//
|
||||
// Component : Aaru unit testing.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2026 Rebecca Wallander
|
||||
// ****************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Aaru.CommonTypes;
|
||||
using Aaru.CommonTypes.Enums;
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
using Aaru.CommonTypes.Structs;
|
||||
using Aaru.Core;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Aaru.Tests.Images;
|
||||
|
||||
public abstract class FluxMediaImageTest : BaseMediaImageTest
|
||||
{
|
||||
public abstract FluxImageTestExpected[] Tests { get; }
|
||||
|
||||
[OneTimeSetUp]
|
||||
public void InitTest() => PluginBase.Init();
|
||||
|
||||
[Test]
|
||||
public void Info()
|
||||
{
|
||||
Environment.CurrentDirectory = DataFolder;
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
foreach(FluxImageTestExpected test in Tests)
|
||||
{
|
||||
string testFile = test.TestFile;
|
||||
|
||||
bool exists = File.Exists(testFile);
|
||||
Assert.That(exists, string.Format(Localization._0_not_found, testFile));
|
||||
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
||||
// It arrives here...
|
||||
if(!exists) continue;
|
||||
|
||||
IFilter filter = PluginRegister.Singleton.GetFilter(testFile);
|
||||
filter.Open(testFile);
|
||||
|
||||
var image = Activator.CreateInstance(Plugin.GetType()) as IMediaImage;
|
||||
|
||||
Assert.That(image,
|
||||
Is.Not.Null,
|
||||
string.Format(Localization.Could_not_instantiate_filesystem_for_0, testFile));
|
||||
|
||||
ErrorNumber opened = image.Open(filter);
|
||||
Assert.That(opened, Is.EqualTo(ErrorNumber.NoError), string.Format(Localization.Open_0, testFile));
|
||||
|
||||
if(opened != ErrorNumber.NoError) continue;
|
||||
|
||||
if(image is not IFluxImage fluxImage)
|
||||
{
|
||||
Assert.Fail($"Image {testFile} does not implement IFluxImage");
|
||||
continue;
|
||||
}
|
||||
|
||||
ErrorNumber error = fluxImage.GetAllFluxCaptures(out List<FluxCapture> captures);
|
||||
|
||||
Assert.That(error, Is.EqualTo(ErrorNumber.NoError), $"GetAllFluxCaptures failed with {error}");
|
||||
Assert.That(captures, Is.Not.Null, "GetAllFluxCaptures returned null");
|
||||
Assert.That(captures, Is.Not.Empty, "GetAllFluxCaptures returned empty list");
|
||||
|
||||
Assert.That(captures.Count,
|
||||
Is.EqualTo(test.FluxCaptureCount),
|
||||
$"Expected {test.FluxCaptureCount} flux captures, got {captures.Count}");
|
||||
|
||||
captures.Should().NotBeEmpty("Flux captures list should not be empty");
|
||||
|
||||
foreach(FluxCapture capture in captures)
|
||||
{
|
||||
// Verify each capture has valid properties
|
||||
capture.IndexResolution.Should().BeGreaterThan(0, "IndexResolution should be greater than 0");
|
||||
capture.DataResolution.Should().BeGreaterThan(0, "DataResolution should be greater than 0");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Contents()
|
||||
{
|
||||
Environment.CurrentDirectory = DataFolder;
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
foreach(FluxImageTestExpected test in Tests)
|
||||
{
|
||||
string testFile = test.TestFile;
|
||||
|
||||
bool exists = File.Exists(testFile);
|
||||
Assert.That(exists, string.Format(Localization._0_not_found, testFile));
|
||||
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
|
||||
// It arrives here...
|
||||
if(!exists) continue;
|
||||
|
||||
IFilter filter = PluginRegister.Singleton.GetFilter(testFile);
|
||||
filter.Open(testFile);
|
||||
|
||||
var image = Activator.CreateInstance(Plugin.GetType()) as IMediaImage;
|
||||
|
||||
Assert.That(image,
|
||||
Is.Not.Null,
|
||||
string.Format(Localization.Could_not_instantiate_filesystem_for_0, testFile));
|
||||
|
||||
ErrorNumber opened = image.Open(filter);
|
||||
Assert.That(opened, Is.EqualTo(ErrorNumber.NoError), string.Format(Localization.Open_0, testFile));
|
||||
|
||||
if(opened != ErrorNumber.NoError) continue;
|
||||
|
||||
if(image is not IFluxImage fluxImage)
|
||||
{
|
||||
Assert.Fail($"Image {testFile} does not implement IFluxImage");
|
||||
continue;
|
||||
}
|
||||
|
||||
ErrorNumber error = fluxImage.GetAllFluxCaptures(out List<FluxCapture> captures);
|
||||
|
||||
Assert.That(error, Is.EqualTo(ErrorNumber.NoError), "GetAllFluxCaptures should succeed");
|
||||
Assert.That(captures, Is.Not.Null.And.Not.Empty, "Should have at least one flux capture");
|
||||
Assert.That(captures.Count,
|
||||
Is.EqualTo(test.FluxCaptureCount),
|
||||
$"Expected {test.FluxCaptureCount} flux captures, got {captures.Count}");
|
||||
|
||||
// If FluxCaptures array is provided, validate those captures
|
||||
if(test.FluxCaptures != null && test.FluxCaptures.Length > 0)
|
||||
{
|
||||
Assert.That(captures.Count,
|
||||
Is.GreaterThanOrEqualTo(test.FluxCaptures.Length),
|
||||
$"Image has {captures.Count} captures, but {test.FluxCaptures.Length} expected captures specified");
|
||||
|
||||
foreach(FluxCaptureTestExpected expectedCapture in test.FluxCaptures)
|
||||
{
|
||||
FluxCapture actualCapture = captures.Find(c => c.Head == expectedCapture.Head &&
|
||||
c.Track == expectedCapture.Track &&
|
||||
c.SubTrack == expectedCapture.SubTrack &&
|
||||
c.CaptureIndex == expectedCapture.CaptureIndex);
|
||||
|
||||
Assert.That(actualCapture,
|
||||
Is.Not.Null,
|
||||
$"Flux capture not found: head={expectedCapture.Head}, track={expectedCapture.Track}, subTrack={expectedCapture.SubTrack}, captureIndex={expectedCapture.CaptureIndex}");
|
||||
|
||||
if(actualCapture != null)
|
||||
{
|
||||
Assert.That(actualCapture.IndexResolution,
|
||||
Is.EqualTo(expectedCapture.IndexResolution),
|
||||
$"IndexResolution mismatch for head={expectedCapture.Head}, track={expectedCapture.Track}, subTrack={expectedCapture.SubTrack}, captureIndex={expectedCapture.CaptureIndex}");
|
||||
Assert.That(actualCapture.DataResolution,
|
||||
Is.EqualTo(expectedCapture.DataResolution),
|
||||
$"DataResolution mismatch for head={expectedCapture.Head}, track={expectedCapture.Track}, subTrack={expectedCapture.SubTrack}, captureIndex={expectedCapture.CaptureIndex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
105
Aaru.Tests/Images/SuperCardPro.cs
Normal file
105
Aaru.Tests/Images/SuperCardPro.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : SuperCardPro.cs
|
||||
// Author(s) : Rebecca Wallander <sakcheen+github@gmail.com>
|
||||
//
|
||||
// Component : Aaru unit testing.
|
||||
//
|
||||
// --[ License ] --------------------------------------------------------------
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
//
|
||||
// ----------------------------------------------------------------------------
|
||||
// Copyright © 2011-2026 Rebecca Wallander
|
||||
// ****************************************************************************/
|
||||
|
||||
using System.IO;
|
||||
using Aaru.CommonTypes.Interfaces;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Aaru.Tests.Images;
|
||||
|
||||
[TestFixture]
|
||||
public class SuperCardPro : FluxMediaImageTest
|
||||
{
|
||||
public override string DataFolder => Path.Combine(Consts.TestFilesRoot, "Media image formats", "SuperCardPro");
|
||||
public override IMediaImage Plugin => new Aaru.Images.SuperCardPro();
|
||||
|
||||
public override FluxImageTestExpected[] Tests =>
|
||||
[
|
||||
new()
|
||||
{
|
||||
TestFile = "Go Simulator (1992)(Infogrames).scp",
|
||||
FluxCaptureCount = 160,
|
||||
FluxCaptures = [
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 0,
|
||||
Track = 0,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 0,
|
||||
IndexResolution = 25000,
|
||||
DataResolution = 25000
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 1,
|
||||
Track = 0,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 0,
|
||||
IndexResolution = 25000,
|
||||
DataResolution = 25000
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 0,
|
||||
Track = 1,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 0,
|
||||
IndexResolution = 25000,
|
||||
DataResolution = 25000
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 1,
|
||||
Track = 1,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 0,
|
||||
IndexResolution = 25000,
|
||||
DataResolution = 25000
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 0,
|
||||
Track = 2,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 0,
|
||||
IndexResolution = 25000,
|
||||
DataResolution = 25000
|
||||
},
|
||||
new FluxCaptureTestExpected
|
||||
{
|
||||
Head = 1,
|
||||
Track = 2,
|
||||
SubTrack = 0,
|
||||
CaptureIndex = 0,
|
||||
IndexResolution = 25000,
|
||||
DataResolution = 25000
|
||||
},
|
||||
]
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -76,6 +76,30 @@ public class TapeImageTestExpected : BlockImageTestExpected
|
||||
public new TapePartition[] Partitions;
|
||||
}
|
||||
|
||||
public class FluxCaptureTestExpected
|
||||
{
|
||||
/// <summary>Physical head (0-based)</summary>
|
||||
public uint Head;
|
||||
/// <summary>Physical track (0-based)</summary>
|
||||
public ushort Track;
|
||||
/// <summary>Physical sub-track (0-based, e.g. half-track)</summary>
|
||||
public byte SubTrack;
|
||||
/// <summary>Capture index for this head/track/subTrack combination</summary>
|
||||
public uint CaptureIndex;
|
||||
/// <summary>Expected index resolution in picoseconds</summary>
|
||||
public ulong IndexResolution;
|
||||
/// <summary>Expected data resolution in picoseconds</summary>
|
||||
public ulong DataResolution;
|
||||
}
|
||||
|
||||
public class FluxImageTestExpected : BlockImageTestExpected
|
||||
{
|
||||
/// <summary>Expected number of flux captures in the image</summary>
|
||||
public uint FluxCaptureCount;
|
||||
/// <summary>Expected flux captures to validate</summary>
|
||||
public FluxCaptureTestExpected[] FluxCaptures;
|
||||
}
|
||||
|
||||
public class PartitionTest
|
||||
{
|
||||
public Partition[] Partitions;
|
||||
|
||||
Reference in New Issue
Block a user