Files
cuetools.net/CUETools.Ripper.SCSI/RsDecode.cs

276 lines
12 KiB
C#
Raw Normal View History

2008-12-03 21:42:22 +00:00
<EFBFBD><EFBFBD>using System;
using System.Collections.Generic;
using System.Text;
namespace CUETools.Ripper.SCSI
{
/**
* <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0: RS<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
*
* @author Masayuki Miyazaki
* http://sourceforge.jp/projects/reedsolomon/
*/
public class RsDecode
{
public const int RS_CORRECT_ERROR = -2;
private static Galois galois = Galois.instance;
private int npar;
public RsDecode(int npar)
{
this.npar = npar;
}
/**
* Modified Berlekamp-Massey
*
* @param sigma int[]
* <EFBFBD>(z)<h }(uM<EFBFBD>R0g'Ynpar/2 + 2 Pn0<EFBFBD><EFBFBD>WL0<EFBFBD>_<EFBFBD><EFBFBD>
* <EFBFBD>0,<EFBFBD>1,<EFBFBD>2, ... <EFBFBD><jisu>
* @param omega int[]
* <EFBFBD>(z)<h }(uM<EFBFBD>R0g'Ynpar/2 + 1 Pn0<EFBFBD><EFBFBD>WL0<EFBFBD>_<EFBFBD><EFBFBD>
* <EFBFBD>0,<EFBFBD>1,<EFBFBD>2, ... <EFBFBD><jisu-1>
* @param syn int[]
* <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0M<EFBFBD>R
* s0,s1,s2, ... s<npar-1>
* @return int
* >= 0: <EFBFBD>n0!kpe
* < 0: <EFBFBD>0<EFBFBD>0<EFBFBD>0
*/
public int calcSigmaMBM(int[] sigma, int[] omega, int[] syn)
{
int[] sg0 = new int[npar];
int[] sg1 = new int[npar];
sg0[1] = 1;
sg1[0] = 1;
int jisu0 = 1;
int jisu1 = 0;
int m = -1;
for (int n = 0; n < npar; n++)
{
// $R%R_<EFBFBD>0<EFBFBD><EFBFBD>{
int d = syn[n];
for (int i = 1; i <= jisu1; i++)
{
d ^= galois.mul(sg1[i], syn[n - i]);
}
if (d != 0)
{
int logd = galois.toLog(d);
int[] wk = new int[npar];
for (int i = 0; i <= n; i++)
{
wk[i] = sg1[i] ^ galois.mulExp(sg0[i], logd);
}
int js = n - m;
if (js > jisu1)
{
m = n - jisu1;
jisu1 = js;
if (jisu1 > npar / 2)
{
return -1; // <EFBFBD>n0!kpeL0npar / 2<EFBFBD>0<EFBFBD><EFBFBD>H0_0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
}
for (int i = 0; i <= jisu0; i++)
{
sg0[i] = galois.divExp(sg1[i], logd);
}
jisu0 = jisu1;
}
sg1 = wk;
}
Array.Copy(sg0, 0, sg0, 1, Math.Min(sg0.Length - 1, jisu0));
sg0[0] = 0;
jisu0++;
}
galois.mulPoly(omega, sg1, syn);
Array.Copy(sg1, 0, sigma, 0, Math.Min(sg1.Length, sigma.Length));
return jisu1;
}
/**
* gB}<EFBFBD>0<EFBFBD>0<EFBFBD>0MOnn0<EFBFBD>0<EFBFBD>0<EFBFBD>0
* @param pos
* <EFBFBD><EFBFBD><EFBFBD>0MOn<h }(uRR
* @param n
* <EFBFBD>0<EFBFBD>0<EFBFBD>0w<EFBFBD>
* @param last
* <EFBFBD>0<EFBFBD>0<EFBFBD>0MOn
* @return
* 0: ck8^B}<EFBFBD>N
* < 0: <EFBFBD>0<EFBFBD>0<EFBFBD>0
*/
private bool setLastErrorPos(int[] pos, int n, int last)
{
if (galois.toLog(last) >= n)
return false; // <EFBFBD>{<EFBFBD>VYj0n0g0<EFBFBD>0<EFBFBD>0<EFBFBD>0
pos[0] = last;
return true;
}
/**
* <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>c"}k0<6B>0<EFBFBD>0<EFBFBD><30><EFBFBD>0MOn<6E>0Bl<42>0<EFBFBD>0
* <EFBFBD>(z) = 0n00<EFBFBD>c"}Y0<59>0
* _0`0W00<EFBFBD>c"}o0<6F>0<EFBFBD>0<EFBFBD>0w<30><77>N<EFBFBD>Qn0<6E><30>n00g0
* jisu Pn0<EFBFBD><EFBFBD>L0<EFBFBD><EFBFBD>d0K0<EFBFBD>0j0Q0<EFBFBD>0p00<EFBFBD>0<EFBFBD>0<EFBFBD>0h0Y0<EFBFBD>0
* @param pos int[]
* <EFBFBD><EFBFBD><EFBFBD>0MOn<h }(uM<EFBFBD>R0jisu Pn0<EFBFBD><EFBFBD>WL0<EFBFBD>_<EFBFBD><EFBFBD>
* @param n int
* <EFBFBD>0<EFBFBD>0<EFBFBD>0w<EFBFBD>
* @param jisu int
* <EFBFBD>n0!kpe
* @param sigma int[]
* <EFBFBD>0,<EFBFBD>1,<EFBFBD>2, ... <EFBFBD><jisu>
* @return int
* 0: ck8^B}<EFBFBD>N
* < 0: <EFBFBD>0<EFBFBD>0<EFBFBD>0
*/
private bool chienSearch(int[] pos, int n, int jisu, int[] sigma)
{
/*
* <EFBFBD>(z) = (1-<EFBFBD>^i*z)(1-<EFBFBD>^j*z)(1-<EFBFBD>^k*z)
* = 1 + <EFBFBD>1z + <EFBFBD>2z^2 +...
* <EFBFBD>1 = <EFBFBD>^i + <EFBFBD>^j + <EFBFBD>^k
* d0~0<EFBFBD>0<EFBFBD>1o0hQf0n0<EFBFBD><EFBFBD>n0T<EFBFBD>h0j0c0f0D0<EFBFBD>00
N<EFBFBD>n0'`0)R(uW0f00<EFBFBD>0<EFBFBD>0gi<EFBFBD>S
* last = <EFBFBD>1K0<EFBFBD>00<EFBFBD><EFBFBD>d0Q0_00!k0h0_D0f0D0O0S0h0k0<EFBFBD>0<EFBFBD>00g<EFBFBD>_n0<EFBFBD><EFBFBD>o0lasth0j0<EFBFBD>0
*/
int last = sigma[1];
if (jisu == 1)
{
// !kpeL01j0<EFBFBD>0p0lastL0]0n0<EFBFBD><EFBFBD>g0B0<EFBFBD>0
return setLastErrorPos(pos, n, last);
}
int posIdx = jisu - 1; // <EFBFBD><EFBFBD><EFBFBD>0MOn<h }(u<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
for (int i = 0; i < n; i++)
{
/*
* <EFBFBD>(z)n0<EFBFBD><EFBFBD>{
* w <EFBFBD>01(0WNn0<EFBFBD>)k0RgSW0_0<EFBFBD>_0<EFBFBD>k<EFBFBD>0n0<EFBFBD><1..jisu><EFBFBD>0<EFBFBD>R<EFBFBD>{
* z = 1/<EFBFBD>^i = <EFBFBD>^Ih0Y0<EFBFBD>0h0
* <EFBFBD>(z) = 1 + <EFBFBD>1<EFBFBD>^I + <EFBFBD>2(<EFBFBD>^I)^2 + <EFBFBD>3(<EFBFBD>^I)^3 + ... + <EFBFBD><jisu>/(<EFBFBD>^I)^<jisu>
* = 1 + <EFBFBD>1<EFBFBD>^I + <EFBFBD>2<EFBFBD>^(I*2) + <EFBFBD>3<EFBFBD>^(I*3) + ... + <EFBFBD><jisu><EFBFBD>^(I*<jisu>)
*/
int z = 255 - i; // z = 1/<EFBFBD>^in0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
int wk = 1;
for (int j = 1; j <= jisu; j++)
{
wk ^= galois.mulExp(sigma[j], (z * j) % 255);
}
if (wk == 0)
{
int pv = galois.toExp(i); // <EFBFBD>(z) = 0n0<EFBFBD><EFBFBD>
last ^= pv; // lastK0<EFBFBD>0<EFBFBD>N<EFBFBD><EFBFBD>d0K0c0_00_O0
pos[posIdx--] = pv;
if (posIdx == 0)
{
// <EFBFBD>k<EFBFBD>0L0Nd0j0<EFBFBD>0p00lastL0]0n0<EFBFBD><EFBFBD>g0B0<EFBFBD>0
return setLastErrorPos(pos, n, last);
}
}
}
// <EFBFBD>c"}k0<6B>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0w<30><77>N<EFBFBD>Qk00jisu Pn0<6E><30>L0<4C><30>d0K0<4B>0j0K0c0_0
return false;
}
/**
* Forney<EFBFBD>lg0<EFBFBD><EFBFBD><EFBFBD>0<EFBFBD>ck<EFBFBD>0L<EFBFBD>F0
* <EFBFBD>(z) = (1-<EFBFBD>^i*z)(1-<EFBFBD>^j*z)(1-<EFBFBD>^k*z)
* <EFBFBD>'(z) = <EFBFBD>^i * (1-<EFBFBD>^j*z)(1-<EFBFBD>^k*z)...
* + <EFBFBD>^j * (1-<EFBFBD>^i*z)(1-<EFBFBD>^k*z)...
* + <EFBFBD>^k * (1-<EFBFBD>^i*z)(1-<EFBFBD>^j*z)...
* <EFBFBD>(z) = (E^i/(1-<EFBFBD>^i*z) + E^j/(1-<EFBFBD>^j*z) + ...) * <EFBFBD>(z)
* = E^i*(1-<EFBFBD>^j*z)(1-<EFBFBD>^k*z)...
* + E^j*(1-<EFBFBD>^i*z)(1-<EFBFBD>^k*z)...
* + E^k*(1-<EFBFBD>^i*z)(1-<EFBFBD>^j*z)...
* 4" E^i = <00>^i * <00>(z) / <00>'(z)
* @param data int[]
* eQ<EFBFBD>R<EFBFBD>0<EFBFBD>0<EFBFBD>0M<EFBFBD>R
* @param length int
* eQ<EFBFBD>R<EFBFBD>0<EFBFBD>0<EFBFBD>0w<EFBFBD>U0
* @param jisu int
* <EFBFBD>n0!kpe
* @param pos int[]
* <EFBFBD><EFBFBD><EFBFBD>0MOnM<EFBFBD>R
* @param sigma int[]
* <EFBFBD>0,<EFBFBD>1,<EFBFBD>2, ... <EFBFBD><jisu>
* @param omega int[]
* <EFBFBD>0,<EFBFBD>1,<EFBFBD>2, ... <EFBFBD><jisu-1>
*/
private void doForney(byte[] data, int length, int jisu, int[] pos, int[] sigma, int[] omega)
{
for (int i = 0; i < jisu; i++)
{
int ps = pos[i];
int zlog = 255 - galois.toLog(ps); // zn0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
// <EFBFBD>(z)n0<EFBFBD><EFBFBD>{
int ov = omega[0];
for (int j = 1; j < jisu; j++)
{
ov ^= galois.mulExp(omega[j], (zlog * j) % 255); // ov += <EFBFBD>i * z^j
}
// <EFBFBD>'(z)n0$P<EFBFBD>0<EFBFBD><EFBFBD>{(<EFBFBD>(z)n0b__<EFBFBD>v<EFBFBD>_R)
int dv = sigma[1];
for (int j = 2; j < jisu; j += 2)
{
dv ^= galois.mulExp(sigma[j + 1], (zlog * j) % 255); // dv += <EFBFBD><j+1> * z^j
}
/*
* <EFBFBD><EFBFBD><EFBFBD>0<EFBFBD>ck E^i = <EFBFBD>^i * <EFBFBD>(z) / <EFBFBD>'(z)
* <EFBFBD><EFBFBD><EFBFBD>0MOnn0<EFBFBD>{<EFBFBD>Vo0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>c"}n0h0M0k0<6B>O<<3C>U0<55>0f0D0<44>0n0g00
* S0S0g0o0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0W0j0D0
*/
data[galois.toPos(length, ps)] ^= (byte)galois.mul(ps, galois.div(ov, dv));
}
}
/**
* RS<EFBFBD>0<EFBFBD>0<EFBFBD>0n0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0
*
* @param data int[]
* eQ<EFBFBD>R<EFBFBD>0<EFBFBD>0<EFBFBD>0M<EFBFBD>R
* @param length int
* <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0+T<EFBFBD>0_0<EFBFBD>0<EFBFBD>0<EFBFBD>0w<EFBFBD>
* @param noCorrect boolean
* <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0n00g0<EFBFBD>cko0L<EFBFBD><EFBFBD>0j0D0
* @return bool
* 0: <EFBFBD>0<EFBFBD>0<EFBFBD>0j0W0
* > 0: ;b<EFBFBD>0$P Pn0<EFBFBD><EFBFBD><EFBFBD>0<EFBFBD>0<EFBFBD>ckW0_0
* < 0: <EFBFBD>ck N<EFBFBD><EFBFBD>
*/
public bool decode(byte[] data, int length, bool noCorrect, out int errors)
{
if (length < npar || length > 255)
throw new Exception("RsDecode: wrong length");
errors = 0;
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD><EFBFBD>{
int[] syn = new int[npar];
if (galois.calcSyndrome(data, length, syn))
return true; // <EFBFBD>0<EFBFBD>0<EFBFBD>0!qW0
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>h0<EFBFBD><EFBFBD>0Bl<EFBFBD>0<EFBFBD>0
int[] sigma = new int[npar / 2 + 2];
int[] omega = new int[npar / 2 + 1];
int jisu = calcSigmaMBM(sigma, omega, syn);
if (jisu <= 0)
return false;
// <EFBFBD>0<EFBFBD>0<EFBFBD>0<EFBFBD>c"}k0<6B>0<EFBFBD>0<EFBFBD><30><EFBFBD>0MOn<6E>0Bl<42>0<EFBFBD>0
int[] pos = new int[jisu];
if (!chienSearch(pos, length, jisu, sigma))
return false;
if (!noCorrect) // <EFBFBD><EFBFBD><EFBFBD>0<EFBFBD>ck
doForney(data, length, jisu, pos, sigma, omega);
errors = jisu;
return true;
}
}
}