Tweaked code and comment in QrCode.encodeSegments() in all language versions.

This commit is contained in:
Project Nayuki 2018-08-26 02:03:27 +00:00
parent c9553ead71
commit c86dacacb7
7 changed files with 37 additions and 27 deletions

View File

@ -914,7 +914,6 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz
} }
// Concatenate all segments to create the data bit string // 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])); memset(qrcode, 0, qrcodegen_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0]));
int bitLen = 0; int bitLen = 0;
for (size_t i = 0; i < len; i++) { 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 // Add terminator and pad up to a byte if applicable
int dataCapacityBits = getNumDataCodewords(version, ecl) * 8;
assert(bitLen <= dataCapacityBits);
int terminatorBits = dataCapacityBits - bitLen; int terminatorBits = dataCapacityBits - bitLen;
if (terminatorBits > 4) if (terminatorBits > 4)
terminatorBits = 4; terminatorBits = 4;
appendBitsToBuffer(0, terminatorBits, qrcode, &bitLen); appendBitsToBuffer(0, terminatorBits, qrcode, &bitLen);
appendBitsToBuffer(0, (8 - bitLen % 8) % 8, 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) for (uint8_t padByte = 0xEC; bitLen < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
appendBitsToBuffer(padByte, 8, qrcode, &bitLen); appendBitsToBuffer(padByte, 8, qrcode, &bitLen);
assert(bitLen % 8 == 0);
// Draw function and data codeword modules // Draw function and data codeword modules
addEccAndInterleave(qrcode, version, ecl, tempBuffer); addEccAndInterleave(qrcode, version, ecl, tempBuffer);

View File

@ -87,7 +87,6 @@ QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl,
} }
// Concatenate all segments to create the data bit string // Concatenate all segments to create the data bit string
size_t dataCapacityBits = getNumDataCodewords(version, ecl) * 8;
BitBuffer bb; BitBuffer bb;
for (const QrSegment &seg : segs) { for (const QrSegment &seg : segs) {
bb.appendBits(seg.getMode().getModeBits(), 4); bb.appendBits(seg.getMode().getModeBits(), 4);
@ -96,15 +95,18 @@ QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl,
} }
// Add terminator and pad up to a byte if applicable // 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<size_t>(4, dataCapacityBits - bb.size())); bb.appendBits(0, std::min<size_t>(4, dataCapacityBits - bb.size()));
bb.appendBits(0, (8 - bb.size() % 8) % 8); 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) if (bb.size() % 8 != 0)
throw std::logic_error("Assertion error"); 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 // Create the QR Code symbol
return QrCode(version, ecl, bb.getBytes(), mask); return QrCode(version, ecl, bb.getBytes(), mask);
} }

View File

@ -141,7 +141,6 @@ public final class QrCode {
} }
// Concatenate all segments to create the data bit string // Concatenate all segments to create the data bit string
int dataCapacityBits = getNumDataCodewords(version, ecl) * 8;
BitBuffer bb = new BitBuffer(); BitBuffer bb = new BitBuffer();
for (QrSegment seg : segs) { for (QrSegment seg : segs) {
bb.appendBits(seg.mode.modeBits, 4); bb.appendBits(seg.mode.modeBits, 4);
@ -150,13 +149,15 @@ public final class QrCode {
} }
// Add terminator and pad up to a byte if applicable // 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, Math.min(4, dataCapacityBits - bb.bitLength()));
bb.appendBits(0, (8 - bb.bitLength() % 8) % 8); 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) for (int padByte = 0xEC; bb.bitLength() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
bb.appendBits(padByte, 8); bb.appendBits(padByte, 8);
assert bb.bitLength() % 8 == 0;
// Create the QR Code symbol // Create the QR Code symbol
return new QrCode(version, ecl, bb.getBytes(), mask); return new QrCode(version, ecl, bb.getBytes(), mask);

View File

@ -554,7 +554,6 @@ var qrcodegen = new function() {
}); });
// Concatenate all segments to create the data bit string // Concatenate all segments to create the data bit string
var dataCapacityBits = QrCode.getNumDataCodewords(version, ecl) * 8;
var bb = new BitBuffer(); var bb = new BitBuffer();
segs.forEach(function(seg) { segs.forEach(function(seg) {
bb.appendBits(seg.mode.modeBits, 4); bb.appendBits(seg.mode.modeBits, 4);
@ -565,15 +564,18 @@ var qrcodegen = new function() {
}); });
// Add terminator and pad up to a byte if applicable // 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, Math.min(4, dataCapacityBits - bb.length));
bb.appendBits(0, (8 - bb.length % 8) % 8); 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) if (bb.length % 8 != 0)
throw "Assertion error"; 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 // Create the QR Code symbol
return new this(bb.getBytes(), mask, version, ecl); return new this(bb.getBytes(), mask, version, ecl);
}; };

