diff --git a/c/qrcodegen.c b/c/qrcodegen.c index 8617044..c2e9381 100644 --- a/c/qrcodegen.c +++ b/c/qrcodegen.c @@ -21,7 +21,12 @@ * Software. */ + +#ifndef ASSERT #include +#define ASSERT(expression) assert(expression) +#endif // ASSERT + #include #include #include @@ -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 } }