beetle-pce-fast-libretro/mednafen/cdrom/recover-raw.cpp
2016-08-14 11:57:54 +02:00

214 lines
5.2 KiB
C++

/* dvdisaster: Additional error correction for optical media.
* Copyright (C) 2004-2007 Carsten Gnoerlich.
* Project home page: http://www.dvdisaster.com
* Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
* or direct your browser at http://www.gnu.org.
*/
#include <boolean.h>
#include "dvdisaster.h"
static GaloisTables *gt = NULL; /* for L-EC Reed-Solomon */
static ReedSolomonTables *rt = NULL;
bool Init_LEC_Correct(void)
{
gt = CreateGaloisTables(0x11d);
rt = CreateReedSolomonTables(gt, 0, 1, 10);
return(1);
}
void Kill_LEC_Correct(void)
{
FreeGaloisTables(gt);
FreeReedSolomonTables(rt);
}
/***
*** CD level CRC calculation
***/
/*
* Test raw sector against its 32bit CRC.
* Returns true if frame is good.
*/
int CheckEDC(const unsigned char *cd_frame, bool xa_mode)
{
unsigned int expected_crc, real_crc;
unsigned int crc_base = xa_mode ? 2072 : 2064;
expected_crc = cd_frame[crc_base + 0] << 0;
expected_crc |= cd_frame[crc_base + 1] << 8;
expected_crc |= cd_frame[crc_base + 2] << 16;
expected_crc |= cd_frame[crc_base + 3] << 24;
if(xa_mode)
real_crc = EDCCrc32(cd_frame+16, 2056);
else
real_crc = EDCCrc32(cd_frame, 2064);
if(expected_crc == real_crc)
return(1);
else
{
//printf("Bad EDC CRC: Calculated: %08x, Recorded: %08x\n", real_crc, expected_crc);
return(0);
}
}
/***
*** A very simple L-EC error correction.
***
* Perform just one pass over the Q and P vectors to see if everything
* is okay respectively correct minor errors. This is pretty much the
* same stuff the drive is supposed to do in the final L-EC stage.
*/
static int simple_lec(unsigned char *frame)
{
unsigned char byte_state[2352];
unsigned char p_vector[P_VECTOR_SIZE];
unsigned char q_vector[Q_VECTOR_SIZE];
unsigned char p_state[P_VECTOR_SIZE];
int erasures[Q_VECTOR_SIZE], erasure_count;
int ignore[2];
int p_failures, q_failures;
int p_corrected, q_corrected;
int p,q;
/* Setup */
memset(byte_state, 0, 2352);
p_failures = q_failures = 0;
p_corrected = q_corrected = 0;
/* Perform Q-Parity error correction */
for(q=0; q<N_Q_VECTORS; q++)
{ int err;
/* We have no erasure information for Q vectors */
GetQVector(frame, q_vector, q);
err = DecodePQ(rt, q_vector, Q_PADDING, ignore, 0);
/* See what we've got */
if(err < 0) /* Uncorrectable. Mark bytes are erasure. */
{ q_failures++;
FillQVector(byte_state, 1, q);
}
else /* Correctable */
{ if(err == 1 || err == 2) /* Store back corrected vector */
{ SetQVector(frame, q_vector, q);
q_corrected++;
}
}
}
/* Perform P-Parity error correction */
for(p=0; p<N_P_VECTORS; p++)
{ int err,i;
/* Try error correction without erasure information */
GetPVector(frame, p_vector, p);
err = DecodePQ(rt, p_vector, P_PADDING, ignore, 0);
/* If unsuccessful, try again using erasures.
Erasure information is uncertain, so try this last. */
if(err < 0 || err > 2)
{ GetPVector(byte_state, p_state, p);
erasure_count = 0;
for(i=0; i<P_VECTOR_SIZE; i++)
if(p_state[i])
erasures[erasure_count++] = i;
if(erasure_count > 0 && erasure_count <= 2)
{ GetPVector(frame, p_vector, p);
err = DecodePQ(rt, p_vector, P_PADDING, erasures, erasure_count);
}
}
/* See what we've got */
if(err < 0) /* Uncorrectable. */
{ p_failures++;
}
else /* Correctable. */
{ if(err == 1 || err == 2) /* Store back corrected vector */
{ SetPVector(frame, p_vector, p);
p_corrected++;
}
}
}
/* Sum up */
if(q_failures || p_failures || q_corrected || p_corrected)
{
return 1;
}
return 0;
}
/***
*** Validate CD raw sector
***/
int ValidateRawSector(unsigned char *frame, bool xaMode)
{
int lec_did_sth = false;
/* Do simple L-EC.
It seems that drives stop their internal L-EC as soon as the
EDC is okay, so we may see uncorrected errors in the parity bytes.
Since we are also interested in the user data only and doing the
L-EC is expensive, we skip our L-EC as well when the EDC is fine. */
if(!CheckEDC(frame, xaMode))
{
unsigned char header[4];
if(xaMode)
{
memcpy(header, frame + 12, 4);
memset(frame + 12, 0, 4);
}
lec_did_sth = simple_lec(frame);
if(xaMode)
memcpy(frame + 12, header, 4);
}
/* Test internal sector checksum again */
if(!CheckEDC(frame, xaMode))
/* EDC failure in RAW sector */
return false;
return true;
}