View File

@ -116,7 +116,6 @@ class QrCode(object):
ecl = newecl ecl = newecl
# Concatenate all segments to create the data bit string # Concatenate all segments to create the data bit string
datacapacitybits = QrCode._get_num_data_codewords(version, ecl) * 8
bb = _BitBuffer() bb = _BitBuffer()
for seg in segs: for seg in segs:
bb.append_bits(seg.get_mode().get_mode_bits(), 4) bb.append_bits(seg.get_mode().get_mode_bits(), 4)
@ -124,15 +123,17 @@ class QrCode(object):
bb.extend(seg._bitdata) bb.extend(seg._bitdata)
# Add terminator and pad up to a byte if applicable # 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, 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 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)): for padbyte in itertools.cycle((0xEC, 0x11)):
if len(bb) >= datacapacitybits: if len(bb) >= datacapacitybits:
break break
bb.append_bits(padbyte, 8) bb.append_bits(padbyte, 8)
assert len(bb) % 8 == 0
# Create the QR Code symbol # Create the QR Code symbol
return QrCode(bb.get_bytes(), mask, version, ecl) return QrCode(bb.get_bytes(), mask, version, ecl)

View File

@ -130,7 +130,6 @@ impl QrCode {
} }
// Concatenate all segments to create the data bit string // 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()); let mut bb = BitBuffer(Vec::new());
for seg in segs { for seg in segs {
bb.append_bits(seg.mode.mode_bits(), 4); bb.append_bits(seg.mode.mode_bits(), 4);
@ -139,19 +138,21 @@ impl QrCode {
} }
// Add terminator and pad up to a byte if applicable // 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()); let numzerobits = std::cmp::min(4, datacapacitybits - bb.0.len());
bb.append_bits(0, numzerobits as u8); bb.append_bits(0, numzerobits as u8);
let numzerobits = bb.0.len().wrapping_neg() & 7; let numzerobits = bb.0.len().wrapping_neg() & 7;
bb.append_bits(0, numzerobits as u8); 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() { for padbyte in [0xEC, 0x11].iter().cycle() {
if bb.0.len() >= datacapacitybits { if bb.0.len() >= datacapacitybits {
break; break;
} }
bb.append_bits(*padbyte, 8); bb.append_bits(*padbyte, 8);
} }
assert_eq!(bb.0.len() % 8, 0, "Assertion error");
let mut bytes = vec![0u8; bb.0.len() / 8]; let mut bytes = vec![0u8; bb.0.len() / 8];
for (i, bit) in bb.0.iter().enumerate() { for (i, bit) in bb.0.iter().enumerate() {

View File

@ -101,7 +101,6 @@ namespace qrcodegen {
}); });
// Concatenate all segments to create the data bit string // Concatenate all segments to create the data bit string
let dataCapacityBits: int = QrCode.getNumDataCodewords(version, ecl) * 8;
let bb = new BitBuffer(); let bb = new BitBuffer();
segs.forEach((seg: QrSegment) => { segs.forEach((seg: QrSegment) => {
bb.appendBits(seg.mode.modeBits, 4); bb.appendBits(seg.mode.modeBits, 4);
@ -111,15 +110,18 @@ namespace qrcodegen {
}); });
// Add terminator and pad up to a byte if applicable // 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, Math.min(4, dataCapacityBits - bb.length));
bb.appendBits(0, (8 - bb.length % 8) % 8); 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) if (bb.length % 8 != 0)
throw "Assertion error"; 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 // Create the QR Code symbol
return new QrCode(bb.getBytes(), mask, version, ecl); return new QrCode(bb.getBytes(), mask, version, ecl);
} }