You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
107 lines
4.2 KiB
107 lines
4.2 KiB
7 years ago
|
/*
|
||
|
* Fast QR Code generator library
|
||
|
*
|
||
|
* Copyright (c) Project Nayuki. (MIT License)
|
||
7 years ago
|
* https://www.nayuki.io/page/fast-qr-code-generator-library
|
||
7 years ago
|
*
|
||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||
|
* this software and associated documentation files (the "Software"), to deal in
|
||
|
* the Software without restriction, including without limitation the rights to
|
||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||
|
* subject to the following conditions:
|
||
|
* - The above copyright notice and this permission notice shall be included in
|
||
|
* all copies or substantial portions of the Software.
|
||
|
* - The Software is provided "as is", without warranty of any kind, express or
|
||
|
* implied, including but not limited to the warranties of merchantability,
|
||
|
* fitness for a particular purpose and noninfringement. In no event shall the
|
||
|
* authors or copyright holders be liable for any claim, damages or other
|
||
|
* liability, whether in an action of contract, tort or otherwise, arising from,
|
||
|
* out of or in connection with the Software or the use or other dealings in the
|
||
|
* Software.
|
||
|
*/
|
||
|
|
||
7 years ago
|
package io.nayuki.fastqrcodegen;
|
||
|
|
||
|
import java.util.Arrays;
|
||
|
import java.util.Objects;
|
||
|
|
||
|
|
||
5 years ago
|
// Computes Reed-Solomon error correction codewords for given data codewords.
|
||
7 years ago
|
final class ReedSolomonGenerator {
|
||
|
|
||
5 years ago
|
// Use this memoizer to get instances of this class.
|
||
5 years ago
|
public static final Memoizer<Integer,ReedSolomonGenerator> MEMOIZER
|
||
|
= new Memoizer<>(ReedSolomonGenerator::new);
|
||
7 years ago
|
|
||
|
|
||
6 years ago
|
// A table of size 256 * degree, where polynomialMultiply[i][j] = multiply(i, coefficients[j]).
|
||
5 years ago
|
// 'coefficients' is the temporary array computed in the constructor.
|
||
6 years ago
|
private byte[][] polynomialMultiply;
|
||
7 years ago
|
|
||
|
|
||
5 years ago
|
// Creates a Reed-Solomon ECC generator polynomial for the given degree.
|
||
7 years ago
|
private ReedSolomonGenerator(int degree) {
|
||
|
if (degree < 1 || degree > 255)
|
||
|
throw new IllegalArgumentException("Degree out of range");
|
||
|
|
||
5 years ago
|
// The divisor polynomial, whose coefficients are stored from highest to lowest power.
|
||
|
// For example, x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.
|
||
7 years ago
|
byte[] coefficients = new byte[degree];
|
||
5 years ago
|
coefficients[degree - 1] = 1; // Start off with the monomial x^0
|
||
7 years ago
|
|
||
|
// Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
|
||
5 years ago
|
// and drop the highest monomial term which is always 1x^degree.
|
||
7 years ago
|
// Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
|
||
|
int root = 1;
|
||
|
for (int i = 0; i < degree; i++) {
|
||
|
// Multiply the current product by (x - r^i)
|
||
|
for (int j = 0; j < coefficients.length; j++) {
|
||
|
coefficients[j] = (byte)multiply(coefficients[j] & 0xFF, root);
|
||
|
if (j + 1 < coefficients.length)
|
||
|
coefficients[j] ^= coefficients[j + 1];
|
||
|
}
|
||
|
root = multiply(root, 0x02);
|
||
|
}
|
||
|
|
||
6 years ago
|
polynomialMultiply = new byte[256][degree];
|
||
|
for (int i = 0; i < polynomialMultiply.length; i++) {
|
||
|
for (int j = 0; j < degree; j++)
|
||
|
polynomialMultiply[i][j] = (byte)multiply(i, coefficients[j] & 0xFF);
|
||
6 years ago
|
}
|
||
7 years ago
|
}
|
||
|
|
||
|
|
||
5 years ago
|
// Returns the error correction codeword for the given data polynomial and this divisor polynomial.
|
||
6 years ago
|
public void getRemainder(byte[] data, int dataOff, int dataLen, byte[] result) {
|
||
7 years ago
|
Objects.requireNonNull(data);
|
||
|
Objects.requireNonNull(result);
|
||
6 years ago
|
int degree = polynomialMultiply[0].length;
|
||
|
assert result.length == degree;
|
||
7 years ago
|
|
||
6 years ago
|
Arrays.fill(result, (byte)0);
|
||
5 years ago
|
for (int i = dataOff, dataEnd = dataOff + dataLen; i < dataEnd; i++) { // Polynomial division
|
||
6 years ago
|
byte[] table = polynomialMultiply[(data[i] ^ result[0]) & 0xFF];
|
||
6 years ago
|
for (int j = 0; j < degree - 1; j++)
|
||
6 years ago
|
result[j] = (byte)(result[j + 1] ^ table[j]);
|
||
|
result[degree - 1] = table[degree - 1];
|
||
7 years ago
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Returns the product of the two given field elements modulo GF(2^8/0x11D). The arguments and result
|
||
|
// are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8.
|
||
|
private static int multiply(int x, int y) {
|
||
5 years ago
|
assert x >> 8 == 0 && y >> 8 == 0;
|
||
7 years ago
|
// Russian peasant multiplication
|
||
|
int z = 0;
|
||
|
for (int i = 7; i >= 0; i--) {
|
||
|
z = (z << 1) ^ ((z >>> 7) * 0x11D);
|
||
|
z ^= ((y >>> i) & 1) * x;
|
||
|
}
|
||
6 years ago
|
assert z >>> 8 == 0;
|
||
7 years ago
|
return z;
|
||
|
}
|
||
|
|
||
|
}
|