Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/zint/backend/maxicode.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 /* maxicode.c - Handles MaxiCode */ | |
| 2 /* | |
| 3 libzint - the open source barcode library | |
| 4 Copyright (C) 2010-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 /* Includes corrections thanks to Monica Swanson @ Source Technologies */ | |
| 34 #include <assert.h> | |
| 35 #include <stdio.h> | |
| 36 #include "common.h" | |
| 37 #include "maxicode.h" | |
| 38 #include "reedsol.h" | |
| 39 | |
| 40 /* Code Set states. Those with PAD (i.e. A, B and E) are first pick */ | |
| 41 #define MX_A 0 | |
| 42 #define MX_B 1 | |
| 43 #define MX_E 2 | |
| 44 #define MX_C 3 | |
| 45 #define MX_D 4 | |
| 46 #define MX_STATES 5 | |
| 47 | |
| 48 /* Prior:A B E C D Later */ | |
| 49 static const char mx_latch_seq[MX_STATES][MX_STATES][2] = { | |
| 50 { { 0 }, {63 }, {58 }, {58 }, {58 } }, /* A */ | |
| 51 { {63 }, { 0 }, {63 }, {63 }, {63 } }, /* B */ | |
| 52 { {62,62}, {62,62}, { 0 }, {62,62}, {62,62} }, /* E */ | |
| 53 { {60,60}, {60,60}, {60,60}, { 0 }, {60,60} }, /* C */ | |
| 54 { {61,61}, {61,61}, {61,61}, {61,61}, { 0 } }, /* D */ | |
| 55 | |
| 56 }; | |
| 57 static const char mx_latch_len[MX_STATES][MX_STATES] = { /* Lengths of above */ | |
| 58 { 0, 1, 1, 1, 1 }, /* A */ | |
| 59 { 1, 0, 1, 1, 1 }, /* B */ | |
| 60 { 2, 2, 0, 2, 2 }, /* E */ | |
| 61 { 2, 2, 2, 0, 2 }, /* C */ | |
| 62 { 2, 2, 2, 2, 0 }, /* D */ | |
| 63 }; | |
| 64 | |
| 65 /* Op */ | |
| 66 struct mx_op { | |
| 67 unsigned char op; | |
| 68 unsigned char intake; /* `output` calculated from this */ | |
| 69 }; | |
| 70 | |
| 71 /* Op table ops */ | |
| 72 #define MX_OP_DGTS 0 | |
| 73 #define MX_OP_SETA 0x01 /* If change these, must change `maxiCodeSet` */ | |
| 74 #define MX_OP_SETB 0x02 | |
| 75 #define MX_OP_SETE 0x04 | |
| 76 #define MX_OP_SETC 0x08 | |
| 77 #define MX_OP_SETD 0x10 | |
| 78 #define MX_OP_SHA (0x20 | MX_OP_SETA) | |
| 79 #define MX_OP_2SHA (0x40 | MX_OP_SETA) | |
| 80 #define MX_OP_3SHA (0x80 | MX_OP_SETA) | |
| 81 #define MX_OP_SHB (0x20 | MX_OP_SETB) | |
| 82 #define MX_OP_SHE (0x20 | MX_OP_SETE) | |
| 83 #define MX_OP_SHC (0x20 | MX_OP_SETC) | |
| 84 #define MX_OP_SHD (0x20 | MX_OP_SETD) | |
| 85 | |
| 86 /* Op table indexes */ | |
| 87 #define MX_OP_DGTS_IDX 0 | |
| 88 #define MX_OP_SETA_IDX 1 | |
| 89 #define MX_OP_SETB_IDX 2 | |
| 90 #define MX_OP_SETE_IDX 3 | |
| 91 #define MX_OP_SETC_IDX 4 | |
| 92 #define MX_OP_SETD_IDX 5 | |
| 93 #define MX_OP_SHA_IDX 6 | |
| 94 #define MX_OP_2SHA_IDX 7 | |
| 95 #define MX_OP_3SHA_IDX 8 | |
| 96 #define MX_OP_SHB_IDX 9 | |
| 97 #define MX_OP_SHE_IDX 10 | |
| 98 #define MX_OP_SHC_IDX 11 | |
| 99 #define MX_OP_SHD_IDX 12 | |
| 100 #define MX_OP_IDXS 13 | |
| 101 | |
| 102 /* Op table (order must match indexes above) */ | |
| 103 static const struct mx_op mx_op_tab[MX_OP_IDXS] = { | |
| 104 /* op intake */ | |
| 105 { MX_OP_DGTS, 9 }, | |
| 106 { MX_OP_SETA, 1 }, | |
| 107 { MX_OP_SETB, 1 }, | |
| 108 { MX_OP_SETE, 1 }, | |
| 109 { MX_OP_SETC, 1 }, | |
| 110 { MX_OP_SETD, 1 }, | |
| 111 { MX_OP_SHA, 1 }, | |
| 112 { MX_OP_2SHA, 2 }, | |
| 113 { MX_OP_3SHA, 3 }, | |
| 114 { MX_OP_SHB, 1 }, | |
| 115 { MX_OP_SHE, 1 }, | |
| 116 { MX_OP_SHC, 1 }, | |
| 117 { MX_OP_SHD, 1 }, | |
| 118 }; | |
| 119 | |
| 120 /* Indexes of op sets relevant to each state - MX_OP_DGTS dealt with separately */ | |
| 121 static const signed char mx_code_set_op_idxs[MX_STATES][8] = { | |
| 122 { MX_OP_SETA_IDX, MX_OP_SHB_IDX, MX_OP_SHE_IDX, MX_OP_SHC_IDX, MX_OP_SHD_IDX, -1 }, /* MX_A */ | |
| 123 { MX_OP_SETB_IDX, MX_OP_SHA_IDX, MX_OP_2SHA_IDX, MX_OP_3SHA_IDX, MX_OP_SHE_IDX, MX_OP_SHC_IDX, /* MX_B */ | |
| 124 MX_OP_SHD_IDX, -1 }, | |
| 125 { MX_OP_SETE_IDX, MX_OP_SHC_IDX, MX_OP_SHD_IDX, -1 }, /* MX_E */ | |
| 126 { MX_OP_SETC_IDX, MX_OP_SHE_IDX, MX_OP_SHD_IDX, -1 }, /* MX_C */ | |
| 127 { MX_OP_SETD_IDX, MX_OP_SHE_IDX, MX_OP_SHC_IDX, -1 }, /* MX_D */ | |
| 128 }; | |
| 129 | |
| 130 /* Whether can encode character `ch` with `op` - MX_OP_DGTS dealt with separately */ | |
| 131 static int mx_can(const unsigned char op, const unsigned char ch, const int num_a) { | |
| 132 if (op == MX_OP_2SHA || op == MX_OP_3SHA) { | |
| 133 return num_a >= 2 + (op == MX_OP_3SHA); | |
| 134 } | |
| 135 return maxiCodeSet[ch] & op; | |
| 136 } | |
| 137 | |
| 138 /* Get the symbol value for `ch` in Code Set of `op`, accounting for chars in multiple Code Sets */ | |
| 139 static int mx_symbol_ch(const unsigned char op, const unsigned char ch) { | |
| 140 if (maxiCodeSet[ch] == (op & 0x1F) || (op & MX_OP_SETA)) { /* Non-multiple or Code Set A */ | |
| 141 return maxiSymbolChar[ch]; | |
| 142 } | |
| 143 if (op & MX_OP_SETB) { | |
| 144 const int p = posn(" ,./:", ch); | |
| 145 if (p >= 0) { | |
| 146 return 47 + p; | |
| 147 } | |
| 148 } | |
| 149 if (op & MX_OP_SETE) { | |
| 150 if (ch >= 28 && ch <= 30) { /* FS GS RS */ | |
| 151 return ch + 4; | |
| 152 } | |
| 153 } | |
| 154 return ch == ' ' ? 59 : ch; /* SP CR FS GS RS */ | |
| 155 } | |
| 156 | |
| 157 /* Encode according to operation `op` (note done backwards) */ | |
| 158 static int mx_enc(unsigned char codewords[144], int ci, const unsigned char source[], const int i, | |
| 159 const unsigned char op) { | |
| 160 if (op == MX_OP_DGTS) { | |
| 161 const int value = (source[i] - '0') * 100000000 + (source[i + 1] - '0') * 10000000 | |
| 162 + (source[i + 2] - '0') * 1000000 + (source[i + 3] - '0') * 100000 | |
| 163 + (source[i + 4] - '0') * 10000 + (source[i + 5] - '0') * 1000 | |
| 164 + (source[i + 6] - '0') * 100 + (source[i + 7] - '0') * 10 + source[i + 8] - '0'; | |
| 165 assert(ci >= 6); | |
| 166 codewords[--ci] = (value & 0x3F); | |
| 167 codewords[--ci] = (value & 0xFC0) >> 6; | |
| 168 codewords[--ci] = (value & 0x3F000) >> 12; | |
| 169 codewords[--ci] = (value & 0xFC0000) >> 18; | |
| 170 codewords[--ci] = (value & 0x3F000000) >> 24; | |
| 171 codewords[--ci] = 31; /* NS */ | |
| 172 } else if (op == MX_OP_2SHA) { | |
| 173 assert(ci >= 3); | |
| 174 codewords[--ci] = mx_symbol_ch(op, source[i + 1]); | |
| 175 codewords[--ci] = mx_symbol_ch(op, source[i]); | |
| 176 codewords[--ci] = 56; | |
| 177 } else if (op == MX_OP_3SHA) { | |
| 178 assert(ci >= 4); | |
| 179 codewords[--ci] = mx_symbol_ch(op, source[i + 2]); | |
| 180 codewords[--ci] = mx_symbol_ch(op, source[i + 1]); | |
| 181 codewords[--ci] = mx_symbol_ch(op, source[i]); | |
| 182 codewords[--ci] = 57; | |
| 183 } else { | |
| 184 assert(ci >= 1); | |
| 185 codewords[--ci] = mx_symbol_ch(op, source[i]); | |
| 186 | |
| 187 if (op & 0x20) { /* Shift */ | |
| 188 assert(ci >= 1); | |
| 189 codewords[--ci] = 59 + 1 * (op == MX_OP_SHC) + 2 * (op == MX_OP_SHD) + 3 * (op == MX_OP_SHE); | |
| 190 } | |
| 191 } | |
| 192 return ci; | |
| 193 } | |
| 194 | |
| 195 /* Encoding length of ECI */ | |
| 196 static int mx_eci_len(const int eci) { | |
| 197 return eci == 0 ? 0 : 2 + (eci > 31) + (eci > 1023) + (eci > 32767); | |
| 198 } | |
| 199 | |
| 200 /* Encode ECI (`eci` non-zero) */ | |
| 201 static int mx_enc_eci(const int eci, unsigned char codewords[144], int ci) { | |
| 202 codewords[--ci] = eci & 0x3F; | |
| 203 if (eci > 31) { | |
| 204 if (eci > 1023) { | |
| 205 codewords[--ci] = (eci & 0xFC0) >> 6; | |
| 206 if (eci > 32767) { | |
| 207 codewords[--ci] = (eci & 0x3F000) >> 12; | |
| 208 codewords[--ci] = 0x38 | ((eci & 0xC0000) >> 18); | |
| 209 } else { | |
| 210 codewords[--ci] = 0x30 | ((eci & 0x7000) >> 12); | |
| 211 } | |
| 212 } else { | |
| 213 codewords[--ci] = 0x20 | ((eci & 0x3C0) >> 6); | |
| 214 } | |
| 215 } | |
| 216 codewords[--ci] = 27; /* ECI */ | |
| 217 | |
| 218 return ci; | |
| 219 } | |
| 220 | |
| 221 /* Get the shortest encoded length for the Code Set (state) and plot the path */ | |
| 222 static int mx_get_best_length(const int state, const int i, const unsigned char ch, const int digits, const int num_a, | |
| 223 const int best_lengths[16][MX_STATES], const char best_origins[16][MX_STATES], | |
| 224 unsigned char *const path_op, char *const prior_code_set) { | |
| 225 const char *const latch_length_s = mx_latch_len[state]; | |
| 226 int min_len = 999999; | |
| 227 int j; | |
| 228 | |
| 229 if (digits >= 9) { /* Nothing can beat digits */ | |
| 230 const int m = (i - 9) & 0x0F; | |
| 231 const int org = best_origins[m][state]; | |
| 232 const int len = best_lengths[m][org] + latch_length_s[org] + 6; | |
| 233 if (len < min_len) { | |
| 234 path_op[state] = MX_OP_DGTS_IDX; | |
| 235 prior_code_set[state] = org; | |
| 236 min_len = len; | |
| 237 } | |
| 238 } else { | |
| 239 const signed char *const op_idx_s = mx_code_set_op_idxs[state]; | |
| 240 for (j = 0; op_idx_s[j] != -1; j++) { | |
| 241 const int op_idx = op_idx_s[j]; | |
| 242 const struct mx_op *const op = &mx_op_tab[op_idx]; | |
| 243 if (mx_can(op->op, ch, num_a)) { | |
| 244 const int m = (i - op->intake) & 0x0F; | |
| 245 const int org = best_origins[m][state]; | |
| 246 const int len = best_lengths[m][org] + latch_length_s[org] + op->intake + (op_idx >= MX_OP_SHA_IDX); | |
| 247 if (len < min_len) { | |
| 248 path_op[state] = op_idx; | |
| 249 prior_code_set[state] = org; | |
| 250 min_len = len; | |
| 251 } | |
| 252 } | |
| 253 } | |
| 254 } | |
| 255 return min_len; | |
| 256 } | |
| 257 | |
| 258 /* Loop to get the best prior Code Set using a row of best encoded lengths */ | |
| 259 static int mx_get_best_origin(const int state, const int *const best_length) { | |
| 260 | |
| 261 const char *const latch_length_s = mx_latch_len[state]; | |
| 262 int orglen = best_length[0] + latch_length_s[0]; | |
| 263 int best_org = 0; | |
| 264 int org; | |
| 265 | |
| 266 for (org = 1; org < MX_STATES; org++) { | |
| 267 const int len = best_length[org] + latch_length_s[org]; | |
| 268 if (len < orglen) { | |
| 269 best_org = org; | |
| 270 orglen = len; | |
| 271 } | |
| 272 } | |
| 273 return best_org; | |
| 274 } | |
| 275 | |
| 276 /* Minimal encoding using backtracking by Bue Jensen, taken from BWIPP - see | |
| 277 https://github.com/bwipp/postscriptbarcode/pull/279 */ | |
| 278 static int mx_text_process_segs(unsigned char codewords[144], const int mode, struct zint_seg segs[], | |
| 279 const int seg_count, const int structapp_cw, const int scm_vv, const int debug_print) { | |
| 280 | |
| 281 /* The encoder needs 10 history rows. The circular history buffers are 16 long for convenience */ | |
| 282 int best_lengths[16][MX_STATES] = {0}; | |
| 283 char best_origins[16][MX_STATES] = {0}; | |
| 284 int *best_length = NULL; /* Suppress clang-tidy-20 warning */ | |
| 285 | |
| 286 int cp = 20 - 9 * (mode > 3); /* Offset the initial codewords index to minimize copying */ | |
| 287 const int max_len = (mode == 5 ? 77 : 93) + 11; /* 11 added to adjust for above offset */ | |
| 288 int ci, ci_top; | |
| 289 | |
| 290 /* Backtracking information */ | |
| 291 const int segs_len = segs_length(segs, seg_count); | |
| 292 char (*prior_code_sets)[MX_STATES] = (char (*)[MX_STATES]) z_alloca(sizeof(*prior_code_sets) * (segs_len + 9)); | |
| 293 unsigned char (*path_ops)[MX_STATES] | |
| 294 = (unsigned char (*)[MX_STATES]) z_alloca(sizeof(*path_ops) * (segs_len + 9)); | |
| 295 | |
| 296 int digits = 0; | |
| 297 int num_a = 0; | |
| 298 | |
| 299 int min_len = 999999; | |
| 300 int min_state = 0; | |
| 301 int state; | |
| 302 | |
| 303 unsigned char *source_scm_vv; /* For SCM prefix `scm_vv` if any */ | |
| 304 int have_eci_scm = 0; /* Set if have ECI and SCM prefix */ | |
| 305 | |
| 306 int seg; | |
| 307 int si = 0; /* Segment offset to `source` position */ | |
| 308 int i, j; | |
| 309 | |
| 310 if (scm_vv != -1) { /* Add SCM prefix */ | |
| 311 source_scm_vv = (unsigned char *) z_alloca(segs[0].length + 9); | |
| 312 sprintf((char *) source_scm_vv, "[)>\03601\035%02d", scm_vv); /* [)>\R01\Gvv */ | |
| 313 memcpy(source_scm_vv + 9, segs[0].source, segs[0].length); | |
| 314 segs[0].source = source_scm_vv; | |
| 315 segs[0].length += 9; | |
| 316 have_eci_scm = segs[0].eci; | |
| 317 } else if (segs[0].length >= 9 && memcmp(segs[0].source, "[)>\03601\035", 7) == 0 | |
| 318 && z_isdigit(segs[0].source[7]) && z_isdigit(segs[0].source[8])) { | |
| 319 have_eci_scm = segs[0].eci; | |
| 320 } | |
| 321 | |
| 322 /* Insert Structured Append at beginning if needed */ | |
| 323 if (structapp_cw) { | |
| 324 codewords[cp++] = 33; /* PAD */ | |
| 325 codewords[cp++] = structapp_cw; | |
| 326 } | |
| 327 | |
| 328 /* Make a table of best path options */ | |
| 329 ci = cp; | |
| 330 for (seg = 0; seg < seg_count; seg++) { | |
| 331 /* Suppress NS compaction for SCM prefix if have ECI so can place ECI after it when encoding */ | |
| 332 const int no_eci_scm_check = !have_eci_scm || seg != 0; | |
| 333 const unsigned char *const source = segs[seg].source; | |
| 334 const int length = segs[seg].length; | |
| 335 const int eci_len = mx_eci_len(segs[seg].eci); | |
| 336 if (eci_len) { | |
| 337 ci += eci_len; | |
| 338 if (ci > max_len) { | |
| 339 return ZINT_ERROR_TOO_LONG; | |
| 340 } | |
| 341 digits = 0; | |
| 342 } | |
| 343 | |
| 344 for (i = 0; i < length; i++) { | |
| 345 const unsigned char ch = source[i]; | |
| 346 const int si_i = i + si; | |
| 347 | |
| 348 /* Get rows of interest */ | |
| 349 unsigned char *const path_op = path_ops[si_i]; | |
| 350 char *const prior_code_set = prior_code_sets[si_i]; | |
| 351 char *const best_origin = best_origins[(si_i) & 0x0F]; | |
| 352 best_length = best_lengths[(si_i) & 0x0F]; | |
| 353 | |
| 354 /* Keep tabs on digits and characters in Code Set A */ | |
| 355 digits = z_isdigit(ch) && (no_eci_scm_check || i >= 9) ? digits + 1 : 0; | |
| 356 num_a = maxiCodeSet[ch] & MX_OP_SETA ? num_a + 1 : 0; | |
| 357 | |
| 358 /* Get best encoded lengths, then best prior Code Sets */ | |
| 359 for (state = 0; state < MX_STATES; state++) { | |
| 360 best_length[state] = mx_get_best_length(state, si_i, ch, digits, num_a, best_lengths, best_origins, | |
| 361 path_op, prior_code_set); | |
| 362 } | |
| 363 for (state = 0; state < MX_STATES; state++) { | |
| 364 best_origin[state] = mx_get_best_origin(state, best_length); | |
| 365 } | |
| 366 } | |
| 367 si += length; | |
| 368 } | |
| 369 assert(best_length == best_lengths[(segs_len + 9 * (scm_vv != -1) - 1) & 0x0F]); /* Set to last char */ | |
| 370 | |
| 371 /* Get the best Code Set to end with */ | |
| 372 for (state = 0; state < MX_STATES; state++) { | |
| 373 const int len = best_length[state]; | |
| 374 if (len < min_len) { | |
| 375 min_state = state; | |
| 376 min_len = len; | |
| 377 } | |
| 378 } | |
| 379 if (ci + min_len > max_len) { | |
| 380 return ZINT_ERROR_TOO_LONG; | |
| 381 } | |
| 382 | |
| 383 /* Follow the best path back to the start of the message */ | |
| 384 ci += min_len; | |
| 385 ci_top = ci; | |
| 386 state = min_state; | |
| 387 for (seg = seg_count - 1; seg >= 0; seg--) { | |
| 388 const unsigned char *const source = segs[seg].source; | |
| 389 const int length = segs[seg].length; | |
| 390 const int eci_scm_check = have_eci_scm && seg == 0; | |
| 391 | |
| 392 si -= length; | |
| 393 assert(si >= 0); | |
| 394 | |
| 395 i = length; | |
| 396 while (i > 0) { | |
| 397 const int ch_i = (i + si) - 1; | |
| 398 const int pcs = prior_code_sets[ch_i][state]; | |
| 399 const int op_idx = path_ops[ch_i][state]; | |
| 400 const struct mx_op *const op = &mx_op_tab[op_idx]; | |
| 401 | |
| 402 if (eci_scm_check && i == 9) { /* Place ECI after SCM prefix */ | |
| 403 assert(ci >= cp + mx_eci_len(segs[0].eci)); | |
| 404 ci = mx_enc_eci(segs[0].eci, codewords, ci); | |
| 405 segs[0].eci = 0; | |
| 406 } | |
| 407 | |
| 408 i -= op->intake; | |
| 409 assert(i >= 0); | |
| 410 ci = mx_enc(codewords, ci, source, i, op->op); | |
| 411 | |
| 412 if (state != pcs) { | |
| 413 const int latch_len = mx_latch_len[state][pcs]; | |
| 414 assert(ci >= cp + latch_len); | |
| 415 for (j = 0; j < latch_len; j++) { | |
| 416 codewords[--ci] = mx_latch_seq[state][pcs][j]; | |
| 417 } | |
| 418 state = pcs; | |
| 419 } | |
| 420 } | |
| 421 if (segs[seg].eci) { | |
| 422 assert(ci >= cp + mx_eci_len(segs[seg].eci)); | |
| 423 ci = mx_enc_eci(segs[seg].eci, codewords, ci); | |
| 424 } | |
| 425 } | |
| 426 assert(ci == cp); | |
| 427 | |
| 428 cp = ci_top; | |
| 429 | |
| 430 /* If end in Code Set C or D, switch to A for padding */ | |
| 431 if (cp < max_len && (min_state == MX_C || min_state == MX_D)) { | |
| 432 codewords[cp++] = 58; /* Latch A */ | |
| 433 } | |
| 434 | |
| 435 if (debug_print) { | |
| 436 if (cp < max_len) { | |
| 437 printf("Pads: %d\n", max_len - cp); | |
| 438 } else { | |
| 439 fputs("No Pads\n", stdout); | |
| 440 } | |
| 441 } | |
| 442 | |
| 443 if (cp < max_len) { | |
| 444 /* Add the padding */ | |
| 445 memset(codewords + cp, min_state == MX_E ? 28 : 33, max_len - cp); | |
| 446 } | |
| 447 | |
| 448 if (debug_print) printf("Length: %d\n", cp); | |
| 449 | |
| 450 if (cp > max_len) { | |
| 451 return ZINT_ERROR_TOO_LONG; | |
| 452 } | |
| 453 | |
| 454 /* Adjust the codeword array */ | |
| 455 if (mode > 3) { | |
| 456 memcpy(codewords + 1, codewords + 20 - 9, 9); /* Primary */ | |
| 457 } | |
| 458 | |
| 459 return 0; | |
| 460 } | |
| 461 | |
| 462 /* Handles error correction of primary message */ | |
| 463 static void mx_do_primary_ecc(unsigned char codewords[144]) { | |
| 464 const int datalen = 10, eclen = 10; | |
| 465 unsigned char ecc[10]; | |
| 466 int j; | |
| 467 rs_t rs; | |
| 468 | |
| 469 rs_init_gf(&rs, 0x43); | |
| 470 rs_init_code(&rs, eclen, 1); | |
| 471 | |
| 472 rs_encode(&rs, datalen, codewords, ecc); | |
| 473 | |
| 474 for (j = 0; j < eclen; j++) { | |
| 475 codewords[datalen + j] = ecc[j]; | |
| 476 } | |
| 477 } | |
| 478 | |
| 479 /* Handles error correction of characters in secondary */ | |
| 480 static void mx_do_secondary_ecc(unsigned char codewords[144], const int datalen, const int eclen) { | |
| 481 unsigned char data[42]; /* Half max `datalen` (84) */ | |
| 482 unsigned char ecc[28]; /* Half max `eclen` (56) */ | |
| 483 int j; | |
| 484 rs_t rs; | |
| 485 | |
| 486 rs_init_gf(&rs, 0x43); | |
| 487 rs_init_code(&rs, eclen, 1); | |
| 488 | |
| 489 /* Even */ | |
| 490 for (j = 0; j < datalen; j += 2) { | |
| 491 data[j >> 1] = codewords[j + 20]; | |
| 492 } | |
| 493 | |
| 494 rs_encode(&rs, datalen >> 1, data, ecc); | |
| 495 | |
| 496 for (j = 0; j < eclen; j++) { | |
| 497 codewords[datalen + (j << 1) + 20] = ecc[j]; | |
| 498 } | |
| 499 | |
| 500 /* Odd */ | |
| 501 for (j = 0; j < datalen; j += 2) { | |
| 502 data[j >> 1] = codewords[j + 1 + 20]; | |
| 503 } | |
| 504 | |
| 505 rs_encode(&rs, datalen >> 1, data, ecc); | |
| 506 | |
| 507 for (j = 0; j < eclen; j++) { | |
| 508 codewords[datalen + (j << 1) + 1 + 20] = ecc[j]; | |
| 509 } | |
| 510 } | |
| 511 | |
| 512 /* Format structured primary for Mode 2 */ | |
| 513 static void mx_do_primary_2(unsigned char codewords[144], const unsigned char postcode[], | |
| 514 const int postcode_length, const int country, const int service) { | |
| 515 | |
| 516 const int postcode_num = to_int(postcode, postcode_length); | |
| 517 | |
| 518 codewords[0] = ((postcode_num & 0x03) << 4) | 2; | |
| 519 codewords[1] = ((postcode_num & 0xFC) >> 2); | |
| 520 codewords[2] = ((postcode_num & 0x3F00) >> 8); | |
| 521 codewords[3] = ((postcode_num & 0xFC000) >> 14); | |
| 522 codewords[4] = ((postcode_num & 0x3F00000) >> 20); | |
| 523 codewords[5] = ((postcode_num & 0x3C000000) >> 26) | ((postcode_length & 0x03) << 4); | |
| 524 codewords[6] = ((postcode_length & 0x3C) >> 2) | ((country & 0x03) << 4); | |
| 525 codewords[7] = (country & 0xFC) >> 2; | |
| 526 codewords[8] = ((country & 0x300) >> 8) | ((service & 0x0F) << 2); | |
| 527 codewords[9] = ((service & 0x3F0) >> 4); | |
| 528 } | |
| 529 | |
| 530 /* Format structured primary for Mode 3 */ | |
| 531 static void mx_do_primary_3(unsigned char codewords[144], unsigned char postcode[], const int country, | |
| 532 const int service) { | |
| 533 int i; | |
| 534 | |
| 535 /* Convert to Code Set A */ | |
| 536 for (i = 0; i < 6; i++) { | |
| 537 postcode[i] = maxiSymbolChar[postcode[i]]; | |
| 538 } | |
| 539 | |
| 540 codewords[0] = ((postcode[5] & 0x03) << 4) | 3; | |
| 541 codewords[1] = ((postcode[4] & 0x03) << 4) | ((postcode[5] & 0x3C) >> 2); | |
| 542 codewords[2] = ((postcode[3] & 0x03) << 4) | ((postcode[4] & 0x3C) >> 2); | |
| 543 codewords[3] = ((postcode[2] & 0x03) << 4) | ((postcode[3] & 0x3C) >> 2); | |
| 544 codewords[4] = ((postcode[1] & 0x03) << 4) | ((postcode[2] & 0x3C) >> 2); | |
| 545 codewords[5] = ((postcode[0] & 0x03) << 4) | ((postcode[1] & 0x3C) >> 2); | |
| 546 codewords[6] = ((postcode[0] & 0x3C) >> 2) | ((country & 0x03) << 4); | |
| 547 codewords[7] = (country & 0xFC) >> 2; | |
| 548 codewords[8] = ((country & 0x300) >> 8) | ((service & 0x0F) << 2); | |
| 549 codewords[9] = ((service & 0x3F0) >> 4); | |
| 550 } | |
| 551 | |
| 552 INTERNAL int maxicode(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) { | |
| 553 int i, j, mode, lp = 0; | |
| 554 int error_number; | |
| 555 unsigned char codewords[144]; | |
| 556 int scm_vv = -1; | |
| 557 int structapp_cw = 0; | |
| 558 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT; | |
| 559 | |
| 560 mode = symbol->option_1; | |
| 561 | |
| 562 if (mode <= 0) { /* If mode is unspecified (-1) or to be auto-determined (0) between 2 and 3 */ | |
| 563 lp = (int) strlen(symbol->primary); | |
| 564 if (lp == 0) { | |
| 565 if (mode == 0) { /* Require primary message to auto-determine between 2 and 3 */ | |
| 566 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 554, "Primary Message empty"); | |
| 567 } | |
| 568 mode = 4; | |
| 569 } else { | |
| 570 mode = 2; | |
| 571 for (i = 0; i < lp - 6; i++) { | |
| 572 if (!z_isdigit(symbol->primary[i]) && (symbol->primary[i] != ' ')) { | |
| 573 mode = 3; | |
| 574 break; | |
| 575 } | |
| 576 } | |
| 577 } | |
| 578 } | |
| 579 | |
| 580 if (mode < 2 || mode > 6) { /* Only codes 2 to 6 supported */ | |
| 581 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 550, "Mode '%d' out of range (2 to 6)", mode); | |
| 582 } | |
| 583 | |
| 584 if (mode <= 3) { /* Modes 2 and 3 need data in symbol->primary */ | |
| 585 unsigned char postcode[10]; | |
| 586 int countrycode; | |
| 587 int service; | |
| 588 int postcode_len; | |
| 589 if (lp == 0) { /* Mode set manually means lp doesn't get set */ | |
| 590 lp = (int) strlen(symbol->primary); | |
| 591 } | |
| 592 if (lp < 7 || lp > 15) { /* 1 to 9 character postcode + 3 digit country code + 3 digit service class */ | |
| 593 if (lp == 0) { | |
| 594 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 548, "Primary Message empty"); | |
| 595 } | |
| 596 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 551, "Primary Message length %d wrong (7 to 15 only)", | |
| 597 lp); | |
| 598 } | |
| 599 postcode_len = lp - 6; | |
| 600 | |
| 601 countrycode = to_int((const unsigned char *) (symbol->primary + postcode_len), 3); | |
| 602 service = to_int((const unsigned char *) (symbol->primary + postcode_len + 3), 3); | |
| 603 | |
| 604 if (countrycode == -1 || service == -1) { /* Check that country code and service are numeric */ | |
| 605 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 552, | |
| 606 "Non-numeric country code or service class in Primary Message"); | |
| 607 } | |
| 608 | |
| 609 memcpy(postcode, symbol->primary, postcode_len); | |
| 610 postcode[postcode_len] = '\0'; | |
| 611 | |
| 612 if (mode == 2) { | |
| 613 for (i = 0; i < postcode_len; i++) { | |
| 614 if (postcode[i] == ' ') { | |
| 615 postcode[i] = '\0'; | |
| 616 postcode_len = i; | |
| 617 break; | |
| 618 } | |
| 619 if (!z_isdigit(postcode[i])) { | |
| 620 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 555, "Non-numeric postcode in Primary Message"); | |
| 621 } | |
| 622 } | |
| 623 if (countrycode == 840 && postcode_len == 5) { | |
| 624 /* Annex B, section B.1, paragraph 4.a, "In the case of country code 840, if the "+4" is unknown, | |
| 625 then fill with zeroes" (adapted from OkaiBarcode, stricter interpretation, props Daniel Gredler) */ | |
| 626 memcpy(postcode + 5, "0000", 5); /* Include NUL char */ | |
| 627 postcode_len = 9; | |
| 628 } | |
| 629 mx_do_primary_2(codewords, postcode, postcode_len, countrycode, service); | |
| 630 } else { | |
| 631 /* Just truncate and space-pad */ | |
| 632 postcode[6] = '\0'; | |
| 633 for (i = postcode_len; i < 6; i++) { | |
| 634 postcode[i] = ' '; | |
| 635 } | |
| 636 /* Upper-case and check for Code Set A characters only */ | |
| 637 to_upper(postcode, postcode_len); | |
| 638 for (i = 0; i < 6; i++) { | |
| 639 /* Don't allow control chars (CR FS GS RS for Code Set A) */ | |
| 640 if (postcode[i] < ' ' || !(maxiCodeSet[postcode[i]] & MX_OP_SETA)) { | |
| 641 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 556, | |
| 642 "Invalid character in postcode in Primary Message"); | |
| 643 } | |
| 644 } | |
| 645 mx_do_primary_3(codewords, postcode, countrycode, service); | |
| 646 } | |
| 647 | |
| 648 if (symbol->option_2) { /* Check for option_2 = vv + 1, where vv is version of SCM prefix "[)>\R01\Gvv" */ | |
| 649 if (symbol->option_2 < 0 || symbol->option_2 > 100) { | |
| 650 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 557, | |
| 651 "SCM prefix version '%d' out of range (1 to 100)", symbol->option_2); | |
| 652 } | |
| 653 if (symbol->eci == 25 || (symbol->eci >= 33 && symbol->eci <= 35)) { /* UTF-16/32 */ | |
| 654 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 547, | |
| 655 "SCM prefix can not be used with ECI %d (ECI must be ASCII compatible)", symbol->eci); | |
| 656 } | |
| 657 scm_vv = symbol->option_2 - 1; | |
| 658 } | |
| 659 | |
| 660 if (debug_print) { | |
| 661 printf("Postcode: %s, Country Code: %d, Service Class: %d\n", postcode, countrycode, service); | |
| 662 } | |
| 663 } else { | |
| 664 codewords[0] = mode; | |
| 665 } | |
| 666 | |
| 667 if (debug_print) { | |
| 668 printf("Mode: %d\n", mode); | |
| 669 } | |
| 670 | |
| 671 if (symbol->structapp.count) { | |
| 672 if (symbol->structapp.count < 2 || symbol->structapp.count > 8) { | |
| 673 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 558, | |
| 674 "Structured Append count '%d' out of range (2 to 8)", symbol->structapp.count); | |
| 675 } | |
| 676 if (symbol->structapp.index < 1 || symbol->structapp.index > symbol->structapp.count) { | |
| 677 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 559, | |
| 678 "Structured Append index '%1$d' out of range (1 to count %2$d)", | |
| 679 symbol->structapp.index, symbol->structapp.count); | |
| 680 } | |
| 681 if (symbol->structapp.id[0]) { | |
| 682 return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 549, "Structured Append ID not available for MaxiCode"); | |
| 683 } | |
| 684 structapp_cw = (symbol->structapp.count - 1) | ((symbol->structapp.index - 1) << 3); | |
| 685 } | |
| 686 | |
| 687 error_number = mx_text_process_segs(codewords, mode, segs, seg_count, structapp_cw, scm_vv, debug_print); | |
| 688 if (error_number == ZINT_ERROR_TOO_LONG) { | |
| 689 return errtxt(error_number, symbol, 553, "Input too long, requires too many codewords (maximum 144)"); | |
| 690 } | |
| 691 | |
| 692 /* All the data is sorted - now do error correction */ | |
| 693 mx_do_primary_ecc(codewords); /* Always Enhanced ECC (EEC) 10 data + 10 error correction */ | |
| 694 | |
| 695 if (mode == 5) { | |
| 696 /* Enhanced ECC (EEC) 68 data + 56 error correction */ | |
| 697 mx_do_secondary_ecc(codewords, 68, 28); /* ECC halved for even/odd */ | |
| 698 } else { | |
| 699 /* Standard ECC (SEC) 84 data + 40 error correction */ | |
| 700 mx_do_secondary_ecc(codewords, 84, 20); /* ECC halved for even/odd */ | |
| 701 } | |
| 702 | |
| 703 if (debug_print) { | |
| 704 fputs("Codewords:", stdout); | |
| 705 for (i = 0; i < 144; i++) printf(" %d", codewords[i]); | |
| 706 fputc('\n', stdout); | |
| 707 } | |
| 708 #ifdef ZINT_TEST | |
| 709 if (symbol->debug & ZINT_DEBUG_TEST) { | |
| 710 debug_test_codeword_dump(symbol, codewords, 144); | |
| 711 } | |
| 712 #endif | |
| 713 | |
| 714 /* Copy data into symbol grid */ | |
| 715 for (i = 0; i < 33; i++) { | |
| 716 for (j = 0; j < 30; j++) { | |
| 717 const int mod_seq = maxiGrid[(i * 30) + j] + 5; | |
| 718 const int block = mod_seq / 6; | |
| 719 | |
| 720 if (block != 0) { | |
| 721 if ((codewords[block - 1] >> (5 - (mod_seq % 6))) & 1) { | |
| 722 set_module(symbol, i, j); | |
| 723 } | |
| 724 } | |
| 725 } | |
| 726 } | |
| 727 | |
| 728 /* Add orientation markings */ | |
| 729 set_module(symbol, 0, 28); /* Top right filler */ | |
| 730 set_module(symbol, 0, 29); | |
| 731 set_module(symbol, 9, 10); /* Top left marker */ | |
| 732 set_module(symbol, 9, 11); | |
| 733 set_module(symbol, 10, 11); | |
| 734 set_module(symbol, 15, 7); /* Left hand marker */ | |
| 735 set_module(symbol, 16, 8); | |
| 736 set_module(symbol, 16, 20); /* Right hand marker */ | |
| 737 set_module(symbol, 17, 20); | |
| 738 set_module(symbol, 22, 10); /* Bottom left marker */ | |
| 739 set_module(symbol, 23, 10); | |
| 740 set_module(symbol, 22, 17); /* Bottom right marker */ | |
| 741 set_module(symbol, 23, 17); | |
| 742 | |
| 743 symbol->width = 30; | |
| 744 symbol->rows = 33; | |
| 745 | |
| 746 /* Note MaxiCode fixed size so symbol height ignored but set anyway */ | |
| 747 (void) set_height(symbol, 5.0f, 0.0f, 0.0f, 1 /*no_errtxt*/); | |
| 748 | |
| 749 return error_number; | |
| 750 } | |
| 751 | |
| 752 /* vim: set ts=4 sw=4 et : */ |
