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[]); void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]);
int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl); int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
int getNumRawDataModules(int version); int getNumRawDataModules(int version);
void calcReedSolomonGenerator(int degree, uint8_t result[]); void reedSolomonComputeDivisor(int degree, uint8_t result[]);
void calcReedSolomonRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]); void reedSolomonComputeRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]);
uint8_t finiteFieldMultiply(uint8_t x, uint8_t y); uint8_t reedSolomonMultiply(uint8_t x, uint8_t y);
void initializeFunctionModules(int version, uint8_t qrcode[]); void initializeFunctionModules(int version, uint8_t qrcode[]);
int getAlignmentPatternPositions(int version, uint8_t result[7]); int getAlignmentPatternPositions(int version, uint8_t result[7]);
bool getModule(const uint8_t qrcode[], int x, int y); 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 // Split data into blocks and append ECC to each block
uint8_t **blocks = malloc(numBlocks * sizeof(uint8_t*)); uint8_t **blocks = malloc(numBlocks * sizeof(uint8_t*));
uint8_t *generator = malloc(blockEccLen * 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++) { for (int i = 0, k = 0; i < numBlocks; i++) {
uint8_t *block = malloc((shortBlockLen + 1) * sizeof(uint8_t)); uint8_t *block = malloc((shortBlockLen + 1) * sizeof(uint8_t));
int datLen = shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1); int datLen = shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1);
memcpy(block, &data[k], datLen * sizeof(uint8_t)); 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; k += datLen;
blocks[i] = block; blocks[i] = block;
} }
@ -235,19 +235,19 @@ static void testGetNumRawDataModules(void) {
} }
static void testCalcReedSolomonGenerator(void) { static void testReedSolomonComputeDivisor(void) {
uint8_t generator[30]; uint8_t generator[30];
calcReedSolomonGenerator(1, generator); reedSolomonComputeDivisor(1, generator);
assert(generator[0] == 0x01); assert(generator[0] == 0x01);
numTestCases++; numTestCases++;
calcReedSolomonGenerator(2, generator); reedSolomonComputeDivisor(2, generator);
assert(generator[0] == 0x03); assert(generator[0] == 0x03);
assert(generator[1] == 0x02); assert(generator[1] == 0x02);
numTestCases++; numTestCases++;
calcReedSolomonGenerator(5, generator); reedSolomonComputeDivisor(5, generator);
assert(generator[0] == 0x1F); assert(generator[0] == 0x1F);
assert(generator[1] == 0xC6); assert(generator[1] == 0xC6);
assert(generator[2] == 0x3F); assert(generator[2] == 0x3F);
@ -255,7 +255,7 @@ static void testCalcReedSolomonGenerator(void) {
assert(generator[4] == 0x74); assert(generator[4] == 0x74);
numTestCases++; numTestCases++;
calcReedSolomonGenerator(30, generator); reedSolomonComputeDivisor(30, generator);
assert(generator[ 0] == 0xD4); assert(generator[ 0] == 0xD4);
assert(generator[ 1] == 0xF6); assert(generator[ 1] == 0xF6);
assert(generator[ 5] == 0xC0); 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 data[1];
uint8_t generator[3]; uint8_t generator[3];
uint8_t remainder[ARRAY_LENGTH(generator)]; uint8_t remainder[ARRAY_LENGTH(generator)];
calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator); reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator);
calcReedSolomonRemainder(data, 0, generator, ARRAY_LENGTH(generator), remainder); reedSolomonComputeRemainder(data, 0, generator, ARRAY_LENGTH(generator), remainder);
assert(remainder[0] == 0); assert(remainder[0] == 0);
assert(remainder[1] == 0); assert(remainder[1] == 0);
assert(remainder[2] == 0); assert(remainder[2] == 0);
@ -284,8 +284,8 @@ static void testCalcReedSolomonRemainder(void) {
uint8_t data[2] = {0, 1}; uint8_t data[2] = {0, 1};
uint8_t generator[4]; uint8_t generator[4];
uint8_t remainder[ARRAY_LENGTH(generator)]; uint8_t remainder[ARRAY_LENGTH(generator)];
calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator); reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator);
calcReedSolomonRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder); reedSolomonComputeRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
assert(remainder[0] == generator[0]); assert(remainder[0] == generator[0]);
assert(remainder[1] == generator[1]); assert(remainder[1] == generator[1]);
assert(remainder[2] == generator[2]); assert(remainder[2] == generator[2]);
@ -296,8 +296,8 @@ static void testCalcReedSolomonRemainder(void) {
uint8_t data[5] = {0x03, 0x3A, 0x60, 0x12, 0xC7}; uint8_t data[5] = {0x03, 0x3A, 0x60, 0x12, 0xC7};
uint8_t generator[5]; uint8_t generator[5];
uint8_t remainder[ARRAY_LENGTH(generator)]; uint8_t remainder[ARRAY_LENGTH(generator)];
calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator); reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator);
calcReedSolomonRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder); reedSolomonComputeRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
assert(remainder[0] == 0xCB); assert(remainder[0] == 0xCB);
assert(remainder[1] == 0x36); assert(remainder[1] == 0x36);
assert(remainder[2] == 0x16); assert(remainder[2] == 0x16);
@ -315,8 +315,8 @@ static void testCalcReedSolomonRemainder(void) {
}; };
uint8_t generator[30]; uint8_t generator[30];
uint8_t remainder[ARRAY_LENGTH(generator)]; uint8_t remainder[ARRAY_LENGTH(generator)];
calcReedSolomonGenerator(ARRAY_LENGTH(generator), generator); reedSolomonComputeDivisor(ARRAY_LENGTH(generator), generator);
calcReedSolomonRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder); reedSolomonComputeRemainder(data, ARRAY_LENGTH(data), generator, ARRAY_LENGTH(generator), remainder);
assert(remainder[ 0] == 0xCE); assert(remainder[ 0] == 0xCE);
assert(remainder[ 1] == 0xF0); assert(remainder[ 1] == 0xF0);
assert(remainder[ 2] == 0x31); 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] = { const uint8_t cases[][3] = {
{0x00, 0x00, 0x00}, {0x00, 0x00, 0x00},
{0x01, 0x01, 0x01}, {0x01, 0x01, 0x01},
@ -354,7 +354,7 @@ static void testFiniteFieldMultiply(void) {
}; };
for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) { for (size_t i = 0; i < ARRAY_LENGTH(cases); i++) {
const uint8_t *tc = 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++; numTestCases++;
} }
} }
@ -1054,9 +1054,9 @@ int main(void) {
testAddEccAndInterleave(); testAddEccAndInterleave();
testGetNumDataCodewords(); testGetNumDataCodewords();
testGetNumRawDataModules(); testGetNumRawDataModules();
testCalcReedSolomonGenerator(); testReedSolomonComputeDivisor();
testCalcReedSolomonRemainder(); testReedSolomonComputeRemainder();
testFiniteFieldMultiply(); testReedSolomonMultiply();
testInitializeFunctionModulesEtc(); testInitializeFunctionModulesEtc();
testGetAlignmentPatternPositions(); testGetAlignmentPatternPositions();
testGetSetModule(); 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 getNumDataCodewords(int version, enum qrcodegen_Ecc ecl);
testable int getNumRawDataModules(int ver); testable int getNumRawDataModules(int ver);
testable void calcReedSolomonGenerator(int degree, uint8_t result[]); testable void reedSolomonComputeDivisor(int degree, uint8_t result[]);
testable void calcReedSolomonRemainder(const uint8_t data[], int dataLen, testable void reedSolomonComputeRemainder(const uint8_t data[], int dataLen,
const uint8_t generator[], int degree, uint8_t result[]); 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[]); testable void initializeFunctionModules(int version, uint8_t qrcode[]);
static void drawWhiteFunctionModules(uint8_t qrcode[], int version); 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 // Split data into blocks, calculate ECC, and interleave
// (not concatenate) the bytes into a single sequence // (not concatenate) the bytes into a single sequence
uint8_t generator[qrcodegen_REED_SOLOMON_DEGREE_MAX]; uint8_t rsdiv[qrcodegen_REED_SOLOMON_DEGREE_MAX];
calcReedSolomonGenerator(blockEccLen, generator); reedSolomonComputeDivisor(blockEccLen, rsdiv);
const uint8_t *dat = data; const uint8_t *dat = data;
for (int i = 0; i < numBlocks; i++) { for (int i = 0; i < numBlocks; i++) {
int datLen = shortBlockDataLen + (i < numShortBlocks ? 0 : 1); int datLen = shortBlockDataLen + (i < numShortBlocks ? 0 : 1);
uint8_t *ecc = &data[dataLen]; // Temporary storage 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 for (int j = 0, k = i; j < datLen; j++, k += numBlocks) { // Copy data
if (j == shortBlockDataLen) if (j == shortBlockDataLen)
k -= numShortBlocks; k -= numShortBlocks;
@ -350,43 +350,44 @@ testable int getNumRawDataModules(int ver) {
/*---- Reed-Solomon ECC generator functions ----*/ /*---- Reed-Solomon ECC generator functions ----*/
// Calculates the Reed-Solomon generator polynomial of the given degree, storing in result[0 : degree]. // Computes a Reed-Solomon ECC generator polynomial for the given degree, storing in result[0 : degree].
testable void calcReedSolomonGenerator(int degree, uint8_t result[]) { // This could be implemented as a lookup table over all possible parameter values, instead of as an algorithm.
// Start with the monomial x^0 testable void reedSolomonComputeDivisor(int degree, uint8_t result[]) {
assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX); 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])); 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}), // 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). // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
uint8_t root = 1; uint8_t root = 1;
for (int i = 0; i < degree; i++) { for (int i = 0; i < degree; i++) {
// Multiply the current product by (x - r^i) // Multiply the current product by (x - r^i)
for (int j = 0; j < degree; j++) { for (int j = 0; j < degree; j++) {
result[j] = finiteFieldMultiply(result[j], root); result[j] = reedSolomonMultiply(result[j], root);
if (j + 1 < degree) if (j + 1 < degree)
result[j] ^= result[j + 1]; 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 // Computes the Reed-Solomon error correction codeword for the given data and divisor polynomials.
// polynomials are in big endian and the generator has an implicit leading 1 term, storing the result in result[0 : degree]. // The remainder when data[0 : dataLen] is divided by divisor[0 : degree] is stored in result[0 : degree].
testable void calcReedSolomonRemainder(const uint8_t data[], int dataLen, // 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[]) { const uint8_t generator[], int degree, uint8_t result[]) {
// Perform polynomial division
assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX); assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX);
memset(result, 0, degree * sizeof(result[0])); 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]; uint8_t factor = data[i] ^ result[0];
memmove(&result[0], &result[1], (degree - 1) * sizeof(result[0])); memmove(&result[0], &result[1], (degree - 1) * sizeof(result[0]));
result[degree - 1] = 0; result[degree - 1] = 0;
for (int j = 0; j < degree; j++) 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). // 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. // 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 // Russian peasant multiplication
uint8_t z = 0; uint8_t z = 0;
for (int i = 7; i >= 0; i--) { for (int i = 7; i >= 0; i--) {

Loading…
Cancel
Save