namespace Gma.QrCodeNet.Encoding.ReedSolomon;
internal sealed class ReedSolomonEncoder
{
///
/// Encode an array of data codeword with GaloisField 256.
///
/// Array of data codewords for a single block.
/// Number of error correction codewords for data codewords
/// Cached or newly create GeneratorPolynomial
/// Return error correction codewords array
internal static byte[] Encode(byte[] dataBytes, int numECBytes, GeneratorPolynomial generatorPoly)
{
int dataLength = dataBytes.Length;
if (generatorPoly == null)
throw new ArgumentNullException(nameof(generatorPoly));
if (dataLength == 0)
{
throw new ArgumentException("There is no data bytes to encode.");
}
if (numECBytes <= 0)
{
throw new ArgumentException("No Error Correction bytes.");
}
int[] toEncode = ConvertToIntArray(dataBytes, dataLength, numECBytes);
Polynomial generator = generatorPoly.GetGenerator(numECBytes);
Polynomial dataPoly = new(generator.GField, toEncode);
PolyDivideStruct divideResult = dataPoly.Divide(generator);
int[] remainderCoeffs = divideResult.Remainder.Coefficients;
return ConvertTosByteArray(remainderCoeffs, numECBytes);
}
///
/// Convert data codewords to int array. And add error correction space at end of that array
///
/// Data codewords array
/// Data codewords length
/// Num of error correction bytes
/// Int array for data codewords array follow by error correction space
private static int[] ConvertToIntArray(byte[] dataBytes, int dataLength, int numECBytes)
{
int[] resultArray = new int[dataLength + numECBytes];
for (int index = 0; index < dataLength; index++)
{
resultArray[index] = dataBytes[index] & 0xff;
}
return resultArray;
}
///
/// Reassembly error correction codewords. As Polynomial class will eliminate zero monomial at front.
///
/// Remainder byte array after divide.
/// Error correction codewords length
/// Error correction codewords
private static byte[] ConvertTosByteArray(int[] remainder, int numECBytes)
{
int remainderLength = remainder.Length;
if (remainderLength > numECBytes)
{
throw new ArgumentException($"Num of {nameof(remainder)} bytes cannot be larger than {nameof(numECBytes)}.");
}
int numZeroCoeffs = numECBytes - remainderLength;
byte[] resultArray = new byte[numECBytes];
for (int index = 0; index < numZeroCoeffs; index++)
{
resultArray[index] = 0;
}
for (int rIndex = 0; rIndex < remainderLength; rIndex++)
{
resultArray[numZeroCoeffs + rIndex] = (byte)remainder[rIndex];
}
return resultArray;
}
}