Refactored C code to split out text properties into new function, and tweaked logic for clarity.

This commit is contained in:
Project Nayuki 2017-04-20 16:23:01 +00:00
parent 2ffc439340
commit af67fe1c0b
1 changed files with 41 additions and 21 deletions

View File

@ -37,6 +37,7 @@
// Also, each of these functions allocate only a small constant amount of memory on the stack,
// they don't allocate or free anything on the heap, and they are thread-safe.
static int getTextProperties(const char *text, bool *isNumeric, bool *isAlphanumeric, int *textBits);
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);
@ -102,34 +103,20 @@ int qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[
assert(0 <= (int)ecl && (int)ecl <= 3 && -1 <= (int)mask && (int)mask <= 7);
// Get text properties
int textLen = 0;
bool isNumeric = true;
bool isAlphanumeric = true;
for (const char *p = text; *p != '\0'; p++, textLen++) { // Read every character
if (textLen == INT16_MAX) // Note: INT16_MAX <= INT_MAX && INT16_MAX <= SIZE_MAX
bool isNumeric, isAlphanumeric;
int textBits;
int textLen = getTextProperties(text, &isNumeric, &isAlphanumeric, &textBits);
if (textLen < 0)
return 0;
char c = *p;
if (c < '0' || c > '9') {
isNumeric = false;
isAlphanumeric &= strchr(ALPHANUMERIC_CHARSET, c) != NULL;
}
}
long textBits;
if (isNumeric)
textBits = textLen * 3L + (textLen + 2L) / 3;
else if (isAlphanumeric)
textBits = textLen * 5L + (textLen + 1L) / 2;
else { // Use binary mode
// Use binary mode or find version
if (!isAlphanumeric) {
if (textLen > qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion))
return 0;
for (int i = 0; i < textLen; i++)
tempBuffer[i] = (uint8_t)text[i];
return qrcodegen_encodeBinary(tempBuffer, (size_t)textLen, qrcode, ecl, minVersion, maxVersion, mask, boostEcl);
}
if (textBits > INT_MAX)
return 0;
int version = fitVersionToData(minVersion, maxVersion, ecl, textLen, (int)textBits,
(isNumeric ? 10 : 9), (isNumeric ? 12 : 11), (isNumeric ? 14 : 13));
if (version == 0)
@ -179,6 +166,39 @@ int qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[
}
// Scans the given string, returns the number of characters, and sets output variables.
// Returns a negative number if the length would exceed INT16_MAX or textBits would exceed INT_MAX.
// Note that INT16_MAX <= 32767 <= INT_MAX and INT16_MAX < 65535 <= SIZE_MAX.
// If the return value is negative, then the pointees of output arguments might not be set.
static int getTextProperties(const char *text, bool *isNumeric, bool *isAlphanumeric, int *textBits) {
int textLen = 0;
*isNumeric = true;
*isAlphanumeric = true;
for (const char *p = text; *p != '\0'; p++, textLen++) { // Read every character
if (textLen >= INT16_MAX)
return -1;
char c = *p;
if (c < '0' || c > '9') {
*isNumeric = false;
*isAlphanumeric &= strchr(ALPHANUMERIC_CHARSET, c) != NULL;
}
}
long tempBits;
if (isNumeric)
tempBits = textLen * 3L + (textLen + 2L) / 3;
else if (isAlphanumeric)
tempBits = textLen * 5L + (textLen + 1L) / 2;
else // Binary mode
tempBits = textLen * 8L;
if (tempBits > INT_MAX)
return -1;
*textBits = (int)tempBits;
return textLen;
}
// Public function - see documentation comment in header file.
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) {