diff --git a/c/qrcodegen.c b/c/qrcodegen.c index 8617044..871bc92 100644 --- a/c/qrcodegen.c +++ b/c/qrcodegen.c @@ -93,6 +93,9 @@ static int numCharCountBits(enum qrcodegen_Mode mode, int version); // value maps to the index in the string. For checking text and encoding segments. static const char *ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; +// Sentinel value for use in only some functions. +#define LENGTH_OVERFLOW -1 + // For generating error correction codes. testable const int8_t ECC_CODEWORDS_PER_BLOCK[4][41] = { // Version: (note that index 0 is for padding, and is set to an illegal value) @@ -150,7 +153,7 @@ bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode tempBuffer[i] = (uint8_t)text[i]; seg.mode = qrcodegen_Mode_BYTE; seg.bitLength = calcSegmentBitLength(seg.mode, textLen); - if (seg.bitLength == -1) + if (seg.bitLength == LENGTH_OVERFLOW) goto fail; seg.numChars = (int)textLen; seg.data = tempBuffer; @@ -170,7 +173,7 @@ bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcod struct qrcodegen_Segment seg; seg.mode = qrcodegen_Mode_BYTE; seg.bitLength = calcSegmentBitLength(seg.mode, dataLen); - if (seg.bitLength == -1) { + if (seg.bitLength == LENGTH_OVERFLOW) { qrcode[0] = 0; // Set size to invalid value for safety return false; } @@ -212,14 +215,14 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz for (version = minVersion; ; version++) { int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available dataUsedBits = getTotalBits(segs, len, version); - if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits) + if (dataUsedBits != LENGTH_OVERFLOW && dataUsedBits <= dataCapacityBits) break; // This version number is found to be suitable if (version >= maxVersion) { // All versions in the range could not fit the given data qrcode[0] = 0; // Set size to invalid value for safety return false; } } - assert(dataUsedBits != -1); + assert(dataUsedBits != LENGTH_OVERFLOW); // 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 @@ -831,7 +834,7 @@ bool qrcodegen_isAlphanumeric(const char *text) { // Public function - see documentation comment in header file. size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars) { int temp = calcSegmentBitLength(mode, numChars); - if (temp == -1) + if (temp == LENGTH_OVERFLOW) return SIZE_MAX; assert(0 <= temp && temp <= INT16_MAX); return ((size_t)temp + 7) / 8; @@ -840,8 +843,8 @@ size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars // Returns the number of data bits needed to represent a segment // containing the given number of characters using the given mode. Notes: -// - Returns -1 on failure, i.e. numChars > INT16_MAX or -// the number of needed bits exceeds INT16_MAX (i.e. 32767). +// - Returns LENGTH_OVERFLOW on failure, i.e. numChars > INT16_MAX +// or the number of needed bits exceeds INT16_MAX (i.e. 32767). // - Otherwise, all valid results are in the range [0, INT16_MAX]. // - For byte mode, numChars measures the number of bytes, not Unicode code points. // - For ECI mode, numChars must be 0, and the worst-case number of bits is returned. @@ -849,7 +852,7 @@ size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars) { // All calculations are designed to avoid overflow on all platforms if (numChars > (unsigned int)INT16_MAX) - return -1; + return LENGTH_OVERFLOW; long result = (long)numChars; if (mode == qrcodegen_Mode_NUMERIC) result = (result * 10 + 2) / 3; // ceil(10/3 * n) @@ -863,11 +866,11 @@ testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars) { result = 3 * 8; else { // Invalid argument assert(false); - return -1; + return LENGTH_OVERFLOW; } assert(result >= 0); if (result > INT16_MAX) - return -1; + return LENGTH_OVERFLOW; return (int)result; } @@ -878,7 +881,7 @@ struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, u struct qrcodegen_Segment result; result.mode = qrcodegen_Mode_BYTE; result.bitLength = calcSegmentBitLength(result.mode, len); - assert(result.bitLength != -1); + assert(result.bitLength != LENGTH_OVERFLOW); result.numChars = (int)len; if (len > 0) memcpy(buf, data, len * sizeof(buf[0])); @@ -894,7 +897,7 @@ struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[] size_t len = strlen(digits); result.mode = qrcodegen_Mode_NUMERIC; int bitLen = calcSegmentBitLength(result.mode, len); - assert(bitLen != -1); + assert(bitLen != LENGTH_OVERFLOW); result.numChars = (int)len; if (bitLen > 0) memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0])); @@ -928,7 +931,7 @@ struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t bu size_t len = strlen(text); result.mode = qrcodegen_Mode_ALPHANUMERIC; int bitLen = calcSegmentBitLength(result.mode, len); - assert(bitLen != -1); + assert(bitLen != LENGTH_OVERFLOW); result.numChars = (int)len; if (bitLen > 0) memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0])); @@ -983,8 +986,8 @@ struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]) { // Calculates the number of bits needed to encode the given segments at the given version. -// 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. +// Returns a non-negative number if successful. Otherwise returns LENGTH_OVERFLOW 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); long result = 0; @@ -996,10 +999,10 @@ testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int int ccbits = numCharCountBits(segs[i].mode, version); assert(0 <= ccbits && ccbits <= 16); if (numChars >= (1L << ccbits)) - return -1; // The segment's length doesn't fit the field's bit width + return LENGTH_OVERFLOW; // 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 + return LENGTH_OVERFLOW; // The sum might overflow an int type } assert(0 <= result && result <= INT16_MAX); return (int)result; @@ -1020,3 +1023,6 @@ static int numCharCountBits(enum qrcodegen_Mode mode, int version) { default: assert(false); return -1; // Dummy value } } + + +#undef LENGTH_OVERFLOW