Renamed functions and variables, and updated comments, thus synchronizing the C language version with the previous changeset.

pull/62/head
Project Nayuki 6 years ago
parent b5aaadf758
commit 76127b8bfe

@ -49,9 +49,9 @@ void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bi
void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]);
int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
int getNumRawDataModules(int version);
void calcReedSolomonGenerator(int degree, uint8_t result[]);
void calcReedSolomonRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]);
uint8_t finiteFieldMultiply(uint8_t x, uint8_t y);
void reedSolomonComputeDivisor(int degree, uint8_t result[]);
void reedSolomonComputeRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]);
uint8_t reedSolomonMultiply(uint8_t x, uint8_t y);
void initializeFunctionModules(int version, uint8_t qrcode[]);
int getAlignmentPatternPositions(int version, uint8_t result[7]);
bool getModule(const uint8_t qrcode[], int x, int y);
@ -116,12 +116,12 @@ static uint8_t *addEccAndInterleaveReference(const uint8_t *data, int version, e
// Split data into blocks and append ECC to each block
uint8_t **blocks = malloc(numBlocks * sizeof(uint8_t*));
uint8_t *generator = malloc(blockEccLen * sizeof(uint8_t));
calcReedSolomonGenerator(blockEccLen, generator);
reedSolomonComputeDivisor(blockEccLen, generator);
for (int i = 0, k = 0; i < numBlocks; i++) {
uint8_t *block = malloc((shortBlockLen + 1) * sizeof(uint8_t));
int datLen = shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1);
memcpy(block, &data[k], datLen * sizeof(uint8_t));
calcReedSolomonRemainder(&data[k], datLen, generator, blockEccLen, &block[shortBlockLen + 1 - blockEccLen]);
reedSolomonComputeRemainder(&data[k], datLen, generator, blockEccLen, &block[shortBlockLen + 1 - blockEccLen]);
k += datLen;
blocks[i] = block;
}
@ -235,19 +235,19 @@ static void testGetNumRawDataModules(void) {
}
static void testCalcReedSolomonGenerator(void) {
static void testReedSolomonComputeDivisor(void) {
uint8_t generator[30];
calcReedSolomonGenerator(1, generator);
reedSolomonComputeDivisor(1, generator);
assert(generator[0] == 0x01);
numTestCases++;
calcReedSolomonGenerator(2, generator);
reedSolomonComputeDivisor(2, generator);
assert(generator[0] == 0x03);
assert(generator[1] == 0x02);
numTestCases++;
calcReedSolomonGenerator(5, generator);
reedSolomonComputeDivisor(5, generator);
assert(generator[0] == 0x1F);
assert(generator[1] == 0xC6);
assert(generator[2] == 0x3F);
@ -255,7 +255,7 @@ static void testCalcReedSolomonGenerator(void) {
assert(generator[4] == 0x74);
numTestCases++;
calcReedSolomonGenerator(30, generator);
reedSolomonComputeDivisor(30, generator);
assert(generator[ 0] == 0xD4);
assert(generator[ 1] == 0xF6);
assert(generator[ 5] == 0xC0);
@ -268,13 +268,13 @@ static void testCalcReedSolomonGenerator(void) {
}
static void testCalcReedSolomonRemainder(void) {
static void testReedSolomonComputeRemainder(void) {
{
uint8_t data[1];
uint8_t generator[3];
uint8_t remainder[ARRAY_LENGTH(generator)];
calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator);
calcReedSolomonRemainder(data, 0, generator, ARRAY_LENGTH(generator), remainder);
reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator);
reedSolomonComputeRemainder(data, 0, generator, ARRAY_LENGTH(generator), remainder);
assert(remainder[0] == 0);
assert(remainder[1] == 0);
assert(remainder[2] == 0);
@ -284,8 +284,8 @@ static void testCalcReedSolomonRemainder(void) {
uint8_t data[2] = {0, 1};
uint8_t generator[4];
uint8_t remainder[ARRAY_LENGTH(generator)];
calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator);
calcReedSolomonRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator);
reedSolomonComputeRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
assert(remainder[0] == generator[0]);
assert(remainder[1] == generator[1]);
assert(remainder[2] == generator[2]);
@ -296,8 +296,8 @@ static void testCalcReedSolomonRemainder(void) {
uint8_t data[5] = {0x03, 0x3A, 0x60, 0x12, 0xC7};
uint8_t generator[5];
uint8_t remainder[ARRAY_LENGTH(generator)];
calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator);
calcReedSolomonRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator);
reedSolomonComputeRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
assert(remainder[0] == 0xCB);
assert(remainder[1] == 0x36);
assert(remainder[2] == 0x16);
@ -315,8 +315,8 @@ static void testCalcReedSolomonRemainder(void) {
};
uint8_t generator[30];
uint8_t remainder[ARRAY_LENGTH(generator)];
calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator);
calcReedSolomonRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator);
reedSolomonComputeRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
assert(remainder[ 0] == 0xCE);
assert(remainder[ 1] == 0xF0);
assert(remainder[ 2] == 0x31);
@ -333,7 +333,7 @@ static void testCalcReedSolomonRemainder(void) {
}
static void testFiniteFieldMultiply(void) {
static void testReedSolomonMultiply(void) {
const uint8_t cases[][3] = {
{0x00, 0x00, 0x00},
{0x01, 0x01, 0x01},
@ -354,7 +354,7 @@ static void testFiniteFieldMultiply(void) {
};
for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
const uint8_t *tc = cases[i];
assert(finiteFieldMultiply(tc[0], tc[1]) == tc[2]);
assert(reedSolomonMultiply(tc[0], tc[1]) == tc[2]);
numTestCases++;
}
}
@ -1054,9 +1054,9 @@ int main(void) {
testAddEccAndInterleave();
testGetNumDataCodewords();
testGetNumRawDataModules();
testCalcReedSolomonGenerator();
testCalcReedSolomonRemainder();
testFiniteFieldMultiply();
testReedSolomonComputeDivisor();
testReedSolomonComputeRemainder();
testReedSolomonMultiply();
testInitializeFunctionModulesEtc();
testGetAlignmentPatternPositions();
testGetSetModule();

@ -58,10 +58,10 @@ testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ec
testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
testable int getNumRawDataModules(int ver);
testable void calcReedSolomonGenerator(int degree, uint8_t result[]);
testable void calcReedSolomonRemainder(const uint8_t data[], int dataLen,
testable void reedSolomonComputeDivisor(int degree, uint8_t result[]);
testable void reedSolomonComputeRemainder(const uint8_t data[], int dataLen,
const uint8_t generator[], int degree, uint8_t result[]);
testable uint8_t finiteFieldMultiply(uint8_t x, uint8_t y);
testable uint8_t reedSolomonMultiply(uint8_t x, uint8_t y);
testable void initializeFunctionModules(int version, uint8_t qrcode[]);
static void drawWhiteFunctionModules(uint8_t qrcode[], int version);
@ -301,13 +301,13 @@ testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ec
// Split data into blocks, calculate ECC, and interleave
// (not concatenate) the bytes into a single sequence
uint8_t generator[qrcodegen_REED_SOLOMON_DEGREE_MAX];
calcReedSolomonGenerator(blockEccLen, generator);
uint8_t rsdiv[qrcodegen_REED_SOLOMON_DEGREE_MAX];
reedSolomonComputeDivisor(blockEccLen, rsdiv);
const uint8_t *dat = data;
for (int i = 0; i < numBlocks; i++) {
int datLen = shortBlockDataLen + (i < numShortBlocks ? 0 : 1);
uint8_t *ecc = &data[dataLen]; // Temporary storage
calcReedSolomonRemainder(dat, datLen, generator, blockEccLen, ecc);
reedSolomonComputeRemainder(dat, datLen, rsdiv, blockEccLen, ecc);
for (int j = 0, k = i; j < datLen; j++, k += numBlocks) { // Copy data
if (j == shortBlockDataLen)
k -= numShortBlocks;
@ -350,43 +350,44 @@ testable int getNumRawDataModules(int ver) {
/*---- Reed-Solomon ECC generator functions ----*/
// Calculates the Reed-Solomon generator polynomial of the given degree, storing in result[0 : degree].
testable void calcReedSolomonGenerator(int degree, uint8_t result[]) {
// Start with the monomial x^0
// Computes a Reed-Solomon ECC generator polynomial for the given degree, storing in result[0 : degree].
// This could be implemented as a lookup table over all possible parameter values, instead of as an algorithm.
testable void reedSolomonComputeDivisor(int degree, uint8_t result[]) {
assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX);
// 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}.
memset(result, 0, degree * sizeof(result[0]));
result[degree - 1] = 1;
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}),
// drop the highest term, and store the rest of the coefficients in order of descending powers.
// 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).
uint8_t root = 1;
for (int i = 0; i < degree; i++) {
// Multiply the current product by (x - r^i)
for (int j = 0; j < degree; j++) {
result[j] = finiteFieldMultiply(result[j], root);
result[j] = reedSolomonMultiply(result[j], root);
if (j + 1 < degree)
result[j] ^= result[j + 1];
}
root = finiteFieldMultiply(root, 0x02);
root = reedSolomonMultiply(root, 0x02);
}
}
// Calculates the remainder of the polynomial data[0 : dataLen] when divided by the generator[0 : degree], where all
// polynomials are in big endian and the generator has an implicit leading 1 term, storing the result in result[0 : degree].
testable void calcReedSolomonRemainder(const uint8_t data[], int dataLen,
// Computes the Reed-Solomon error correction codeword for the given data and divisor polynomials.
// The remainder when data[0 : dataLen] is divided by divisor[0 : degree] is stored in result[0 : degree].
// All polynomials are in big endian, and the generator has an implicit leading 1 term.
testable void reedSolomonComputeRemainder(const uint8_t data[], int dataLen,
const uint8_t generator[], int degree, uint8_t result[]) {
// Perform polynomial division
assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX);
memset(result, 0, degree * sizeof(result[0]));
for (int i = 0; i < dataLen; i++) {
for (int i = 0; i < dataLen; i++) { // Polynomial division
uint8_t factor = data[i] ^ result[0];
memmove(&result[0], &result[1], (degree - 1) * sizeof(result[0]));
result[degree - 1] = 0;
for (int j = 0; j < degree; j++)
result[j] ^= finiteFieldMultiply(generator[j], factor);
result[j] ^= reedSolomonMultiply(generator[j], factor);
}
}
@ -395,7 +396,7 @@ testable void calcReedSolomonRemainder(const uint8_t data[], int dataLen,
// Returns the product of the two given field elements modulo GF(2^8/0x11D).
// All inputs are valid. This could be implemented as a 256*256 lookup table.
testable uint8_t finiteFieldMultiply(uint8_t x, uint8_t y) {
testable uint8_t reedSolomonMultiply(uint8_t x, uint8_t y) {
// Russian peasant multiplication
uint8_t z = 0;
for (int i = 7; i >= 0; i--) {

Loading…
Cancel
Save