Revamped C++ BitBuffer code to be based on std::vector<bool>, updated dependent code.
This commit is contained in:
parent
2c1991adad
commit
5a47e04b52
|
@ -27,44 +27,23 @@
|
|||
|
||||
namespace qrcodegen {
|
||||
|
||||
BitBuffer::BitBuffer() :
|
||||
data(),
|
||||
bitLength(0) {}
|
||||
|
||||
|
||||
int BitBuffer::getBitLength() const {
|
||||
return bitLength;
|
||||
}
|
||||
BitBuffer::BitBuffer()
|
||||
: std::vector<bool>() {}
|
||||
|
||||
|
||||
std::vector<std::uint8_t> BitBuffer::getBytes() const {
|
||||
return data;
|
||||
std::vector<std::uint8_t> result((size() + 7) / 8);
|
||||
for (std::size_t i = 0; i < size(); i++)
|
||||
result[i >> 3] |= (*this)[i] ? 1 << (7 - (i & 7)) : 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void BitBuffer::appendBits(std::uint32_t val, int len) {
|
||||
if (len < 0 || len > 32 || (len < 32 && (val >> len) != 0))
|
||||
throw "Value out of range";
|
||||
if (len > INT_MAX - bitLength)
|
||||
throw "Buffer too long";
|
||||
unsigned int newByteLen = ((unsigned int)bitLength + len + 7) / 8;
|
||||
while (data.size() < newByteLen)
|
||||
data.push_back(0);
|
||||
for (int i = len - 1; i >= 0; i--, bitLength++) // Append bit by bit
|
||||
data.at(bitLength >> 3) |= ((val >> i) & 1) << (7 - (bitLength & 7));
|
||||
}
|
||||
|
||||
|
||||
void BitBuffer::appendData(const QrSegment &seg) {
|
||||
if (seg.bitLength > INT_MAX - bitLength)
|
||||
throw "Buffer too long";
|
||||
unsigned int newByteLen = ((unsigned int)bitLength + seg.bitLength + 7) / 8;
|
||||
while (data.size() < newByteLen)
|
||||
data.push_back(0);
|
||||
for (int i = 0; i < seg.bitLength; i++, bitLength++) { // Append bit by bit
|
||||
int bit = (seg.data.at(i >> 3) >> (7 - (i & 7))) & 1;
|
||||
data.at(bitLength >> 3) |= bit << (7 - (bitLength & 7));
|
||||
}
|
||||
for (int i = len - 1; i >= 0; i--) // Append bit by bit
|
||||
this->push_back(((val >> i) & 1) != 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include "QrSegment.hpp"
|
||||
|
||||
|
||||
namespace qrcodegen {
|
||||
|
@ -33,14 +32,7 @@ namespace qrcodegen {
|
|||
/*
|
||||
* An appendable sequence of bits. Bits are packed in big endian within a byte.
|
||||
*/
|
||||
class BitBuffer final {
|
||||
|
||||
/*---- Fields ----*/
|
||||
|
||||
private: std::vector<std::uint8_t> data;
|
||||
private: int bitLength;
|
||||
|
||||
|
||||
class BitBuffer final : public std::vector<bool> {
|
||||
|
||||
/*---- Constructor ----*/
|
||||
|
||||
|
@ -51,11 +43,7 @@ class BitBuffer final {
|
|||
|
||||
/*---- Methods ----*/
|
||||
|
||||
// Returns the number of bits in the buffer, which is a non-negative value.
|
||||
public: int getBitLength() const;
|
||||
|
||||
|
||||
// Returns a copy of all bytes, padding up to the nearest byte.
|
||||
// Returns a copy of all bytes, padding up to the nearest byte. Bits are packed in big endian within a byte.
|
||||
public: std::vector<std::uint8_t> getBytes() const;
|
||||
|
||||
|
||||
|
@ -63,10 +51,6 @@ class BitBuffer final {
|
|||
// If 0 <= len <= 31, then this requires 0 <= val < 2^len.
|
||||
public: void appendBits(std::uint32_t val, int len);
|
||||
|
||||
|
||||
// Appends the data of the given segment to this bit buffer.
|
||||
public: void appendData(const QrSegment &seg);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -88,22 +88,23 @@ QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, const Ecc &ecl,
|
|||
}
|
||||
|
||||
// Create the data bit string by concatenating all segments
|
||||
int dataCapacityBits = getNumDataCodewords(version, *newEcl) * 8;
|
||||
size_t dataCapacityBits = getNumDataCodewords(version, *newEcl) * 8;
|
||||
BitBuffer bb;
|
||||
for (const QrSegment &seg : segs) {
|
||||
bb.appendBits(seg.mode.modeBits, 4);
|
||||
bb.appendBits(seg.numChars, seg.mode.numCharCountBits(version));
|
||||
bb.appendData(seg);
|
||||
for (int i = 0; i < seg.bitLength; i++)
|
||||
bb.push_back(((seg.data.at(i >> 3) >> (7 - (i & 7))) & 1) != 0);
|
||||
}
|
||||
|
||||
// Add terminator and pad up to a byte if applicable
|
||||
bb.appendBits(0, std::min(4, dataCapacityBits - bb.getBitLength()));
|
||||
bb.appendBits(0, (8 - bb.getBitLength() % 8) % 8);
|
||||
bb.appendBits(0, std::min(static_cast<size_t>(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.getBitLength() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
|
||||
for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
|
||||
bb.appendBits(padByte, 8);
|
||||
if (bb.getBitLength() % 8 != 0)
|
||||
if (bb.size() % 8 != 0)
|
||||
throw "Assertion error";
|
||||
|
||||
// Create the QR Code symbol
|
||||
|
|
|
@ -83,7 +83,7 @@ QrSegment QrSegment::makeNumeric(const char *digits) {
|
|||
}
|
||||
if (accumCount > 0) // 1 or 2 digits remaining
|
||||
bb.appendBits(accumData, accumCount * 3 + 1);
|
||||
return QrSegment(Mode::NUMERIC, charCount, bb.getBytes(), bb.getBitLength());
|
||||
return QrSegment(Mode::NUMERIC, charCount, bb.getBytes(), bb.size());
|
||||
}
|
||||
|
||||
|
||||
|
@ -106,7 +106,7 @@ QrSegment QrSegment::makeAlphanumeric(const char *text) {
|
|||
}
|
||||
if (accumCount > 0) // 1 character remaining
|
||||
bb.appendBits(accumData, 6);
|
||||
return QrSegment(Mode::ALPHANUMERIC, charCount, bb.getBytes(), bb.getBitLength());
|
||||
return QrSegment(Mode::ALPHANUMERIC, charCount, bb.getBytes(), bb.size());
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue