Allow the assert to be redefined

The C code is very clean but it depends on the system assert which can print and abort the process. This is not always acceptable, so this change defines a `ASSERT` macro that can be redefined to something else to avoid the dependency on the system `assert`, even while debugging.
pull/165/head
Gaspard Petit 3 years ago
parent 0dbd3b2133
commit e237eb0d0b

@ -21,7 +21,12 @@
* Software.
*/
#ifndef ASSERT
#include <assert.h>
#define ASSERT(expression) assert(expression)
#endif // ASSERT
#include <limits.h>
#include <stdlib.h>
#include <string.h>
@ -183,7 +188,7 @@ bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcod
// Appends the given number of low-order bits of the given value to the given byte-based
// bit buffer, increasing the bit length. Requires 0 <= numBits <= 16 and val < 2^numBits.
testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen) {
assert(0 <= numBits && numBits <= 16 && (unsigned long)val >> numBits == 0);
ASSERT(0 <= numBits && numBits <= 16 && (unsigned long)val >> numBits == 0);
for (int i = numBits - 1; i >= 0; i--, (*bitLen)++)
buffer[*bitLen >> 3] |= ((val >> i) & 1) << (7 - (*bitLen & 7));
}
@ -203,9 +208,9 @@ bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len,
// Public function - see documentation comment in header file.
bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl,
int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl, uint8_t tempBuffer[], uint8_t qrcode[]) {
assert(segs != NULL || len == 0);
assert(qrcodegen_VERSION_MIN <= minVersion && minVersion <= maxVersion && maxVersion <= qrcodegen_VERSION_MAX);
assert(0 <= (int)ecl && (int)ecl <= 3 && -1 <= (int)mask && (int)mask <= 7);
ASSERT(segs != NULL || len == 0);
ASSERT(qrcodegen_VERSION_MIN <= minVersion && minVersion <= maxVersion && maxVersion <= qrcodegen_VERSION_MAX);
ASSERT(0 <= (int)ecl && (int)ecl <= 3 && -1 <= (int)mask && (int)mask <= 7);
// Find the minimal version number to use
int version, dataUsedBits;
@ -219,7 +224,7 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz
return false;
}
}
assert(dataUsedBits != -1);
ASSERT(dataUsedBits != -1);
// Increase the error correction level while the data still fits in the current version number
for (int i = (int)qrcodegen_Ecc_MEDIUM; i <= (int)qrcodegen_Ecc_HIGH; i++) { // From low to high
@ -239,17 +244,17 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz
appendBitsToBuffer((unsigned int)bit, 1, qrcode, &bitLen);
}
}
assert(bitLen == dataUsedBits);
ASSERT(bitLen == dataUsedBits);
// Add terminator and pad up to a byte if applicable
int dataCapacityBits = getNumDataCodewords(version, ecl) * 8;
assert(bitLen <= dataCapacityBits);
ASSERT(bitLen <= dataCapacityBits);
int terminatorBits = dataCapacityBits - bitLen;
if (terminatorBits > 4)
terminatorBits = 4;
appendBitsToBuffer(0, terminatorBits, qrcode, &bitLen);
appendBitsToBuffer(0, (8 - bitLen % 8) % 8, qrcode, &bitLen);
assert(bitLen % 8 == 0);
ASSERT(bitLen % 8 == 0);
// Pad with alternating bytes until data capacity is reached
for (uint8_t padByte = 0xEC; bitLen < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
@ -277,7 +282,7 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz
applyMask(tempBuffer, qrcode, msk); // Undoes the mask due to XOR
}
}
assert(0 <= (int)mask && (int)mask <= 7);
ASSERT(0 <= (int)mask && (int)mask <= 7);
applyMask(tempBuffer, qrcode, mask); // Apply the final choice of mask
drawFormatBits(ecl, mask, qrcode); // Overwrite old format bits
return true;
@ -293,7 +298,7 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz
// be clobbered by this function. The final answer is stored in result[0 : rawCodewords].
testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]) {
// Calculate parameter numbers
assert(0 <= (int)ecl && (int)ecl < 4 && qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX);
ASSERT(0 <= (int)ecl && (int)ecl < 4 && qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX);
int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[(int)ecl][version];
int blockEccLen = ECC_CODEWORDS_PER_BLOCK [(int)ecl][version];
int rawCodewords = getNumRawDataModules(version) / 8;
@ -326,7 +331,7 @@ testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ec
// for the given version number and error correction level. The result is in the range [9, 2956].
testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl) {
int v = version, e = (int)ecl;
assert(0 <= e && e < 4);
ASSERT(0 <= e && e < 4);
return getNumRawDataModules(v) / 8
- ECC_CODEWORDS_PER_BLOCK [e][v]
* NUM_ERROR_CORRECTION_BLOCKS[e][v];
@ -337,7 +342,7 @@ testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl) {
// all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
// The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
testable int getNumRawDataModules(int ver) {
assert(qrcodegen_VERSION_MIN <= ver && ver <= qrcodegen_VERSION_MAX);
ASSERT(qrcodegen_VERSION_MIN <= ver && ver <= qrcodegen_VERSION_MAX);
int result = (16 * ver + 128) * ver + 64;
if (ver >= 2) {
int numAlign = ver / 7 + 2;
@ -345,7 +350,7 @@ testable int getNumRawDataModules(int ver) {
if (ver >= 7)
result -= 36;
}
assert(208 <= result && result <= 29648);
ASSERT(208 <= result && result <= 29648);
return result;
}
@ -356,7 +361,7 @@ testable int getNumRawDataModules(int ver) {
// 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);
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, (size_t)degree * sizeof(result[0]));
@ -383,7 +388,7 @@ testable void reedSolomonComputeDivisor(int degree, uint8_t result[]) {
// 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[]) {
assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX);
ASSERT(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX);
memset(result, 0, (size_t)degree * sizeof(result[0]));
for (int i = 0; i < dataLen; i++) { // Polynomial division
uint8_t factor = data[i] ^ result[0];
@ -495,7 +500,7 @@ static void drawLightFunctionModules(uint8_t qrcode[], int version) {
for (int i = 0; i < 12; i++)
rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
long bits = (long)version << 12 | rem; // uint18
assert(bits >> 18 == 0);
ASSERT(bits >> 18 == 0);
// Draw two copies
for (int i = 0; i < 6; i++) {
@ -515,14 +520,14 @@ static void drawLightFunctionModules(uint8_t qrcode[], int version) {
// the format bits, unlike drawLightFunctionModules() which might skip dark modules.
static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[]) {
// Calculate error correction code and pack bits
assert(0 <= (int)mask && (int)mask <= 7);
ASSERT(0 <= (int)mask && (int)mask <= 7);
static const int table[] = {1, 0, 3, 2};
int data = table[(int)ecl] << 3 | (int)mask; // errCorrLvl is uint2, mask is uint3
int rem = data;
for (int i = 0; i < 10; i++)
rem = (rem << 1) ^ ((rem >> 9) * 0x537);
int bits = (data << 10 | rem) ^ 0x5412; // uint15
assert(bits >> 15 == 0);
ASSERT(bits >> 15 == 0);
// Draw first copy
for (int i = 0; i <= 5; i++)
@ -596,7 +601,7 @@ static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]) {
}
}
}
assert(i == dataLen * 8);
ASSERT(i == dataLen * 8);
}
@ -606,7 +611,7 @@ static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]) {
// the same mask value a second time will undo the mask. A final well-formed
// QR Code needs exactly one (not zero, two, etc.) mask applied.
static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qrcodegen_Mask mask) {
assert(0 <= (int)mask && (int)mask <= 7); // Disallows qrcodegen_Mask_AUTO
ASSERT(0 <= (int)mask && (int)mask <= 7); // Disallows qrcodegen_Mask_AUTO
int qrsize = qrcodegen_getSize(qrcode);
for (int y = 0; y < qrsize; y++) {
for (int x = 0; x < qrsize; x++) {
@ -622,7 +627,7 @@ static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qr
case 5: invert = x * y % 2 + x * y % 3 == 0; break;
case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
default: assert(false); return;
default: ASSERT(false); return;
}
bool val = getModuleBounded(qrcode, x, y);
setModuleBounded(qrcode, x, y, val ^ invert);
@ -704,9 +709,9 @@ static long getPenaltyScore(const uint8_t qrcode[]) {
int total = qrsize * qrsize; // Note that size is odd, so dark/total != 1/2
// Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)%
int k = (int)((labs(dark * 20L - total * 10L) + total - 1) / total) - 1;
assert(0 <= k && k <= 9);
ASSERT(0 <= k && k <= 9);
result += k * PENALTY_N4;
assert(0 <= result && result <= 2568888L); // Non-tight upper bound based on default values of PENALTY_N1, ..., N4
ASSERT(0 <= result && result <= 2568888L); // Non-tight upper bound based on default values of PENALTY_N1, ..., N4
return result;
}
@ -715,7 +720,7 @@ static long getPenaltyScore(const uint8_t qrcode[]) {
// returns either 0, 1, or 2. A helper function for getPenaltyScore().
static int finderPenaltyCountPatterns(const int runHistory[7], int qrsize) {
int n = runHistory[1];
assert(n <= qrsize * 3); (void)qrsize;
ASSERT(n <= qrsize * 3); (void)qrsize;
bool core = n > 0 && runHistory[2] == n && runHistory[3] == n * 3 && runHistory[4] == n && runHistory[5] == n;
// The maximum QR Code size is 177, hence the dark run length n <= 177.
// Arithmetic is promoted to int, so n*4 will not overflow.
@ -750,9 +755,9 @@ static void finderPenaltyAddHistory(int currentRunLength, int runHistory[7], int
// Public function - see documentation comment in header file.
int qrcodegen_getSize(const uint8_t qrcode[]) {
assert(qrcode != NULL);
ASSERT(qrcode != NULL);
int result = qrcode[0];
assert((qrcodegen_VERSION_MIN * 4 + 17) <= result
ASSERT((qrcodegen_VERSION_MIN * 4 + 17) <= result
&& result <= (qrcodegen_VERSION_MAX * 4 + 17));
return result;
}
@ -760,7 +765,7 @@ int qrcodegen_getSize(const uint8_t qrcode[]) {
// Public function - see documentation comment in header file.
bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y) {
assert(qrcode != NULL);
ASSERT(qrcode != NULL);
int qrsize = qrcode[0];
return (0 <= x && x < qrsize && 0 <= y && y < qrsize) && getModuleBounded(qrcode, x, y);
}
@ -769,7 +774,7 @@ bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y) {
// Returns the color of the module at the given coordinates, which must be in bounds.
testable bool getModuleBounded(const uint8_t qrcode[], int x, int y) {
int qrsize = qrcode[0];
assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize);
ASSERT(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize);
int index = y * qrsize + x;
return getBit(qrcode[(index >> 3) + 1], index & 7);
}
@ -778,7 +783,7 @@ testable bool getModuleBounded(const uint8_t qrcode[], int x, int y) {
// Sets the color of the module at the given coordinates, which must be in bounds.
testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isDark) {
int qrsize = qrcode[0];
assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize);
ASSERT(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize);
int index = y * qrsize + x;
int bitIndex = index & 7;
int byteIndex = (index >> 3) + 1;
@ -808,7 +813,7 @@ static bool getBit(int x, int i) {
// Public function - see documentation comment in header file.
bool qrcodegen_isNumeric(const char *text) {
assert(text != NULL);
ASSERT(text != NULL);
for (; *text != '\0'; text++) {
if (*text < '0' || *text > '9')
return false;
@ -819,7 +824,7 @@ bool qrcodegen_isNumeric(const char *text) {
// Public function - see documentation comment in header file.
bool qrcodegen_isAlphanumeric(const char *text) {
assert(text != NULL);
ASSERT(text != NULL);
for (; *text != '\0'; text++) {
if (strchr(ALPHANUMERIC_CHARSET, *text) == NULL)
return false;
@ -833,7 +838,7 @@ size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars
int temp = calcSegmentBitLength(mode, numChars);
if (temp == -1)
return SIZE_MAX;
assert(0 <= temp && temp <= INT16_MAX);
ASSERT(0 <= temp && temp <= INT16_MAX);
return ((size_t)temp + 7) / 8;
}
@ -862,10 +867,10 @@ testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars) {
else if (mode == qrcodegen_Mode_ECI && numChars == 0)
result = 3 * 8;
else { // Invalid argument
assert(false);
ASSERT(false);
return -1;
}
assert(result >= 0);
ASSERT(result >= 0);
if (result > INT16_MAX)
return -1;
return (int)result;
@ -874,11 +879,11 @@ testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars) {
// Public function - see documentation comment in header file.
struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]) {
assert(data != NULL || len == 0);
ASSERT(data != NULL || len == 0);
struct qrcodegen_Segment result;
result.mode = qrcodegen_Mode_BYTE;
result.bitLength = calcSegmentBitLength(result.mode, len);
assert(result.bitLength != -1);
ASSERT(result.bitLength != -1);
result.numChars = (int)len;
if (len > 0)
memcpy(buf, data, len * sizeof(buf[0]));
@ -889,12 +894,12 @@ struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, u
// Public function - see documentation comment in header file.
struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]) {
assert(digits != NULL);
ASSERT(digits != NULL);
struct qrcodegen_Segment result;
size_t len = strlen(digits);
result.mode = qrcodegen_Mode_NUMERIC;
int bitLen = calcSegmentBitLength(result.mode, len);
assert(bitLen != -1);
ASSERT(bitLen != -1);
result.numChars = (int)len;
if (bitLen > 0)
memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0]));
@ -904,7 +909,7 @@ struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]
int accumCount = 0;
for (; *digits != '\0'; digits++) {
char c = *digits;
assert('0' <= c && c <= '9');
ASSERT('0' <= c && c <= '9');
accumData = accumData * 10 + (unsigned int)(c - '0');
accumCount++;
if (accumCount == 3) {
@ -915,7 +920,7 @@ struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]
}
if (accumCount > 0) // 1 or 2 digits remaining
appendBitsToBuffer(accumData, accumCount * 3 + 1, buf, &result.bitLength);
assert(result.bitLength == bitLen);
ASSERT(result.bitLength == bitLen);
result.data = buf;
return result;
}
@ -923,12 +928,12 @@ struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]
// Public function - see documentation comment in header file.
struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]) {
assert(text != NULL);
ASSERT(text != NULL);
struct qrcodegen_Segment result;
size_t len = strlen(text);
result.mode = qrcodegen_Mode_ALPHANUMERIC;
int bitLen = calcSegmentBitLength(result.mode, len);
assert(bitLen != -1);
ASSERT(bitLen != -1);
result.numChars = (int)len;
if (bitLen > 0)
memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0]));
@ -938,7 +943,7 @@ struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t bu
int accumCount = 0;
for (; *text != '\0'; text++) {
const char *temp = strchr(ALPHANUMERIC_CHARSET, *text);
assert(temp != NULL);
ASSERT(temp != NULL);
accumData = accumData * 45 + (unsigned int)(temp - ALPHANUMERIC_CHARSET);
accumCount++;
if (accumCount == 2) {
@ -949,7 +954,7 @@ struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t bu
}
if (accumCount > 0) // 1 character remaining
appendBitsToBuffer(accumData, 6, buf, &result.bitLength);
assert(result.bitLength == bitLen);
ASSERT(result.bitLength == bitLen);
result.data = buf;
return result;
}
@ -962,7 +967,7 @@ struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]) {
result.numChars = 0;
result.bitLength = 0;
if (assignVal < 0)
assert(false);
ASSERT(false);
else if (assignVal < (1 << 7)) {
memset(buf, 0, 1 * sizeof(buf[0]));
appendBitsToBuffer((unsigned int)assignVal, 8, buf, &result.bitLength);
@ -976,7 +981,7 @@ struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]) {
appendBitsToBuffer((unsigned int)(assignVal >> 10), 11, buf, &result.bitLength);
appendBitsToBuffer((unsigned int)(assignVal & 0x3FF), 10, buf, &result.bitLength);
} else
assert(false);
ASSERT(false);
result.data = buf;
return result;
}
@ -986,22 +991,22 @@ struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]) {
// Returns a non-negative number if successful. Otherwise returns -1 if a segment has too
// many characters to fit its length field, or the total bits exceeds INT16_MAX.
testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version) {
assert(segs != NULL || len == 0);
ASSERT(segs != NULL || len == 0);
long result = 0;
for (size_t i = 0; i < len; i++) {
int numChars = segs[i].numChars;
int bitLength = segs[i].bitLength;
assert(0 <= numChars && numChars <= INT16_MAX);
assert(0 <= bitLength && bitLength <= INT16_MAX);
ASSERT(0 <= numChars && numChars <= INT16_MAX);
ASSERT(0 <= bitLength && bitLength <= INT16_MAX);
int ccbits = numCharCountBits(segs[i].mode, version);
assert(0 <= ccbits && ccbits <= 16);
ASSERT(0 <= ccbits && ccbits <= 16);
if (numChars >= (1L << ccbits))
return -1; // The segment's length doesn't fit the field's bit width
result += 4L + ccbits + bitLength;
if (result > INT16_MAX)
return -1; // The sum might overflow an int type
}
assert(0 <= result && result <= INT16_MAX);
ASSERT(0 <= result && result <= INT16_MAX);
return (int)result;
}
@ -1009,7 +1014,7 @@ testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int
// Returns the bit width of the character count field for a segment in the given mode
// in a QR Code at the given version number. The result is in the range [0, 16].
static int numCharCountBits(enum qrcodegen_Mode mode, int version) {
assert(qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX);
ASSERT(qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX);
int i = (version + 7) / 17;
switch (mode) {
case qrcodegen_Mode_NUMERIC : { static const int temp[] = {10, 12, 14}; return temp[i]; }
@ -1017,6 +1022,6 @@ static int numCharCountBits(enum qrcodegen_Mode mode, int version) {
case qrcodegen_Mode_BYTE : { static const int temp[] = { 8, 16, 16}; return temp[i]; }
case qrcodegen_Mode_KANJI : { static const int temp[] = { 8, 10, 12}; return temp[i]; }
case qrcodegen_Mode_ECI : return 0;
default: assert(false); return -1; // Dummy value
default: ASSERT(false); return -1; // Dummy value
}
}

Loading…
Cancel
Save