diff --git a/c/qrcodegen.c b/c/qrcodegen.c index 386fd1e..eac0a21 100644 --- a/c/qrcodegen.c +++ b/c/qrcodegen.c @@ -914,7 +914,6 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz } // Concatenate all segments to create the data bit string - int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; memset(qrcode, 0, qrcodegen_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0])); int bitLen = 0; for (size_t i = 0; i < len; i++) { @@ -935,16 +934,18 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz } // Add terminator and pad up to a byte if applicable + int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; + 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); - // Pad with alternate bytes until data capacity is reached + // Pad with alternating bytes until data capacity is reached for (uint8_t padByte = 0xEC; bitLen < dataCapacityBits; padByte ^= 0xEC ^ 0x11) appendBitsToBuffer(padByte, 8, qrcode, &bitLen); - assert(bitLen % 8 == 0); // Draw function and data codeword modules addEccAndInterleave(qrcode, version, ecl, tempBuffer); diff --git a/cpp/QrCode.cpp b/cpp/QrCode.cpp index 6ddb0c7..99bdd11 100644 --- a/cpp/QrCode.cpp +++ b/cpp/QrCode.cpp @@ -87,7 +87,6 @@ QrCode QrCode::encodeSegments(const vector &segs, Ecc ecl, } // Concatenate all segments to create the data bit string - size_t dataCapacityBits = getNumDataCodewords(version, ecl) * 8; BitBuffer bb; for (const QrSegment &seg : segs) { bb.appendBits(seg.getMode().getModeBits(), 4); @@ -96,15 +95,18 @@ QrCode QrCode::encodeSegments(const vector &segs, Ecc ecl, } // Add terminator and pad up to a byte if applicable + size_t dataCapacityBits = getNumDataCodewords(version, ecl) * 8; + if (bb.size() > dataCapacityBits) + throw std::logic_error("Assertion error"); bb.appendBits(0, std::min(4, dataCapacityBits - bb.size())); bb.appendBits(0, (8 - bb.size() % 8) % 8); - - // Pad with alternate bytes until data capacity is reached - for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; padByte ^= 0xEC ^ 0x11) - bb.appendBits(padByte, 8); if (bb.size() % 8 != 0) throw std::logic_error("Assertion error"); + // Pad with alternating bytes until data capacity is reached + for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; padByte ^= 0xEC ^ 0x11) + bb.appendBits(padByte, 8); + // Create the QR Code symbol return QrCode(version, ecl, bb.getBytes(), mask); } diff --git a/java/io/nayuki/qrcodegen/QrCode.java b/java/io/nayuki/qrcodegen/QrCode.java index d46bdd3..225f2e7 100644 --- a/java/io/nayuki/qrcodegen/QrCode.java +++ b/java/io/nayuki/qrcodegen/QrCode.java @@ -141,7 +141,6 @@ public final class QrCode { } // Concatenate all segments to create the data bit string - int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; BitBuffer bb = new BitBuffer(); for (QrSegment seg : segs) { bb.appendBits(seg.mode.modeBits, 4); @@ -150,13 +149,15 @@ public final class QrCode { } // Add terminator and pad up to a byte if applicable + int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; + assert bb.bitLength() <= dataCapacityBits; bb.appendBits(0, Math.min(4, dataCapacityBits - bb.bitLength())); bb.appendBits(0, (8 - bb.bitLength() % 8) % 8); + assert bb.bitLength() % 8 == 0; - // Pad with alternate bytes until data capacity is reached + // Pad with alternating bytes until data capacity is reached for (int padByte = 0xEC; bb.bitLength() < dataCapacityBits; padByte ^= 0xEC ^ 0x11) bb.appendBits(padByte, 8); - assert bb.bitLength() % 8 == 0; // Create the QR Code symbol return new QrCode(version, ecl, bb.getBytes(), mask); diff --git a/javascript/qrcodegen.js b/javascript/qrcodegen.js index 8da8e89..2f9579f 100644 --- a/javascript/qrcodegen.js +++ b/javascript/qrcodegen.js @@ -554,7 +554,6 @@ var qrcodegen = new function() { }); // Concatenate all segments to create the data bit string - var dataCapacityBits = QrCode.getNumDataCodewords(version, ecl) * 8; var bb = new BitBuffer(); segs.forEach(function(seg) { bb.appendBits(seg.mode.modeBits, 4); @@ -565,15 +564,18 @@ var qrcodegen = new function() { }); // Add terminator and pad up to a byte if applicable + var dataCapacityBits = QrCode.getNumDataCodewords(version, ecl) * 8; + if (bb.length > dataCapacityBits) + throw "Assertion error"; bb.appendBits(0, Math.min(4, dataCapacityBits - bb.length)); bb.appendBits(0, (8 - bb.length % 8) % 8); - - // Pad with alternate bytes until data capacity is reached - for (var padByte = 0xEC; bb.length < dataCapacityBits; padByte ^= 0xEC ^ 0x11) - bb.appendBits(padByte, 8); if (bb.length % 8 != 0) throw "Assertion error"; + // Pad with alternating bytes until data capacity is reached + for (var padByte = 0xEC; bb.length < dataCapacityBits; padByte ^= 0xEC ^ 0x11) + bb.appendBits(padByte, 8); + // Create the QR Code symbol return new this(bb.getBytes(), mask, version, ecl); }; diff --git a/python/qrcodegen.py b/python/qrcodegen.py index 3399821..8e297af 100644 --- a/python/qrcodegen.py +++ b/python/qrcodegen.py @@ -116,7 +116,6 @@ class QrCode(object): ecl = newecl # Concatenate all segments to create the data bit string - datacapacitybits = QrCode._get_num_data_codewords(version, ecl) * 8 bb = _BitBuffer() for seg in segs: bb.append_bits(seg.get_mode().get_mode_bits(), 4) @@ -124,15 +123,17 @@ class QrCode(object): bb.extend(seg._bitdata) # Add terminator and pad up to a byte if applicable + datacapacitybits = QrCode._get_num_data_codewords(version, ecl) * 8 + assert len(bb) <= datacapacitybits bb.append_bits(0, min(4, datacapacitybits - len(bb))) bb.append_bits(0, -len(bb) % 8) # Note: Python's modulo on negative numbers behaves better than C family languages + assert len(bb) % 8 == 0 - # Pad with alternate bytes until data capacity is reached + # Pad with alternating bytes until data capacity is reached for padbyte in itertools.cycle((0xEC, 0x11)): if len(bb) >= datacapacitybits: break bb.append_bits(padbyte, 8) - assert len(bb) % 8 == 0 # Create the QR Code symbol return QrCode(bb.get_bytes(), mask, version, ecl) diff --git a/rust/src/lib.rs b/rust/src/lib.rs index 589c01b..82abe1d 100644 --- a/rust/src/lib.rs +++ b/rust/src/lib.rs @@ -130,7 +130,6 @@ impl QrCode { } // Concatenate all segments to create the data bit string - let datacapacitybits: usize = QrCode::get_num_data_codewords(version, ecl) * 8; let mut bb = BitBuffer(Vec::new()); for seg in segs { bb.append_bits(seg.mode.mode_bits(), 4); @@ -139,19 +138,21 @@ impl QrCode { } // Add terminator and pad up to a byte if applicable + let datacapacitybits: usize = QrCode::get_num_data_codewords(version, ecl) * 8; + assert!(bb.0.len() <= datacapacitybits); let numzerobits = std::cmp::min(4, datacapacitybits - bb.0.len()); bb.append_bits(0, numzerobits as u8); let numzerobits = bb.0.len().wrapping_neg() & 7; bb.append_bits(0, numzerobits as u8); + assert_eq!(bb.0.len() % 8, 0, "Assertion error"); - // Pad with alternate bytes until data capacity is reached + // Pad with alternating bytes until data capacity is reached for padbyte in [0xEC, 0x11].iter().cycle() { if bb.0.len() >= datacapacitybits { break; } bb.append_bits(*padbyte, 8); } - assert_eq!(bb.0.len() % 8, 0, "Assertion error"); let mut bytes = vec![0u8; bb.0.len() / 8]; for (i, bit) in bb.0.iter().enumerate() { diff --git a/typescript/qrcodegen.ts b/typescript/qrcodegen.ts index 0c19436..c1e4862 100644 --- a/typescript/qrcodegen.ts +++ b/typescript/qrcodegen.ts @@ -101,7 +101,6 @@ namespace qrcodegen { }); // Concatenate all segments to create the data bit string - let dataCapacityBits: int = QrCode.getNumDataCodewords(version, ecl) * 8; let bb = new BitBuffer(); segs.forEach((seg: QrSegment) => { bb.appendBits(seg.mode.modeBits, 4); @@ -111,15 +110,18 @@ namespace qrcodegen { }); // Add terminator and pad up to a byte if applicable + let dataCapacityBits: int = QrCode.getNumDataCodewords(version, ecl) * 8; + if (bb.length > dataCapacityBits) + throw "Assertion error"; bb.appendBits(0, Math.min(4, dataCapacityBits - bb.length)); bb.appendBits(0, (8 - bb.length % 8) % 8); - - // Pad with alternate bytes until data capacity is reached - for (let padByte = 0xEC; bb.length < dataCapacityBits; padByte ^= 0xEC ^ 0x11) - bb.appendBits(padByte, 8); if (bb.length % 8 != 0) throw "Assertion error"; + // Pad with alternating bytes until data capacity is reached + for (let padByte = 0xEC; bb.length < dataCapacityBits; padByte ^= 0xEC ^ 0x11) + bb.appendBits(padByte, 8); + // Create the QR Code symbol return new QrCode(bb.getBytes(), mask, version, ecl); }