mirror of
https://github.com/openharmony/third_party_qrcodegen.git
synced 2026-07-01 09:10:48 -04:00
@@ -1,5 +1,9 @@
|
||||
# Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved.
|
||||
|
||||
declare_args() {
|
||||
qrcodegen_feature_ace_engine_qrcode_able = true
|
||||
}
|
||||
|
||||
if (defined(ohos_lite)) {
|
||||
import("//build/lite/config/component/lite_component.gni")
|
||||
} else {
|
||||
@@ -50,4 +54,22 @@ if (defined(ohos_lite)) {
|
||||
configs = [ ":qrcodegen_config" ]
|
||||
public_configs = [ ":libqrcodegen_config" ]
|
||||
}
|
||||
if (qrcodegen_feature_ace_engine_qrcode_able) {
|
||||
config("ace_engine_qrcode_config") {
|
||||
include_dirs = [ "//third_party/qrcodegen/cpp" ]
|
||||
defines = [ "ACE_ENGINE_QRCODE_ABLE" ]
|
||||
cflags = [
|
||||
"-Wall",
|
||||
"-Wno-reorder",
|
||||
]
|
||||
cflags_cc = cflags
|
||||
}
|
||||
|
||||
ohos_static_library("ace_engine_qrcode") {
|
||||
sources = [ "cpp/qrcodegen.cpp" ]
|
||||
public_configs = [ ":ace_engine_qrcode_config" ]
|
||||
subsystem_name = "thirdparty"
|
||||
part_name = "qrcodegen"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
-2
@@ -14,7 +14,9 @@
|
||||
"name": "qrcodegen",
|
||||
"subsystem": "thirdparty",
|
||||
"syscap": [],
|
||||
"features": [],
|
||||
"features": [
|
||||
"qrcodegen_feature_ace_engine_qrcode_able"
|
||||
],
|
||||
"adapted_system_type": [
|
||||
"small",
|
||||
"mini",
|
||||
@@ -28,7 +30,11 @@
|
||||
},
|
||||
"build": {
|
||||
"sub_component": [],
|
||||
"inner_kits": [],
|
||||
"inner_kits": [
|
||||
{
|
||||
"name": "//third_party/qrcodegen:ace_engine_qrcode"
|
||||
}
|
||||
],
|
||||
"test": []
|
||||
}
|
||||
}
|
||||
|
||||
+252
-5
@@ -59,23 +59,34 @@ int QrSegment::Mode::numCharCountBits(int ver) const {
|
||||
}
|
||||
|
||||
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
const QrSegment::Mode QrSegment::Mode::NUMERIC (0x1, 10, 12, 14);
|
||||
const QrSegment::Mode QrSegment::Mode::ALPHANUMERIC(0x2, 9, 11, 13);
|
||||
const QrSegment::Mode QrSegment::Mode::BYTE (0x4, 8, 16, 16);
|
||||
const QrSegment::Mode QrSegment::Mode::KANJI (0x8, 8, 10, 12);
|
||||
const QrSegment::Mode QrSegment::Mode::ECI (0x7, 0, 0, 0);
|
||||
|
||||
#endif
|
||||
|
||||
QrSegment QrSegment::makeBytes(const vector<uint8_t> &data) {
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
BitBuffer bb;
|
||||
for (uint8_t b : data)
|
||||
bb.appendBits(b, 8);
|
||||
Mode md(0x4, 8, 16, 16);
|
||||
return QrSegment(md, static_cast<int>(data.size()), std::move(bb));
|
||||
#else
|
||||
if (data.size() > static_cast<unsigned int>(INT_MAX))
|
||||
throw std::length_error("Data too long");
|
||||
BitBuffer bb;
|
||||
for (uint8_t b : data)
|
||||
bb.appendBits(b, 8);
|
||||
return QrSegment(Mode::BYTE, static_cast<int>(data.size()), std::move(bb));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
QrSegment QrSegment::makeNumeric(const char *digits) {
|
||||
BitBuffer bb;
|
||||
int accumData = 0;
|
||||
@@ -121,15 +132,18 @@ QrSegment QrSegment::makeAlphanumeric(const char *text) {
|
||||
return QrSegment(Mode::ALPHANUMERIC, charCount, std::move(bb));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
vector<QrSegment> QrSegment::makeSegments(const char *text) {
|
||||
// Select the most efficient segment encoding automatically
|
||||
vector<QrSegment> result;
|
||||
if (*text == '\0'); // Leave result empty
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
else if (isNumeric(text))
|
||||
result.push_back(makeNumeric(text));
|
||||
else if (isAlphanumeric(text))
|
||||
result.push_back(makeAlphanumeric(text));
|
||||
#endif
|
||||
else {
|
||||
vector<uint8_t> bytes;
|
||||
for (; *text != '\0'; text++)
|
||||
@@ -139,6 +153,7 @@ vector<QrSegment> QrSegment::makeSegments(const char *text) {
|
||||
return result;
|
||||
}
|
||||
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
|
||||
QrSegment QrSegment::makeEci(long assignVal) {
|
||||
BitBuffer bb;
|
||||
@@ -166,20 +181,31 @@ QrSegment::QrSegment(const Mode &md, int numCh, const std::vector<bool> &dt) :
|
||||
throw std::domain_error("Invalid value");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
QrSegment::QrSegment(const Mode &md, int numCh, std::vector<bool> &&dt) :
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
mode(md),
|
||||
#else
|
||||
mode(&md),
|
||||
#endif
|
||||
numChars(numCh),
|
||||
data(std::move(dt)) {
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (numCh < 0)
|
||||
throw std::domain_error("Invalid value");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int QrSegment::getTotalBits(const vector<QrSegment> &segs, int version) {
|
||||
int result = 0;
|
||||
for (const QrSegment &seg : segs) {
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
int ccbits = seg.mode.numCharCountBits(version);
|
||||
#else
|
||||
int ccbits = seg.mode->numCharCountBits(version);
|
||||
#endif
|
||||
if (seg.numChars >= (1L << ccbits))
|
||||
return -1; // The segment's length doesn't fit the field's bit width
|
||||
if (4 + ccbits > INT_MAX - result)
|
||||
@@ -192,6 +218,7 @@ int QrSegment::getTotalBits(const vector<QrSegment> &segs, int version) {
|
||||
return result;
|
||||
}
|
||||
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
|
||||
bool QrSegment::isNumeric(const char *text) {
|
||||
for (; *text != '\0'; text++) {
|
||||
@@ -211,9 +238,14 @@ bool QrSegment::isAlphanumeric(const char *text) {
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const QrSegment::Mode &QrSegment::getMode() const {
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
return mode;
|
||||
#else
|
||||
return *mode;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -226,10 +258,11 @@ const std::vector<bool> &QrSegment::getData() const {
|
||||
return data;
|
||||
}
|
||||
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
|
||||
const char *QrSegment::ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*---- Class QrCode ----*/
|
||||
|
||||
@@ -239,30 +272,56 @@ int QrCode::getFormatBits(Ecc ecl) {
|
||||
case Ecc::MEDIUM : return 0;
|
||||
case Ecc::QUARTILE: return 3;
|
||||
case Ecc::HIGH : return 2;
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
default: return -1; //This scenario does not exist after adaptation.
|
||||
#else
|
||||
default: throw std::logic_error("Unreachable");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QrCode QrCode::encodeText(const char *text, Ecc ecl) {
|
||||
vector<QrSegment> segs = QrSegment::makeSegments(text);
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
return encodeSegments(segs, ecl, MIN_VERSION, MAX_VERSION, 5);
|
||||
#else
|
||||
return encodeSegments(segs, ecl);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
QrCode QrCode::encodeBinary(const vector<uint8_t> &data, Ecc ecl) {
|
||||
vector<QrSegment> segs{QrSegment::makeBytes(data)};
|
||||
return encodeSegments(segs, ecl);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl,
|
||||
int minVersion, int maxVersion, int mask, bool boostEcl) {
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
|
||||
throw std::invalid_argument("Invalid value");
|
||||
|
||||
#endif
|
||||
// Find the minimal version number to use
|
||||
int version, dataUsedBits;
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
vector<uint8_t> dataCodewordsTemp;
|
||||
#endif
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
for (version = minVersion; ; version++) {
|
||||
int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
|
||||
dataUsedBits = QrSegment::getTotalBits(segs, version);
|
||||
if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
|
||||
break; // This version number is found to be suitable
|
||||
if (version >= maxVersion) { // All versions in the range could not fit the given data
|
||||
return QrCode(ERR_VERSION, ecl, dataCodewordsTemp, mask);
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (version = minVersion; ; version++) {
|
||||
int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
|
||||
dataUsedBits = QrSegment::getTotalBits(segs, version);
|
||||
@@ -279,8 +338,14 @@ QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl,
|
||||
throw data_too_long(sb.str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (dataUsedBits == -1)
|
||||
return QrCode(ERR_VERSION, ecl, dataCodewordsTemp, mask);
|
||||
#else
|
||||
assert(dataUsedBits != -1);
|
||||
|
||||
#endif
|
||||
|
||||
// Increase the error correction level while the data still fits in the current version number
|
||||
for (Ecc newEcl : {Ecc::MEDIUM, Ecc::QUARTILE, Ecc::HIGH}) { // From low to high
|
||||
if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8)
|
||||
@@ -294,14 +359,29 @@ QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl,
|
||||
bb.appendBits(static_cast<uint32_t>(seg.getNumChars()), seg.getMode().numCharCountBits(version));
|
||||
bb.insert(bb.end(), seg.getData().begin(), seg.getData().end());
|
||||
}
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (bb.size() != static_cast<unsigned int>(dataUsedBits))
|
||||
return QrCode(ERR_VERSION, ecl, dataCodewordsTemp, mask);
|
||||
#else
|
||||
assert(bb.size() == static_cast<unsigned int>(dataUsedBits));
|
||||
#endif
|
||||
|
||||
// Add terminator and pad up to a byte if applicable
|
||||
size_t dataCapacityBits = static_cast<size_t>(getNumDataCodewords(version, ecl)) * 8;
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (bb.size() > dataCapacityBits)
|
||||
return QrCode(ERR_VERSION, ecl, dataCodewordsTemp, mask);
|
||||
#else
|
||||
assert(bb.size() <= dataCapacityBits);
|
||||
#endif
|
||||
bb.appendBits(0, std::min(4, static_cast<int>(dataCapacityBits - bb.size())));
|
||||
bb.appendBits(0, (8 - static_cast<int>(bb.size() % 8)) % 8);
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (bb.size() % 8 != 0)
|
||||
return QrCode(ERR_VERSION, ecl, dataCodewordsTemp, mask);
|
||||
#else
|
||||
assert(bb.size() % 8 == 0);
|
||||
#endif
|
||||
|
||||
// Pad with alternating bytes until data capacity is reached
|
||||
for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
|
||||
@@ -319,12 +399,25 @@ QrCode QrCode::encodeSegments(const vector<QrSegment> &segs, Ecc ecl,
|
||||
|
||||
QrCode::QrCode(int ver, Ecc ecl, const vector<uint8_t> &dataCodewords, int msk) :
|
||||
// Initialize fields and check arguments
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
version(ver), errorCorrectionLevel(ecl), flag(true) {
|
||||
if (ver < MIN_VERSION || ver > MAX_VERSION) {
|
||||
flag = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (msk < -1 || msk > 7) {
|
||||
flag = false;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
version(ver),
|
||||
errorCorrectionLevel(ecl) {
|
||||
if (ver < MIN_VERSION || ver > MAX_VERSION)
|
||||
throw std::domain_error("Version value out of range");
|
||||
if (msk < -1 || msk > 7)
|
||||
throw std::domain_error("Mask value out of range");
|
||||
#endif
|
||||
size = ver * 4 + 17;
|
||||
size_t sz = static_cast<size_t>(size);
|
||||
modules = vector<vector<bool> >(sz, vector<bool>(sz)); // Initially all light
|
||||
@@ -332,9 +425,28 @@ QrCode::QrCode(int ver, Ecc ecl, const vector<uint8_t> &dataCodewords, int msk)
|
||||
|
||||
// Compute ECC, draw modules
|
||||
drawFunctionPatterns();
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (!flag) {
|
||||
clearFunctionPatterns();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
const vector<uint8_t> allCodewords = addEccAndInterleave(dataCodewords);
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (!flag){
|
||||
clearFunctionPatterns();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
drawCodewords(allCodewords);
|
||||
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (!flag) {
|
||||
clearFunctionPatterns();
|
||||
return;
|
||||
}
|
||||
#else
|
||||
// Do masking
|
||||
if (msk == -1) { // Automatically choose best mask
|
||||
long minPenalty = LONG_MAX;
|
||||
@@ -350,14 +462,31 @@ QrCode::QrCode(int ver, Ecc ecl, const vector<uint8_t> &dataCodewords, int msk)
|
||||
}
|
||||
}
|
||||
assert(0 <= msk && msk <= 7);
|
||||
#endif
|
||||
mask = msk;
|
||||
applyMask(msk); // Apply the final choice of mask
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (!flag) {
|
||||
clearFunctionPatterns();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
drawFormatBits(msk); // Overwrite old format bits
|
||||
|
||||
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
clearFunctionPatterns();
|
||||
#else
|
||||
isFunction.clear();
|
||||
isFunction.shrink_to_fit();
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
bool QrCode::getFlag() const {
|
||||
return flag;
|
||||
}
|
||||
#endif
|
||||
|
||||
int QrCode::getVersion() const {
|
||||
return version;
|
||||
@@ -409,6 +538,13 @@ void QrCode::drawFunctionPatterns() {
|
||||
|
||||
// Draw configuration data
|
||||
drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
|
||||
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (!flag) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
drawVersion();
|
||||
}
|
||||
|
||||
@@ -420,7 +556,14 @@ void QrCode::drawFormatBits(int msk) {
|
||||
for (int i = 0; i < 10; i++)
|
||||
rem = (rem << 1) ^ ((rem >> 9) * 0x537);
|
||||
int bits = (data << 10 | rem) ^ 0x5412; // uint15
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (bits >> 15 != 0) {
|
||||
flag = false;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
assert(bits >> 15 == 0);
|
||||
#endif
|
||||
|
||||
// Draw first copy
|
||||
for (int i = 0; i <= 5; i++)
|
||||
@@ -449,7 +592,14 @@ void QrCode::drawVersion() {
|
||||
for (int i = 0; i < 12; i++)
|
||||
rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
|
||||
long bits = static_cast<long>(version) << 12 | rem; // uint18
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (bits >> 18 != 0) {
|
||||
flag = false;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
assert(bits >> 18 == 0);
|
||||
#endif
|
||||
|
||||
// Draw two copies
|
||||
for (int i = 0; i < 18; i++) {
|
||||
@@ -495,9 +645,18 @@ bool QrCode::module(int x, int y) const {
|
||||
}
|
||||
|
||||
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
vector<uint8_t> QrCode::addEccAndInterleave(const vector<uint8_t> &data) {
|
||||
vector<uint8_t> result;
|
||||
if (data.size() != static_cast<unsigned int>(getNumDataCodewords(version, errorCorrectionLevel))) {
|
||||
flag = false;
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
vector<uint8_t> QrCode::addEccAndInterleave(const vector<uint8_t> &data) const {
|
||||
if (data.size() != static_cast<unsigned int>(getNumDataCodewords(version, errorCorrectionLevel)))
|
||||
throw std::invalid_argument("Invalid argument");
|
||||
#endif
|
||||
|
||||
// Calculate parameter numbers
|
||||
int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[static_cast<int>(errorCorrectionLevel)][version];
|
||||
@@ -509,10 +668,20 @@ vector<uint8_t> QrCode::addEccAndInterleave(const vector<uint8_t> &data) const {
|
||||
// Split data into blocks and append ECC to each block
|
||||
vector<vector<uint8_t> > blocks;
|
||||
const vector<uint8_t> rsDiv = reedSolomonComputeDivisor(blockEccLen);
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (!flag) {
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
for (int i = 0, k = 0; i < numBlocks; i++) {
|
||||
vector<uint8_t> dat(data.cbegin() + k, data.cbegin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1)));
|
||||
k += static_cast<int>(dat.size());
|
||||
const vector<uint8_t> ecc = reedSolomonComputeRemainder(dat, rsDiv);
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (!flag) {
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
if (i < numShortBlocks)
|
||||
dat.push_back(0);
|
||||
dat.insert(dat.end(), ecc.cbegin(), ecc.cend());
|
||||
@@ -520,7 +689,9 @@ vector<uint8_t> QrCode::addEccAndInterleave(const vector<uint8_t> &data) const {
|
||||
}
|
||||
|
||||
// Interleave (not concatenate) the bytes from every block into a single sequence
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
vector<uint8_t> result;
|
||||
#endif
|
||||
for (size_t i = 0; i < blocks.at(0).size(); i++) {
|
||||
for (size_t j = 0; j < blocks.size(); j++) {
|
||||
// Skip the padding byte in short blocks
|
||||
@@ -528,14 +699,26 @@ vector<uint8_t> QrCode::addEccAndInterleave(const vector<uint8_t> &data) const {
|
||||
result.push_back(blocks.at(j).at(i));
|
||||
}
|
||||
}
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (result.size() != static_cast<unsigned int>(rawCodewords))
|
||||
flag = false;
|
||||
#else
|
||||
assert(result.size() == static_cast<unsigned int>(rawCodewords));
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void QrCode::drawCodewords(const vector<uint8_t> &data) {
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (data.size() != static_cast<unsigned int>(getNumRawDataModules(version) / 8)) {
|
||||
flag = false;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (data.size() != static_cast<unsigned int>(getNumRawDataModules(version) / 8))
|
||||
throw std::invalid_argument("Invalid argument");
|
||||
#endif
|
||||
|
||||
size_t i = 0; // Bit index into the data
|
||||
// Do the funny zigzag scan
|
||||
@@ -556,13 +739,22 @@ void QrCode::drawCodewords(const vector<uint8_t> &data) {
|
||||
}
|
||||
}
|
||||
}
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (i != data.size() * 8){
|
||||
flag = false;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
assert(i == data.size() * 8);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void QrCode::applyMask(int msk) {
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (msk < 0 || msk > 7)
|
||||
throw std::domain_error("Mask value out of range");
|
||||
#endif
|
||||
size_t sz = static_cast<size_t>(size);
|
||||
for (size_t y = 0; y < sz; y++) {
|
||||
for (size_t x = 0; x < sz; x++) {
|
||||
@@ -576,7 +768,11 @@ void QrCode::applyMask(int msk) {
|
||||
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;
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
default: return;
|
||||
#else
|
||||
default: throw std::logic_error("Unreachable");
|
||||
#endif
|
||||
}
|
||||
modules.at(y).at(x) = modules.at(y).at(x) ^ (invert & !isFunction.at(y).at(x));
|
||||
}
|
||||
@@ -584,6 +780,7 @@ void QrCode::applyMask(int msk) {
|
||||
}
|
||||
|
||||
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
long QrCode::getPenaltyScore() const {
|
||||
long result = 0;
|
||||
|
||||
@@ -660,6 +857,7 @@ long QrCode::getPenaltyScore() const {
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
vector<int> QrCode::getAlignmentPatternPositions() const {
|
||||
if (version == 1)
|
||||
@@ -678,8 +876,10 @@ vector<int> QrCode::getAlignmentPatternPositions() const {
|
||||
|
||||
|
||||
int QrCode::getNumRawDataModules(int ver) {
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (ver < MIN_VERSION || ver > MAX_VERSION)
|
||||
throw std::domain_error("Version number out of range");
|
||||
#endif
|
||||
int result = (16 * ver + 128) * ver + 64;
|
||||
if (ver >= 2) {
|
||||
int numAlign = ver / 7 + 2;
|
||||
@@ -687,7 +887,9 @@ int QrCode::getNumRawDataModules(int ver) {
|
||||
if (ver >= 7)
|
||||
result -= 36;
|
||||
}
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
assert(208 <= result && result <= 29648);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -700,8 +902,10 @@ int QrCode::getNumDataCodewords(int ver, Ecc ecl) {
|
||||
|
||||
|
||||
vector<uint8_t> QrCode::reedSolomonComputeDivisor(int degree) {
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (degree < 1 || degree > 255)
|
||||
throw std::domain_error("Degree out of range");
|
||||
#endif
|
||||
// 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}.
|
||||
vector<uint8_t> result(static_cast<size_t>(degree));
|
||||
@@ -715,10 +919,20 @@ vector<uint8_t> QrCode::reedSolomonComputeDivisor(int degree) {
|
||||
// Multiply the current product by (x - r^i)
|
||||
for (size_t j = 0; j < result.size(); j++) {
|
||||
result.at(j) = reedSolomonMultiply(result.at(j), root);
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (!flag) {
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
if (j + 1 < result.size())
|
||||
result.at(j) ^= result.at(j + 1);
|
||||
}
|
||||
root = reedSolomonMultiply(root, 0x02);
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (!flag) {
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -730,8 +944,17 @@ vector<uint8_t> QrCode::reedSolomonComputeRemainder(const vector<uint8_t> &data,
|
||||
uint8_t factor = b ^ result.at(0);
|
||||
result.erase(result.begin());
|
||||
result.push_back(0);
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
for (size_t i = 0; i < result.size(); i++) {
|
||||
result.at(i) ^= reedSolomonMultiply(divisor.at(i), factor);
|
||||
if (!flag) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
#else
|
||||
for (size_t i = 0; i < result.size(); i++)
|
||||
result.at(i) ^= reedSolomonMultiply(divisor.at(i), factor);
|
||||
#endif
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -744,11 +967,17 @@ uint8_t QrCode::reedSolomonMultiply(uint8_t x, uint8_t y) {
|
||||
z = (z << 1) ^ ((z >> 7) * 0x11D);
|
||||
z ^= ((y >> i) & 1) * x;
|
||||
}
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (z >> 8 != 0)
|
||||
flag = false;
|
||||
return static_cast<uint8_t>(z);
|
||||
#else
|
||||
assert(z >> 8 == 0);
|
||||
return static_cast<uint8_t>(z);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
int QrCode::finderPenaltyCountPatterns(const std::array<int,7> &runHistory) const {
|
||||
int n = runHistory.at(1);
|
||||
assert(n <= size * 3);
|
||||
@@ -775,6 +1004,15 @@ void QrCode::finderPenaltyAddHistory(int currentRunLength, std::array<int,7> &ru
|
||||
std::copy_backward(runHistory.cbegin(), runHistory.cend() - 1, runHistory.end());
|
||||
runHistory.at(0) = currentRunLength;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
void QrCode::clearFunctionPatterns()
|
||||
{
|
||||
isFunction.clear();
|
||||
isFunction.shrink_to_fit();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool QrCode::getBit(long x, int i) {
|
||||
@@ -784,10 +1022,12 @@ bool QrCode::getBit(long x, int i) {
|
||||
|
||||
/*---- Tables of constants ----*/
|
||||
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
const int QrCode::PENALTY_N1 = 3;
|
||||
const int QrCode::PENALTY_N2 = 3;
|
||||
const int QrCode::PENALTY_N3 = 40;
|
||||
const int QrCode::PENALTY_N4 = 10;
|
||||
#endif
|
||||
|
||||
|
||||
const int8_t QrCode::ECC_CODEWORDS_PER_BLOCK[4][41] = {
|
||||
@@ -809,8 +1049,10 @@ const int8_t QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][41] = {
|
||||
};
|
||||
|
||||
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
data_too_long::data_too_long(const std::string &msg) :
|
||||
std::length_error(msg) {}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -821,8 +1063,13 @@ BitBuffer::BitBuffer()
|
||||
|
||||
|
||||
void BitBuffer::appendBits(std::uint32_t val, int len) {
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
if (len < 0 || len > 31 || val >> len != 0)
|
||||
return;
|
||||
#else
|
||||
if (len < 0 || len > 31 || val >> len != 0)
|
||||
throw std::domain_error("Value out of range");
|
||||
#endif
|
||||
for (int i = len - 1; i >= 0; i--) // Append bit by bit
|
||||
this->push_back(((val >> i) & 1) != 0);
|
||||
}
|
||||
|
||||
+102
-20
@@ -22,6 +22,8 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef QRCODEEGEN_H
|
||||
#define QRCODEEGEN_H
|
||||
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
@@ -52,6 +54,7 @@ class QrSegment final {
|
||||
*/
|
||||
public: class Mode final {
|
||||
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
/*-- Constants --*/
|
||||
|
||||
public: static const Mode NUMERIC;
|
||||
@@ -59,7 +62,8 @@ class QrSegment final {
|
||||
public: static const Mode BYTE;
|
||||
public: static const Mode KANJI;
|
||||
public: static const Mode ECI;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*-- Fields --*/
|
||||
|
||||
@@ -72,7 +76,13 @@ class QrSegment final {
|
||||
|
||||
/*-- Constructor --*/
|
||||
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
public: Mode(int mode, int cc0, int cc1, int cc2);
|
||||
|
||||
public: Mode() {}
|
||||
#else
|
||||
private: Mode(int mode, int cc0, int cc1, int cc2);
|
||||
#endif
|
||||
|
||||
|
||||
/*-- Methods --*/
|
||||
@@ -99,9 +109,14 @@ class QrSegment final {
|
||||
* byte mode. All input byte vectors are acceptable. Any text string
|
||||
* can be converted to UTF-8 bytes and encoded as a byte mode segment.
|
||||
*/
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
private: static QrSegment makeBytes(const std::vector<std::uint8_t> &data);
|
||||
#else
|
||||
public: static QrSegment makeBytes(const std::vector<std::uint8_t> &data);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
/*
|
||||
* Returns a segment representing the given string of decimal digits encoded in numeric mode.
|
||||
*/
|
||||
@@ -114,7 +129,8 @@ class QrSegment final {
|
||||
* dollar, percent, asterisk, plus, hyphen, period, slash, colon.
|
||||
*/
|
||||
public: static QrSegment makeAlphanumeric(const char *text);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Returns a list of zero or more segments to represent the given text string. The result
|
||||
@@ -122,7 +138,8 @@ class QrSegment final {
|
||||
*/
|
||||
public: static std::vector<QrSegment> makeSegments(const char *text);
|
||||
|
||||
|
||||
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
/*
|
||||
* Returns a segment representing an Extended Channel Interpretation
|
||||
* (ECI) designator with the given assignment value.
|
||||
@@ -145,13 +162,18 @@ class QrSegment final {
|
||||
* (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
|
||||
*/
|
||||
public: static bool isAlphanumeric(const char *text);
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*---- Instance fields ----*/
|
||||
|
||||
/* The mode indicator of this segment. Accessed through getMode(). */
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
private: Mode mode;
|
||||
#else
|
||||
private: const Mode *mode;
|
||||
#endif
|
||||
|
||||
|
||||
/* The length of this segment's unencoded data. Measured in characters for
|
||||
* numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode.
|
||||
@@ -165,14 +187,16 @@ class QrSegment final {
|
||||
|
||||
/*---- Constructors (low level) ----*/
|
||||
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
/*
|
||||
* Creates a new QR Code segment with the given attributes and data.
|
||||
* The character count (numCh) must agree with the mode and the bit buffer length,
|
||||
* but the constraint isn't checked. The given bit buffer is copied and stored.
|
||||
*/
|
||||
public: QrSegment(const Mode &md, int numCh, const std::vector<bool> &dt);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Creates a new QR Code segment with the given parameters and data.
|
||||
* The character count (numCh) must agree with the mode and the bit buffer length,
|
||||
@@ -206,13 +230,13 @@ class QrSegment final {
|
||||
// segment has too many characters to fit its length field, or the total bits exceeds INT_MAX.
|
||||
public: static int getTotalBits(const std::vector<QrSegment> &segs, int version);
|
||||
|
||||
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
/*---- Private constant ----*/
|
||||
|
||||
/* The set of all legal characters in alphanumeric mode, where
|
||||
* each character value maps to the index in the string. */
|
||||
private: static const char *ALPHANUMERIC_CHARSET;
|
||||
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -264,7 +288,8 @@ class QrCode final {
|
||||
*/
|
||||
public: static QrCode encodeText(const char *text, Ecc ecl);
|
||||
|
||||
|
||||
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
/*
|
||||
* Returns a QR Code representing the given binary data at the given error correction level.
|
||||
* This function always encodes using the binary segment mode, not any text mode. The maximum number of
|
||||
@@ -272,8 +297,9 @@ class QrCode final {
|
||||
* The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
|
||||
*/
|
||||
public: static QrCode encodeBinary(const std::vector<std::uint8_t> &data, Ecc ecl);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*---- Static factory functions (mid level) ----*/
|
||||
|
||||
/*
|
||||
@@ -287,8 +313,13 @@ class QrCode final {
|
||||
* between modes (such as alphanumeric and byte) to encode text in less space.
|
||||
* This is a mid-level API; the high-level API is encodeText() and encodeBinary().
|
||||
*/
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
private: static QrCode encodeSegments(const std::vector<QrSegment> &segs, Ecc ecl,
|
||||
int minVersion=1, int maxVersion=40, int mask=-1, bool boostEcl=true); // All optional parameters
|
||||
#else
|
||||
public: static QrCode encodeSegments(const std::vector<QrSegment> &segs, Ecc ecl,
|
||||
int minVersion=1, int maxVersion=40, int mask=-1, bool boostEcl=true); // All optional parameters
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -321,6 +352,11 @@ class QrCode final {
|
||||
// Indicates function modules that are not subjected to masking. Discarded when constructor finishes.
|
||||
private: std::vector<std::vector<bool> > isFunction;
|
||||
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
/* QR Code Generation Success Flag.
|
||||
* This Success :true */
|
||||
private: bool flag;
|
||||
#endif
|
||||
|
||||
|
||||
/*---- Constructor (low level) ----*/
|
||||
@@ -331,11 +367,21 @@ class QrCode final {
|
||||
* This is a low-level API that most users should not use directly.
|
||||
* A mid-level API is the encodeSegments() function.
|
||||
*/
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
private: QrCode(int ver, Ecc ecl, const std::vector<std::uint8_t> &dataCodewords, int msk);
|
||||
#else
|
||||
public: QrCode(int ver, Ecc ecl, const std::vector<std::uint8_t> &dataCodewords, int msk);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*---- Public instance methods ----*/
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
/*
|
||||
* Returns this QR Code's version, in the range [1, 40].
|
||||
*/
|
||||
public: bool getFlag() const;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Returns this QR Code's version, in the range [1, 40].
|
||||
@@ -409,7 +455,11 @@ class QrCode final {
|
||||
|
||||
// Returns a new byte string representing the given data with the appropriate error correction
|
||||
// codewords appended to it, based on this object's version and error correction level.
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
private: std::vector<std::uint8_t> addEccAndInterleave(const std::vector<std::uint8_t> &data);
|
||||
#else
|
||||
private: std::vector<std::uint8_t> addEccAndInterleave(const std::vector<std::uint8_t> &data) const;
|
||||
#endif
|
||||
|
||||
|
||||
// Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
|
||||
@@ -424,10 +474,12 @@ class QrCode final {
|
||||
// QR Code needs exactly one (not zero, two, etc.) mask applied.
|
||||
private: void applyMask(int msk);
|
||||
|
||||
|
||||
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
// Calculates and returns the penalty score based on state of this QR Code's current modules.
|
||||
// This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
|
||||
private: long getPenaltyScore() const;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -453,18 +505,30 @@ class QrCode final {
|
||||
|
||||
// Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be
|
||||
// implemented as a lookup table over all possible parameter values, instead of as an algorithm.
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
private: std::vector<std::uint8_t> reedSolomonComputeDivisor(int degree);
|
||||
#else
|
||||
private: static std::vector<std::uint8_t> reedSolomonComputeDivisor(int degree);
|
||||
#endif
|
||||
|
||||
|
||||
// Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials.
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
private: std::vector<std::uint8_t> reedSolomonComputeRemainder(const std::vector<std::uint8_t> &data, const std::vector<std::uint8_t> &divisor);
|
||||
#else
|
||||
private: static std::vector<std::uint8_t> reedSolomonComputeRemainder(const std::vector<std::uint8_t> &data, const std::vector<std::uint8_t> &divisor);
|
||||
#endif
|
||||
|
||||
|
||||
// Returns the product of the two given field elements modulo GF(2^8/0x11D).
|
||||
// All inputs are valid. This could be implemented as a 256*256 lookup table.
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
private: std::uint8_t reedSolomonMultiply(std::uint8_t x, std::uint8_t y);
|
||||
#else
|
||||
private: static std::uint8_t reedSolomonMultiply(std::uint8_t x, std::uint8_t y);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
// Can only be called immediately after a light run is added, and
|
||||
// returns either 0, 1, or 2. A helper function for getPenaltyScore().
|
||||
private: int finderPenaltyCountPatterns(const std::array<int,7> &runHistory) const;
|
||||
@@ -476,6 +540,12 @@ class QrCode final {
|
||||
|
||||
// Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore().
|
||||
private: void finderPenaltyAddHistory(int currentRunLength, std::array<int,7> &runHistory) const;
|
||||
#endif
|
||||
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
// clear Function.
|
||||
private: void clearFunctionPatterns();
|
||||
#endif
|
||||
|
||||
|
||||
// Returns true iff the i'th bit of x is set to 1.
|
||||
@@ -483,20 +553,31 @@ class QrCode final {
|
||||
|
||||
|
||||
/*---- Constants and tables ----*/
|
||||
|
||||
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
// The error version number supported in the QR Code Model 2 standard.
|
||||
private: static constexpr int ERR_VERSION = 0;
|
||||
#endif
|
||||
// The minimum version number supported in the QR Code Model 2 standard.
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
private: static constexpr int MIN_VERSION = 1;
|
||||
#else
|
||||
public: static constexpr int MIN_VERSION = 1;
|
||||
#endif
|
||||
|
||||
// The maximum version number supported in the QR Code Model 2 standard.
|
||||
#if defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
private: static constexpr int MAX_VERSION = 40;
|
||||
#else
|
||||
public: static constexpr int MAX_VERSION = 40;
|
||||
|
||||
|
||||
#endif
|
||||
#if !defined(ACE_ENGINE_QRCODE_ABLE)
|
||||
// For use in getPenaltyScore(), when evaluating which mask is best.
|
||||
private: static const int PENALTY_N1;
|
||||
private: static const int PENALTY_N2;
|
||||
private: static const int PENALTY_N3;
|
||||
private: static const int PENALTY_N4;
|
||||
|
||||
#endif
|
||||
|
||||
private: static const std::int8_t ECC_CODEWORDS_PER_BLOCK[4][41];
|
||||
private: static const std::int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41];
|
||||
@@ -547,3 +628,4 @@ class BitBuffer final : public std::vector<bool> {
|
||||
};
|
||||
|
||||
}
|
||||
#endif // QRCODEEGEN_H
|
||||
|
||||
Reference in New Issue
Block a user