/* dvdisaster: Additional error correction for optical media.1* Copyright (C) 2004-2007 Carsten Gnoerlich.2* Project home page: http://www.dvdisaster.com3* Email: [email protected] -or- [email protected]4*5* The Reed-Solomon error correction draws a lot of inspiration - and even code -6* from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fec/7*8* This program is free software; you can redistribute it and/or modify9* it under the terms of the GNU General Public License as published by10* the Free Software Foundation; either version 2 of the License, or11* (at your option) any later version.12*13* This program is distributed in the hope that it will be useful,14* but WITHOUT ANY WARRANTY; without even the implied warranty of15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the16* GNU General Public License for more details.17*18* You should have received a copy of the GNU General Public License19* along with this program; if not, write to the Free Software20* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,21* or direct your browser at http://www.gnu.org.22*/2324#include "dvdisaster.h"2526#include "galois-inlines.h"2728/***29*** Galois field arithmetic.30***31* Calculations are done over the extension field GF(2**n).32* Be careful not to overgeneralize these arithmetics;33* they only work for the case of GF(p**n) with p being prime.34*/3536/* Initialize the Galois field tables */373839GaloisTables* CreateGaloisTables(int32 gf_generator)40{41GaloisTables *gt = (GaloisTables *)calloc(1, sizeof(GaloisTables));42int32 b,log;4344/* Allocate the tables.45The encoder uses a special version of alpha_to which has the mod_fieldmax()46folded into the table. */4748gt->gfGenerator = gf_generator;4950gt->indexOf = (int32 *)calloc(GF_FIELDSIZE, sizeof(int32));51gt->alphaTo = (int32 *)calloc(GF_FIELDSIZE, sizeof(int32));52gt->encAlphaTo = (int32 *)calloc(2*GF_FIELDSIZE, sizeof(int32));5354/* create the log/ilog values */5556for(b=1, log=0; log<GF_FIELDMAX; log++)57{ gt->indexOf[b] = log;58gt->alphaTo[log] = b;59b = b << 1;60if(b & GF_FIELDSIZE)61b = b ^ gf_generator;62}6364if(b!=1)65{66printf("Failed to create the Galois field log tables!\n");67exit(1);68}6970/* we're even closed using infinity (makes things easier) */7172gt->indexOf[0] = GF_ALPHA0; /* log(0) = inf */73gt->alphaTo[GF_ALPHA0] = 0; /* and the other way around */7475for(b=0; b<2*GF_FIELDSIZE; b++)76gt->encAlphaTo[b] = gt->alphaTo[mod_fieldmax(b)];7778return gt;79}8081void FreeGaloisTables(GaloisTables *gt)82{83if(gt->indexOf) free(gt->indexOf);84if(gt->alphaTo) free(gt->alphaTo);85if(gt->encAlphaTo) free(gt->encAlphaTo);8687free(gt);88}8990/***91*** Create the the Reed-Solomon generator polynomial92*** and some auxiliary data structures.93*/9495ReedSolomonTables *CreateReedSolomonTables(GaloisTables *gt,96int32 first_consecutive_root,97int32 prim_elem,98int nroots_in)99{ ReedSolomonTables *rt = (ReedSolomonTables *)calloc(1, sizeof(ReedSolomonTables));100int32 i,j,root;101102rt->gfTables = gt;103rt->fcr = first_consecutive_root;104rt->primElem = prim_elem;105rt->nroots = nroots_in;106rt->ndata = GF_FIELDMAX - rt->nroots;107108rt->gpoly = (int32 *)calloc((rt->nroots+1), sizeof(int32));109110/* Create the RS code generator polynomial */111112rt->gpoly[0] = 1;113114for(i=0, root=first_consecutive_root*prim_elem; i<rt->nroots; i++, root+=prim_elem)115{ rt->gpoly[i+1] = 1;116117/* Multiply gpoly by alpha**(root+x) */118119for(j=i; j>0; j--)120{121if(rt->gpoly[j] != 0)122rt->gpoly[j] = rt->gpoly[j-1] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[j]] + root)];123else124rt->gpoly[j] = rt->gpoly[j-1];125}126127rt->gpoly[0] = gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[0]] + root)];128}129130/* Store the polynomials index for faster encoding */131132for(i=0; i<=rt->nroots; i++)133rt->gpoly[i] = gt->indexOf[rt->gpoly[i]];134135#if 0136/* for the precalculated unrolled loops only */137138for(i=gt->nroots-1; i>0; i--)139PrintCLI(140" par_idx[((++spk)&%d)] ^= enc_alpha_to[feedback + %3d];\n",141nroots-1,gt->gpoly[i]);142143PrintCLI(" par_idx[sp] = enc_alpha_to[feedback + %3d];\n",144gt->gpoly[0]);145#endif146147return rt;148}149150void FreeReedSolomonTables(ReedSolomonTables *rt)151{152if(rt->gpoly) free(rt->gpoly);153154free(rt);155}156157158