Files
Aaru/Aaru.Decoders/CD/SectorBuilder.cs

236 lines
7.5 KiB
C#
Raw Normal View History

2020-07-19 22:01:25 +01:00
// /***************************************************************************
// Aaru Data Preservation Suite
// ----------------------------------------------------------------------------
//
// Filename : SectorBuilder.cs
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// Component : Device structures decoders.
//
// --[ 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/>.
//
// ----------------------------------------------------------------------------
2024-05-01 04:17:32 +01:00
// Copyright © 2011-2024 Natalia Portillo
2020-07-19 22:01:25 +01:00
// ****************************************************************************/
using System;
using Aaru.CommonTypes.Enums;
namespace Aaru.Decoders.CD;
2022-03-06 13:29:37 +00:00
public class SectorBuilder
{
2022-03-06 13:29:37 +00:00
readonly byte[] _eccBTable;
readonly byte[] _eccFTable;
readonly uint[] _edcTable;
public SectorBuilder()
{
2022-03-06 13:29:37 +00:00
_eccFTable = new byte[256];
_eccBTable = new byte[256];
_edcTable = new uint[256];
2022-03-06 13:29:37 +00:00
for(uint i = 0; i < 256; i++)
{
2022-03-06 13:29:37 +00:00
uint edc = i;
2023-10-03 23:09:28 +01:00
var j = (uint)(i << 1 ^ ((i & 0x80) == 0x80 ? 0x11D : 0));
2022-03-06 13:29:37 +00:00
_eccFTable[i] = (byte)j;
_eccBTable[i ^ j] = (byte)i;
2024-05-01 04:05:22 +01:00
for(j = 0; j < 8; j++) edc = edc >> 1 ^ ((edc & 1) > 0 ? 0xD8018001 : 0);
2022-03-06 13:29:37 +00:00
_edcTable[i] = edc;
}
2022-03-06 13:29:37 +00:00
}
2022-03-06 13:29:37 +00:00
static (byte minute, byte second, byte frame) LbaToMsf(long pos) =>
((byte)((pos + 150) / 75 / 60), (byte)((pos + 150) / 75 % 60), (byte)((pos + 150) % 75));
2022-03-06 13:29:37 +00:00
public void ReconstructPrefix(ref byte[] sector, // must point to a full 2352-byte sector
2023-10-03 23:09:28 +01:00
TrackType type, long lba)
2022-03-06 13:29:37 +00:00
{
//
// Sync
//
sector[0x000] = 0x00;
sector[0x001] = 0xFF;
sector[0x002] = 0xFF;
sector[0x003] = 0xFF;
sector[0x004] = 0xFF;
sector[0x005] = 0xFF;
sector[0x006] = 0xFF;
sector[0x007] = 0xFF;
sector[0x008] = 0xFF;
sector[0x009] = 0xFF;
sector[0x00A] = 0xFF;
sector[0x00B] = 0x00;
(byte minute, byte second, byte frame) msf = LbaToMsf(lba);
2023-10-03 23:09:28 +01:00
sector[0x00C] = (byte)((msf.minute / 10 << 4) + msf.minute % 10);
sector[0x00D] = (byte)((msf.second / 10 << 4) + msf.second % 10);
sector[0x00E] = (byte)((msf.frame / 10 << 4) + msf.frame % 10);
2022-03-06 13:29:37 +00:00
switch(type)
{
2022-03-06 13:29:37 +00:00
case TrackType.CdMode1:
//
// Mode
//
sector[0x00F] = 0x01;
2022-03-06 13:29:37 +00:00
break;
case TrackType.CdMode2Form1:
case TrackType.CdMode2Form2:
case TrackType.CdMode2Formless:
//
// Mode
//
sector[0x00F] = 0x02;
2022-03-06 13:29:37 +00:00
//
// Flags
//
sector[0x010] = sector[0x014];
sector[0x011] = sector[0x015];
sector[0x012] = sector[0x016];
sector[0x013] = sector[0x017];
2022-03-06 13:29:37 +00:00
break;
2023-10-03 23:09:28 +01:00
default:
return;
}
2022-03-06 13:29:37 +00:00
}
2022-03-06 13:29:37 +00:00
uint ComputeEdc(uint edc, byte[] src, int size, int srcOffset = 0)
{
int pos = srcOffset;
2024-05-01 04:05:22 +01:00
for(; size > 0; size--) edc = edc >> 8 ^ _edcTable[(edc ^ src[pos++]) & 0xFF];
2022-03-06 13:29:37 +00:00
return edc;
}
2022-03-06 13:29:37 +00:00
public void ReconstructEcc(ref byte[] sector, // must point to a full 2352-byte sector
2023-10-03 23:09:28 +01:00
TrackType type)
2022-03-06 13:29:37 +00:00
{
byte[] computedEdc;
2022-03-06 13:29:37 +00:00
switch(type)
{
//
2022-03-06 13:29:37 +00:00
// Compute EDC
//
2022-03-06 13:29:37 +00:00
case TrackType.CdMode1:
computedEdc = BitConverter.GetBytes(ComputeEdc(0, sector, 0x810));
sector[0x810] = computedEdc[0];
sector[0x811] = computedEdc[1];
sector[0x812] = computedEdc[2];
sector[0x813] = computedEdc[3];
break;
case TrackType.CdMode2Form1:
computedEdc = BitConverter.GetBytes(ComputeEdc(0, sector, 0x808, 0x10));
sector[0x818] = computedEdc[0];
sector[0x819] = computedEdc[1];
sector[0x81A] = computedEdc[2];
sector[0x81B] = computedEdc[3];
break;
case TrackType.CdMode2Form2:
computedEdc = BitConverter.GetBytes(ComputeEdc(0, sector, 0x91C, 0x10));
sector[0x92C] = computedEdc[0];
sector[0x92D] = computedEdc[1];
sector[0x92E] = computedEdc[2];
sector[0x92F] = computedEdc[3];
break;
2023-10-03 23:09:28 +01:00
default:
return;
}
2023-10-03 23:09:28 +01:00
var zeroaddress = new byte[4];
2022-03-06 13:29:37 +00:00
switch(type)
{
2022-03-06 13:29:37 +00:00
//
// Compute ECC
//
case TrackType.CdMode1:
//
// Reserved
//
sector[0x814] = 0x00;
sector[0x815] = 0x00;
sector[0x816] = 0x00;
sector[0x817] = 0x00;
sector[0x818] = 0x00;
sector[0x819] = 0x00;
sector[0x81A] = 0x00;
sector[0x81B] = 0x00;
EccWriteSector(sector, sector, ref sector, 0xC, 0x10, 0x81C);
break;
case TrackType.CdMode2Form1:
EccWriteSector(zeroaddress, sector, ref sector, 0, 0x10, 0x81C);
break;
2023-10-03 23:09:28 +01:00
default:
return;
}
2022-03-06 13:29:37 +00:00
//
// Done
//
}
2022-03-07 07:36:42 +00:00
void EccWriteSector(byte[] address, byte[] data, ref byte[] ecc, int addressOffset, int dataOffset, int eccOffset)
2022-03-06 13:29:37 +00:00
{
2023-10-03 23:09:28 +01:00
WriteEcc(address, data, 86, 24, 2, 86, ref ecc, addressOffset, dataOffset, eccOffset); // P
2022-03-06 13:29:37 +00:00
WriteEcc(address, data, 52, 43, 86, 88, ref ecc, addressOffset, dataOffset, eccOffset + 0xAC); // Q
}
2023-10-03 23:09:28 +01:00
void WriteEcc(byte[] address, byte[] data, uint majorCount, uint minorCount, uint majorMult, uint minorInc,
ref byte[] ecc, int addressOffset, int dataOffset, int eccOffset)
2022-03-06 13:29:37 +00:00
{
uint size = majorCount * minorCount;
uint major;
for(major = 0; major < majorCount; major++)
{
2023-10-03 23:09:28 +01:00
uint idx = (major >> 1) * majorMult + (major & 1);
2022-03-06 13:29:37 +00:00
byte eccA = 0;
byte eccB = 0;
uint minor;
2022-03-06 13:29:37 +00:00
for(minor = 0; minor < minorCount; minor++)
{
2022-03-06 13:29:37 +00:00
byte temp = idx < 4 ? address[idx + addressOffset] : data[idx + dataOffset - 4];
idx += minorInc;
2024-05-01 04:05:22 +01:00
if(idx >= size) idx -= size;
2022-03-06 13:29:37 +00:00
eccA ^= temp;
eccB ^= temp;
eccA = _eccFTable[eccA];
}
2022-03-06 13:29:37 +00:00
eccA = _eccBTable[_eccFTable[eccA] ^ eccB];
ecc[major + eccOffset] = eccA;
ecc[major + majorCount + eccOffset] = (byte)(eccA ^ eccB);
}
}
}