From 69cb9bf10e3bd8c7764d241e9e1dfe6d198f9899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=AF=E6=A5=A0?= Date: Mon, 18 Nov 2024 11:36:16 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E4=BF=AE=E5=A4=8DREADME=E5=BC=80=E6=BA=90?= =?UTF-8?q?=E5=85=B3=E9=94=AE=E8=AF=8D=E5=A4=9A=E4=BD=99=E7=A9=BA=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: fengnan --- README.OpenSource | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.OpenSource b/README.OpenSource index 59d72d2..457e18a 100755 --- a/README.OpenSource +++ b/README.OpenSource @@ -3,7 +3,7 @@ "Name": "QR-Code-generator", "License": "MIT License", "License File": "LICENSE", - "Version Number": " 1.8.0", + "Version Number": "1.8.0", "Owner": "guorensong1@huawei.com", "Upstream URL": "https://www.nayuki.io/page/qr-code-generator-library", "Description": "QR-Code-generator" -- Gitee From cfa3bb1e263698d2f51c373d2963b8b5c74b9298 Mon Sep 17 00:00:00 2001 From: zhoulianhai Date: Mon, 2 Dec 2024 19:56:44 +0800 Subject: [PATCH 2/5] =?UTF-8?q?qrcode=E7=8B=AC=E7=AB=8B=E7=BC=96=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhoulianhai Change-Id: Iafe147c3ecaebb8974a0f3b2b36190026befc6a0 --- BUILD.gn | 22 ++++ bundle.json | 10 +- cpp/qrcodegen.cpp | 257 +++++++++++++++++++++++++++++++++++++++++++++- cpp/qrcodegen.hpp | 122 ++++++++++++++++++---- 4 files changed, 384 insertions(+), 27 deletions(-) diff --git a/BUILD.gn b/BUILD.gn index 67e5601..3e285a1 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" + } + } } diff --git a/bundle.json b/bundle.json index e346b4b..285bce2 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 0957b79..5436957 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,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); } diff --git a/cpp/qrcodegen.hpp b/cpp/qrcodegen.hpp index 9448982..b7f12a0 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,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 { }; } +#endif // QRCODEEGEN_H -- Gitee From ca1c4bf479b69504b144824bebad5849f0c6b814 Mon Sep 17 00:00:00 2001 From: zhangzhongyuan Date: Fri, 18 Apr 2025 12:45:13 +0800 Subject: [PATCH 3/5] =?UTF-8?q?=E5=A2=9E=E5=8A=A0qrcode=E7=8B=AC=E7=AB=8B?= =?UTF-8?q?=E7=BC=96=E8=AF=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: zhangzhongyuan --- bundle.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/bundle.json b/bundle.json index 285bce2..63908ce 100644 --- a/bundle.json +++ b/bundle.json @@ -33,7 +33,17 @@ "inner_kits": [ { "name": "//third_party/qrcodegen:ace_engine_qrcode" + }, + { + "name": "//third_party/qrcodegen:qrcodegen_static", + "header": { + "header_files": [ + "qrcodegen.hpp" + ], + "header_base": "//third_party/qrcodegen/cpp" + } } + ], "test": [] } -- Gitee From 539beb32dfabf54af43b45c46fe9a8d619ff47ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E6=B1=9F=E8=AF=9A?= Date: Mon, 28 Apr 2025 11:05:06 +0800 Subject: [PATCH 4/5] =?UTF-8?q?=E5=A2=9E=E5=8A=A0qrode=E7=BC=96=E8=AF=91?= =?UTF-8?q?=20Signed-off-by:=20=E6=9D=A8=E6=B1=9F=E8=AF=9A=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- c/qrcodegen.c | 434 ++++++++++++++++++++++++++++---------------------- c/qrcodegen.h | 39 ++--- 2 files changed, 264 insertions(+), 209 deletions(-) diff --git a/c/qrcodegen.c b/c/qrcodegen.c index 8617044..546a4f4 100755 --- a/c/qrcodegen.c +++ b/c/qrcodegen.c @@ -21,7 +21,6 @@ * Software. */ -#include #include #include #include @@ -33,7 +32,6 @@ #define testable // Expose private functions #endif - /*---- Forward declarations for private functions ----*/ // Regarding all public and private functions defined in this source file: @@ -85,14 +83,26 @@ testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars); testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version); static int numCharCountBits(enum qrcodegen_Mode mode, int version); - - /*---- Private tables of constants ----*/ // The set of all legal characters in alphanumeric mode, where each character // value maps to the index in the string. For checking text and encoding segments. static const char *ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; +static int abs(int n) +{ + if (n < 0) { + return -n; + } + return n; +} +static long labs(long n) +{ + if (n < 0) { + return -n; + } + return n; +} // For generating error correction codes. testable const int8_t ECC_CODEWORDS_PER_BLOCK[4][41] = { // Version: (note that index 0 is for padding, and is set to an illegal value) @@ -121,19 +131,25 @@ static const int PENALTY_N2 = 3; static const int PENALTY_N3 = 40; static const int PENALTY_N4 = 10; - - +#ifdef INT16_MAX +#undef INT16_MAX +#endif +#ifdef SIZE_MAX +#undef SIZE_MAX +#endif +#define INT16_MAX 0x7fff +#define SIZE_MAX 65535 /*---- High-level QR Code encoding functions ----*/ // Public function - see documentation comment in header file. bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[], enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl) { - + size_t textLen = strlen(text); if (textLen == 0) return qrcodegen_encodeSegmentsAdvanced(NULL, 0, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode); size_t bufLen = (size_t)qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion); - + struct qrcodegen_Segment seg; if (qrcodegen_isNumeric(text)) { if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, textLen) > bufLen) @@ -146,7 +162,8 @@ bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode } else { if (textLen > bufLen) goto fail; - for (size_t i = 0; i < textLen; i++) + size_t i; + for (i = 0; i < textLen; i++) tempBuffer[i] = (uint8_t)text[i]; seg.mode = qrcodegen_Mode_BYTE; seg.bitLength = calcSegmentBitLength(seg.mode, textLen); @@ -156,17 +173,16 @@ bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode seg.data = tempBuffer; } return qrcodegen_encodeSegmentsAdvanced(&seg, 1, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode); - + fail: qrcode[0] = 0; // Set size to invalid value for safety return false; } - // Public function - see documentation comment in header file. bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[], enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl) { - + struct qrcodegen_Segment seg; seg.mode = qrcodegen_Mode_BYTE; seg.bitLength = calcSegmentBitLength(seg.mode, dataLen); @@ -179,17 +195,16 @@ bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcod return qrcodegen_encodeSegmentsAdvanced(&seg, 1, ecl, minVersion, maxVersion, mask, boostEcl, dataAndTemp, qrcode); } - // Appends the given number of low-order bits of the given value to the given byte-based // bit buffer, increasing the bit length. Requires 0 <= numBits <= 16 and val < 2^numBits. testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen) { - assert(0 <= numBits && numBits <= 16 && (unsigned long)val >> numBits == 0); - for (int i = numBits - 1; i >= 0; i--, (*bitLen)++) + if(!(0 <= numBits && numBits <= 16 && (unsigned long)val >> numBits == 0)) + return; + int i; + for (i = numBits - 1; i >= 0; i--, (*bitLen)++) buffer[*bitLen >> 3] |= ((val >> i) & 1) << (7 - (*bitLen & 7)); } - - /*---- Low-level QR Code encoding functions ----*/ // Public function - see documentation comment in header file. @@ -199,14 +214,15 @@ bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true, tempBuffer, qrcode); } - // Public function - see documentation comment in header file. bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl, uint8_t tempBuffer[], uint8_t qrcode[]) { - assert(segs != NULL || len == 0); - assert(qrcodegen_VERSION_MIN <= minVersion && minVersion <= maxVersion && maxVersion <= qrcodegen_VERSION_MAX); - assert(0 <= (int)ecl && (int)ecl <= 3 && -1 <= (int)mask && (int)mask <= 7); - + if (!(segs != NULL || len == 0)) + return false; + if (!(qrcodegen_VERSION_MIN <= minVersion && minVersion <= maxVersion && maxVersion <= qrcodegen_VERSION_MAX)) + return false; + if (!(0 <= (int)ecl && (int)ecl <= 3 && -1 <= (int)mask && (int)mask <= 7)) + return false; // Find the minimal version number to use int version, dataUsedBits; for (version = minVersion; ; version++) { @@ -219,53 +235,61 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz return false; } } - assert(dataUsedBits != -1); - + if (dataUsedBits == -1) { + return false; + } // Increase the error correction level while the data still fits in the current version number - for (int i = (int)qrcodegen_Ecc_MEDIUM; i <= (int)qrcodegen_Ecc_HIGH; i++) { // From low to high + int i, j; + for (i = (int)qrcodegen_Ecc_MEDIUM; i <= (int)qrcodegen_Ecc_HIGH; i++) { // From low to high if (boostEcl && dataUsedBits <= getNumDataCodewords(version, (enum qrcodegen_Ecc)i) * 8) ecl = (enum qrcodegen_Ecc)i; } - + // Concatenate all segments to create the data bit string memset(qrcode, 0, (size_t)qrcodegen_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0])); int bitLen = 0; - for (size_t i = 0; i < len; i++) { - const struct qrcodegen_Segment *seg = &segs[i]; + size_t k; + for (k = 0; k < len; k++) { + const struct qrcodegen_Segment *seg = &segs[k]; appendBitsToBuffer((unsigned int)seg->mode, 4, qrcode, &bitLen); appendBitsToBuffer((unsigned int)seg->numChars, numCharCountBits(seg->mode, version), qrcode, &bitLen); - for (int j = 0; j < seg->bitLength; j++) { + for (j = 0; j < seg->bitLength; j++) { int bit = (seg->data[j >> 3] >> (7 - (j & 7))) & 1; appendBitsToBuffer((unsigned int)bit, 1, qrcode, &bitLen); } } - assert(bitLen == dataUsedBits); - + if (bitLen != dataUsedBits) { + return false; + } // Add terminator and pad up to a byte if applicable int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; - assert(bitLen <= dataCapacityBits); + if (bitLen > dataCapacityBits) { + return false; + } 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); - + if (bitLen % 8 != 0) { + return false; + } // Pad with alternating bytes until data capacity is reached - for (uint8_t padByte = 0xEC; bitLen < dataCapacityBits; padByte ^= 0xEC ^ 0x11) + uint8_t padByte; + for (padByte = 0xEC; bitLen < dataCapacityBits; padByte ^= 0xEC ^ 0x11) { appendBitsToBuffer(padByte, 8, qrcode, &bitLen); - + } // Compute ECC, draw modules addEccAndInterleave(qrcode, version, ecl, tempBuffer); initializeFunctionModules(version, qrcode); drawCodewords(tempBuffer, getNumRawDataModules(version) / 8, qrcode); drawLightFunctionModules(qrcode, version); initializeFunctionModules(version, tempBuffer); - + // Do masking if (mask == qrcodegen_Mask_AUTO) { // Automatically choose best mask long minPenalty = LONG_MAX; - for (int i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) { enum qrcodegen_Mask msk = (enum qrcodegen_Mask)i; applyMask(tempBuffer, qrcode, msk); drawFormatBits(ecl, msk, qrcode); @@ -277,14 +301,13 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz applyMask(tempBuffer, qrcode, msk); // Undoes the mask due to XOR } } - assert(0 <= (int)mask && (int)mask <= 7); + if (!(0 <= (int)mask && (int)mask <= 7)) + return false; applyMask(tempBuffer, qrcode, mask); // Apply the final choice of mask drawFormatBits(ecl, mask, qrcode); // Overwrite old format bits return true; } - - /*---- Error correction code generation functions ----*/ // Appends error correction bytes to each block of the given data array, then interleaves @@ -293,40 +316,44 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz // be clobbered by this function. The final answer is stored in result[0 : rawCodewords]. testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]) { // Calculate parameter numbers - assert(0 <= (int)ecl && (int)ecl < 4 && qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX); + if (!(0 <= (int)ecl && (int)ecl < 4 && qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX)) { + return; + } int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[(int)ecl][version]; int blockEccLen = ECC_CODEWORDS_PER_BLOCK [(int)ecl][version]; int rawCodewords = getNumRawDataModules(version) / 8; int dataLen = getNumDataCodewords(version, ecl); int numShortBlocks = numBlocks - rawCodewords % numBlocks; int shortBlockDataLen = rawCodewords / numBlocks - blockEccLen; - + // Split data into blocks, calculate ECC, and interleave // (not concatenate) the bytes into a single sequence uint8_t rsdiv[qrcodegen_REED_SOLOMON_DEGREE_MAX]; reedSolomonComputeDivisor(blockEccLen, rsdiv); const uint8_t *dat = data; - for (int i = 0; i < numBlocks; i++) { + int i, j, k; + for (i = 0; i < numBlocks; i++) { int datLen = shortBlockDataLen + (i < numShortBlocks ? 0 : 1); uint8_t *ecc = &data[dataLen]; // Temporary storage reedSolomonComputeRemainder(dat, datLen, rsdiv, blockEccLen, ecc); - for (int j = 0, k = i; j < datLen; j++, k += numBlocks) { // Copy data + for (j = 0, k = i; j < datLen; j++, k += numBlocks) { // Copy data if (j == shortBlockDataLen) k -= numShortBlocks; result[k] = dat[j]; } - for (int j = 0, k = dataLen + i; j < blockEccLen; j++, k += numBlocks) // Copy ECC + for (j = 0, k = dataLen + i; j < blockEccLen; j++, k += numBlocks) // Copy ECC result[k] = ecc[j]; dat += datLen; } } - // Returns the number of 8-bit codewords that can be used for storing data (not ECC), // for the given version number and error correction level. The result is in the range [9, 2956]. testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl) { int v = version, e = (int)ecl; - assert(0 <= e && e < 4); + if (!(0 <= e && e < 4)) { + return 0; + } return getNumRawDataModules(v) / 8 - ECC_CODEWORDS_PER_BLOCK [e][v] * NUM_ERROR_CORRECTION_BLOCKS[e][v]; @@ -337,7 +364,9 @@ testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl) { // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8. // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table. testable int getNumRawDataModules(int ver) { - assert(qrcodegen_VERSION_MIN <= ver && ver <= qrcodegen_VERSION_MAX); + if (!(qrcodegen_VERSION_MIN <= ver && ver <= qrcodegen_VERSION_MAX)) { + return 0; + } int result = (16 * ver + 128) * ver + 64; if (ver >= 2) { int numAlign = ver / 7 + 2; @@ -345,30 +374,32 @@ testable int getNumRawDataModules(int ver) { if (ver >= 7) result -= 36; } - assert(208 <= result && result <= 29648); + if (!(208 <= result && result <= 29648)) { + return 0; + } return result; } - - /*---- Reed-Solomon ECC generator functions ----*/ // Computes a Reed-Solomon ECC generator polynomial for the given degree, storing in result[0 : degree]. // This could be implemented as a lookup table over all possible parameter values, instead of as an algorithm. testable void reedSolomonComputeDivisor(int degree, uint8_t result[]) { - assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX); + if (!(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX)) { + return; + } // 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}. memset(result, 0, (size_t)degree * sizeof(result[0])); result[degree - 1] = 1; // Start off with the monomial x^0 - // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), // drop the highest monomial term which is always 1x^degree. // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). uint8_t root = 1; - for (int i = 0; i < degree; i++) { + int i, j; + for (i = 0; i < degree; i++) { // Multiply the current product by (x - r^i) - for (int j = 0; j < degree; j++) { + for (j = 0; j < degree; j++) { result[j] = reedSolomonMultiply(result[j], root); if (j + 1 < degree) result[j] ^= result[j + 1]; @@ -377,40 +408,40 @@ testable void reedSolomonComputeDivisor(int degree, uint8_t result[]) { } } - // Computes the Reed-Solomon error correction codeword for the given data and divisor polynomials. // The remainder when data[0 : dataLen] is divided by divisor[0 : degree] is stored in result[0 : degree]. // All polynomials are in big endian, and the generator has an implicit leading 1 term. testable void reedSolomonComputeRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]) { - assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX); + if (!(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX)) { + return; + } memset(result, 0, (size_t)degree * sizeof(result[0])); - for (int i = 0; i < dataLen; i++) { // Polynomial division + int i, j; + for (i = 0; i < dataLen; i++) { // Polynomial division uint8_t factor = data[i] ^ result[0]; memmove(&result[0], &result[1], (size_t)(degree - 1) * sizeof(result[0])); result[degree - 1] = 0; - for (int j = 0; j < degree; j++) + for (j = 0; j < degree; j++) result[j] ^= reedSolomonMultiply(generator[j], factor); } } #undef qrcodegen_REED_SOLOMON_DEGREE_MAX - // 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. testable uint8_t reedSolomonMultiply(uint8_t x, uint8_t y) { // Russian peasant multiplication uint8_t z = 0; - for (int i = 7; i >= 0; i--) { + int i; + for (i = 7; i >= 0; i--) { z = (uint8_t)((z << 1) ^ ((z >> 7) * 0x11D)); z ^= ((y >> i) & 1) * x; } return z; } - - /*---- Drawing function modules ----*/ // Clears the given QR Code grid with light modules for the given @@ -420,27 +451,28 @@ testable void initializeFunctionModules(int version, uint8_t qrcode[]) { int qrsize = version * 4 + 17; memset(qrcode, 0, (size_t)((qrsize * qrsize + 7) / 8 + 1) * sizeof(qrcode[0])); qrcode[0] = (uint8_t)qrsize; - + // Fill horizontal and vertical timing patterns fillRectangle(6, 0, 1, qrsize, qrcode); fillRectangle(0, 6, qrsize, 1, qrcode); - + // Fill 3 finder patterns (all corners except bottom right) and format bits fillRectangle(0, 0, 9, 9, qrcode); fillRectangle(qrsize - 8, 0, 8, 9, qrcode); fillRectangle(0, qrsize - 8, 9, 8, qrcode); - + // Fill numerous alignment patterns uint8_t alignPatPos[7]; int numAlign = getAlignmentPatternPositions(version, alignPatPos); - for (int i = 0; i < numAlign; i++) { - for (int j = 0; j < numAlign; j++) { + int i, j; + for (i = 0; i < numAlign; i++) { + for (j = 0; j < numAlign; j++) { // Don't draw on the three finder corners if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0))) fillRectangle(alignPatPos[i] - 2, alignPatPos[j] - 2, 5, 5, qrcode); } } - + // Fill version blocks if (version >= 7) { fillRectangle(qrsize - 11, 0, 3, 6, qrcode); @@ -455,17 +487,19 @@ testable void initializeFunctionModules(int version, uint8_t qrcode[]) { static void drawLightFunctionModules(uint8_t qrcode[], int version) { // Draw horizontal and vertical timing patterns int qrsize = qrcodegen_getSize(qrcode); - for (int i = 7; i < qrsize - 7; i += 2) { + int i, j, dx, dy; + for (i = 7; i < qrsize - 7; i += 2) { setModuleBounded(qrcode, 6, i, false); setModuleBounded(qrcode, i, 6, false); } - + // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules) - for (int dy = -4; dy <= 4; dy++) { - for (int dx = -4; dx <= 4; dx++) { + for (dy = -4; dy <= 4; dy++) { + for (dx = -4; dx <= 4; dx++) { int dist = abs(dx); - if (abs(dy) > dist) + if (abs(dy) > dist) { dist = abs(dy); + } if (dist == 2 || dist == 4) { setModuleUnbounded(qrcode, 3 + dx, 3 + dy, false); setModuleUnbounded(qrcode, qrsize - 4 + dx, 3 + dy, false); @@ -473,33 +507,34 @@ static void drawLightFunctionModules(uint8_t qrcode[], int version) { } } } - + // Draw numerous alignment patterns uint8_t alignPatPos[7]; int numAlign = getAlignmentPatternPositions(version, alignPatPos); - for (int i = 0; i < numAlign; i++) { - for (int j = 0; j < numAlign; j++) { + for (i = 0; i < numAlign; i++) { + for (j = 0; j < numAlign; j++) { if ((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0)) continue; // Don't draw on the three finder corners - for (int dy = -1; dy <= 1; dy++) { - for (int dx = -1; dx <= 1; dx++) + for (dy = -1; dy <= 1; dy++) { + for (dx = -1; dx <= 1; dx++) setModuleBounded(qrcode, alignPatPos[i] + dx, alignPatPos[j] + dy, dx == 0 && dy == 0); } } } - + // Draw version blocks if (version >= 7) { // Calculate error correction code and pack bits int rem = version; // version is uint6, in the range [7, 40] - for (int i = 0; i < 12; i++) + for (i = 0; i < 12; i++) rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); long bits = (long)version << 12 | rem; // uint18 - assert(bits >> 18 == 0); - + if (!(bits >> 18 == 0)) { + return; + } // Draw two copies - for (int i = 0; i < 6; i++) { - for (int j = 0; j < 3; j++) { + for (i = 0; i < 6; i++) { + for (j = 0; j < 3; j++) { int k = qrsize - 11 + j; setModuleBounded(qrcode, k, i, (bits & 1) != 0); setModuleBounded(qrcode, i, k, (bits & 1) != 0); @@ -515,34 +550,37 @@ static void drawLightFunctionModules(uint8_t qrcode[], int version) { // the format bits, unlike drawLightFunctionModules() which might skip dark modules. static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[]) { // Calculate error correction code and pack bits - assert(0 <= (int)mask && (int)mask <= 7); + if (!(0 <= (int)mask && (int)mask <= 7)) { + return; + } static const int table[] = {1, 0, 3, 2}; int data = table[(int)ecl] << 3 | (int)mask; // errCorrLvl is uint2, mask is uint3 int rem = data; - for (int i = 0; i < 10; i++) + int i; + for (i = 0; i < 10; i++) rem = (rem << 1) ^ ((rem >> 9) * 0x537); int bits = (data << 10 | rem) ^ 0x5412; // uint15 - assert(bits >> 15 == 0); - + if (!(bits >> 15 == 0)) { + return; + } // Draw first copy - for (int i = 0; i <= 5; i++) + for (i = 0; i <= 5; i++) setModuleBounded(qrcode, 8, i, getBit(bits, i)); setModuleBounded(qrcode, 8, 7, getBit(bits, 6)); setModuleBounded(qrcode, 8, 8, getBit(bits, 7)); setModuleBounded(qrcode, 7, 8, getBit(bits, 8)); - for (int i = 9; i < 15; i++) + for (i = 9; i < 15; i++) setModuleBounded(qrcode, 14 - i, 8, getBit(bits, i)); // Draw second copy int qrsize = qrcodegen_getSize(qrcode); - for (int i = 0; i < 8; i++) + for (i = 0; i < 8; i++) setModuleBounded(qrcode, qrsize - 1 - i, 8, getBit(bits, i)); - for (int i = 8; i < 15; i++) + for (i = 8; i < 15; i++) setModuleBounded(qrcode, 8, qrsize - 15 + i, getBit(bits, i)); setModuleBounded(qrcode, 8, qrsize - 8, true); // Always dark } - // Calculates and stores an ascending list of positions of alignment patterns // for this version number, returning the length of the list (in the range [0,7]). // Each position is in the range [0,177), and are used on both the x and y axes. @@ -552,8 +590,9 @@ testable int getAlignmentPatternPositions(int version, uint8_t result[7]) { return 0; int numAlign = version / 7 + 2; int step = (version == 32) ? 26 : - (version * 4 + numAlign * 2 + 1) / (numAlign * 2 - 2) * 2; - for (int i = numAlign - 1, pos = version * 4 + 10; i >= 1; i--, pos -= step) + (version*4 + numAlign*2 + 1) / (numAlign*2 - 2) * 2; + int i, pos; + for (i = numAlign - 1, pos = version * 4 + 10; i >= 1; i--, pos -= step) result[i] = (uint8_t)pos; result[0] = 6; return numAlign; @@ -562,27 +601,26 @@ testable int getAlignmentPatternPositions(int version, uint8_t result[7]) { // Sets every module in the range [left : left + width] * [top : top + height] to dark. static void fillRectangle(int left, int top, int width, int height, uint8_t qrcode[]) { - for (int dy = 0; dy < height; dy++) { - for (int dx = 0; dx < width; dx++) + int dy, dx; + for (dy = 0; dy < height; dy++) { + for (dx = 0; dx < width; dx++) setModuleBounded(qrcode, left + dx, top + dy, true); } } - - /*---- Drawing data modules and masking ----*/ // Draws the raw codewords (including data and ECC) onto the given QR Code. This requires the initial state of -// the QR Code to be dark at function modules and light at codeword modules (including unused remainder bits). static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]) { int qrsize = qrcodegen_getSize(qrcode); int i = 0; // Bit index into the data // Do the funny zigzag scan - for (int right = qrsize - 1; right >= 1; right -= 2) { // Index of right column in each column pair + int right, vert, j; + for (right = qrsize - 1; right >= 1; right -= 2) { // Index of right column in each column pair if (right == 6) right = 5; - for (int vert = 0; vert < qrsize; vert++) { // Vertical counter - for (int j = 0; j < 2; j++) { + for (vert = 0; vert < qrsize; vert++) { // Vertical counter + for (j = 0; j < 2; j++) { int x = right - j; // Actual x coordinate bool upward = ((right + 1) & 2) == 0; int y = upward ? qrsize - 1 - vert : vert; // Actual y coordinate @@ -596,7 +634,9 @@ static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]) { } } } - assert(i == dataLen * 8); + if (!(i == dataLen * 8)) { + return; + } } @@ -606,10 +646,13 @@ static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]) { // the same mask value a second time will undo the mask. A final well-formed // QR Code needs exactly one (not zero, two, etc.) mask applied. static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qrcodegen_Mask mask) { - assert(0 <= (int)mask && (int)mask <= 7); // Disallows qrcodegen_Mask_AUTO + if (!(0 <= (int)mask && (int)mask <= 7)) { // Disallows qrcodegen_Mask_AUTO + return; + } int qrsize = qrcodegen_getSize(qrcode); - for (int y = 0; y < qrsize; y++) { - for (int x = 0; x < qrsize; x++) { + int x, y; + for (y = 0; y < qrsize; y++) { + for (x = 0; x < qrsize; x++) { if (getModuleBounded(functionModules, x, y)) continue; bool invert; @@ -622,7 +665,7 @@ static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qr 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; - default: assert(false); return; + default: return; } bool val = getModuleBounded(qrcode, x, y); setModuleBounded(qrcode, x, y, val ^ invert); @@ -630,19 +673,18 @@ static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qr } } - // Calculates and returns the penalty score based on state of the given QR Code's current modules. // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score. static long getPenaltyScore(const uint8_t qrcode[]) { int qrsize = qrcodegen_getSize(qrcode); long result = 0; - // Adjacent modules in row having same color, and finder-like patterns - for (int y = 0; y < qrsize; y++) { + int x, y; + for (y = 0; y < qrsize; y++) { bool runColor = false; int runX = 0; int runHistory[7] = {0}; - for (int x = 0; x < qrsize; x++) { + for (x = 0; x < qrsize; x++) { if (getModuleBounded(qrcode, x, y) == runColor) { runX++; if (runX == 5) @@ -660,11 +702,11 @@ static long getPenaltyScore(const uint8_t qrcode[]) { result += finderPenaltyTerminateAndCount(runColor, runX, runHistory, qrsize) * PENALTY_N3; } // Adjacent modules in column having same color, and finder-like patterns - for (int x = 0; x < qrsize; x++) { + for (x = 0; x < qrsize; x++) { bool runColor = false; int runY = 0; int runHistory[7] = {0}; - for (int y = 0; y < qrsize; y++) { + for (y = 0; y < qrsize; y++) { if (getModuleBounded(qrcode, x, y) == runColor) { runY++; if (runY == 5) @@ -681,10 +723,10 @@ static long getPenaltyScore(const uint8_t qrcode[]) { } result += finderPenaltyTerminateAndCount(runColor, runY, runHistory, qrsize) * PENALTY_N3; } - + // 2*2 blocks of modules having same color - for (int y = 0; y < qrsize - 1; y++) { - for (int x = 0; x < qrsize - 1; x++) { + for (y = 0; y < qrsize - 1; y++) { + for (x = 0; x < qrsize - 1; x++) { bool color = getModuleBounded(qrcode, x, y); if ( color == getModuleBounded(qrcode, x + 1, y) && color == getModuleBounded(qrcode, x, y + 1) && @@ -692,11 +734,11 @@ static long getPenaltyScore(const uint8_t qrcode[]) { result += PENALTY_N2; } } - + // Balance of dark and light modules int dark = 0; - for (int y = 0; y < qrsize; y++) { - for (int x = 0; x < qrsize; x++) { + for (y = 0; y < qrsize; y++) { + for (x = 0; x < qrsize; x++) { if (getModuleBounded(qrcode, x, y)) dark++; } @@ -704,26 +746,31 @@ static long getPenaltyScore(const uint8_t qrcode[]) { int total = qrsize * qrsize; // Note that size is odd, so dark/total != 1/2 // Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)% int k = (int)((labs(dark * 20L - total * 10L) + total - 1) / total) - 1; - assert(0 <= k && k <= 9); + if (0 <= k && k <= 9) { + return 0; + } result += k * PENALTY_N4; - assert(0 <= result && result <= 2568888L); // Non-tight upper bound based on default values of PENALTY_N1, ..., N4 + if (0 <= result && result <= 2568888L) { // Non-tight upper bound based on default values of PENALTY_N1, ..., N4 + return 0; + } return result; } - // Can only be called immediately after a light run is added, and // returns either 0, 1, or 2. A helper function for getPenaltyScore(). static int finderPenaltyCountPatterns(const int runHistory[7], int qrsize) { int n = runHistory[1]; - assert(n <= qrsize * 3); (void)qrsize; + if (!(n <= qrsize * 3)) { + return -1; + } + (void)qrsize; bool core = n > 0 && runHistory[2] == n && runHistory[3] == n * 3 && runHistory[4] == n && runHistory[5] == n; // The maximum QR Code size is 177, hence the dark run length n <= 177. // Arithmetic is promoted to int, so n*4 will not overflow. - return (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0) - + (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0); + return (core && runHistory[0] >= n * 4 && runHistory[6] >= n ? 1 : 0) + + (core && runHistory[6] >= n * 4 && runHistory[0] >= n ? 1 : 0); } - // Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore(). static int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int runHistory[7], int qrsize) { if (currentRunColor) { // Terminate dark run @@ -735,7 +782,6 @@ static int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLe return finderPenaltyCountPatterns(runHistory, qrsize); } - // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore(). static void finderPenaltyAddHistory(int currentRunLength, int runHistory[7], int qrsize) { if (runHistory[0] == 0) @@ -744,23 +790,25 @@ static void finderPenaltyAddHistory(int currentRunLength, int runHistory[7], int runHistory[0] = currentRunLength; } - - /*---- Basic QR Code information ----*/ - // Public function - see documentation comment in header file. int qrcodegen_getSize(const uint8_t qrcode[]) { - assert(qrcode != NULL); + if(!(qrcode != NULL)) { + return 0; + } int result = qrcode[0]; - assert((qrcodegen_VERSION_MIN * 4 + 17) <= result - && result <= (qrcodegen_VERSION_MAX * 4 + 17)); + if(!((qrcodegen_VERSION_MIN * 4 + 17) <= result && + result <= (qrcodegen_VERSION_MAX * 4 + 17))) { + return 0; + } return result; } - // Public function - see documentation comment in header file. bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y) { - assert(qrcode != NULL); + if(!(qrcode != NULL)) { + return false; + } int qrsize = qrcode[0]; return (0 <= x && x < qrsize && 0 <= y && y < qrsize) && getModuleBounded(qrcode, x, y); } @@ -769,7 +817,10 @@ bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y) { // Returns the color of the module at the given coordinates, which must be in bounds. testable bool getModuleBounded(const uint8_t qrcode[], int x, int y) { int qrsize = qrcode[0]; - assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize); + if (!(21 <= qrsize && qrsize <= 177 && + 0 <= x && x < qrsize && 0 <= y && y < qrsize)) { + return false; + } int index = y * qrsize + x; return getBit(qrcode[(index >> 3) + 1], index & 7); } @@ -778,12 +829,16 @@ testable bool getModuleBounded(const uint8_t qrcode[], int x, int y) { // Sets the color of the module at the given coordinates, which must be in bounds. testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isDark) { int qrsize = qrcode[0]; - assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize); + if (!(21 <= qrsize && qrsize <= 177 && + 0 <= x && x < qrsize && 0 <= y && y < qrsize)) { + return; + } int index = y * qrsize + x; int bitIndex = index & 7; int byteIndex = (index >> 3) + 1; - if (isDark) + if (isDark) { qrcode[byteIndex] |= 1 << bitIndex; + } else qrcode[byteIndex] &= (1 << bitIndex) ^ 0xFF; } @@ -796,48 +851,49 @@ testable void setModuleUnbounded(uint8_t qrcode[], int x, int y, bool isDark) { setModuleBounded(qrcode, x, y, isDark); } +// Public function - see documentation comment in header file. +bool qrcodegen_isAlphanumeric(const char *text) { + if (text == NULL) { + return false; + } + for (; *text != '\0'; text++) { + if (strchr(ALPHANUMERIC_CHARSET, *text) == NULL) + return false; + } + return true; +} // Returns true iff the i'th bit of x is set to 1. Requires x >= 0 and 0 <= i <= 14. static bool getBit(int x, int i) { return ((x >> i) & 1) != 0; } - - /*---- Segment handling ----*/ // Public function - see documentation comment in header file. bool qrcodegen_isNumeric(const char *text) { - assert(text != NULL); - for (; *text != '\0'; text++) { - if (*text < '0' || *text > '9') - return false; + if (text == NULL) { + return false; } - return true; -} - - -// Public function - see documentation comment in header file. -bool qrcodegen_isAlphanumeric(const char *text) { - assert(text != NULL); for (; *text != '\0'; text++) { - if (strchr(ALPHANUMERIC_CHARSET, *text) == NULL) + if (*text < '0' || *text > '9') return false; } return true; } - // Public function - see documentation comment in header file. size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars) { int temp = calcSegmentBitLength(mode, numChars); - if (temp == -1) + if (temp == -1) { + return SIZE_MAX; + } + if (!(0 <= temp && temp <= INT16_MAX)) { return SIZE_MAX; - assert(0 <= temp && temp <= INT16_MAX); + } return ((size_t)temp + 7) / 8; } - // Returns the number of data bits needed to represent a segment // containing the given number of characters using the given mode. Notes: // - Returns -1 on failure, i.e. numChars > INT16_MAX or @@ -862,23 +918,21 @@ testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars) { else if (mode == qrcodegen_Mode_ECI && numChars == 0) result = 3 * 8; else { // Invalid argument - assert(false); return -1; } - assert(result >= 0); + if (result < 0) { + return -1; + } if (result > INT16_MAX) return -1; return (int)result; } - // Public function - see documentation comment in header file. struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]) { - assert(data != NULL || len == 0); struct qrcodegen_Segment result; result.mode = qrcodegen_Mode_BYTE; result.bitLength = calcSegmentBitLength(result.mode, len); - assert(result.bitLength != -1); result.numChars = (int)len; if (len > 0) memcpy(buf, data, len * sizeof(buf[0])); @@ -886,25 +940,21 @@ struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, u return result; } - // Public function - see documentation comment in header file. struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]) { - assert(digits != NULL); struct qrcodegen_Segment result; size_t len = strlen(digits); result.mode = qrcodegen_Mode_NUMERIC; int bitLen = calcSegmentBitLength(result.mode, len); - assert(bitLen != -1); result.numChars = (int)len; if (bitLen > 0) memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0])); result.bitLength = 0; - + unsigned int accumData = 0; int accumCount = 0; for (; *digits != '\0'; digits++) { char c = *digits; - assert('0' <= c && c <= '9'); accumData = accumData * 10 + (unsigned int)(c - '0'); accumCount++; if (accumCount == 3) { @@ -915,30 +965,25 @@ struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[] } if (accumCount > 0) // 1 or 2 digits remaining appendBitsToBuffer(accumData, accumCount * 3 + 1, buf, &result.bitLength); - assert(result.bitLength == bitLen); result.data = buf; return result; } - // Public function - see documentation comment in header file. struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]) { - assert(text != NULL); struct qrcodegen_Segment result; size_t len = strlen(text); result.mode = qrcodegen_Mode_ALPHANUMERIC; int bitLen = calcSegmentBitLength(result.mode, len); - assert(bitLen != -1); result.numChars = (int)len; if (bitLen > 0) memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0])); result.bitLength = 0; - + unsigned int accumData = 0; int accumCount = 0; for (; *text != '\0'; text++) { - const char *temp = strchr(ALPHANUMERIC_CHARSET, *text); - assert(temp != NULL); + const char *temp = (char *)strchr(ALPHANUMERIC_CHARSET, *text); accumData = accumData * 45 + (unsigned int)(temp - ALPHANUMERIC_CHARSET); accumCount++; if (accumCount == 2) { @@ -949,12 +994,10 @@ struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t bu } if (accumCount > 0) // 1 character remaining appendBitsToBuffer(accumData, 6, buf, &result.bitLength); - assert(result.bitLength == bitLen); result.data = buf; return result; } - // Public function - see documentation comment in header file. struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]) { struct qrcodegen_Segment result; @@ -962,7 +1005,7 @@ struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]) { result.numChars = 0; result.bitLength = 0; if (assignVal < 0) - assert(false); + return result; else if (assignVal < (1 << 7)) { memset(buf, 0, 1 * sizeof(buf[0])); appendBitsToBuffer((unsigned int)assignVal, 8, buf, &result.bitLength); @@ -976,40 +1019,51 @@ struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]) { appendBitsToBuffer((unsigned int)(assignVal >> 10), 11, buf, &result.bitLength); appendBitsToBuffer((unsigned int)(assignVal & 0x3FF), 10, buf, &result.bitLength); } else - assert(false); + return result; result.data = buf; return result; } - // Calculates the number of bits needed to encode the given segments at the given version. // Returns a non-negative number if successful. Otherwise returns -1 if a segment has too // many characters to fit its length field, or the total bits exceeds INT16_MAX. testable int getTotalBits(const struct qrcodegen_Segment segs[], size_t len, int version) { - assert(segs != NULL || len == 0); + if (!(segs != NULL || len == 0)) { + return -1; + } long result = 0; - for (size_t i = 0; i < len; i++) { + size_t i; + for (i = 0; i < len; i++) { int numChars = segs[i].numChars; int bitLength = segs[i].bitLength; - assert(0 <= numChars && numChars <= INT16_MAX); - assert(0 <= bitLength && bitLength <= INT16_MAX); + if (!(0 <= numChars && numChars <= INT16_MAX)) { + return -1; + } + if (!(0 <= bitLength && bitLength <= INT16_MAX)) { + return -1; + } int ccbits = numCharCountBits(segs[i].mode, version); - assert(0 <= ccbits && ccbits <= 16); + if (!(0 <= ccbits && ccbits <= 16)) { + return -1; + } if (numChars >= (1L << ccbits)) return -1; // The segment's length doesn't fit the field's bit width result += 4L + ccbits + bitLength; if (result > INT16_MAX) return -1; // The sum might overflow an int type } - assert(0 <= result && result <= INT16_MAX); + if (!(0 <= result && result <= INT16_MAX)) { + return -1; + } return (int)result; } - // Returns the bit width of the character count field for a segment in the given mode // in a QR Code at the given version number. The result is in the range [0, 16]. static int numCharCountBits(enum qrcodegen_Mode mode, int version) { - assert(qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX); + if (!(qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX)) { + return -1; + } int i = (version + 7) / 17; switch (mode) { case qrcodegen_Mode_NUMERIC : { static const int temp[] = {10, 12, 14}; return temp[i]; } @@ -1017,6 +1071,6 @@ static int numCharCountBits(enum qrcodegen_Mode mode, int version) { case qrcodegen_Mode_BYTE : { static const int temp[] = { 8, 16, 16}; return temp[i]; } case qrcodegen_Mode_KANJI : { static const int temp[] = { 8, 10, 12}; return temp[i]; } case qrcodegen_Mode_ECI : return 0; - default: assert(false); return -1; // Dummy value + default: return(false); return -1; // Dummy value } } diff --git a/c/qrcodegen.h b/c/qrcodegen.h index 6bbc157..7f59b85 100755 --- a/c/qrcodegen.h +++ b/c/qrcodegen.h @@ -1,4 +1,4 @@ -/* +/* * QR Code generator library (C) * * Copyright (c) Project Nayuki. (MIT License) @@ -32,8 +32,9 @@ extern "C" { #endif +char *strchr(const char *s, int c); -/* +/* * This library creates QR Code symbols, which is a type of two-dimension barcode. * Invented by Denso Wave and described in the ISO/IEC 18004 standard. * A QR Code structure is an immutable square grid of dark and light cells. @@ -51,7 +52,7 @@ extern "C" { /*---- Enum and struct types----*/ -/* +/* * The error correction level in a QR Code symbol. */ enum qrcodegen_Ecc { @@ -64,7 +65,7 @@ enum qrcodegen_Ecc { }; -/* +/* * The mask pattern used in a QR Code symbol. */ enum qrcodegen_Mask { @@ -83,7 +84,7 @@ enum qrcodegen_Mask { }; -/* +/* * Describes how a segment's data bits are interpreted. */ enum qrcodegen_Mode { @@ -95,7 +96,7 @@ enum qrcodegen_Mode { }; -/* +/* * A segment of character/binary/control data in a QR Code symbol. * The mid-level way to create a segment is to take the payload data * and call a factory function such as qrcodegen_makeNumeric(). @@ -147,7 +148,7 @@ struct qrcodegen_Segment { /*---- Functions (high level) to generate QR Codes ----*/ -/* +/* * Encodes the given text string to a QR Code, returning true if successful. * If the data is too long to fit in any version in the given range * at the given ECC level, then false is returned. @@ -188,7 +189,7 @@ bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl); -/* +/* * Encodes the given binary data to a QR Code, returning true if successful. * If the data is too long to fit in any version in the given range * at the given ECC level, then false is returned. @@ -229,7 +230,7 @@ bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcod /*---- Functions (low level) to generate QR Codes ----*/ -/* +/* * Encodes the given segments to a QR Code, returning true if successful. * If the data is too long to fit in any version at the given ECC level, * then false is returned. @@ -264,7 +265,7 @@ bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]); -/* +/* * Encodes the given segments to a QR Code, returning true if successful. * If the data is too long to fit in any version in the given range * at the given ECC level, then false is returned. @@ -303,14 +304,14 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl, uint8_t tempBuffer[], uint8_t qrcode[]); -/* +/* * Tests whether the given string can be encoded as a segment in numeric mode. * A string is encodable iff each character is in the range 0 to 9. */ bool qrcodegen_isNumeric(const char *text); -/* +/* * Tests whether the given string can be encoded as a segment in alphanumeric mode. * A string is encodable iff each character is in the following set: 0 to 9, A to Z * (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon. @@ -318,7 +319,7 @@ bool qrcodegen_isNumeric(const char *text); bool qrcodegen_isAlphanumeric(const char *text); -/* +/* * Returns the number of bytes (uint8_t) needed for the data buffer of a segment * containing the given number of characters using the given mode. Notes: * - Returns SIZE_MAX on failure, i.e. numChars > INT16_MAX or the internal @@ -332,7 +333,7 @@ bool qrcodegen_isAlphanumeric(const char *text); size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars); -/* +/* * Returns a segment representing the given binary data encoded in * byte mode. All input byte arrays are acceptable. Any text string * can be converted to UTF-8 bytes and encoded as a byte mode segment. @@ -340,13 +341,13 @@ size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]); -/* +/* * Returns a segment representing the given string of decimal digits encoded in numeric mode. */ struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]); -/* +/* * Returns a segment representing the given text string encoded in alphanumeric mode. * The characters allowed are: 0 to 9, A to Z (uppercase only), space, * dollar, percent, asterisk, plus, hyphen, period, slash, colon. @@ -354,7 +355,7 @@ struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[] struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]); -/* +/* * Returns a segment representing an Extended Channel Interpretation * (ECI) designator with the given assignment value. */ @@ -363,7 +364,7 @@ struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]); /*---- Functions to extract raw data from QR Codes ----*/ -/* +/* * Returns the side length of the given QR Code, assuming that encoding succeeded. * The result is in the range [21, 177]. Note that the length of the array buffer * is related to the side length - every 'uint8_t qrcode[]' must have length at least @@ -372,7 +373,7 @@ struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]); int qrcodegen_getSize(const uint8_t qrcode[]); -/* +/* * Returns the color of the module (pixel) at the given coordinates, which is false * for light or true for dark. The top left corner has the coordinates (x=0, y=0). * If the given coordinates are out of bounds, then false (light) is returned. -- Gitee From 3ef72385f064e545b6a74e98f486015caf537573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=AD=E6=A2=A6=E7=8E=891?= Date: Mon, 23 Jun 2025 08:40:06 +0000 Subject: [PATCH 5/5] add LICENSE. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 郭梦玉1 --- LICENSE | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..0efd517 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 The Khronos Group Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. -- Gitee