| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551 |
- /* dotcode.c - Handles DotCode */
- /*
- libzint - the open source barcode library
- Copyright (C) 2017-2024 Robin Stuart <rstuart114@gmail.com>
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. Neither the name of the project nor the names of its contributors
- may be used to endorse or promote products derived from this software
- without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
- */
- /* SPDX-License-Identifier: BSD-3-Clause */
- /*
- * Attempts to encode DotCode according to (AIMD013) ISS DotCode Rev. 4.0, DRAFT 0.15, TSC Pre-PR #5,
- * dated May 28, 2019
- * Incorporating suggestions from Terry Burton at BWIPP
- */
- #include <assert.h>
- #include <math.h>
- #include <stdio.h>
- #include "common.h"
- #include "gs1.h"
- #define GF 113
- #define PM 3
- #define SCORE_UNLIT_EDGE -99999
- /* DotCode symbol character dot patterns, from Annex C */
- static const unsigned short dc_dot_patterns[113] = {
- 0x155, 0x0ab, 0x0ad, 0x0b5, 0x0d5, 0x156, 0x15a, 0x16a, 0x1aa, 0x0ae,
- 0x0b6, 0x0ba, 0x0d6, 0x0da, 0x0ea, 0x12b, 0x12d, 0x135, 0x14b, 0x14d,
- 0x153, 0x159, 0x165, 0x169, 0x195, 0x1a5, 0x1a9, 0x057, 0x05b, 0x05d,
- 0x06b, 0x06d, 0x075, 0x097, 0x09b, 0x09d, 0x0a7, 0x0b3, 0x0b9, 0x0cb,
- 0x0cd, 0x0d3, 0x0d9, 0x0e5, 0x0e9, 0x12e, 0x136, 0x13a, 0x14e, 0x15c,
- 0x166, 0x16c, 0x172, 0x174, 0x196, 0x19a, 0x1a6, 0x1ac, 0x1b2, 0x1b4,
- 0x1ca, 0x1d2, 0x1d4, 0x05e, 0x06e, 0x076, 0x07a, 0x09e, 0x0bc, 0x0ce,
- 0x0dc, 0x0e6, 0x0ec, 0x0f2, 0x0f4, 0x117, 0x11b, 0x11d, 0x127, 0x133,
- 0x139, 0x147, 0x163, 0x171, 0x18b, 0x18d, 0x193, 0x199, 0x1a3, 0x1b1,
- 0x1c5, 0x1c9, 0x1d1, 0x02f, 0x037, 0x03b, 0x03d, 0x04f, 0x067, 0x073,
- 0x079, 0x08f, 0x0c7, 0x0e3, 0x0f1, 0x11e, 0x13c, 0x178, 0x18e, 0x19c,
- 0x1b8, 0x1c6, 0x1cc
- };
- /* Printed() routine from Annex A adapted to char array of ASCII 1's and 0's */
- static int dc_get_dot(const char Dots[], const int Hgt, const int Wid, const int x, const int y) {
- if ((x >= 0) && (x < Wid) && (y >= 0) && (y < Hgt)) {
- if (Dots[(y * Wid) + x] == '1') {
- return 1;
- }
- }
- return 0;
- }
- static int dc_clr_col(const char *Dots, const int Hgt, const int Wid, const int x) {
- int y;
- for (y = x & 1; y < Hgt; y += 2) {
- if (dc_get_dot(Dots, Hgt, Wid, x, y)) {
- return 0;
- }
- }
- return 1;
- }
- static int dc_clr_row(const char *Dots, const int Hgt, const int Wid, const int y) {
- int x;
- for (x = y & 1; x < Wid; x += 2) {
- if (dc_get_dot(Dots, Hgt, Wid, x, y)) {
- return 0;
- }
- }
- return 1;
- }
- /* calc penalty for empty interior columns */
- static int dc_col_penalty(const char *Dots, const int Hgt, const int Wid) {
- int x, penalty = 0, penalty_local = 0;
- for (x = 1; x < Wid - 1; x++) {
- if (dc_clr_col(Dots, Hgt, Wid, x)) {
- if (penalty_local == 0) {
- penalty_local = Hgt;
- } else {
- penalty_local *= Hgt;
- }
- } else {
- if (penalty_local) {
- penalty += penalty_local;
- penalty_local = 0;
- }
- }
- }
- return penalty + penalty_local;
- }
- /* calc penalty for empty interior rows */
- static int dc_row_penalty(const char *Dots, const int Hgt, const int Wid) {
- int y, penalty = 0, penalty_local = 0;
- for (y = 1; y < Hgt - 1; y++) {
- if (dc_clr_row(Dots, Hgt, Wid, y)) {
- if (penalty_local == 0) {
- penalty_local = Wid;
- } else {
- penalty_local *= Wid;
- }
- } else {
- if (penalty_local) {
- penalty += penalty_local;
- penalty_local = 0;
- }
- }
- }
- return penalty + penalty_local;
- }
- /* Dot pattern scoring routine from Annex A */
- static int dc_score_array(const char Dots[], const int Hgt, const int Wid) {
- int x, y, worstedge, first, last, sum;
- int penalty = 0;
- /* first, guard against "pathelogical" gaps in the array
- subtract a penalty score for empty rows/columns from total code score for each mask,
- where the penalty is Sum(N ^ n), where N is the number of positions in a column/row,
- and n is the number of consecutive empty rows/columns */
- penalty = dc_row_penalty(Dots, Hgt, Wid) + dc_col_penalty(Dots, Hgt, Wid);
- sum = 0;
- first = -1;
- last = -1;
- /* across the top edge, count printed dots and measure their extent */
- for (x = 0; x < Wid; x += 2) {
- if (dc_get_dot(Dots, Hgt, Wid, x, 0)) {
- if (first < 0) {
- first = x;
- }
- last = x;
- sum++;
- }
- }
- if (sum == 0) {
- return SCORE_UNLIT_EDGE; /* guard against empty top edge */
- }
- worstedge = sum + last - first;
- worstedge *= Hgt;
- sum = 0;
- first = -1;
- last = -1;
- /* across the bottom edge, ditto */
- for (x = Wid & 1; x < Wid; x += 2) {
- if (dc_get_dot(Dots, Hgt, Wid, x, Hgt - 1)) {
- if (first < 0) {
- first = x;
- }
- last = x;
- sum++;
- }
- }
- if (sum == 0) {
- return SCORE_UNLIT_EDGE; /* guard against empty bottom edge */
- }
- sum += last - first;
- sum *= Hgt;
- if (sum < worstedge) {
- worstedge = sum;
- }
- sum = 0;
- first = -1;
- last = -1;
- /* down the left edge, ditto */
- for (y = 0; y < Hgt; y += 2) {
- if (dc_get_dot(Dots, Hgt, Wid, 0, y)) {
- if (first < 0) {
- first = y;
- }
- last = y;
- sum++;
- }
- }
- if (sum == 0) {
- return SCORE_UNLIT_EDGE; /* guard against empty left edge */
- }
- sum += last - first;
- sum *= Wid;
- if (sum < worstedge) {
- worstedge = sum;
- }
- sum = 0;
- first = -1;
- last = -1;
- /* down the right edge, ditto */
- for (y = Hgt & 1; y < Hgt; y += 2) {
- if (dc_get_dot(Dots, Hgt, Wid, Wid - 1, y)) {
- if (first < 0) {
- first = y;
- }
- last = y;
- sum++;
- }
- }
- if (sum == 0) {
- return SCORE_UNLIT_EDGE; /* guard against empty right edge */
- }
- sum += last - first;
- sum *= Wid;
- if (sum < worstedge) {
- worstedge = sum;
- }
- /* throughout the array, count the # of unprinted 5-somes (cross patterns)
- plus the # of printed dots surrounded by 8 unprinted neighbors */
- sum = 0;
- for (y = 0; y < Hgt; y++) {
- for (x = y & 1; x < Wid; x += 2) {
- if (!dc_get_dot(Dots, Hgt, Wid, x - 1, y - 1) && !dc_get_dot(Dots, Hgt, Wid, x + 1, y - 1)
- && !dc_get_dot(Dots, Hgt, Wid, x - 1, y + 1) && !dc_get_dot(Dots, Hgt, Wid, x + 1, y + 1)
- && (!dc_get_dot(Dots, Hgt, Wid, x, y)
- || (!dc_get_dot(Dots, Hgt, Wid, x - 2, y) && !dc_get_dot(Dots, Hgt, Wid, x, y - 2)
- && !dc_get_dot(Dots, Hgt, Wid, x + 2, y) && !dc_get_dot(Dots, Hgt, Wid, x, y + 2)))) {
- sum++;
- }
- }
- }
- return (worstedge - sum * sum - penalty);
- }
- /*-------------------------------------------------------------------------
- // "rsencode(nd,nc)" adds "nc" R-S check words to "nd" data words in wd[]
- // employing Galois Field GF, where GF is prime, with a prime modulus of PM
- //-------------------------------------------------------------------------*/
- static void dc_rsencode(const int nd, const int nc, unsigned char *wd) {
- /* Pre-calculated coefficients for GF(113) of generator polys of degree 3 to 39. To generate run
- "backend/tests/test_dotcode -f generate -g" and place result below */
- static const char coefs[820 - 5] = { /* 40*(41 + 1)/2 == 820 less 2 + 3 (degrees 1 and 2) */
- 1, 74, 12, 62,
- 1, 106, 7, 107, 63,
- 1, 89, 13, 101, 52, 59,
- 1, 38, 107, 3, 99, 6, 42,
- 1, 111, 56, 17, 92, 1, 28, 15,
- 1, 104, 70, 77, 86, 35, 21, 45, 8,
- 1, 83, 33, 76, 51, 37, 77, 56, 80, 58,
- 1, 20, 2, 31, 9, 101, 6, 64, 55, 103, 75,
- 1, 57, 64, 105, 26, 95, 14, 60, 50, 104, 44, 63,
- 1, 55, 63, 90, 42, 43, 50, 32, 43, 4, 62, 88, 100,
- 1, 49, 72, 51, 67, 17, 18, 71, 77, 85, 38, 55, 24, 78,
- 1, 31, 94, 111, 53, 54, 51, 86, 42, 55, 90, 49, 51, 98, 65,
- 1, 90, 2, 7, 48, 17, 73, 44, 31, 47, 58, 48, 4, 56, 84, 106,
- 1, 41, 112, 22, 44, 38, 31, 83, 22, 110, 15, 31, 25, 86, 52, 58, 4,
- 1, 7, 74, 56, 87, 11, 95, 46, 25, 40, 4, 86, 101, 27, 66, 98, 66, 90,
- 1, 18, 38, 79, 25, 64, 103, 74, 79, 89, 105, 17, 30, 8, 24, 33, 14, 25, 86,
- 1, 51, 67, 90, 33, 98, 68, 83, 35, 97, 104, 92, 26, 94, 62, 34, 86, 35, 7, 13,
- 1, 37, 31, 56, 16, 88, 52, 35, 3, 59, 102, 105, 94, 69, 102, 70, 62, 74, 82, 28, 44,
- 1, 108, 59, 110, 37, 94, 85, 111, 2, 46, 110, 2, 91, 76, 29, 80, 60, 69, 25, 87, 111, 73,
- 1, 95, 11, 21, 76, 65, 106, 23, 28, 20, 77, 41, 65, 23, 58, 42, 37, 80, 32, 101, 110, 99,
- 68,
- 1, 56, 35, 44, 48, 39, 57, 70, 35, 58, 88, 89, 48, 87, 65, 40, 94, 106, 76, 96, 13, 103,
- 49, 60,
- 1, 52, 37, 17, 98, 73, 14, 68, 94, 31, 82, 76, 31, 8, 56, 6, 47, 69, 104, 18, 81, 51,
- 89, 90, 99,
- 1, 40, 91, 25, 7, 27, 42, 13, 69, 33, 49, 109, 23, 88, 73, 12, 88, 70, 67, 13, 91, 96,
- 42, 39, 36, 55,
- 1, 4, 7, 26, 11, 1, 87, 83, 53, 35, 104, 40, 54, 51, 69, 96, 108, 66, 33, 87, 75, 97,
- 89, 109, 101, 2, 54,
- 1, 9, 27, 61, 28, 56, 92, 66, 16, 74, 53, 108, 28, 95, 98, 102, 23, 41, 24, 26, 58, 20,
- 9, 102, 81, 55, 64, 44,
- 1, 24, 49, 14, 39, 24, 28, 90, 102, 88, 33, 112, 66, 63, 54, 103, 84, 47, 74, 47, 109, 99,
- 83, 11, 29, 27, 98, 100, 95,
- 1, 69, 112, 72, 104, 84, 91, 107, 84, 45, 38, 15, 21, 95, 64, 47, 86, 98, 42, 100, 77, 32,
- 18, 17, 72, 89, 70, 103, 75, 94,
- 1, 91, 48, 50, 106, 112, 18, 75, 65, 85, 11, 60, 12, 105, 7, 99, 103, 69, 51, 7, 17, 31,
- 44, 74, 107, 91, 107, 61, 81, 49, 34,
- 1, 44, 65, 54, 16, 102, 65, 20, 43, 81, 84, 108, 17, 106, 44, 109, 83, 87, 85, 96, 27, 23,
- 56, 40, 19, 34, 11, 4, 39, 84, 104, 97,
- 1, 16, 76, 42, 86, 106, 34, 8, 48, 7, 76, 16, 44, 82, 14, 7, 82, 23, 22, 89, 51, 58,
- 90, 54, 29, 67, 76, 35, 40, 9, 12, 10, 109,
- 1, 45, 88, 99, 61, 1, 57, 90, 54, 43, 53, 73, 56, 2, 19, 74, 59, 28, 11, 49, 33, 68,
- 77, 65, 13, 4, 98, 92, 38, 39, 47, 19, 60, 110,
- 1, 19, 48, 71, 86, 110, 31, 77, 87, 108, 65, 51, 79, 15, 80, 32, 56, 76, 74, 102, 2, 1,
- 4, 97, 18, 5, 107, 30, 19, 68, 50, 40, 18, 19, 78,
- 1, 54, 35, 56, 85, 69, 39, 32, 70, 102, 3, 66, 56, 68, 40, 7, 46, 2, 22, 93, 69, 71,
- 39, 11, 23, 70, 56, 46, 52, 55, 57, 95, 62, 84, 65, 18,
- 1, 46, 55, 2, 89, 67, 52, 59, 40, 107, 91, 42, 93, 72, 61, 26, 103, 86, 6, 30, 3, 84,
- 36, 38, 48, 112, 61, 50, 23, 91, 69, 91, 93, 40, 71, 63, 82,
- 1, 22, 81, 38, 41, 78, 26, 54, 93, 51, 9, 5, 102, 100, 28, 31, 44, 100, 89, 112, 74, 12,
- 54, 78, 40, 90, 85, 55, 66, 104, 32, 17, 56, 68, 15, 54, 39, 66,
- 1, 63, 79, 82, 17, 64, 60, 103, 47, 22, 66, 35, 81, 101, 60, 49, 72, 96, 8, 32, 33, 108,
- 94, 32, 74, 35, 46, 37, 61, 98, 2, 86, 75, 104, 91, 104, 106, 83, 107,
- 1, 73, 31, 81, 46, 8, 22, 25, 60, 40, 60, 17, 92, 7, 53, 84, 110, 25, 64, 112, 14, 99,
- 44, 68, 55, 97, 57, 45, 92, 30, 78, 106, 31, 63, 1, 110, 16, 13, 33, 53,
- };
- static const short cinds[39 - 2] = { /* Indexes into above coefs[] array */
- 0, 4, 9, 15, 22, 30, 39, 49, 60, 72, 85, 99, 114, 130, 147, 165, 184, 204, 225, 247, 270, 294,
- 319, 345, 372, 400, 429, 459, 490, 522, 555, 589, 624, 660, 697, 735, 774,
- };
- int i, j, k, nw, start, step;
- const char *c;
- /* Here we compute how many interleaved R-S blocks will be needed */
- nw = nd + nc;
- step = (nw + GF - 2) / (GF - 1);
- /* ...& then for each such block: */
- for (start = 0; start < step; start++) {
- const int ND = (nd - start + step - 1) / step;
- const int NW = (nw - start + step - 1) / step;
- const int NC = NW - ND;
- unsigned char *const e = wd + start + ND * step;
- /* first set the generator polynomial "c" of order "NC": */
- c = coefs + cinds[NC - 3];
- /* & then compute the corresponding checkword values into wd[]
- ... (a) starting at wd[start] & (b) stepping by step */
- for (i = 0; i < NC; i++) {
- e[i * step] = 0;
- }
- for (i = 0; i < ND; i++) {
- k = (wd[start + i * step] + e[0]) % GF;
- for (j = 0; j < NC - 1; j++) {
- e[j * step] = (GF - ((c[j + 1] * k) % GF) + e[(j + 1) * step]) % GF;
- }
- e[(NC - 1) * step] = (GF - ((c[NC] * k) % GF)) % GF;
- }
- for (i = 0; i < NC; i++) {
- if (e[i * step]) {
- e[i * step] = GF - e[i * step];
- }
- }
- }
- }
- /* Check if the next character is directly encodable in code set A (Annex F.II.D) */
- static int dc_datum_a(const unsigned char source[], const int length, const int position) {
- if (position < length && source[position] <= 95) {
- return 1;
- }
- return 0;
- }
- /* Check if the next character is directly encodable in code set B (Annex F.II.D).
- * Note changed to return 2 if CR/LF */
- static int dc_datum_b(const unsigned char source[], const int length, const int position) {
- if (position < length) {
- if ((source[position] >= 32) && (source[position] <= 127)) {
- return 1;
- }
- switch (source[position]) {
- case 9: /* HT */
- case 28: /* FS */
- case 29: /* GS */
- case 30: /* RS */
- return 1;
- break;
- }
- if ((position + 1 < length) && (source[position] == 13) && (source[position + 1] == 10)) { /* CRLF */
- return 2;
- }
- }
- return 0;
- }
- /* Check if the next characters are directly encodable in code set C (Annex F.II.D) */
- static int dc_datum_c(const unsigned char source[], const int length, const int position) {
- return is_twodigits(source, length, position);
- }
- /* Checks ahead for 10 or more digits starting "17xxxxxx10..." (Annex F.II.B) */
- static int dc_seventeen_ten(const unsigned char source[], const int length, const int position) {
- if (position + 9 < length && source[position] == '1' && source[position + 1] == '7'
- && source[position + 8] == '1' && source[position + 9] == '0'
- && cnt_digits(source, length, position + 2, 6) >= 6) {
- return 1;
- }
- return 0;
- }
- /* Checks how many characters ahead can be reached while dc_datum_c is true,
- * returning the resulting number of codewords (Annex F.II.E)
- */
- static int dc_ahead_c(const unsigned char source[], const int length, const int position) {
- int count = 0;
- int i;
- for (i = position; (i < length) && dc_datum_c(source, length, i); i += 2) {
- count++;
- }
- return count;
- }
- /* Annex F.II.F */
- static int dc_try_c(const unsigned char source[], const int length, const int position) {
- if (position < length && z_isdigit(source[position])) { /* cnt_digits(position) > 0 */
- const int ahead_c_position = dc_ahead_c(source, length, position);
- if (ahead_c_position > dc_ahead_c(source, length, position + 1)) {
- return ahead_c_position;
- }
- }
- return 0;
- }
- /* Annex F.II.G */
- static int dc_ahead_a(const unsigned char source[], const int length, const int position) {
- int count = 0;
- int i;
- for (i = position; i < length && dc_datum_a(source, length, i) && dc_try_c(source, length, i) < 2; i++) {
- count++;
- }
- return count;
- }
- /* Annex F.II.H Note: changed to return number of chars encodable. Number of codewords returned in *p_nx. */
- static int dc_ahead_b(const unsigned char source[], const int length, const int position, int *p_nx) {
- int count = 0;
- int i, incr;
- for (i = position; i < length && (incr = dc_datum_b(source, length, i))
- && dc_try_c(source, length, i) < 2; i += incr) {
- count++;
- }
- if (p_nx != NULL) {
- *p_nx = count;
- }
- return i - position;
- }
- /* Checks if the next character is in the range 128 to 255 (Annex F.II.I) */
- static int dc_binary(const unsigned char source[], const int length, const int position) {
- if (position < length && source[position] >= 128) {
- return 1;
- }
- return 0;
- }
- /* Empty binary buffer */
- static int dc_empty_bin_buf(unsigned char *codeword_array, int ap, uint64_t *p_bin_buf, int *p_bin_buf_size) {
- int i;
- int lawrencium[6]; /* Reversed radix 103 values */
- uint64_t bin_buf = *p_bin_buf;
- int bin_buf_size = *p_bin_buf_size;
- if (bin_buf_size) {
- for (i = 0; i < bin_buf_size + 1; i++) {
- lawrencium[i] = (int) (bin_buf % 103);
- bin_buf /= 103;
- }
- for (i = 0; i < bin_buf_size + 1; i++) {
- codeword_array[ap++] = lawrencium[bin_buf_size - i];
- }
- }
- *p_bin_buf = 0;
- *p_bin_buf_size = 0;
- return ap;
- }
- /* Add value to binary buffer, emptying if full */
- static int dc_append_to_bin_buf(unsigned char *codeword_array, int ap, unsigned int val, uint64_t *p_bin_buf,
- int *p_bin_buf_size) {
- *p_bin_buf *= 259;
- *p_bin_buf += val;
- (*p_bin_buf_size)++;
- if (*p_bin_buf_size == 5) {
- ap = dc_empty_bin_buf(codeword_array, ap, p_bin_buf, p_bin_buf_size);
- }
- return ap;
- }
- /* Analyse input data stream and encode using algorithm from Annex F */
- static int dc_encode_message(struct zint_symbol *symbol, const unsigned char source[], const int length,
- const int eci, const int last_seg, const int last_EOT, const int last_RSEOT,
- int ap, unsigned char *codeword_array, char *p_encoding_mode, int *p_inside_macro,
- uint64_t *p_bin_buf, int *p_bin_buf_size, unsigned char structapp_array[], int *p_structapp_size) {
- static const char lead_specials[] = "\x09\x1C\x1D\x1E"; /* HT, FS, GS, RS */
- int i;
- int position = 0;
- char encoding_mode = *p_encoding_mode;
- int inside_macro = *p_inside_macro;
- uint64_t bin_buf = *p_bin_buf;
- int bin_buf_size = *p_bin_buf_size;
- int nx;
- const int first_seg = ap == 0;
- const int gs1 = (symbol->input_mode & 0x07) == GS1_MODE;
- const int debug_print = (symbol->debug & ZINT_DEBUG_PRINT);
- if (first_seg) {
- if (symbol->output_options & READER_INIT) {
- codeword_array[ap++] = 109; /* FNC3 */
- } else if (!gs1 && eci == 0 && length > 2 && is_twodigits(source, length, 0)) {
- codeword_array[ap++] = 107; /* FNC1 */
- } else if (posn(lead_specials, source[0]) != -1) {
- /* Prevent encodation as a macro if a special character is in first position */
- codeword_array[ap++] = 101; /* Latch A */
- codeword_array[ap++] = source[0] + 64;
- encoding_mode = 'A';
- position++;
- } else if (length > 5) { /* Note assuming macro headers don't straddle segments */
- /* Step C1 */
- if (source[0] == '[' && source[1] == ')' && source[2] == '>' && source[3] == 30 /*RS*/ && last_EOT) {
- int format_050612 = (source[4] == '0' && (source[5] == '5' || source[5] == '6'))
- || (source[4] == '1' && source[5] == '2');
- inside_macro = 0;
- if (length > 6 && format_050612 && source[6] == 29 /*GS*/ && last_RSEOT) {
- if (source[5] == '5') {
- inside_macro = 97;
- } else if (source[5] == '6') {
- inside_macro = 98;
- } else {
- inside_macro = 99;
- }
- } else if (!format_050612 && is_twodigits(source, length, 4) ) {
- inside_macro = 100; /* Note no longer using for malformed 05/06/12 */
- }
- if (inside_macro) {
- codeword_array[ap++] = 106; /* Latch B */
- encoding_mode = 'B';
- codeword_array[ap++] = inside_macro; /* Macro */
- if (inside_macro == 100) {
- codeword_array[ap++] = ctoi(source[4]) + 16;
- codeword_array[ap++] = ctoi(source[5]) + 16;
- position += 6;
- } else {
- position += 7;
- }
- if (debug_print) printf("C1/%d ", inside_macro - 96);
- }
- }
- }
- }
- if (eci > 0) {
- if (encoding_mode == 'X') {
- if (eci <= 0xFF) {
- ap = dc_append_to_bin_buf(codeword_array, ap, 256, &bin_buf, &bin_buf_size);
- ap = dc_append_to_bin_buf(codeword_array, ap, eci, &bin_buf, &bin_buf_size);
- /* Following BWIPP, assuming big-endian byte order */
- } else if (eci <= 0xFFFF) {
- ap = dc_append_to_bin_buf(codeword_array, ap, 257, &bin_buf, &bin_buf_size);
- ap = dc_append_to_bin_buf(codeword_array, ap, eci >> 8, &bin_buf, &bin_buf_size);
- ap = dc_append_to_bin_buf(codeword_array, ap, eci & 0xFF, &bin_buf, &bin_buf_size);
- } else {
- ap = dc_append_to_bin_buf(codeword_array, ap, 258, &bin_buf, &bin_buf_size);
- ap = dc_append_to_bin_buf(codeword_array, ap, eci >> 16, &bin_buf, &bin_buf_size);
- ap = dc_append_to_bin_buf(codeword_array, ap, (eci >> 8) & 0xFF, &bin_buf, &bin_buf_size);
- ap = dc_append_to_bin_buf(codeword_array, ap, eci & 0xFF, &bin_buf, &bin_buf_size);
- }
- } else {
- codeword_array[ap++] = 108; /* FNC2 */
- if (eci <= 39) {
- codeword_array[ap++] = eci;
- } else {
- /* the next three codewords valued A, B & C encode the ECI value of
- (A - 40) * 12769 + B * 113 + C + 40 (Section 5.2.1) */
- int a, b, c;
- a = (eci - 40) / 12769;
- b = ((eci - 40) - (12769 * a)) / 113;
- c = (eci - 40) - (12769 * a) - (113 * b);
- codeword_array[ap++] = a + 40;
- codeword_array[ap++] = b;
- codeword_array[ap++] = c;
- }
- }
- }
- while (position < length) {
- /* Step A */
- if (last_seg && (position == length - 2) && (inside_macro != 0) && (inside_macro != 100)) {
- /* inside_macro only gets set to 97, 98 or 99 if the last two characters are RS/EOT */
- position += 2;
- if (debug_print) fputs("A ", stdout);
- continue;
- }
- /* Step B */
- if (last_seg && (position == length - 1) && (inside_macro == 100)) {
- /* inside_macro only gets set to 100 if the last character is EOT */
- position++;
- if (debug_print) fputs("B ", stdout);
- continue;
- }
- if (encoding_mode == 'C') {
- /* Step C2 */
- if (dc_seventeen_ten(source, length, position)) {
- codeword_array[ap++] = 100; /* (17)...(10) */
- codeword_array[ap++] = to_int(source + position + 2, 2);
- codeword_array[ap++] = to_int(source + position + 4, 2);
- codeword_array[ap++] = to_int(source + position + 6, 2);
- position += 10;
- if (debug_print) fputs("C2/1 ", stdout);
- continue;
- }
- if (dc_datum_c(source, length, position) || (gs1 && source[position] == '\x1D')) {
- if (source[position] == '\x1D') {
- codeword_array[ap++] = 107; /* FNC1 */
- position++;
- } else {
- codeword_array[ap++] = to_int(source + position, 2);
- position += 2;
- }
- if (debug_print) fputs("C2/2 ", stdout);
- continue;
- }
- /* Step C3 */
- if (dc_binary(source, length, position)) {
- /* cnt_digits(position + 1) > 0 */
- if (position + 1 < length && z_isdigit(source[position + 1])) {
- if ((source[position] - 128) < 32) {
- codeword_array[ap++] = 110; /* Upper Shift A */
- codeword_array[ap++] = source[position] - 128 + 64;
- } else {
- codeword_array[ap++] = 111; /* Upper Shift B */
- codeword_array[ap++] = source[position] - 128 - 32;
- }
- position++;
- } else {
- codeword_array[ap++] = 112; /* Bin Latch */
- encoding_mode = 'X';
- }
- if (debug_print) fputs("C3 ", stdout);
- continue;
- }
- /* Step C4 */
- {
- const int m = dc_ahead_a(source, length, position);
- const int n = dc_ahead_b(source, length, position, &nx);
- if (m > n) {
- codeword_array[ap++] = 101; /* Latch A */
- encoding_mode = 'A';
- } else {
- if (nx >= 1 && nx <= 4) {
- codeword_array[ap++] = 101 + nx; /* nx Shift B */
- for (i = 0; i < nx; i++) {
- if (source[position] >= 32) {
- codeword_array[ap++] = source[position] - 32;
- } else if (source[position] == 13) { /* CR/LF */
- codeword_array[ap++] = 96;
- position++;
- } else {
- switch (source[position]) {
- case 9: codeword_array[ap++] = 97; break; /* HT */
- case 28: codeword_array[ap++] = 98; break; /* FS */
- case 29: codeword_array[ap++] = 99; break; /* GS */
- case 30: codeword_array[ap++] = 100; break; /* RS */
- }
- }
- position++;
- }
- } else {
- codeword_array[ap++] = 106; /* Latch B */
- encoding_mode = 'B';
- }
- }
- if (debug_print) fputs("C4 ", stdout);
- continue;
- }
- } /* encoding_mode == 'C' */
- if (encoding_mode == 'B') {
- /* Step D1 */
- const int n = dc_try_c(source, length, position);
- if (n >= 2) {
- if (n <= 4) {
- codeword_array[ap++] = 103 + (n - 2); /* nx Shift C */
- for (i = 0; i < n; i++) {
- codeword_array[ap++] = to_int(source + position, 2);
- position += 2;
- }
- } else {
- codeword_array[ap++] = 106; /* Latch C */
- encoding_mode = 'C';
- }
- if (debug_print) fputs("D1 ", stdout);
- continue;
- }
- /* Step D2 */
- if (gs1 && source[position] == '\x1D') {
- codeword_array[ap++] = 107; /* FNC1 */
- position++;
- if (debug_print) fputs("D2/1 ", stdout);
- continue;
- }
- if (dc_datum_b(source, length, position)) {
- int done = 0;
- if ((source[position] >= 32) && (source[position] <= 127)) {
- codeword_array[ap++] = source[position] - 32;
- done = 1;
- } else if (source[position] == 13) {
- /* CR/LF */
- codeword_array[ap++] = 96;
- position++;
- done = 1;
- } else if (!first_seg || position != 0) {
- /* HT, FS, GS and RS in the first data position would be interpreted as a macro
- * (see table 2) */
- switch (source[position]) {
- case 9: codeword_array[ap++] = 97; break; /* HT */
- case 28: codeword_array[ap++] = 98; break; /* FS */
- case 29: codeword_array[ap++] = 99; break; /* GS */
- case 30: codeword_array[ap++] = 100; break; /* RS */
- }
- done = 1;
- }
- if (done == 1) {
- position++;
- if (debug_print) fputs("D2/2 ", stdout);
- continue;
- }
- }
- /* Step D3 */
- if (dc_binary(source, length, position)) {
- if (dc_datum_b(source, length, position + 1)) {
- if ((source[position] - 128) < 32) {
- codeword_array[ap++] = 110; /* Bin Shift A */
- codeword_array[ap++] = source[position] - 128 + 64;
- } else {
- codeword_array[ap++] = 111; /* Bin Shift B */
- codeword_array[ap++] = source[position] - 128 - 32;
- }
- position++;
- } else {
- codeword_array[ap++] = 112; /* Bin Latch */
- encoding_mode = 'X';
- }
- if (debug_print) fputs("D3 ", stdout);
- continue;
- }
- /* Step D4 */
- if (dc_ahead_a(source, length, position) == 1) {
- codeword_array[ap++] = 101; /* Shift A */
- if (source[position] < 32) {
- codeword_array[ap++] = source[position] + 64;
- } else {
- codeword_array[ap++] = source[position] - 32;
- }
- position++;
- } else {
- codeword_array[ap++] = 102; /* Latch A */
- encoding_mode = 'A';
- }
- if (debug_print) fputs("D4 ", stdout);
- continue;
- } /* encoding_mode == 'B' */
- if (encoding_mode == 'A') {
- /* Step E1 */
- const int n = dc_try_c(source, length, position);
- if (n >= 2) {
- if (n <= 4) {
- codeword_array[ap++] = 103 + (n - 2); /* nx Shift C */
- for (i = 0; i < n; i++) {
- codeword_array[ap++] = to_int(source + position, 2);
- position += 2;
- }
- } else {
- codeword_array[ap++] = 106; /* Latch C */
- encoding_mode = 'C';
- }
- if (debug_print) fputs("E1 ", stdout);
- continue;
- }
- /* Step E2 */
- if (gs1 && source[position] == '\x1D') {
- /* Note: this branch probably never reached as no reason to be in Code Set A for GS1 data */
- codeword_array[ap++] = 107; /* FNC1 */
- position++;
- if (debug_print) fputs("E2/1 ", stdout);
- continue;
- }
- if (dc_datum_a(source, length, position)) {
- if (source[position] < 32) {
- codeword_array[ap++] = source[position] + 64;
- } else {
- codeword_array[ap++] = source[position] - 32;
- }
- position++;
- if (debug_print) fputs("E2/2 ", stdout);
- continue;
- }
- /* Step E3 */
- if (dc_binary(source, length, position)) {
- if (dc_datum_a(source, length, position + 1)) {
- if ((source[position] - 128) < 32) {
- codeword_array[ap++] = 110; /* Bin Shift A */
- codeword_array[ap++] = source[position] - 128 + 64;
- } else {
- codeword_array[ap++] = 111; /* Bin Shift B */
- codeword_array[ap++] = source[position] - 128 - 32;
- }
- position++;
- } else {
- codeword_array[ap++] = 112; /* Bin Latch */
- encoding_mode = 'X';
- }
- if (debug_print) fputs("E3 ", stdout);
- continue;
- }
- /* Step E4 */
- dc_ahead_b(source, length, position, &nx);
- if (nx >= 1 && nx <= 6) {
- codeword_array[ap++] = 95 + nx; /* nx Shift B */
- for (i = 0; i < nx; i++) {
- if (source[position] >= 32) {
- codeword_array[ap++] = source[position] - 32;
- } else if (source[position] == 13) { /* CR/LF */
- codeword_array[ap++] = 96;
- position++;
- } else {
- switch (source[position]) {
- case 9: codeword_array[ap++] = 97; break; /* HT */
- case 28: codeword_array[ap++] = 98; break; /* FS */
- case 29: codeword_array[ap++] = 99; break; /* GS */
- case 30: codeword_array[ap++] = 100; break; /* RS */
- }
- }
- position++;
- }
- } else {
- codeword_array[ap++] = 102; /* Latch B */
- encoding_mode = 'B';
- }
- if (debug_print) fputs("E4 ", stdout);
- continue;
- } /* encoding_mode == 'A' */
- /* Step F1 */
- if (encoding_mode == 'X') {
- const int n = dc_try_c(source, length, position);
- if (n >= 2) {
- ap = dc_empty_bin_buf(codeword_array, ap, &bin_buf, &bin_buf_size);
- if (n <= 7) {
- codeword_array[ap++] = 101 + n; /* Interrupt for nx Shift C */
- for (i = 0; i < n; i++) {
- codeword_array[ap++] = to_int(source + position, 2);
- position += 2;
- }
- } else {
- codeword_array[ap++] = 111; /* Terminate with Latch to C */
- encoding_mode = 'C';
- }
- if (debug_print) fputs("F1 ", stdout);
- continue;
- }
- /* Step F2 */
- /* Section 5.2.1.1 para D.2.i states:
- * "Groups of six codewords, each valued between 0 and 102, are radix converted from
- * base 103 into five base 259 values..."
- */
- if (dc_binary(source, length, position)
- || dc_binary(source, length, position + 1)
- || dc_binary(source, length, position + 2)
- || dc_binary(source, length, position + 3)) {
- ap = dc_append_to_bin_buf(codeword_array, ap, source[position], &bin_buf, &bin_buf_size);
- position++;
- if (debug_print) fputs("F2 ", stdout);
- continue;
- }
- /* Step F3 */
- ap = dc_empty_bin_buf(codeword_array, ap, &bin_buf, &bin_buf_size); /* Empty binary buffer */
- if (dc_ahead_a(source, length, position) > dc_ahead_b(source, length, position, NULL)) {
- codeword_array[ap++] = 109; /* Terminate with Latch to A */
- encoding_mode = 'A';
- } else {
- codeword_array[ap++] = 110; /* Terminate with Latch to B */
- encoding_mode = 'B';
- }
- if (debug_print) fputs("F3 ", stdout);
- } /* encoding_mode == 'X' */
- }
- if (last_seg) {
- if (encoding_mode == 'X' && bin_buf_size != 0) {
- /* Empty binary buffer */
- ap = dc_empty_bin_buf(codeword_array, ap, &bin_buf, &bin_buf_size);
- }
- if (symbol->structapp.count) {
- int sp = 0;
- /* Need Code Set A or B - choosing A here (TEC-IT chooses B) */
- if (encoding_mode == 'C') {
- structapp_array[sp++] = 101; /* Latch A */
- } else if (encoding_mode == 'X') {
- structapp_array[sp++] = 109; /* Terminate with Latch A */
- }
- if (symbol->structapp.index < 10) {
- structapp_array[sp++] = 16 + symbol->structapp.index; /* '0' + index for 1-9 */
- } else {
- structapp_array[sp++] = 33 + symbol->structapp.index - 10; /* 'A' + index for A-Z */
- }
- if (symbol->structapp.count < 10) {
- structapp_array[sp++] = 16 + symbol->structapp.count; /* '0' + count for 1-9 */
- } else {
- structapp_array[sp++] = 33 + symbol->structapp.count - 10; /* 'A' + count for A-Z */
- }
- structapp_array[sp++] = 108; /* FNC2 as last codeword */
- *p_structapp_size = sp;
- }
- }
- if (debug_print) {
- fputc('\n', stdout);
- }
- *p_encoding_mode = encoding_mode;
- *p_inside_macro = inside_macro;
- *p_bin_buf = bin_buf;
- *p_bin_buf_size = bin_buf_size;
- return ap;
- }
- /* Call `dc_encode_message()` for each segment */
- static int dc_encode_message_segs(struct zint_symbol *symbol, const struct zint_seg segs[], const int seg_count,
- unsigned char *codeword_array, int *p_binary_finish, unsigned char structapp_array[],
- int *p_structapp_size) {
- int i;
- int last_EOT = 0;
- int last_RSEOT = 0;
- int ap = 0;
- char encoding_mode = 'C';
- int inside_macro = 0;
- uint64_t bin_buf = 0;
- int bin_buf_size = 0;
- const struct zint_seg *last_seg = &segs[seg_count - 1];
- last_EOT = last_seg->source[last_seg->length - 1] == 4; /* EOT */
- if (last_EOT && last_seg->length > 1) {
- last_RSEOT = last_seg->source[last_seg->length - 2] == 30; /* RS */
- }
- for (i = 0; i < seg_count; i++) {
- ap = dc_encode_message(symbol, segs[i].source, segs[i].length, segs[i].eci, i == seg_count - 1 /*last_seg*/,
- last_EOT, last_RSEOT, ap, codeword_array, &encoding_mode, &inside_macro, &bin_buf, &bin_buf_size,
- structapp_array, p_structapp_size);
- }
- *p_binary_finish = encoding_mode == 'X';
- return ap + *p_structapp_size;
- }
- /* Convert codewords to binary data stream */
- static int dc_make_dotstream(const unsigned char masked_array[], const int array_length, char dot_stream[]) {
- int i;
- int bp = 0;
- /* Mask value is encoded as two dots */
- bp = bin_append_posn(masked_array[0], 2, dot_stream, bp);
- /* The rest of the data uses 9-bit dot patterns from Annex C */
- for (i = 1; i < array_length; i++) {
- bp = bin_append_posn(dc_dot_patterns[masked_array[i]], 9, dot_stream, bp);
- }
- return bp;
- }
- /* Determines if a given dot is a reserved corner dot
- * to be used by one of the last six bits
- */
- static int dc_is_corner(const int column, const int row, const int width, const int height) {
- /* Top Left */
- if ((column == 0) && (row == 0)) {
- return 1;
- }
- /* Top Right */
- if (height & 1) {
- if (((column == width - 2) && (row == 0))
- || ((column == width - 1) && (row == 1))) {
- return 1;
- }
- } else {
- if ((column == width - 1) && (row == 0)) {
- return 1;
- }
- }
- /* Bottom Left */
- if (height & 1) {
- if ((column == 0) && (row == height - 1)) {
- return 1;
- }
- } else {
- if (((column == 0) && (row == height - 2))
- || ((column == 1) && (row == height - 1))) {
- return 1;
- }
- }
- /* Bottom Right */
- if (((column == width - 2) && (row == height - 1))
- || ((column == width - 1) && (row == height - 2))) {
- return 1;
- }
- return 0;
- }
- /* Place the dots in the symbol*/
- static void dc_fold_dotstream(const char dot_stream[], const int width, const int height, char dot_array[]) {
- int column, row;
- int position = 0;
- if (height & 1) {
- /* Horizontal folding */
- for (row = 0; row < height; row++) {
- for (column = 0; column < width; column++) {
- if (!((column + row) & 1)) {
- if (dc_is_corner(column, row, width, height)) {
- dot_array[(row * width) + column] = 'C';
- } else {
- dot_array[((height - row - 1) * width) + column] = dot_stream[position++];
- }
- } else {
- dot_array[((height - row - 1) * width) + column] = ' '; /* Non-data position */
- }
- }
- }
- /* Corners */
- dot_array[width - 2] = dot_stream[position++];
- dot_array[(height * width) - 2] = dot_stream[position++];
- dot_array[(width * 2) - 1] = dot_stream[position++];
- dot_array[((height - 1) * width) - 1] = dot_stream[position++];
- dot_array[0] = dot_stream[position++];
- dot_array[(height - 1) * width] = dot_stream[position];
- } else {
- /* Vertical folding */
- for (column = 0; column < width; column++) {
- for (row = 0; row < height; row++) {
- if (!((column + row) & 1)) {
- if (dc_is_corner(column, row, width, height)) {
- dot_array[(row * width) + column] = 'C';
- } else {
- dot_array[(row * width) + column] = dot_stream[position++];
- }
- } else {
- dot_array[(row * width) + column] = ' '; /* Non-data position */
- }
- }
- }
- /* Corners */
- dot_array[((height - 1) * width) - 1] = dot_stream[position++];
- dot_array[(height - 2) * width] = dot_stream[position++];
- dot_array[(height * width) - 2] = dot_stream[position++];
- dot_array[((height - 1) * width) + 1] = dot_stream[position++];
- dot_array[width - 1] = dot_stream[position++];
- dot_array[0] = dot_stream[position];
- }
- }
- static void dc_apply_mask(const int mask, const int data_length, unsigned char *masked_codeword_array,
- const unsigned char *codeword_array, const int ecc_length) {
- int weight = 0;
- int j;
- assert(mask >= 0 && mask <= 3); /* Suppress clang-analyzer taking default branch */
- assert(data_length > 0); /* Suppress clang-analyzer-core.UndefinedBinaryOperatorResult */
- switch (mask) {
- case 0:
- masked_codeword_array[0] = 0;
- for (j = 0; j < data_length; j++) {
- masked_codeword_array[j + 1] = codeword_array[j];
- }
- break;
- case 1:
- masked_codeword_array[0] = 1;
- for (j = 0; j < data_length; j++) {
- masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113;
- weight += 3;
- }
- break;
- case 2:
- masked_codeword_array[0] = 2;
- for (j = 0; j < data_length; j++) {
- masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113;
- weight += 7;
- }
- break;
- case 3:
- masked_codeword_array[0] = 3;
- for (j = 0; j < data_length; j++) {
- masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113;
- weight += 17;
- }
- break;
- }
- dc_rsencode(data_length + 1, ecc_length, masked_codeword_array);
- }
- static void dc_force_corners(const int width, const int height, char *dot_array) {
- if (width & 1) {
- /* "Vertical" symbol */
- dot_array[0] = '1';
- dot_array[width - 1] = '1';
- dot_array[(height - 2) * width] = '1';
- dot_array[((height - 1) * width) - 1] = '1';
- dot_array[((height - 1) * width) + 1] = '1';
- dot_array[(height * width) - 2] = '1';
- } else {
- /* "Horizontal" symbol */
- dot_array[0] = '1';
- dot_array[width - 2] = '1';
- dot_array[(2 * width) - 1] = '1';
- dot_array[((height - 1) * width) - 1] = '1';
- dot_array[(height - 1) * width] = '1';
- dot_array[(height * width) - 2] = '1';
- }
- }
- INTERNAL int dotcode(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
- int warn_number = 0;
- int i, j, k;
- int jc, n_dots;
- int data_length, ecc_length;
- int min_dots, min_area;
- int height, width;
- int mask_score[8];
- int user_mask;
- int dot_stream_length;
- int high_score, best_mask;
- int binary_finish = 0;
- unsigned char structapp_array[5];
- int structapp_size = 0;
- int padding_dots;
- const int gs1 = (symbol->input_mode & 0x07) == GS1_MODE;
- const int debug_print = (symbol->debug & ZINT_DEBUG_PRINT);
- /* Allow 4 codewords per input + 2 (FNC) + seg_count * 4 (ECI) + 2 (special char 1st position)
- + 5 (Structured Append) + 10 (PAD) */
- const int codeword_array_len = segs_length(segs, seg_count) * 4 + 2 + seg_count * 4 + 2 + 5 + 10;
- unsigned char *codeword_array = (unsigned char *) z_alloca(codeword_array_len);
- char *dot_stream;
- char *dot_array;
- unsigned char *masked_codeword_array;
- if (symbol->eci > 811799) {
- return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 525, "ECI code '%d' out of range (0 to 811799)",
- symbol->eci);
- }
- user_mask = (symbol->option_3 >> 8) & 0x0F; /* User mask is mask + 1, so >= 1 and <= 8 */
- if (user_mask > 8) {
- user_mask = 0; /* Ignore */
- }
- if (symbol->structapp.count) {
- if (symbol->structapp.count < 2 || symbol->structapp.count > 35) {
- return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 730,
- "Structured Append count '%d' out of range (2 to 35)", symbol->structapp.count);
- }
- if (symbol->structapp.index < 1 || symbol->structapp.index > symbol->structapp.count) {
- return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 731,
- "Structured Append index '%1$d' out of range (1 to count %2$d)",
- symbol->structapp.index, symbol->structapp.count);
- }
- if (symbol->structapp.id[0]) {
- return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 732, "Structured Append ID not available for DotCode");
- }
- }
- /* GS1 General Specifications 22.0 section 5.8.2 says Structured Append and ECIs not supported
- for GS1 DotCode so check and return ZINT_WARN_NONCOMPLIANT if either true */
- if (gs1 && warn_number == 0) {
- for (i = 0; i < seg_count; i++) {
- if (segs[i].eci) {
- warn_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 733,
- "Using ECI in GS1 mode not supported by GS1 standards");
- break;
- }
- }
- if (warn_number == 0 && symbol->structapp.count) {
- warn_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 734,
- "Using Structured Append in GS1 mode not supported by GS1 standards");
- }
- }
- data_length = dc_encode_message_segs(symbol, segs, seg_count, codeword_array, &binary_finish, structapp_array,
- &structapp_size);
- /* Suppresses clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult/uninitialized.ArraySubscript
- * warnings */
- assert(data_length > 0);
- ecc_length = 3 + (data_length / 2);
- min_dots = 9 * (data_length + 3 + (data_length / 2)) + 2;
- min_area = min_dots * 2;
- if (symbol->option_2 == 0) {
- /* Automatic sizing */
- /* Following Rule 3 (Section 5.2.2) and applying a recommended width to height ratio 3:2 */
- /* Eliminates under sized symbols */
- float h = (float) (sqrt(min_area * 0.666));
- float w = (float) (sqrt(min_area * 1.5));
- height = (int) h;
- width = (int) w;
- if (((width + height) & 1) == 1) {
- if ((width * height) < min_area) {
- width++;
- height++;
- }
- } else {
- if ((h * width) < (w * height)) {
- width++;
- if ((width * height) < min_area) {
- width--;
- height++;
- if ((width * height) < min_area) {
- width += 2;
- }
- }
- } else {
- height++;
- if ((width * height) < min_area) {
- width++;
- height--;
- if ((width * height) < min_area) {
- height += 2;
- }
- }
- }
- }
- } else {
- /* User defined width */
- /* Eliminates under sized symbols */
- width = symbol->option_2;
- height = (min_area + (width - 1)) / width;
- if (!((width + height) & 1)) {
- height++;
- }
- }
- if (debug_print) {
- printf("Width = %d, Height = %d\n", width, height);
- }
- if ((height > 200) || (width > 200)) {
- if (height > 200 && width > 200) {
- errtxtf(0, symbol, 526, "Symbol size '%1$dx%2$d' (WxH) is too large", width, height);
- } else {
- errtxtf(0, symbol, 528, "Symbol %1$s '%2$d' is too large",
- width > 200 ? "width" : "height", width > 200 ? width : height);
- }
- return ZINT_ERROR_INVALID_OPTION;
- }
- if ((height < 5) || (width < 5)) {
- if (height < 5 && width < 5) { /* Won't happen as if width < 5, min height is 19 */
- errtxtf(0, symbol, 527, "Symbol size '%1$dx%2$d' (WxH) is too small", width, height); /* Not reached */
- } else {
- errtxtf(0, symbol, 529, "Symbol %1$s '%2$d' is too small",
- width < 5 ? "width" : "height", width < 5 ? width : height);
- }
- return ZINT_ERROR_INVALID_OPTION;
- }
- n_dots = (height * width) / 2;
- dot_stream = (char *) z_alloca(height * width * 3);
- dot_array = (char *) z_alloca(width * height);
- /* Add pad characters */
- padding_dots = n_dots - min_dots; /* get the number of free dots available for padding */
- if (padding_dots >= 9) {
- int is_first = 1; /* first padding character flag */
- int padp = data_length - structapp_size;
- while (padding_dots >= 9) {
- if (padding_dots < 18 && (data_length & 1) == 0) {
- padding_dots -= 9;
- } else if (padding_dots >= 18) {
- if ((data_length & 1) == 0) {
- padding_dots -= 9;
- } else {
- padding_dots -= 18;
- }
- } else {
- break; /* not enough padding dots left for padding */
- }
- if (is_first && binary_finish) {
- codeword_array[padp++] = 109;
- } else {
- codeword_array[padp++] = 106;
- }
- data_length++;
- is_first = 0;
- }
- if (structapp_size) {
- if (structapp_array[0] == 109) { /* Binary latch no longer valid */
- structapp_array[0] = 106;
- }
- for (i = 0; i < structapp_size; i++) {
- codeword_array[padp++] = structapp_array[i];
- }
- }
- } else if (structapp_size) {
- data_length -= structapp_size;
- for (i = 0; i < structapp_size; i++) {
- codeword_array[data_length++] = structapp_array[i];
- }
- }
- if (debug_print) {
- printf("Codeword length = %d, ECC length = %d\n", data_length, ecc_length);
- fputs("Codewords:", stdout);
- for (i = 0; i < data_length; i++) {
- printf(" %d", codeword_array[i]);
- }
- fputc('\n', stdout);
- }
- #ifdef ZINT_TEST
- if (symbol->debug & ZINT_DEBUG_TEST) {
- debug_test_codeword_dump(symbol, codeword_array, data_length);
- }
- #endif
- ecc_length = 3 + (data_length / 2);
- masked_codeword_array = (unsigned char *) z_alloca(data_length + 1 + ecc_length);
- if (user_mask) {
- best_mask = user_mask - 1;
- if (debug_print) {
- printf("Applying mask %d (specified)\n", best_mask);
- }
- } else {
- /* Evaluate data mask options */
- for (i = 0; i < 4; i++) {
- dc_apply_mask(i, data_length, masked_codeword_array, codeword_array, ecc_length);
- dot_stream_length = dc_make_dotstream(masked_codeword_array, (data_length + ecc_length + 1), dot_stream);
- /* Add pad bits */
- for (jc = dot_stream_length; jc < n_dots; jc++) {
- dot_stream[dot_stream_length++] = '1';
- }
- dc_fold_dotstream(dot_stream, width, height, dot_array);
- mask_score[i] = dc_score_array(dot_array, height, width);
- if (debug_print) {
- printf("Mask %d score is %d\n", i, mask_score[i]);
- }
- }
- high_score = mask_score[0];
- best_mask = 0;
- for (i = 1; i < 4; i++) {
- if (mask_score[i] >= high_score) {
- high_score = mask_score[i];
- best_mask = i;
- }
- }
- /* Re-evaluate using forced corners if needed */
- if (high_score <= (height * width) / 2) {
- if (debug_print) {
- printf("High score %d <= %d (height * width) / 2\n", high_score, (height * width) / 2);
- }
- for (i = 0; i < 4; i++) {
- dc_apply_mask(i, data_length, masked_codeword_array, codeword_array, ecc_length);
- dot_stream_length = dc_make_dotstream(masked_codeword_array, (data_length + ecc_length + 1),
- dot_stream);
- /* Add pad bits */
- for (jc = dot_stream_length; jc < n_dots; jc++) {
- dot_stream[dot_stream_length++] = '1';
- }
- dc_fold_dotstream(dot_stream, width, height, dot_array);
- dc_force_corners(width, height, dot_array);
- mask_score[i + 4] = dc_score_array(dot_array, height, width);
- if (debug_print) {
- printf("Mask %d score is %d\n", i + 4, mask_score[i + 4]);
- }
- }
- for (i = 4; i < 8; i++) {
- if (mask_score[i] >= high_score) {
- high_score = mask_score[i];
- best_mask = i;
- }
- }
- }
- if (debug_print) {
- printf("Applying mask %d, high_score %d\n", best_mask, high_score);
- }
- }
- /* Apply best mask */
- dc_apply_mask(best_mask % 4, data_length, masked_codeword_array, codeword_array, ecc_length);
- if (debug_print) {
- printf("Masked codewords (%d):", data_length);
- for (i = 1; i < data_length + 1; i++) {
- printf(" [%d]", masked_codeword_array[i]);
- }
- fputc('\n', stdout);
- printf("Masked ECCs (%d):", ecc_length);
- for (i = data_length + 1; i < data_length + ecc_length + 1; i++) {
- printf(" [%d]", masked_codeword_array[i]);
- }
- fputc('\n', stdout);
- }
- dot_stream_length = dc_make_dotstream(masked_codeword_array, (data_length + ecc_length + 1), dot_stream);
- /* Add pad bits */
- for (jc = dot_stream_length; jc < n_dots; jc++) {
- dot_stream[dot_stream_length++] = '1';
- }
- if (debug_print) printf("Binary (%d): %.*s\n", dot_stream_length, dot_stream_length, dot_stream);
- dc_fold_dotstream(dot_stream, width, height, dot_array);
- if (best_mask >= 4) {
- dc_force_corners(width, height, dot_array);
- }
- /* Copy values to symbol */
- symbol->width = width;
- symbol->rows = height;
- for (k = 0; k < height; k++) {
- for (j = 0; j < width; j++) {
- if (dot_array[(k * width) + j] == '1') {
- set_module(symbol, k, j);
- }
- }
- symbol->row_height[k] = 1;
- }
- symbol->height = height;
- symbol->output_options |= BARCODE_DOTTY_MODE;
- return warn_number;
- }
- /* vim: set ts=4 sw=4 et : */
|