Files
dvdisaster/smart-lec.c
Stéphane Lesimple 38defdf7aa Apply (most) debian patches
Apply debian patch 02-encryption
Apply debian patch 03-dvdrom
Apply a modified version of patch 05-help-dialog
Apply debian patch 08-fix-gnu-make-detection
Apply debian patch 10-use-non-size-specific-icon-and-add-keywords-to-desktop-file
Apply debian patch 12-fix-spelling-of-up-to
Apply debian patch 13-fix-missing-language-field-in-po-files
Apply a modified version of debian patch 14-make-builds-reproducible
Apply debian patch 17-fix-all-but-deprecated-api-warnings
Apply a modified version of debian patch 18-update-copyright-in-about-dialog
Apply debian patch 19-show-text-files-with-abs-path
Apply debian patch 22-fix-hurd-i386-ftbfs
Apply debian patch 23-add-bdrom-support
Apply debian patch 25-fix-man-pages
Apply debian patch 27-allow-opening-in-browser-again
Apply debian patch 28-pdftex-reproducibility
Apply debian patch 29-fix-more-typos
Apply debian patch 30-hurd-kfreebsd-ftbfs
Apply debian patch 31-improve-hurd-and-kfreebsd-support
Apply debian patch 33-honour-LDFLAGS
Apply debian patch 34-gcc8-format-security.patch
Apply debian patch 35-archived-homepage
Apply debian patch 36-fix-parallelism
2020-08-20 14:17:35 +02:00

1712 lines
45 KiB
C

