mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 18:14:25 +00:00
192 lines
7.1 KiB
C#
192 lines
7.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
|
|
namespace CUETools.Parity
|
|
{
|
|
public class ParityToSyndrome
|
|
{
|
|
private int[] erasures_pos;
|
|
private int[] erasure_loc_pol;
|
|
private int[] erasure_diff;
|
|
private int npar;
|
|
const int w = 16;
|
|
const int max = (1 << w) - 1;
|
|
|
|
public ParityToSyndrome(int npar)
|
|
{
|
|
this.npar = npar;
|
|
this.InitTables();
|
|
}
|
|
|
|
private void InitTables()
|
|
{
|
|
var num_erasures = this.npar;
|
|
|
|
// Compute the erasure locator polynomial:
|
|
erasures_pos = new int[num_erasures];
|
|
for (int x = 0; x < num_erasures; x++)
|
|
erasures_pos[x] = x;
|
|
|
|
//%Compute the erasure-locator polynomial
|
|
// Optimized version
|
|
var erasure_loc_pol_exp = new int[num_erasures + 1];
|
|
erasure_loc_pol_exp[0] = 1;
|
|
for (int i = 0; i < num_erasures; i++)
|
|
for (int x = num_erasures; x > 0; x--)
|
|
erasure_loc_pol_exp[x] ^= Galois16.instance.mulExp(erasure_loc_pol_exp[x - 1], erasures_pos[i]);
|
|
erasure_loc_pol = Galois16.instance.toLog(erasure_loc_pol_exp);
|
|
erasure_diff = Galois16.instance.gfdiff(erasure_loc_pol);
|
|
}
|
|
|
|
public static unsafe byte[] Syndrome2Bytes(ushort[,] inArray)
|
|
{
|
|
int stride = inArray.GetLength(0);
|
|
int npar = inArray.GetLength(1);
|
|
var outBuf = new byte[npar * stride * 2];
|
|
fixed (byte* outPtr = outBuf)
|
|
{
|
|
var ppar = (ushort*)outPtr;
|
|
for (int i = 0; i < npar; i++)
|
|
for (int j = 0; j < stride; j++)
|
|
ppar[j + i * stride] = inArray[j, i];
|
|
}
|
|
return outBuf;
|
|
}
|
|
|
|
public static unsafe ushort[,] Bytes2Syndrome(int stride, int npar, byte[] parity)
|
|
{
|
|
if (parity.Length < npar * stride * 2)
|
|
throw new Exception("invalid parity length");
|
|
var syndrome = new ushort[stride, npar];
|
|
fixed (byte* pbpar = parity)
|
|
fixed (ushort* psyn = syndrome)
|
|
{
|
|
var ppar = (ushort*)pbpar;
|
|
for (int i = 0; i < npar; i++)
|
|
for (int j = 0; j < stride; j++)
|
|
psyn[i + j * npar] = ppar[j + i * stride];
|
|
}
|
|
return syndrome;
|
|
}
|
|
|
|
public static unsafe byte[] Syndrome2Parity(ushort[,] syndrome, byte[] parity = null)
|
|
{
|
|
var stride = syndrome.GetLength(0);
|
|
var npar = syndrome.GetLength(1);
|
|
var converter = new ParityToSyndrome(npar);
|
|
if (parity == null)
|
|
parity = new byte[npar * stride * 2];
|
|
fixed (byte* bpar = parity)
|
|
fixed (ushort* syn = syndrome)
|
|
{
|
|
ushort* par = (ushort*)bpar;
|
|
for (int i = 0; i < stride; i++)
|
|
converter.Syndrome2Parity(syn + i * npar, par + i * npar);
|
|
}
|
|
return parity;
|
|
}
|
|
|
|
public static unsafe ushort[,] Parity2Syndrome(int stride, int stride2, int npar, int npar2, byte[] parity, int pos = 0, int offset = 0)
|
|
{
|
|
if (npar > npar2 || stride > stride2)
|
|
throw new InvalidOperationException();
|
|
var syndrome = new ushort[stride, npar];
|
|
fixed (byte* pbpar = &parity[pos])
|
|
fixed (ushort* psyn = syndrome, plog = Galois16.instance.LogTbl, pexp = Galois16.instance.ExpTbl)
|
|
{
|
|
var ppar = (ushort*)pbpar;
|
|
for (int y = 0; y < stride; y++)
|
|
{
|
|
int y1 = (y - offset + stride2) % stride2;
|
|
ushort* syn = psyn + y * npar;
|
|
ushort* par = ppar + y1 * npar2;
|
|
for (int x1 = 0; x1 < npar2; x1++)
|
|
{
|
|
ushort lo = par[x1];
|
|
if (lo != 0)
|
|
{
|
|
var llo = plog[lo] + 0xffff;
|
|
for (int x = 0; x < npar; x++)
|
|
syn[x] ^= pexp[llo - (1 + x1) * x];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return syndrome;
|
|
}
|
|
|
|
public unsafe void Syndrome2Parity(ushort* syndrome, ushort* parity)
|
|
{
|
|
// Advance syndrome by npar zeroes (for npar 'erased' parity symbols)
|
|
var S_pol = new int[npar + 1];
|
|
S_pol[0] = -1;
|
|
for (int i = 0; i < npar; i++)
|
|
{
|
|
if (syndrome[i] == 0)
|
|
S_pol[i + 1] = -1;
|
|
else
|
|
{
|
|
var exp = Galois16.instance.LogTbl[syndrome[i]] + npar * i;
|
|
S_pol[i + 1] = (exp & max) + (exp >> w);
|
|
}
|
|
}
|
|
var mod_syn = Galois16.instance.gfconv(erasure_loc_pol, S_pol, npar + 1);
|
|
|
|
//%Calculate remaining errors (non-erasures)
|
|
//
|
|
//S_M = [];
|
|
//for i = 1:h - num_erasures
|
|
// S_M(i) = mod_syn(i + num_erasures + 1);
|
|
//end
|
|
//flag = 0;
|
|
//if isempty(S_M) == 1
|
|
// flag = 0;
|
|
//else
|
|
// for i = 1:length(S_M)
|
|
// if (S_M(i) ~= -Inf)
|
|
// flag = 1; %Other errors occured in conjunction with erasures
|
|
// end
|
|
// end
|
|
//end
|
|
//%Find error-location polynomial sigma (Berlekamp's iterative algorithm -
|
|
//if (flag == 1)
|
|
//{
|
|
// ...
|
|
//}
|
|
//else
|
|
//{
|
|
// sigma = 0;
|
|
// comp_error_locs = [];
|
|
//}
|
|
|
|
#if kjsljdf
|
|
var sigma = new int[1] { 0 };
|
|
var omega = gfconv(sigma, gfadd(mod_syn, 0), npar + 1);
|
|
var tsi = gfconv(sigma, erasure_loc_pol);
|
|
var tsi_diff = gfdiff(tsi);
|
|
//var e_e_places = [erasures_pos comp_error_locs];
|
|
#else
|
|
var omega = mod_syn;
|
|
var tsi_diff = erasure_diff;
|
|
var e_e_places = erasures_pos;
|
|
#endif
|
|
|
|
//%Calculate the error magnitudes
|
|
//%Substitute the inverse into sigma_diff
|
|
//var ERR = new int[e_e_places.Length];
|
|
for (int ii = 0; ii < e_e_places.Length; ii++)
|
|
{
|
|
var point = max - e_e_places[ii];
|
|
var ERR_DEN = Galois16.instance.gfsubstitute(tsi_diff, point, tsi_diff.Length);
|
|
var ERR_NUM = Galois16.instance.gfsubstitute(omega, point, omega.Length);
|
|
// Additional +ii because we use slightly different syndrome
|
|
var pow = ERR_NUM + e_e_places[ii] + ii + max - ERR_DEN;
|
|
|
|
//ERR[ii] = ERR_NUM == -1 ? 0 : expTbl[(pow & max) + (pow >> w)];
|
|
parity[npar - 1 - ii] = ERR_NUM == -1 ? (ushort)0 : Galois16.instance.ExpTbl[(pow & max) + (pow >> w)];
|
|
}
|
|
}
|
|
}
|
|
}
|