diff --git a/BUILD.gn b/BUILD.gn index 67e5601973eb911b74263c359f1c3239da43a7b7..cb795867b521cd6acab0a118fe04c220eb3e52c0 100755 --- a/BUILD.gn +++ b/BUILD.gn @@ -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" + } + } +} \ No newline at end of file diff --git a/bundle.json b/bundle.json index e346b4b90c28e0f5eb88214f01919cd0c8e6d0d2..285bce26efd03e7329025c8687c1b7ee4a937f3c 100644 --- a/bundle.json +++ b/bundle.json @@ -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": [] } } diff --git a/cpp/qrcodegen.cpp b/cpp/qrcodegen.cpp index 0957b79bfe4aac6b9fd8dfb8613f80fe9a112b73..90ded9cc98fd1b29ff2beaede6b6cc84d95fb7c3 100644 --- a/cpp/qrcodegen.cpp +++ b/cpp/qrcodegen.cpp @@ -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 &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(data.size()), std::move(bb)); +#else if (data.size() > static_cast(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(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::makeSegments(const char *text) { // Select the most efficient segment encoding automatically vector 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 bytes; for (; *text != '\0'; text++) @@ -139,6 +153,7 @@ vector 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 &dt) : throw std::domain_error("Invalid value"); } +#endif QrSegment::QrSegment(const Mode &md, int numCh, std::vector &&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 &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 &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 &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 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 &data, Ecc ecl) { vector segs{QrSegment::makeBytes(data)}; return encodeSegments(segs, ecl); } +#endif QrCode QrCode::encodeSegments(const vector &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 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 &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 &segs, Ecc ecl, bb.appendBits(static_cast(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(dataUsedBits)) + return QrCode(ERR_VERSION, ecl, dataCodewordsTemp, mask); +#else assert(bb.size() == static_cast(dataUsedBits)); +#endif // Add terminator and pad up to a byte if applicable size_t dataCapacityBits = static_cast(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(dataCapacityBits - bb.size()))); bb.appendBits(0, (8 - static_cast(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 &segs, Ecc ecl, QrCode::QrCode(int ver, Ecc ecl, const vector &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); modules = vector >(sz, vector(sz)); // Initially all light @@ -332,9 +425,28 @@ QrCode::QrCode(int ver, Ecc ecl, const vector &dataCodewords, int msk) // Compute ECC, draw modules drawFunctionPatterns(); +#if defined(ACE_ENGINE_QRCODE_ABLE) + if (!flag) { + clearFunctionPatterns(); + return; + } +#endif + const vector 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 &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(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 QrCode::addEccAndInterleave(const vector &data) { + vector result; + if (data.size() != static_cast(getNumDataCodewords(version, errorCorrectionLevel))) { + flag = false; + return result; + } +#else vector QrCode::addEccAndInterleave(const vector &data) const { if (data.size() != static_cast(getNumDataCodewords(version, errorCorrectionLevel))) throw std::invalid_argument("Invalid argument"); +#endif // Calculate parameter numbers int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[static_cast(errorCorrectionLevel)][version]; @@ -509,10 +668,20 @@ vector QrCode::addEccAndInterleave(const vector &data) const { // Split data into blocks and append ECC to each block vector > blocks; const vector rsDiv = reedSolomonComputeDivisor(blockEccLen); +#if defined(ACE_ENGINE_QRCODE_ABLE) + if (!flag) { + return result; + } +#endif for (int i = 0, k = 0; i < numBlocks; i++) { vector dat(data.cbegin() + k, data.cbegin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1))); k += static_cast(dat.size()); const vector 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 QrCode::addEccAndInterleave(const vector &data) const { } // Interleave (not concatenate) the bytes from every block into a single sequence +#if !defined(ACE_ENGINE_QRCODE_ABLE) vector 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 QrCode::addEccAndInterleave(const vector &data) const { result.push_back(blocks.at(j).at(i)); } } +#if defined(ACE_ENGINE_QRCODE_ABLE) + if (result.size() != static_cast(rawCodewords)) + flag = false; +#else assert(result.size() == static_cast(rawCodewords)); +#endif return result; } void QrCode::drawCodewords(const vector &data) { +#if defined(ACE_ENGINE_QRCODE_ABLE) + if (data.size() != static_cast(getNumRawDataModules(version) / 8)) { + flag = false; + return; + } +#else if (data.size() != static_cast(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 &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); 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 QrCode::getAlignmentPatternPositions() const { if (version == 1) @@ -678,8 +876,10 @@ vector 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 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 result(static_cast(degree)); @@ -715,10 +919,20 @@ vector 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 QrCode::reedSolomonComputeRemainder(const vector &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(z); +#else assert(z >> 8 == 0); return static_cast(z); +#endif } - +#if !defined(ACE_ENGINE_QRCODE_ABLE) int QrCode::finderPenaltyCountPatterns(const std::array &runHistory) const { int n = runHistory.at(1); assert(n <= size * 3); @@ -775,6 +1004,15 @@ void QrCode::finderPenaltyAddHistory(int currentRunLength, std::array &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,12 +1022,24 @@ 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 +#if defined(ACE_ENGINE_QRCODE_ABLE) +const int8_t QrCode::ECC_CODEWORDS_PER_BLOCK[4][11] = { + // Version: (note that index 0 is for padding, and is set to an illegal value) + //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level + {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18}, // Low + {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26}, // Medium + {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24}, // Quartile + {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28}, // High +}; +#else const int8_t QrCode::ECC_CODEWORDS_PER_BLOCK[4][41] = { // Version: (note that index 0 is for padding, and is set to an illegal value) //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level @@ -798,7 +1048,18 @@ const int8_t QrCode::ECC_CODEWORDS_PER_BLOCK[4][41] = { {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High }; +#endif +#if defined(ACE_ENGINE_QRCODE_ABLE) +const int8_t QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][11] = { + // Version: (note that index 0 is for padding, and is set to an illegal value) + //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level + {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4}, // Low + {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5}, // Medium + {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8}, // Quartile + {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8}, // High +}; +#else const int8_t QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][41] = { // Version: (note that index 0 is for padding, and is set to an illegal value) //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level @@ -807,10 +1068,13 @@ const int8_t QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][41] = { {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High }; +#endif +#if !defined(ACE_ENGINE_QRCODE_ABLE) data_too_long::data_too_long(const std::string &msg) : std::length_error(msg) {} +#endif @@ -821,8 +1085,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); } diff --git a/cpp/qrcodegen.hpp b/cpp/qrcodegen.hpp index 944898264f6ceab5219e7fc288bd487d7178ad14..44d0d4d4637067c1666645e52714cf975cb4c568 100644 --- a/cpp/qrcodegen.hpp +++ b/cpp/qrcodegen.hpp @@ -22,6 +22,8 @@ */ #pragma once +#ifndef QRCODEEGEN_H +#define QRCODEEGEN_H #include #include @@ -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 &data); +#else public: static QrSegment makeBytes(const std::vector &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 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 &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 &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 &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 &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 &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 > 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 &dataCodewords, int msk); +#else public: QrCode(int ver, Ecc ecl, const std::vector &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 addEccAndInterleave(const std::vector &data); +#else private: std::vector addEccAndInterleave(const std::vector &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 reedSolomonComputeDivisor(int degree); +#else private: static std::vector 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 reedSolomonComputeRemainder(const std::vector &data, const std::vector &divisor); +#else private: static std::vector reedSolomonComputeRemainder(const std::vector &data, const std::vector &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 &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 &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,23 +553,39 @@ 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 = 10; +#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 - +#if defined(ACE_ENGINE_QRCODE_ABLE) + private: static const std::int8_t ECC_CODEWORDS_PER_BLOCK[4][11]; + private: static const std::int8_t NUM_ERROR_CORRECTION_BLOCKS[4][11]; +#else private: static const std::int8_t ECC_CODEWORDS_PER_BLOCK[4][41]; private: static const std::int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41]; +#endif }; @@ -547,3 +633,4 @@ class BitBuffer final : public std::vector { }; } +#endif // QRCODEEGEN_H