Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/zint/backend/dotcode.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 1 /* dotcode.c - Handles DotCode */ | |
| 2 /* | |
| 3 libzint - the open source barcode library | |
| 4 Copyright (C) 2017-2024 Robin Stuart <rstuart114@gmail.com> | |
| 5 | |
| 6 Redistribution and use in source and binary forms, with or without | |
| 7 modification, are permitted provided that the following conditions | |
| 8 are met: | |
| 9 | |
| 10 1. Redistributions of source code must retain the above copyright | |
| 11 notice, this list of conditions and the following disclaimer. | |
| 12 2. Redistributions in binary form must reproduce the above copyright | |
| 13 notice, this list of conditions and the following disclaimer in the | |
| 14 documentation and/or other materials provided with the distribution. | |
| 15 3. Neither the name of the project nor the names of its contributors | |
| 16 may be used to endorse or promote products derived from this software | |
| 17 without specific prior written permission. | |
| 18 | |
| 19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
| 20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | |
| 23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 25 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 26 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 27 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 28 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 29 SUCH DAMAGE. | |
| 30 */ | |
| 31 /* SPDX-License-Identifier: BSD-3-Clause */ | |
| 32 | |
| 33 /* | |
| 34 * Attempts to encode DotCode according to (AIMD013) ISS DotCode Rev. 4.0, DRAFT 0.15, TSC Pre-PR #5, | |
| 35 * dated May 28, 2019 | |
| 36 * Incorporating suggestions from Terry Burton at BWIPP | |
| 37 */ | |
| 38 | |
| 39 #include <assert.h> | |
| 40 #include <math.h> | |
| 41 #include <stdio.h> | |
| 42 #include "common.h" | |
| 43 #include "gs1.h" | |
| 44 | |
| 45 #define GF 113 | |
| 46 #define PM 3 | |
| 47 #define SCORE_UNLIT_EDGE -99999 | |
| 48 | |
| 49 /* DotCode symbol character dot patterns, from Annex C */ | |
| 50 static const unsigned short dc_dot_patterns[113] = { | |
| 51 0x155, 0x0ab, 0x0ad, 0x0b5, 0x0d5, 0x156, 0x15a, 0x16a, 0x1aa, 0x0ae, | |
| 52 0x0b6, 0x0ba, 0x0d6, 0x0da, 0x0ea, 0x12b, 0x12d, 0x135, 0x14b, 0x14d, | |
| 53 0x153, 0x159, 0x165, 0x169, 0x195, 0x1a5, 0x1a9, 0x057, 0x05b, 0x05d, | |
| 54 0x06b, 0x06d, 0x075, 0x097, 0x09b, 0x09d, 0x0a7, 0x0b3, 0x0b9, 0x0cb, | |
| 55 0x0cd, 0x0d3, 0x0d9, 0x0e5, 0x0e9, 0x12e, 0x136, 0x13a, 0x14e, 0x15c, | |
| 56 0x166, 0x16c, 0x172, 0x174, 0x196, 0x19a, 0x1a6, 0x1ac, 0x1b2, 0x1b4, | |
| 57 0x1ca, 0x1d2, 0x1d4, 0x05e, 0x06e, 0x076, 0x07a, 0x09e, 0x0bc, 0x0ce, | |
| 58 0x0dc, 0x0e6, 0x0ec, 0x0f2, 0x0f4, 0x117, 0x11b, 0x11d, 0x127, 0x133, | |
| 59 0x139, 0x147, 0x163, 0x171, 0x18b, 0x18d, 0x193, 0x199, 0x1a3, 0x1b1, | |
| 60 0x1c5, 0x1c9, 0x1d1, 0x02f, 0x037, 0x03b, 0x03d, 0x04f, 0x067, 0x073, | |
| 61 0x079, 0x08f, 0x0c7, 0x0e3, 0x0f1, 0x11e, 0x13c, 0x178, 0x18e, 0x19c, | |
| 62 0x1b8, 0x1c6, 0x1cc | |
| 63 }; | |
| 64 | |
| 65 /* Printed() routine from Annex A adapted to char array of ASCII 1's and 0's */ | |
| 66 static int dc_get_dot(const char Dots[], const int Hgt, const int Wid, const int x, const int y) { | |
| 67 | |
| 68 if ((x >= 0) && (x < Wid) && (y >= 0) && (y < Hgt)) { | |
| 69 if (Dots[(y * Wid) + x] == '1') { | |
| 70 return 1; | |
| 71 } | |
| 72 } | |
| 73 | |
| 74 return 0; | |
| 75 } | |
| 76 | |
| 77 static int dc_clr_col(const char *Dots, const int Hgt, const int Wid, const int x) { | |
| 78 int y; | |
| 79 for (y = x & 1; y < Hgt; y += 2) { | |
| 80 if (dc_get_dot(Dots, Hgt, Wid, x, y)) { | |
| 81 return 0; | |
| 82 } | |
| 83 } | |
| 84 | |
| 85 return 1; | |
| 86 } | |
| 87 | |
| 88 static int dc_clr_row(const char *Dots, const int Hgt, const int Wid, const int y) { | |
| 89 int x; | |
| 90 for (x = y & 1; x < Wid; x += 2) { | |
| 91 if (dc_get_dot(Dots, Hgt, Wid, x, y)) { | |
| 92 return 0; | |
| 93 } | |
| 94 } | |
| 95 | |
| 96 return 1; | |
| 97 } | |
| 98 | |
| 99 /* calc penalty for empty interior columns */ | |
| 100 static int dc_col_penalty(const char *Dots, const int Hgt, const int Wid) { | |
| 101 int x, penalty = 0, penalty_local = 0; | |
| 102 | |
| 103 for (x = 1; x < Wid - 1; x++) { | |
| 104 if (dc_clr_col(Dots, Hgt, Wid, x)) { | |
| 105 if (penalty_local == 0) { | |
| 106 penalty_local = Hgt; | |
| 107 } else { | |
| 108 penalty_local *= Hgt; | |
| 109 } | |
| 110 } else { | |
| 111 if (penalty_local) { | |
| 112 penalty += penalty_local; | |
| 113 penalty_local = 0; | |
| 114 } | |
| 115 } | |
| 116 } | |
| 117 | |
| 118 return penalty + penalty_local; | |
| 119 } | |
| 120 | |
| 121 /* calc penalty for empty interior rows */ | |
| 122 static int dc_row_penalty(const char *Dots, const int Hgt, const int Wid) { | |
| 123 int y, penalty = 0, penalty_local = 0; | |
| 124 | |
| 125 for (y = 1; y < Hgt - 1; y++) { | |
| 126 if (dc_clr_row(Dots, Hgt, Wid, y)) { | |
| 127 if (penalty_local == 0) { | |
| 128 penalty_local = Wid; | |
| 129 } else { | |
| 130 penalty_local *= Wid; | |
| 131 } | |
| 132 } else { | |
| 133 if (penalty_local) { | |
| 134 penalty += penalty_local; | |
| 135 penalty_local = 0; | |
| 136 } | |
| 137 } | |
| 138 } | |
| 139 | |
| 140 return penalty + penalty_local; | |
| 141 } | |
| 142 | |
| 143 /* Dot pattern scoring routine from Annex A */ | |
| 144 static int dc_score_array(const char Dots[], const int Hgt, const int Wid) { | |
| 145 int x, y, worstedge, first, last, sum; | |
| 146 int penalty = 0; | |
| 147 | |
| 148 /* first, guard against "pathelogical" gaps in the array | |
| 149 subtract a penalty score for empty rows/columns from total code score for each mask, | |
| 150 where the penalty is Sum(N ^ n), where N is the number of positions in a column/row, | |
| 151 and n is the number of consecutive empty rows/columns */ | |
| 152 penalty = dc_row_penalty(Dots, Hgt, Wid) + dc_col_penalty(Dots, Hgt, Wid); | |
| 153 | |
| 154 sum = 0; | |
| 155 first = -1; | |
| 156 last = -1; | |
| 157 | |
| 158 /* across the top edge, count printed dots and measure their extent */ | |
| 159 for (x = 0; x < Wid; x += 2) { | |
| 160 if (dc_get_dot(Dots, Hgt, Wid, x, 0)) { | |
| 161 if (first < 0) { | |
| 162 first = x; | |
| 163 } | |
| 164 last = x; | |
| 165 sum++; | |
| 166 } | |
| 167 } | |
| 168 if (sum == 0) { | |
| 169 return SCORE_UNLIT_EDGE; /* guard against empty top edge */ | |
| 170 } | |
| 171 | |
| 172 worstedge = sum + last - first; | |
| 173 worstedge *= Hgt; | |
| 174 | |
| 175 sum = 0; | |
| 176 first = -1; | |
| 177 last = -1; | |
| 178 | |
| 179 /* across the bottom edge, ditto */ | |
| 180 for (x = Wid & 1; x < Wid; x += 2) { | |
| 181 if (dc_get_dot(Dots, Hgt, Wid, x, Hgt - 1)) { | |
| 182 if (first < 0) { | |
| 183 first = x; | |
| 184 } | |
| 185 last = x; | |
| 186 sum++; | |
| 187 } | |
| 188 } | |
| 189 if (sum == 0) { | |
| 190 return SCORE_UNLIT_EDGE; /* guard against empty bottom edge */ | |
| 191 } | |
| 192 | |
| 193 sum += last - first; | |
| 194 sum *= Hgt; | |
| 195 if (sum < worstedge) { | |
| 196 worstedge = sum; | |
| 197 } | |
| 198 | |
| 199 sum = 0; | |
| 200 first = -1; | |
| 201 last = -1; | |
| 202 | |
| 203 /* down the left edge, ditto */ | |
| 204 for (y = 0; y < Hgt; y += 2) { | |
| 205 if (dc_get_dot(Dots, Hgt, Wid, 0, y)) { | |
| 206 if (first < 0) { | |
| 207 first = y; | |
| 208 } | |
| 209 last = y; | |
| 210 sum++; | |
| 211 } | |
| 212 } | |
| 213 if (sum == 0) { | |
| 214 return SCORE_UNLIT_EDGE; /* guard against empty left edge */ | |
| 215 } | |
| 216 | |
| 217 sum += last - first; | |
| 218 sum *= Wid; | |
| 219 if (sum < worstedge) { | |
| 220 worstedge = sum; | |
| 221 } | |
| 222 | |
| 223 sum = 0; | |
| 224 first = -1; | |
| 225 last = -1; | |
| 226 | |
| 227 /* down the right edge, ditto */ | |
| 228 for (y = Hgt & 1; y < Hgt; y += 2) { | |
| 229 if (dc_get_dot(Dots, Hgt, Wid, Wid - 1, y)) { | |
| 230 if (first < 0) { | |
| 231 first = y; | |
| 232 } | |
| 233 last = y; | |
| 234 sum++; | |
| 235 } | |
| 236 } | |
| 237 if (sum == 0) { | |
| 238 return SCORE_UNLIT_EDGE; /* guard against empty right edge */ | |
| 239 } | |
| 240 | |
| 241 sum += last - first; | |
| 242 sum *= Wid; | |
| 243 if (sum < worstedge) { | |
| 244 worstedge = sum; | |
| 245 } | |
| 246 | |
| 247 /* throughout the array, count the # of unprinted 5-somes (cross patterns) | |
| 248 plus the # of printed dots surrounded by 8 unprinted neighbors */ | |
| 249 sum = 0; | |
| 250 for (y = 0; y < Hgt; y++) { | |
| 251 for (x = y & 1; x < Wid; x += 2) { | |
| 252 if (!dc_get_dot(Dots, Hgt, Wid, x - 1, y - 1) && !dc_get_dot(Dots, Hgt, Wid, x + 1, y - 1) | |
| 253 && !dc_get_dot(Dots, Hgt, Wid, x - 1, y + 1) && !dc_get_dot(Dots, Hgt, Wid, x + 1, y + 1) | |
| 254 && (!dc_get_dot(Dots, Hgt, Wid, x, y) | |
| 255 || (!dc_get_dot(Dots, Hgt, Wid, x - 2, y) && !dc_get_dot(Dots, Hgt, Wid, x, y - 2) | |
| 256 && !dc_get_dot(Dots, Hgt, Wid, x + 2, y) && !dc_get_dot(Dots, Hgt, Wid, x, y + 2)))) { | |
| 257 sum++; | |
| 258 } | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 return (worstedge - sum * sum - penalty); | |
| 263 } | |
| 264 | |
| 265 /*------------------------------------------------------------------------- | |
| 266 // "rsencode(nd,nc)" adds "nc" R-S check words to "nd" data words in wd[] | |
| 267 // employing Galois Field GF, where GF is prime, with a prime modulus of PM | |
| 268 //-------------------------------------------------------------------------*/ | |
| 269 | |
| 270 static void dc_rsencode(const int nd, const int nc, unsigned char *wd) { | |
| 271 /* Pre-calculated coefficients for GF(113) of generator polys of degree 3 to 39. To generate run | |
| 272 "backend/tests/test_dotcode -f generate -g" and place result below */ | |
| 273 static const char coefs[820 - 5] = { /* 40*(41 + 1)/2 == 820 less 2 + 3 (degrees 1 and 2) */ | |
| 274 1, 74, 12, 62, | |
| 275 1, 106, 7, 107, 63, | |
| 276 1, 89, 13, 101, 52, 59, | |
| 277 1, 38, 107, 3, 99, 6, 42, | |
| 278 1, 111, 56, 17, 92, 1, 28, 15, | |
| 279 1, 104, 70, 77, 86, 35, 21, 45, 8, | |
| 280 1, 83, 33, 76, 51, 37, 77, 56, 80, 58, | |
| 281 1, 20, 2, 31, 9, 101, 6, 64, 55, 103, 75, | |
| 282 1, 57, 64, 105, 26, 95, 14, 60, 50, 104, 44, 63, | |
| 283 1, 55, 63, 90, 42, 43, 50, 32, 43, 4, 62, 88, 100, | |
| 284 1, 49, 72, 51, 67, 17, 18, 71, 77, 85, 38, 55, 24, 78, | |
| 285 1, 31, 94, 111, 53, 54, 51, 86, 42, 55, 90, 49, 51, 98, 65, | |
| 286 1, 90, 2, 7, 48, 17, 73, 44, 31, 47, 58, 48, 4, 56, 84, 106, | |
| 287 1, 41, 112, 22, 44, 38, 31, 83, 22, 110, 15, 31, 25, 86, 52, 58, 4, | |
| 288 1, 7, 74, 56, 87, 11, 95, 46, 25, 40, 4, 86, 101, 27, 66, 98, 66, 90, | |
| 289 1, 18, 38, 79, 25, 64, 103, 74, 79, 89, 105, 17, 30, 8, 24, 33, 14, 25, 86, | |
| 290 1, 51, 67, 90, 33, 98, 68, 83, 35, 97, 104, 92, 26, 94, 62, 34, 86, 35, 7, 13, | |
| 291 1, 37, 31, 56, 16, 88, 52, 35, 3, 59, 102, 105, 94, 69, 102, 70, 62, 74, 82, 28, 44, | |
| 292 1, 108, 59, 110, 37, 94, 85, 111, 2, 46, 110, 2, 91, 76, 29, 80, 60, 69, 25, 87, 111, 73, | |
| 293 1, 95, 11, 21, 76, 65, 106, 23, 28, 20, 77, 41, 65, 23, 58, 42, 37, 80, 32, 101, 110, 99, | |
| 294 68, | |
| 295 1, 56, 35, 44, 48, 39, 57, 70, 35, 58, 88, 89, 48, 87, 65, 40, 94, 106, 76, 96, 13, 103, | |
| 296 49, 60, | |
| 297 1, 52, 37, 17, 98, 73, 14, 68, 94, 31, 82, 76, 31, 8, 56, 6, 47, 69, 104, 18, 81, 51, | |
| 298 89, 90, 99, | |
| 299 1, 40, 91, 25, 7, 27, 42, 13, 69, 33, 49, 109, 23, 88, 73, 12, 88, 70, 67, 13, 91, 96, | |
| 300 42, 39, 36, 55, | |
| 301 1, 4, 7, 26, 11, 1, 87, 83, 53, 35, 104, 40, 54, 51, 69, 96, 108, 66, 33, 87, 75, 97, | |
| 302 89, 109, 101, 2, 54, | |
| 303 1, 9, 27, 61, 28, 56, 92, 66, 16, 74, 53, 108, 28, 95, 98, 102, 23, 41, 24, 26, 58, 20, | |
| 304 9, 102, 81, 55, 64, 44, | |
| 305 1, 24, 49, 14, 39, 24, 28, 90, 102, 88, 33, 112, 66, 63, 54, 103, 84, 47, 74, 47, 109, 99, | |
| 306 83, 11, 29, 27, 98, 100, 95, | |
| 307 1, 69, 112, 72, 104, 84, 91, 107, 84, 45, 38, 15, 21, 95, 64, 47, 86, 98, 42, 100, 77, 32, | |
| 308 18, 17, 72, 89, 70, 103, 75, 94, | |
| 309 1, 91, 48, 50, 106, 112, 18, 75, 65, 85, 11, 60, 12, 105, 7, 99, 103, 69, 51, 7, 17, 31, | |
| 310 44, 74, 107, 91, 107, 61, 81, 49, 34, | |
| 311 1, 44, 65, 54, 16, 102, 65, 20, 43, 81, 84, 108, 17, 106, 44, 109, 83, 87, 85, 96, 27, 23, | |
| 312 56, 40, 19, 34, 11, 4, 39, 84, 104, 97, | |
| 313 1, 16, 76, 42, 86, 106, 34, 8, 48, 7, 76, 16, 44, 82, 14, 7, 82, 23, 22, 89, 51, 58, | |
| 314 90, 54, 29, 67, 76, 35, 40, 9, 12, 10, 109, | |
| 315 1, 45, 88, 99, 61, 1, 57, 90, 54, 43, 53, 73, 56, 2, 19, 74, 59, 28, 11, 49, 33, 68, | |
| 316 77, 65, 13, 4, 98, 92, 38, 39, 47, 19, 60, 110, | |
| 317 1, 19, 48, 71, 86, 110, 31, 77, 87, 108, 65, 51, 79, 15, 80, 32, 56, 76, 74, 102, 2, 1, | |
| 318 4, 97, 18, 5, 107, 30, 19, 68, 50, 40, 18, 19, 78, | |
| 319 1, 54, 35, 56, 85, 69, 39, 32, 70, 102, 3, 66, 56, 68, 40, 7, 46, 2, 22, 93, 69, 71, | |
| 320 39, 11, 23, 70, 56, 46, 52, 55, 57, 95, 62, 84, 65, 18, | |
| 321 1, 46, 55, 2, 89, 67, 52, 59, 40, 107, 91, 42, 93, 72, 61, 26, 103, 86, 6, 30, 3, 84, | |
| 322 36, 38, 48, 112, 61, 50, 23, 91, 69, 91, 93, 40, 71, 63, 82, | |
| 323 1, 22, 81, 38, 41, 78, 26, 54, 93, 51, 9, 5, 102, 100, 28, 31, 44, 100, 89, 112, 74, 12, | |
| 324 54, 78, 40, 90, 85, 55, 66, 104, 32, 17, 56, 68, 15, 54, 39, 66, | |
| 325 1, 63, 79, 82, 17, 64, 60, 103, 47, 22, 66, 35, 81, 101, 60, 49, 72, 96, 8, 32, 33, 108, | |
| 326 94, 32, 74, 35, 46, 37, 61, 98, 2, 86, 75, 104, 91, 104, 106, 83, 107, | |
| 327 1, 73, 31, 81, 46, 8, 22, 25, 60, 40, 60, 17, 92, 7, 53, 84, 110, 25, 64, 112, 14, 99, | |
| 328 44, 68, 55, 97, 57, 45, 92, 30, 78, 106, 31, 63, 1, 110, 16, 13, 33, 53, | |
| 329 }; | |
| 330 static const short cinds[39 - 2] = { /* Indexes into above coefs[] array */ | |
| 331 0, 4, 9, 15, 22, 30, 39, 49, 60, 72, 85, 99, 114, 130, 147, 165, 184, 204, 225, 247, 270, 294, | |
| 332 319, 345, 372, 400, 429, 459, 490, 522, 555, 589, 624, 660, 697, 735, 774, | |
| 333 }; | |
| 334 int i, j, k, nw, start, step; | |
| 335 const char *c; | |
| 336 | |
| 337 /* Here we compute how many interleaved R-S blocks will be needed */ | |
| 338 nw = nd + nc; | |
| 339 step = (nw + GF - 2) / (GF - 1); | |
| 340 | |
| 341 /* ...& then for each such block: */ | |
| 342 for (start = 0; start < step; start++) { | |
| 343 const int ND = (nd - start + step - 1) / step; | |
| 344 const int NW = (nw - start + step - 1) / step; | |
| 345 const int NC = NW - ND; | |
| 346 unsigned char *const e = wd + start + ND * step; | |
| 347 | |
| 348 /* first set the generator polynomial "c" of order "NC": */ | |
| 349 c = coefs + cinds[NC - 3]; | |
| 350 | |
| 351 /* & then compute the corresponding checkword values into wd[] | |
| 352 ... (a) starting at wd[start] & (b) stepping by step */ | |
| 353 for (i = 0; i < NC; i++) { | |
| 354 e[i * step] = 0; | |
| 355 } | |
| 356 for (i = 0; i < ND; i++) { | |
| 357 k = (wd[start + i * step] + e[0]) % GF; | |
| 358 for (j = 0; j < NC - 1; j++) { | |
| 359 e[j * step] = (GF - ((c[j + 1] * k) % GF) + e[(j + 1) * step]) % GF; | |
| 360 } | |
| 361 e[(NC - 1) * step] = (GF - ((c[NC] * k) % GF)) % GF; | |
| 362 } | |
| 363 for (i = 0; i < NC; i++) { | |
| 364 if (e[i * step]) { | |
| 365 e[i * step] = GF - e[i * step]; | |
| 366 } | |
| 367 } | |
| 368 } | |
| 369 } | |
| 370 | |
| 371 /* Check if the next character is directly encodable in code set A (Annex F.II.D) */ | |
| 372 static int dc_datum_a(const unsigned char source[], const int length, const int position) { | |
| 373 | |
| 374 if (position < length && source[position] <= 95) { | |
| 375 return 1; | |
| 376 } | |
| 377 | |
| 378 return 0; | |
| 379 } | |
| 380 | |
| 381 /* Check if the next character is directly encodable in code set B (Annex F.II.D). | |
| 382 * Note changed to return 2 if CR/LF */ | |
| 383 static int dc_datum_b(const unsigned char source[], const int length, const int position) { | |
| 384 | |
| 385 if (position < length) { | |
| 386 if ((source[position] >= 32) && (source[position] <= 127)) { | |
| 387 return 1; | |
| 388 } | |
| 389 | |
| 390 switch (source[position]) { | |
| 391 case 9: /* HT */ | |
| 392 case 28: /* FS */ | |
| 393 case 29: /* GS */ | |
| 394 case 30: /* RS */ | |
| 395 return 1; | |
| 396 break; | |
| 397 } | |
| 398 | |
| 399 if ((position + 1 < length) && (source[position] == 13) && (source[position + 1] == 10)) { /* CRLF */ | |
| 400 return 2; | |
| 401 } | |
| 402 } | |
| 403 | |
| 404 return 0; | |
| 405 } | |
| 406 | |
| 407 /* Check if the next characters are directly encodable in code set C (Annex F.II.D) */ | |
| 408 static int dc_datum_c(const unsigned char source[], const int length, const int position) { | |
| 409 return is_twodigits(source, length, position); | |
| 410 } | |
| 411 | |
| 412 /* Checks ahead for 10 or more digits starting "17xxxxxx10..." (Annex F.II.B) */ | |
| 413 static int dc_seventeen_ten(const unsigned char source[], const int length, const int position) { | |
| 414 | |
| 415 if (position + 9 < length && source[position] == '1' && source[position + 1] == '7' | |
| 416 && source[position + 8] == '1' && source[position + 9] == '0' | |
| 417 && cnt_digits(source, length, position + 2, 6) >= 6) { | |
| 418 return 1; | |
| 419 } | |
| 420 | |
| 421 return 0; | |
| 422 } | |
| 423 | |
| 424 /* Checks how many characters ahead can be reached while dc_datum_c is true, | |
| 425 * returning the resulting number of codewords (Annex F.II.E) | |
| 426 */ | |
| 427 static int dc_ahead_c(const unsigned char source[], const int length, const int position) { | |
| 428 int count = 0; | |
| 429 int i; | |
| 430 | |
| 431 for (i = position; (i < length) && dc_datum_c(source, length, i); i += 2) { | |
| 432 count++; | |
| 433 } | |
| 434 | |
| 435 return count; | |
| 436 } | |
| 437 | |
| 438 /* Annex F.II.F */ | |
| 439 static int dc_try_c(const unsigned char source[], const int length, const int position) { | |
| 440 | |
| 441 if (position < length && z_isdigit(source[position])) { /* cnt_digits(position) > 0 */ | |
| 442 const int ahead_c_position = dc_ahead_c(source, length, position); | |
| 443 if (ahead_c_position > dc_ahead_c(source, length, position + 1)) { | |
| 444 return ahead_c_position; | |
| 445 } | |
| 446 } | |
| 447 | |
| 448 return 0; | |
| 449 } | |
| 450 | |
| 451 /* Annex F.II.G */ | |
| 452 static int dc_ahead_a(const unsigned char source[], const int length, const int position) { | |
| 453 int count = 0; | |
| 454 int i; | |
| 455 | |
| 456 for (i = position; i < length && dc_datum_a(source, length, i) && dc_try_c(source, length, i) < 2; i++) { | |
| 457 count++; | |
| 458 } | |
| 459 | |
| 460 return count; | |
| 461 } | |
| 462 | |
| 463 /* Annex F.II.H Note: changed to return number of chars encodable. Number of codewords returned in *p_nx. */ | |
| 464 static int dc_ahead_b(const unsigned char source[], const int length, const int position, int *p_nx) { | |
| 465 int count = 0; | |
| 466 int i, incr; | |
| 467 | |
| 468 for (i = position; i < length && (incr = dc_datum_b(source, length, i)) | |
| 469 && dc_try_c(source, length, i) < 2; i += incr) { | |
| 470 count++; | |
| 471 } | |
| 472 | |
| 473 if (p_nx != NULL) { | |
| 474 *p_nx = count; | |
| 475 } | |
| 476 | |
| 477 return i - position; | |
| 478 } | |
| 479 | |
| 480 /* Checks if the next character is in the range 128 to 255 (Annex F.II.I) */ | |
| 481 static int dc_binary(const unsigned char source[], const int length, const int position) { | |
| 482 | |
| 483 if (position < length && source[position] >= 128) { | |
| 484 return 1; | |
| 485 } | |
| 486 | |
| 487 return 0; | |
| 488 } | |
| 489 | |
| 490 /* Empty binary buffer */ | |
| 491 static int dc_empty_bin_buf(unsigned char *codeword_array, int ap, uint64_t *p_bin_buf, int *p_bin_buf_size) { | |
| 492 int i; | |
| 493 int lawrencium[6]; /* Reversed radix 103 values */ | |
| 494 uint64_t bin_buf = *p_bin_buf; | |
| 495 int bin_buf_size = *p_bin_buf_size; | |
| 496 | |
| 497 if (bin_buf_size) { | |
| 498 for (i = 0; i < bin_buf_size + 1; i++) { | |
| 499 lawrencium[i] = (int) (bin_buf % 103); | |
| 500 bin_buf /= 103; | |
| 501 } | |
| 502 | |
| 503 for (i = 0; i < bin_buf_size + 1; i++) { | |
| 504 codeword_array[ap++] = lawrencium[bin_buf_size - i]; | |
| 505 } | |
| 506 } | |
| 507 | |
| 508 *p_bin_buf = 0; | |
| 509 *p_bin_buf_size = 0; | |
| 510 | |
| 511 return ap; | |
| 512 } | |
| 513 | |
| 514 /* Add value to binary buffer, emptying if full */ | |
| 515 static int dc_append_to_bin_buf(unsigned char *codeword_array, int ap, unsigned int val, uint64_t *p_bin_buf, | |
| 516 int *p_bin_buf_size) { | |
| 517 | |
| 518 *p_bin_buf *= 259; | |
| 519 *p_bin_buf += val; | |
| 520 (*p_bin_buf_size)++; | |
| 521 | |
| 522 if (*p_bin_buf_size == 5) { | |
| 523 ap = dc_empty_bin_buf(codeword_array, ap, p_bin_buf, p_bin_buf_size); | |
| 524 } | |
| 525 | |
| 526 return ap; | |
| 527 } | |
| 528 | |
| 529 /* Analyse input data stream and encode using algorithm from Annex F */ | |
| 530 static int dc_encode_message(struct zint_symbol *symbol, const unsigned char source[], const int length, | |
| 531 const int eci, const int last_seg, const int last_EOT, const int last_RSEOT, | |
| 532 int ap, unsigned char *codeword_array, char *p_encoding_mode, int *p_inside_macro, | |
| 533 uint64_t *p_bin_buf, int *p_bin_buf_size, unsigned char structapp_array[], int *p_structapp_size) { | |
| 534 static const char lead_specials[] = "\x09\x1C\x1D\x1E"; /* HT, FS, GS, RS */ | |
| 535 | |
| 536 int i; | |
| 537 int position = 0; | |
| 538 char encoding_mode = *p_encoding_mode; | |
| 539 int inside_macro = *p_inside_macro; | |
| 540 uint64_t bin_buf = *p_bin_buf; | |
| 541 int bin_buf_size = *p_bin_buf_size; | |
| 542 int nx; | |
| 543 | |
| 544 const int first_seg = ap == 0; | |
| 545 const int gs1 = (symbol->input_mode & 0x07) == GS1_MODE; | |
| 546 const int debug_print = (symbol->debug & ZINT_DEBUG_PRINT); | |
| 547 | |
| 548 if (first_seg) { | |
| 549 if (symbol->output_options & READER_INIT) { | |
| 550 codeword_array[ap++] = 109; /* FNC3 */ | |
| 551 | |
| 552 } else if (!gs1 && eci == 0 && length > 2 && is_twodigits(source, length, 0)) { | |
| 553 codeword_array[ap++] = 107; /* FNC1 */ | |
| 554 | |
| 555 } else if (posn(lead_specials, source[0]) != -1) { | |
| 556 /* Prevent encodation as a macro if a special character is in first position */ | |
| 557 codeword_array[ap++] = 101; /* Latch A */ | |
| 558 codeword_array[ap++] = source[0] + 64; | |
| 559 encoding_mode = 'A'; | |
| 560 position++; | |
| 561 | |
| 562 } else if (length > 5) { /* Note assuming macro headers don't straddle segments */ | |
| 563 /* Step C1 */ | |
| 564 if (source[0] == '[' && source[1] == ')' && source[2] == '>' && source[3] == 30 /*RS*/ && last_EOT) { | |
| 565 int format_050612 = (source[4] == '0' && (source[5] == '5' || source[5] == '6')) | |
| 566 || (source[4] == '1' && source[5] == '2'); | |
| 567 inside_macro = 0; | |
| 568 if (length > 6 && format_050612 && source[6] == 29 /*GS*/ && last_RSEOT) { | |
| 569 if (source[5] == '5') { | |
| 570 inside_macro = 97; | |
| 571 } else if (source[5] == '6') { | |
| 572 inside_macro = 98; | |
| 573 } else { | |
| 574 inside_macro = 99; | |
| 575 } | |
| 576 } else if (!format_050612 && is_twodigits(source, length, 4) ) { | |
| 577 inside_macro = 100; /* Note no longer using for malformed 05/06/12 */ | |
| 578 } | |
| 579 if (inside_macro) { | |
| 580 codeword_array[ap++] = 106; /* Latch B */ | |
| 581 encoding_mode = 'B'; | |
| 582 codeword_array[ap++] = inside_macro; /* Macro */ | |
| 583 if (inside_macro == 100) { | |
| 584 codeword_array[ap++] = ctoi(source[4]) + 16; | |
| 585 codeword_array[ap++] = ctoi(source[5]) + 16; | |
| 586 position += 6; | |
| 587 } else { | |
| 588 position += 7; | |
| 589 } | |
| 590 if (debug_print) printf("C1/%d ", inside_macro - 96); | |
| 591 } | |
| 592 } | |
| 593 } | |
| 594 } | |
| 595 | |
| 596 if (eci > 0) { | |
| 597 if (encoding_mode == 'X') { | |
| 598 if (eci <= 0xFF) { | |
| 599 ap = dc_append_to_bin_buf(codeword_array, ap, 256, &bin_buf, &bin_buf_size); | |
| 600 ap = dc_append_to_bin_buf(codeword_array, ap, eci, &bin_buf, &bin_buf_size); | |
| 601 /* Following BWIPP, assuming big-endian byte order */ | |
| 602 } else if (eci <= 0xFFFF) { | |
| 603 ap = dc_append_to_bin_buf(codeword_array, ap, 257, &bin_buf, &bin_buf_size); | |
| 604 ap = dc_append_to_bin_buf(codeword_array, ap, eci >> 8, &bin_buf, &bin_buf_size); | |
| 605 ap = dc_append_to_bin_buf(codeword_array, ap, eci & 0xFF, &bin_buf, &bin_buf_size); | |
| 606 } else { | |
| 607 ap = dc_append_to_bin_buf(codeword_array, ap, 258, &bin_buf, &bin_buf_size); | |
| 608 ap = dc_append_to_bin_buf(codeword_array, ap, eci >> 16, &bin_buf, &bin_buf_size); | |
| 609 ap = dc_append_to_bin_buf(codeword_array, ap, (eci >> 8) & 0xFF, &bin_buf, &bin_buf_size); | |
| 610 ap = dc_append_to_bin_buf(codeword_array, ap, eci & 0xFF, &bin_buf, &bin_buf_size); | |
| 611 } | |
| 612 } else { | |
| 613 codeword_array[ap++] = 108; /* FNC2 */ | |
| 614 if (eci <= 39) { | |
| 615 codeword_array[ap++] = eci; | |
| 616 } else { | |
| 617 /* the next three codewords valued A, B & C encode the ECI value of | |
| 618 (A - 40) * 12769 + B * 113 + C + 40 (Section 5.2.1) */ | |
| 619 int a, b, c; | |
| 620 a = (eci - 40) / 12769; | |
| 621 b = ((eci - 40) - (12769 * a)) / 113; | |
| 622 c = (eci - 40) - (12769 * a) - (113 * b); | |
| 623 | |
| 624 codeword_array[ap++] = a + 40; | |
| 625 codeword_array[ap++] = b; | |
| 626 codeword_array[ap++] = c; | |
| 627 } | |
| 628 } | |
| 629 } | |
| 630 | |
| 631 while (position < length) { | |
| 632 /* Step A */ | |
| 633 if (last_seg && (position == length - 2) && (inside_macro != 0) && (inside_macro != 100)) { | |
| 634 /* inside_macro only gets set to 97, 98 or 99 if the last two characters are RS/EOT */ | |
| 635 position += 2; | |
| 636 if (debug_print) fputs("A ", stdout); | |
| 637 continue; | |
| 638 } | |
| 639 | |
| 640 /* Step B */ | |
| 641 if (last_seg && (position == length - 1) && (inside_macro == 100)) { | |
| 642 /* inside_macro only gets set to 100 if the last character is EOT */ | |
| 643 position++; | |
| 644 if (debug_print) fputs("B ", stdout); | |
| 645 continue; | |
| 646 } | |
| 647 | |
| 648 if (encoding_mode == 'C') { | |
| 649 | |
| 650 /* Step C2 */ | |
| 651 if (dc_seventeen_ten(source, length, position)) { | |
| 652 codeword_array[ap++] = 100; /* (17)...(10) */ | |
| 653 codeword_array[ap++] = to_int(source + position + 2, 2); | |
| 654 codeword_array[ap++] = to_int(source + position + 4, 2); | |
| 655 codeword_array[ap++] = to_int(source + position + 6, 2); | |
| 656 position += 10; | |
| 657 if (debug_print) fputs("C2/1 ", stdout); | |
| 658 continue; | |
| 659 } | |
| 660 | |
| 661 if (dc_datum_c(source, length, position) || (gs1 && source[position] == '\x1D')) { | |
| 662 if (source[position] == '\x1D') { | |
| 663 codeword_array[ap++] = 107; /* FNC1 */ | |
| 664 position++; | |
| 665 } else { | |
| 666 codeword_array[ap++] = to_int(source + position, 2); | |
| 667 position += 2; | |
| 668 } | |
| 669 if (debug_print) fputs("C2/2 ", stdout); | |
| 670 continue; | |
| 671 } | |
| 672 | |
| 673 /* Step C3 */ | |
| 674 if (dc_binary(source, length, position)) { | |
| 675 /* cnt_digits(position + 1) > 0 */ | |
| 676 if (position + 1 < length && z_isdigit(source[position + 1])) { | |
| 677 if ((source[position] - 128) < 32) { | |
| 678 codeword_array[ap++] = 110; /* Upper Shift A */ | |
| 679 codeword_array[ap++] = source[position] - 128 + 64; | |
| 680 } else { | |
| 681 codeword_array[ap++] = 111; /* Upper Shift B */ | |
| 682 codeword_array[ap++] = source[position] - 128 - 32; | |
| 683 } | |
| 684 position++; | |
| 685 } else { | |
| 686 codeword_array[ap++] = 112; /* Bin Latch */ | |
| 687 encoding_mode = 'X'; | |
| 688 } | |
| 689 if (debug_print) fputs("C3 ", stdout); | |
| 690 continue; | |
| 691 } | |
| 692 | |
| 693 /* Step C4 */ | |
| 694 { | |
| 695 const int m = dc_ahead_a(source, length, position); | |
| 696 const int n = dc_ahead_b(source, length, position, &nx); | |
| 697 if (m > n) { | |
| 698 codeword_array[ap++] = 101; /* Latch A */ | |
| 699 encoding_mode = 'A'; | |
| 700 } else { | |
| 701 if (nx >= 1 && nx <= 4) { | |
| 702 codeword_array[ap++] = 101 + nx; /* nx Shift B */ | |
| 703 | |
| 704 for (i = 0; i < nx; i++) { | |
| 705 if (source[position] >= 32) { | |
| 706 codeword_array[ap++] = source[position] - 32; | |
| 707 } else if (source[position] == 13) { /* CR/LF */ | |
| 708 codeword_array[ap++] = 96; | |
| 709 position++; | |
| 710 } else { | |
| 711 switch (source[position]) { | |
| 712 case 9: codeword_array[ap++] = 97; break; /* HT */ | |
| 713 case 28: codeword_array[ap++] = 98; break; /* FS */ | |
| 714 case 29: codeword_array[ap++] = 99; break; /* GS */ | |
| 715 case 30: codeword_array[ap++] = 100; break; /* RS */ | |
| 716 } | |
| 717 } | |
| 718 position++; | |
| 719 } | |
| 720 } else { | |
| 721 codeword_array[ap++] = 106; /* Latch B */ | |
| 722 encoding_mode = 'B'; | |
| 723 } | |
| 724 } | |
| 725 if (debug_print) fputs("C4 ", stdout); | |
| 726 continue; | |
| 727 } | |
| 728 } /* encoding_mode == 'C' */ | |
| 729 | |
| 730 if (encoding_mode == 'B') { | |
| 731 /* Step D1 */ | |
| 732 const int n = dc_try_c(source, length, position); | |
| 733 | |
| 734 if (n >= 2) { | |
| 735 if (n <= 4) { | |
| 736 codeword_array[ap++] = 103 + (n - 2); /* nx Shift C */ | |
| 737 for (i = 0; i < n; i++) { | |
| 738 codeword_array[ap++] = to_int(source + position, 2); | |
| 739 position += 2; | |
| 740 } | |
| 741 } else { | |
| 742 codeword_array[ap++] = 106; /* Latch C */ | |
| 743 encoding_mode = 'C'; | |
| 744 } | |
| 745 if (debug_print) fputs("D1 ", stdout); | |
| 746 continue; | |
| 747 } | |
| 748 | |
| 749 /* Step D2 */ | |
| 750 if (gs1 && source[position] == '\x1D') { | |
| 751 codeword_array[ap++] = 107; /* FNC1 */ | |
| 752 position++; | |
| 753 if (debug_print) fputs("D2/1 ", stdout); | |
| 754 continue; | |
| 755 } | |
| 756 | |
| 757 if (dc_datum_b(source, length, position)) { | |
| 758 int done = 0; | |
| 759 | |
| 760 if ((source[position] >= 32) && (source[position] <= 127)) { | |
| 761 codeword_array[ap++] = source[position] - 32; | |
| 762 done = 1; | |
| 763 | |
| 764 } else if (source[position] == 13) { | |
| 765 /* CR/LF */ | |
| 766 codeword_array[ap++] = 96; | |
| 767 position++; | |
| 768 done = 1; | |
| 769 | |
| 770 } else if (!first_seg || position != 0) { | |
| 771 /* HT, FS, GS and RS in the first data position would be interpreted as a macro | |
| 772 * (see table 2) */ | |
| 773 switch (source[position]) { | |
| 774 case 9: codeword_array[ap++] = 97; break; /* HT */ | |
| 775 case 28: codeword_array[ap++] = 98; break; /* FS */ | |
| 776 case 29: codeword_array[ap++] = 99; break; /* GS */ | |
| 777 case 30: codeword_array[ap++] = 100; break; /* RS */ | |
| 778 } | |
| 779 done = 1; | |
| 780 } | |
| 781 | |
| 782 if (done == 1) { | |
| 783 position++; | |
| 784 if (debug_print) fputs("D2/2 ", stdout); | |
| 785 continue; | |
| 786 } | |
| 787 } | |
| 788 | |
| 789 /* Step D3 */ | |
| 790 if (dc_binary(source, length, position)) { | |
| 791 if (dc_datum_b(source, length, position + 1)) { | |
| 792 if ((source[position] - 128) < 32) { | |
| 793 codeword_array[ap++] = 110; /* Bin Shift A */ | |
| 794 codeword_array[ap++] = source[position] - 128 + 64; | |
| 795 } else { | |
| 796 codeword_array[ap++] = 111; /* Bin Shift B */ | |
| 797 codeword_array[ap++] = source[position] - 128 - 32; | |
| 798 } | |
| 799 position++; | |
| 800 } else { | |
| 801 codeword_array[ap++] = 112; /* Bin Latch */ | |
| 802 encoding_mode = 'X'; | |
| 803 } | |
| 804 if (debug_print) fputs("D3 ", stdout); | |
| 805 continue; | |
| 806 } | |
| 807 | |
| 808 /* Step D4 */ | |
| 809 if (dc_ahead_a(source, length, position) == 1) { | |
| 810 codeword_array[ap++] = 101; /* Shift A */ | |
| 811 if (source[position] < 32) { | |
| 812 codeword_array[ap++] = source[position] + 64; | |
| 813 } else { | |
| 814 codeword_array[ap++] = source[position] - 32; | |
| 815 } | |
| 816 position++; | |
| 817 } else { | |
| 818 codeword_array[ap++] = 102; /* Latch A */ | |
| 819 encoding_mode = 'A'; | |
| 820 } | |
| 821 if (debug_print) fputs("D4 ", stdout); | |
| 822 continue; | |
| 823 } /* encoding_mode == 'B' */ | |
| 824 | |
| 825 if (encoding_mode == 'A') { | |
| 826 /* Step E1 */ | |
| 827 const int n = dc_try_c(source, length, position); | |
| 828 if (n >= 2) { | |
| 829 if (n <= 4) { | |
| 830 codeword_array[ap++] = 103 + (n - 2); /* nx Shift C */ | |
| 831 for (i = 0; i < n; i++) { | |
| 832 codeword_array[ap++] = to_int(source + position, 2); | |
| 833 position += 2; | |
| 834 } | |
| 835 } else { | |
| 836 codeword_array[ap++] = 106; /* Latch C */ | |
| 837 encoding_mode = 'C'; | |
| 838 } | |
| 839 if (debug_print) fputs("E1 ", stdout); | |
| 840 continue; | |
| 841 } | |
| 842 | |
| 843 /* Step E2 */ | |
| 844 if (gs1 && source[position] == '\x1D') { | |
| 845 /* Note: this branch probably never reached as no reason to be in Code Set A for GS1 data */ | |
| 846 codeword_array[ap++] = 107; /* FNC1 */ | |
| 847 position++; | |
| 848 if (debug_print) fputs("E2/1 ", stdout); | |
| 849 continue; | |
| 850 } | |
| 851 if (dc_datum_a(source, length, position)) { | |
| 852 if (source[position] < 32) { | |
| 853 codeword_array[ap++] = source[position] + 64; | |
| 854 } else { | |
| 855 codeword_array[ap++] = source[position] - 32; | |
| 856 } | |
| 857 position++; | |
| 858 if (debug_print) fputs("E2/2 ", stdout); | |
| 859 continue; | |
| 860 } | |
| 861 | |
| 862 /* Step E3 */ | |
| 863 if (dc_binary(source, length, position)) { | |
| 864 if (dc_datum_a(source, length, position + 1)) { | |
| 865 if ((source[position] - 128) < 32) { | |
| 866 codeword_array[ap++] = 110; /* Bin Shift A */ | |
| 867 codeword_array[ap++] = source[position] - 128 + 64; | |
| 868 } else { | |
| 869 codeword_array[ap++] = 111; /* Bin Shift B */ | |
| 870 codeword_array[ap++] = source[position] - 128 - 32; | |
| 871 } | |
| 872 position++; | |
| 873 } else { | |
| 874 codeword_array[ap++] = 112; /* Bin Latch */ | |
| 875 encoding_mode = 'X'; | |
| 876 } | |
| 877 if (debug_print) fputs("E3 ", stdout); | |
| 878 continue; | |
| 879 } | |
| 880 | |
| 881 /* Step E4 */ | |
| 882 dc_ahead_b(source, length, position, &nx); | |
| 883 | |
| 884 if (nx >= 1 && nx <= 6) { | |
| 885 codeword_array[ap++] = 95 + nx; /* nx Shift B */ | |
| 886 for (i = 0; i < nx; i++) { | |
| 887 if (source[position] >= 32) { | |
| 888 codeword_array[ap++] = source[position] - 32; | |
| 889 } else if (source[position] == 13) { /* CR/LF */ | |
| 890 codeword_array[ap++] = 96; | |
| 891 position++; | |
| 892 } else { | |
| 893 switch (source[position]) { | |
| 894 case 9: codeword_array[ap++] = 97; break; /* HT */ | |
| 895 case 28: codeword_array[ap++] = 98; break; /* FS */ | |
| 896 case 29: codeword_array[ap++] = 99; break; /* GS */ | |
| 897 case 30: codeword_array[ap++] = 100; break; /* RS */ | |
| 898 } | |
| 899 } | |
| 900 position++; | |
| 901 } | |
| 902 } else { | |
| 903 codeword_array[ap++] = 102; /* Latch B */ | |
| 904 encoding_mode = 'B'; | |
| 905 } | |
| 906 if (debug_print) fputs("E4 ", stdout); | |
| 907 continue; | |
| 908 } /* encoding_mode == 'A' */ | |
| 909 | |
| 910 /* Step F1 */ | |
| 911 if (encoding_mode == 'X') { | |
| 912 const int n = dc_try_c(source, length, position); | |
| 913 | |
| 914 if (n >= 2) { | |
| 915 ap = dc_empty_bin_buf(codeword_array, ap, &bin_buf, &bin_buf_size); | |
| 916 | |
| 917 if (n <= 7) { | |
| 918 codeword_array[ap++] = 101 + n; /* Interrupt for nx Shift C */ | |
| 919 for (i = 0; i < n; i++) { | |
| 920 codeword_array[ap++] = to_int(source + position, 2); | |
| 921 position += 2; | |
| 922 } | |
| 923 } else { | |
| 924 codeword_array[ap++] = 111; /* Terminate with Latch to C */ | |
| 925 encoding_mode = 'C'; | |
| 926 } | |
| 927 if (debug_print) fputs("F1 ", stdout); | |
| 928 continue; | |
| 929 } | |
| 930 | |
| 931 /* Step F2 */ | |
| 932 /* Section 5.2.1.1 para D.2.i states: | |
| 933 * "Groups of six codewords, each valued between 0 and 102, are radix converted from | |
| 934 * base 103 into five base 259 values..." | |
| 935 */ | |
| 936 if (dc_binary(source, length, position) | |
| 937 || dc_binary(source, length, position + 1) | |
| 938 || dc_binary(source, length, position + 2) | |
| 939 || dc_binary(source, length, position + 3)) { | |
| 940 ap = dc_append_to_bin_buf(codeword_array, ap, source[position], &bin_buf, &bin_buf_size); | |
| 941 position++; | |
| 942 if (debug_print) fputs("F2 ", stdout); | |
| 943 continue; | |
| 944 } | |
| 945 | |
| 946 /* Step F3 */ | |
| 947 ap = dc_empty_bin_buf(codeword_array, ap, &bin_buf, &bin_buf_size); /* Empty binary buffer */ | |
| 948 | |
| 949 if (dc_ahead_a(source, length, position) > dc_ahead_b(source, length, position, NULL)) { | |
| 950 codeword_array[ap++] = 109; /* Terminate with Latch to A */ | |
| 951 encoding_mode = 'A'; | |
| 952 } else { | |
| 953 codeword_array[ap++] = 110; /* Terminate with Latch to B */ | |
| 954 encoding_mode = 'B'; | |
| 955 } | |
| 956 if (debug_print) fputs("F3 ", stdout); | |
| 957 } /* encoding_mode == 'X' */ | |
| 958 } | |
| 959 | |
| 960 if (last_seg) { | |
| 961 if (encoding_mode == 'X' && bin_buf_size != 0) { | |
| 962 /* Empty binary buffer */ | |
| 963 ap = dc_empty_bin_buf(codeword_array, ap, &bin_buf, &bin_buf_size); | |
| 964 } | |
| 965 | |
| 966 if (symbol->structapp.count) { | |
| 967 int sp = 0; | |
| 968 /* Need Code Set A or B - choosing A here (TEC-IT chooses B) */ | |
| 969 if (encoding_mode == 'C') { | |
| 970 structapp_array[sp++] = 101; /* Latch A */ | |
| 971 } else if (encoding_mode == 'X') { | |
| 972 structapp_array[sp++] = 109; /* Terminate with Latch A */ | |
| 973 } | |
| 974 if (symbol->structapp.index < 10) { | |
| 975 structapp_array[sp++] = 16 + symbol->structapp.index; /* '0' + index for 1-9 */ | |
| 976 } else { | |
| 977 structapp_array[sp++] = 33 + symbol->structapp.index - 10; /* 'A' + index for A-Z */ | |
| 978 } | |
| 979 if (symbol->structapp.count < 10) { | |
| 980 structapp_array[sp++] = 16 + symbol->structapp.count; /* '0' + count for 1-9 */ | |
| 981 } else { | |
| 982 structapp_array[sp++] = 33 + symbol->structapp.count - 10; /* 'A' + count for A-Z */ | |
| 983 } | |
| 984 structapp_array[sp++] = 108; /* FNC2 as last codeword */ | |
| 985 *p_structapp_size = sp; | |
| 986 } | |
| 987 } | |
| 988 | |
| 989 if (debug_print) { | |
| 990 fputc('\n', stdout); | |
| 991 } | |
| 992 | |
| 993 *p_encoding_mode = encoding_mode; | |
| 994 *p_inside_macro = inside_macro; | |
| 995 *p_bin_buf = bin_buf; | |
| 996 *p_bin_buf_size = bin_buf_size; | |
| 997 | |
| 998 return ap; | |
| 999 } | |
| 1000 | |
| 1001 /* Call `dc_encode_message()` for each segment */ | |
| 1002 static int dc_encode_message_segs(struct zint_symbol *symbol, const struct zint_seg segs[], const int seg_count, | |
| 1003 unsigned char *codeword_array, int *p_binary_finish, unsigned char structapp_array[], | |
| 1004 int *p_structapp_size) { | |
| 1005 int i; | |
| 1006 | |
| 1007 int last_EOT = 0; | |
| 1008 int last_RSEOT = 0; | |
| 1009 int ap = 0; | |
| 1010 char encoding_mode = 'C'; | |
| 1011 int inside_macro = 0; | |
| 1012 uint64_t bin_buf = 0; | |
| 1013 int bin_buf_size = 0; | |
| 1014 | |
| 1015 const struct zint_seg *last_seg = &segs[seg_count - 1]; | |
| 1016 | |
| 1017 last_EOT = last_seg->source[last_seg->length - 1] == 4; /* EOT */ | |
| 1018 if (last_EOT && last_seg->length > 1) { | |
| 1019 last_RSEOT = last_seg->source[last_seg->length - 2] == 30; /* RS */ | |
| 1020 } | |
| 1021 | |
| 1022 for (i = 0; i < seg_count; i++) { | |
| 1023 ap = dc_encode_message(symbol, segs[i].source, segs[i].length, segs[i].eci, i == seg_count - 1 /*last_seg*/, | |
| 1024 last_EOT, last_RSEOT, ap, codeword_array, &encoding_mode, &inside_macro, &bin_buf, &bin_buf_size, | |
| 1025 structapp_array, p_structapp_size); | |
| 1026 } | |
| 1027 | |
| 1028 *p_binary_finish = encoding_mode == 'X'; | |
| 1029 | |
| 1030 return ap + *p_structapp_size; | |
| 1031 } | |
| 1032 | |
| 1033 /* Convert codewords to binary data stream */ | |
| 1034 static int dc_make_dotstream(const unsigned char masked_array[], const int array_length, char dot_stream[]) { | |
| 1035 int i; | |
| 1036 int bp = 0; | |
| 1037 | |
| 1038 /* Mask value is encoded as two dots */ | |
| 1039 bp = bin_append_posn(masked_array[0], 2, dot_stream, bp); | |
| 1040 | |
| 1041 /* The rest of the data uses 9-bit dot patterns from Annex C */ | |
| 1042 for (i = 1; i < array_length; i++) { | |
| 1043 bp = bin_append_posn(dc_dot_patterns[masked_array[i]], 9, dot_stream, bp); | |
| 1044 } | |
| 1045 | |
| 1046 return bp; | |
| 1047 } | |
| 1048 | |
| 1049 /* Determines if a given dot is a reserved corner dot | |
| 1050 * to be used by one of the last six bits | |
| 1051 */ | |
| 1052 static int dc_is_corner(const int column, const int row, const int width, const int height) { | |
| 1053 | |
| 1054 /* Top Left */ | |
| 1055 if ((column == 0) && (row == 0)) { | |
| 1056 return 1; | |
| 1057 } | |
| 1058 | |
| 1059 /* Top Right */ | |
| 1060 if (height & 1) { | |
| 1061 if (((column == width - 2) && (row == 0)) | |
| 1062 || ((column == width - 1) && (row == 1))) { | |
| 1063 return 1; | |
| 1064 } | |
| 1065 } else { | |
| 1066 if ((column == width - 1) && (row == 0)) { | |
| 1067 return 1; | |
| 1068 } | |
| 1069 } | |
| 1070 | |
| 1071 /* Bottom Left */ | |
| 1072 if (height & 1) { | |
| 1073 if ((column == 0) && (row == height - 1)) { | |
| 1074 return 1; | |
| 1075 } | |
| 1076 } else { | |
| 1077 if (((column == 0) && (row == height - 2)) | |
| 1078 || ((column == 1) && (row == height - 1))) { | |
| 1079 return 1; | |
| 1080 } | |
| 1081 } | |
| 1082 | |
| 1083 /* Bottom Right */ | |
| 1084 if (((column == width - 2) && (row == height - 1)) | |
| 1085 || ((column == width - 1) && (row == height - 2))) { | |
| 1086 return 1; | |
| 1087 } | |
| 1088 | |
| 1089 return 0; | |
| 1090 } | |
| 1091 | |
| 1092 /* Place the dots in the symbol*/ | |
| 1093 static void dc_fold_dotstream(const char dot_stream[], const int width, const int height, char dot_array[]) { | |
| 1094 int column, row; | |
| 1095 int position = 0; | |
| 1096 | |
| 1097 if (height & 1) { | |
| 1098 /* Horizontal folding */ | |
| 1099 for (row = 0; row < height; row++) { | |
| 1100 for (column = 0; column < width; column++) { | |
| 1101 if (!((column + row) & 1)) { | |
| 1102 if (dc_is_corner(column, row, width, height)) { | |
| 1103 dot_array[(row * width) + column] = 'C'; | |
| 1104 } else { | |
| 1105 dot_array[((height - row - 1) * width) + column] = dot_stream[position++]; | |
| 1106 } | |
| 1107 } else { | |
| 1108 dot_array[((height - row - 1) * width) + column] = ' '; /* Non-data position */ | |
| 1109 } | |
| 1110 } | |
| 1111 } | |
| 1112 | |
| 1113 /* Corners */ | |
| 1114 dot_array[width - 2] = dot_stream[position++]; | |
| 1115 dot_array[(height * width) - 2] = dot_stream[position++]; | |
| 1116 dot_array[(width * 2) - 1] = dot_stream[position++]; | |
| 1117 dot_array[((height - 1) * width) - 1] = dot_stream[position++]; | |
| 1118 dot_array[0] = dot_stream[position++]; | |
| 1119 dot_array[(height - 1) * width] = dot_stream[position]; | |
| 1120 } else { | |
| 1121 /* Vertical folding */ | |
| 1122 for (column = 0; column < width; column++) { | |
| 1123 for (row = 0; row < height; row++) { | |
| 1124 if (!((column + row) & 1)) { | |
| 1125 if (dc_is_corner(column, row, width, height)) { | |
| 1126 dot_array[(row * width) + column] = 'C'; | |
| 1127 } else { | |
| 1128 dot_array[(row * width) + column] = dot_stream[position++]; | |
| 1129 } | |
| 1130 } else { | |
| 1131 dot_array[(row * width) + column] = ' '; /* Non-data position */ | |
| 1132 } | |
| 1133 } | |
| 1134 } | |
| 1135 | |
| 1136 /* Corners */ | |
| 1137 dot_array[((height - 1) * width) - 1] = dot_stream[position++]; | |
| 1138 dot_array[(height - 2) * width] = dot_stream[position++]; | |
| 1139 dot_array[(height * width) - 2] = dot_stream[position++]; | |
| 1140 dot_array[((height - 1) * width) + 1] = dot_stream[position++]; | |
| 1141 dot_array[width - 1] = dot_stream[position++]; | |
| 1142 dot_array[0] = dot_stream[position]; | |
| 1143 } | |
| 1144 } | |
| 1145 | |
| 1146 static void dc_apply_mask(const int mask, const int data_length, unsigned char *masked_codeword_array, | |
| 1147 const unsigned char *codeword_array, const int ecc_length) { | |
| 1148 int weight = 0; | |
| 1149 int j; | |
| 1150 | |
| 1151 assert(mask >= 0 && mask <= 3); /* Suppress clang-analyzer taking default branch */ | |
| 1152 assert(data_length > 0); /* Suppress clang-analyzer-core.UndefinedBinaryOperatorResult */ | |
| 1153 switch (mask) { | |
| 1154 case 0: | |
| 1155 masked_codeword_array[0] = 0; | |
| 1156 for (j = 0; j < data_length; j++) { | |
| 1157 masked_codeword_array[j + 1] = codeword_array[j]; | |
| 1158 } | |
| 1159 break; | |
| 1160 case 1: | |
| 1161 masked_codeword_array[0] = 1; | |
| 1162 for (j = 0; j < data_length; j++) { | |
| 1163 masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113; | |
| 1164 weight += 3; | |
| 1165 } | |
| 1166 break; | |
| 1167 case 2: | |
| 1168 masked_codeword_array[0] = 2; | |
| 1169 for (j = 0; j < data_length; j++) { | |
| 1170 masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113; | |
| 1171 weight += 7; | |
| 1172 } | |
| 1173 break; | |
| 1174 case 3: | |
| 1175 masked_codeword_array[0] = 3; | |
| 1176 for (j = 0; j < data_length; j++) { | |
| 1177 masked_codeword_array[j + 1] = (weight + codeword_array[j]) % 113; | |
| 1178 weight += 17; | |
| 1179 } | |
| 1180 break; | |
| 1181 } | |
| 1182 | |
| 1183 dc_rsencode(data_length + 1, ecc_length, masked_codeword_array); | |
| 1184 } | |
| 1185 | |
| 1186 static void dc_force_corners(const int width, const int height, char *dot_array) { | |
| 1187 if (width & 1) { | |
| 1188 /* "Vertical" symbol */ | |
| 1189 dot_array[0] = '1'; | |
| 1190 dot_array[width - 1] = '1'; | |
| 1191 dot_array[(height - 2) * width] = '1'; | |
| 1192 dot_array[((height - 1) * width) - 1] = '1'; | |
| 1193 dot_array[((height - 1) * width) + 1] = '1'; | |
| 1194 dot_array[(height * width) - 2] = '1'; | |
| 1195 } else { | |
| 1196 /* "Horizontal" symbol */ | |
| 1197 dot_array[0] = '1'; | |
| 1198 dot_array[width - 2] = '1'; | |
| 1199 dot_array[(2 * width) - 1] = '1'; | |
| 1200 dot_array[((height - 1) * width) - 1] = '1'; | |
| 1201 dot_array[(height - 1) * width] = '1'; | |
| 1202 dot_array[(height * width) - 2] = '1'; | |
| 1203 } | |
| 1204 } | |
| 1205 | |
| 1206 INTERNAL int dotcode(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) { | |
| 1207 int warn_number = 0; | |
| 1208 int i, j, k; | |
| 1209 int jc, n_dots; | |
| 1210 int data_length, ecc_length; | |
| 1211 int min_dots, min_area; | |
| 1212 int height, width; | |
| 1213 int mask_score[8]; | |
| 1214 int user_mask; | |
| 1215 int dot_stream_length; | |
| 1216 int high_score, best_mask; | |
| 1217 int binary_finish = 0; | |
| 1218 unsigned char structapp_array[5]; | |
| 1219 int structapp_size = 0; | |
| 1220 int padding_dots; | |
| 1221 const int gs1 = (symbol->input_mode & 0x07) == GS1_MODE; | |
| 1222 const int debug_print = (symbol->debug & ZINT_DEBUG_PRINT); | |
| 1223 /* Allow 4 codewords per input + 2 (FNC) + seg_count * 4 (ECI) + 2 (special char 1st position) | |
| 1224 + 5 (Structured Append) + 10 (PAD) */ | |
| 1225 const int codeword_array_len = segs_length(segs, seg_count) * 4 + 2 + seg_count * 4 + 2 + 5 + 10; | |
| 1226 unsigned char *codeword_array = (unsigned char *) z_alloca(codeword_array_len); | |
| 1227 char *dot_stream; | |
| 1228 char *dot_array; | |
| 1229 unsigned char *masked_codeword_array; | |
| 1230 | |
| 1231 if (symbol->eci > 811799) { | |
| 1232 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 525, "ECI code '%d' out of range (0 to 811799)", | |
| 1233 symbol->eci); | |
| 1234 } | |
| 1235 | |
| 1236 user_mask = (symbol->option_3 >> 8) & 0x0F; /* User mask is mask + 1, so >= 1 and <= 8 */ | |
| 1237 if (user_mask > 8) { | |
| 1238 user_mask = 0; /* Ignore */ | |
| 1239 } | |
| 1240 | |
| 1241 if (symbol->structapp.count) { | |
| 1242 if (symbol->structapp.count < 2 || symbol->structapp.count > 35) { | |
| 1243 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 730, | |
| 1244 "Structured Append count '%d' out of range (2 to 35)", symbol->structapp.count); | |
| 1245 } | |
| 1246 if (symbol->structapp.index < 1 || symbol->structapp.index > symbol->structapp.count) { | |
| 1247 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 731, | |
| 1248 "Structured Append index '%1$d' out of range (1 to count %2$d)", | |
| 1249 symbol->structapp.index, symbol->structapp.count); | |
| 1250 } | |
| 1251 if (symbol->structapp.id[0]) { | |
| 1252 return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 732, "Structured Append ID not available for DotCode"); | |
| 1253 } | |
| 1254 } | |
| 1255 | |
| 1256 /* GS1 General Specifications 22.0 section 5.8.2 says Structured Append and ECIs not supported | |
| 1257 for GS1 DotCode so check and return ZINT_WARN_NONCOMPLIANT if either true */ | |
| 1258 if (gs1 && warn_number == 0) { | |
| 1259 for (i = 0; i < seg_count; i++) { | |
| 1260 if (segs[i].eci) { | |
| 1261 warn_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 733, | |
| 1262 "Using ECI in GS1 mode not supported by GS1 standards"); | |
| 1263 break; | |
| 1264 } | |
| 1265 } | |
| 1266 if (warn_number == 0 && symbol->structapp.count) { | |
| 1267 warn_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 734, | |
| 1268 "Using Structured Append in GS1 mode not supported by GS1 standards"); | |
| 1269 } | |
| 1270 } | |
| 1271 | |
| 1272 data_length = dc_encode_message_segs(symbol, segs, seg_count, codeword_array, &binary_finish, structapp_array, | |
| 1273 &structapp_size); | |
| 1274 | |
| 1275 /* Suppresses clang-tidy clang-analyzer-core.UndefinedBinaryOperatorResult/uninitialized.ArraySubscript | |
| 1276 * warnings */ | |
| 1277 assert(data_length > 0); | |
| 1278 | |
| 1279 ecc_length = 3 + (data_length / 2); | |
| 1280 | |
| 1281 min_dots = 9 * (data_length + 3 + (data_length / 2)) + 2; | |
| 1282 min_area = min_dots * 2; | |
| 1283 | |
| 1284 if (symbol->option_2 == 0) { | |
| 1285 /* Automatic sizing */ | |
| 1286 /* Following Rule 3 (Section 5.2.2) and applying a recommended width to height ratio 3:2 */ | |
| 1287 /* Eliminates under sized symbols */ | |
| 1288 | |
| 1289 float h = (float) (sqrt(min_area * 0.666)); | |
| 1290 float w = (float) (sqrt(min_area * 1.5)); | |
| 1291 | |
| 1292 height = (int) h; | |
| 1293 width = (int) w; | |
| 1294 | |
| 1295 if (((width + height) & 1) == 1) { | |
| 1296 if ((width * height) < min_area) { | |
| 1297 width++; | |
| 1298 height++; | |
| 1299 } | |
| 1300 } else { | |
| 1301 if ((h * width) < (w * height)) { | |
| 1302 width++; | |
| 1303 if ((width * height) < min_area) { | |
| 1304 width--; | |
| 1305 height++; | |
| 1306 if ((width * height) < min_area) { | |
| 1307 width += 2; | |
| 1308 } | |
| 1309 } | |
| 1310 } else { | |
| 1311 height++; | |
| 1312 if ((width * height) < min_area) { | |
| 1313 width++; | |
| 1314 height--; | |
| 1315 if ((width * height) < min_area) { | |
| 1316 height += 2; | |
| 1317 } | |
| 1318 } | |
| 1319 } | |
| 1320 } | |
| 1321 | |
| 1322 } else { | |
| 1323 /* User defined width */ | |
| 1324 /* Eliminates under sized symbols */ | |
| 1325 | |
| 1326 width = symbol->option_2; | |
| 1327 height = (min_area + (width - 1)) / width; | |
| 1328 | |
| 1329 if (!((width + height) & 1)) { | |
| 1330 height++; | |
| 1331 } | |
| 1332 } | |
| 1333 | |
| 1334 if (debug_print) { | |
| 1335 printf("Width = %d, Height = %d\n", width, height); | |
| 1336 } | |
| 1337 | |
| 1338 if ((height > 200) || (width > 200)) { | |
| 1339 if (height > 200 && width > 200) { | |
| 1340 errtxtf(0, symbol, 526, "Symbol size '%1$dx%2$d' (WxH) is too large", width, height); | |
| 1341 } else { | |
| 1342 errtxtf(0, symbol, 528, "Symbol %1$s '%2$d' is too large", | |
| 1343 width > 200 ? "width" : "height", width > 200 ? width : height); | |
| 1344 } | |
| 1345 return ZINT_ERROR_INVALID_OPTION; | |
| 1346 } | |
| 1347 | |
| 1348 if ((height < 5) || (width < 5)) { | |
| 1349 if (height < 5 && width < 5) { /* Won't happen as if width < 5, min height is 19 */ | |
| 1350 errtxtf(0, symbol, 527, "Symbol size '%1$dx%2$d' (WxH) is too small", width, height); /* Not reached */ | |
| 1351 } else { | |
| 1352 errtxtf(0, symbol, 529, "Symbol %1$s '%2$d' is too small", | |
| 1353 width < 5 ? "width" : "height", width < 5 ? width : height); | |
| 1354 } | |
| 1355 return ZINT_ERROR_INVALID_OPTION; | |
| 1356 } | |
| 1357 | |
| 1358 n_dots = (height * width) / 2; | |
| 1359 | |
| 1360 dot_stream = (char *) z_alloca(height * width * 3); | |
| 1361 dot_array = (char *) z_alloca(width * height); | |
| 1362 | |
| 1363 /* Add pad characters */ | |
| 1364 padding_dots = n_dots - min_dots; /* get the number of free dots available for padding */ | |
| 1365 | |
| 1366 if (padding_dots >= 9) { | |
| 1367 int is_first = 1; /* first padding character flag */ | |
| 1368 int padp = data_length - structapp_size; | |
| 1369 while (padding_dots >= 9) { | |
| 1370 if (padding_dots < 18 && (data_length & 1) == 0) { | |
| 1371 padding_dots -= 9; | |
| 1372 } else if (padding_dots >= 18) { | |
| 1373 if ((data_length & 1) == 0) { | |
| 1374 padding_dots -= 9; | |
| 1375 } else { | |
| 1376 padding_dots -= 18; | |
| 1377 } | |
| 1378 } else { | |
| 1379 break; /* not enough padding dots left for padding */ | |
| 1380 } | |
| 1381 if (is_first && binary_finish) { | |
| 1382 codeword_array[padp++] = 109; | |
| 1383 } else { | |
| 1384 codeword_array[padp++] = 106; | |
| 1385 } | |
| 1386 | |
| 1387 data_length++; | |
| 1388 is_first = 0; | |
| 1389 } | |
| 1390 if (structapp_size) { | |
| 1391 if (structapp_array[0] == 109) { /* Binary latch no longer valid */ | |
| 1392 structapp_array[0] = 106; | |
| 1393 } | |
| 1394 for (i = 0; i < structapp_size; i++) { | |
| 1395 codeword_array[padp++] = structapp_array[i]; | |
| 1396 } | |
| 1397 } | |
| 1398 } else if (structapp_size) { | |
| 1399 data_length -= structapp_size; | |
| 1400 for (i = 0; i < structapp_size; i++) { | |
| 1401 codeword_array[data_length++] = structapp_array[i]; | |
| 1402 } | |
| 1403 } | |
| 1404 | |
| 1405 if (debug_print) { | |
| 1406 printf("Codeword length = %d, ECC length = %d\n", data_length, ecc_length); | |
| 1407 fputs("Codewords:", stdout); | |
| 1408 for (i = 0; i < data_length; i++) { | |
| 1409 printf(" %d", codeword_array[i]); | |
| 1410 } | |
| 1411 fputc('\n', stdout); | |
| 1412 } | |
| 1413 #ifdef ZINT_TEST | |
| 1414 if (symbol->debug & ZINT_DEBUG_TEST) { | |
| 1415 debug_test_codeword_dump(symbol, codeword_array, data_length); | |
| 1416 } | |
| 1417 #endif | |
| 1418 | |
| 1419 ecc_length = 3 + (data_length / 2); | |
| 1420 | |
| 1421 masked_codeword_array = (unsigned char *) z_alloca(data_length + 1 + ecc_length); | |
| 1422 | |
| 1423 if (user_mask) { | |
| 1424 best_mask = user_mask - 1; | |
| 1425 if (debug_print) { | |
| 1426 printf("Applying mask %d (specified)\n", best_mask); | |
| 1427 } | |
| 1428 } else { | |
| 1429 /* Evaluate data mask options */ | |
| 1430 for (i = 0; i < 4; i++) { | |
| 1431 | |
| 1432 dc_apply_mask(i, data_length, masked_codeword_array, codeword_array, ecc_length); | |
| 1433 | |
| 1434 dot_stream_length = dc_make_dotstream(masked_codeword_array, (data_length + ecc_length + 1), dot_stream); | |
| 1435 | |
| 1436 /* Add pad bits */ | |
| 1437 for (jc = dot_stream_length; jc < n_dots; jc++) { | |
| 1438 dot_stream[dot_stream_length++] = '1'; | |
| 1439 } | |
| 1440 | |
| 1441 dc_fold_dotstream(dot_stream, width, height, dot_array); | |
| 1442 | |
| 1443 mask_score[i] = dc_score_array(dot_array, height, width); | |
| 1444 | |
| 1445 if (debug_print) { | |
| 1446 printf("Mask %d score is %d\n", i, mask_score[i]); | |
| 1447 } | |
| 1448 } | |
| 1449 | |
| 1450 high_score = mask_score[0]; | |
| 1451 best_mask = 0; | |
| 1452 | |
| 1453 for (i = 1; i < 4; i++) { | |
| 1454 if (mask_score[i] >= high_score) { | |
| 1455 high_score = mask_score[i]; | |
| 1456 best_mask = i; | |
| 1457 } | |
| 1458 } | |
| 1459 | |
| 1460 /* Re-evaluate using forced corners if needed */ | |
| 1461 if (high_score <= (height * width) / 2) { | |
| 1462 if (debug_print) { | |
| 1463 printf("High score %d <= %d (height * width) / 2\n", high_score, (height * width) / 2); | |
| 1464 } | |
| 1465 | |
| 1466 for (i = 0; i < 4; i++) { | |
| 1467 | |
| 1468 dc_apply_mask(i, data_length, masked_codeword_array, codeword_array, ecc_length); | |
| 1469 | |
| 1470 dot_stream_length = dc_make_dotstream(masked_codeword_array, (data_length + ecc_length + 1), | |
| 1471 dot_stream); | |
| 1472 | |
| 1473 /* Add pad bits */ | |
| 1474 for (jc = dot_stream_length; jc < n_dots; jc++) { | |
| 1475 dot_stream[dot_stream_length++] = '1'; | |
| 1476 } | |
| 1477 | |
| 1478 dc_fold_dotstream(dot_stream, width, height, dot_array); | |
| 1479 | |
| 1480 dc_force_corners(width, height, dot_array); | |
| 1481 | |
| 1482 mask_score[i + 4] = dc_score_array(dot_array, height, width); | |
| 1483 | |
| 1484 if (debug_print) { | |
| 1485 printf("Mask %d score is %d\n", i + 4, mask_score[i + 4]); | |
| 1486 } | |
| 1487 } | |
| 1488 | |
| 1489 for (i = 4; i < 8; i++) { | |
| 1490 if (mask_score[i] >= high_score) { | |
| 1491 high_score = mask_score[i]; | |
| 1492 best_mask = i; | |
| 1493 } | |
| 1494 } | |
| 1495 } | |
| 1496 | |
| 1497 if (debug_print) { | |
| 1498 printf("Applying mask %d, high_score %d\n", best_mask, high_score); | |
| 1499 } | |
| 1500 } | |
| 1501 | |
| 1502 /* Apply best mask */ | |
| 1503 dc_apply_mask(best_mask % 4, data_length, masked_codeword_array, codeword_array, ecc_length); | |
| 1504 | |
| 1505 if (debug_print) { | |
| 1506 printf("Masked codewords (%d):", data_length); | |
| 1507 for (i = 1; i < data_length + 1; i++) { | |
| 1508 printf(" [%d]", masked_codeword_array[i]); | |
| 1509 } | |
| 1510 fputc('\n', stdout); | |
| 1511 printf("Masked ECCs (%d):", ecc_length); | |
| 1512 for (i = data_length + 1; i < data_length + ecc_length + 1; i++) { | |
| 1513 printf(" [%d]", masked_codeword_array[i]); | |
| 1514 } | |
| 1515 fputc('\n', stdout); | |
| 1516 } | |
| 1517 | |
| 1518 dot_stream_length = dc_make_dotstream(masked_codeword_array, (data_length + ecc_length + 1), dot_stream); | |
| 1519 | |
| 1520 /* Add pad bits */ | |
| 1521 for (jc = dot_stream_length; jc < n_dots; jc++) { | |
| 1522 dot_stream[dot_stream_length++] = '1'; | |
| 1523 } | |
| 1524 if (debug_print) printf("Binary (%d): %.*s\n", dot_stream_length, dot_stream_length, dot_stream); | |
| 1525 | |
| 1526 dc_fold_dotstream(dot_stream, width, height, dot_array); | |
| 1527 | |
| 1528 if (best_mask >= 4) { | |
| 1529 dc_force_corners(width, height, dot_array); | |
| 1530 } | |
| 1531 | |
| 1532 /* Copy values to symbol */ | |
| 1533 symbol->width = width; | |
| 1534 symbol->rows = height; | |
| 1535 | |
| 1536 for (k = 0; k < height; k++) { | |
| 1537 for (j = 0; j < width; j++) { | |
| 1538 if (dot_array[(k * width) + j] == '1') { | |
| 1539 set_module(symbol, k, j); | |
| 1540 } | |
| 1541 } | |
| 1542 symbol->row_height[k] = 1; | |
| 1543 } | |
| 1544 symbol->height = height; | |
| 1545 | |
| 1546 symbol->output_options |= BARCODE_DOTTY_MODE; | |
| 1547 | |
| 1548 return warn_number; | |
| 1549 } | |
| 1550 | |
| 1551 /* vim: set ts=4 sw=4 et : */ |
