Simplified the arithmetic of an internal C function.

pull/39/merge
Project Nayuki 6 years ago
parent a19c7aa21b
commit aa264f5a4d

@ -714,48 +714,28 @@ size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars
// - For ECI mode, numChars must be 0, and the worst-case number of bits is returned. // - For ECI mode, numChars must be 0, and the worst-case number of bits is returned.
// An actual ECI segment can have shorter data. For non-ECI modes, the result is exact. // An actual ECI segment can have shorter data. For non-ECI modes, the result is exact.
testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars) { testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars) {
const int LIMIT = INT16_MAX; // Can be configured as high as INT_MAX // All calculations are designed to avoid overflow on all platforms
if (numChars > (unsigned int)LIMIT) if (numChars > (unsigned int)INT16_MAX)
return -1; return -1;
int n = (int)numChars; long result = (long)numChars;
if (mode == qrcodegen_Mode_NUMERIC)
int result; result = (result * 10 + 2) / 3; // ceil(10/3 * n)
if (mode == qrcodegen_Mode_NUMERIC) { else if (mode == qrcodegen_Mode_ALPHANUMERIC)
// n * 3 + ceil(n / 3) result = (result * 11 + 1) / 2; // ceil(11/2 * n)
if (n > LIMIT / 3) else if (mode == qrcodegen_Mode_BYTE)
goto overflow; result *= 8;
result = n * 3; else if (mode == qrcodegen_Mode_KANJI)
int temp = n / 3 + (n % 3 > 0 ? 1 : 0); result *= 13;
if (temp > LIMIT - result) else if (mode == qrcodegen_Mode_ECI && numChars == 0)
goto overflow;
result += temp;
} else if (mode == qrcodegen_Mode_ALPHANUMERIC) {
// n * 5 + ceil(n / 2)
if (n > LIMIT / 5)
goto overflow;
result = n * 5;
int temp = n / 2 + n % 2;
if (temp > LIMIT - result)
goto overflow;
result += temp;
} else if (mode == qrcodegen_Mode_BYTE) {
if (n > LIMIT / 8)
goto overflow;
result = n * 8;
} else if (mode == qrcodegen_Mode_KANJI) {
if (n > LIMIT / 13)
goto overflow;
result = n * 13;
} else if (mode == qrcodegen_Mode_ECI && numChars == 0)
result = 3 * 8; result = 3 * 8;
else { else { // Invalid argument
assert(false); assert(false);
return -1; return -1;
} }
assert(0 <= result && result <= LIMIT); assert(result >= 0);
return result; if (result > (unsigned int)INT16_MAX)
overflow: return -1;
return -1; return (int)result;
} }

Loading…
Cancel
Save