mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Add option to fix subchannels.
This commit is contained in:
@@ -96,6 +96,7 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
// Check subchannel
|
// Check subchannel
|
||||||
for(int subPos = 0; subPos < deSub.Length; subPos += 96)
|
for(int subPos = 0; subPos < deSub.Length; subPos += 96)
|
||||||
{
|
{
|
||||||
|
bool @fixed = false;
|
||||||
byte[] q = new byte[12];
|
byte[] q = new byte[12];
|
||||||
Array.Copy(deSub, subPos + 12, q, 0, 12);
|
Array.Copy(deSub, subPos + 12, q, 0, 12);
|
||||||
|
|
||||||
@@ -124,12 +125,15 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
if(deSub[rw] != 0)
|
if(deSub[rw] != 0)
|
||||||
rwOk = false;
|
rwOk = false;
|
||||||
|
|
||||||
|
bool rwPacket = false;
|
||||||
|
bool cdtextPacket = false;
|
||||||
|
|
||||||
if(!rwOk)
|
if(!rwOk)
|
||||||
{
|
{
|
||||||
byte[] sectorSub = new byte[96];
|
byte[] sectorSub = new byte[96];
|
||||||
Array.Copy(sub, subPos, sectorSub, 0, 96);
|
Array.Copy(sub, subPos, sectorSub, 0, 96);
|
||||||
|
|
||||||
DetectRwPackets(sectorSub, out _, out bool rwPacket, out bool cdtextPacket);
|
DetectRwPackets(sectorSub, out _, out rwPacket, out cdtextPacket);
|
||||||
|
|
||||||
// TODO: CD+G reed solomon
|
// TODO: CD+G reed solomon
|
||||||
if(rwPacket && !cdtextPacket)
|
if(rwPacket && !cdtextPacket)
|
||||||
@@ -139,30 +143,103 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
rwOk = CheckCdTextPackets(sectorSub);
|
rwOk = CheckCdTextPackets(sectorSub);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Fix
|
if(!pOk && _fixSubchannel)
|
||||||
|
{
|
||||||
|
if(pWeight >= 48)
|
||||||
|
for(int p = subPos; p < subPos + 12; p++)
|
||||||
|
deSub[p] = 255;
|
||||||
|
else
|
||||||
|
for(int p = subPos; p < subPos + 12; p++)
|
||||||
|
deSub[p] = 0;
|
||||||
|
|
||||||
|
pOk = true;
|
||||||
|
@fixed = true;
|
||||||
|
|
||||||
|
subLog.WritePFix();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!rwOk &&
|
||||||
|
!rwPacket &&
|
||||||
|
!cdtextPacket &&
|
||||||
|
_fixSubchannel)
|
||||||
|
{
|
||||||
|
for(int rw = subPos + 24; rw < subPos + 96; rw++)
|
||||||
|
deSub[rw] = 0;
|
||||||
|
|
||||||
|
rwOk = true;
|
||||||
|
@fixed = true;
|
||||||
|
|
||||||
|
subLog.WriteRwFix();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte smin, ssec, sframe, amin, asec, aframe, pmin, psec, pframe;
|
||||||
|
byte rmin, rsec, rframe;
|
||||||
|
int aPos;
|
||||||
|
|
||||||
|
if(!crcOk &&
|
||||||
|
_fixSubchannel &&
|
||||||
|
subPos > 0 &&
|
||||||
|
subPos < deSub.Length - 96)
|
||||||
|
{
|
||||||
|
crcOk = FixQSubchannel(deSub, q, subPos, sectorAddress, _fixSubchannelCrc, out bool fixedAdr,
|
||||||
|
out bool controlFix, out bool fixedZero, out bool fixedTno,
|
||||||
|
out bool fixedIndex, out bool fixedRelPos, out bool fixedAbsPos,
|
||||||
|
out bool fixedCrc);
|
||||||
|
|
||||||
|
if(crcOk)
|
||||||
|
{
|
||||||
|
Array.Copy(q, 0, deSub, subPos + 12, 12);
|
||||||
|
@fixed = true;
|
||||||
|
|
||||||
|
if(fixedAdr)
|
||||||
|
subLog.WriteQAdrFix();
|
||||||
|
|
||||||
|
if(controlFix)
|
||||||
|
subLog.WriteQCtrlFix();
|
||||||
|
|
||||||
|
if(fixedZero)
|
||||||
|
subLog.WriteQZeroFix();
|
||||||
|
|
||||||
|
if(fixedTno)
|
||||||
|
subLog.WriteQTnoFix();
|
||||||
|
|
||||||
|
if(fixedIndex)
|
||||||
|
subLog.WriteQIndexFix();
|
||||||
|
|
||||||
|
if(fixedRelPos)
|
||||||
|
subLog.WriteQRelPosFix();
|
||||||
|
|
||||||
|
if(fixedAbsPos)
|
||||||
|
subLog.WriteQAbsPosFix();
|
||||||
|
|
||||||
|
if(fixedCrc)
|
||||||
|
subLog.WriteQCrcFix();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(!pOk ||
|
if(!pOk ||
|
||||||
!crcOk ||
|
!crcOk ||
|
||||||
!rwOk)
|
!rwOk)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int aPos = int.MinValue;
|
aPos = int.MinValue;
|
||||||
|
|
||||||
byte aframe = (byte)(((q[9] / 16) * 10) + (q[9] & 0x0F));
|
aframe = (byte)(((q[9] / 16) * 10) + (q[9] & 0x0F));
|
||||||
|
|
||||||
if((q[0] & 0x3) == 1)
|
if((q[0] & 0x3) == 1)
|
||||||
{
|
{
|
||||||
byte amin = (byte)(((q[7] / 16) * 10) + (q[7] & 0x0F));
|
amin = (byte)(((q[7] / 16) * 10) + (q[7] & 0x0F));
|
||||||
byte asec = (byte)(((q[8] / 16) * 10) + (q[8] & 0x0F));
|
asec = (byte)(((q[8] / 16) * 10) + (q[8] & 0x0F));
|
||||||
aPos = ((amin * 60 * 75) + (asec * 75) + aframe) - 150;
|
aPos = ((amin * 60 * 75) + (asec * 75) + aframe) - 150;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ulong expectedSectorAddress = sectorAddress + (ulong)(subPos / 96) + 150;
|
ulong expectedSectorAddress = sectorAddress + (ulong)(subPos / 96) + 150;
|
||||||
byte smin = (byte)(expectedSectorAddress / 60 / 75);
|
smin = (byte)(expectedSectorAddress / 60 / 75);
|
||||||
expectedSectorAddress -= (ulong)(smin * 60 * 75);
|
expectedSectorAddress -= (ulong)(smin * 60 * 75);
|
||||||
byte ssec = (byte)(expectedSectorAddress / 75);
|
ssec = (byte)(expectedSectorAddress / 75);
|
||||||
expectedSectorAddress -= (ulong)(smin * 75);
|
expectedSectorAddress -= (ulong)(smin * 75);
|
||||||
byte sframe = (byte)(expectedSectorAddress - ((ulong)ssec * 75));
|
sframe = (byte)(expectedSectorAddress - ((ulong)ssec * 75));
|
||||||
|
|
||||||
aPos = ((smin * 60 * 75) + (ssec * 75) + aframe) - 150;
|
aPos = ((smin * 60 * 75) + (ssec * 75) + aframe) - 150;
|
||||||
|
|
||||||
@@ -183,6 +260,10 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
_outputPlugin.WriteSectorTag(posSub, (ulong)aPos, SectorTagType.CdSectorSubchannel);
|
_outputPlugin.WriteSectorTag(posSub, (ulong)aPos, SectorTagType.CdSectorSubchannel);
|
||||||
|
|
||||||
subchannelExtents.Remove(aPos);
|
subchannelExtents.Remove(aPos);
|
||||||
|
|
||||||
|
if(@fixed)
|
||||||
|
subLog?.WriteEntry(posSub, supportedSubchannel == MmcSubchannel.Raw,
|
||||||
|
(long)sectorAddress + (subPos / 96), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return indexesChanged;
|
return indexesChanged;
|
||||||
@@ -635,5 +716,529 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FixQSubchannel(byte[] deSub, byte[] q, int subPos, ulong sectorAddress, bool fixCrc, out bool fixedAdr,
|
||||||
|
out bool controlFix, out bool fixedZero, out bool fixedTno, out bool fixedIndex,
|
||||||
|
out bool fixedRelPos, out bool fixedAbsPos, out bool fixedCrc)
|
||||||
|
{
|
||||||
|
byte smin, ssec, sframe, amin, asec, aframe, pmin, psec, pframe;
|
||||||
|
byte rmin, rsec, rframe;
|
||||||
|
int aPos, rPos, pPos, dPos;
|
||||||
|
controlFix = false;
|
||||||
|
fixedZero = false;
|
||||||
|
fixedTno = false;
|
||||||
|
fixedIndex = false;
|
||||||
|
fixedRelPos = false;
|
||||||
|
fixedAbsPos = false;
|
||||||
|
fixedCrc = false;
|
||||||
|
|
||||||
|
ulong expectedSectorAddress = sectorAddress + (ulong)(subPos / 96) + 150;
|
||||||
|
smin = (byte)(expectedSectorAddress / 60 / 75);
|
||||||
|
expectedSectorAddress -= (ulong)(smin * 60 * 75);
|
||||||
|
ssec = (byte)(expectedSectorAddress / 75);
|
||||||
|
expectedSectorAddress -= (ulong)(smin * 75);
|
||||||
|
sframe = (byte)(expectedSectorAddress - ((ulong)ssec * 75));
|
||||||
|
|
||||||
|
byte[] preQ = new byte[12];
|
||||||
|
byte[] nextQ = new byte[12];
|
||||||
|
Array.Copy(deSub, (subPos + 12) - 96, preQ, 0, 12);
|
||||||
|
Array.Copy(deSub, subPos + 12 + 96, nextQ, 0, 12);
|
||||||
|
bool status;
|
||||||
|
|
||||||
|
CRC16CCITTContext.Data(preQ, 10, out byte[] preCrc);
|
||||||
|
bool preCrcOk = preCrc[0] == preQ[10] && preCrc[1] == preQ[11];
|
||||||
|
|
||||||
|
CRC16CCITTContext.Data(nextQ, 10, out byte[] nextCrc);
|
||||||
|
bool nextCrcOk = nextCrc[0] == nextQ[10] && nextCrc[1] == nextQ[11];
|
||||||
|
|
||||||
|
fixedAdr = false;
|
||||||
|
|
||||||
|
// Extraneous bits in ADR
|
||||||
|
if((q[0] & 0xC) != 0)
|
||||||
|
{
|
||||||
|
q[0] &= 0xF3;
|
||||||
|
fixedAdr = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CRC16CCITTContext.Data(q, 10, out byte[] qCrc);
|
||||||
|
status = qCrc[0] == q[10] && qCrc[1] == q[11];
|
||||||
|
|
||||||
|
if(fixedAdr && status)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
int oldAdr = q[0] & 0x3;
|
||||||
|
|
||||||
|
// Try Q-Mode 1
|
||||||
|
q[0] = (byte)((q[0] & 0xF0) + 1);
|
||||||
|
CRC16CCITTContext.Data(q, 10, out qCrc);
|
||||||
|
status = qCrc[0] == q[10] && qCrc[1] == q[11];
|
||||||
|
|
||||||
|
if(status)
|
||||||
|
{
|
||||||
|
fixedAdr = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try Q-Mode 2
|
||||||
|
q[0] = (byte)((q[0] & 0xF0) + 2);
|
||||||
|
CRC16CCITTContext.Data(q, 10, out qCrc);
|
||||||
|
status = qCrc[0] == q[10] && qCrc[1] == q[11];
|
||||||
|
|
||||||
|
if(status)
|
||||||
|
{
|
||||||
|
fixedAdr = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try Q-Mode 3
|
||||||
|
q[0] = (byte)((q[0] & 0xF0) + 3);
|
||||||
|
CRC16CCITTContext.Data(q, 10, out qCrc);
|
||||||
|
status = qCrc[0] == q[10] && qCrc[1] == q[11];
|
||||||
|
|
||||||
|
if(status)
|
||||||
|
{
|
||||||
|
fixedAdr = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
q[0] = (byte)((q[0] & 0xF0) + oldAdr);
|
||||||
|
|
||||||
|
oldAdr = q[0];
|
||||||
|
|
||||||
|
// Try using previous control
|
||||||
|
if(preCrcOk && (q[0] & 0xF0) != (preQ[0] & 0xF0))
|
||||||
|
{
|
||||||
|
q[0] = (byte)((q[0] & 0x03) + (preQ[0] & 0xF0));
|
||||||
|
|
||||||
|
CRC16CCITTContext.Data(q, 10, out qCrc);
|
||||||
|
status = qCrc[0] == q[10] && qCrc[1] == q[11];
|
||||||
|
|
||||||
|
if(status)
|
||||||
|
{
|
||||||
|
controlFix = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
q[0] = (byte)oldAdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try using next control
|
||||||
|
if(nextCrcOk && (q[0] & 0xF0) != (nextQ[0] & 0xF0))
|
||||||
|
{
|
||||||
|
q[0] = (byte)((q[0] & 0x03) + (nextQ[0] & 0xF0));
|
||||||
|
|
||||||
|
CRC16CCITTContext.Data(q, 10, out qCrc);
|
||||||
|
status = qCrc[0] == q[10] && qCrc[1] == q[11];
|
||||||
|
|
||||||
|
if(status)
|
||||||
|
{
|
||||||
|
controlFix = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
q[0] = (byte)oldAdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(preCrcOk &&
|
||||||
|
nextCrcOk &&
|
||||||
|
(nextQ[0] & 0xF0) == (preQ[0] & 0xF0) &&
|
||||||
|
(q[0] & 0xF0) != (nextQ[0] & 0xF0))
|
||||||
|
{
|
||||||
|
q[0] = (byte)((q[0] & 0x03) + (nextQ[0] & 0xF0));
|
||||||
|
|
||||||
|
controlFix = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((q[0] & 0x3) == 1)
|
||||||
|
{
|
||||||
|
// ZERO not zero
|
||||||
|
if(q[6] != 0)
|
||||||
|
{
|
||||||
|
q[6] = 0;
|
||||||
|
fixedZero = true;
|
||||||
|
|
||||||
|
CRC16CCITTContext.Data(q, 10, out qCrc);
|
||||||
|
status = qCrc[0] == q[10] && qCrc[1] == q[11];
|
||||||
|
|
||||||
|
if(status)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(preCrcOk && nextCrcOk)
|
||||||
|
{
|
||||||
|
if(preQ[1] == nextQ[1] &&
|
||||||
|
preQ[1] != q[1])
|
||||||
|
{
|
||||||
|
q[1] = preQ[1];
|
||||||
|
fixedTno = true;
|
||||||
|
|
||||||
|
CRC16CCITTContext.Data(q, 10, out qCrc);
|
||||||
|
status = qCrc[0] == q[10] && qCrc[1] == q[11];
|
||||||
|
|
||||||
|
if(status)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(preCrcOk && nextCrcOk)
|
||||||
|
{
|
||||||
|
if(preQ[2] == nextQ[2] &&
|
||||||
|
preQ[2] != q[2])
|
||||||
|
{
|
||||||
|
q[2] = preQ[2];
|
||||||
|
fixedIndex = true;
|
||||||
|
|
||||||
|
CRC16CCITTContext.Data(q, 10, out qCrc);
|
||||||
|
status = qCrc[0] == q[10] && qCrc[1] == q[11];
|
||||||
|
|
||||||
|
if(status)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
amin = (byte)(((q[7] / 16) * 10) + (q[7] & 0x0F));
|
||||||
|
asec = (byte)(((q[8] / 16) * 10) + (q[8] & 0x0F));
|
||||||
|
aframe = (byte)(((q[9] / 16) * 10) + (q[9] & 0x0F));
|
||||||
|
aPos = ((amin * 60 * 75) + (asec * 75) + aframe) - 150;
|
||||||
|
|
||||||
|
pmin = (byte)(((q[3] / 16) * 10) + (q[3] & 0x0F));
|
||||||
|
psec = (byte)(((q[4] / 16) * 10) + (q[4] & 0x0F));
|
||||||
|
pframe = (byte)(((q[5] / 16) * 10) + (q[5] & 0x0F));
|
||||||
|
pPos = (pmin * 60 * 75) + (psec * 75) + pframe;
|
||||||
|
|
||||||
|
// TODO: pregap
|
||||||
|
// Not pregap
|
||||||
|
if(q[2] > 0)
|
||||||
|
{
|
||||||
|
// Previous was not pregap either
|
||||||
|
if(preQ[2] > 0 && preCrcOk)
|
||||||
|
{
|
||||||
|
rmin = (byte)(((preQ[3] / 16) * 10) + (preQ[3] & 0x0F));
|
||||||
|
rsec = (byte)(((preQ[4] / 16) * 10) + (preQ[4] & 0x0F));
|
||||||
|
rframe = (byte)(((preQ[5] / 16) * 10) + (preQ[5] & 0x0F));
|
||||||
|
rPos = (rmin * 60 * 75) + (rsec * 75) + rframe;
|
||||||
|
|
||||||
|
dPos = pPos - rPos;
|
||||||
|
|
||||||
|
if(dPos != 1)
|
||||||
|
{
|
||||||
|
q[3] = preQ[3];
|
||||||
|
q[4] = preQ[4];
|
||||||
|
q[5] = preQ[5];
|
||||||
|
|
||||||
|
// BCD add 1, so 0x39 becomes 0x40
|
||||||
|
if((q[5] & 0xF) == 9)
|
||||||
|
q[5] += 7;
|
||||||
|
else
|
||||||
|
q[5]++;
|
||||||
|
|
||||||
|
// 74 frames, so from 0x00 to 0x74, BCD
|
||||||
|
if(q[5] >= 0x74)
|
||||||
|
{
|
||||||
|
// 0 frames
|
||||||
|
q[5] = 0;
|
||||||
|
|
||||||
|
// Add 1 second
|
||||||
|
if((q[4] & 0xF) == 9)
|
||||||
|
q[4] += 7;
|
||||||
|
else
|
||||||
|
q[4]++;
|
||||||
|
|
||||||
|
// 60 seconds, so from 0x00 to 0x59, BCD
|
||||||
|
if(q[4] >= 0x59)
|
||||||
|
{
|
||||||
|
// 0 seconds
|
||||||
|
q[4] = 0;
|
||||||
|
|
||||||
|
// Add 1 minute
|
||||||
|
q[3]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fixedRelPos = true;
|
||||||
|
|
||||||
|
CRC16CCITTContext.Data(q, 10, out qCrc);
|
||||||
|
status = qCrc[0] == q[10] && qCrc[1] == q[11];
|
||||||
|
|
||||||
|
if(status)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next is not pregap and we didn't fix relative position with previous
|
||||||
|
if(nextQ[2] > 0 &&
|
||||||
|
nextCrcOk &&
|
||||||
|
!fixedRelPos)
|
||||||
|
{
|
||||||
|
rmin = (byte)(((nextQ[3] / 16) * 10) + (nextQ[3] & 0x0F));
|
||||||
|
rsec = (byte)(((nextQ[4] / 16) * 10) + (nextQ[4] & 0x0F));
|
||||||
|
rframe = (byte)(((nextQ[5] / 16) * 10) + (nextQ[5] & 0x0F));
|
||||||
|
rPos = (rmin * 60 * 75) + (rsec * 75) + rframe;
|
||||||
|
|
||||||
|
dPos = rPos - pPos;
|
||||||
|
|
||||||
|
if(dPos != 1)
|
||||||
|
{
|
||||||
|
q[3] = nextQ[3];
|
||||||
|
q[4] = nextQ[4];
|
||||||
|
q[5] = nextQ[5];
|
||||||
|
|
||||||
|
// If frames is 0
|
||||||
|
if(q[5] == 0)
|
||||||
|
{
|
||||||
|
// If seconds is 0
|
||||||
|
if(q[4] == 0)
|
||||||
|
{
|
||||||
|
// BCD decrease minutes
|
||||||
|
if((q[3] & 0xF) == 0)
|
||||||
|
q[3] = (byte)((q[3] & 0xF0) - 0x10);
|
||||||
|
else
|
||||||
|
q[3]--;
|
||||||
|
|
||||||
|
q[4] = 0x59;
|
||||||
|
q[5] = 0x73;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// BCD decrease seconds
|
||||||
|
if((q[4] & 0xF) == 0)
|
||||||
|
q[4] = (byte)((q[4] & 0xF0) - 0x10);
|
||||||
|
else
|
||||||
|
q[4]--;
|
||||||
|
|
||||||
|
q[5] = 0x73;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BCD decrease frames
|
||||||
|
else if((q[5] & 0xF) == 0)
|
||||||
|
q[5] = (byte)((q[5] & 0xF0) - 0x10);
|
||||||
|
else
|
||||||
|
q[5]--;
|
||||||
|
|
||||||
|
fixedRelPos = true;
|
||||||
|
|
||||||
|
CRC16CCITTContext.Data(q, 10, out qCrc);
|
||||||
|
status = qCrc[0] == q[10] && qCrc[1] == q[11];
|
||||||
|
|
||||||
|
if(status)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(preCrcOk)
|
||||||
|
{
|
||||||
|
rmin = (byte)(((preQ[7] / 16) * 10) + (preQ[7] & 0x0F));
|
||||||
|
rsec = (byte)(((preQ[8] / 16) * 10) + (preQ[8] & 0x0F));
|
||||||
|
rframe = (byte)(((preQ[9] / 16) * 10) + (preQ[9] & 0x0F));
|
||||||
|
rPos = ((rmin * 60 * 75) + (rsec * 75) + rframe) - 150;
|
||||||
|
|
||||||
|
dPos = aPos - rPos;
|
||||||
|
|
||||||
|
if(dPos != 1)
|
||||||
|
{
|
||||||
|
q[7] = preQ[7];
|
||||||
|
q[8] = preQ[8];
|
||||||
|
q[9] = preQ[9];
|
||||||
|
|
||||||
|
// BCD add 1, so 0x39 becomes 0x40
|
||||||
|
if((q[9] & 0xF) == 9)
|
||||||
|
q[9] += 7;
|
||||||
|
else
|
||||||
|
q[9]++;
|
||||||
|
|
||||||
|
// 74 frames, so from 0x00 to 0x74, BCD
|
||||||
|
if(q[9] >= 0x74)
|
||||||
|
{
|
||||||
|
// 0 frames
|
||||||
|
q[9] = 0;
|
||||||
|
|
||||||
|
// Add 1 second
|
||||||
|
if((q[8] & 0xF) == 9)
|
||||||
|
q[8] += 7;
|
||||||
|
else
|
||||||
|
q[8]++;
|
||||||
|
|
||||||
|
// 60 seconds, so from 0x00 to 0x59, BCD
|
||||||
|
if(q[8] >= 0x59)
|
||||||
|
{
|
||||||
|
// 0 seconds
|
||||||
|
q[8] = 0;
|
||||||
|
|
||||||
|
// Add 1 minute
|
||||||
|
q[7]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fixedAbsPos = true;
|
||||||
|
|
||||||
|
CRC16CCITTContext.Data(q, 10, out qCrc);
|
||||||
|
status = qCrc[0] == q[10] && qCrc[1] == q[11];
|
||||||
|
|
||||||
|
if(status)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next is not pregap and we didn't fix relative position with previous
|
||||||
|
if(nextQ[2] > 0 &&
|
||||||
|
nextCrcOk &&
|
||||||
|
!fixedAbsPos)
|
||||||
|
{
|
||||||
|
rmin = (byte)(((nextQ[7] / 16) * 10) + (nextQ[7] & 0x0F));
|
||||||
|
rsec = (byte)(((nextQ[8] / 16) * 10) + (nextQ[8] & 0x0F));
|
||||||
|
rframe = (byte)(((nextQ[9] / 16) * 10) + (nextQ[9] & 0x0F));
|
||||||
|
rPos = ((rmin * 60 * 75) + (rsec * 75) + rframe) - 150;
|
||||||
|
|
||||||
|
dPos = rPos - pPos;
|
||||||
|
|
||||||
|
if(dPos != 1)
|
||||||
|
{
|
||||||
|
q[7] = nextQ[7];
|
||||||
|
q[8] = nextQ[8];
|
||||||
|
q[9] = nextQ[9];
|
||||||
|
|
||||||
|
// If frames is 0
|
||||||
|
if(q[9] == 0)
|
||||||
|
{
|
||||||
|
// If seconds is 0
|
||||||
|
if(q[8] == 0)
|
||||||
|
{
|
||||||
|
// BCD decrease minutes
|
||||||
|
if((q[7] & 0xF) == 0)
|
||||||
|
q[7] = (byte)((q[7] & 0xF0) - 0x10);
|
||||||
|
else
|
||||||
|
q[7]--;
|
||||||
|
|
||||||
|
q[8] = 0x59;
|
||||||
|
q[9] = 0x73;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// BCD decrease seconds
|
||||||
|
if((q[8] & 0xF) == 0)
|
||||||
|
q[8] = (byte)((q[8] & 0xF0) - 0x10);
|
||||||
|
else
|
||||||
|
q[8]--;
|
||||||
|
|
||||||
|
q[9] = 0x73;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// BCD decrease frames
|
||||||
|
else if((q[9] & 0xF) == 0)
|
||||||
|
q[9] = (byte)((q[9] & 0xF0) - 0x10);
|
||||||
|
else
|
||||||
|
q[9]--;
|
||||||
|
|
||||||
|
fixedAbsPos = true;
|
||||||
|
|
||||||
|
CRC16CCITTContext.Data(q, 10, out qCrc);
|
||||||
|
status = qCrc[0] == q[10] && qCrc[1] == q[11];
|
||||||
|
|
||||||
|
if(status)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CRC16CCITTContext.Data(q, 10, out qCrc);
|
||||||
|
status = qCrc[0] == q[10] && qCrc[1] == q[11];
|
||||||
|
|
||||||
|
// Game Over
|
||||||
|
if(!fixCrc || status)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(preCrcOk)
|
||||||
|
{
|
||||||
|
rmin = (byte)(((preQ[7] / 16) * 10) + (preQ[7] & 0x0F));
|
||||||
|
rsec = (byte)(((preQ[8] / 16) * 10) + (preQ[8] & 0x0F));
|
||||||
|
rframe = (byte)(((preQ[9] / 16) * 10) + (preQ[9] & 0x0F));
|
||||||
|
rPos = ((rmin * 60 * 75) + (rsec * 75) + rframe) - 150;
|
||||||
|
|
||||||
|
dPos = aPos - rPos;
|
||||||
|
|
||||||
|
bool absOk = dPos == 1;
|
||||||
|
|
||||||
|
rmin = (byte)(((preQ[3] / 16) * 10) + (preQ[3] & 0x0F));
|
||||||
|
rsec = (byte)(((preQ[4] / 16) * 10) + (preQ[4] & 0x0F));
|
||||||
|
rframe = (byte)(((preQ[5] / 16) * 10) + (preQ[5] & 0x0F));
|
||||||
|
rPos = (rmin * 60 * 75) + (rsec * 75) + rframe;
|
||||||
|
|
||||||
|
dPos = pPos - rPos;
|
||||||
|
|
||||||
|
bool relOk = dPos == 1;
|
||||||
|
|
||||||
|
if(q[0] != preQ[0] ||
|
||||||
|
q[1] != preQ[1] ||
|
||||||
|
q[2] != preQ[2] ||
|
||||||
|
q[6] != 0 ||
|
||||||
|
!absOk ||
|
||||||
|
!relOk)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CRC16CCITTContext.Data(q, 10, out qCrc);
|
||||||
|
q[10] = qCrc[0];
|
||||||
|
q[11] = qCrc[1];
|
||||||
|
|
||||||
|
fixedCrc = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if(nextCrcOk)
|
||||||
|
{
|
||||||
|
rmin = (byte)(((nextQ[7] / 16) * 10) + (nextQ[7] & 0x0F));
|
||||||
|
rsec = (byte)(((nextQ[8] / 16) * 10) + (nextQ[8] & 0x0F));
|
||||||
|
rframe = (byte)(((nextQ[9] / 16) * 10) + (nextQ[9] & 0x0F));
|
||||||
|
rPos = ((rmin * 60 * 75) + (rsec * 75) + rframe) - 150;
|
||||||
|
|
||||||
|
dPos = rPos - aPos;
|
||||||
|
|
||||||
|
bool absOk = dPos == 1;
|
||||||
|
|
||||||
|
rmin = (byte)(((nextQ[3] / 16) * 10) + (nextQ[3] & 0x0F));
|
||||||
|
rsec = (byte)(((nextQ[4] / 16) * 10) + (nextQ[4] & 0x0F));
|
||||||
|
rframe = (byte)(((nextQ[5] / 16) * 10) + (nextQ[5] & 0x0F));
|
||||||
|
rPos = (rmin * 60 * 75) + (rsec * 75) + rframe;
|
||||||
|
|
||||||
|
dPos = rPos - pPos;
|
||||||
|
|
||||||
|
bool relOk = dPos == 1;
|
||||||
|
|
||||||
|
if(q[0] != nextQ[0] ||
|
||||||
|
q[1] != nextQ[1] ||
|
||||||
|
q[2] != nextQ[2] ||
|
||||||
|
q[6] != 0 ||
|
||||||
|
!absOk ||
|
||||||
|
!relOk)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
CRC16CCITTContext.Data(q, 10, out qCrc);
|
||||||
|
q[10] = qCrc[0];
|
||||||
|
q[11] = qCrc[1];
|
||||||
|
|
||||||
|
fixedCrc = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ok if previous and next are both BAD I won't rewrite the CRC at all
|
||||||
|
}
|
||||||
|
else if((q[0] & 0x3) == 2)
|
||||||
|
{
|
||||||
|
// TODO: MCN
|
||||||
|
}
|
||||||
|
else if((q[0] & 0x3) == 3)
|
||||||
|
{
|
||||||
|
// TODO: ISRC
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,6 +72,7 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
readonly CICMMetadataType _preSidecar;
|
readonly CICMMetadataType _preSidecar;
|
||||||
readonly bool _private;
|
readonly bool _private;
|
||||||
readonly ushort _retryPasses;
|
readonly ushort _retryPasses;
|
||||||
|
readonly bool _retrySubchannel;
|
||||||
readonly bool _stopOnError;
|
readonly bool _stopOnError;
|
||||||
readonly DumpSubchannel _subchannel;
|
readonly DumpSubchannel _subchannel;
|
||||||
readonly bool _trim;
|
readonly bool _trim;
|
||||||
@@ -80,9 +81,10 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
Database.Models.Device _dbDev; // Device database entry
|
Database.Models.Device _dbDev; // Device database entry
|
||||||
bool _dumpFirstTrackPregap;
|
bool _dumpFirstTrackPregap;
|
||||||
bool _fixOffset;
|
bool _fixOffset;
|
||||||
|
readonly bool _fixSubchannel;
|
||||||
|
readonly bool _fixSubchannelCrc;
|
||||||
uint _maximumReadable; // Maximum number of sectors drive can read at once
|
uint _maximumReadable; // Maximum number of sectors drive can read at once
|
||||||
Resume _resume;
|
Resume _resume;
|
||||||
readonly bool _retrySubchannel;
|
|
||||||
Sidecar _sidecarClass;
|
Sidecar _sidecarClass;
|
||||||
uint _skip;
|
uint _skip;
|
||||||
int _speed;
|
int _speed;
|
||||||
@@ -115,7 +117,7 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
Encoding encoding, string outputPrefix, string outputPath, Dictionary<string, string> formatOptions,
|
Encoding encoding, string outputPrefix, string outputPath, Dictionary<string, string> formatOptions,
|
||||||
CICMMetadataType preSidecar, uint skip, bool metadata, bool trim, bool dumpFirstTrackPregap,
|
CICMMetadataType preSidecar, uint skip, bool metadata, bool trim, bool dumpFirstTrackPregap,
|
||||||
bool fixOffset, bool debug, DumpSubchannel subchannel, int speed, bool @private,
|
bool fixOffset, bool debug, DumpSubchannel subchannel, int speed, bool @private,
|
||||||
bool fixSubchannelPosition, bool retrySubchannel)
|
bool fixSubchannelPosition, bool retrySubchannel, bool fixSubchannel, bool fixSubchannelCrc)
|
||||||
{
|
{
|
||||||
_doResume = doResume;
|
_doResume = doResume;
|
||||||
_dev = dev;
|
_dev = dev;
|
||||||
@@ -147,6 +149,8 @@ namespace Aaru.Core.Devices.Dumping
|
|||||||
_private = @private;
|
_private = @private;
|
||||||
_fixSubchannelPosition = fixSubchannelPosition;
|
_fixSubchannelPosition = fixSubchannelPosition;
|
||||||
_retrySubchannel = retrySubchannel;
|
_retrySubchannel = retrySubchannel;
|
||||||
|
_fixSubchannel = fixSubchannel;
|
||||||
|
_fixSubchannelCrc = fixSubchannelCrc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Starts dumping with the stablished fields and autodetecting the device type</summary>
|
/// <summary>Starts dumping with the stablished fields and autodetecting the device type</summary>
|
||||||
|
|||||||
@@ -185,5 +185,75 @@ namespace Aaru.Core.Logging
|
|||||||
|
|
||||||
_logSw.Flush();
|
_logSw.Flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WritePFix()
|
||||||
|
{
|
||||||
|
_logSw.WriteLine("Fixed P subchannel using weight average.");
|
||||||
|
|
||||||
|
_logSw.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteRwFix()
|
||||||
|
{
|
||||||
|
_logSw.WriteLine("Fixed R-W subchannels writing empty data.");
|
||||||
|
|
||||||
|
_logSw.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteQAdrFix()
|
||||||
|
{
|
||||||
|
_logSw.WriteLine("Fixed Q subchannel with correct ADR.");
|
||||||
|
|
||||||
|
_logSw.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteQCtrlFix()
|
||||||
|
{
|
||||||
|
_logSw.WriteLine("Fixed Q subchannel with correct CONTROL.");
|
||||||
|
|
||||||
|
_logSw.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteQZeroFix()
|
||||||
|
{
|
||||||
|
_logSw.WriteLine("Fixed Q subchannel with correct ZERO.");
|
||||||
|
|
||||||
|
_logSw.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteQTnoFix()
|
||||||
|
{
|
||||||
|
_logSw.WriteLine("Fixed Q subchannel with correct TNO.");
|
||||||
|
|
||||||
|
_logSw.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteQIndexFix()
|
||||||
|
{
|
||||||
|
_logSw.WriteLine("Fixed Q subchannel with correct INDEX.");
|
||||||
|
|
||||||
|
_logSw.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteQRelPosFix()
|
||||||
|
{
|
||||||
|
_logSw.WriteLine("Fixed Q subchannel with correct RELATIVE POSITION.");
|
||||||
|
|
||||||
|
_logSw.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteQAbsPosFix()
|
||||||
|
{
|
||||||
|
_logSw.WriteLine("Fixed Q subchannel with correct ABSOLUTE POSITION.");
|
||||||
|
|
||||||
|
_logSw.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteQCrcFix()
|
||||||
|
{
|
||||||
|
_logSw.WriteLine("Fixed Q subchannel with correct CRC.");
|
||||||
|
|
||||||
|
_logSw.Flush();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -800,7 +800,7 @@ namespace Aaru.Gui.ViewModels.Windows
|
|||||||
_dumper = new Dump(Resume, _dev, _devicePath, SelectedPlugin.Plugin, (ushort)Retries, Force, false,
|
_dumper = new Dump(Resume, _dev, _devicePath, SelectedPlugin.Plugin, (ushort)Retries, Force, false,
|
||||||
Persistent, StopOnError, _resume, dumpLog, encoding, _outputPrefix, Destination,
|
Persistent, StopOnError, _resume, dumpLog, encoding, _outputPrefix, Destination,
|
||||||
parsedOptions, _sidecar, (uint)Skipped, ExistingMetadata == false, Trim == false,
|
parsedOptions, _sidecar, (uint)Skipped, ExistingMetadata == false, Trim == false,
|
||||||
Track1Pregap, true, false, DumpSubchannel.Any, 0, false, false, false);
|
Track1Pregap, true, false, DumpSubchannel.Any, 0, false, false, false, false, false);
|
||||||
|
|
||||||
new Thread(DoWork).Start();
|
new Thread(DoWork).Start();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -194,11 +194,27 @@ namespace Aaru.Commands.Media
|
|||||||
Add(new Option(new[]
|
Add(new Option(new[]
|
||||||
{
|
{
|
||||||
"--retry-subchannel"
|
"--retry-subchannel"
|
||||||
}, "Retry subchannel. Implies fixing subchannel position..")
|
}, "Retry subchannel. Implies fixing subchannel position.")
|
||||||
{
|
{
|
||||||
Argument = new Argument<bool>(() => true), Required = false
|
Argument = new Argument<bool>(() => true), Required = false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Add(new Option(new[]
|
||||||
|
{
|
||||||
|
"--fix-subchannel"
|
||||||
|
}, "Try to fix subchannel. Implies fixing subchannel position.")
|
||||||
|
{
|
||||||
|
Argument = new Argument<bool>(() => false), Required = false
|
||||||
|
});
|
||||||
|
|
||||||
|
Add(new Option(new[]
|
||||||
|
{
|
||||||
|
"--fix-subchannel-crc"
|
||||||
|
}, "If subchannel looks OK but CRC fails, rewrite it. Implies fixing subchannel.")
|
||||||
|
{
|
||||||
|
Argument = new Argument<bool>(() => false), Required = false
|
||||||
|
});
|
||||||
|
|
||||||
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
|
Handler = CommandHandler.Create(GetType().GetMethod(nameof(Invoke)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +222,8 @@ namespace Aaru.Commands.Media
|
|||||||
string encoding, bool firstPregap, bool fixOffset, bool force, bool metadata,
|
string encoding, bool firstPregap, bool fixOffset, bool force, bool metadata,
|
||||||
bool trim, string outputPath, string options, bool persistent, ushort retryPasses,
|
bool trim, string outputPath, string options, bool persistent, ushort retryPasses,
|
||||||
uint skip, byte speed, bool stopOnError, string format, string subchannel,
|
uint skip, byte speed, bool stopOnError, string format, string subchannel,
|
||||||
bool @private, bool fixSubchannelPosition, bool retrySubchannel)
|
bool @private, bool fixSubchannelPosition, bool retrySubchannel, bool fixSubchannel,
|
||||||
|
bool fixSubchannelCrc)
|
||||||
{
|
{
|
||||||
MainClass.PrintCopyright();
|
MainClass.PrintCopyright();
|
||||||
|
|
||||||
@@ -216,7 +233,10 @@ namespace Aaru.Commands.Media
|
|||||||
if(verbose)
|
if(verbose)
|
||||||
AaruConsole.VerboseWriteLineEvent += System.Console.WriteLine;
|
AaruConsole.VerboseWriteLineEvent += System.Console.WriteLine;
|
||||||
|
|
||||||
if(retrySubchannel)
|
if(fixSubchannelCrc)
|
||||||
|
fixSubchannel = true;
|
||||||
|
|
||||||
|
if(retrySubchannel || fixSubchannel)
|
||||||
fixSubchannelPosition = true;
|
fixSubchannelPosition = true;
|
||||||
|
|
||||||
Statistics.AddCommand("dump-media");
|
Statistics.AddCommand("dump-media");
|
||||||
@@ -243,6 +263,8 @@ namespace Aaru.Commands.Media
|
|||||||
AaruConsole.DebugWriteLine("Dump-Media command", "--private={0}", @private);
|
AaruConsole.DebugWriteLine("Dump-Media command", "--private={0}", @private);
|
||||||
AaruConsole.DebugWriteLine("Dump-Media command", "--fix-subchannel-position={0}", fixSubchannelPosition);
|
AaruConsole.DebugWriteLine("Dump-Media command", "--fix-subchannel-position={0}", fixSubchannelPosition);
|
||||||
AaruConsole.DebugWriteLine("Dump-Media command", "--retry-subchannel={0}", retrySubchannel);
|
AaruConsole.DebugWriteLine("Dump-Media command", "--retry-subchannel={0}", retrySubchannel);
|
||||||
|
AaruConsole.DebugWriteLine("Dump-Media command", "--fix-subchannel={0}", fixSubchannel);
|
||||||
|
AaruConsole.DebugWriteLine("Dump-Media command", "--fix-subchannel-crc={0}", fixSubchannelCrc);
|
||||||
|
|
||||||
// TODO: Disabled temporarily
|
// TODO: Disabled temporarily
|
||||||
//AaruConsole.DebugWriteLine("Dump-Media command", "--raw={0}", raw);
|
//AaruConsole.DebugWriteLine("Dump-Media command", "--raw={0}", raw);
|
||||||
@@ -441,7 +463,8 @@ namespace Aaru.Commands.Media
|
|||||||
var dumper = new Dump(resume, dev, devicePath, outputFormat, retryPasses, force, false, persistent,
|
var dumper = new Dump(resume, dev, devicePath, outputFormat, retryPasses, force, false, persistent,
|
||||||
stopOnError, resumeClass, dumpLog, encodingClass, outputPrefix, outputPath,
|
stopOnError, resumeClass, dumpLog, encodingClass, outputPrefix, outputPath,
|
||||||
parsedOptions, sidecar, skip, metadata, trim, firstPregap, fixOffset, debug,
|
parsedOptions, sidecar, skip, metadata, trim, firstPregap, fixOffset, debug,
|
||||||
wantedSubchannel, speed, @private, fixSubchannelPosition, retrySubchannel);
|
wantedSubchannel, speed, @private, fixSubchannelPosition, retrySubchannel,
|
||||||
|
fixSubchannel, fixSubchannelCrc);
|
||||||
|
|
||||||
dumper.UpdateStatus += Progress.UpdateStatus;
|
dumper.UpdateStatus += Progress.UpdateStatus;
|
||||||
dumper.ErrorMessage += Progress.ErrorMessage;
|
dumper.ErrorMessage += Progress.ErrorMessage;
|
||||||
|
|||||||
Reference in New Issue
Block a user