/* dvdisaster: Additional error correction for optical media.
* Copyright (C) 2004-2017 Carsten Gnoerlich.
*
* Email: carsten@dvdisaster.org -or- cgnoerlich@fsfe.org
* Project homepage: http://www.dvdisaster.org
*
* This file is part of dvdisaster.
*
* dvdisaster 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.
*
* dvdisaster 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 dvdisaster. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dvdisaster.h"
//#define LOCAL_ONLY 1
//#define PRINT_STEPS 1
#define VERBOSE 1
#ifdef VERBOSE
#define verbose(format,...) printf(format, __VA_ARGS__)
#else
#define verbose(format,...)
#endif
/***
*** Weights for the evaluation heuristics
***/
/* Weights for self-correcting vectors */
/* Vector corrected itself */
#define BONUS_SELF_CORRECT 50
/* Vector corrected itself and improved another one */
#define BONUS_CROSSED_CORRECT 100
/* Vector corrected itself but destroyed another one */
#define MALUS_CROSSED_DESTROY 100
/* Weights for swapping vector alternatives */
/* Vector was swapped with an accepting one */
#define BONUS_SWAPPED_WITH_BETTER_VECTOR 50
/* Swapped vector improved another vector */
#define BONUS_SWAP_IMPROVED_CROSSING 100
/* Swapped vector destroyed another vector */
#define MALUS_SWAP_DESTROYED_CROSSING 100
/* Swapped for improvement bonus */
#define SWAPPED_WITH_IMPROVEMENT_BONUS 95
/* Swapped for improvement change crossing vector for worse */
#define SWAPPED_WITH_IMPROVEMENT_MALUS 50
/* Indirect improvement bonus for initial P */
#define INDIRECT_IMPROVEMENT_BONUS_FOR_P 90
#define INDIRECT_IMPROVEMENT_MALUS_FOR_P 40
/* Indirect improvement bonus for inner P2 and Q*/
#define INDIRECT_IMPROVEMENT_BONUS_FOR_P2 50
#define INDIRECT_IMPROVEMENT_BONUS_FOR_Q 90
/* Penalty for reaching an already existing solution */
#define CYCLE_PENALTY 20
/***
*** Local data struct
***/
enum
{ ITERATION_AUTORUN,
ITERATION_PICK_BEST_SECTOR,
ITERATION_RUN_HEURISTICS
};
typedef struct _sh_context
{ RawBuffer *rb;
unsigned char *visited; /* md5sums of already tried solutions */
int *penalty; /* penalty for allready tried solution */
int visitedMax;
int visitedCnt;
int iteration; /* for iterative running within the editor */
char msg[SMART_LEC_MESSAGE_SIZE]; /* diagnostic output */
unsigned char bestFrame[MAX_RAW_TRANSFER_SIZE];
int bestBonus;
int bestMalus;
int pState[N_P_VECTORS];
int pPosition[N_P_VECTORS]; /* position of erroneous byte in P vector */
int pValue[N_P_VECTORS]; /* value of corrected byte */
int crossedQ[N_P_VECTORS]; /* q vector affected by corrected byte */
int crossedQIdx[N_P_VECTORS]; /* q vector affected by corrected byte */
int hitByQ[N_P_VECTORS]; /* hit by how many q vectors? */
int qState[N_Q_VECTORS];
int qPosition[N_Q_VECTORS]; /* position of erroneous byte in Q vector */
int qValue[N_Q_VECTORS]; /* value of corrected byte */
int crossedP[N_Q_VECTORS]; /* p vector affected by corrected byte */
int crossedPIdx[N_Q_VECTORS]; /* p vector affected by corrected byte */
int hitByP[N_Q_VECTORS]; /* hit by how many p vectors? */
} sh_context;
static sh_context* create_sh_context(RawBuffer *rb)
{ sh_context *shc = g_malloc0(sizeof(sh_context));
shc->rb = rb;
shc->visited = g_malloc(16*4);
shc->penalty = g_malloc(sizeof(int)*4);
shc->visitedMax = 4;
shc->visitedCnt = 0;
return shc;
}
static void free_sh_context(sh_context *shc)
{
g_free(shc->visited);
g_free(shc->penalty);
g_free(shc);
}
/*
* Predicate for recognizing a better solution
*/
int found_better_solution(sh_context *shc, int bonus, int malus)
{
if(bonus < 0 || malus > shc->bestMalus)
return FALSE;
if( (malus < shc->bestMalus && bonus > 0)
|| (malus == shc->bestMalus && bonus > shc->bestBonus))
{ shc->bestBonus = bonus;
shc->bestMalus = malus;
verbose("pick %d/%d\n",bonus,malus);
return TRUE;
}
return FALSE;
}
/*
* Add a frame to the visited list
*/
static void push_frame(sh_context *shc, unsigned char *frame)
{ MD5Context ctxt;
if(shc->visitedCnt >= shc->visitedMax)
{ shc->visitedMax *= 2;
shc->visited = g_realloc(shc->visited, 16*shc->visitedMax);
shc->penalty = g_realloc(shc->penalty, sizeof(int)*shc->visitedMax);
}
MD5Init(&ctxt);
MD5Update(&ctxt, frame, shc->rb->sampleSize);
MD5Final(&shc->visited[16*shc->visitedCnt], &ctxt);
shc->penalty[shc->visitedCnt] = 0;
shc->visitedCnt++;
printf("pushed\n");
}
/*
* Check whether the solution was found before
*/
static int frame_visited(sh_context *shc, unsigned char *frame)
{ MD5Context ctxt;
unsigned char md5sum[16];
int i,n;
MD5Init(&ctxt);
MD5Update(&ctxt, frame, shc->rb->sampleSize);
MD5Final(md5sum, &ctxt);
n = shc->visitedCnt*16;
for(i=0; i<n; i+=16)
if(!memcmp(md5sum, &shc->visited[i], 16))
return i/16+1;
return 0;
}
/*
* Calculate a penalty for already seen solution
*/
static int cycle_penalty(sh_context *shc, unsigned char *frame)
{ int idx = frame_visited(shc, frame);
if(!idx) return 0;
idx--;
shc->penalty[idx] += CYCLE_PENALTY;
return shc->penalty[idx];
}
/*
* Check whether the frame has been corrected
*/
static int frame_corrected(RawBuffer *rb)
{
if( CheckEDC(rb->recovered, rb->xaMode)
&& CheckMSF(rb->recovered, rb->lba, STRICT_MSF_CHECK))
return TRUE;
return FALSE;
}
/*
* Try lec with given p/q vectors without erasures.
* Returns position of error if err==1
*/
static int decode_p(RawBuffer *rb, unsigned char* p_vector, int *pos)
{ int eras[2], err;
unsigned char backup[P_VECTOR_SIZE];
memcpy(backup, p_vector, P_VECTOR_SIZE);
err = DecodePQ(rb->rt, p_vector, P_PADDING, eras, 0);
if(err == 0)
return err;
if(err == 1)
{ int i;
for(i=0; i<P_VECTOR_SIZE; i++)
if(backup[i] != p_vector[i] && i != eras[0])
{ printf("POSITION FAILURE\n");
exit(0);
}
*pos = eras[0];
return err;
}
return 2;
}
static int decode_q(RawBuffer *rb, unsigned char* q_vector, int *pos)
{ int eras[2], err;
unsigned char backup[Q_VECTOR_SIZE];
memcpy(backup, q_vector, Q_VECTOR_SIZE);
err = DecodePQ(rb->rt, q_vector, Q_PADDING, eras, 0);
if(err == 0)
return err;
if(err == 1)
{ int i;
for(i=0; i<Q_VECTOR_SIZE; i++)
if(backup[i] != q_vector[i] && i != eras[0])
{ printf("POSITION FAILURE\n");
exit(0);
}
*pos = eras[0];
return err;
}
return 2;
}
/***
*** Pick the best P/Q vectors.
***
* Find all different versions of P/Q vectors in the samples
* which evaluate to 0 or 1 in the error correction.
* In the latter case, the corrected version is stored.
*/
void CollectGoodVectors(RawBuffer *rb)
{ unsigned char vector[Q_VECTOR_SIZE];
int eras[2];
int sample_idx;
int err;
int i,p,q;
if(!rb->samplesRead) /* We need at least one sample */
return;
sample_idx = rb->samplesRead-1;
/* Find all P vectors which are accepted by the error correction */
for(p=0; p<N_P_VECTORS; p++)
{ int found = FALSE;
int last_p = rb->pn[p];
GetPVector(rb->rawBuf[sample_idx], vector, p);
err = DecodePQ(rb->rt, vector, P_PADDING, eras, 0);
if(err != 0 && err != 1)
continue;
for(i=0; i<last_p; i++)
if(!memcmp(rb->pList[p][i], vector, P_VECTOR_SIZE))
{ found = TRUE;
break;
}
if(!found)
{ memcpy(rb->pList[p][last_p], vector, P_VECTOR_SIZE);
rb->pn[p]++;
}
}
/* Find all Q vectors which are accepted by the error correction */
for(q=0; q<N_Q_VECTORS; q++)
{ int found = FALSE;
int last_q = rb->qn[q];
GetQVector(rb->rawBuf[sample_idx], vector, q);
err = DecodePQ(rb->rt, vector, Q_PADDING, eras, 0);
if(err != 0 && err != 1)
continue;
for(i=0; i<last_q; i++)
if(!memcmp(rb->qList[q][i], vector, Q_VECTOR_SIZE))
{ found = TRUE;
break;
}
if(!found)
{ memcpy(rb->qList[q][last_q], vector, Q_VECTOR_SIZE);
rb->qn[q]++;
}
}
}
/*
* Debugging function
*/
void PrintPQStats(RawBuffer *rb)
{ int i;
PrintLog("PQ vector good variants from read samples:\n");
for(i=0; i<N_P_VECTORS; i++)
PrintLog("P%02d: %02d\n", i, rb->pn[i]);
for(i=0; i<N_Q_VECTORS; i++)
PrintLog("Q%02d: %02d\n", i, rb->qn[i]);
}
/***
*** Find correctable vectors and their interrelationship
***/
static void update_pq_state(sh_context *shc)
{ RawBuffer *rb = shc->rb;
unsigned char vector[Q_VECTOR_SIZE];
int eras[2],err,i;
int crossed,crossed_idx;
memset(shc->crossedP, 0, sizeof(shc->crossedP));
memset(shc->crossedQ, 0, sizeof(shc->crossedQ));
memset(shc->crossedPIdx, 0, sizeof(shc->crossedPIdx));
memset(shc->crossedQIdx, 0, sizeof(shc->crossedQIdx));
memset(shc->hitByP, 0, sizeof(shc->hitByP));
memset(shc->hitByQ, 0, sizeof(shc->hitByQ));
for(i=0; i<N_P_VECTORS; i++)
{ GetPVector(rb->recovered, vector, i);
err = DecodePQ(rb->rt, vector, P_PADDING, eras, 0);
switch(err)
{ case 0:
shc->pState[i] = 0;
break;
case 1:
shc->pState[i] = 1;
shc->pPosition[i] = eras[0];
shc->pValue[i] = vector[eras[0]];
ByteIndexToQ(PToByteIndex(i, eras[0]), &crossed, &crossed_idx);
shc->crossedQ[i] = crossed;
shc->crossedQIdx[i] = crossed_idx;
shc->hitByP[crossed]++;
break;
default:
shc->pState[i] = 2;
break;
}
}
for(i=0; i<N_Q_VECTORS; i++)
{ GetQVector(rb->recovered, vector, i);
err = DecodePQ(rb->rt, vector, Q_PADDING, eras, 0);
switch(err)
{ case 0:
shc->qState[i] = 0;
break;
case 1:
shc->qState[i] = 1;
shc->qPosition[i] = eras[0];
shc->qValue[i] = vector[eras[0]];
ByteIndexToP(QToByteIndex(i, eras[0]), &crossed, &crossed_idx);
shc->crossedP[i] = crossed;
shc->crossedPIdx[i] = crossed_idx;
shc->hitByQ[crossed]++;
break;
default:
shc->qState[i] = 2;
break;
}
}
}
static void print_pq_state(sh_context *shc)
{ int i;
verbose("%s", "PQ states: \n");
for(i=0; i<N_P_VECTORS; i++)
{ if(shc->pState[i] == 1)
verbose("P %02d: correctable, crosses Q %02d\n", i, shc->crossedQ[i]);
if(shc->pState[i] == 2)
verbose("P %02d: failure\n", i);
}
for(i=0; i<N_Q_VECTORS; i++)
{
if(shc->qState[i] == 1)
verbose("Q %02d: correctable, crosses P %02d\n", i, shc->crossedP[i]);
if(shc->qState[i] == 2)
verbose("Q %02d: failure\n", i);
}
}
/***
*** Track changes of one byte recursively
***/
static void recursive_q_correction(RawBuffer*, unsigned char*, int, int, int*, int*);
static void recursive_p_correction(RawBuffer *rb, unsigned char *frame,
int byte_idx, int new_byte,
int *better, int *worse)
{ unsigned char p_vector[P_VECTOR_SIZE];
int old_err, new_err, pos;
int p,p_idx;
ByteIndexToP(byte_idx, &p, &p_idx);
GetPVector(frame, p_vector, p);
old_err = decode_p(rb, p_vector, &pos);
GetPVector(frame, p_vector, p);
p_vector[p_idx] = new_byte;
new_err = decode_p(rb, p_vector, &pos);
if(new_err > old_err)
{ *worse += (new_err - old_err);
verbose("rec_p_corr(%d): %d > %d, stopping\n", p, new_err, old_err);
return;
}
/* Return if no improvent occurred.
Exception: If P goes from 1->1 it might have made up its mind on
which byte to correct. */
if(new_err == old_err && new_err != 1)
{ verbose("rec_p_corr(%d): %d == %d, no improvement\n", p, new_err, old_err);
return;
}
/* P corrected another byte;
update frame and continue with crossed Q */
frame[byte_idx] = new_byte;
(*better)++;
verbose("rec_p_corr(%d): %d < %d, continue\n", p, new_err, old_err);
recursive_q_correction(rb, frame, PToByteIndex(p, pos), p_vector[pos], better, worse);
}
static void recursive_q_correction(RawBuffer *rb, unsigned char *frame,
int byte_idx, int new_byte,
int *better, int *worse)
{ unsigned char q_vector[Q_VECTOR_SIZE];
int old_err, new_err, pos;
int q,q_idx;
ByteIndexToQ(byte_idx, &q, &q_idx);
GetQVector(frame, q_vector, q);
old_err = decode_q(rb, q_vector, &pos);
GetQVector(frame, q_vector, q);
q_vector[q_idx] = new_byte;
new_err = decode_q(rb, q_vector, &pos);
if(new_err > old_err)
{ *worse += (new_err - old_err);
verbose("rec_q_corr(%d): %d > %d, stopping\n", q, new_err, old_err);
return;
}
/* Return if no improvent occurred.
Exception: If Q goes from 1->1 it might have made up its mind on
which byte to correct. */
if(new_err == old_err && new_err != 1)
{ verbose("rec_q_corr(%d): %d == %d, no improvement\n", q, new_err, old_err);
return;
}
/* Q corrected another byte;
update frame and continue with crossed P */
frame[byte_idx] = new_byte;
(*better)++;
verbose("rec_q_corr(%d): %d < %d, continue\n", q, new_err, old_err);
recursive_p_correction(rb, frame, QToByteIndex(q, pos), q_vector[pos], better, worse);
}
/***
*** See if multiple vectors can correct a crossed vector
***
* Strategy note: If the crossed vector becomes correctable,
* e.g. it evaluates to err=1, we could try to propagate
* the one-byte correction further (and possible gain a good
* scoring). This might have the disadvantage of masking off
* another crossing correction, though
* Example: Q is crossed by 4 P vectors; if all 4 P are corrected,
* Q will evaluate to zero errors, also. That implies that applying
* all combinations of 3 P will leave Q with err=1, and the recursive
* propagation might give it a higher score than the solution with
* 4 corrected P. Therefore we might miss picking the better case
* using all 4 corrected P. So we avoid doing the recursive
* propagation here in order to max out the crossing vectors.
*/
/*
* Try to correct a q vector from crossing p vectors
*/
static void many_p_correct_one_q(sh_context *shc)
{ RawBuffer *rb = shc->rb;
int crossing_p[N_P_VECTORS];
int selection[N_P_VECTORS];
int i,p,q;
int n_p=0;
/* Determine all P vectors which cross the Q */
for(q=0; q<N_Q_VECTORS; q++)
{ int n_iterations=1;
if(shc->hitByP[q] < 2)
continue;
verbose("Q%02d is crossed by: ",q);
n_p = 0;
for(p=0; p<N_P_VECTORS; p++)
if(shc->crossedQ[p] == q)
{ crossing_p[n_p] = p;
selection[n_p] = 1;
n_p++;
n_iterations *= 2;
verbose("P%02d ", p);
}
n_iterations--; /* number of combinations to test */
verbose(" (%d combinations)\n", n_iterations);
if(n_iterations <= 0)
continue;
/* Enumerate all combinations by using <selection> as a binary counter */
verbose("Trying all combinations for Q%02d\n", q);
while(n_iterations--)
{ unsigned char scratch[MAX_RAW_TRANSFER_SIZE];
unsigned char vector[Q_VECTOR_SIZE];
int q_before, q_after, pos;
int bonus = 0;
int malus = 0;
int index = 0;
int better = 0;
int worse = 0;
for(p=n_p-1; p>=0; p--)
verbose("%d", selection[p]);
/* evaluate the vector combination */
GetQVector(rb->recovered, vector, q);
q_before = decode_q(rb, vector, &pos);
GetQVector(rb->recovered, vector, q);
for(i=0; i<n_p; i++)
{ if(selection[i])
{ p = crossing_p[i];
bonus += BONUS_SELF_CORRECT;
vector[shc->crossedQIdx[p]] = shc->pValue[p];
}
}
q_after = decode_q(rb, vector, &pos);
if(q_after <= q_before)
bonus += (q_before-q_after)*BONUS_CROSSED_CORRECT;
else malus += (q_after-q_before)*MALUS_CROSSED_DESTROY;
verbose(" Q:%d->%d; bonus: %3d malus: %3d\n",
q_before, q_after, bonus, malus);
/* If q becomes correctable, continue correction. */
if(q_after == 1)
{ unsigned char byte_before_corr;
int byte_idx;
byte_idx = QToByteIndex(q, pos);
byte_before_corr = rb->recovered[byte_idx];
/* Copy rb->recovered into scratch, including all bytes changed
in Q (there may be many, up to n_p.
However the byte which Q currently wants to correct is NOT
included in scratch so that recursive_p_correction() can
judge for itself. */
memcpy(scratch, rb->recovered, rb->sampleSize);
SetQVector(scratch, vector, q);
scratch[byte_idx] = byte_before_corr;
recursive_p_correction(rb, scratch, byte_idx, vector[pos], &better, &worse);
verbose(" recursive gain: better/worse: %d / %d\n", better, worse);
bonus += BONUS_CROSSED_CORRECT * better;
// malus -= MALUS_CROSSED_DESTROY; /* P went back from 1->0 */
malus += MALUS_CROSSED_DESTROY * worse;
}
/* Better solution found? */
bonus -= cycle_penalty(shc, scratch);
if(q_after < 2 && found_better_solution(shc, bonus, malus))
{ if(q_after != 1)
{ memcpy(shc->bestFrame, rb->recovered, rb->sampleSize);
SetQVector(shc->bestFrame, vector, q);
}
else memcpy(shc->bestFrame, scratch, rb->sampleSize);
snprintf(shc->msg, SMART_LEC_MESSAGE_SIZE,
"Q%02d improved from %d->%d by crossing P vectors (bonus %d/ malus %d).",
q,q_before, q_after, bonus, malus);
}
/* binary decrement on selection[] */
while(selection[index] != 1 && index < n_p)
{ index++;
selection[index-1] = 1;
}
if(index >= n_p) break;
selection[index]=0;
}
}
}
/*
* Try to correct a p vector from crossing q vectors
*/
static void many_q_correct_one_p(sh_context *shc)
{ RawBuffer *rb = shc->rb;
int crossing_q[N_Q_VECTORS];
int selection[N_Q_VECTORS];
int i,p,q;
int n_q=0;
/* Determine all Q vectors which cross the P */
for(p=0; p<N_P_VECTORS; p++)
{ int n_iterations=1;
if(shc->hitByQ[p] < 1)
continue;
verbose("P%02d is crossed by: ",p);
n_q = 0;
for(q=0; q<N_Q_VECTORS; q++)
if(shc->crossedP[q] == p)
{ crossing_q[n_q] = q;
selection[n_q] = 1;
n_q++;
n_iterations *= 2;
verbose("Q%02d ", q);
}
n_iterations--; /* number of combinations to test */
verbose("(%d combinations)\n", n_iterations);
if(n_iterations <= 0)
continue;
/* Enumerate all combinations by using <selection> as a binary counter */
verbose("Trying all combinations for P%02d\n", p);
while(n_iterations--)
{ unsigned char scratch[MAX_RAW_TRANSFER_SIZE];
unsigned char vector[Q_VECTOR_SIZE];
int p_before, p_after, pos;
int bonus = 0;
int malus = 0;
int index = 0;
int better = 0;
int worse = 0;
for(q=n_q-1; q>=0; q--)
verbose("%d", selection[q]);
/* evaluate the vector combination */
GetPVector(rb->recovered, vector, p);
p_before = decode_p(rb, vector, &pos);
GetPVector(rb->recovered, vector, p);
for(i=0; i<n_q; i++)
{ if(selection[i])
{ q = crossing_q[i];
bonus += BONUS_SELF_CORRECT;
vector[shc->crossedPIdx[q]] = shc->qValue[q];
}
}
p_after = decode_p(rb, vector, &pos);
if(p_after <= p_before)
bonus += (p_before-p_after)*BONUS_CROSSED_CORRECT;
else malus += (p_after-p_before)*MALUS_CROSSED_DESTROY;
verbose(" P:%d->%d; bonus: %3d malus: %3d\n",
p_before, p_after, bonus, malus);
/* If p becomes correctable, continue correction. */
if(p_after == 1)
{ unsigned char byte_before_corr;
int byte_idx;
byte_idx = PToByteIndex(p, pos);
byte_before_corr = rb->recovered[byte_idx];
/* Copy rb->recovered into scratch, including all bytes changed
in P (there may be many, up to n_q.
However the byte which P currently wants to correct is NOT
included in scratch so that recursive_q_correction() can
judge for itself. */
memcpy(scratch, rb->recovered, rb->sampleSize);
SetPVector(scratch, vector, p);
scratch[byte_idx] = byte_before_corr;
recursive_q_correction(rb, scratch, byte_idx, vector[pos], &better, &worse);
verbose(" recursive gain: better/worse: %d / %d\n", better, worse);
bonus += BONUS_CROSSED_CORRECT * better;
// malus -= MALUS_CROSSED_DESTROY; /* P went back from 1->0 */
malus += MALUS_CROSSED_DESTROY * worse;
}
/* Better solution found? */
bonus -= cycle_penalty(shc, scratch);
if(p_after < 2 && found_better_solution(shc, bonus, malus))
{ if(p_after != 1)
{ memcpy(shc->bestFrame, rb->recovered, rb->sampleSize);
SetPVector(shc->bestFrame, vector, p);
}
else memcpy(shc->bestFrame, scratch, rb->sampleSize);
snprintf(shc->msg, SMART_LEC_MESSAGE_SIZE,
"P%02d improved from %d->%d by crossing Q vectors (bonus %d/ malus %d).",
p,p_before, p_after, bonus, malus);
}
verbose("%d\n", rb->sampleSize);
/* binary decrement on selection[] */
while(selection[index] != 1 && index < n_q)
{ selection[index] = 1;
index++;
}
selection[index]=0;
}
}
}
/***
*** See if replacing a vector with another accepting version improves anything
***/
static void evaluate_new_frame(sh_context *shc, unsigned char *new,
int *better, int *worse)
{ RawBuffer *rb = shc->rb;
unsigned char vector[Q_VECTOR_SIZE];
int p,q;
int err, pos;
for(p=0; p<N_P_VECTORS; p++)
{ GetPVector(new, vector, p);
err = decode_p(rb, vector, &pos);
if(err > shc->pState[p]) *worse += err - shc->pState[p];
else *better += shc->pState[p] - err;
}
for(q=0; q<N_Q_VECTORS; q++)
{ GetQVector(new, vector, q);
err = decode_q(rb, vector, &pos);
if(err > shc->qState[q]) *worse += err - shc->qState[q];
else *better += shc->qState[q] - err;
}
}
static void try_alternative_vectors(sh_context *shc)
{ RawBuffer *rb = shc->rb;
unsigned char scratch[MAX_RAW_TRANSFER_SIZE];
int better, worse;
int i,p,q;
for(p=0; p<N_P_VECTORS; p++)
{ if(shc->pState[p] == 0)
continue;
for(i=0; i<rb->pn[p]; i++)
{ int bonus;
int malus;
memcpy(scratch, rb->recovered, rb->sampleSize);
SetPVector(scratch, rb->pList[p][i], p);
better = -shc->pState[p]; /* We replaced damaged P with an accepting P */
worse = 0;
evaluate_new_frame(shc, scratch, &better, &worse);
bonus = BONUS_SWAPPED_WITH_BETTER_VECTOR*2
+ BONUS_SWAP_IMPROVED_CROSSING*better;
malus = MALUS_SWAP_DESTROYED_CROSSING*worse;
bonus -= cycle_penalty(shc, scratch);
verbose("Trying P%02d, variant %d: %d better, %d worse (%d/%d)\n",
p, i, better, worse, bonus, malus);
/* This is maybe too restrictive? */
if(malus > 0)
continue;
if(found_better_solution(shc, bonus, malus))
{ memcpy(shc->bestFrame, scratch, rb->sampleSize);
snprintf(shc->msg, SMART_LEC_MESSAGE_SIZE,
"Found alternative vector for P%02d (bonus %d/ malus %d).",
p, bonus, malus);
}
}
}
for(q=0; q<N_Q_VECTORS; q++)
{ if(shc->qState[q] == 0)
continue;
for(i=0; i<rb->qn[q]; i++)
{ int bonus;
int malus;
memcpy(scratch, rb->recovered, rb->sampleSize);
SetQVector(scratch, rb->qList[q][i], q);
better = -shc->qState[q]; /* We replaced damaged Q with an accepting Q */
worse = 0;
evaluate_new_frame(shc, scratch, &better, &worse);
bonus = BONUS_SWAPPED_WITH_BETTER_VECTOR*2
+ BONUS_SWAP_IMPROVED_CROSSING*better;
malus = MALUS_SWAP_DESTROYED_CROSSING*worse;
bonus -= cycle_penalty(shc, scratch);
verbose("Trying Q%02d, variant %d: %d better, %d worse (%d/%d)\n",
q, i, better, worse, bonus, malus);
/* This is maybe too restrictive? */
if(malus > 0)
continue;
if(found_better_solution(shc, bonus, malus))
{ memcpy(shc->bestFrame, scratch, rb->sampleSize);
snprintf(shc->msg, SMART_LEC_MESSAGE_SIZE,
"Found alternative vector for Q%02d (bonus %d/ malus %d).",
q, bonus, malus);
}
}
}
}
/***
*** See if swapping some bytes from alternative vectors improves something
***/
static void try_alternative_crossing_bytes(sh_context *shc)
{ RawBuffer *rb = shc->rb;
unsigned char scratch[MAX_RAW_TRANSFER_SIZE];
int better, worse;
int i,j,p,q;
for(p=0; p<N_P_VECTORS; p++)
{ unsigned char current_p[P_VECTOR_SIZE];
if(shc->pState[p] == 0)
continue;
GetPVector(rb->recovered, current_p, p);
for(i=0; i<rb->pn[p]; i++)
{ unsigned char *alternative_p = rb->pList[p][i];
/* If the alternative vector differs in byte j,
see if swapping the current byte with byte j improves
the crossed vector. */
for(j=0; j<P_VECTOR_SIZE; j++)
{ if(current_p[j] != alternative_p[j])
{ int byte_idx, crossed, crossed_idx;
byte_idx = PToByteIndex(p, j);
ByteIndexToQ(byte_idx, &crossed, &crossed_idx);
if(shc->qState[crossed] > 0)
{ better = worse = 0;
memcpy(scratch, rb->recovered, rb->sampleSize);
recursive_q_correction(rb, scratch, byte_idx, alternative_p[j],
&better, &worse);
if(better > 0)
{ int bonus, malus;
verbose("Q%02d improved by swapping %d in P%02d, %d/%d\n",
crossed, j, p, better, worse);
bonus = better*BONUS_CROSSED_CORRECT
- cycle_penalty(shc, scratch);
malus = worse*MALUS_CROSSED_DESTROY;
if(found_better_solution(shc, bonus, malus))
{ memcpy(shc->bestFrame, scratch, rb->sampleSize);
snprintf(shc->msg, SMART_LEC_MESSAGE_SIZE,
"Q%02d improved by swapping %d in P%02d, %d/%d (bonus %d/ malus %d).",
crossed, j, p, better, worse, bonus, malus);
}
}
}
}
}
}
}
for(q=0; q<N_Q_VECTORS; q++)
{ unsigned char current_q[Q_VECTOR_SIZE];
if(shc->qState[q] == 0)
continue;
GetQVector(rb->recovered, current_q, q);
for(i=0; i<rb->qn[q]; i++)
{ unsigned char *alternative_q = rb->qList[q][i];
/* If the alternative vector differs in byte j,
see if swapping the current byte with byte j improves
the crossed vector. */
for(j=0; j<Q_VECTOR_SIZE; j++)
{ if(current_q[j] != alternative_q[j])
{ int byte_idx, crossed, crossed_idx;
byte_idx = QToByteIndex(q, j);
ByteIndexToP(byte_idx, &crossed, &crossed_idx);
if(shc->pState[crossed] > 0)
{ better = worse = 0;
memcpy(scratch, rb->recovered, rb->sampleSize);
recursive_p_correction(rb, scratch, byte_idx, alternative_q[j],
&better, &worse);
if(better > 0)
{ int bonus, malus;
verbose("P%02d improved by swapping %d in Q%02d, %d/%d\n",
crossed, j, q, better, worse);
bonus = better*BONUS_CROSSED_CORRECT
- cycle_penalty(shc, scratch);
malus = worse*MALUS_CROSSED_DESTROY;
if(found_better_solution(shc, bonus, malus))
{ memcpy(shc->bestFrame, scratch, rb->sampleSize);
snprintf(shc->msg, SMART_LEC_MESSAGE_SIZE,
"P%02d improved by swapping %d in Q%02d, %d/%d (bonus %d/ malus %d).",
crossed, j, q, better, worse, bonus, malus);
}
}
}
}
}
}
}
}
/***
*** See if a p can improve two crossing q vectors
***/
static void recursive_double_q_correction(RawBuffer*, unsigned char*,
int, int, int, int, int*, int*);
static void recursive_double_p_correction(RawBuffer *rb, unsigned char *frame,
int byte_idx1, int new_byte1,
int byte_idx2, int new_byte2,
int *better, int *worse)
{ unsigned char p_vector1[P_VECTOR_SIZE];
unsigned char p_vector2[P_VECTOR_SIZE];
int old_err1, new_err1, pos1;
int old_err2, new_err2, pos2;
int p1,p1_idx,p2,p2_idx;
ByteIndexToP(byte_idx1, &p1, &p1_idx);
GetPVector(frame, p_vector1, p1);
old_err1 = decode_p(rb, p_vector1, &pos1);
GetPVector(frame, p_vector1, p1);
p_vector1[p1_idx] = new_byte1;
new_err1 = decode_p(rb, p_vector1, &pos1);
ByteIndexToP(byte_idx2, &p2, &p2_idx);
GetPVector(frame, p_vector2, p2);
old_err2 = decode_p(rb, p_vector2, &pos2);
if(p1 != p2)
{ GetPVector(frame, p_vector2, p2);
p_vector2[p2_idx] = new_byte2;
new_err2 = decode_p(rb, p_vector2, &pos2);
}
else new_err2 = old_err2 = new_err1;
verbose("rec 2p: old %d %d, new %d %d - %d %d\n",
old_err1, old_err2, new_err1, new_err2, p1, p2);
/* Best case: both P improved */
if(new_err1 < old_err1 && new_err2 < old_err2)
{ frame[byte_idx1] = new_byte1;
frame[byte_idx2] = new_byte2;
(*better) +=(old_err1-new_err1)+(old_err2-new_err2);
recursive_double_q_correction(rb, frame,
PToByteIndex(p1, pos1), p_vector1[pos1],
PToByteIndex(p2, pos2), p_vector2[pos2],
better, worse);
return;
}
/* Nothing improved at all */
if(new_err1 >= old_err1 && new_err2 >= old_err2)
{ (*worse)+=(new_err1-old_err1)+(new_err2-old_err2);
return;
}
/* One P improved */
if(new_err1 < old_err1) /* first P improved */
{ (*better) += old_err1 - new_err1;
(*worse) += new_err2 - old_err2;
frame[byte_idx1] = new_byte1;
recursive_q_correction(rb, frame, PToByteIndex(p1, pos1), p_vector1[pos1],
better, worse);
return;
}
else /* second P improved */
{ (*better) += old_err2 - new_err2;
(*worse) += new_err1 - old_err1;
frame[byte_idx2] = new_byte2;
recursive_q_correction(rb, frame, PToByteIndex(p2, pos2), p_vector2[pos2],
better, worse);
return;
}
}
static void recursive_double_q_correction(RawBuffer *rb, unsigned char *frame,
int byte_idx1, int new_byte1,
int byte_idx2, int new_byte2,
int *better, int *worse)
{ unsigned char q_vector1[Q_VECTOR_SIZE];
unsigned char q_vector2[Q_VECTOR_SIZE];
int old_err1, new_err1, pos1;
int old_err2, new_err2, pos2;
int q1,q1_idx,q2,q2_idx;
ByteIndexToQ(byte_idx1, &q1, &q1_idx);
GetQVector(frame, q_vector1, q1);
old_err1 = decode_q(rb, q_vector1, &pos1);
GetQVector(frame, q_vector1, q1);
q_vector1[q1_idx] = new_byte1;
new_err1 = decode_q(rb, q_vector1, &pos1);
ByteIndexToQ(byte_idx2, &q2, &q2_idx);
GetQVector(frame, q_vector2, q2);
old_err2 = decode_q(rb, q_vector2, &pos2);
if(q1 != q2)
{ GetQVector(frame, q_vector2, q2);
q_vector2[q2_idx] = new_byte2;
new_err2 = decode_q(rb, q_vector2, &pos2);
}
else new_err2 = old_err2 = new_err1;
verbose("rec 2q: old %d %d, new %d %d - %d %d\n",
old_err1, old_err2, new_err1, new_err2, q1, q2);
/* Best case: both Q improved */
if(new_err1 < old_err1 && new_err2 < old_err2)
{ frame[byte_idx1] = new_byte1;
frame[byte_idx2] = new_byte2;
(*better) +=(old_err1-new_err1)+(old_err2-new_err2);
recursive_double_p_correction(rb, frame,
QToByteIndex(q1, pos1), q_vector1[pos1],
QToByteIndex(q2, pos2), q_vector2[pos2],
better, worse);
return;
}
/* Nothing improved at all */
if(new_err1 >= old_err1 && new_err2 >= old_err2)
{ (*worse)+=(new_err1-old_err1)+(new_err2-old_err2);
return;
}
/* One Q improved */
if(new_err1 < old_err1) /* first Q improved */
{ (*better) += old_err1 - new_err1;
(*worse) += new_err2 - old_err2;
frame[byte_idx1] = new_byte1;
recursive_p_correction(rb, frame, QToByteIndex(q1, pos1), q_vector1[pos1],
better, worse);
return;
}
else /* second Q improved */
{ (*better) += old_err2 - new_err2;
(*worse) += new_err1 - old_err1;
frame[byte_idx2] = new_byte2;
recursive_p_correction(rb, frame, QToByteIndex(q2, pos2), q_vector2[pos2],
better, worse);
return;
}
}
static void find_p_with_two_erasures(sh_context *shc)
{ RawBuffer *rb = shc->rb;
int erasure_pos[P_VECTOR_SIZE];
int crossed_q[P_VECTOR_SIZE];
int crossed_q_idx[P_VECTOR_SIZE];
int n_q = 0;
int p,q,i;
int e1, e2;
for(p=0; p<=N_P_VECTORS; p++)
{ if(shc->pState[p] != 2)
continue;
for(i=0; i<P_VECTOR_SIZE; i++)
{ int q_idx;
ByteIndexToQ(PToByteIndex(p, i), &q, &q_idx);
if(shc->qState[q] > 0)
{ erasure_pos[n_q] = i;
crossed_q[n_q] = q;
crossed_q_idx[n_q] = q_idx;
n_q++;
}
}
if(n_q < 2) continue;
if(n_q > 7) return; /* too much damage */
/* Enumerate all erasure combinations */
for(e1=0; e1<n_q-1; e1++)
for(e2=e1+1; e2<n_q; e2++)
{ unsigned char p_vector[P_VECTOR_SIZE];
unsigned char scratch[MAX_RAW_TRANSFER_SIZE];
int better, worse;
int eras[2], err;
GetPVector(rb->recovered, p_vector, p);
eras[0] = erasure_pos[e1];
eras[1] = erasure_pos[e2];
err = DecodePQ(rb->rt, p_vector, P_PADDING, eras, 2);
if(err != 2) continue;
better = worse = 0;
memcpy(scratch, rb->recovered, rb->sampleSize);
recursive_double_q_correction(rb, scratch,
QToByteIndex(crossed_q[e1],crossed_q_idx[e1]), p_vector[erasure_pos[e1]],
QToByteIndex(crossed_q[e2],crossed_q_idx[e2]), p_vector[erasure_pos[e2]],
&better, &worse);
if(better > 0)
{ int bonus, malus;
verbose("P%02d with erasure pos %02d/%02d: %d better, %d worse\n",
p,erasure_pos[e1],erasure_pos[e2],better,worse);
bonus = better*BONUS_CROSSED_CORRECT
- cycle_penalty(shc, scratch);
malus = worse*MALUS_CROSSED_DESTROY;
if(found_better_solution(shc, bonus, malus))
{ memcpy(shc->bestFrame, scratch, rb->sampleSize);
snprintf(shc->msg, SMART_LEC_MESSAGE_SIZE,
"P%02d with erasures %02d/%02d: %d better, %d worse (bonus %d/ malus %d).",
p,erasure_pos[e1],erasure_pos[e2],better,worse,bonus,malus);
}
}
}
}
}
/***
*** Swap P with an alternative vector,
*** then selectively correct the crossing vectors
* to see if a new combination arises which makes P
* correct a new vector.
*/
static void swap_p_for_new_improvement(sh_context *shc)
{ RawBuffer *rb = shc->rb;
unsigned char old_vector[Q_VECTOR_SIZE];
unsigned char new_vector[Q_VECTOR_SIZE];
unsigned char p_vector[P_VECTOR_SIZE];
unsigned char q_vector[Q_VECTOR_SIZE];
unsigned char scratch[MAX_RAW_TRANSFER_SIZE];
int err_pos;
int p,q;
for(p=0; p<N_P_VECTORS; p++)
//for(p=45; p<46; p++)
{ int crossed, crossed_idx;
int i,j;
if(shc->pState[p] == 0)
continue;
GetPVector(rb->recovered, old_vector, p);
for(i=0; i<rb->pn[p]; i++) /* try all alternative p vectors */
{ int selection[N_Q_VECTORS];
int crossing_q[N_Q_VECTORS];
int crossing_err[N_Q_VECTORS];
int err;
int n_q = 0;
int n_iterations = 1;
verbose("swap p for new improvement: alternative %d for P%02d\n",i, p);
memcpy(scratch, rb->recovered, rb->sampleSize);
SetPVector(scratch, rb->pList[p][i], p);
memcpy(new_vector, rb->pList[p][i], P_VECTOR_SIZE);
for(j=0; j<P_VECTOR_SIZE; j++)
{ if(old_vector[j] != new_vector[j])
{
ByteIndexToQ(PToByteIndex(p, j), &crossed, &crossed_idx);
GetQVector(scratch, q_vector, crossed);
err = decode_q(rb, q_vector, &err_pos);
verbose("diff at %2d: Q%2d from %d->%d\n",
j, crossed, shc->qState[crossed], err);
crossing_q[n_q] = crossed;
crossing_err[n_q] = err;
selection[n_q] = 1;
n_q++;
n_iterations *= 2;
}
}
if(n_q < 2) /* We need at least 2 crossing vectors */
continue;
n_iterations--; /* number of combinations to test */
/* Enumerate all combinations by using <selection> as a binary counter */
verbose("Trying all combinations for P%02d\n", p);
while(n_iterations--)
{ int index = 0;
int count = 0;
int bonus = 0;
int malus = 0;
for(q=n_q-1; q>=0; q--)
verbose("%d", selection[q]);
/* Count number of changed crossed vectors.
Less than 2 do not produce an interesting new P vector. */
for(j=0; j<n_q; j++)
if(selection[j])
count++;
if(count < 2)
{ verbose("%s", " pruned");
goto decrement;
}
/* See if we get an interesting P vector from
correcting some of the crossing Qs */
memcpy(scratch, rb->recovered, rb->sampleSize);
SetPVector(scratch, new_vector, p);
for(j=0; j<n_q; j++)
{ if(!selection[j])
{ malus += crossing_err[j] * SWAPPED_WITH_IMPROVEMENT_MALUS;
continue;
}
GetQVector(scratch, q_vector, crossing_q[j]);
err = decode_q(rb, q_vector, &err_pos);
if(err == 1) SetQVector(scratch, q_vector, crossing_q[j]);
}
GetPVector(scratch, p_vector, p);
err = decode_p(rb, p_vector, &err_pos);
verbose(" %3d", err);
if(err==1)
{ int crossed_q;
int prev_state, new_state;
ByteIndexToQ(PToByteIndex(p, err_pos), &crossed_q, &crossed_idx);
verbose(", affecting Q %d:", crossed_q);
GetQVector(scratch, q_vector, crossed_q);
prev_state = decode_q(rb, q_vector, &err_pos);
SetPVector(scratch, p_vector, p);
GetQVector(scratch, q_vector, crossed_q);
new_state = decode_q(rb, q_vector, &err_pos);
verbose("%d -> %d", prev_state, new_state);
/* Better solution found? */
if(prev_state > new_state)
{ bonus = SWAPPED_WITH_IMPROVEMENT_BONUS - cycle_penalty(shc, scratch);
if(found_better_solution(shc, bonus, malus))
{ memcpy(shc->bestFrame, scratch, rb->sampleSize);
snprintf(shc->msg, SMART_LEC_MESSAGE_SIZE,
"P%02d swapped; Q%02d improved (%d/%d)",p,crossed_q,bonus,malus);
}
}
}
/* binary decrement on selection[] */
decrement:
while(selection[index] != 1 && index < n_q)
{ index++;
selection[index-1] = 1;
}
if(index >= n_q) break;
selection[index]=0;
verbose("%s", "\n");
}
}
}
}
/***
*** Try to get out of a local maximum.
***
* See if swapping a byte in P produces a Q which can be changed
* by another crossing P. At worst, we get rid of the crossing P
* and the changed Q might correct something else in a later stage.
*/
static void try_indirect_improvement(sh_context *shc)
{ RawBuffer *rb = shc->rb;
unsigned char scratch[MAX_RAW_TRANSFER_SIZE];
unsigned char vector[Q_VECTOR_SIZE];
int i,j,p,q;
/* Find uncorrected P vectors */
for(p=0; p<N_P_VECTORS; p++)
{ unsigned char current_p[P_VECTOR_SIZE];
if(shc->pState[p] == 0)
continue; /* already good */
GetPVector(rb->recovered, current_p, p);
for(i=0; i<rb->pn[p]; i++)
{ unsigned char *alternative_p = rb->pList[p][i];
/* If the alternative vector differs in byte j,
see what happens with the Q crossing byte j. */
for(j=0; j<P_VECTOR_SIZE; j++)
{ if(current_p[j] != alternative_p[j])
{ unsigned char crossed_q[Q_VECTOR_SIZE];
int byte_idx, crossed_idx, ignore, err;
int bonus=0, malus=0;
/* Determine crossed Q and modify it */
byte_idx = PToByteIndex(p, j);
ByteIndexToQ(byte_idx, &q, &crossed_idx);
GetQVector(rb->recovered, crossed_q, q);
crossed_q[crossed_idx] = alternative_p[j];
/* Calculated state of modified Q.
We want a Q which either improves or stays within the
correctable state (maybe it corrects the right byte now) */
memcpy(vector, crossed_q, Q_VECTOR_SIZE);
err = decode_q(rb, vector, &ignore);
if(err == 1)
{ int p2,p2_index,k;
verbose("indirect for P%02d: interesting Q%02d %d->%d\n", p, q, shc->qState[q], err);
/* Now see if we can find another crossing P which makes Q go from
1->1 or 0 */
memcpy(scratch, rb->recovered, rb->sampleSize);
scratch[byte_idx] = alternative_p[j];
for(k=0; k<Q_VECTOR_SIZE; k++)
{ unsigned char p_vector[P_VECTOR_SIZE];
byte_idx = QToByteIndex(q,k);
ByteIndexToP(byte_idx, &p2, &p2_index);
if( (p2 == p)
|| (shc->pState[p2] != 1)
|| (shc->pPosition[p2] != p2_index))
continue; /* trivially reject; crossing P won't change Q */
/* Crossed P changed something in Q. Re-evaluate Q. */
memcpy(vector, crossed_q, Q_VECTOR_SIZE);
vector[k] = shc->pValue[p2];
err = decode_q(rb, vector, &ignore);
if(err>1) /* Q got uncorrectable */
continue;
scratch[byte_idx] = shc->pValue[p2];
/* Add bonus for improved Q (err of Q was 1 before) */
if(!err) bonus += INDIRECT_IMPROVEMENT_BONUS_FOR_Q;
/* Set score for the outer P */
memcpy(p_vector, current_p, P_VECTOR_SIZE);
current_p[j] = alternative_p[j];
err = decode_p(rb, p_vector, &ignore);
if(err < shc->pState[p]) bonus += INDIRECT_IMPROVEMENT_BONUS_FOR_P;
if(err > shc->pState[p]) malus += INDIRECT_IMPROVEMENT_MALUS_FOR_P;
/* Add some for the inner P which changed from 1->0 */
bonus += INDIRECT_IMPROVEMENT_BONUS_FOR_P;
verbose("crossed P%02d does something (%d/%d)\n", p2,bonus,malus);
if(found_better_solution(shc, bonus, malus))
{ memcpy(shc->bestFrame, scratch, rb->sampleSize);
snprintf(shc->msg, SMART_LEC_MESSAGE_SIZE,
"Q%02d improved indirectly by P%02d, P%02d (%d/%d)",q,p,p2,bonus,malus);
}
}
}
}
}
}
}
}
/***
*** Try all bytes at positions where uncorrectable p/q overlap
***/
#if 0
static void guess_crossing_byte(sh_context *shc)
{ RawBuffer *rb = shc->rb;
int p,q,i,j,g;
for(p=0; p<N_P_VECTORS; p++)
{ int crossed_idx;
if(shc->pState[p] != 2)
continue;
for(i=0; i<P_VECTOR_SIZE; i++)
{ ByteIndexToQ(PToByteIndex(p, i), &q, &crossed_idx);
if(shc->qState[q] != 2)
continue;
verbose("Guess candidate P%02d.%02d / Q%02d.%02d\n", p,i,q,crossed_idx);
for(g=0; g<256; g++)
{ unsigned char p_vector[P_VECTOR_SIZE];
unsigned char q_vector[Q_VECTOR_SIZE];
int ignore;
int idx = PToByteIndex(p, i);
for(j=0; j<rb->samplesRead; j++)
if(rb->rawBuf[j][idx] == g)
break;
if(j>=256) continue;
GetPVector(rb->recovered, p_vector, p);
p_vector[i] = g;
if(decode_p(rb, p_vector, &ignore) == 1)
{ GetQVector(rb->recovered, q_vector, q);
q_vector[crossed_idx] = g;
if(decode_q(rb, q_vector, &ignore) == 1)
verbose("... guess %d solves P and Q\n", g);
}
}
}
}
}
#endif
/***
*** The smart lec wrapper.
***/
static void pick_best_frame(sh_context *shc, char *message)
{ RawBuffer *rb = shc->rb;
printf("Best P: %d/%d, %d/%d\n", rb->bestP2, rb->bestP1, rb->bestQ2, rb->bestQ1);
memcpy(rb->recovered, rb->rawBuf[rb->bestFrame], rb->sampleSize);
if(message)
snprintf(message, SMART_LEC_MESSAGE_SIZE,
"selected best sector frame %d with %d/%d, %d/%d defective P/Q vectors.",
rb->bestFrame, rb->bestP2, rb->bestP1, rb->bestQ2, rb->bestQ1);
}
static int smart_lec_iteration(sh_context *shc, char *message)
{ RawBuffer *rb = shc->rb;
shc->bestBonus = 0;
shc->bestMalus = 100000;
memcpy(shc->bestFrame, rb->recovered, rb->sampleSize);
sprintf(shc->msg, "smart_lec: no further improvement");
update_pq_state(shc);
print_pq_state(shc);
many_p_correct_one_q(shc);
many_q_correct_one_p(shc);
#ifndef LOCAL_ONLY
try_alternative_vectors(shc);
try_alternative_crossing_bytes(shc);
#endif
find_p_with_two_erasures(shc);
swap_p_for_new_improvement(shc);
try_indirect_improvement(shc);
if(frame_visited(shc, shc->bestFrame))
printf("pruning!\n");
memcpy(rb->recovered, shc->bestFrame, rb->sampleSize);
push_frame(shc, shc->bestFrame);
if(message)
memcpy(message, shc->msg, SMART_LEC_MESSAGE_SIZE);
return TRUE;
}
int SmartLEC(RawBuffer *rb)
{ sh_context *shc = create_sh_context(rb);
unsigned char prev_state[rb->sampleSize];
pick_best_frame(shc, NULL);
#ifdef PRINT_STEPS
printf("%s\n", shc->msg);
#endif
CreateMissingSector(prev_state, rb->lba, NULL, 0,
"SmartLEC() dummy sector");
while(TRUE)
{ smart_lec_iteration(shc, NULL);
#ifdef PRINT_STEPS
printf("%s\n", shc->msg);
#endif
if(frame_corrected(shc->rb))
{ free_sh_context(shc);
return TRUE;
}
if(!memcmp(prev_state, rb->recovered, rb->sampleSize))
{ free_sh_context(shc);
return FALSE;
}
memcpy(prev_state, rb->recovered, rb->sampleSize);
}
free_sh_context(shc);
return FALSE;
}
/*
* Special actions for iteratively running the smart lec
* from the raw editor
*/
void *PrepareIterativeSmartLEC(RawBuffer *rb)
{ sh_context *shc = create_sh_context(rb);
shc->iteration = ITERATION_PICK_BEST_SECTOR;
return shc;
}
void SmartLECIteration(void *shc_handle, char *message)
{ sh_context *shc = (sh_context*)shc_handle;
switch(shc->iteration)
{ case ITERATION_PICK_BEST_SECTOR:
#ifndef LOCAL_ONLY
pick_best_frame(shc, message);
#endif
shc->iteration++;
break;
default:
smart_lec_iteration(shc, message);
break;
}
#ifdef PRINT_STEPS
printf("%s\n", shc->msg);
#endif
}
void EndIterativeSmartLEC(void *shc)
{ free_sh_context((sh_context*)shc);
}