@ -483,12 +483,12 @@ public final class QrCode {
// Split data into blocks and append ECC to each block
// Split data into blocks and append ECC to each block
byte [ ] [ ] blocks = new byte [ numBlocks ] [ ] ;
byte [ ] [ ] blocks = new byte [ numBlocks ] [ ] ;
ReedSolomonGenerator rs = new ReedSolomonGenerat or( blockEccLen ) ;
byte [ ] rsDiv = reedSolomonComputeDivis or( blockEccLen ) ;
for ( int i = 0 , k = 0 ; i < numBlocks ; i + + ) {
for ( int i = 0 , k = 0 ; i < numBlocks ; i + + ) {
byte [ ] dat = Arrays . copyOfRange ( data , k , k + shortBlockLen - blockEccLen + ( i < numShortBlocks ? 0 : 1 ) ) ;
byte [ ] dat = Arrays . copyOfRange ( data , k , k + shortBlockLen - blockEccLen + ( i < numShortBlocks ? 0 : 1 ) ) ;
k + = dat . length ;
k + = dat . length ;
byte [ ] block = Arrays . copyOf ( dat , shortBlockLen + 1 ) ;
byte [ ] block = Arrays . copyOf ( dat , shortBlockLen + 1 ) ;
byte [ ] ecc = r s. getRemainder ( dat ) ;
byte [ ] ecc = r eedSolomonComputeRemainder( dat , rsDiv ) ;
System . arraycopy ( ecc , 0 , block , block . length - blockEccLen , ecc . length ) ;
System . arraycopy ( ecc , 0 , block , block . length - blockEccLen , ecc . length ) ;
blocks [ i ] = block ;
blocks [ i ] = block ;
}
}
@ -722,6 +722,64 @@ public final class QrCode {
}
}
// Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be
// implemented as a lookup table over all possible parameter values, instead of as an algorithm.
private static byte [ ] reedSolomonComputeDivisor ( int degree ) {
if ( degree < 1 | | degree > 255 )
throw new IllegalArgumentException ( "Degree out of range" ) ;
// Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1.
// For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.
byte [ ] result = new byte [ degree ] ;
result [ degree - 1 ] = 1 ; // Start off with the monomial x^0
// Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
// and drop the highest monomial term which is always 1x^degree.
// 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 < result . length ; j + + ) {
result [ j ] = ( byte ) reedSolomonMultiply ( result [ j ] & 0xFF , root ) ;
if ( j + 1 < result . length )
result [ j ] ^ = result [ j + 1 ] ;
}
root = reedSolomonMultiply ( root , 0x02 ) ;
}
return result ;
}
// Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials.
private static byte [ ] reedSolomonComputeRemainder ( byte [ ] data , byte [ ] divisor ) {
Objects . requireNonNull ( data ) ;
Objects . requireNonNull ( divisor ) ;
byte [ ] result = new byte [ divisor . length ] ;
for ( byte b : data ) { // Polynomial division
int factor = ( b ^ result [ 0 ] ) & 0xFF ;
System . arraycopy ( result , 1 , result , 0 , result . length - 1 ) ;
result [ result . length - 1 ] = 0 ;
for ( int i = 0 ; i < result . length ; i + + )
result [ i ] ^ = reedSolomonMultiply ( divisor [ i ] & 0xFF , factor ) ;
}
return result ;
}
// 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 reedSolomonMultiply ( int x , int y ) {
assert x > > > 8 = = 0 & & y > > > 8 = = 0 ;
// Russian peasant multiplication
int z = 0 ;
for ( int i = 7 ; i > = 0 ; i - - ) {
z = ( z < < 1 ) ^ ( ( z > > > 7 ) * 0x11D ) ;
z ^ = ( ( y > > > i ) & 1 ) * x ;
}
assert z > > > 8 = = 0 ;
return z ;
}
// Returns the number of 8-bit data (i.e. not error correction) codewords contained in any
// Returns the number of 8-bit data (i.e. not error correction) codewords contained in any
// QR Code of the given version number and error correction level, with remainder bits discarded.
// QR Code of the given version number and error correction level, with remainder bits discarded.
// This stateless pure function could be implemented as a (40*4)-cell lookup table.
// This stateless pure function could be implemented as a (40*4)-cell lookup table.
@ -826,98 +884,4 @@ public final class QrCode {
}
}
}
}
/*---- Private helper class ----*/
/ * *
* Computes the Reed - Solomon error correction codewords for a sequence of data codewords
* at a given degree . Objects are immutable , and the state only depends on the degree .
* This class exists because each data block in a QR Code shares the same the divisor polynomial .
* /
private static final class ReedSolomonGenerator {
/*-- Field --*/
// Coefficients of the divisor polynomial, stored from highest to lowest power, excluding the leading term which
// is always 1. For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.
private final byte [ ] coefficients ;
/*-- Constructor --*/
/ * *
* Constructs a Reed - Solomon ECC generator for the specified degree . This could be implemented
* as a lookup table over all possible parameter values , instead of as an algorithm .
* @param degree the divisor polynomial degree , which must be between 1 and 255 ( inclusive )
* @throws IllegalArgumentException if degree & lt ; 1 or degree > 255
* /
public ReedSolomonGenerator ( int degree ) {
if ( degree < 1 | | degree > 255 )
throw new IllegalArgumentException ( "Degree out of range" ) ;
// Start with the monomial x^0
coefficients = new byte [ degree ] ;
coefficients [ degree - 1 ] = 1 ;
// Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
// drop the highest term, and store the rest of the coefficients in order of descending powers.
// 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 ) ;
}
}
/*-- Method --*/
/ * *
* Computes and returns the Reed - Solomon error correction codewords for the specified
* sequence of data codewords . The returned object is always a new byte array .
* This method does not alter this object ' s state ( because it is immutable ) .
* @param data the sequence of data codewords
* @return the Reed - Solomon error correction codewords
* @throws NullPointerException if the data is { @code null }
* /
public byte [ ] getRemainder ( byte [ ] data ) {
Objects . requireNonNull ( data ) ;
// Compute the remainder by performing polynomial division
byte [ ] result = new byte [ coefficients . length ] ;
for ( byte b : data ) {
int factor = ( b ^ result [ 0 ] ) & 0xFF ;
System . arraycopy ( result , 1 , result , 0 , result . length - 1 ) ;
result [ result . length - 1 ] = 0 ;
for ( int i = 0 ; i < result . length ; i + + )
result [ i ] ^ = multiply ( coefficients [ i ] & 0xFF , factor ) ;
}
return result ;
}
/*-- Static function --*/
// 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 ) {
assert x > > > 8 = = 0 & & y > > > 8 = = 0 ;
// Russian peasant multiplication
int z = 0 ;
for ( int i = 7 ; i > = 0 ; i - - ) {
z = ( z < < 1 ) ^ ( ( z > > > 7 ) * 0x11D ) ;
z ^ = ( ( y > > > i ) & 1 ) * x ;
}
assert z > > > 8 = = 0 ;
return z ;
}
}
}
}