2018-07-23 23:25:43 +01:00
|
|
|
|
// /***************************************************************************
|
2020-02-27 12:31:25 +00:00
|
|
|
|
// Aaru Data Preservation Suite
|
2018-07-23 23:25:43 +01:00
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
|
//
|
|
|
|
|
|
// Filename : Helpers.cs
|
|
|
|
|
|
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
|
|
|
|
//
|
|
|
|
|
|
// Component : Disk image plugins.
|
|
|
|
|
|
//
|
|
|
|
|
|
// --[ Description ] ----------------------------------------------------------
|
|
|
|
|
|
//
|
|
|
|
|
|
// Contains helpers for MAME Compressed Hunks of Data disk images.
|
|
|
|
|
|
//
|
|
|
|
|
|
// --[ License ] --------------------------------------------------------------
|
|
|
|
|
|
//
|
|
|
|
|
|
// This library is free software; you can redistribute it and/or modify
|
|
|
|
|
|
// it under the terms of the GNU Lesser General Public License as
|
|
|
|
|
|
// published by the Free Software Foundation; either version 2.1 of the
|
|
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
|
|
//
|
|
|
|
|
|
// This library 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
|
|
|
|
|
|
// Lesser General Public License for more details.
|
|
|
|
|
|
//
|
|
|
|
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
|
|
|
|
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
//
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
2022-02-18 10:02:53 +00:00
|
|
|
|
// Copyright © 2011-2022 Natalia Portillo
|
2018-07-23 23:25:43 +01:00
|
|
|
|
// ****************************************************************************/
|
|
|
|
|
|
|
2022-03-07 07:36:44 +00:00
|
|
|
|
namespace Aaru.DiscImages;
|
|
|
|
|
|
|
2018-07-23 23:25:43 +01:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Linq;
|
2021-09-21 04:55:28 +01:00
|
|
|
|
using Aaru.CommonTypes.Enums;
|
2020-02-27 00:33:26 +00:00
|
|
|
|
using Aaru.CommonTypes.Structs;
|
2021-09-21 04:55:28 +01:00
|
|
|
|
using Aaru.Console;
|
2020-02-27 00:33:26 +00:00
|
|
|
|
using Aaru.Helpers;
|
2018-07-23 23:25:43 +01:00
|
|
|
|
using SharpCompress.Compressors;
|
|
|
|
|
|
using SharpCompress.Compressors.Deflate;
|
|
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
public sealed partial class Chd
|
2018-07-23 23:25:43 +01:00
|
|
|
|
{
|
2022-03-06 13:29:38 +00:00
|
|
|
|
Track GetTrack(ulong sector)
|
2018-07-23 23:25:43 +01:00
|
|
|
|
{
|
2022-03-06 13:29:38 +00:00
|
|
|
|
var track = new Track();
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
foreach(KeyValuePair<ulong, uint> kvp in _offsetmap.Where(kvp => sector >= kvp.Key))
|
|
|
|
|
|
_tracks.TryGetValue(kvp.Value, out track);
|
2018-07-23 23:25:43 +01:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
return track;
|
|
|
|
|
|
}
|
2018-07-23 23:25:43 +01:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
ulong GetAbsoluteSector(ulong relativeSector, uint track)
|
|
|
|
|
|
{
|
|
|
|
|
|
_tracks.TryGetValue(track, out Track aaruTrack);
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
return (aaruTrack?.StartSector ?? 0) + relativeSector;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ErrorNumber GetHunk(ulong hunkNo, out byte[] buffer)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(_hunkCache.TryGetValue(hunkNo, out buffer))
|
|
|
|
|
|
return ErrorNumber.NoError;
|
2018-07-23 23:25:43 +01:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
switch(_mapVersion)
|
2018-07-23 23:25:43 +01:00
|
|
|
|
{
|
2022-03-06 13:29:38 +00:00
|
|
|
|
case 1:
|
|
|
|
|
|
ulong offset = _hunkTable[hunkNo] & 0x00000FFFFFFFFFFF;
|
|
|
|
|
|
ulong length = _hunkTable[hunkNo] >> 44;
|
|
|
|
|
|
|
2022-03-07 07:36:44 +00:00
|
|
|
|
var compHunk = new byte[length];
|
2022-03-06 13:29:38 +00:00
|
|
|
|
_imageStream.Seek((long)offset, SeekOrigin.Begin);
|
2022-11-14 09:43:16 +00:00
|
|
|
|
_imageStream.EnsureRead(compHunk, 0, compHunk.Length);
|
2022-03-06 13:29:38 +00:00
|
|
|
|
|
|
|
|
|
|
if(length == _sectorsPerHunk * _imageInfo.SectorSize)
|
|
|
|
|
|
buffer = compHunk;
|
|
|
|
|
|
else if((Compression)_hdrCompression > Compression.Zlib)
|
|
|
|
|
|
{
|
|
|
|
|
|
AaruConsole.ErrorWriteLine($"Unsupported compression {(Compression)_hdrCompression}");
|
|
|
|
|
|
|
|
|
|
|
|
return ErrorNumber.InvalidArgument;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var zStream = new DeflateStream(new MemoryStream(compHunk), CompressionMode.Decompress);
|
|
|
|
|
|
buffer = new byte[_sectorsPerHunk * _imageInfo.SectorSize];
|
2022-11-14 09:43:16 +00:00
|
|
|
|
int read = zStream.EnsureRead(buffer, 0, (int)(_sectorsPerHunk * _imageInfo.SectorSize));
|
2022-03-06 13:29:38 +00:00
|
|
|
|
|
|
|
|
|
|
if(read != _sectorsPerHunk * _imageInfo.SectorSize)
|
2021-09-21 04:55:28 +01:00
|
|
|
|
{
|
2022-03-06 13:29:38 +00:00
|
|
|
|
AaruConsole.
|
|
|
|
|
|
ErrorWriteLine($"Unable to decompress hunk correctly, got {read} bytes, expected {_sectorsPerHunk * _imageInfo.SectorSize}");
|
2021-09-21 04:55:28 +01:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
return ErrorNumber.InOutError;
|
2021-09-21 04:55:28 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
zStream.Close();
|
|
|
|
|
|
}
|
2018-07-23 23:25:43 +01:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
break;
|
|
|
|
|
|
case 3:
|
2022-03-07 07:36:44 +00:00
|
|
|
|
var entryBytes = new byte[16];
|
2022-03-06 13:29:38 +00:00
|
|
|
|
Array.Copy(_hunkMap, (int)(hunkNo * 16), entryBytes, 0, 16);
|
|
|
|
|
|
MapEntryV3 entry = Marshal.ByteArrayToStructureBigEndian<MapEntryV3>(entryBytes);
|
2018-07-23 23:25:43 +01:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
switch((EntryFlagsV3)(entry.flags & 0x0F))
|
|
|
|
|
|
{
|
|
|
|
|
|
case EntryFlagsV3.Invalid:
|
|
|
|
|
|
AaruConsole.ErrorWriteLine("Invalid hunk found.");
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
return ErrorNumber.InvalidArgument;
|
|
|
|
|
|
case EntryFlagsV3.Compressed:
|
|
|
|
|
|
switch((Compression)_hdrCompression)
|
|
|
|
|
|
{
|
|
|
|
|
|
case Compression.None: goto uncompressedV3;
|
|
|
|
|
|
case Compression.Zlib:
|
|
|
|
|
|
case Compression.ZlibPlus:
|
|
|
|
|
|
if(_isHdd)
|
|
|
|
|
|
{
|
2022-03-07 07:36:44 +00:00
|
|
|
|
var zHunk = new byte[(entry.lengthLsb << 16) + entry.lengthLsb];
|
2022-03-06 13:29:38 +00:00
|
|
|
|
_imageStream.Seek((long)entry.offset, SeekOrigin.Begin);
|
2022-11-14 09:43:16 +00:00
|
|
|
|
_imageStream.EnsureRead(zHunk, 0, zHunk.Length);
|
2022-03-06 13:29:38 +00:00
|
|
|
|
|
|
|
|
|
|
var zStream =
|
|
|
|
|
|
new DeflateStream(new MemoryStream(zHunk), CompressionMode.Decompress);
|
|
|
|
|
|
|
|
|
|
|
|
buffer = new byte[_bytesPerHunk];
|
2022-11-14 09:43:16 +00:00
|
|
|
|
int read = zStream.EnsureRead(buffer, 0, (int)_bytesPerHunk);
|
2022-03-06 13:29:38 +00:00
|
|
|
|
|
|
|
|
|
|
if(read != _bytesPerHunk)
|
2018-07-23 23:25:43 +01:00
|
|
|
|
{
|
2022-03-06 13:29:38 +00:00
|
|
|
|
AaruConsole.
|
|
|
|
|
|
ErrorWriteLine($"Unable to decompress hunk correctly, got {read} bytes, expected {_bytesPerHunk}");
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
return ErrorNumber.InOutError;
|
|
|
|
|
|
}
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
zStream.Close();
|
|
|
|
|
|
}
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
// TODO: Guess wth is MAME doing with these hunks
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
AaruConsole.ErrorWriteLine("Compressed CD/GD-ROM hunks are not yet supported");
|
2021-09-21 04:55:28 +01:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
return ErrorNumber.NotImplemented;
|
|
|
|
|
|
}
|
2018-07-23 23:25:43 +01:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
break;
|
|
|
|
|
|
case Compression.Av:
|
2022-03-07 07:36:44 +00:00
|
|
|
|
AaruConsole.ErrorWriteLine($"Unsupported compression {(Compression)_hdrCompression}");
|
2020-02-29 18:03:35 +00:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
return ErrorNumber.NotImplemented;
|
|
|
|
|
|
}
|
2021-09-21 04:55:28 +01:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
break;
|
|
|
|
|
|
case EntryFlagsV3.Uncompressed:
|
2022-03-07 07:36:44 +00:00
|
|
|
|
uncompressedV3:
|
2022-03-06 13:29:38 +00:00
|
|
|
|
buffer = new byte[_bytesPerHunk];
|
|
|
|
|
|
_imageStream.Seek((long)entry.offset, SeekOrigin.Begin);
|
2022-11-14 09:43:16 +00:00
|
|
|
|
_imageStream.EnsureRead(buffer, 0, buffer.Length);
|
2018-07-23 23:25:43 +01:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
break;
|
|
|
|
|
|
case EntryFlagsV3.Mini:
|
|
|
|
|
|
buffer = new byte[_bytesPerHunk];
|
2022-11-13 20:27:32 +00:00
|
|
|
|
byte[] mini = BigEndianBitConverter.GetBytes(entry.offset);
|
2021-09-21 04:55:28 +01:00
|
|
|
|
|
2022-03-07 07:36:44 +00:00
|
|
|
|
for(var i = 0; i < _bytesPerHunk; i++)
|
2022-03-06 13:29:38 +00:00
|
|
|
|
buffer[i] = mini[i % 8];
|
2018-07-23 23:25:43 +01:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
break;
|
|
|
|
|
|
case EntryFlagsV3.SelfHunk: return GetHunk(entry.offset, out buffer);
|
|
|
|
|
|
case EntryFlagsV3.ParentHunk:
|
|
|
|
|
|
AaruConsole.ErrorWriteLine("Parent images are not supported");
|
2021-09-21 04:55:28 +01:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
return ErrorNumber.NotImplemented;
|
|
|
|
|
|
case EntryFlagsV3.SecondCompressed:
|
|
|
|
|
|
AaruConsole.ErrorWriteLine("FLAC is not supported");
|
2018-07-23 23:25:43 +01:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
return ErrorNumber.NotImplemented;
|
|
|
|
|
|
default:
|
|
|
|
|
|
AaruConsole.ErrorWriteLine($"Hunk type {entry.flags & 0xF} is not supported");
|
2021-09-21 04:55:28 +01:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
return ErrorNumber.NotSupported;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 5:
|
|
|
|
|
|
if(_hdrCompression == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
buffer = new byte[_bytesPerHunk];
|
|
|
|
|
|
_imageStream.Seek(_hunkTableSmall[hunkNo] * _bytesPerHunk, SeekOrigin.Begin);
|
2022-11-14 09:43:16 +00:00
|
|
|
|
_imageStream.EnsureRead(buffer, 0, buffer.Length);
|
2022-03-06 13:29:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
AaruConsole.ErrorWriteLine("Compressed v5 hunks not yet supported");
|
2018-07-23 23:25:43 +01:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
return ErrorNumber.NotSupported;
|
|
|
|
|
|
}
|
2018-07-23 23:25:43 +01:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
AaruConsole.ErrorWriteLine($"Unsupported hunk map version {_mapVersion}");
|
2018-07-23 23:25:43 +01:00
|
|
|
|
|
2022-03-06 13:29:38 +00:00
|
|
|
|
return ErrorNumber.NotSupported;
|
2018-07-23 23:25:43 +01:00
|
|
|
|
}
|
2022-03-06 13:29:38 +00:00
|
|
|
|
|
|
|
|
|
|
if(_hunkCache.Count >= _maxBlockCache)
|
|
|
|
|
|
_hunkCache.Clear();
|
|
|
|
|
|
|
|
|
|
|
|
_hunkCache.Add(hunkNo, buffer);
|
|
|
|
|
|
|
|
|
|
|
|
return ErrorNumber.NoError;
|
2018-07-23 23:25:43 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|