LCOV - code coverage report
Current view: top level - src/encode - writer.c (source / functions) Coverage Total Hit
Test: lierre Coverage Report Lines: 89.5 % 799 715
Test Date: 2026-03-06 08:40:14 Functions: 100.0 % 37 37
Legend: Lines: hit not hit

            Line data    Source code
       1              : /*
       2              :  * liblierre - writer.c
       3              :  *
       4              :  * This file is part of liblierre.
       5              :  *
       6              :  * Author: Go Kudo <zeriyoshi@gmail.com>
       7              :  * SPDX-License-Identifier: MIT
       8              :  */
       9              : 
      10              : #include <stdint.h>
      11              : #include <string.h>
      12              : 
      13              : #include <lierre.h>
      14              : #include <lierre/writer.h>
      15              : 
      16              : #include <poporon.h>
      17              : 
      18              : #include "../internal/memory.h"
      19              : #include "../internal/structs.h"
      20              : 
      21              : #define RS_GF256_PRIMITIVE_POLY 0x11D
      22              : #define RS_GF256_GENERATOR_ROOT 0x1
      23              : #define RS_BYTE_BITS            7
      24              : 
      25              : #define FORMAT_POLY            0x537
      26              : #define FORMAT_XOR_MASK        0x5412
      27              : #define FORMAT_POLY_SHIFT      9
      28              : #define FORMAT_DATA_SHIFT      10
      29              : #define FORMAT_BITS_COUNT      15
      30              : #define FORMAT_BITS_LOOP_END   6
      31              : #define FORMAT_BITS_LOOP_START 9
      32              : 
      33              : #define QR_VERSION_MAX               40
      34              : #define QR_VERSION_MIN               1
      35              : #define QR_VERSION1_SIZE             17
      36              : #define QR_VERSION_SIZE_FORMULA(v)   ((v) * 4 + QR_VERSION1_SIZE)
      37              : #define QR_BUFFER_LEN_FOR_VERSION(n) (((((n) * 4 + 17) * ((n) * 4 + 17) + 7) >> 3) + 1)
      38              : #define QR_BUFFER_LEN_MAX            QR_BUFFER_LEN_FOR_VERSION(QR_VERSION_MAX)
      39              : #define QR_RS_DEGREE_MAX             30
      40              : #define QR_MASK_COUNT                8
      41              : 
      42              : #define QR_MODE_NUMERIC_INDICATOR      0x1
      43              : #define QR_MODE_ALPHANUMERIC_INDICATOR 0x2
      44              : #define QR_MODE_BYTE_INDICATOR         0x4
      45              : #define QR_MODE_ECI_INDICATOR          0x7
      46              : #define QR_MODE_KANJI_INDICATOR        0x8
      47              : #define QR_MODE_INDICATOR_BITS         4
      48              : #define QR_TERMINATOR_MAX_BITS         4
      49              : #define QR_PAD_BYTE_BITS               8
      50              : 
      51              : #define VERSION_THRESHOLD_SMALL  10
      52              : #define VERSION_THRESHOLD_MEDIUM 27
      53              : #define VERSION_INFO_MIN         7
      54              : #define VERSION_INFO_BITS        12
      55              : #define VERSION_INFO_POLY        0x1F25
      56              : #define VERSION_INFO_SHIFT       11
      57              : #define VERSION_INFO_DATA_SHIFT  12
      58              : #define VERSION_INFO_AREA_WIDTH  3
      59              : #define VERSION_INFO_AREA_HEIGHT 6
      60              : #define VERSION_INFO_OFFSET      11
      61              : 
      62              : #define NUMERIC_BITS_SMALL  10
      63              : #define NUMERIC_BITS_MEDIUM 12
      64              : #define NUMERIC_BITS_LARGE  14
      65              : 
      66              : #define ALPHA_BITS_SMALL  9
      67              : #define ALPHA_BITS_MEDIUM 11
      68              : #define ALPHA_BITS_LARGE  13
      69              : 
      70              : #define BYTE_BITS_SMALL 8
      71              : #define BYTE_BITS_LARGE 16
      72              : 
      73              : #define KANJI_BITS_SMALL  8
      74              : #define KANJI_BITS_MEDIUM 10
      75              : #define KANJI_BITS_LARGE  12
      76              : 
      77              : #define NUMERIC_GROUP_SIZE      3
      78              : #define NUMERIC_GROUP_BITS      10
      79              : #define NUMERIC_REMAINDER2_BITS 7
      80              : #define NUMERIC_REMAINDER1_BITS 4
      81              : 
      82              : #define ALPHANUMERIC_CHARSET_SIZE   45
      83              : #define ALPHANUMERIC_GROUP_SIZE     2
      84              : #define ALPHANUMERIC_GROUP_BITS     11
      85              : #define ALPHANUMERIC_REMAINDER_BITS 6
      86              : 
      87              : #define KANJI_ENCODED_BITS      13
      88              : #define KANJI_SJIS_RANGE1_START 0x8140
      89              : #define KANJI_SJIS_RANGE1_END   0x9FFC
      90              : #define KANJI_SJIS_RANGE2_START 0xE040
      91              : #define KANJI_SJIS_RANGE2_END   0xEBBF
      92              : #define KANJI_ENCODE_BASE1      0x8140
      93              : #define KANJI_ENCODE_BASE2      0xC140
      94              : #define KANJI_ENCODE_MULTIPLIER 0xC0
      95              : 
      96              : #define PAD_BYTE_FIRST  0xEC
      97              : #define PAD_BYTE_SECOND 0x11
      98              : 
      99              : #define ECI_SINGLE_BYTE_MAX 127
     100              : #define ECI_DOUBLE_BYTE_MAX 16383
     101              : #define ECI_PREFIX_2BYTE    0x80
     102              : #define ECI_PREFIX_3BYTE    0xC0
     103              : #define ECI_MASK_2BYTE      0x3F
     104              : #define ECI_MASK_3BYTE      0x1F
     105              : #define ECI_BITS_3BYTE      24
     106              : #define ECI_DEFAULT_VALUE   26
     107              : 
     108              : #define FINDER_PATTERN_CENTER 3
     109              : #define FINDER_PATTERN_RADIUS 4
     110              : #define FINDER_QUIET_SIZE     8
     111              : #define FINDER_CORNER_SIZE    9
     112              : 
     113              : #define TIMING_PATTERN_POSITION 6
     114              : #define TIMING_PATTERN_START    7
     115              : 
     116              : #define ALIGNMENT_PATTERN_SIZE   5
     117              : #define ALIGNMENT_PATTERN_OFFSET 2
     118              : #define ALIGNMENT_BASE_POSITION  6
     119              : 
     120              : #define PENALTY_RUN_THRESHOLD        5
     121              : #define PENALTY_RUN_BASE             3
     122              : #define PENALTY_FINDER_LIKE          40
     123              : #define PENALTY_2X2_BLOCK            3
     124              : #define PENALTY_BALANCE_MULTIPLIER   10
     125              : #define PENALTY_BALANCE_FACTOR_DARK  20
     126              : #define PENALTY_BALANCE_FACTOR_TOTAL 10
     127              : #define PENALTY_HISTORY_SIZE         7
     128              : #define PENALTY_HISTORY_MOVE_SIZE    6
     129              : 
     130              : #define ALPHA_LETTER_OFFSET  10
     131              : #define ALPHA_SPACE_VALUE    36
     132              : #define ALPHA_DOLLAR_VALUE   37
     133              : #define ALPHA_PERCENT_VALUE  38
     134              : #define ALPHA_ASTERISK_VALUE 39
     135              : #define ALPHA_PLUS_VALUE     40
     136              : #define ALPHA_MINUS_VALUE    41
     137              : #define ALPHA_DOT_VALUE      42
     138              : #define ALPHA_SLASH_VALUE    43
     139              : #define ALPHA_COLON_VALUE    44
     140              : 
     141              : static const int8_t ECC_CODEWORDS_PER_BLOCK[4][41] = {
     142              :     {-1, 7,  10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28,
     143              :      28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
     144              :     {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26,
     145              :      26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28},
     146              :     {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30,
     147              :      28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
     148              :     {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28,
     149              :      30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30},
     150              : };
     151              : 
     152              : static const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41] = {
     153              :     {-1, 1, 1, 1,  1,  1,  2,  2,  2,  2,  4,  4,  4,  4,  4,  6,  6,  6,  6,  7, 8,
     154              :      8,  9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25},
     155              :     {-1, 1,  1,  1,  2,  2,  4,  4,  4,  5,  5,  5,  8,  9,  9,  10, 10, 11, 13, 14, 16,
     156              :      17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49},
     157              :     {-1, 1,  1,  2,  2,  4,  4,  6,  6,  8,  8,  8,  10, 12, 16, 12, 17, 16, 18, 21, 20,
     158              :      23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68},
     159              :     {-1, 1,  1,  2,  4,  4,  4,  5,  6,  8,  8,  11, 11, 16, 16, 18, 16, 19, 21, 25, 25,
     160              :      25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81},
     161              : };
     162              : 
     163              : static const int16_t DATA_CODEWORDS[4][41] = {
     164              :     /* ECL L */
     165              :     {-1,   19,   34,   55,   80,   108,  136,  156,  194,  232,  274,  324,  370,  428,
     166              :      461,  523,  589,  647,  721,  795,  861,  932,  1006, 1094, 1174, 1276, 1370, 1468,
     167              :      1531, 1631, 1735, 1843, 1955, 2071, 2191, 2306, 2434, 2566, 2702, 2812, 2956},
     168              :     /* ECL M */
     169              :     {-1,   16,   28,   44,   64,   86,   108,  124,  154,  182,  216,  254,  290,  334,
     170              :      365,  415,  453,  507,  563,  627,  669,  714,  782,  860,  914,  1000, 1062, 1128,
     171              :      1193, 1267, 1373, 1455, 1541, 1631, 1725, 1812, 1914, 1992, 2102, 2216, 2334},
     172              :     /* ECL Q */
     173              :     {-1,  13,  22,  34,  48,  62,  76,  88,  110, 132, 154,  180,  206,  244,  261,  295,  325,  367,  397,  445, 485,
     174              :      512, 568, 614, 664, 718, 754, 808, 871, 911, 985, 1033, 1115, 1171, 1231, 1286, 1354, 1426, 1502, 1582, 1666},
     175              :     /* ECL H */
     176              :     {-1,  9,   16,  26,  36,  46,  60,  66,  86,  100, 122, 140, 158, 180, 197, 223,  253,  283,  313,  341, 385,
     177              :      406, 442, 464, 514, 538, 596, 628, 661, 701, 745, 793, 845, 901, 961, 986, 1054, 1096, 1142, 1222, 1276},
     178              : };
     179              : 
     180              : static const int16_t CHAR_CAPACITY[4][41][4] = {
     181              :     /* ECL L */
     182              :     {
     183              :         {-1, -1, -1, -1},         /* version 0 (invalid) */
     184              :         {41, 25, 17, 10},         /* version 1 */
     185              :         {77, 47, 32, 20},         /* version 2 */
     186              :         {127, 77, 53, 32},        /* version 3 */
     187              :         {187, 114, 78, 48},       /* version 4 */
     188              :         {255, 154, 106, 65},      /* version 5 */
     189              :         {322, 195, 134, 82},      /* version 6 */
     190              :         {370, 224, 154, 95},      /* version 7 */
     191              :         {461, 279, 192, 118},     /* version 8 */
     192              :         {552, 335, 230, 141},     /* version 9 */
     193              :         {652, 395, 271, 167},     /* version 10 */
     194              :         {772, 468, 321, 198},     /* version 11 */
     195              :         {883, 535, 367, 226},     /* version 12 */
     196              :         {1022, 619, 425, 262},    /* version 13 */
     197              :         {1101, 667, 458, 282},    /* version 14 */
     198              :         {1250, 758, 520, 320},    /* version 15 */
     199              :         {1408, 854, 586, 361},    /* version 16 */
     200              :         {1548, 938, 644, 397},    /* version 17 */
     201              :         {1725, 1046, 718, 442},   /* version 18 */
     202              :         {1903, 1153, 792, 488},   /* version 19 */
     203              :         {2061, 1249, 858, 528},   /* version 20 */
     204              :         {2232, 1352, 929, 572},   /* version 21 */
     205              :         {2409, 1460, 1003, 618},  /* version 22 */
     206              :         {2620, 1588, 1091, 672},  /* version 23 */
     207              :         {2812, 1704, 1171, 721},  /* version 24 */
     208              :         {3057, 1853, 1273, 784},  /* version 25 */
     209              :         {3283, 1990, 1367, 842},  /* version 26 */
     210              :         {3517, 2132, 1465, 902},  /* version 27 */
     211              :         {3669, 2223, 1528, 940},  /* version 28 */
     212              :         {3909, 2369, 1628, 1002}, /* version 29 */
     213              :         {4158, 2520, 1732, 1066}, /* version 30 */
     214              :         {4417, 2677, 1840, 1132}, /* version 31 */
     215              :         {4686, 2840, 1952, 1201}, /* version 32 */
     216              :         {4965, 3009, 2068, 1273}, /* version 33 */
     217              :         {5253, 3183, 2188, 1347}, /* version 34 */
     218              :         {5529, 3351, 2303, 1417}, /* version 35 */
     219              :         {5836, 3537, 2431, 1496}, /* version 36 */
     220              :         {6153, 3729, 2563, 1577}, /* version 37 */
     221              :         {6479, 3927, 2699, 1661}, /* version 38 */
     222              :         {6743, 4087, 2809, 1729}, /* version 39 */
     223              :         {7089, 4296, 2953, 1817}, /* version 40 */
     224              :     },
     225              :     /* ECL M */
     226              :     {
     227              :         {-1, -1, -1, -1},         /* version 0 (invalid) */
     228              :         {34, 20, 14, 8},          /* version 1 */
     229              :         {63, 38, 26, 16},         /* version 2 */
     230              :         {101, 61, 42, 26},        /* version 3 */
     231              :         {149, 90, 62, 38},        /* version 4 */
     232              :         {202, 122, 84, 52},       /* version 5 */
     233              :         {255, 154, 106, 65},      /* version 6 */
     234              :         {293, 178, 122, 75},      /* version 7 */
     235              :         {365, 221, 152, 93},      /* version 8 */
     236              :         {432, 262, 180, 111},     /* version 9 */
     237              :         {513, 311, 213, 131},     /* version 10 */
     238              :         {604, 366, 251, 155},     /* version 11 */
     239              :         {691, 419, 287, 177},     /* version 12 */
     240              :         {796, 483, 331, 204},     /* version 13 */
     241              :         {871, 528, 362, 223},     /* version 14 */
     242              :         {991, 600, 412, 254},     /* version 15 */
     243              :         {1082, 656, 450, 277},    /* version 16 */
     244              :         {1212, 734, 504, 310},    /* version 17 */
     245              :         {1346, 816, 560, 345},    /* version 18 */
     246              :         {1500, 909, 624, 384},    /* version 19 */
     247              :         {1600, 970, 666, 410},    /* version 20 */
     248              :         {1708, 1035, 711, 438},   /* version 21 */
     249              :         {1872, 1134, 779, 480},   /* version 22 */
     250              :         {2059, 1248, 857, 528},   /* version 23 */
     251              :         {2188, 1326, 911, 561},   /* version 24 */
     252              :         {2395, 1451, 997, 614},   /* version 25 */
     253              :         {2544, 1542, 1059, 652},  /* version 26 */
     254              :         {2701, 1637, 1125, 692},  /* version 27 */
     255              :         {2857, 1732, 1190, 732},  /* version 28 */
     256              :         {3035, 1839, 1264, 778},  /* version 29 */
     257              :         {3289, 1994, 1370, 843},  /* version 30 */
     258              :         {3486, 2113, 1452, 894},  /* version 31 */
     259              :         {3693, 2238, 1538, 947},  /* version 32 */
     260              :         {3909, 2369, 1628, 1002}, /* version 33 */
     261              :         {4134, 2506, 1722, 1060}, /* version 34 */
     262              :         {4343, 2632, 1809, 1113}, /* version 35 */
     263              :         {4588, 2780, 1911, 1176}, /* version 36 */
     264              :         {4775, 2894, 1989, 1224}, /* version 37 */
     265              :         {5039, 3054, 2099, 1292}, /* version 38 */
     266              :         {5313, 3220, 2213, 1362}, /* version 39 */
     267              :         {5596, 3391, 2331, 1435}, /* version 40 */
     268              :     },
     269              :     /* ECL Q */
     270              :     {
     271              :         {-1, -1, -1, -1},         /* version 0 (invalid) */
     272              :         {27, 16, 11, 7},          /* version 1 */
     273              :         {48, 29, 20, 12},         /* version 2 */
     274              :         {77, 47, 32, 20},         /* version 3 */
     275              :         {111, 67, 46, 28},        /* version 4 */
     276              :         {144, 87, 60, 37},        /* version 5 */
     277              :         {178, 108, 74, 45},       /* version 6 */
     278              :         {207, 125, 86, 53},       /* version 7 */
     279              :         {259, 157, 108, 66},      /* version 8 */
     280              :         {312, 189, 130, 80},      /* version 9 */
     281              :         {364, 221, 151, 93},      /* version 10 */
     282              :         {427, 259, 177, 109},     /* version 11 */
     283              :         {489, 296, 203, 125},     /* version 12 */
     284              :         {580, 352, 241, 149},     /* version 13 */
     285              :         {621, 376, 258, 159},     /* version 14 */
     286              :         {703, 426, 292, 180},     /* version 15 */
     287              :         {775, 470, 322, 198},     /* version 16 */
     288              :         {876, 531, 364, 224},     /* version 17 */
     289              :         {948, 574, 394, 243},     /* version 18 */
     290              :         {1063, 644, 442, 272},    /* version 19 */
     291              :         {1159, 702, 482, 297},    /* version 20 */
     292              :         {1224, 742, 509, 314},    /* version 21 */
     293              :         {1358, 823, 565, 348},    /* version 22 */
     294              :         {1468, 890, 611, 376},    /* version 23 */
     295              :         {1588, 963, 661, 407},    /* version 24 */
     296              :         {1718, 1041, 715, 440},   /* version 25 */
     297              :         {1804, 1094, 751, 462},   /* version 26 */
     298              :         {1933, 1172, 805, 496},   /* version 27 */
     299              :         {2085, 1263, 868, 534},   /* version 28 */
     300              :         {2181, 1322, 908, 559},   /* version 29 */
     301              :         {2358, 1429, 982, 604},   /* version 30 */
     302              :         {2473, 1499, 1030, 634},  /* version 31 */
     303              :         {2670, 1618, 1112, 684},  /* version 32 */
     304              :         {2805, 1700, 1168, 719},  /* version 33 */
     305              :         {2949, 1787, 1228, 756},  /* version 34 */
     306              :         {3081, 1867, 1283, 790},  /* version 35 */
     307              :         {3244, 1966, 1351, 832},  /* version 36 */
     308              :         {3417, 2071, 1423, 876},  /* version 37 */
     309              :         {3599, 2181, 1499, 923},  /* version 38 */
     310              :         {3791, 2298, 1579, 972},  /* version 39 */
     311              :         {3993, 2420, 1663, 1024}, /* version 40 */
     312              :     },
     313              :     /* ECL H */
     314              :     {
     315              :         {-1, -1, -1, -1},        /* version 0 (invalid) */
     316              :         {17, 10, 7, 4},          /* version 1 */
     317              :         {34, 20, 14, 8},         /* version 2 */
     318              :         {58, 35, 24, 15},        /* version 3 */
     319              :         {82, 50, 34, 21},        /* version 4 */
     320              :         {106, 64, 44, 27},       /* version 5 */
     321              :         {139, 84, 58, 36},       /* version 6 */
     322              :         {154, 93, 64, 39},       /* version 7 */
     323              :         {202, 122, 84, 52},      /* version 8 */
     324              :         {235, 143, 98, 60},      /* version 9 */
     325              :         {288, 174, 119, 74},     /* version 10 */
     326              :         {331, 200, 137, 85},     /* version 11 */
     327              :         {374, 227, 155, 96},     /* version 12 */
     328              :         {427, 259, 177, 109},    /* version 13 */
     329              :         {468, 283, 194, 120},    /* version 14 */
     330              :         {530, 321, 220, 136},    /* version 15 */
     331              :         {602, 365, 250, 154},    /* version 16 */
     332              :         {674, 408, 280, 173},    /* version 17 */
     333              :         {746, 452, 310, 191},    /* version 18 */
     334              :         {813, 493, 338, 208},    /* version 19 */
     335              :         {919, 557, 382, 235},    /* version 20 */
     336              :         {969, 587, 403, 248},    /* version 21 */
     337              :         {1056, 640, 439, 270},   /* version 22 */
     338              :         {1108, 672, 461, 284},   /* version 23 */
     339              :         {1228, 744, 511, 315},   /* version 24 */
     340              :         {1286, 779, 535, 330},   /* version 25 */
     341              :         {1425, 864, 593, 365},   /* version 26 */
     342              :         {1501, 910, 625, 385},   /* version 27 */
     343              :         {1581, 958, 658, 405},   /* version 28 */
     344              :         {1677, 1016, 698, 430},  /* version 29 */
     345              :         {1782, 1080, 742, 457},  /* version 30 */
     346              :         {1897, 1150, 790, 486},  /* version 31 */
     347              :         {2022, 1226, 842, 518},  /* version 32 */
     348              :         {2157, 1307, 898, 553},  /* version 33 */
     349              :         {2301, 1394, 958, 590},  /* version 34 */
     350              :         {2361, 1431, 983, 605},  /* version 35 */
     351              :         {2524, 1530, 1051, 647}, /* version 36 */
     352              :         {2625, 1591, 1093, 673}, /* version 37 */
     353              :         {2735, 1658, 1139, 701}, /* version 38 */
     354              :         {2927, 1774, 1219, 750}, /* version 39 */
     355              :         {3057, 1852, 1273, 784}, /* version 40 */
     356              :     },
     357              : };
     358              : 
     359       106782 : static inline void append_bits(uint32_t val, uint8_t num_bits, uint8_t buffer[], int32_t *bit_len)
     360              : {
     361              :     int32_t i;
     362              : 
     363       950110 :     for (i = num_bits - 1; i >= 0; i--, (*bit_len)++) {
     364       843328 :         buffer[*bit_len >> 3] |= ((val >> i) & 1) << (7 - (*bit_len & 7));
     365              :     }
     366       106782 : }
     367              : 
     368         1450 : static inline int32_t get_num_raw_data_modules(uint8_t ver)
     369              : {
     370              :     int32_t result, num_align;
     371              : 
     372         1450 :     result = (16 * ver + 128) * ver + 64;
     373         1450 :     if (ver >= 2) {
     374         1238 :         num_align = ver / 7 + 2;
     375         1238 :         result -= (25 * num_align - 10) * num_align - 55;
     376         1238 :         if (ver >= 7) {
     377          284 :             result -= 36;
     378              :         }
     379              :     }
     380         1450 :     return result;
     381              : }
     382              : 
     383         5609 : static inline int32_t get_num_data_codewords(uint8_t version, uint8_t ecl)
     384              : {
     385         5609 :     if (ecl > 3 || version < 1 || version > 40) {
     386            0 :         return DATA_CODEWORDS[0][version < 1 ? 1 : (version > 40 ? 40 : version)];
     387              :     }
     388              : 
     389         5609 :     return DATA_CODEWORDS[ecl][version];
     390              : }
     391              : 
     392          725 : static inline bool add_ecc_and_interleave(uint8_t data[], uint8_t version, uint8_t ecl, uint8_t result[])
     393              : {
     394              :     const uint8_t *dat;
     395              :     poporon_t *pprn;
     396              :     poporon_config_t *config;
     397              :     uint8_t num_blocks, block_ecc_len, num_short_blocks, short_block_data_len, *ecc;
     398              :     int32_t raw_codewords, data_len, i, j, k, dat_len;
     399              : 
     400          725 :     num_blocks = NUM_ERROR_CORRECTION_BLOCKS[ecl][version];
     401          725 :     block_ecc_len = ECC_CODEWORDS_PER_BLOCK[ecl][version];
     402          725 :     raw_codewords = get_num_raw_data_modules(version) >> 3;
     403          725 :     data_len = get_num_data_codewords(version, ecl);
     404          725 :     num_short_blocks = num_blocks - raw_codewords % num_blocks;
     405          725 :     short_block_data_len = raw_codewords / num_blocks - block_ecc_len;
     406              : 
     407          725 :     config = poporon_rs_config_create(8, RS_GF256_PRIMITIVE_POLY, 0, 1, block_ecc_len, NULL, NULL);
     408          725 :     if (!config) {
     409            0 :         return false;
     410              :     }
     411              : 
     412          725 :     pprn = poporon_create(config);
     413          725 :     if (!pprn) {
     414            0 :         poporon_config_destroy(config);
     415            0 :         return false;
     416              :     }
     417              : 
     418          725 :     dat = data;
     419              : 
     420         3729 :     for (i = 0; i < num_blocks; i++) {
     421         3004 :         dat_len = short_block_data_len + (i < num_short_blocks ? 0 : 1);
     422         3004 :         ecc = &data[data_len];
     423              : 
     424         3004 :         poporon_encode(pprn, (uint8_t *)dat, (size_t)dat_len, ecc);
     425              : 
     426       108420 :         for (j = 0, k = i; j < dat_len; j++, k += num_blocks) {
     427       105416 :             if (j == short_block_data_len) {
     428         1073 :                 k -= num_short_blocks;
     429              :             }
     430       105416 :             result[k] = dat[j];
     431              :         }
     432              : 
     433        75804 :         for (j = 0, k = data_len + i; j < block_ecc_len; j++, k += num_blocks) {
     434        72800 :             result[k] = ecc[j];
     435              :         }
     436              : 
     437         3004 :         dat += dat_len;
     438              :     }
     439              : 
     440          725 :     poporon_destroy(pprn);
     441          725 :     poporon_config_destroy(config);
     442          725 :     return true;
     443              : }
     444              : 
     445         2175 : static inline uint8_t get_alignment_pattern_positions(uint8_t version, uint8_t result[7])
     446              : {
     447              :     uint8_t num_align, step, i, pos;
     448              : 
     449         2175 :     if (version == 1) {
     450          318 :         return 0;
     451              :     }
     452              : 
     453         1857 :     num_align = version / 7 + 2;
     454         1857 :     step = (version * 8 + num_align * 3 + 5) / (num_align * 4 - 4) * 2;
     455              : 
     456         4542 :     for (i = num_align - 1, pos = version * 4 + 10; i >= 1; i--, pos -= step) {
     457         2685 :         result[i] = pos;
     458              :     }
     459              : 
     460         1857 :     result[0] = 6;
     461              : 
     462         1857 :     return num_align;
     463              : }
     464              : 
     465        12864 : static inline void fill_rectangle(int32_t left, int32_t top, int32_t width, int32_t height, uint8_t qrcode[])
     466              : {
     467              :     int32_t dx, dy, qrsize, index, byte_idx, bit_idx;
     468              : 
     469        12864 :     qrsize = qrcode[0];
     470              : 
     471       137722 :     for (dy = 0; dy < height; dy++) {
     472       703326 :         for (dx = 0; dx < width; dx++) {
     473       578468 :             index = (top + dy) * qrsize + (left + dx);
     474       578468 :             byte_idx = (index >> 3) + 1;
     475       578468 :             bit_idx = index & 7;
     476       578468 :             qrcode[byte_idx] |= 1 << bit_idx;
     477              :         }
     478              :     }
     479        12864 : }
     480              : 
     481    132851923 : static inline bool get_module(const uint8_t qrcode[], int32_t x, int32_t y)
     482              : {
     483              :     int32_t qrsize, index;
     484              : 
     485    132851923 :     qrsize = qrcode[0];
     486    132851923 :     if (x < 0 || x >= qrsize || y < 0 || y >= qrsize) {
     487            0 :         return false;
     488              :     }
     489              : 
     490    132851923 :     index = y * qrsize + x;
     491              : 
     492    132851923 :     return ((qrcode[(index >> 3) + 1] >> (index & 7)) & 1) != 0;
     493              : }
     494              : 
     495     24129115 : static inline void set_module(uint8_t qrcode[], int32_t x, int32_t y, bool is_dark)
     496              : {
     497              :     int32_t qrsize, index, bit_idx, byte_idx;
     498              : 
     499     24129115 :     qrsize = qrcode[0];
     500     24129115 :     if (x < 0 || x >= qrsize || y < 0 || y >= qrsize) {
     501        36975 :         return;
     502              :     }
     503              : 
     504     24092140 :     index = y * qrsize + x;
     505     24092140 :     bit_idx = index & 7;
     506     24092140 :     byte_idx = (index >> 3) + 1;
     507              : 
     508     24092140 :     if (is_dark) {
     509     11672800 :         qrcode[byte_idx] |= 1 << bit_idx;
     510              :     } else {
     511     12419340 :         qrcode[byte_idx] &= (1 << bit_idx) ^ 0xFF;
     512              :     }
     513              : }
     514              : 
     515         1450 : static inline void initialize_function_modules(uint8_t version, uint8_t qrcode[])
     516              : {
     517              :     uint8_t qrsize, align_pat_pos[7], num_align, i, j;
     518              : 
     519         1450 :     qrsize = QR_VERSION_SIZE_FORMULA(version);
     520         1450 :     lmemset(qrcode, 0, (size_t)(((qrsize * qrsize + 7) >> 3) + 1) * sizeof(qrcode[0]));
     521         1450 :     qrcode[0] = qrsize;
     522              : 
     523         1450 :     fill_rectangle(TIMING_PATTERN_POSITION, 0, 1, qrsize, qrcode);
     524         1450 :     fill_rectangle(0, TIMING_PATTERN_POSITION, qrsize, 1, qrcode);
     525              : 
     526         1450 :     fill_rectangle(0, 0, FINDER_CORNER_SIZE, FINDER_CORNER_SIZE, qrcode);
     527         1450 :     fill_rectangle(qrsize - FINDER_QUIET_SIZE, 0, FINDER_QUIET_SIZE, FINDER_CORNER_SIZE, qrcode);
     528         1450 :     fill_rectangle(0, qrsize - FINDER_QUIET_SIZE, FINDER_CORNER_SIZE, FINDER_QUIET_SIZE, qrcode);
     529              : 
     530         1450 :     num_align = get_alignment_pattern_positions(version, align_pat_pos);
     531              : 
     532         4478 :     for (i = 0; i < num_align; i++) {
     533        11788 :         for (j = 0; j < num_align; j++) {
     534         8760 :             if (!((i == 0 && j == 0) || (i == 0 && j == num_align - 1) || (i == num_align - 1 && j == 0))) {
     535         5046 :                 fill_rectangle(align_pat_pos[i] - ALIGNMENT_PATTERN_OFFSET, align_pat_pos[j] - ALIGNMENT_PATTERN_OFFSET,
     536              :                                ALIGNMENT_PATTERN_SIZE, ALIGNMENT_PATTERN_SIZE, qrcode);
     537              :             }
     538              :         }
     539              :     }
     540              : 
     541         1450 :     if (version >= VERSION_INFO_MIN) {
     542          284 :         fill_rectangle(qrsize - VERSION_INFO_OFFSET, 0, VERSION_INFO_AREA_WIDTH, VERSION_INFO_AREA_HEIGHT, qrcode);
     543          284 :         fill_rectangle(0, qrsize - VERSION_INFO_OFFSET, VERSION_INFO_AREA_HEIGHT, VERSION_INFO_AREA_WIDTH, qrcode);
     544              :     }
     545         1450 : }
     546              : 
     547          725 : static inline void draw_light_function_modules(uint8_t qrcode[], uint8_t version)
     548              : {
     549              :     uint32_t bits;
     550              :     uint8_t align_pat_pos[7], num_align;
     551              :     int32_t qrsize, i, j, k, dx, dy, dist, rem;
     552              : 
     553          725 :     qrsize = qrcode[0];
     554        10493 :     for (i = TIMING_PATTERN_START; i < qrsize - TIMING_PATTERN_START; i += 2) {
     555         9768 :         set_module(qrcode, TIMING_PATTERN_POSITION, i, false);
     556         9768 :         set_module(qrcode, i, TIMING_PATTERN_POSITION, false);
     557              :     }
     558              : 
     559         7250 :     for (dy = -FINDER_PATTERN_RADIUS; dy <= FINDER_PATTERN_RADIUS; dy++) {
     560        65250 :         for (dx = -FINDER_PATTERN_RADIUS; dx <= FINDER_PATTERN_RADIUS; dx++) {
     561        58725 :             dist = (dx < 0) ? -dx : dx;
     562              : 
     563        58725 :             if ((dy < 0 ? -dy : dy) > dist) {
     564        23200 :                 dist = (dy < 0) ? -dy : dy;
     565              :             }
     566              : 
     567        58725 :             if (dist == ALIGNMENT_PATTERN_OFFSET || dist == FINDER_PATTERN_RADIUS) {
     568        34800 :                 set_module(qrcode, FINDER_PATTERN_CENTER + dx, FINDER_PATTERN_CENTER + dy, false);
     569        34800 :                 set_module(qrcode, qrsize - FINDER_PATTERN_RADIUS + dx, FINDER_PATTERN_CENTER + dy, false);
     570        34800 :                 set_module(qrcode, FINDER_PATTERN_CENTER + dx, qrsize - FINDER_PATTERN_RADIUS + dy, false);
     571              :             }
     572              :         }
     573              :     }
     574              : 
     575          725 :     num_align = get_alignment_pattern_positions(version, align_pat_pos);
     576         2239 :     for (i = 0; i < num_align; i++) {
     577         5894 :         for (j = 0; j < num_align; j++) {
     578         4380 :             if ((i == 0 && j == 0) || (i == 0 && j == num_align - 1) || (i == num_align - 1 && j == 0)) {
     579         1857 :                 continue;
     580              :             }
     581              : 
     582        10092 :             for (dy = -1; dy <= 1; dy++) {
     583        30276 :                 for (dx = -1; dx <= 1; dx++) {
     584        22707 :                     set_module(qrcode, align_pat_pos[i] + dx, align_pat_pos[j] + dy, dx == 0 && dy == 0);
     585              :                 }
     586              :             }
     587              :         }
     588              :     }
     589              : 
     590          725 :     if (version >= VERSION_INFO_MIN) {
     591          142 :         rem = version;
     592              : 
     593         1846 :         for (i = 0; i < VERSION_INFO_BITS; i++) {
     594         1704 :             rem = (rem << 1) ^ ((rem >> VERSION_INFO_SHIFT) * VERSION_INFO_POLY);
     595              :         }
     596              : 
     597          142 :         bits = (uint32_t)version << VERSION_INFO_DATA_SHIFT | (uint32_t)rem;
     598              : 
     599          994 :         for (i = 0; i < VERSION_INFO_AREA_HEIGHT; i++) {
     600         3408 :             for (j = 0; j < VERSION_INFO_AREA_WIDTH; j++) {
     601         2556 :                 k = qrsize - VERSION_INFO_OFFSET + j;
     602              : 
     603         2556 :                 set_module(qrcode, k, i, (bits & 1) != 0);
     604         2556 :                 set_module(qrcode, i, k, (bits & 1) != 0);
     605         2556 :                 bits >>= 1;
     606              :             }
     607              :         }
     608              :     }
     609          725 : }
     610              : 
     611         5053 : static inline void draw_format_bits(uint8_t ecl, int8_t mask, uint8_t qrcode[])
     612              : {
     613              :     static const int32_t table[] = {1, 0, 3, 2};
     614              :     int32_t data, rem, bits_val, qrsize, i;
     615              : 
     616         5053 :     data = table[ecl] << 3 | mask;
     617         5053 :     rem = data;
     618              : 
     619        55583 :     for (i = 0; i < FORMAT_DATA_SHIFT; i++) {
     620        50530 :         rem = (rem << 1) ^ ((rem >> FORMAT_POLY_SHIFT) * FORMAT_POLY);
     621              :     }
     622              : 
     623         5053 :     bits_val = (data << FORMAT_DATA_SHIFT | rem) ^ FORMAT_XOR_MASK;
     624              : 
     625        35371 :     for (i = 0; i <= 5; i++) {
     626        30318 :         set_module(qrcode, 8, i, ((bits_val >> i) & 1) != 0);
     627              :     }
     628              : 
     629         5053 :     set_module(qrcode, 8, 7, ((bits_val >> 6) & 1) != 0);
     630         5053 :     set_module(qrcode, 8, 8, ((bits_val >> 7) & 1) != 0);
     631         5053 :     set_module(qrcode, 7, 8, ((bits_val >> 8) & 1) != 0);
     632              : 
     633        35371 :     for (i = FORMAT_BITS_LOOP_START; i < FORMAT_BITS_COUNT; i++) {
     634        30318 :         set_module(qrcode, 14 - i, 8, ((bits_val >> i) & 1) != 0);
     635              :     }
     636              : 
     637         5053 :     qrsize = qrcode[0];
     638              : 
     639        45477 :     for (i = 0; i < FINDER_QUIET_SIZE; i++) {
     640        40424 :         set_module(qrcode, qrsize - 1 - i, 8, ((bits_val >> i) & 1) != 0);
     641              :     }
     642              : 
     643        40424 :     for (i = FINDER_QUIET_SIZE; i < FORMAT_BITS_COUNT; i++) {
     644        35371 :         set_module(qrcode, 8, qrsize - FORMAT_BITS_COUNT + i, ((bits_val >> i) & 1) != 0);
     645              :     }
     646              : 
     647         5053 :     set_module(qrcode, 8, qrsize - FINDER_QUIET_SIZE, true);
     648         5053 : }
     649              : 
     650          725 : static inline void draw_codewords(const uint8_t data[], int32_t data_len, uint8_t qrcode[])
     651              : {
     652              :     int32_t qrsize, bit_idx, right, vert, j, x, y;
     653              :     bool upward, dark;
     654              : 
     655          725 :     qrsize = qrcode[0];
     656          725 :     bit_idx = 0;
     657              : 
     658        14843 :     for (right = qrsize - 1; right >= 1; right -= 2) {
     659        14118 :         if (right == 6) {
     660          725 :             right = 5;
     661              :         }
     662              : 
     663       845156 :         for (vert = 0; vert < qrsize; vert++) {
     664      2493114 :             for (j = 0; j < 2; j++) {
     665      1662076 :                 x = right - j;
     666      1662076 :                 upward = ((right + 1) & 2) == 0;
     667      1662076 :                 y = upward ? qrsize - 1 - vert : vert;
     668              : 
     669      1662076 :                 if (!get_module(qrcode, x, y) && bit_idx < data_len * 8) {
     670      1425728 :                     dark = ((data[bit_idx >> 3] >> (7 - (bit_idx & 7))) & 1) != 0;
     671      1425728 :                     set_module(qrcode, x, y, dark);
     672      1425728 :                     bit_idx++;
     673              :                 }
     674              :             }
     675              :         }
     676              :     }
     677          725 : }
     678              : 
     679         9381 : static inline void apply_mask(const uint8_t function_modules[], uint8_t qrcode[], int8_t mask)
     680              : {
     681              :     int32_t qrsize, y, x;
     682              :     bool invert, val;
     683              : 
     684         9381 :     qrsize = qrcode[0];
     685              : 
     686       413782 :     for (y = 0; y < qrsize; y++) {
     687     26449822 :         for (x = 0; x < qrsize; x++) {
     688     26045421 :             if (get_module(function_modules, x, y)) {
     689      3650432 :                 continue;
     690              :             }
     691              : 
     692     22394989 :             switch (mask) {
     693      2903648 :             case 0:
     694      2903648 :                 invert = (x + y) % 2 == 0;
     695      2903648 :                 break;
     696      2659304 :             case 1:
     697      2659304 :                 invert = y % 2 == 0;
     698      2659304 :                 break;
     699      2965000 :             case 2:
     700      2965000 :                 invert = x % 3 == 0;
     701      2965000 :                 break;
     702      2925246 :             case 3:
     703      2925246 :                 invert = (x + y) % 3 == 0;
     704      2925246 :                 break;
     705      2828161 :             case 4:
     706      2828161 :                 invert = (x / 3 + y / 2) % 2 == 0;
     707      2828161 :                 break;
     708      2672945 :             case 5:
     709      2672945 :                 invert = x * y % 2 + x * y % 3 == 0;
     710      2672945 :                 break;
     711      2737328 :             case 6:
     712      2737328 :                 invert = (x * y % 2 + x * y % 3) % 2 == 0;
     713      2737328 :                 break;
     714      2703357 :             case 7:
     715      2703357 :                 invert = ((x + y) % 2 + x * y % 3) % 2 == 0;
     716      2703357 :                 break;
     717            0 :             default:
     718            0 :                 invert = false;
     719            0 :                 break;
     720              :             }
     721              : 
     722     22394989 :             val = get_module(qrcode, x, y);
     723     22394989 :             set_module(qrcode, x, y, val ^ invert);
     724              :         }
     725              :     }
     726         9381 : }
     727              : 
     728     12732054 : static inline int32_t finder_penalty_add_history(int32_t current_run_len, int32_t run_history[PENALTY_HISTORY_SIZE],
     729              :                                                  int32_t qrsize)
     730              : {
     731     12732054 :     if (run_history[0] == 0) {
     732       375440 :         current_run_len += qrsize;
     733              :     }
     734              : 
     735     12732054 :     lmemmove(&run_history[1], &run_history[0], PENALTY_HISTORY_MOVE_SIZE * sizeof(run_history[0]));
     736     12732054 :     run_history[0] = current_run_len;
     737              : 
     738     12732054 :     return current_run_len;
     739              : }
     740              : 
     741      6553747 : static inline int32_t finder_penalty_count_patterns(const int32_t run_history[PENALTY_HISTORY_SIZE], int32_t qrsize)
     742              : {
     743              :     int32_t n;
     744              :     bool core;
     745              : 
     746      6553747 :     n = run_history[1];
     747              :     (void)qrsize;
     748      6553747 :     core = n > 0 && run_history[2] == n && run_history[3] == n * 3 && run_history[4] == n && run_history[5] == n;
     749     13107494 :     return (core && run_history[0] >= n * 4 && run_history[6] >= n ? 1 : 0) +
     750      6553747 :            (core && run_history[6] >= n * 4 && run_history[0] >= n ? 1 : 0);
     751              : }
     752              : 
     753       375440 : static inline int32_t finder_penalty_terminate(bool current_run_color, int32_t current_run_len,
     754              :                                                int32_t run_history[PENALTY_HISTORY_SIZE], int32_t qrsize)
     755              : {
     756       375440 :     if (current_run_color) {
     757       210220 :         finder_penalty_add_history(current_run_len, run_history, qrsize);
     758       210220 :         current_run_len = 0;
     759              :     }
     760              : 
     761       375440 :     current_run_len += qrsize;
     762              : 
     763       375440 :     finder_penalty_add_history(current_run_len, run_history, qrsize);
     764              : 
     765       375440 :     return finder_penalty_count_patterns(run_history, qrsize);
     766              : }
     767              : 
     768         4328 : static inline int32_t get_penalty_score(const uint8_t qrcode[])
     769              : {
     770              :     int32_t qrsize, y, x, run_x, run_y, run_history[PENALTY_HISTORY_SIZE], dark, total, k, result;
     771              :     bool run_color, color;
     772              : 
     773         4328 :     qrsize = qrcode[0];
     774         4328 :     result = 0;
     775              : 
     776       192048 :     for (y = 0; y < qrsize; y++) {
     777       187720 :         run_color = false;
     778       187720 :         run_x = 0;
     779       187720 :         lmemset(run_history, 0, sizeof(run_history));
     780              : 
     781     12364912 :         for (x = 0; x < qrsize; x++) {
     782     12177192 :             if (get_module(qrcode, x, y) == run_color) {
     783      6101801 :                 run_x++;
     784      6101801 :                 if (run_x == PENALTY_RUN_THRESHOLD) {
     785       415024 :                     result += PENALTY_RUN_BASE;
     786      5686777 :                 } else if (run_x > PENALTY_RUN_THRESHOLD) {
     787       480823 :                     result++;
     788              :                 }
     789              :             } else {
     790      6075391 :                 finder_penalty_add_history(run_x, run_history, qrsize);
     791      6075391 :                 if (!run_color) {
     792      3088947 :                     result += finder_penalty_count_patterns(run_history, qrsize) * PENALTY_FINDER_LIKE;
     793              :                 }
     794      6075391 :                 run_color = get_module(qrcode, x, y);
     795      6075391 :                 run_x = 1;
     796              :             }
     797              :         }
     798       187720 :         result += finder_penalty_terminate(run_color, run_x, run_history, qrsize) * PENALTY_FINDER_LIKE;
     799              :     }
     800              : 
     801       192048 :     for (x = 0; x < qrsize; x++) {
     802       187720 :         run_color = false;
     803       187720 :         run_y = 0;
     804       187720 :         lmemset(run_history, 0, sizeof(run_history));
     805              : 
     806     12364912 :         for (y = 0; y < qrsize; y++) {
     807     12177192 :             if (get_module(qrcode, x, y) == run_color) {
     808      6106189 :                 run_y++;
     809      6106189 :                 if (run_y == PENALTY_RUN_THRESHOLD) {
     810       402837 :                     result += PENALTY_RUN_BASE;
     811      5703352 :                 } else if (run_y > PENALTY_RUN_THRESHOLD) {
     812       496823 :                     result++;
     813              :                 }
     814              :             } else {
     815      6071003 :                 finder_penalty_add_history(run_y, run_history, qrsize);
     816      6071003 :                 if (!run_color) {
     817      3089360 :                     result += finder_penalty_count_patterns(run_history, qrsize) * PENALTY_FINDER_LIKE;
     818              :                 }
     819      6071003 :                 run_color = get_module(qrcode, x, y);
     820      6071003 :                 run_y = 1;
     821              :             }
     822              :         }
     823              : 
     824       187720 :         result += finder_penalty_terminate(run_color, run_y, run_history, qrsize) * PENALTY_FINDER_LIKE;
     825              :     }
     826              : 
     827       187720 :     for (y = 0; y < qrsize - 1; y++) {
     828     11989472 :         for (x = 0; x < qrsize - 1; x++) {
     829     11806080 :             color = get_module(qrcode, x, y);
     830     14638917 :             if (color == get_module(qrcode, x + 1, y) && color == get_module(qrcode, x, y + 1) &&
     831      2832837 :                 color == get_module(qrcode, x + 1, y + 1)) {
     832      1402264 :                 result += PENALTY_2X2_BLOCK;
     833              :             }
     834              :         }
     835              :     }
     836              : 
     837         4328 :     dark = 0;
     838       192048 :     for (y = 0; y < qrsize; y++) {
     839     12364912 :         for (x = 0; x < qrsize; x++) {
     840     12177192 :             if (get_module(qrcode, x, y)) {
     841      6170136 :                 dark++;
     842              :             }
     843              :         }
     844              :     }
     845              : 
     846         4328 :     total = qrsize * qrsize;
     847              : 
     848         8656 :     k = ((dark * PENALTY_BALANCE_FACTOR_DARK - total * PENALTY_BALANCE_FACTOR_TOTAL) < 0
     849         1499 :              ? -(dark * PENALTY_BALANCE_FACTOR_DARK - total * PENALTY_BALANCE_FACTOR_TOTAL)
     850         4328 :              : (dark * PENALTY_BALANCE_FACTOR_DARK - total * PENALTY_BALANCE_FACTOR_TOTAL));
     851              : 
     852         4328 :     k = (k + total - 1) / total - 1;
     853              : 
     854         4328 :     result += k * PENALTY_BALANCE_MULTIPLIER;
     855              : 
     856         4328 :     return result;
     857              : }
     858              : 
     859              : static inline bool is_numeric_data(const uint8_t *data, size_t data_len)
     860              : {
     861              :     size_t i;
     862              : 
     863              :     for (i = 0; i < data_len; i++) {
     864              :         if (data[i] < '0' || data[i] > '9') {
     865              :             return false;
     866              :         }
     867              :     }
     868              : 
     869              :     return true;
     870              : }
     871              : 
     872            3 : static inline int32_t numeric_count_bits(uint8_t version, size_t char_count)
     873              : {
     874              :     int32_t count_bits;
     875              : 
     876            3 :     if (version < VERSION_THRESHOLD_SMALL) {
     877            3 :         count_bits = NUMERIC_BITS_SMALL;
     878            0 :     } else if (version < VERSION_THRESHOLD_MEDIUM) {
     879            0 :         count_bits = NUMERIC_BITS_MEDIUM;
     880              :     } else {
     881            0 :         count_bits = NUMERIC_BITS_LARGE;
     882              :     }
     883              : 
     884            3 :     return QR_MODE_INDICATOR_BITS + count_bits + ((int32_t)char_count / NUMERIC_GROUP_SIZE) * NUMERIC_GROUP_BITS +
     885            3 :            ((char_count % NUMERIC_GROUP_SIZE == 1)
     886              :                 ? NUMERIC_REMAINDER1_BITS
     887            3 :                 : ((char_count % NUMERIC_GROUP_SIZE == 2) ? NUMERIC_REMAINDER2_BITS : 0));
     888              : }
     889              : 
     890            2 : static inline bool encode_numeric(const uint8_t *data, size_t data_len, uint8_t temp_buffer[], uint8_t qrcode[],
     891              :                                   uint8_t ecl, int8_t min_version, int8_t max_version, int8_t mask)
     892              : {
     893              :     uint8_t pad_byte, version, best_mask;
     894              :     int32_t data_capacity_bits, data_used_bits, bit_len, terminator_bits, i, min_penalty, penalty, count_bits, value;
     895              :     size_t idx;
     896              : 
     897            2 :     for (version = min_version;; version++) {
     898            3 :         data_capacity_bits = get_num_data_codewords(version, ecl) * 8;
     899            3 :         data_used_bits = numeric_count_bits(version, data_len);
     900              : 
     901            3 :         if (data_used_bits <= data_capacity_bits) {
     902            2 :             break;
     903              :         }
     904              : 
     905            1 :         if (version >= max_version) {
     906            0 :             qrcode[0] = 0;
     907            0 :             return false;
     908              :         }
     909              :     }
     910              : 
     911            2 :     if (version < VERSION_THRESHOLD_SMALL) {
     912            2 :         count_bits = NUMERIC_BITS_SMALL;
     913            0 :     } else if (version < VERSION_THRESHOLD_MEDIUM) {
     914            0 :         count_bits = NUMERIC_BITS_MEDIUM;
     915              :     } else {
     916            0 :         count_bits = NUMERIC_BITS_LARGE;
     917              :     }
     918              : 
     919            2 :     lmemset(qrcode, 0, (size_t)QR_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0]));
     920            2 :     bit_len = 0;
     921            2 :     append_bits(QR_MODE_NUMERIC_INDICATOR, QR_MODE_INDICATOR_BITS, qrcode, &bit_len);
     922            2 :     append_bits((uint32_t)data_len, count_bits, qrcode, &bit_len);
     923              : 
     924            2 :     idx = 0;
     925           21 :     while (idx + NUMERIC_GROUP_SIZE <= data_len) {
     926           19 :         value = (data[idx] - '0') * 100 + (data[idx + 1] - '0') * 10 + (data[idx + 2] - '0');
     927           19 :         append_bits((uint32_t)value, NUMERIC_GROUP_BITS, qrcode, &bit_len);
     928           19 :         idx += NUMERIC_GROUP_SIZE;
     929              :     }
     930              : 
     931            2 :     if (data_len - idx == 2) {
     932            1 :         value = (data[idx] - '0') * 10 + (data[idx + 1] - '0');
     933            1 :         append_bits((uint32_t)value, NUMERIC_REMAINDER2_BITS, qrcode, &bit_len);
     934            1 :     } else if (data_len - idx == 1) {
     935            1 :         value = data[idx] - '0';
     936            1 :         append_bits((uint32_t)value, NUMERIC_REMAINDER1_BITS, qrcode, &bit_len);
     937              :     }
     938              : 
     939            2 :     data_capacity_bits = get_num_data_codewords(version, ecl) * QR_PAD_BYTE_BITS;
     940            2 :     terminator_bits = data_capacity_bits - bit_len;
     941              : 
     942            2 :     if (terminator_bits > QR_TERMINATOR_MAX_BITS) {
     943            2 :         terminator_bits = QR_TERMINATOR_MAX_BITS;
     944              :     }
     945              : 
     946            2 :     append_bits(0, terminator_bits, qrcode, &bit_len);
     947            2 :     append_bits(0, (QR_PAD_BYTE_BITS - bit_len % QR_PAD_BYTE_BITS) % QR_PAD_BYTE_BITS, qrcode, &bit_len);
     948              : 
     949           21 :     for (pad_byte = PAD_BYTE_FIRST; bit_len < data_capacity_bits; pad_byte ^= PAD_BYTE_FIRST ^ PAD_BYTE_SECOND) {
     950           19 :         append_bits(pad_byte, QR_PAD_BYTE_BITS, qrcode, &bit_len);
     951              :     }
     952              : 
     953            2 :     if (!add_ecc_and_interleave(qrcode, version, ecl, temp_buffer)) {
     954            0 :         return false;
     955              :     }
     956            2 :     initialize_function_modules(version, qrcode);
     957            2 :     draw_codewords(temp_buffer, get_num_raw_data_modules(version) >> 3, qrcode);
     958            2 :     draw_light_function_modules(qrcode, version);
     959            2 :     initialize_function_modules(version, temp_buffer);
     960              : 
     961            2 :     if (mask < 0) {
     962            2 :         min_penalty = INT32_MAX;
     963            2 :         best_mask = 0;
     964              : 
     965           18 :         for (i = 0; i < QR_MASK_COUNT; i++) {
     966           16 :             apply_mask(temp_buffer, qrcode, (int8_t)i);
     967           16 :             draw_format_bits(ecl, (int8_t)i, qrcode);
     968           16 :             penalty = get_penalty_score(qrcode);
     969              : 
     970           16 :             if (penalty < min_penalty) {
     971            2 :                 best_mask = (int8_t)i;
     972            2 :                 min_penalty = penalty;
     973              :             }
     974              : 
     975           16 :             apply_mask(temp_buffer, qrcode, (int8_t)i);
     976              :         }
     977            2 :         mask = best_mask;
     978              :     }
     979              : 
     980            2 :     apply_mask(temp_buffer, qrcode, mask);
     981            2 :     draw_format_bits(ecl, mask, qrcode);
     982              : 
     983            2 :     return true;
     984              : }
     985              : 
     986           26 : static inline int8_t alphanumeric_char_value(uint8_t c)
     987              : {
     988           26 :     if (c >= '0' && c <= '9') {
     989            3 :         return (int8_t)(c - '0');
     990              :     }
     991              : 
     992           23 :     if (c >= 'A' && c <= 'Z') {
     993           13 :         return (int8_t)(c - 'A' + ALPHA_LETTER_OFFSET);
     994              :     }
     995              : 
     996           10 :     switch (c) {
     997            2 :     case ' ':
     998            2 :         return ALPHA_SPACE_VALUE;
     999            1 :     case '$':
    1000            1 :         return ALPHA_DOLLAR_VALUE;
    1001            1 :     case '%':
    1002            1 :         return ALPHA_PERCENT_VALUE;
    1003            1 :     case '*':
    1004            1 :         return ALPHA_ASTERISK_VALUE;
    1005            1 :     case '+':
    1006            1 :         return ALPHA_PLUS_VALUE;
    1007            1 :     case '-':
    1008            1 :         return ALPHA_MINUS_VALUE;
    1009            1 :     case '.':
    1010            1 :         return ALPHA_DOT_VALUE;
    1011            1 :     case '/':
    1012            1 :         return ALPHA_SLASH_VALUE;
    1013            1 :     case ':':
    1014            1 :         return ALPHA_COLON_VALUE;
    1015            0 :     default:
    1016            0 :         return -1;
    1017              :     }
    1018              : }
    1019              : 
    1020              : static inline bool is_alphanumeric_data(const uint8_t *data, size_t data_len)
    1021              : {
    1022              :     size_t i;
    1023              : 
    1024              :     for (i = 0; i < data_len; i++) {
    1025              :         if (alphanumeric_char_value(data[i]) < 0) {
    1026              :             return false;
    1027              :         }
    1028              :     }
    1029              : 
    1030              :     return true;
    1031              : }
    1032              : 
    1033            2 : static inline int32_t alphanumeric_count_bits(uint8_t version, size_t char_count)
    1034              : {
    1035              :     int32_t count_bits;
    1036              : 
    1037            2 :     if (version < VERSION_THRESHOLD_SMALL) {
    1038            2 :         count_bits = ALPHA_BITS_SMALL;
    1039            0 :     } else if (version < VERSION_THRESHOLD_MEDIUM) {
    1040            0 :         count_bits = ALPHA_BITS_MEDIUM;
    1041              :     } else {
    1042            0 :         count_bits = ALPHA_BITS_LARGE;
    1043              :     }
    1044              : 
    1045            2 :     return QR_MODE_INDICATOR_BITS + count_bits +
    1046            2 :            ((int32_t)char_count / ALPHANUMERIC_GROUP_SIZE) * ALPHANUMERIC_GROUP_BITS +
    1047            2 :            ((char_count % ALPHANUMERIC_GROUP_SIZE) ? ALPHANUMERIC_REMAINDER_BITS : 0);
    1048              : }
    1049              : 
    1050            2 : static inline bool encode_alphanumeric(const uint8_t *data, size_t data_len, uint8_t temp_buffer[], uint8_t qrcode[],
    1051              :                                        uint8_t ecl, int8_t min_version, int8_t max_version, int8_t mask)
    1052              : {
    1053              :     uint8_t pad_byte, version, best_mask;
    1054              :     int32_t data_capacity_bits, data_used_bits, bit_len, terminator_bits, i, min_penalty, penalty, count_bits, value;
    1055              :     size_t idx;
    1056              : 
    1057            2 :     for (version = min_version;; version++) {
    1058            2 :         data_capacity_bits = get_num_data_codewords(version, ecl) * 8;
    1059            2 :         data_used_bits = alphanumeric_count_bits(version, data_len);
    1060              : 
    1061            2 :         if (data_used_bits <= data_capacity_bits) {
    1062            2 :             break;
    1063              :         }
    1064              : 
    1065            0 :         if (version >= max_version) {
    1066            0 :             qrcode[0] = 0;
    1067            0 :             return false;
    1068              :         }
    1069              :     }
    1070              : 
    1071            2 :     if (version < VERSION_THRESHOLD_SMALL) {
    1072            2 :         count_bits = ALPHA_BITS_SMALL;
    1073            0 :     } else if (version < VERSION_THRESHOLD_MEDIUM) {
    1074            0 :         count_bits = ALPHA_BITS_MEDIUM;
    1075              :     } else {
    1076            0 :         count_bits = ALPHA_BITS_LARGE;
    1077              :     }
    1078              : 
    1079            2 :     lmemset(qrcode, 0, (size_t)QR_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0]));
    1080            2 :     bit_len = 0;
    1081            2 :     append_bits(QR_MODE_ALPHANUMERIC_INDICATOR, QR_MODE_INDICATOR_BITS, qrcode, &bit_len);
    1082            2 :     append_bits((uint32_t)data_len, count_bits, qrcode, &bit_len);
    1083              : 
    1084            2 :     idx = 0;
    1085           14 :     while (idx + ALPHANUMERIC_GROUP_SIZE <= data_len) {
    1086           12 :         value = alphanumeric_char_value(data[idx]) * ALPHANUMERIC_CHARSET_SIZE + alphanumeric_char_value(data[idx + 1]);
    1087           12 :         append_bits((uint32_t)value, ALPHANUMERIC_GROUP_BITS, qrcode, &bit_len);
    1088           12 :         idx += ALPHANUMERIC_GROUP_SIZE;
    1089              :     }
    1090              : 
    1091            2 :     if (data_len - idx == 1) {
    1092            2 :         value = alphanumeric_char_value(data[idx]);
    1093            2 :         append_bits((uint32_t)value, ALPHANUMERIC_REMAINDER_BITS, qrcode, &bit_len);
    1094              :     }
    1095              : 
    1096            2 :     data_capacity_bits = get_num_data_codewords(version, ecl) * QR_PAD_BYTE_BITS;
    1097            2 :     terminator_bits = data_capacity_bits - bit_len;
    1098              : 
    1099            2 :     if (terminator_bits > QR_TERMINATOR_MAX_BITS) {
    1100            2 :         terminator_bits = QR_TERMINATOR_MAX_BITS;
    1101              :     }
    1102              : 
    1103            2 :     append_bits(0, terminator_bits, qrcode, &bit_len);
    1104            2 :     append_bits(0, (QR_PAD_BYTE_BITS - bit_len % QR_PAD_BYTE_BITS) % QR_PAD_BYTE_BITS, qrcode, &bit_len);
    1105              : 
    1106           14 :     for (pad_byte = PAD_BYTE_FIRST; bit_len < data_capacity_bits; pad_byte ^= PAD_BYTE_FIRST ^ PAD_BYTE_SECOND) {
    1107           12 :         append_bits(pad_byte, QR_PAD_BYTE_BITS, qrcode, &bit_len);
    1108              :     }
    1109              : 
    1110            2 :     if (!add_ecc_and_interleave(qrcode, version, ecl, temp_buffer)) {
    1111            0 :         return false;
    1112              :     }
    1113              : 
    1114            2 :     initialize_function_modules(version, qrcode);
    1115            2 :     draw_codewords(temp_buffer, get_num_raw_data_modules(version) >> 3, qrcode);
    1116            2 :     draw_light_function_modules(qrcode, version);
    1117            2 :     initialize_function_modules(version, temp_buffer);
    1118              : 
    1119            2 :     if (mask < 0) {
    1120            2 :         min_penalty = INT32_MAX;
    1121            2 :         best_mask = 0;
    1122              : 
    1123           18 :         for (i = 0; i < QR_MASK_COUNT; i++) {
    1124           16 :             apply_mask(temp_buffer, qrcode, (int8_t)i);
    1125           16 :             draw_format_bits(ecl, (int8_t)i, qrcode);
    1126           16 :             penalty = get_penalty_score(qrcode);
    1127              : 
    1128           16 :             if (penalty < min_penalty) {
    1129            3 :                 best_mask = (int8_t)i;
    1130            3 :                 min_penalty = penalty;
    1131              :             }
    1132              : 
    1133           16 :             apply_mask(temp_buffer, qrcode, (int8_t)i);
    1134              :         }
    1135            2 :         mask = best_mask;
    1136              :     }
    1137              : 
    1138            2 :     apply_mask(temp_buffer, qrcode, mask);
    1139            2 :     draw_format_bits(ecl, mask, qrcode);
    1140              : 
    1141            2 :     return true;
    1142              : }
    1143              : 
    1144              : static inline bool is_kanji_byte_pair(uint8_t high, uint8_t low)
    1145              : {
    1146              :     uint16_t code;
    1147              : 
    1148              :     code = ((uint16_t)high << 8) | low;
    1149              : 
    1150              :     return (code >= KANJI_SJIS_RANGE1_START && code <= KANJI_SJIS_RANGE1_END) ||
    1151              :            (code >= KANJI_SJIS_RANGE2_START && code <= KANJI_SJIS_RANGE2_END);
    1152              : }
    1153              : 
    1154              : static inline bool is_kanji_data(const uint8_t *data, size_t data_len)
    1155              : {
    1156              :     size_t i;
    1157              : 
    1158              :     if (data_len == 0 || data_len % 2 != 0) {
    1159              :         return false;
    1160              :     }
    1161              : 
    1162              :     for (i = 0; i < data_len; i += 2) {
    1163              :         if (!is_kanji_byte_pair(data[i], data[i + 1])) {
    1164              :             return false;
    1165              :         }
    1166              :     }
    1167              : 
    1168              :     return true;
    1169              : }
    1170              : 
    1171            2 : static inline int32_t kanji_count_bits(uint8_t version, size_t char_count)
    1172              : {
    1173              :     int32_t count_bits;
    1174              : 
    1175            2 :     if (version < VERSION_THRESHOLD_SMALL) {
    1176            2 :         count_bits = KANJI_BITS_SMALL;
    1177            0 :     } else if (version < VERSION_THRESHOLD_MEDIUM) {
    1178            0 :         count_bits = KANJI_BITS_MEDIUM;
    1179              :     } else {
    1180            0 :         count_bits = KANJI_BITS_LARGE;
    1181              :     }
    1182              : 
    1183            2 :     return QR_MODE_INDICATOR_BITS + count_bits + (int32_t)char_count * KANJI_ENCODED_BITS;
    1184              : }
    1185              : 
    1186            2 : static inline bool encode_kanji(const uint8_t *data, size_t data_len, uint8_t temp_buffer[], uint8_t qrcode[],
    1187              :                                 uint8_t ecl, int8_t min_version, int8_t max_version, int8_t mask)
    1188              : {
    1189              :     uint16_t sjis_char;
    1190              :     uint8_t pad_byte, version, best_mask;
    1191              :     int32_t data_capacity_bits, data_used_bits, bit_len, terminator_bits, i, min_penalty, penalty, count_bits,
    1192              :         high_byte, low_byte, intermediate, encoded_value;
    1193              :     size_t idx, char_count;
    1194              : 
    1195            2 :     char_count = data_len / 2;
    1196              : 
    1197            2 :     for (version = min_version;; version++) {
    1198            2 :         data_capacity_bits = get_num_data_codewords(version, ecl) * 8;
    1199            2 :         data_used_bits = kanji_count_bits(version, char_count);
    1200              : 
    1201            2 :         if (data_used_bits <= data_capacity_bits) {
    1202            2 :             break;
    1203              :         }
    1204              : 
    1205            0 :         if (version >= max_version) {
    1206            0 :             qrcode[0] = 0;
    1207            0 :             return false;
    1208              :         }
    1209              :     }
    1210              : 
    1211            2 :     if (version < VERSION_THRESHOLD_SMALL) {
    1212            2 :         count_bits = KANJI_BITS_SMALL;
    1213            0 :     } else if (version < VERSION_THRESHOLD_MEDIUM) {
    1214            0 :         count_bits = KANJI_BITS_MEDIUM;
    1215              :     } else {
    1216            0 :         count_bits = KANJI_BITS_LARGE;
    1217              :     }
    1218              : 
    1219            2 :     lmemset(qrcode, 0, (size_t)QR_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0]));
    1220            2 :     bit_len = 0;
    1221            2 :     append_bits(QR_MODE_KANJI_INDICATOR, QR_MODE_INDICATOR_BITS, qrcode, &bit_len);
    1222            2 :     append_bits((uint32_t)char_count, count_bits, qrcode, &bit_len);
    1223              : 
    1224            7 :     for (idx = 0; idx < data_len; idx += 2) {
    1225            5 :         sjis_char = ((uint16_t)data[idx] << 8) | data[idx + 1];
    1226              : 
    1227            5 :         if (sjis_char >= KANJI_SJIS_RANGE1_START && sjis_char <= KANJI_SJIS_RANGE1_END) {
    1228            5 :             intermediate = sjis_char - KANJI_ENCODE_BASE1;
    1229              :         } else {
    1230            0 :             intermediate = sjis_char - KANJI_ENCODE_BASE2;
    1231              :         }
    1232              : 
    1233            5 :         high_byte = (intermediate >> 8) & 0xFF;
    1234            5 :         low_byte = intermediate & 0xFF;
    1235            5 :         encoded_value = high_byte * KANJI_ENCODE_MULTIPLIER + low_byte;
    1236              : 
    1237            5 :         append_bits((uint32_t)encoded_value, KANJI_ENCODED_BITS, qrcode, &bit_len);
    1238              :     }
    1239              : 
    1240            2 :     data_capacity_bits = get_num_data_codewords(version, ecl) * QR_PAD_BYTE_BITS;
    1241            2 :     terminator_bits = data_capacity_bits - bit_len;
    1242              : 
    1243            2 :     if (terminator_bits > QR_TERMINATOR_MAX_BITS) {
    1244            2 :         terminator_bits = QR_TERMINATOR_MAX_BITS;
    1245              :     }
    1246              : 
    1247            2 :     append_bits(0, terminator_bits, qrcode, &bit_len);
    1248            2 :     append_bits(0, (QR_PAD_BYTE_BITS - bit_len % QR_PAD_BYTE_BITS) % QR_PAD_BYTE_BITS, qrcode, &bit_len);
    1249              : 
    1250           24 :     for (pad_byte = PAD_BYTE_FIRST; bit_len < data_capacity_bits; pad_byte ^= PAD_BYTE_FIRST ^ PAD_BYTE_SECOND) {
    1251           22 :         append_bits(pad_byte, QR_PAD_BYTE_BITS, qrcode, &bit_len);
    1252              :     }
    1253              : 
    1254            2 :     if (!add_ecc_and_interleave(qrcode, version, ecl, temp_buffer)) {
    1255            0 :         return false;
    1256              :     }
    1257            2 :     initialize_function_modules(version, qrcode);
    1258            2 :     draw_codewords(temp_buffer, get_num_raw_data_modules(version) >> 3, qrcode);
    1259            2 :     draw_light_function_modules(qrcode, version);
    1260            2 :     initialize_function_modules(version, temp_buffer);
    1261              : 
    1262            2 :     if (mask < 0) {
    1263            2 :         min_penalty = INT32_MAX;
    1264            2 :         best_mask = 0;
    1265              : 
    1266           18 :         for (i = 0; i < QR_MASK_COUNT; i++) {
    1267           16 :             apply_mask(temp_buffer, qrcode, (int8_t)i);
    1268           16 :             draw_format_bits(ecl, (int8_t)i, qrcode);
    1269           16 :             penalty = get_penalty_score(qrcode);
    1270              : 
    1271           16 :             if (penalty < min_penalty) {
    1272            3 :                 best_mask = (int8_t)i;
    1273            3 :                 min_penalty = penalty;
    1274              :             }
    1275              : 
    1276           16 :             apply_mask(temp_buffer, qrcode, (int8_t)i);
    1277              :         }
    1278            2 :         mask = best_mask;
    1279              :     }
    1280              : 
    1281            2 :     apply_mask(temp_buffer, qrcode, mask);
    1282            2 :     draw_format_bits(ecl, mask, qrcode);
    1283              : 
    1284            2 :     return true;
    1285              : }
    1286              : 
    1287            1 : static inline int32_t eci_header_bits(uint32_t eci_value)
    1288              : {
    1289            1 :     if (eci_value <= ECI_SINGLE_BYTE_MAX) {
    1290            1 :         return QR_MODE_INDICATOR_BITS + QR_PAD_BYTE_BITS;
    1291            0 :     } else if (eci_value <= ECI_DOUBLE_BYTE_MAX) {
    1292            0 :         return QR_MODE_INDICATOR_BITS + BYTE_BITS_LARGE;
    1293              :     } else {
    1294            0 :         return QR_MODE_INDICATOR_BITS + ECI_BITS_3BYTE;
    1295              :     }
    1296              : }
    1297              : 
    1298            1 : static inline bool encode_eci(const uint8_t *data, size_t data_len, uint8_t temp_buffer[], uint8_t qrcode[],
    1299              :                               uint8_t ecl, int8_t min_version, int8_t max_version, int8_t mask, uint32_t eci_value)
    1300              : {
    1301              :     uint8_t pad_byte, version, best_mask;
    1302              :     int32_t data_capacity_bits, data_used_bits, bit_len, terminator_bits, i, min_penalty, penalty, ehb;
    1303              : 
    1304            1 :     ehb = eci_header_bits(eci_value);
    1305              : 
    1306            1 :     for (version = min_version;; version++) {
    1307            1 :         data_capacity_bits = get_num_data_codewords(version, ecl) * QR_PAD_BYTE_BITS;
    1308            2 :         data_used_bits = ehb + QR_MODE_INDICATOR_BITS +
    1309            1 :                          ((version < VERSION_THRESHOLD_SMALL) ? BYTE_BITS_SMALL : BYTE_BITS_LARGE) +
    1310            1 :                          (int32_t)data_len * QR_PAD_BYTE_BITS;
    1311              : 
    1312            1 :         if (data_used_bits <= data_capacity_bits) {
    1313            1 :             break;
    1314              :         }
    1315              : 
    1316            0 :         if (version >= max_version) {
    1317            0 :             qrcode[0] = 0;
    1318            0 :             return false;
    1319              :         }
    1320              :     }
    1321              : 
    1322            1 :     lmemset(qrcode, 0, (size_t)QR_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0]));
    1323            1 :     bit_len = 0;
    1324              : 
    1325            1 :     append_bits(QR_MODE_ECI_INDICATOR, QR_MODE_INDICATOR_BITS, qrcode, &bit_len);
    1326              : 
    1327            1 :     if (eci_value <= ECI_SINGLE_BYTE_MAX) {
    1328            1 :         append_bits(eci_value, QR_PAD_BYTE_BITS, qrcode, &bit_len);
    1329            0 :     } else if (eci_value <= ECI_DOUBLE_BYTE_MAX) {
    1330            0 :         append_bits(ECI_PREFIX_2BYTE | ((eci_value >> 8) & ECI_MASK_2BYTE), QR_PAD_BYTE_BITS, qrcode, &bit_len);
    1331            0 :         append_bits(eci_value & 0xFF, QR_PAD_BYTE_BITS, qrcode, &bit_len);
    1332              :     } else {
    1333            0 :         append_bits(ECI_PREFIX_3BYTE | ((eci_value >> 16) & ECI_MASK_3BYTE), QR_PAD_BYTE_BITS, qrcode, &bit_len);
    1334            0 :         append_bits((eci_value >> 8) & 0xFF, QR_PAD_BYTE_BITS, qrcode, &bit_len);
    1335            0 :         append_bits(eci_value & 0xFF, QR_PAD_BYTE_BITS, qrcode, &bit_len);
    1336              :     }
    1337              : 
    1338            1 :     append_bits(QR_MODE_BYTE_INDICATOR, QR_MODE_INDICATOR_BITS, qrcode, &bit_len);
    1339            1 :     append_bits((uint32_t)data_len, (version < VERSION_THRESHOLD_SMALL) ? BYTE_BITS_SMALL : BYTE_BITS_LARGE, qrcode,
    1340              :                 &bit_len);
    1341              : 
    1342           13 :     for (i = 0; i < (int32_t)data_len; i++) {
    1343           12 :         append_bits(data[i], QR_PAD_BYTE_BITS, qrcode, &bit_len);
    1344              :     }
    1345              : 
    1346            1 :     data_capacity_bits = get_num_data_codewords(version, ecl) * QR_PAD_BYTE_BITS;
    1347            1 :     terminator_bits = data_capacity_bits - bit_len;
    1348              : 
    1349            1 :     if (terminator_bits > QR_TERMINATOR_MAX_BITS) {
    1350            1 :         terminator_bits = QR_TERMINATOR_MAX_BITS;
    1351              :     }
    1352              : 
    1353            1 :     append_bits(0, terminator_bits, qrcode, &bit_len);
    1354            1 :     append_bits(0, (QR_PAD_BYTE_BITS - bit_len % QR_PAD_BYTE_BITS) % QR_PAD_BYTE_BITS, qrcode, &bit_len);
    1355              : 
    1356            4 :     for (pad_byte = PAD_BYTE_FIRST; bit_len < data_capacity_bits; pad_byte ^= PAD_BYTE_FIRST ^ PAD_BYTE_SECOND) {
    1357            3 :         append_bits(pad_byte, QR_PAD_BYTE_BITS, qrcode, &bit_len);
    1358              :     }
    1359              : 
    1360            1 :     if (!add_ecc_and_interleave(qrcode, version, ecl, temp_buffer)) {
    1361            0 :         return false;
    1362              :     }
    1363            1 :     initialize_function_modules(version, qrcode);
    1364            1 :     draw_codewords(temp_buffer, get_num_raw_data_modules(version) >> 3, qrcode);
    1365            1 :     draw_light_function_modules(qrcode, version);
    1366            1 :     initialize_function_modules(version, temp_buffer);
    1367              : 
    1368            1 :     if (mask < 0) {
    1369            1 :         min_penalty = INT32_MAX;
    1370            1 :         best_mask = 0;
    1371              : 
    1372            9 :         for (i = 0; i < QR_MASK_COUNT; i++) {
    1373            8 :             apply_mask(temp_buffer, qrcode, (int8_t)i);
    1374            8 :             draw_format_bits(ecl, (int8_t)i, qrcode);
    1375            8 :             penalty = get_penalty_score(qrcode);
    1376              : 
    1377            8 :             if (penalty < min_penalty) {
    1378            4 :                 best_mask = (int8_t)i;
    1379            4 :                 min_penalty = penalty;
    1380              :             }
    1381              : 
    1382            8 :             apply_mask(temp_buffer, qrcode, (int8_t)i);
    1383              :         }
    1384            1 :         mask = best_mask;
    1385              :     }
    1386              : 
    1387            1 :     apply_mask(temp_buffer, qrcode, mask);
    1388            1 :     draw_format_bits(ecl, mask, qrcode);
    1389              : 
    1390            1 :     return true;
    1391              : }
    1392              : 
    1393          718 : static inline bool encode_binary(const uint8_t *data, size_t data_len, uint8_t temp_buffer[], uint8_t qrcode[],
    1394              :                                  uint8_t ecl, int8_t min_version, int8_t max_version, int8_t mask)
    1395              : {
    1396              :     uint8_t pad_byte, version, best_mask;
    1397              :     int32_t data_capacity_bits, data_used_bits, bit_len, terminator_bits, i, min_penalty, penalty;
    1398              : 
    1399          718 :     for (version = min_version;; version++) {
    1400         4151 :         data_capacity_bits = get_num_data_codewords(version, ecl) * QR_PAD_BYTE_BITS;
    1401         4151 :         data_used_bits = QR_MODE_INDICATOR_BITS +
    1402              :                          ((version < VERSION_THRESHOLD_SMALL) ? BYTE_BITS_SMALL : BYTE_BITS_LARGE) +
    1403         4151 :                          (int32_t)data_len * QR_PAD_BYTE_BITS;
    1404              : 
    1405         4151 :         if (data_used_bits <= data_capacity_bits) {
    1406          718 :             break;
    1407              :         }
    1408              : 
    1409         3433 :         if (version >= max_version) {
    1410            0 :             qrcode[0] = 0;
    1411            0 :             return false;
    1412              :         }
    1413              :     }
    1414              : 
    1415          718 :     lmemset(qrcode, 0, (size_t)QR_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0]));
    1416          718 :     bit_len = 0;
    1417          718 :     append_bits(QR_MODE_BYTE_INDICATOR, QR_MODE_INDICATOR_BITS, qrcode, &bit_len);
    1418          718 :     append_bits((uint32_t)data_len, (version < VERSION_THRESHOLD_SMALL) ? BYTE_BITS_SMALL : BYTE_BITS_LARGE, qrcode,
    1419              :                 &bit_len);
    1420              : 
    1421        94619 :     for (i = 0; i < (int32_t)data_len; i++) {
    1422        93901 :         append_bits(data[i], QR_PAD_BYTE_BITS, qrcode, &bit_len);
    1423              :     }
    1424              : 
    1425          718 :     data_capacity_bits = get_num_data_codewords(version, ecl) * QR_PAD_BYTE_BITS;
    1426          718 :     terminator_bits = data_capacity_bits - bit_len;
    1427              : 
    1428          718 :     if (terminator_bits > QR_TERMINATOR_MAX_BITS) {
    1429          686 :         terminator_bits = QR_TERMINATOR_MAX_BITS;
    1430              :     }
    1431              : 
    1432          718 :     append_bits(0, terminator_bits, qrcode, &bit_len);
    1433          718 :     append_bits(0, (QR_PAD_BYTE_BITS - bit_len % QR_PAD_BYTE_BITS) % QR_PAD_BYTE_BITS, qrcode, &bit_len);
    1434              : 
    1435        10589 :     for (pad_byte = PAD_BYTE_FIRST; bit_len < data_capacity_bits; pad_byte ^= PAD_BYTE_FIRST ^ PAD_BYTE_SECOND) {
    1436         9871 :         append_bits(pad_byte, QR_PAD_BYTE_BITS, qrcode, &bit_len);
    1437              :     }
    1438              : 
    1439          718 :     if (!add_ecc_and_interleave(qrcode, version, ecl, temp_buffer)) {
    1440            0 :         return false;
    1441              :     }
    1442          718 :     initialize_function_modules(version, qrcode);
    1443          718 :     draw_codewords(temp_buffer, get_num_raw_data_modules(version) >> 3, qrcode);
    1444          718 :     draw_light_function_modules(qrcode, version);
    1445          718 :     initialize_function_modules(version, temp_buffer);
    1446              : 
    1447          718 :     if (mask < 0) {
    1448          534 :         min_penalty = INT32_MAX;
    1449          534 :         best_mask = 0;
    1450              : 
    1451         4806 :         for (i = 0; i < QR_MASK_COUNT; i++) {
    1452         4272 :             apply_mask(temp_buffer, qrcode, (int8_t)i);
    1453         4272 :             draw_format_bits(ecl, (int8_t)i, qrcode);
    1454         4272 :             penalty = get_penalty_score(qrcode);
    1455              : 
    1456         4272 :             if (penalty < min_penalty) {
    1457         1064 :                 best_mask = (int8_t)i;
    1458         1064 :                 min_penalty = penalty;
    1459              :             }
    1460              : 
    1461         4272 :             apply_mask(temp_buffer, qrcode, (int8_t)i);
    1462              :         }
    1463          534 :         mask = best_mask;
    1464              :     }
    1465              : 
    1466          718 :     apply_mask(temp_buffer, qrcode, mask);
    1467          718 :     draw_format_bits(ecl, mask, qrcode);
    1468              : 
    1469          718 :     return true;
    1470              : }
    1471              : 
    1472         1001 : extern lierre_error_t lierre_writer_param_init(lierre_writer_param_t *param, uint8_t *data, size_t data_size,
    1473              :                                                size_t scale, size_t margin, lierre_writer_ecc_t ecc_level,
    1474              :                                                lierre_writer_mask_t mask_pattern, lierre_writer_mode_t mode)
    1475              : {
    1476         1001 :     if (!param || !data || data_size == 0 || scale == 0) {
    1477            4 :         return LIERRE_ERROR_INVALID_PARAMS;
    1478              :     }
    1479              : 
    1480          997 :     param->data = data;
    1481          997 :     param->data_size = data_size;
    1482          997 :     param->scale = scale;
    1483          997 :     param->margin = margin;
    1484          997 :     param->ecc_level = ecc_level;
    1485          997 :     param->mask_pattern = mask_pattern;
    1486          997 :     param->mode = mode;
    1487              : 
    1488          997 :     return LIERRE_ERROR_SUCCESS;
    1489              : }
    1490              : 
    1491         2240 : extern lierre_qr_version_t lierre_writer_qr_version(const lierre_writer_param_t *param)
    1492              : {
    1493              :     lierre_qr_version_t ver;
    1494              :     uint8_t ecl, mode_idx;
    1495              :     size_t char_count;
    1496              : 
    1497         2240 :     if (!param || !param->data || param->data_size == 0) {
    1498            3 :         return LIERRE_WRITER_QR_VERSION_ERR;
    1499              :     }
    1500              : 
    1501         2237 :     ecl = (uint8_t)param->ecc_level;
    1502         2237 :     if (ecl > 3) {
    1503            1 :         ecl = 0;
    1504              :     }
    1505              : 
    1506         2237 :     switch (param->mode) {
    1507           58 :     case MODE_NUMERIC:
    1508           58 :         mode_idx = 0;
    1509           58 :         char_count = param->data_size;
    1510           58 :         break;
    1511           58 :     case MODE_ALPHANUMERIC:
    1512           58 :         mode_idx = 1;
    1513           58 :         char_count = param->data_size;
    1514           58 :         break;
    1515           58 :     case MODE_KANJI:
    1516           58 :         mode_idx = 3;
    1517           58 :         char_count = param->data_size / 2;
    1518           58 :         break;
    1519         2063 :     case MODE_BYTE:
    1520              :     default:
    1521         2063 :         mode_idx = 2;
    1522         2063 :         char_count = param->data_size;
    1523         2063 :         break;
    1524              :     }
    1525              : 
    1526        14331 :     for (ver = 1; ver <= 40; ver++) {
    1527        14325 :         if ((size_t)CHAR_CAPACITY[ecl][ver][mode_idx] >= char_count) {
    1528         2231 :             return ver;
    1529              :         }
    1530              :     }
    1531              : 
    1532            6 :     return LIERRE_WRITER_QR_VERSION_ERR;
    1533              : }
    1534              : 
    1535         1286 : extern bool lierre_writer_get_res(const lierre_writer_param_t *param, lierre_reso_t *res)
    1536              : {
    1537              :     lierre_qr_version_t ver;
    1538              :     size_t qr_size, total_size;
    1539              : 
    1540         1286 :     if (!param || !res) {
    1541            4 :         return false;
    1542              :     }
    1543              : 
    1544         1282 :     ver = lierre_writer_qr_version(param);
    1545         1282 :     if (ver == LIERRE_WRITER_QR_VERSION_ERR) {
    1546            3 :         return false;
    1547              :     }
    1548              : 
    1549         1279 :     qr_size = (size_t)QR_VERSION_SIZE_FORMULA(ver);
    1550              : 
    1551         1279 :     if (param->margin > SIZE_MAX / 2) {
    1552            0 :         return false;
    1553              :     }
    1554              : 
    1555         1279 :     if (param->margin * 2 > SIZE_MAX - qr_size) {
    1556            0 :         return false;
    1557              :     }
    1558              : 
    1559         1279 :     if (param->scale != 0 && (qr_size + param->margin * 2) > SIZE_MAX / param->scale) {
    1560            0 :         return false;
    1561              :     }
    1562              : 
    1563         1279 :     total_size = (qr_size + param->margin * 2) * param->scale;
    1564              : 
    1565         1279 :     res->width = total_size;
    1566         1279 :     res->height = total_size;
    1567              : 
    1568         1279 :     return true;
    1569              : }
    1570              : 
    1571            4 : extern size_t lierre_writer_get_res_width(const lierre_writer_param_t *param)
    1572              : {
    1573              :     lierre_reso_t res;
    1574              : 
    1575            4 :     if (!lierre_writer_get_res(param, &res)) {
    1576            2 :         return 0;
    1577              :     }
    1578              : 
    1579            2 :     return res.width;
    1580              : }
    1581              : 
    1582            3 : extern size_t lierre_writer_get_res_height(const lierre_writer_param_t *param)
    1583              : {
    1584              :     lierre_reso_t res;
    1585              : 
    1586            3 :     if (!lierre_writer_get_res(param, &res)) {
    1587            1 :         return 0;
    1588              :     }
    1589              : 
    1590            2 :     return res.height;
    1591              : }
    1592              : 
    1593          730 : extern lierre_writer_t *lierre_writer_create(const lierre_writer_param_t *param, const lierre_rgba_t *fill_color,
    1594              :                                              const lierre_rgba_t *bg_color)
    1595              : {
    1596              :     lierre_writer_t *writer;
    1597              :     lierre_reso_t res;
    1598              :     size_t data_size;
    1599              : 
    1600          730 :     if (!param || !fill_color || !bg_color) {
    1601            3 :         return NULL;
    1602              :     }
    1603              : 
    1604          727 :     if (!lierre_writer_get_res(param, &res)) {
    1605            1 :         return NULL;
    1606              :     }
    1607              : 
    1608          726 :     writer = lmalloc(sizeof(lierre_writer_t));
    1609          726 :     if (!writer) {
    1610            0 :         return NULL;
    1611              :     }
    1612              : 
    1613          726 :     writer->param = lmalloc(sizeof(lierre_writer_param_t));
    1614          726 :     if (!writer->param) {
    1615            0 :         lfree(writer);
    1616            0 :         return NULL;
    1617              :     }
    1618          726 :     lmemcpy(writer->param, param, sizeof(lierre_writer_param_t));
    1619              : 
    1620          726 :     if (res.width != 0 && res.height > SIZE_MAX / res.width) {
    1621            0 :         lfree(writer->param);
    1622            0 :         lfree(writer);
    1623            0 :         return NULL;
    1624              :     }
    1625              : 
    1626          726 :     if (res.width * res.height > SIZE_MAX / 4) {
    1627            0 :         lfree(writer->param);
    1628            0 :         lfree(writer);
    1629            0 :         return NULL;
    1630              :     }
    1631          726 :     data_size = res.width * res.height * 4;
    1632          726 :     writer->data = lmalloc(sizeof(lierre_rgb_data_t));
    1633          726 :     if (!writer->data) {
    1634            0 :         lfree(writer->param);
    1635            0 :         lfree(writer);
    1636            0 :         return NULL;
    1637              :     }
    1638              : 
    1639          726 :     writer->data->data = lmalloc(data_size);
    1640          726 :     if (!writer->data->data) {
    1641            0 :         lfree(writer->data);
    1642            0 :         lfree(writer->param);
    1643            0 :         lfree(writer);
    1644            0 :         return NULL;
    1645              :     }
    1646              : 
    1647          726 :     writer->data->data_size = data_size;
    1648          726 :     writer->data->width = res.width;
    1649          726 :     writer->data->height = res.height;
    1650              : 
    1651          726 :     writer->stroke_color_rgba[0] = fill_color->r;
    1652          726 :     writer->stroke_color_rgba[1] = fill_color->g;
    1653          726 :     writer->stroke_color_rgba[2] = fill_color->b;
    1654          726 :     writer->stroke_color_rgba[3] = fill_color->a;
    1655              : 
    1656          726 :     writer->fill_color_rgba[0] = bg_color->r;
    1657          726 :     writer->fill_color_rgba[1] = bg_color->g;
    1658          726 :     writer->fill_color_rgba[2] = bg_color->b;
    1659          726 :     writer->fill_color_rgba[3] = bg_color->a;
    1660              : 
    1661          726 :     return writer;
    1662              : }
    1663              : 
    1664          727 : extern void lierre_writer_destroy(lierre_writer_t *writer)
    1665              : {
    1666          727 :     if (!writer) {
    1667            1 :         return;
    1668              :     }
    1669              : 
    1670          726 :     if (writer->data) {
    1671          726 :         if (writer->data->data) {
    1672          726 :             lfree(writer->data->data);
    1673              :         }
    1674              : 
    1675          726 :         lfree(writer->data);
    1676              :     }
    1677              : 
    1678          726 :     if (writer->param) {
    1679          726 :         lfree(writer->param);
    1680              :     }
    1681              : 
    1682          726 :     lfree(writer);
    1683              : }
    1684              : 
    1685          726 : extern lierre_error_t lierre_writer_write(lierre_writer_t *writer)
    1686              : {
    1687              :     lierre_qr_version_t ver;
    1688              :     uint8_t *temp_buffer, *qr_buffer, *pixel;
    1689              :     int32_t qr_size, x, y, px, py;
    1690              :     size_t scale, margin, sx, sy, img_x, img_y, offset;
    1691              :     bool is_dark, encode_success;
    1692              : 
    1693          726 :     if (!writer || !writer->param || !writer->data || !writer->data->data) {
    1694            1 :         return LIERRE_ERROR_INVALID_PARAMS;
    1695              :     }
    1696              : 
    1697          725 :     ver = lierre_writer_qr_version(writer->param);
    1698          725 :     if (ver == LIERRE_WRITER_QR_VERSION_ERR) {
    1699            0 :         return LIERRE_ERROR_SIZE_EXCEEDED;
    1700              :     }
    1701              : 
    1702          725 :     temp_buffer = lcalloc(1, QR_BUFFER_LEN_MAX);
    1703          725 :     qr_buffer = lcalloc(1, QR_BUFFER_LEN_MAX);
    1704          725 :     if (!temp_buffer || !qr_buffer) {
    1705            0 :         lfree(temp_buffer);
    1706            0 :         lfree(qr_buffer);
    1707              : 
    1708            0 :         return LIERRE_ERROR_DATA_OVERFLOW;
    1709              :     }
    1710              : 
    1711          725 :     encode_success = false;
    1712              : 
    1713          725 :     switch (writer->param->mode) {
    1714            2 :     case MODE_NUMERIC:
    1715            2 :         encode_success = encode_numeric(writer->param->data, writer->param->data_size, temp_buffer, qr_buffer,
    1716            2 :                                         (uint8_t)writer->param->ecc_level, 1, 40, (int8_t)writer->param->mask_pattern);
    1717            2 :         break;
    1718            2 :     case MODE_ALPHANUMERIC:
    1719              :         encode_success =
    1720            2 :             encode_alphanumeric(writer->param->data, writer->param->data_size, temp_buffer, qr_buffer,
    1721            2 :                                 (uint8_t)writer->param->ecc_level, 1, 40, (int8_t)writer->param->mask_pattern);
    1722            2 :         break;
    1723            2 :     case MODE_KANJI:
    1724            2 :         encode_success = encode_kanji(writer->param->data, writer->param->data_size, temp_buffer, qr_buffer,
    1725            2 :                                       (uint8_t)writer->param->ecc_level, 1, 40, (int8_t)writer->param->mask_pattern);
    1726            2 :         break;
    1727            1 :     case MODE_ECI:
    1728            1 :         encode_success = encode_eci(writer->param->data, writer->param->data_size, temp_buffer, qr_buffer,
    1729            1 :                                     (uint8_t)writer->param->ecc_level, 1, 40, (int8_t)writer->param->mask_pattern, 26);
    1730            1 :         break;
    1731          718 :     case MODE_BYTE:
    1732              :     default:
    1733          718 :         encode_success = encode_binary(writer->param->data, writer->param->data_size, temp_buffer, qr_buffer,
    1734          718 :                                        (uint8_t)writer->param->ecc_level, 1, 40, (int8_t)writer->param->mask_pattern);
    1735          718 :         break;
    1736              :     }
    1737              : 
    1738          725 :     if (!encode_success) {
    1739            0 :         lfree(temp_buffer);
    1740            0 :         lfree(qr_buffer);
    1741              : 
    1742            0 :         return LIERRE_ERROR_SIZE_EXCEEDED;
    1743              :     }
    1744              : 
    1745          725 :     qr_size = qr_buffer[0];
    1746          725 :     scale = writer->param->scale;
    1747          725 :     margin = writer->param->margin;
    1748              : 
    1749       158971 :     for (x = 0; x < (int32_t)writer->data->width; x++) {
    1750       158246 :         offset = (size_t)x * 4;
    1751       158246 :         pixel = &writer->data->data[offset];
    1752       158246 :         pixel[0] = writer->fill_color_rgba[0];
    1753       158246 :         pixel[1] = writer->fill_color_rgba[1];
    1754       158246 :         pixel[2] = writer->fill_color_rgba[2];
    1755       158246 :         pixel[3] = writer->fill_color_rgba[3];
    1756              :     }
    1757       158246 :     for (y = 1; y < (int32_t)writer->data->height; y++) {
    1758       157521 :         lmemcpy(&writer->data->data[(size_t)y * writer->data->width * 4], writer->data->data, writer->data->width * 4);
    1759              :     }
    1760              : 
    1761        29686 :     for (py = 0; py < qr_size; py++) {
    1762      1719998 :         for (px = 0; px < qr_size; px++) {
    1763      1691037 :             is_dark = get_module(qr_buffer, px, py);
    1764     14021341 :             for (sy = 0; sy < scale; sy++) {
    1765    126179848 :                 for (sx = 0; sx < scale; sx++) {
    1766    113849544 :                     img_x = (margin + (size_t)px) * scale + sx;
    1767    113849544 :                     img_y = (margin + (size_t)py) * scale + sy;
    1768              : 
    1769    113849544 :                     if (img_x < writer->data->width && img_y < writer->data->height) {
    1770    113849544 :                         offset = (img_y * writer->data->width + img_x) * 4;
    1771    113849544 :                         pixel = &writer->data->data[offset];
    1772              : 
    1773    113849544 :                         if (is_dark) {
    1774     57723331 :                             pixel[0] = writer->stroke_color_rgba[0];
    1775     57723331 :                             pixel[1] = writer->stroke_color_rgba[1];
    1776     57723331 :                             pixel[2] = writer->stroke_color_rgba[2];
    1777     57723331 :                             pixel[3] = writer->stroke_color_rgba[3];
    1778              :                         }
    1779              :                     }
    1780              :                 }
    1781              :             }
    1782              :         }
    1783              :     }
    1784              : 
    1785          725 :     lfree(temp_buffer);
    1786          725 :     lfree(qr_buffer);
    1787              : 
    1788          725 :     return LIERRE_ERROR_SUCCESS;
    1789              : }
    1790              : 
    1791          113 : extern const uint8_t *lierre_writer_get_rgba_data(const lierre_writer_t *writer)
    1792              : {
    1793          113 :     if (!writer || !writer->data) {
    1794            0 :         return NULL;
    1795              :     }
    1796              : 
    1797          113 :     return writer->data->data;
    1798              : }
    1799              : 
    1800            1 : extern size_t lierre_writer_get_rgba_data_size(const lierre_writer_t *writer)
    1801              : {
    1802            1 :     if (!writer || !writer->data) {
    1803            0 :         return 0;
    1804              :     }
    1805              : 
    1806            1 :     return writer->data->data_size;
    1807              : }
        

Generated by: LCOV version 2.0-1