diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index be4ec9bcde..64c997cb11 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -152,6 +152,7 @@ jobs: fetch_dep sqlite3 "${platform}" "${arch}" SQLITE3_GITHUB_TOKEN SQLITE3_RELEASE_TAG SQLITE3_GITHUB_REPO fetch_dep mbedtls "${platform}" "${arch}" MBEDTLS_GITHUB_TOKEN MBEDTLS_RELEASE_TAG MBEDTLS_GITHUB_REPO fetch_dep axtls "${platform}" "${arch}" AXTLS_GITHUB_TOKEN AXTLS_RELEASE_TAG AXTLS_GITHUB_REPO + fetch_dep qrcodegen "${platform}" "${arch}" QRCODEGEN_GITHUB_TOKEN QRCODEGEN_RELEASE_TAG QRCODEGEN_GITHUB_REPO fetch_dep skia "${platform}" "${arch}" SKIA_GITHUB_TOKEN SKIA_RELEASE_TAG SKIA_GITHUB_REPO --install-dev done @@ -777,7 +778,9 @@ jobs: run: | cmake ../ \ -GXcode \ - -DCMAKE_SYSTEM_NAME=iOS + -DCMAKE_SYSTEM_NAME=iOS \ + -DCMAKE_OSX_SYSROOT=iphoneos \ + -DCMAKE_OSX_ARCHITECTURES=arm64 ruby -pi -e "gsub(\"config.build_settings['ARCHS[sdk=iphonesimulator*]'] = 'x86_64'\", \"config.build_settings['ARCHS[sdk=iphonesimulator*]'] = 'arm64'\")" Podfile pod install /usr/libexec/PlistBuddy -c "Add :DisableBuildSystemDeprecationDiagnostic bool" TotalCross.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings || true diff --git a/TotalCrossVM/CMakeLists.txt b/TotalCrossVM/CMakeLists.txt index 62d640744b..1f5ac58eed 100644 --- a/TotalCrossVM/CMakeLists.txt +++ b/TotalCrossVM/CMakeLists.txt @@ -81,12 +81,41 @@ if (NOT DEFINED AXTLS_AUTO_FETCH) set(AXTLS_AUTO_FETCH ON) endif() +if (NOT DEFINED QRCODE_AUTO_FETCH) + set(QRCODE_AUTO_FETCH ON) +endif() + +if (NOT DEFINED QRCODEGEN_AUTO_FETCH) + set(QRCODEGEN_AUTO_FETCH ON) +endif() + if(TCVM_SHARED) add_library(tcvm SHARED) else() add_library(tcvm STATIC) endif() +# qrcodegen is the default backend and is mandatory for _MSC_VER. +set(TC_QRCODE_MSVC_COMPATIBLE OFF) +set(TC_QRCODE_USE_QRCODEGEN_DEFAULT ON) +if(MSVC OR CMAKE_C_SIMULATE_ID STREQUAL "MSVC") + set(TC_QRCODE_MSVC_COMPATIBLE ON) +endif() + +option(TC_QRCODE_USE_QRCODEGEN + "Use qrcodegen instead of qrcode to generate QR codes" + ${TC_QRCODE_USE_QRCODEGEN_DEFAULT}) + +if(TC_QRCODE_MSVC_COMPATIBLE AND NOT TC_QRCODE_USE_QRCODEGEN) + message(FATAL_ERROR "TC_QRCODE_USE_QRCODEGEN must be ON when compiling with _MSC_VER") +endif() + +if(TC_QRCODE_USE_QRCODEGEN) + target_compile_definitions(tcvm PRIVATE TC_QRCODE_USE_QRCODEGEN=1) +else() + target_compile_definitions(tcvm PRIVATE TC_QRCODE_USE_QRCODEGEN=0) +endif() + # Force using madler zlib on wince instead of zlib-ng, which isn't supported if(NOT DEFINED USE_MADLER_ZLIB) if(TARGET_WINCE) @@ -128,6 +157,8 @@ if(NOT EXISTS "${TCVM_DEPOT_TOOLS_DIR}/deps.yml") endif() set(CMAKE_MODULE_PATH + "${TCVM_DEPOT_TOOLS_DIR}/qrcode/cmake" + "${TCVM_DEPOT_TOOLS_DIR}/qrcodegen/cmake" "${TCVM_DEPOT_TOOLS_DIR}/zlib-ng/cmake" "${TCVM_DEPOT_TOOLS_DIR}/minizip-ng/cmake" "${TCVM_DEPOT_TOOLS_DIR}/libpng/cmake" @@ -165,6 +196,12 @@ foreach(TCVM_DEP_CACHE_VAR AXTLS_DIR AXTLS_INCLUDE_DIR AXTLS_LIBRARY + QRCODE_DIR + QRCODE_INCLUDE_DIR + QRCODE_LIBRARY + QRCODEGEN_DIR + QRCODEGEN_INCLUDE_DIR + QRCODEGEN_LIBRARY SKIA_CONFIG_INCLUDE_DIR SKIA_CORE_INCLUDE_DIR SKIA_UTILS_INCLUDE_DIR @@ -192,6 +229,22 @@ if(AXTLS_AUTO_FETCH) endif() find_package(AxTLS REQUIRED) +if(TC_QRCODE_USE_QRCODEGEN) + include("${TCVM_DEPOT_TOOLS_DIR}/qrcodegen/cmake/AutoFetchQRCodeGen.cmake") + if(QRCODEGEN_AUTO_FETCH) + tcvm_auto_fetch_qrcodegen() + endif() + find_package(QRCodeGen REQUIRED) + set(TC_QRCODE_LIBRARY QRCodeGen::QRCodeGen) +else() + include("${TCVM_DEPOT_TOOLS_DIR}/qrcode/cmake/AutoFetchQRCode.cmake") + if(QRCODE_AUTO_FETCH) + tcvm_auto_fetch_qrcode() + endif() + find_package(QRCode REQUIRED) + set(TC_QRCODE_LIBRARY QRCode::QRCode) +endif() + if(TARGET_WINCE) if(NOT DEFINED MINIZIP_DIR) message(FATAL_ERROR @@ -268,7 +321,7 @@ endif() add_subdirectory(third_party) if(CMAKE_GENERATOR STREQUAL Xcode) - target_link_libraries(tcvm PRIVATE zlibstatic png_static JPEG::JPEG SQLite::SQLite3 MINIZIP::MINIZIP AxTLS::AxTLS) + target_link_libraries(tcvm PRIVATE zlibstatic png_static JPEG::JPEG SQLite::SQLite3 MINIZIP::MINIZIP AxTLS::AxTLS ${TC_QRCODE_LIBRARY}) if(NOT TARGET_WINCE) target_link_libraries(tcvm PRIVATE MbedTLS::mbedtls @@ -278,6 +331,7 @@ if(CMAKE_GENERATOR STREQUAL Xcode) endif() else() target_link_libraries(tcvm zlibstatic) + target_link_libraries(tcvm ${TC_QRCODE_LIBRARY}) target_link_libraries(tcvm MINIZIP::MINIZIP) target_link_libraries(tcvm AxTLS::AxTLS) target_link_libraries(tcvm png_static) @@ -459,14 +513,12 @@ endif(UNIX AND NOT (DEFINED ANDROID_ABI OR APPLE)) if(MSVC) set(TC_MSVC_SOURCES ${TC_SRCDIR}/util/winsockLib.c - ${TC_SRCDIR}/nm/qrcode/win/qrcodegen.c ) endif(MSVC) if(NOT MSVC) set(TC_NOT_MSVC_SOURCES ${TC_SRCDIR}/nm/lang/posix/cpproc.c - ${TC_SRCDIR}/nm/qrcode/qrcode.c ) endif(NOT MSVC) @@ -581,15 +633,13 @@ include_directories(${TC_SRCDIR}/tcvm) include_directories(${TC_SRCDIR}/util) include_directories(${TC_SRCDIR}/util/android) -if(MSVC) - include_directories(${TC_SRCDIR}/nm/qrcode/win) - if(TARGET_WINCE) - include_directories(${TC_SRCDIR}/core/wince) # Only include this folder for WinCE! - endif() -else() - include_directories(${TC_SRCDIR}/nm/qrcode) +if(MSVC AND TARGET_WINCE) + include_directories(${TC_SRCDIR}/core/wince) # Only include this folder for WinCE! +endif() + +if(NOT MSVC) include_directories(${TC_SRCDIR}/nm/lang/posix) -endif(MSVC) +endif() # add_definitions if(DEFINED ANDROID_ABI) @@ -653,6 +703,10 @@ endif() # XCode Properties if(CMAKE_GENERATOR STREQUAL Xcode) # Fold prebuilt native dependencies into libtcvm.a at archive creation time. + get_target_property(TC_QRCODE_LIBRARY_PATH ${TC_QRCODE_LIBRARY} IMPORTED_LOCATION) + if(NOT TC_QRCODE_LIBRARY_PATH) + message(FATAL_ERROR "Unable to resolve the selected QR Code static library") + endif() set(TCVM_XCODE_ARCHIVE_DEPENDENCIES "${PNG_LIBRARY}" "${ZLIB_LIBRARY}" @@ -661,6 +715,7 @@ if(CMAKE_GENERATOR STREQUAL Xcode) "${SQLITE3_LIBRARIES}" "${MBEDTLS_LIBRARIES}" "${AXTLS_LIBRARY}" + "${TC_QRCODE_LIBRARY_PATH}" ) if(TCVM_ENABLE_SKIA) set(TCVM_XCODE_ARCHIVE_DEPENDENCIES diff --git a/TotalCrossVM/deps/totalcross-depot-tools.ref b/TotalCrossVM/deps/totalcross-depot-tools.ref index 7a7de80aa7..2b7d60ab9d 100644 --- a/TotalCrossVM/deps/totalcross-depot-tools.ref +++ b/TotalCrossVM/deps/totalcross-depot-tools.ref @@ -2,4 +2,4 @@ # # SPDX-License-Identifier: LGPL-2.1-only -axtls-2.1.5-tc.1 +qrcodegen-20250123 diff --git a/TotalCrossVM/src/nm/qrcode/qrcode.c b/TotalCrossVM/src/nm/qrcode/qrcode.c deleted file mode 100644 index 940c06eef8..0000000000 --- a/TotalCrossVM/src/nm/qrcode/qrcode.c +++ /dev/null @@ -1,872 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2017 Richard Moore - * - * 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. - */ - -/** - * Special thanks to Nayuki (https://www.nayuki.io/) from which this library was - * heavily inspired and compared against. - * - * See: https://github.com/nayuki/QR-Code-generator/tree/master/cpp - */ - -#include "qrcode.h" - -#include -#include - -#pragma mark - Error Correction Lookup tables - -#if LOCK_VERSION == 0 - -static const uint16_t NUM_ERROR_CORRECTION_CODEWORDS[4][40] = { - // 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 - { 10, 16, 26, 36, 48, 64, 72, 88, 110, 130, 150, 176, 198, 216, 240, 280, 308, 338, 364, 416, 442, 476, 504, 560, 588, 644, 700, 728, 784, 812, 868, 924, 980, 1036, 1064, 1120, 1204, 1260, 1316, 1372}, // Medium - { 7, 10, 15, 20, 26, 36, 40, 48, 60, 72, 80, 96, 104, 120, 132, 144, 168, 180, 196, 224, 224, 252, 270, 300, 312, 336, 360, 390, 420, 450, 480, 510, 540, 570, 570, 600, 630, 660, 720, 750}, // Low - { 17, 28, 44, 64, 88, 112, 130, 156, 192, 224, 264, 308, 352, 384, 432, 480, 532, 588, 650, 700, 750, 816, 900, 960, 1050, 1110, 1200, 1260, 1350, 1440, 1530, 1620, 1710, 1800, 1890, 1980, 2100, 2220, 2310, 2430}, // High - { 13, 22, 36, 52, 72, 96, 108, 132, 160, 192, 224, 260, 288, 320, 360, 408, 448, 504, 546, 600, 644, 690, 750, 810, 870, 952, 1020, 1050, 1140, 1200, 1290, 1350, 1440, 1530, 1590, 1680, 1770, 1860, 1950, 2040}, // Quartile -}; - -static const uint8_t NUM_ERROR_CORRECTION_BLOCKS[4][40] = { - // Version: (note that index 0 is for padding, and is set to an illegal value) - // 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, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium - { 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low - { 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 - { 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 -}; - -static const uint16_t NUM_RAW_DATA_MODULES[40] = { - // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 208, 359, 567, 807, 1079, 1383, 1568, 1936, 2336, 2768, 3232, 3728, 4256, 4651, 5243, 5867, 6523, - // 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 7211, 7931, 8683, 9252, 10068, 10916, 11796, 12708, 13652, 14628, 15371, 16411, 17483, 18587, - // 32, 33, 34, 35, 36, 37, 38, 39, 40 - 19723, 20891, 22091, 23008, 24272, 25568, 26896, 28256, 29648 -}; - -// @TODO: Put other LOCK_VERSIONS here -#elif LOCK_VERSION == 3 - -static const int16_t NUM_ERROR_CORRECTION_CODEWORDS[4] = { - 26, 15, 44, 36 -}; - -static const int8_t NUM_ERROR_CORRECTION_BLOCKS[4] = { - 1, 1, 2, 2 -}; - -static const uint16_t NUM_RAW_DATA_MODULES = 567; - -#else - -#error Unsupported LOCK_VERSION (add it...) - -#endif - - -static int max(int a, int b) { - if (a > b) { return a; } - return b; -} - -/* -static int abs(int value) { - if (value < 0) { return -value; } - return value; -} -*/ - - -#pragma mark - Mode testing and conversion - -static int8_t getAlphanumeric(char c) { - - if (c >= '0' && c <= '9') { return (c - '0'); } - if (c >= 'A' && c <= 'Z') { return (c - 'A' + 10); } - - switch (c) { - case ' ': return 36; - case '$': return 37; - case '%': return 38; - case '*': return 39; - case '+': return 40; - case '-': return 41; - case '.': return 42; - case '/': return 43; - case ':': return 44; - } - - return -1; -} - -static bool isAlphanumeric(const char *text, uint16_t length) { - while (length != 0) { - if (getAlphanumeric(text[--length]) == -1) { return false; } - } - return true; -} - - -static bool isNumeric(const char *text, uint16_t length) { - while (length != 0) { - char c = text[--length]; - if (c < '0' || c > '9') { return false; } - } - return true; -} - - -#pragma mark - Counting - -// We store the following tightly packed (less 8) in modeInfo -// <=9 <=26 <= 40 -// NUMERIC ( 10, 12, 14); -// ALPHANUMERIC ( 9, 11, 13); -// BYTE ( 8, 16, 16); -static char getModeBits(uint8_t version, uint8_t mode) { - // Note: We use 15 instead of 16; since 15 doesn't exist and we cannot store 16 (8 + 8) in 3 bits - // hex(int("".join(reversed([('00' + bin(x - 8)[2:])[-3:] for x in [10, 9, 8, 12, 11, 15, 14, 13, 15]])), 2)) - unsigned int modeInfo = 0x7bbb80a; - -#if LOCK_VERSION == 0 || LOCK_VERSION > 9 - if (version > 9) { modeInfo >>= 9; } -#endif - -#if LOCK_VERSION == 0 || LOCK_VERSION > 26 - if (version > 26) { modeInfo >>= 9; } -#endif - - char result = 8 + ((modeInfo >> (3 * mode)) & 0x07); - if (result == 15) { result = 16; } - - return result; -} - - -#pragma mark - BitBucket - -typedef struct BitBucket { - uint32_t bitOffsetOrWidth; - uint16_t capacityBytes; - uint8_t *data; -} BitBucket; - -/* -void bb_dump(BitBucket *bitBuffer) { - printf("Buffer: "); - for (uint32_t i = 0; i < bitBuffer->capacityBytes; i++) { - printf("%02x", bitBuffer->data[i]); - if ((i % 4) == 3) { printf(" "); } - } - printf("\n"); -} -*/ - -static uint16_t bb_getGridSizeBytes(uint8_t size) { - return (((size * size) + 7) / 8); -} - -static uint16_t bb_getBufferSizeBytes(uint32_t bits) { - return ((bits + 7) / 8); -} - -static void bb_initBuffer(BitBucket *bitBuffer, uint8_t *data, int32_t capacityBytes) { - bitBuffer->bitOffsetOrWidth = 0; - bitBuffer->capacityBytes = capacityBytes; - bitBuffer->data = data; - - memset(data, 0, bitBuffer->capacityBytes); -} - -static void bb_initGrid(BitBucket *bitGrid, uint8_t *data, uint8_t size) { - bitGrid->bitOffsetOrWidth = size; - bitGrid->capacityBytes = bb_getGridSizeBytes(size); - bitGrid->data = data; - - memset(data, 0, bitGrid->capacityBytes); -} - -static void bb_appendBits(BitBucket *bitBuffer, uint32_t val, uint8_t length) { - uint32_t offset = bitBuffer->bitOffsetOrWidth; - for (int8_t i = length - 1; i >= 0; i--, offset++) { - bitBuffer->data[offset >> 3] |= ((val >> i) & 1) << (7 - (offset & 7)); - } - bitBuffer->bitOffsetOrWidth = offset; -} -/* -void bb_setBits(BitBucket *bitBuffer, uint32_t val, int offset, uint8_t length) { - for (int8_t i = length - 1; i >= 0; i--, offset++) { - bitBuffer->data[offset >> 3] |= ((val >> i) & 1) << (7 - (offset & 7)); - } -} -*/ -static void bb_setBit(BitBucket *bitGrid, uint8_t x, uint8_t y, bool on) { - uint32_t offset = y * bitGrid->bitOffsetOrWidth + x; - uint8_t mask = 1 << (7 - (offset & 0x07)); - if (on) { - bitGrid->data[offset >> 3] |= mask; - } else { - bitGrid->data[offset >> 3] &= ~mask; - } -} - -static void bb_invertBit(BitBucket *bitGrid, uint8_t x, uint8_t y, bool invert) { - uint32_t offset = y * bitGrid->bitOffsetOrWidth + x; - uint8_t mask = 1 << (7 - (offset & 0x07)); - bool on = ((bitGrid->data[offset >> 3] & (1 << (7 - (offset & 0x07)))) != 0); - if (on ^ invert) { - bitGrid->data[offset >> 3] |= mask; - } else { - bitGrid->data[offset >> 3] &= ~mask; - } -} - -static bool bb_getBit(BitBucket *bitGrid, uint8_t x, uint8_t y) { - uint32_t offset = y * bitGrid->bitOffsetOrWidth + x; - return (bitGrid->data[offset >> 3] & (1 << (7 - (offset & 0x07)))) != 0; -} - - -#pragma mark - Drawing Patterns - -// XORs the data modules in this QR Code with the given mask pattern. Due to XOR's mathematical -// properties, calling applyMask(m) twice with the same value is equivalent to no change at all. -// This means it is possible to apply a mask, undo it, and try another mask. Note that a final -// well-formed QR Code symbol needs exactly one mask applied (not zero, not two, etc.). -static void applyMask(BitBucket *modules, BitBucket *isFunction, uint8_t mask) { - uint8_t size = modules->bitOffsetOrWidth; - - for (uint8_t y = 0; y < size; y++) { - for (uint8_t x = 0; x < size; x++) { - if (bb_getBit(isFunction, x, y)) { continue; } - - bool invert = 0; - switch (mask) { - case 0: invert = (x + y) % 2 == 0; break; - case 1: invert = y % 2 == 0; break; - case 2: invert = x % 3 == 0; break; - case 3: invert = (x + y) % 3 == 0; break; - case 4: invert = (x / 3 + y / 2) % 2 == 0; break; - 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; - } - bb_invertBit(modules, x, y, invert); - } - } -} - -static void setFunctionModule(BitBucket *modules, BitBucket *isFunction, uint8_t x, uint8_t y, bool on) { - bb_setBit(modules, x, y, on); - bb_setBit(isFunction, x, y, true); -} - -// Draws a 9*9 finder pattern including the border separator, with the center module at (x, y). -static void drawFinderPattern(BitBucket *modules, BitBucket *isFunction, uint8_t x, uint8_t y) { - uint8_t size = modules->bitOffsetOrWidth; - - for (int8_t i = -4; i <= 4; i++) { - for (int8_t j = -4; j <= 4; j++) { - uint8_t dist = max(abs(i), abs(j)); // Chebyshev/infinity norm - int16_t xx = x + j, yy = y + i; - if (0 <= xx && xx < size && 0 <= yy && yy < size) { - setFunctionModule(modules, isFunction, xx, yy, dist != 2 && dist != 4); - } - } - } -} - -// Draws a 5*5 alignment pattern, with the center module at (x, y). -static void drawAlignmentPattern(BitBucket *modules, BitBucket *isFunction, uint8_t x, uint8_t y) { - for (int8_t i = -2; i <= 2; i++) { - for (int8_t j = -2; j <= 2; j++) { - setFunctionModule(modules, isFunction, x + j, y + i, max(abs(i), abs(j)) != 1); - } - } -} - -// Draws two copies of the format bits (with its own error correction code) -// based on the given mask and this object's error correction level field. -static void drawFormatBits(BitBucket *modules, BitBucket *isFunction, uint8_t ecc, uint8_t mask) { - - uint8_t size = modules->bitOffsetOrWidth; - - // Calculate error correction code and pack bits - uint32_t data = ecc << 3 | mask; // errCorrLvl is uint2, mask is uint3 - uint32_t rem = data; - for (int i = 0; i < 10; i++) { - rem = (rem << 1) ^ ((rem >> 9) * 0x537); - } - - data = data << 10 | rem; - data ^= 0x5412; // uint15 - - // Draw first copy - for (uint8_t i = 0; i <= 5; i++) { - setFunctionModule(modules, isFunction, 8, i, ((data >> i) & 1) != 0); - } - - setFunctionModule(modules, isFunction, 8, 7, ((data >> 6) & 1) != 0); - setFunctionModule(modules, isFunction, 8, 8, ((data >> 7) & 1) != 0); - setFunctionModule(modules, isFunction, 7, 8, ((data >> 8) & 1) != 0); - - for (int8_t i = 9; i < 15; i++) { - setFunctionModule(modules, isFunction, 14 - i, 8, ((data >> i) & 1) != 0); - } - - // Draw second copy - for (int8_t i = 0; i <= 7; i++) { - setFunctionModule(modules, isFunction, size - 1 - i, 8, ((data >> i) & 1) != 0); - } - - for (int8_t i = 8; i < 15; i++) { - setFunctionModule(modules, isFunction, 8, size - 15 + i, ((data >> i) & 1) != 0); - } - - setFunctionModule(modules, isFunction, 8, size - 8, true); -} - - -// Draws two copies of the version bits (with its own error correction code), -// based on this object's version field (which only has an effect for 7 <= version <= 40). -static void drawVersion(BitBucket *modules, BitBucket *isFunction, uint8_t version) { - - int8_t size = modules->bitOffsetOrWidth; - -#if LOCK_VERSION != 0 && LOCK_VERSION < 7 - return; - -#else - if (version < 7) { return; } - - // Calculate error correction code and pack bits - uint32_t rem = version; // version is uint6, in the range [7, 40] - for (uint8_t i = 0; i < 12; i++) { - rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); - } - - uint32_t data = version << 12 | rem; // uint18 - - // Draw two copies - for (uint8_t i = 0; i < 18; i++) { - bool bit = ((data >> i) & 1) != 0; - uint8_t a = size - 11 + i % 3, b = i / 3; - setFunctionModule(modules, isFunction, a, b, bit); - setFunctionModule(modules, isFunction, b, a, bit); - } - -#endif -} - -static void drawFunctionPatterns(BitBucket *modules, BitBucket *isFunction, uint8_t version, uint8_t ecc) { - - uint8_t size = modules->bitOffsetOrWidth; - - // Draw the horizontal and vertical timing patterns - for (uint8_t i = 0; i < size; i++) { - setFunctionModule(modules, isFunction, 6, i, i % 2 == 0); - setFunctionModule(modules, isFunction, i, 6, i % 2 == 0); - } - - // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules) - drawFinderPattern(modules, isFunction, 3, 3); - drawFinderPattern(modules, isFunction, size - 4, 3); - drawFinderPattern(modules, isFunction, 3, size - 4); - -#if LOCK_VERSION == 0 || LOCK_VERSION > 1 - - if (version > 1) { - - // Draw the numerous alignment patterns - - uint8_t alignCount = version / 7 + 2; - uint8_t step; - if (version != 32) { - step = (version * 4 + alignCount * 2 + 1) / (2 * alignCount - 2) * 2; // ceil((size - 13) / (2*numAlign - 2)) * 2 - } else { // C-C-C-Combo breaker! - step = 26; - } - - uint8_t alignPositionIndex = alignCount - 1; - uint8_t alignPosition[alignCount]; - - alignPosition[0] = 6; - - uint8_t size = version * 4 + 17; - for (uint8_t i = 0, pos = size - 7; i < alignCount - 1; i++, pos -= step) { - alignPosition[alignPositionIndex--] = pos; - } - - for (uint8_t i = 0; i < alignCount; i++) { - for (uint8_t j = 0; j < alignCount; j++) { - if ((i == 0 && j == 0) || (i == 0 && j == alignCount - 1) || (i == alignCount - 1 && j == 0)) { - continue; // Skip the three finder corners - } else { - drawAlignmentPattern(modules, isFunction, alignPosition[i], alignPosition[j]); - } - } - } - } - -#endif - - // Draw configuration data - drawFormatBits(modules, isFunction, ecc, 0); // Dummy mask value; overwritten later in the constructor - drawVersion(modules, isFunction, version); -} - - -// Draws the given sequence of 8-bit codewords (data and error correction) onto the entire -// data area of this QR Code symbol. Function modules need to be marked off before this is called. -static void drawCodewords(BitBucket *modules, BitBucket *isFunction, BitBucket *codewords) { - - uint32_t bitLength = codewords->bitOffsetOrWidth; - uint8_t *data = codewords->data; - - uint8_t size = modules->bitOffsetOrWidth; - - // Bit index into the data - uint32_t i = 0; - - // Do the funny zigzag scan - for (int16_t right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair - if (right == 6) { right = 5; } - - for (uint8_t vert = 0; vert < size; vert++) { // Vertical counter - for (int j = 0; j < 2; j++) { - uint8_t x = right - j; // Actual x coordinate - bool upwards = ((right & 2) == 0) ^ (x < 6); - uint8_t y = upwards ? size - 1 - vert : vert; // Actual y coordinate - if (!bb_getBit(isFunction, x, y) && i < bitLength) { - bb_setBit(modules, x, y, ((data[i >> 3] >> (7 - (i & 7))) & 1) != 0); - i++; - } - // If there are any remainder bits (0 to 7), they are already - // set to 0/false/white when the grid of modules was initialized - } - } - } -} - - - -#pragma mark - Penalty Calculation - -#define PENALTY_N1 3 -#define PENALTY_N2 3 -#define PENALTY_N3 40 -#define PENALTY_N4 10 - -// 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. -// @TODO: This can be optimized by working with the bytes instead of bits. -static uint32_t getPenaltyScore(BitBucket *modules) { - uint32_t result = 0; - - uint8_t size = modules->bitOffsetOrWidth; - - // Adjacent modules in row having same color - for (uint8_t y = 0; y < size; y++) { - - bool colorX = bb_getBit(modules, 0, y); - for (uint8_t x = 1, runX = 1; x < size; x++) { - bool cx = bb_getBit(modules, x, y); - if (cx != colorX) { - colorX = cx; - runX = 1; - - } else { - runX++; - if (runX == 5) { - result += PENALTY_N1; - } else if (runX > 5) { - result++; - } - } - } - } - - // Adjacent modules in column having same color - for (uint8_t x = 0; x < size; x++) { - bool colorY = bb_getBit(modules, x, 0); - for (uint8_t y = 1, runY = 1; y < size; y++) { - bool cy = bb_getBit(modules, x, y); - if (cy != colorY) { - colorY = cy; - runY = 1; - } else { - runY++; - if (runY == 5) { - result += PENALTY_N1; - } else if (runY > 5) { - result++; - } - } - } - } - - uint16_t black = 0; - for (uint8_t y = 0; y < size; y++) { - uint16_t bitsRow = 0, bitsCol = 0; - for (uint8_t x = 0; x < size; x++) { - bool color = bb_getBit(modules, x, y); - - // 2*2 blocks of modules having same color - if (x > 0 && y > 0) { - bool colorUL = bb_getBit(modules, x - 1, y - 1); - bool colorUR = bb_getBit(modules, x, y - 1); - bool colorL = bb_getBit(modules, x - 1, y); - if (color == colorUL && color == colorUR && color == colorL) { - result += PENALTY_N2; - } - } - - // Finder-like pattern in rows and columns - bitsRow = ((bitsRow << 1) & 0x7FF) | color; - bitsCol = ((bitsCol << 1) & 0x7FF) | bb_getBit(modules, y, x); - - // Needs 11 bits accumulated - if (x >= 10) { - if (bitsRow == 0x05D || bitsRow == 0x5D0) { - result += PENALTY_N3; - } - if (bitsCol == 0x05D || bitsCol == 0x5D0) { - result += PENALTY_N3; - } - } - - // Balance of black and white modules - if (color) { black++; } - } - } - - // Find smallest k such that (45-5k)% <= dark/total <= (55+5k)% - uint16_t total = size * size; - for (uint16_t k = 0; black * 20 < (9 - k) * total || black * 20 > (11 + k) * total; k++) { - result += PENALTY_N4; - } - - return result; -} - - -#pragma mark - Reed-Solomon Generator - -static uint8_t rs_multiply(uint8_t x, uint8_t y) { - // Russian peasant multiplication - // See: https://en.wikipedia.org/wiki/Ancient_Egyptian_multiplication - uint16_t z = 0; - for (int8_t i = 7; i >= 0; i--) { - z = (z << 1) ^ ((z >> 7) * 0x11D); - z ^= ((y >> i) & 1) * x; - } - return z; -} - -static void rs_init(uint8_t degree, uint8_t *coeff) { - memset(coeff, 0, degree); - coeff[degree - 1] = 1; - - // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), - // drop the highest term, and store the rest of the coefficients in order of descending powers. - // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). - uint16_t root = 1; - for (uint8_t i = 0; i < degree; i++) { - // Multiply the current product by (x - r^i) - for (uint8_t j = 0; j < degree; j++) { - coeff[j] = rs_multiply(coeff[j], root); - if (j + 1 < degree) { - coeff[j] ^= coeff[j + 1]; - } - } - root = (root << 1) ^ ((root >> 7) * 0x11D); // Multiply by 0x02 mod GF(2^8/0x11D) - } -} - -static void rs_getRemainder(uint8_t degree, uint8_t *coeff, uint8_t *data, uint8_t length, uint8_t *result, uint8_t stride) { - // Compute the remainder by performing polynomial division - - //for (uint8_t i = 0; i < degree; i++) { result[] = 0; } - //memset(result, 0, degree); - - for (uint8_t i = 0; i < length; i++) { - uint8_t factor = data[i] ^ result[0]; - for (uint8_t j = 1; j < degree; j++) { - result[(j - 1) * stride] = result[j * stride]; - } - result[(degree - 1) * stride] = 0; - - for (uint8_t j = 0; j < degree; j++) { - result[j * stride] ^= rs_multiply(coeff[j], factor); - } - } -} - - - -#pragma mark - QrCode - -static int8_t encodeDataCodewords(BitBucket *dataCodewords, const uint8_t *text, uint16_t length, uint8_t version) { - int8_t mode = MODE_BYTE; - - if (isNumeric((char*)text, length)) { - mode = MODE_NUMERIC; - bb_appendBits(dataCodewords, 1 << MODE_NUMERIC, 4); - bb_appendBits(dataCodewords, length, getModeBits(version, MODE_NUMERIC)); - - uint16_t accumData = 0; - uint8_t accumCount = 0; - for (uint16_t i = 0; i < length; i++) { - accumData = accumData * 10 + ((char)(text[i]) - '0'); - accumCount++; - if (accumCount == 3) { - bb_appendBits(dataCodewords, accumData, 10); - accumData = 0; - accumCount = 0; - } - } - - // 1 or 2 digits remaining - if (accumCount > 0) { - bb_appendBits(dataCodewords, accumData, accumCount * 3 + 1); - } - - } else if (isAlphanumeric((char*)text, length)) { - mode = MODE_ALPHANUMERIC; - bb_appendBits(dataCodewords, 1 << MODE_ALPHANUMERIC, 4); - bb_appendBits(dataCodewords, length, getModeBits(version, MODE_ALPHANUMERIC)); - - uint16_t accumData = 0; - uint8_t accumCount = 0; - for (uint16_t i = 0; i < length; i++) { - accumData = accumData * 45 + getAlphanumeric((char)(text[i])); - accumCount++; - if (accumCount == 2) { - bb_appendBits(dataCodewords, accumData, 11); - accumData = 0; - accumCount = 0; - } - } - - // 1 character remaining - if (accumCount > 0) { - bb_appendBits(dataCodewords, accumData, 6); - } - - } else { - bb_appendBits(dataCodewords, 1 << MODE_BYTE, 4); - bb_appendBits(dataCodewords, length, getModeBits(version, MODE_BYTE)); - for (uint16_t i = 0; i < length; i++) { - bb_appendBits(dataCodewords, (char)(text[i]), 8); - } - } - - //bb_setBits(dataCodewords, length, 4, getModeBits(version, mode)); - - return mode; -} - -static void performErrorCorrection(uint8_t version, uint8_t ecc, BitBucket *data) { - - // See: http://www.thonky.com/qr-code-tutorial/structure-final-message - -#if LOCK_VERSION == 0 - uint8_t numBlocks = NUM_ERROR_CORRECTION_BLOCKS[ecc][version - 1]; - uint16_t totalEcc = NUM_ERROR_CORRECTION_CODEWORDS[ecc][version - 1]; - uint16_t moduleCount = NUM_RAW_DATA_MODULES[version - 1]; -#else - uint8_t numBlocks = NUM_ERROR_CORRECTION_BLOCKS[ecc]; - uint16_t totalEcc = NUM_ERROR_CORRECTION_CODEWORDS[ecc]; - uint16_t moduleCount = NUM_RAW_DATA_MODULES; -#endif - - uint8_t blockEccLen = totalEcc / numBlocks; - uint8_t numShortBlocks = numBlocks - moduleCount / 8 % numBlocks; - uint8_t shortBlockLen = moduleCount / 8 / numBlocks; - - uint8_t shortDataBlockLen = shortBlockLen - blockEccLen; - - uint8_t result[data->capacityBytes]; - memset(result, 0, sizeof(result)); - - uint8_t coeff[blockEccLen]; - rs_init(blockEccLen, coeff); - - uint16_t offset = 0; - uint8_t *dataBytes = data->data; - - - // Interleave all short blocks - for (uint8_t i = 0; i < shortDataBlockLen; i++) { - uint16_t index = i; - uint8_t stride = shortDataBlockLen; - for (uint8_t blockNum = 0; blockNum < numBlocks; blockNum++) { - result[offset++] = dataBytes[index]; - -#if LOCK_VERSION == 0 || LOCK_VERSION >= 5 - if (blockNum == numShortBlocks) { stride++; } -#endif - index += stride; - } - } - - // Version less than 5 only have short blocks -#if LOCK_VERSION == 0 || LOCK_VERSION >= 5 - { - // Interleave long blocks - uint16_t index = shortDataBlockLen * (numShortBlocks + 1); - uint8_t stride = shortDataBlockLen; - for (uint8_t blockNum = 0; blockNum < numBlocks - numShortBlocks; blockNum++) { - result[offset++] = dataBytes[index]; - - if (blockNum == 0) { stride++; } - index += stride; - } - } -#endif - - // Add all ecc blocks, interleaved - uint8_t blockSize = shortDataBlockLen; - for (uint8_t blockNum = 0; blockNum < numBlocks; blockNum++) { - -#if LOCK_VERSION == 0 || LOCK_VERSION >= 5 - if (blockNum == numShortBlocks) { blockSize++; } -#endif - rs_getRemainder(blockEccLen, coeff, dataBytes, blockSize, &result[offset + blockNum], numBlocks); - dataBytes += blockSize; - } - - memcpy(data->data, result, data->capacityBytes); - data->bitOffsetOrWidth = moduleCount; -} - -// We store the Format bits tightly packed into a single byte (each of the 4 modes is 2 bits) -// The format bits can be determined by ECC_FORMAT_BITS >> (2 * ecc) -static const uint8_t ECC_FORMAT_BITS = (0x02 << 6) | (0x03 << 4) | (0x00 << 2) | (0x01 << 0); - - -#pragma mark - Public QRCode functions - -uint16_t qrcode_getBufferSize(uint8_t version) { - return bb_getGridSizeBytes(4 * version + 17); -} - -// @TODO: Return error if data is too big. -int8_t qrcode_initBytes(QRCode *qrcode, uint8_t *modules, uint8_t version, uint8_t ecc, uint8_t *data, uint16_t length) { - uint8_t size = version * 4 + 17; - qrcode->version = version; - qrcode->size = size; - qrcode->ecc = ecc; - qrcode->modules = modules; - - uint8_t eccFormatBits = (ECC_FORMAT_BITS >> (2 * ecc)) & 0x03; - -#if LOCK_VERSION == 0 - uint16_t moduleCount = NUM_RAW_DATA_MODULES[version - 1]; - uint16_t dataCapacity = moduleCount / 8 - NUM_ERROR_CORRECTION_CODEWORDS[eccFormatBits][version - 1]; -#else - version = LOCK_VERSION; - uint16_t moduleCount = NUM_RAW_DATA_MODULES; - uint16_t dataCapacity = moduleCount / 8 - NUM_ERROR_CORRECTION_CODEWORDS[eccFormatBits]; -#endif - - struct BitBucket codewords; - uint8_t codewordBytes[bb_getBufferSizeBytes(moduleCount)]; - bb_initBuffer(&codewords, codewordBytes, (int32_t)sizeof(codewordBytes)); - - // Place the data code words into the buffer - int8_t mode = encodeDataCodewords(&codewords, data, length, version); - - if (mode < 0) { return -1; } - qrcode->mode = mode; - - // Add terminator and pad up to a byte if applicable - uint32_t padding = (dataCapacity * 8) - codewords.bitOffsetOrWidth; - if (padding > 4) { padding = 4; } - bb_appendBits(&codewords, 0, padding); - bb_appendBits(&codewords, 0, (8 - codewords.bitOffsetOrWidth % 8) % 8); - - // Pad with alternate bytes until data capacity is reached - for (uint8_t padByte = 0xEC; codewords.bitOffsetOrWidth < (dataCapacity * 8); padByte ^= 0xEC ^ 0x11) { - bb_appendBits(&codewords, padByte, 8); - } - - BitBucket modulesGrid; - bb_initGrid(&modulesGrid, modules, size); - - BitBucket isFunctionGrid; - uint8_t isFunctionGridBytes[bb_getGridSizeBytes(size)]; - bb_initGrid(&isFunctionGrid, isFunctionGridBytes, size); - - // Draw function patterns, draw all codewords, do masking - drawFunctionPatterns(&modulesGrid, &isFunctionGrid, version, eccFormatBits); - performErrorCorrection(version, eccFormatBits, &codewords); - drawCodewords(&modulesGrid, &isFunctionGrid, &codewords); - - // Find the best (lowest penalty) mask - uint8_t mask = 0; - int32_t minPenalty = INT32_MAX; - for (uint8_t i = 0; i < 8; i++) { - drawFormatBits(&modulesGrid, &isFunctionGrid, eccFormatBits, i); - applyMask(&modulesGrid, &isFunctionGrid, i); - int penalty = getPenaltyScore(&modulesGrid); - if (penalty < minPenalty) { - mask = i; - minPenalty = penalty; - } - applyMask(&modulesGrid, &isFunctionGrid, i); // Undoes the mask due to XOR - } - - qrcode->mask = mask; - - // Overwrite old format bits - drawFormatBits(&modulesGrid, &isFunctionGrid, eccFormatBits, mask); - - // Apply the final choice of mask - applyMask(&modulesGrid, &isFunctionGrid, mask); - - return 0; -} - -int8_t qrcode_initText(QRCode *qrcode, uint8_t *modules, uint8_t version, uint8_t ecc, const char *data) { - return qrcode_initBytes(qrcode, modules, version, ecc, (uint8_t*)data, strlen(data)); -} - -bool qrcode_getModule(QRCode *qrcode, uint8_t x, uint8_t y) { - if (x < 0 || x >= qrcode->size || y < 0 || y >= qrcode->size) { - return false; - } - - uint32_t offset = y * qrcode->size + x; - return (qrcode->modules[offset >> 3] & (1 << (7 - (offset & 0x07)))) != 0; -} - -/* -uint8_t qrcode_getHexLength(QRCode *qrcode) { - return ((qrcode->size * qrcode->size) + 7) / 4; -} - -void qrcode_getHex(QRCode *qrcode, char *result) { - -} -*/ diff --git a/TotalCrossVM/src/nm/qrcode/qrcode.h b/TotalCrossVM/src/nm/qrcode/qrcode.h deleted file mode 100644 index 53de85857a..0000000000 --- a/TotalCrossVM/src/nm/qrcode/qrcode.h +++ /dev/null @@ -1,99 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2017 Richard Moore - * - * 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. - */ - -/** - * Special thanks to Nayuki (https://www.nayuki.io/) from which this library was - * heavily inspired and compared against. - * - * See: https://github.com/nayuki/QR-Code-generator/tree/master/cpp - */ - - -#ifndef __QRCODE_H_ -#define __QRCODE_H_ - -#include "xtypes.h" - -#ifndef __cplusplus -#ifndef _STDBOOL_H -typedef unsigned char bool; -static const bool false = 0; -static const bool true = 1; -#endif -#endif - -#include - - -// QR Code Format Encoding -#define MODE_NUMERIC 0 -#define MODE_ALPHANUMERIC 1 -#define MODE_BYTE 2 - - -// Error Correction Code Levels -#define ECC_LOW 0 -#define ECC_MEDIUM 1 -#define ECC_QUARTILE 2 -#define ECC_HIGH 3 - - -// If set to non-zero, this library can ONLY produce QR codes at that version -// This saves a lot of dynamic memory, as the codeword tables are skipped -#ifndef LOCK_VERSION -#define LOCK_VERSION 0 -#endif - - -typedef struct QRCode { - uint8_t version; - uint8_t size; - uint8_t ecc; - uint8_t mode; - uint8_t mask; - uint8_t *modules; -} QRCode; - - -#ifdef __cplusplus -extern "C"{ -#endif /* __cplusplus */ - - - -uint16_t qrcode_getBufferSize(uint8_t version); - -int8_t qrcode_initText(QRCode *qrcode, uint8_t *modules, uint8_t version, uint8_t ecc, const char *data); -int8_t qrcode_initBytes(QRCode *qrcode, uint8_t *modules, uint8_t version, uint8_t ecc, uint8_t *data, uint16_t length); - -bool qrcode_getModule(QRCode *qrcode, uint8_t x, uint8_t y); - - - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - - -#endif /* __QRCODE_H_ */ diff --git a/TotalCrossVM/src/nm/qrcode/qrcode_compat.h b/TotalCrossVM/src/nm/qrcode/qrcode_compat.h new file mode 100644 index 0000000000..4fff226a7b --- /dev/null +++ b/TotalCrossVM/src/nm/qrcode/qrcode_compat.h @@ -0,0 +1,78 @@ +// Copyright (C) 2026 Amalgam Solucoes em TI Ltda +// +// SPDX-License-Identifier: LGPL-2.1-only + +#ifndef TC_QRCODE_COMPAT_H +#define TC_QRCODE_COMPAT_H + +/* + * CMake sets TC_QRCODE_USE_QRCODEGEN to 0 or 1 and compiles the matching + * implementation source. + */ +#ifndef TC_QRCODE_USE_QRCODEGEN + #error "TC_QRCODE_USE_QRCODEGEN must be defined by the build configuration" +#endif + +#if TC_QRCODE_USE_QRCODEGEN != 0 && TC_QRCODE_USE_QRCODEGEN != 1 + #error "TC_QRCODE_USE_QRCODEGEN must be 0 or 1" +#endif + +#if TC_QRCODE_USE_QRCODEGEN + +/* tcvm.h already provides bool, true, and false. */ +#ifndef __bool_true_false_are_defined + #define __bool_true_false_are_defined 1 +#endif +#include "qrcodegen.h" + +typedef struct TCQRCode { + uint8_t modules[qrcodegen_BUFFER_LEN_MAX]; + uint8_t temporary[qrcodegen_BUFFER_LEN_MAX]; +} TCQRCode; + +static void tcQRCodeInitText(TCQRCode* qrcode, uint8_t version, uint8_t ecc, const char* text) { + qrcodegen_encodeText(text, qrcode->temporary, qrcode->modules, + (enum qrcodegen_Ecc)ecc, version, version, qrcodegen_Mask_AUTO, true); +} + +static int tcQRCodeGetSize(const TCQRCode* qrcode) { + return qrcodegen_getSize(qrcode->modules); +} + +static bool tcQRCodeGetModule(const TCQRCode* qrcode, int x, int y) { + return qrcodegen_getModule(qrcode->modules, x, y); +} + +static void tcQRCodeDispose(TCQRCode* qrcode) { + (void)qrcode; +} + +#else + +#include "qrcode.h" + +typedef struct TCQRCode { + QRCode code; + uint8_t* modules; +} TCQRCode; + +static void tcQRCodeInitText(TCQRCode* qrcode, uint8_t version, uint8_t ecc, const char* text) { + qrcode->modules = xmalloc(sizeof(uint8_t) * qrcode_getBufferSize(version)); + qrcode_initText(&qrcode->code, qrcode->modules, version, ecc, text); +} + +static int tcQRCodeGetSize(const TCQRCode* qrcode) { + return qrcode->code.size; +} + +static bool tcQRCodeGetModule(const TCQRCode* qrcode, int x, int y) { + return qrcode_getModule((QRCode*)&qrcode->code, (uint8_t)x, (uint8_t)y); +} + +static void tcQRCodeDispose(TCQRCode* qrcode) { + xfree(qrcode->modules); +} + +#endif + +#endif diff --git a/TotalCrossVM/src/nm/qrcode/qrcode_generation.c b/TotalCrossVM/src/nm/qrcode/qrcode_generation.c index 77d2975934..076228e082 100644 --- a/TotalCrossVM/src/nm/qrcode/qrcode_generation.c +++ b/TotalCrossVM/src/nm/qrcode/qrcode_generation.c @@ -1,14 +1,14 @@ +// Copyright (C) 2020-2021 TotalCross Global Mobile Platform Ltda. +// Copyright (C) 2022-2026 Amalgam Solucoes em TI Ltda +// +// SPDX-License-Identifier: LGPL-2.1-only + #include "tcvm.h" -#ifdef _MSC_VER -#include "win/qrcodegen.h" -#else -#include "qrcode.h" -#endif +#include "qrcode_compat.h" TC_API void tqQRC_nativeGetBytes_sii(NMParams p) { uint8_t version = p->i32[1]; uint8_t ecc = p->i32[0]; //Error correction - uint8_t* qrcodeBytes; TCObject text = p->obj[1]; int y; int x; @@ -16,48 +16,30 @@ TC_API void tqQRC_nativeGetBytes_sii(NMParams p) { TCObject byteMatrix; TCObjectArray out; CharP textChars = String2CharP(text); -{ -#if defined WIN32 || defined WINCE - uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX]; - uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX]; - - qrcodegen_encodeText(textChars, tempBuffer, qrcode, ecc, version, version, qrcodegen_Mask_AUTO, true); - size = qrcodegen_getSize(qrcode); -#else - QRCode qrcode; - qrcodeBytes = xmalloc(sizeof(uint8_t) * qrcode_getBufferSize(version)); - qrcode_initText(&qrcode, qrcodeBytes, version, ecc, textChars); + TCQRCode qrcode; + + tcQRCodeInitText(&qrcode, version, ecc, textChars); xfree(textChars); - size = qrcode.size; -#endif - byteMatrix = createArrayObject(p->currentContext, "[[&B", size); - out = (TCObjectArray)ARRAYOBJ_START(byteMatrix); - for(y = 0; y < size; y++, out++) { - *out = createByteArray(p->currentContext, size); - { - uint8_t* byteArrayWithInfoForTheQRCode = ARRAYOBJ_START(*out); - for(x = 0; x < size; x++) { -#if defined WIN32 || defined WINCE - if(qrcodegen_getModule(qrcode, x, y)) { -#else - if(qrcode_getModule(&qrcode, x, y)) { -#endif - + + size = tcQRCodeGetSize(&qrcode); + byteMatrix = createArrayObject(p->currentContext, "[[&B", size); + out = (TCObjectArray)ARRAYOBJ_START(byteMatrix); + for(y = 0; y < size; y++, out++) { + *out = createByteArray(p->currentContext, size); + { + uint8_t* byteArrayWithInfoForTheQRCode = ARRAYOBJ_START(*out); + for(x = 0; x < size; x++) { + if(tcQRCodeGetModule(&qrcode, x, y)) { byteArrayWithInfoForTheQRCode[x] = 0xFF; //11111111 - } else { - byteArrayWithInfoForTheQRCode[x] = 0; //00000000 - } + } else { + byteArrayWithInfoForTheQRCode[x] = 0; //00000000 } } - setObjectLock(*out, UNLOCKED); } + setObjectLock(*out, UNLOCKED); } -#ifdef _MSC_VER - -#else - xfree(qrcodeBytes); -#endif + tcQRCodeDispose(&qrcode); p->retO = byteMatrix; setObjectLock(p->retO, UNLOCKED); } -//private void getBytes(int module, int errorCorrection, String text, byte[] qrcodeByte); \ No newline at end of file +//private void getBytes(int module, int errorCorrection, String text, byte[] qrcodeByte); diff --git a/TotalCrossVM/src/nm/qrcode/win/qrcodegen.c b/TotalCrossVM/src/nm/qrcode/win/qrcodegen.c deleted file mode 100644 index 6c720c6eed..0000000000 --- a/TotalCrossVM/src/nm/qrcode/win/qrcodegen.c +++ /dev/null @@ -1,1059 +0,0 @@ -/* - * QR Code generator library (C) - * - * Copyright (c) Project Nayuki. (MIT License) - * https://www.nayuki.io/page/qr-code-generator-library - * - * 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. - */ - -#include -#include -#include -#include -#include "qrcodegen.h" - -#ifdef WINCE -#undef assert -#define assert(x) -#endif - -#ifndef QRCODEGEN_TEST - #define testable static // Keep functions private -#else - #define testable // Expose private functions -#endif - - -/*---- Forward declarations for private functions ----*/ - -// Regarding all public and private functions defined in this source file: -// - They require all pointer/array arguments to be not null unless the array length is zero. -// - They only read input scalar/array arguments, write to output pointer/array -// arguments, and return scalar values; they are "pure" functions. -// - They don't read mutable global variables or write to any global variables. -// - They don't perform I/O, read the clock, print to console, etc. -// - They allocate a small and constant amount of stack memory. -// - They don't allocate or free any memory on the heap. -// - They don't recurse or mutually recurse. All the code -// could be inlined into the top-level public functions. -// - They run in at most quadratic time with respect to input arguments. -// Most functions run in linear time, and some in constant time. -// There are no unbounded loops or non-obvious termination conditions. -// - They are completely thread-safe if the caller does not give the -// same writable buffer to concurrent calls to these functions. - -testable void appendBitsToBuffer(unsigned int val, int numBits, uint8_t buffer[], int *bitLen); - -testable void addEccAndInterleave(uint8_t data[], int version, enum qrcodegen_Ecc ecl, uint8_t result[]); -testable int getNumDataCodewords(int version, enum qrcodegen_Ecc ecl); -testable int getNumRawDataModules(int ver); - -testable void reedSolomonComputeDivisor(int degree, uint8_t result[]); -testable void reedSolomonComputeRemainder(const uint8_t data[], int dataLen, - const uint8_t generator[], int degree, uint8_t result[]); -testable uint8_t reedSolomonMultiply(uint8_t x, uint8_t y); - -testable void initializeFunctionModules(int version, uint8_t qrcode[]); -static void drawWhiteFunctionModules(uint8_t qrcode[], int version); -static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[]); -testable int getAlignmentPatternPositions(int version, uint8_t result[7]); -static void fillRectangle(int left, int top, int width, int height, uint8_t qrcode[]); - -static void drawCodewords(const uint8_t data[], int dataLen, uint8_t qrcode[]); -static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qrcodegen_Mask mask); -static long getPenaltyScore(const uint8_t qrcode[]); -static int finderPenaltyCountPatterns(const int runHistory[7], int qrsize); -static int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, int runHistory[7], int qrsize); -static void finderPenaltyAddHistory(int currentRunLength, int runHistory[7]); - -testable bool getModule(const uint8_t qrcode[], int x, int y); -testable void setModule(uint8_t qrcode[], int x, int y, bool isBlack); -testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isBlack); -static bool getBit(int x, int i); - -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 $%*+-./:"; - -// 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) - //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, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low - {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium - {-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 -}; - -#define qrcodegen_REED_SOLOMON_DEGREE_MAX 30 // Based on the table above - -// For generating error correction codes. -testable const int8_t 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 - {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low - {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium - {-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 -}; - -// For automatic mask pattern selection. -static const int PENALTY_N1 = 3; -static const int PENALTY_N2 = 3; -static const int PENALTY_N3 = 40; -static const int PENALTY_N4 = 10; - - - -/*---- 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); - size_t bufLen = qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion); - struct qrcodegen_Segment seg; - size_t i = 0; - - if (textLen == 0) - return qrcodegen_encodeSegmentsAdvanced(NULL, 0, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode); - - if (qrcodegen_isNumeric(text)) { - if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, textLen) > bufLen) - goto fail; - seg = qrcodegen_makeNumeric(text, tempBuffer); - } else if (qrcodegen_isAlphanumeric(text)) { - if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ALPHANUMERIC, textLen) > bufLen) - goto fail; - seg = qrcodegen_makeAlphanumeric(text, tempBuffer); - } else { - if (textLen > bufLen) - goto fail; - for (i = 0; i < textLen; i++) - tempBuffer[i] = (uint8_t)text[i]; - seg.mode = qrcodegen_Mode_BYTE; - seg.bitLength = calcSegmentBitLength(seg.mode, textLen); - if (seg.bitLength == -1) - goto fail; - seg.numChars = (int)textLen; - 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); - if (seg.bitLength == -1) { - qrcode[0] = 0; // Set size to invalid value for safety - return false; - } - seg.numChars = (int)dataLen; - seg.data = dataAndTemp; - 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) { - int i = 0; - assert(0 <= numBits && numBits <= 16 && (unsigned long)val >> numBits == 0); - 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. -bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len, - enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]) { - return qrcodegen_encodeSegmentsAdvanced(segs, len, ecl, - 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[]) { - int version, dataUsedBits, i, j, bitLen; - int dataCapacityBits, terminatorBits; - uint8_t padByte; - - 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); - - // Find the minimal version number to use - for (version = minVersion; ; version++) { - int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available - dataUsedBits = getTotalBits(segs, len, 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 - qrcode[0] = 0; // Set size to invalid value for safety - return false; - } - } - assert(dataUsedBits != -1); - - // Increase the error correction level while the data still fits in the current version number - 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, qrcodegen_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0])); - bitLen = 0; - for (i = 0; i < len; i++) { - const struct qrcodegen_Segment *seg = &segs[i]; - appendBitsToBuffer((int)seg->mode, 4, qrcode, &bitLen); - appendBitsToBuffer(seg->numChars, numCharCountBits(seg->mode, version), qrcode, &bitLen); - for (j = 0; j < seg->bitLength; j++) - appendBitsToBuffer((seg->data[j >> 3] >> (7 - (j & 7))) & 1, 1, qrcode, &bitLen); - } - assert(bitLen == dataUsedBits); - - // Add terminator and pad up to a byte if applicable - dataCapacityBits = getNumDataCodewords(version, ecl) * 8; - assert(bitLen <= dataCapacityBits); - 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); - - // Pad with alternating bytes until data capacity is reached - for (padByte = 0xEC; bitLen < dataCapacityBits; padByte ^= 0xEC ^ 0x11) - appendBitsToBuffer(padByte, 8, qrcode, &bitLen); - - // Draw function and data codeword modules - addEccAndInterleave(qrcode, version, ecl, tempBuffer); - initializeFunctionModules(version, qrcode); - drawCodewords(tempBuffer, getNumRawDataModules(version) / 8, qrcode); - drawWhiteFunctionModules(qrcode, version); - initializeFunctionModules(version, tempBuffer); - - // Handle masking - if (mask == qrcodegen_Mask_AUTO) { // Automatically choose best mask - long minPenalty = LONG_MAX; - for (i = 0; i < 8; i++) { - enum qrcodegen_Mask msk = (enum qrcodegen_Mask)i; - long penalty; - applyMask(tempBuffer, qrcode, msk); - drawFormatBits(ecl, msk, qrcode); - penalty = getPenaltyScore(qrcode); - if (penalty < minPenalty) { - mask = msk; - minPenalty = penalty; - } - applyMask(tempBuffer, qrcode, msk); // Undoes the mask due to XOR - } - } - assert(0 <= (int)mask && (int)mask <= 7); - applyMask(tempBuffer, qrcode, mask); - drawFormatBits(ecl, mask, qrcode); - return true; -} - - - -/*---- Error correction code generation functions ----*/ - -// Appends error correction bytes to each block of the given data array, then interleaves -// bytes from the blocks and stores them in the result array. data[0 : dataLen] contains -// the input data. data[dataLen : rawCodewords] is used as a temporary work area and will -// 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 - 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; - uint8_t rsdiv[qrcodegen_REED_SOLOMON_DEGREE_MAX]; - const uint8_t *dat = data; - int i,j,k; - assert(0 <= (int)ecl && (int)ecl < 4 && qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX); - - // Split data into blocks, calculate ECC, and interleave - // (not concatenate) the bytes into a single sequence - reedSolomonComputeDivisor(blockEccLen, rsdiv); - 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 (j = 0, k = i; j < datLen; j++, k += numBlocks) { // Copy data - if (j == shortBlockDataLen) - k -= numShortBlocks; - result[k] = dat[j]; - } - 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); - return getNumRawDataModules(v) / 8 - - ECC_CODEWORDS_PER_BLOCK [e][v] - * NUM_ERROR_CORRECTION_BLOCKS[e][v]; -} - - -// Returns the number of data bits that can be stored in a QR Code of the given version number, after -// 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) { - int result = (16 * ver + 128) * ver + 64; - assert(qrcodegen_VERSION_MIN <= ver && ver <= qrcodegen_VERSION_MAX); - if (ver >= 2) { - int numAlign = ver / 7 + 2; - result -= (25 * numAlign - 10) * numAlign - 55; - if (ver >= 7) - result -= 36; - } - 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[]) { - uint8_t root = 1; - int i, j; - assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX); - // 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, 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). - for (i = 0; i < degree; i++) { - // Multiply the current product by (x - r^i) - for (j = 0; j < degree; j++) { - result[j] = reedSolomonMultiply(result[j], root); - if (j + 1 < degree) - result[j] ^= result[j + 1]; - } - root = reedSolomonMultiply(root, 0x02); - } -} - - -// 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[]) { - int i, j; - assert(1 <= degree && degree <= qrcodegen_REED_SOLOMON_DEGREE_MAX); - memset(result, 0, degree * sizeof(result[0])); - for (i = 0; i < dataLen; i++) { // Polynomial division - uint8_t factor = data[i] ^ result[0]; - memmove(&result[0], &result[1], (degree - 1) * sizeof(result[0])); - result[degree - 1] = 0; - 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; - int i; - for (i = 7; i >= 0; i--) { - z = (z << 1) ^ ((z >> 7) * 0x11D); - z ^= ((y >> i) & 1) * x; - } - return z; -} - - - -/*---- Drawing function modules ----*/ - -// Clears the given QR Code grid with white modules for the given -// version's size, then marks every function module as black. -testable void initializeFunctionModules(int version, uint8_t qrcode[]) { - // Initialize QR Code - uint8_t alignPatPos[7]; - int qrsize = version * 4 + 17; - int i,j; - int numAlign; - memset(qrcode, 0, ((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); - - numAlign = getAlignmentPatternPositions(version, alignPatPos); - // Fill numerous alignment patterns - 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); - fillRectangle(0, qrsize - 11, 6, 3, qrcode); - } -} - - -// Draws white function modules and possibly some black modules onto the given QR Code, without changing -// non-function modules. This does not draw the format bits. This requires all function modules to be previously -// marked black (namely by initializeFunctionModules()), because this may skip redrawing black function modules. -static void drawWhiteFunctionModules(uint8_t qrcode[], int version) { - // Draw horizontal and vertical timing patterns - int qrsize = qrcodegen_getSize(qrcode); - int i, j, dy, dx; - // Draw numerous alignment patterns - uint8_t alignPatPos[7]; - int numAlign = getAlignmentPatternPositions(version, alignPatPos); - - for (i = 7; i < qrsize - 7; i += 2) { - setModule(qrcode, 6, i, false); - setModule(qrcode, i, 6, false); - } - - // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules) - for (dy = -4; dy <= 4; dy++) { - for (dx = -4; dx <= 4; dx++) { - int dist = abs(dx); - if (abs(dy) > dist) - dist = abs(dy); - if (dist == 2 || dist == 4) { - setModuleBounded(qrcode, 3 + dx, 3 + dy, false); - setModuleBounded(qrcode, qrsize - 4 + dx, 3 + dy, false); - setModuleBounded(qrcode, 3 + dx, qrsize - 4 + dy, false); - } - } - } - - - 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 ( dy = -1; dy <= 1; dy++) { - for ( dx = -1; dx <= 1; dx++) - setModule(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] - long bits; - int k; - for ( i = 0; i < 12; i++) - rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); - bits = (long)version << 12 | rem; // uint18 - assert(bits >> 18 == 0); - - // Draw two copies - for (i = 0; i < 6; i++) { - for (j = 0; j < 3; j++) { - k = qrsize - 11 + j; - setModule(qrcode, k, i, (bits & 1) != 0); - setModule(qrcode, i, k, (bits & 1) != 0); - bits >>= 1; - } - } - } -} - - -// Draws two copies of the format bits (with its own error correction code) based -// on the given mask and error correction level. This always draws all modules of -// the format bits, unlike drawWhiteFunctionModules() which might skip black modules. -static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uint8_t qrcode[]) { - // Calculate error correction code and pack bits - 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; - int bits, i; - int qrsize; - assert(0 <= (int)mask && (int)mask <= 7); - for (i = 0; i < 10; i++) - rem = (rem << 1) ^ ((rem >> 9) * 0x537); - bits = (data << 10 | rem) ^ 0x5412; // uint15 - assert(bits >> 15 == 0); - - // Draw first copy - for ( i = 0; i <= 5; i++) - setModule(qrcode, 8, i, getBit(bits, i)); - setModule(qrcode, 8, 7, getBit(bits, 6)); - setModule(qrcode, 8, 8, getBit(bits, 7)); - setModule(qrcode, 7, 8, getBit(bits, 8)); - for ( i = 9; i < 15; i++) - setModule(qrcode, 14 - i, 8, getBit(bits, i)); - - // Draw second copy - qrsize = qrcodegen_getSize(qrcode); - for ( i = 0; i < 8; i++) - setModule(qrcode, qrsize - 1 - i, 8, getBit(bits, i)); - for ( i = 8; i < 15; i++) - setModule(qrcode, 8, qrsize - 15 + i, getBit(bits, i)); - setModule(qrcode, 8, qrsize - 8, true); // Always black -} - - -// 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. -// This could be implemented as lookup table of 40 variable-length lists of unsigned bytes. -testable int getAlignmentPatternPositions(int version, uint8_t result[7]) { - int numAlign = version / 7 + 2; - int pos; - int step = (version == 32) ? 26 : - (version*4 + numAlign*2 + 1) / (numAlign*2 - 2) * 2; - int i; - if (version == 1) - return 0; - for ( i = numAlign - 1, pos = version * 4 + 10; i >= 1; i--, pos -= step) - result[i] = pos; - result[0] = 6; - return numAlign; -} - - -// Sets every pixel in the range [left : left + width] * [top : top + height] to black. -static void fillRectangle(int left, int top, int width, int height, uint8_t qrcode[]) { - int dy, dx; - for ( dy = 0; dy < height; dy++) { - for ( dx = 0; dx < width; dx++) - setModule(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 black at function modules and white 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, right; // Bit index into the data - // Do the funny zigzag scan - for ( right = qrsize - 1; right >= 1; right -= 2) { // Index of right column in each column pair - int vert, j; - if (right == 6) - right = 5; - 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 - if (!getModule(qrcode, x, y) && i < dataLen * 8) { - bool black = getBit(data[i >> 3], 7 - (i & 7)); - setModule(qrcode, x, y, black); - i++; - } - // If this QR Code has any remainder bits (0 to 7), they were assigned as - // 0/false/white by the constructor and are left unchanged by this method - } - } - } - assert(i == dataLen * 8); -} - - -// XORs the codeword modules in this QR Code with the given mask pattern. -// The function modules must be marked and the codeword bits must be drawn -// before masking. Due to the arithmetic of XOR, calling applyMask() with -// 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) { - int qrsize = qrcodegen_getSize(qrcode); - int y; - assert(0 <= (int)mask && (int)mask <= 7); // Disallows qrcodegen_Mask_AUTO - for (y = 0; y < qrsize; y++) { - int x; - for ( x = 0; x < qrsize; x++) { - bool invert, val; - if (getModule(functionModules, x, y)) - continue; - switch ((int)mask) { - case 0: invert = (x + y) % 2 == 0; break; - case 1: invert = y % 2 == 0; break; - case 2: invert = x % 3 == 0; break; - case 3: invert = (x + y) % 3 == 0; break; - case 4: invert = (x / 3 + y / 2) % 2 == 0; break; - 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; - } - val = getModule(qrcode, x, y); - setModule(qrcode, x, y, val ^ invert); - } - } -} - - -// 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; - int y, x, k; - int black, total; - // Adjacent modules in row having same color, and finder-like patterns - for (y = 0; y < qrsize; y++) { - bool runColor = false; - int runX = 0; - int runHistory[7] = {0}; - int padRun = qrsize; // Add white border to initial run - int x; - for (x = 0; x < qrsize; x++) { - if (getModule(qrcode, x, y) == runColor) { - runX++; - if (runX == 5) - result += PENALTY_N1; - else if (runX > 5) - result++; - } else { - finderPenaltyAddHistory(runX + padRun, runHistory); - padRun = 0; - if (!runColor) - result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3; - runColor = getModule(qrcode, x, y); - runX = 1; - } - } - result += finderPenaltyTerminateAndCount(runColor, runX + padRun, runHistory, qrsize) * PENALTY_N3; - } - // Adjacent modules in column having same color, and finder-like patterns - for (x = 0; x < qrsize; x++) { - bool runColor = false; - int runY = 0; - int runHistory[7] = {0}; - int padRun = qrsize; // Add white border to initial run - int y; - for (y = 0; y < qrsize; y++) { - if (getModule(qrcode, x, y) == runColor) { - runY++; - if (runY == 5) - result += PENALTY_N1; - else if (runY > 5) - result++; - } else { - finderPenaltyAddHistory(runY + padRun, runHistory); - padRun = 0; - if (!runColor) - result += finderPenaltyCountPatterns(runHistory, qrsize) * PENALTY_N3; - runColor = getModule(qrcode, x, y); - runY = 1; - } - } - result += finderPenaltyTerminateAndCount(runColor, runY + padRun, runHistory, qrsize) * PENALTY_N3; - } - - // 2*2 blocks of modules having same color - for (y = 0; y < qrsize - 1; y++) { - for (x = 0; x < qrsize - 1; x++) { - bool color = getModule(qrcode, x, y); - if ( color == getModule(qrcode, x + 1, y) && - color == getModule(qrcode, x, y + 1) && - color == getModule(qrcode, x + 1, y + 1)) - result += PENALTY_N2; - } - } - - // Balance of black and white modules - - black = 0; - for ( y = 0; y < qrsize; y++) { - for ( x = 0; x < qrsize; x++) { - if (getModule(qrcode, x, y)) - black++; - } - } - total = qrsize * qrsize; // Note that size is odd, so black/total != 1/2 - // Compute the smallest integer k >= 0 such that (45-5k)% <= black/total <= (55+5k)% - k = (int)((labs(black * 20L - total * 10L) + total - 1) / total) - 1; - result += k * PENALTY_N4; - return result; -} - - -// Can only be called immediately after a white 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]; - bool core = n > 0 && runHistory[2] == n && runHistory[3] == n * 3 && runHistory[4] == n && runHistory[5] == n; - assert(n <= qrsize * 3); - // The maximum QR Code size is 177, hence the black 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); -} - - -// 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 black run - finderPenaltyAddHistory(currentRunLength, runHistory); - currentRunLength = 0; - } - currentRunLength += qrsize; // Add white border to final run - finderPenaltyAddHistory(currentRunLength, runHistory); - 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]) { - memmove(&runHistory[1], &runHistory[0], 6 * sizeof(runHistory[0])); - runHistory[0] = currentRunLength; -} - - - -/*---- Basic QR Code information ----*/ - -// Public function - see documentation comment in header file. -int qrcodegen_getSize(const uint8_t qrcode[]) { - int result = qrcode[0]; - assert(qrcode != NULL); - assert((qrcodegen_VERSION_MIN * 4 + 17) <= result - && result <= (qrcodegen_VERSION_MAX * 4 + 17)); - return result; -} - - -// Public function - see documentation comment in header file. -bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y) { - int qrsize = qrcode[0]; - assert(qrcode != NULL); - return (0 <= x && x < qrsize && 0 <= y && y < qrsize) && getModule(qrcode, x, y); -} - - -// Gets the module at the given coordinates, which must be in bounds. -testable bool getModule(const uint8_t qrcode[], int x, int y) { - int qrsize = qrcode[0]; - int index = y * qrsize + x; - assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize); - return getBit(qrcode[(index >> 3) + 1], index & 7); -} - - -// Sets the module at the given coordinates, which must be in bounds. -testable void setModule(uint8_t qrcode[], int x, int y, bool isBlack) { - int qrsize = qrcode[0]; - int index = y * qrsize + x; - int bitIndex = index & 7; - int byteIndex = (index >> 3) + 1; - assert(21 <= qrsize && qrsize <= 177 && 0 <= x && x < qrsize && 0 <= y && y < qrsize); - if (isBlack) - qrcode[byteIndex] |= 1 << bitIndex; - else - qrcode[byteIndex] &= (1 << bitIndex) ^ 0xFF; -} - - -// Sets the module at the given coordinates, doing nothing if out of bounds. -testable void setModuleBounded(uint8_t qrcode[], int x, int y, bool isBlack) { - int qrsize = qrcode[0]; - if (0 <= x && x < qrsize && 0 <= y && y < qrsize) - setModule(qrcode, x, y, isBlack); -} - - -// 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_isAlphanumeric(const char *text) { - assert(text != NULL); - for (; *text != '\0'; text++) { - if (strchr(ALPHANUMERIC_CHARSET, *text) == NULL) - return false; - } - return true; -} - - -// 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; - } - 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) - 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 -// the number of needed bits exceeds INT16_MAX (i.e. 32767). -// - Otherwise, all valid results are in the range [0, INT16_MAX]. -// - For byte mode, numChars measures the number of bytes, not Unicode code points. -// - For ECI mode, numChars must be 0, and the worst-case number of bits is returned. -// An actual ECI segment can have shorter data. For non-ECI modes, the result is exact. -testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars) { - long result; - // All calculations are designed to avoid overflow on all platforms - if (numChars > (unsigned int)INT16_MAX) - return -1; - result = (long)numChars; - if (mode == qrcodegen_Mode_NUMERIC) - result = (result * 10 + 2) / 3; // ceil(10/3 * n) - else if (mode == qrcodegen_Mode_ALPHANUMERIC) - result = (result * 11 + 1) / 2; // ceil(11/2 * n) - else if (mode == qrcodegen_Mode_BYTE) - result *= 8; - else if (mode == qrcodegen_Mode_KANJI) - result *= 13; - else if (mode == qrcodegen_Mode_ECI && numChars == 0) - result = 3 * 8; - else { // Invalid argument - assert(false); - return -1; - } - assert(result >= 0); - 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[]) { - struct qrcodegen_Segment result; - assert(data != NULL || len == 0); - 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])); - result.data = buf; - return result; -} - - -// Public function - see documentation comment in header file. -struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]) { - struct qrcodegen_Segment result; - size_t len = strlen(digits); - int bitLen = 0; - unsigned int accumData = 0; - int accumCount = 0; - - assert(digits != NULL); - result.mode = qrcodegen_Mode_NUMERIC; - 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; - - for (; *digits != '\0'; digits++) { - char c = *digits; - assert('0' <= c && c <= '9'); - accumData = accumData * 10 + (unsigned int)(c - '0'); - accumCount++; - if (accumCount == 3) { - appendBitsToBuffer(accumData, 10, buf, &result.bitLength); - accumData = 0; - accumCount = 0; - } - } - 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[]) { - struct qrcodegen_Segment result; - size_t len = strlen(text); - unsigned int accumData = 0; - int accumCount = 0; - int bitLen; - result.mode = qrcodegen_Mode_ALPHANUMERIC; - bitLen = calcSegmentBitLength(result.mode, len); - assert(text != NULL); - - assert(bitLen != -1); - result.numChars = (int)len; - if (bitLen > 0) - memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0])); - result.bitLength = 0; - - for (; *text != '\0'; text++) { - const char *temp = strchr(ALPHANUMERIC_CHARSET, *text); - assert(temp != NULL); - accumData = accumData * 45 + (unsigned int)(temp - ALPHANUMERIC_CHARSET); - accumCount++; - if (accumCount == 2) { - appendBitsToBuffer(accumData, 11, buf, &result.bitLength); - accumData = 0; - accumCount = 0; - } - } - 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; - result.mode = qrcodegen_Mode_ECI; - result.numChars = 0; - result.bitLength = 0; - if (assignVal < 0) - assert(false); - else if (assignVal < (1 << 7)) { - memset(buf, 0, 1 * sizeof(buf[0])); - appendBitsToBuffer(assignVal, 8, buf, &result.bitLength); - } else if (assignVal < (1 << 14)) { - memset(buf, 0, 2 * sizeof(buf[0])); - appendBitsToBuffer(2, 2, buf, &result.bitLength); - appendBitsToBuffer(assignVal, 14, buf, &result.bitLength); - } else if (assignVal < 1000000L) { - memset(buf, 0, 3 * sizeof(buf[0])); - appendBitsToBuffer(6, 3, buf, &result.bitLength); - appendBitsToBuffer(assignVal >> 10, 11, buf, &result.bitLength); - appendBitsToBuffer(assignVal & 0x3FF, 10, buf, &result.bitLength); - } else - assert(false); - 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) { - long result = 0; - size_t i; - assert(segs != NULL || len == 0); - for (i = 0; i < len; i++) { - int numChars = segs[i].numChars; - int bitLength = segs[i].bitLength; - int ccbits = numCharCountBits(segs[i].mode, version); - assert(0 <= numChars && numChars <= INT16_MAX); - assert(0 <= bitLength && bitLength <= INT16_MAX); - assert(0 <= ccbits && ccbits <= 16); - 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); - 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) { - int i = (version + 7) / 17; - assert(qrcodegen_VERSION_MIN <= version && version <= qrcodegen_VERSION_MAX); - switch (mode) { - case qrcodegen_Mode_NUMERIC : { static const int temp[] = {10, 12, 14}; return temp[i]; } - case qrcodegen_Mode_ALPHANUMERIC: { static const int temp[] = { 9, 11, 13}; return temp[i]; } - 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 - } -} diff --git a/TotalCrossVM/src/nm/qrcode/win/qrcodegen.h b/TotalCrossVM/src/nm/qrcode/win/qrcodegen.h deleted file mode 100644 index b3052a7978..0000000000 --- a/TotalCrossVM/src/nm/qrcode/win/qrcodegen.h +++ /dev/null @@ -1,311 +0,0 @@ -/* - * QR Code generator library (C) - * - * Copyright (c) Project Nayuki. (MIT License) - * https://www.nayuki.io/page/qr-code-generator-library - * - * 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. - */ - -#pragma once - -#include "stdbool.h" -#include -#include - - -#ifdef __cplusplus -extern "C" { -#endif - - -/* - * 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 black and white cells. - * The library provides functions to create a QR Code from text or binary data. - * The library covers the QR Code Model 2 specification, supporting all versions (sizes) - * from 1 to 40, all 4 error correction levels, and 4 character encoding modes. - * - * Ways to create a QR Code object: - * - High level: Take the payload data and call qrcodegen_encodeText() or qrcodegen_encodeBinary(). - * - Low level: Custom-make the list of segments and call - * qrcodegen_encodeSegments() or qrcodegen_encodeSegmentsAdvanced(). - * (Note that all ways require supplying the desired error correction level and various byte buffers.) - */ - - -/*---- Enum and struct types----*/ - -/* - * The error correction level in a QR Code symbol. - */ -enum qrcodegen_Ecc { - // Must be declared in ascending order of error protection - // so that an internal qrcodegen function works properly - qrcodegen_Ecc_LOW = 0 , // The QR Code can tolerate about 7% erroneous codewords - qrcodegen_Ecc_MEDIUM , // The QR Code can tolerate about 15% erroneous codewords - qrcodegen_Ecc_QUARTILE, // The QR Code can tolerate about 25% erroneous codewords - qrcodegen_Ecc_HIGH , // The QR Code can tolerate about 30% erroneous codewords -}; - - -/* - * The mask pattern used in a QR Code symbol. - */ -enum qrcodegen_Mask { - // A special value to tell the QR Code encoder to - // automatically select an appropriate mask pattern - qrcodegen_Mask_AUTO = -1, - // The eight actual mask patterns - qrcodegen_Mask_0 = 0, - qrcodegen_Mask_1, - qrcodegen_Mask_2, - qrcodegen_Mask_3, - qrcodegen_Mask_4, - qrcodegen_Mask_5, - qrcodegen_Mask_6, - qrcodegen_Mask_7, -}; - - -/* - * Describes how a segment's data bits are interpreted. - */ -enum qrcodegen_Mode { - qrcodegen_Mode_NUMERIC = 0x1, - qrcodegen_Mode_ALPHANUMERIC = 0x2, - qrcodegen_Mode_BYTE = 0x4, - qrcodegen_Mode_KANJI = 0x8, - qrcodegen_Mode_ECI = 0x7, -}; - - -/* - * 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(). - * The low-level way to create a segment is to custom-make the bit buffer - * and initialize a qrcodegen_Segment struct with appropriate values. - * Even in the most favorable conditions, a QR Code can only hold 7089 characters of data. - * Any segment longer than this is meaningless for the purpose of generating QR Codes. - * Moreover, the maximum allowed bit length is 32767 because - * the largest QR Code (version 40) has 31329 modules. - */ -struct qrcodegen_Segment { - // The mode indicator of this segment. - enum qrcodegen_Mode mode; - - // 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. - // Always zero or positive. Not the same as the data's bit length. - int numChars; - - // The data bits of this segment, packed in bitwise big endian. - // Can be null if the bit length is zero. - uint8_t *data; - - // The number of valid data bits used in the buffer. Requires - // 0 <= bitLength <= 32767, and bitLength <= (capacity of data array) * 8. - // The character count (numChars) must agree with the mode and the bit buffer length. - int bitLength; -}; - - - -/*---- Macro constants and functions ----*/ - -#define qrcodegen_VERSION_MIN 1 // The minimum version number supported in the QR Code Model 2 standard -#define qrcodegen_VERSION_MAX 40 // The maximum version number supported in the QR Code Model 2 standard - -// Calculates the number of bytes needed to store any QR Code up to and including the given version number, -// as a compile-time constant. For example, 'uint8_t buffer[qrcodegen_BUFFER_LEN_FOR_VERSION(25)];' -// can store any single QR Code from version 1 to 25 (inclusive). The result fits in an int (or int16). -// Requires qrcodegen_VERSION_MIN <= n <= qrcodegen_VERSION_MAX. -#define qrcodegen_BUFFER_LEN_FOR_VERSION(n) ((((n) * 4 + 17) * ((n) * 4 + 17) + 7) / 8 + 1) - -// The worst-case number of bytes needed to store one QR Code, up to and including -// version 40. This value equals 3918, which is just under 4 kilobytes. -// Use this more convenient value to avoid calculating tighter memory bounds for buffers. -#define qrcodegen_BUFFER_LEN_MAX qrcodegen_BUFFER_LEN_FOR_VERSION(qrcodegen_VERSION_MAX) - - - -/*---- Functions (high level) to generate QR Codes ----*/ - -/* - * Encodes the given text string to a QR Code, returning true if encoding succeeded. - * If the data is too long to fit in any version in the given range - * at the given ECC level, then false is returned. - * - The input text must be encoded in UTF-8 and contain no NULs. - * - The variables ecl and mask must correspond to enum constant values. - * - Requires 1 <= minVersion <= maxVersion <= 40. - * - The arrays tempBuffer and qrcode must each have a length - * of at least qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion). - * - After the function returns, tempBuffer contains no useful data. - * - If successful, the resulting QR Code may use numeric, - * alphanumeric, or byte mode to encode the text. - * - In the most optimistic case, a QR Code at version 40 with low ECC - * can hold any UTF-8 string up to 2953 bytes, or any alphanumeric string - * up to 4296 characters, or any digit string up to 7089 characters. - * These numbers represent the hard upper limit of the QR Code standard. - * - Please consult the QR Code specification for information on - * data capacities per version, ECC level, and text encoding mode. - */ -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 encoding succeeded. - * If the data is too long to fit in any version in the given range - * at the given ECC level, then false is returned. - * - The input array range dataAndTemp[0 : dataLen] should normally be - * valid UTF-8 text, but is not required by the QR Code standard. - * - The variables ecl and mask must correspond to enum constant values. - * - Requires 1 <= minVersion <= maxVersion <= 40. - * - The arrays dataAndTemp and qrcode must each have a length - * of at least qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion). - * - After the function returns, the contents of dataAndTemp may have changed, - * and does not represent useful data anymore. - * - If successful, the resulting QR Code will use byte mode to encode the data. - * - In the most optimistic case, a QR Code at version 40 with low ECC can hold any byte - * sequence up to length 2953. This is the hard upper limit of the QR Code standard. - * - Please consult the QR Code specification for information on - * data capacities per version, ECC level, and text encoding mode. - */ -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); - - -/*---- Functions (low level) to generate QR Codes ----*/ - -/* - * Renders a QR Code representing the given segments at the given error correction level. - * The smallest possible QR Code version is automatically chosen for the output. Returns true if - * QR Code creation succeeded, or false if the data is too long to fit in any version. The ECC level - * of the result may be higher than the ecl argument if it can be done without increasing the version. - * This function allows the user to create a custom sequence of segments that switches - * between modes (such as alphanumeric and byte) to encode text in less space. - * This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary(). - * To save memory, the segments' data buffers can alias/overlap tempBuffer, and will - * result in them being clobbered, but the QR Code output will still be correct. - * But the qrcode array must not overlap tempBuffer or any segment's data buffer. - */ -bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len, - enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]); - - -/* - * Renders a QR Code representing the given segments with the given encoding parameters. - * Returns true if QR Code creation succeeded, or false if the data is too long to fit in the range of versions. - * The smallest possible QR Code version within the given range is automatically - * chosen for the output. Iff boostEcl is true, then the ECC level of the result - * may be higher than the ecl argument if it can be done without increasing the - * version. The mask is either between qrcodegen_Mask_0 to 7 to force that mask, or - * qrcodegen_Mask_AUTO to automatically choose an appropriate mask (which may be slow). - * This function allows the user to create a custom sequence of segments that switches - * between modes (such as alphanumeric and byte) to encode text in less space. - * This is a low-level API; the high-level API is qrcodegen_encodeText() and qrcodegen_encodeBinary(). - * To save memory, the segments' data buffers can alias/overlap tempBuffer, and will - * result in them being clobbered, but the QR Code output will still be correct. - * But the qrcode array must not overlap tempBuffer or any segment's data buffer. - */ -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[]); - - -/* - * 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. - */ -bool qrcodegen_isAlphanumeric(const char *text); - - -/* - * 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); - - -/* - * 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 number of needed bits exceeds INT16_MAX (i.e. 32767). - * - Otherwise, all valid results are in the range [0, ceil(INT16_MAX / 8)], i.e. at most 4096. - * - It is okay for the user to allocate more bytes for the buffer than needed. - * - For byte mode, numChars measures the number of bytes, not Unicode code points. - * - For ECI mode, numChars must be 0, and the worst-case number of bytes is returned. - * An actual ECI segment can have shorter data. For non-ECI modes, the result is exact. - */ -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. - */ -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. - */ -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. - */ -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 - * qrcodegen_BUFFER_LEN_FOR_VERSION(version), which equals ceil(size^2 / 8 + 1). - */ -int qrcodegen_getSize(const uint8_t qrcode[]); - - -/* - * Returns the color of the module (pixel) at the given coordinates, which is false - * for white or true for black. The top left corner has the coordinates (x=0, y=0). - * If the given coordinates are out of bounds, then false (white) is returned. - */ -bool qrcodegen_getModule(const uint8_t qrcode[], int x, int y); - - -#ifdef __cplusplus -} -#endif diff --git a/TotalCrossVM/src/nm/qrcode/win/stdbool.h b/TotalCrossVM/src/nm/qrcode/win/stdbool.h deleted file mode 100644 index 6a41b139d0..0000000000 --- a/TotalCrossVM/src/nm/qrcode/win/stdbool.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef STDBOOL_H_ -#define STDBOOL_H_ - -/** - * stdbool.h - ISO C99 Boolean type - * Author - Bill Chatfield - * E-mail - bill underscore chatfield at yahoo dot com - * Copyright - You are free to use for any purpose except illegal acts - * Warrenty - None: don't blame me if it breaks something - * - * In ISO C99, stdbool.h is a standard header and _Bool is a keyword, but - * some compilers don't offer these yet. This header file is an - * implementation of the standard ISO C99 stdbool.h header file. It checks - * for various compiler versions and defines things that are missing in - * those versions. - * - * The GNU and Watcom compilers include a stdbool.h, but the Borland - * C/C++ 5.5.1 compiler and the Microsoft compilers do not. - * - * See http://predef.sourceforge.net/precomp.html for compile macros. - */ - -/** - * Borland C++ 5.5.1 does not define _Bool. - */ -#ifdef __BORLANDC__ -typedef int _Bool; -#endif - -/** - * Microsoft C/C++ version 14.00.50727.762, which comes with Visual C++ 2005, - * and version 15.00.30729.01, which comes with Visual C++ 2008, do not - * define _Bool. - */ -#if defined(_MSC_VER) && _MSC_VER <= 1500 -typedef int _Bool; -#endif - -/** - * Define the Boolean macros only if they are not already defined. - */ -#ifndef __bool_true_false_are_defined -#define bool _Bool -#define false 0 -#define true 1 -#define __bool_true_false_are_defined 1 -#endif - -#endif /*STDBOOL_H_*/ \ No newline at end of file