@ -21,7 +21,12 @@
* Software .
*/
# ifndef ASSERT
# include <assert.h>
# define ASSERT(expression) assert(expression)
# endif // ASSERT
# include <limits.h>
# include <stdlib.h>
# include <string.h>
@ -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
}
}