|
|
|
@ -31,6 +31,7 @@
|
|
|
|
|
|
|
|
|
|
/*---- Forward declarations for private functions ----*/
|
|
|
|
|
|
|
|
|
|
static int fitVersionToData(int minVersion, int maxVersion, enum qrcodegen_Ecc ecl, int dataLen, int dataBitLen, int ver1To9LenBits, int ver10To26LenBits, int ver27To40LenBits);
|
|
|
|
|
static void encodeQrCodeTail(uint8_t dataAndQrcode[], int bitLen, uint8_t tempBuffer[], int version, enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, bool boostEcl);
|
|
|
|
|
static long getPenaltyScore(const uint8_t qrcode[], int qrsize);
|
|
|
|
|
static void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen);
|
|
|
|
@ -128,31 +129,14 @@ int qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[
|
|
|
|
|
return qrcodegen_encodeBinary(tempBuffer, (size_t)textLen, qrcode, ecl, minVersion, maxVersion, mask, boostEcl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int version;
|
|
|
|
|
int dataUsedBits = -1;
|
|
|
|
|
int dataCapacityBits = -1;
|
|
|
|
|
int lengthBits = -1;
|
|
|
|
|
for (version = minVersion; ; version++) {
|
|
|
|
|
if (version <= 9)
|
|
|
|
|
lengthBits = isNumeric ? 10 : 9;
|
|
|
|
|
else if (version <= 26)
|
|
|
|
|
lengthBits = isNumeric ? 12 : 11;
|
|
|
|
|
else
|
|
|
|
|
lengthBits = isNumeric ? 14 : 13;
|
|
|
|
|
if (textLen < (1 << lengthBits)) {
|
|
|
|
|
dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
|
|
|
|
|
dataUsedBits = checkedAdd(4 + lengthBits, textBits);
|
|
|
|
|
if (0 <= dataUsedBits && 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
|
|
|
|
|
int version = fitVersionToData(minVersion, maxVersion, ecl, textLen, textBits,
|
|
|
|
|
(isNumeric ? 10 : 9), (isNumeric ? 12 : 11), (isNumeric ? 14 : 13));
|
|
|
|
|
if (version == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
assert(dataUsedBits >= 0 && dataCapacityBits >= 0);
|
|
|
|
|
|
|
|
|
|
memset(qrcode, 0, qrcodegen_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0]));
|
|
|
|
|
int bitLen = 0;
|
|
|
|
|
appendBitsToBuffer(isNumeric ? 1 : 2, 4, qrcode, &bitLen);
|
|
|
|
|
int lengthBits = (version <= 9 ? 9 : (version <= 26 ? 11 : 13)) + (isNumeric ? 1 : 0);
|
|
|
|
|
appendBitsToBuffer((unsigned int)textLen, lengthBits, qrcode, &bitLen);
|
|
|
|
|
if (isNumeric) {
|
|
|
|
|
int accumData = 0;
|
|
|
|
@ -193,25 +177,13 @@ int qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode
|
|
|
|
|
enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl) {
|
|
|
|
|
assert(qrcodegen_VERSION_MIN <= minVersion && minVersion <= maxVersion && maxVersion <= qrcodegen_VERSION_MAX);
|
|
|
|
|
assert(0 <= (int)ecl && (int)ecl <= 3 && -1 <= (int)mask && (int)mask <= 7);
|
|
|
|
|
if (dataLen > INT16_MAX)
|
|
|
|
|
if (dataLen > INT16_MAX / 8)
|
|
|
|
|
return 0;
|
|
|
|
|
// Now dataLen <= INT_MAX, since int has at least 16 bits
|
|
|
|
|
|
|
|
|
|
int version;
|
|
|
|
|
int dataUsedBits = -1;
|
|
|
|
|
int dataCapacityBits = -1;
|
|
|
|
|
for (version = minVersion; ; version++) {
|
|
|
|
|
if ((version <= 9 && dataLen < (1U << 8)) || dataLen < (1U << 16)) {
|
|
|
|
|
dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
|
|
|
|
|
dataUsedBits = checkedAdd(4 + (version <= 9 ? 8 : 16), checkedMultiply((int)dataLen, 8));
|
|
|
|
|
if (0 <= dataUsedBits && 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
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
assert(dataUsedBits >= 0 && dataCapacityBits >= 0);
|
|
|
|
|
// Now dataLen * 8 <= 65535 <= INT_MAX
|
|
|
|
|
|
|
|
|
|
int version = fitVersionToData(minVersion, maxVersion, ecl, (int)dataLen, (int)dataLen * 8, 8, 16, 16);
|
|
|
|
|
if (version == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
memset(qrcode, 0, qrcodegen_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0]));
|
|
|
|
|
int bitLen = 0;
|
|
|
|
|
appendBitsToBuffer(4, 4, qrcode, &bitLen);
|
|
|
|
@ -223,6 +195,34 @@ int qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int fitVersionToData(int minVersion, int maxVersion, enum qrcodegen_Ecc ecl,
|
|
|
|
|
int dataLen, int dataBitLen, int ver1To9LenBits, int ver10To26LenBits, int ver27To40LenBits) {
|
|
|
|
|
|
|
|
|
|
assert(qrcodegen_VERSION_MIN <= minVersion && minVersion <= maxVersion && maxVersion <= qrcodegen_VERSION_MAX);
|
|
|
|
|
assert(0 <= (int)ecl && (int)ecl <= 3);
|
|
|
|
|
assert(dataLen >= 0 && dataBitLen >= 0);
|
|
|
|
|
assert(1 <= ver1To9LenBits && ver1To9LenBits <= 16);
|
|
|
|
|
assert(1 <= ver10To26LenBits && ver10To26LenBits <= 16);
|
|
|
|
|
assert(1 <= ver27To40LenBits && ver27To40LenBits <= 16);
|
|
|
|
|
|
|
|
|
|
for (int version = minVersion; ; version++) {
|
|
|
|
|
int lengthBits;
|
|
|
|
|
if (version <= 9) lengthBits = ver1To9LenBits;
|
|
|
|
|
else if (version <= 26) lengthBits = ver10To26LenBits;
|
|
|
|
|
else lengthBits = ver27To40LenBits;
|
|
|
|
|
|
|
|
|
|
if (dataLen >= (1L << lengthBits))
|
|
|
|
|
continue;
|
|
|
|
|
int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
|
|
|
|
|
int dataUsedBits = checkedAdd(4 + lengthBits, dataBitLen);
|
|
|
|
|
if (0 <= dataUsedBits && dataUsedBits <= dataCapacityBits)
|
|
|
|
|
return version; // This version number is found to be suitable
|
|
|
|
|
if (version >= maxVersion) // All versions in the range could not fit the given data
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Given data codewords in dataAndQrcode already padded to the length specified by the
|
|
|
|
|
// version and ECC level, this function adds ECC bytes, interleaves blocks, renders the
|
|
|
|
|
// QR Code symbol back to the array dataAndQrcode, and handles automatic mask selection.
|
|
|
|
|