Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/zint/backend/dmatrix.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 /* dmatrix.c Handles Data Matrix ECC 200 symbols */ | |
| 2 /* | |
| 3 libzint - the open source barcode library | |
| 4 Copyright (C) 2009-2024 Robin Stuart <rstuart114@gmail.com> | |
| 5 | |
| 6 developed from and including some functions from: | |
| 7 IEC16022 bar code generation | |
| 8 Adrian Kennard, Andrews & Arnold Ltd | |
| 9 with help from Cliff Hones on the RS coding | |
| 10 | |
| 11 (c) 2004 Adrian Kennard, Andrews & Arnold Ltd | |
| 12 (c) 2006 Stefan Schmidt <stefan@datenfreihafen.org> | |
| 13 | |
| 14 Redistribution and use in source and binary forms, with or without | |
| 15 modification, are permitted provided that the following conditions | |
| 16 are met: | |
| 17 | |
| 18 1. Redistributions of source code must retain the above copyright | |
| 19 notice, this list of conditions and the following disclaimer. | |
| 20 2. Redistributions in binary form must reproduce the above copyright | |
| 21 notice, this list of conditions and the following disclaimer in the | |
| 22 documentation and/or other materials provided with the distribution. | |
| 23 3. Neither the name of the project nor the names of its contributors | |
| 24 may be used to endorse or promote products derived from this software | |
| 25 without specific prior written permission. | |
| 26 | |
| 27 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
| 28 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 29 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 30 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | |
| 31 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 32 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 33 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 34 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 35 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 36 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 37 SUCH DAMAGE. | |
| 38 */ | |
| 39 /* SPDX-License-Identifier: BSD-3-Clause */ | |
| 40 | |
| 41 #include <assert.h> | |
| 42 #include <limits.h> | |
| 43 #include <stdio.h> | |
| 44 #include "common.h" | |
| 45 #include "reedsol.h" | |
| 46 #include "dmatrix.h" | |
| 47 | |
| 48 /* Annex F placement algorithm low level */ | |
| 49 static void dm_placementbit(int *array, const int NR, const int NC, int r, int c, const int p, const char b) { | |
| 50 if (r < 0) { | |
| 51 r += NR; | |
| 52 c += 4 - ((NR + 4) % 8); | |
| 53 } | |
| 54 if (c < 0) { | |
| 55 c += NC; | |
| 56 r += 4 - ((NC + 4) % 8); | |
| 57 } | |
| 58 /* Necessary for DMRE (ISO/IEC 21471:2020 Annex E) */ | |
| 59 if (r >= NR) { | |
| 60 r -= NR; | |
| 61 } | |
| 62 /* Check index limits */ | |
| 63 assert(r < NR); | |
| 64 assert(c < NC); | |
| 65 /* Check double-assignment */ | |
| 66 assert(0 == array[r * NC + c]); | |
| 67 array[r * NC + c] = (p << 3) + b; | |
| 68 } | |
| 69 | |
| 70 static void dm_placementblock(int *array, const int NR, const int NC, const int r, | |
| 71 const int c, const int p) { | |
| 72 dm_placementbit(array, NR, NC, r - 2, c - 2, p, 7); | |
| 73 dm_placementbit(array, NR, NC, r - 2, c - 1, p, 6); | |
| 74 dm_placementbit(array, NR, NC, r - 1, c - 2, p, 5); | |
| 75 dm_placementbit(array, NR, NC, r - 1, c - 1, p, 4); | |
| 76 dm_placementbit(array, NR, NC, r - 1, c - 0, p, 3); | |
| 77 dm_placementbit(array, NR, NC, r - 0, c - 2, p, 2); | |
| 78 dm_placementbit(array, NR, NC, r - 0, c - 1, p, 1); | |
| 79 dm_placementbit(array, NR, NC, r - 0, c - 0, p, 0); | |
| 80 } | |
| 81 | |
| 82 static void dm_placementcornerA(int *array, const int NR, const int NC, const int p) { | |
| 83 dm_placementbit(array, NR, NC, NR - 1, 0, p, 7); | |
| 84 dm_placementbit(array, NR, NC, NR - 1, 1, p, 6); | |
| 85 dm_placementbit(array, NR, NC, NR - 1, 2, p, 5); | |
| 86 dm_placementbit(array, NR, NC, 0, NC - 2, p, 4); | |
| 87 dm_placementbit(array, NR, NC, 0, NC - 1, p, 3); | |
| 88 dm_placementbit(array, NR, NC, 1, NC - 1, p, 2); | |
| 89 dm_placementbit(array, NR, NC, 2, NC - 1, p, 1); | |
| 90 dm_placementbit(array, NR, NC, 3, NC - 1, p, 0); | |
| 91 } | |
| 92 | |
| 93 static void dm_placementcornerB(int *array, const int NR, const int NC, const int p) { | |
| 94 dm_placementbit(array, NR, NC, NR - 3, 0, p, 7); | |
| 95 dm_placementbit(array, NR, NC, NR - 2, 0, p, 6); | |
| 96 dm_placementbit(array, NR, NC, NR - 1, 0, p, 5); | |
| 97 dm_placementbit(array, NR, NC, 0, NC - 4, p, 4); | |
| 98 dm_placementbit(array, NR, NC, 0, NC - 3, p, 3); | |
| 99 dm_placementbit(array, NR, NC, 0, NC - 2, p, 2); | |
| 100 dm_placementbit(array, NR, NC, 0, NC - 1, p, 1); | |
| 101 dm_placementbit(array, NR, NC, 1, NC - 1, p, 0); | |
| 102 } | |
| 103 | |
| 104 static void dm_placementcornerC(int *array, const int NR, const int NC, const int p) { | |
| 105 dm_placementbit(array, NR, NC, NR - 3, 0, p, 7); | |
| 106 dm_placementbit(array, NR, NC, NR - 2, 0, p, 6); | |
| 107 dm_placementbit(array, NR, NC, NR - 1, 0, p, 5); | |
| 108 dm_placementbit(array, NR, NC, 0, NC - 2, p, 4); | |
| 109 dm_placementbit(array, NR, NC, 0, NC - 1, p, 3); | |
| 110 dm_placementbit(array, NR, NC, 1, NC - 1, p, 2); | |
| 111 dm_placementbit(array, NR, NC, 2, NC - 1, p, 1); | |
| 112 dm_placementbit(array, NR, NC, 3, NC - 1, p, 0); | |
| 113 } | |
| 114 | |
| 115 static void dm_placementcornerD(int *array, const int NR, const int NC, const int p) { | |
| 116 dm_placementbit(array, NR, NC, NR - 1, 0, p, 7); | |
| 117 dm_placementbit(array, NR, NC, NR - 1, NC - 1, p, 6); | |
| 118 dm_placementbit(array, NR, NC, 0, NC - 3, p, 5); | |
| 119 dm_placementbit(array, NR, NC, 0, NC - 2, p, 4); | |
| 120 dm_placementbit(array, NR, NC, 0, NC - 1, p, 3); | |
| 121 dm_placementbit(array, NR, NC, 1, NC - 3, p, 2); | |
| 122 dm_placementbit(array, NR, NC, 1, NC - 2, p, 1); | |
| 123 dm_placementbit(array, NR, NC, 1, NC - 1, p, 0); | |
| 124 } | |
| 125 | |
| 126 /* Annex F placement algorithm main function */ | |
| 127 static void dm_placement(int *array, const int NR, const int NC) { | |
| 128 int r, c, p; | |
| 129 /* start */ | |
| 130 p = 1; | |
| 131 r = 4; | |
| 132 c = 0; | |
| 133 do { | |
| 134 /* check corner */ | |
| 135 if (r == NR && !c) | |
| 136 dm_placementcornerA(array, NR, NC, p++); | |
| 137 if (r == NR - 2 && !c && NC % 4) | |
| 138 dm_placementcornerB(array, NR, NC, p++); | |
| 139 if (r == NR - 2 && !c && (NC % 8) == 4) | |
| 140 dm_placementcornerC(array, NR, NC, p++); | |
| 141 if (r == NR + 4 && c == 2 && !(NC % 8)) | |
| 142 dm_placementcornerD(array, NR, NC, p++); | |
| 143 /* up/right */ | |
| 144 do { | |
| 145 if (r < NR && c >= 0 && !array[r * NC + c]) | |
| 146 dm_placementblock(array, NR, NC, r, c, p++); | |
| 147 r -= 2; | |
| 148 c += 2; | |
| 149 } while (r >= 0 && c < NC); | |
| 150 r++; | |
| 151 c += 3; | |
| 152 /* down/left */ | |
| 153 do { | |
| 154 if (r >= 0 && c < NC && !array[r * NC + c]) | |
| 155 dm_placementblock(array, NR, NC, r, c, p++); | |
| 156 r += 2; | |
| 157 c -= 2; | |
| 158 } while (r < NR && c >= 0); | |
| 159 r += 3; | |
| 160 c++; | |
| 161 } while (r < NR || c < NC); | |
| 162 /* unfilled corner */ | |
| 163 if (!array[NR * NC - 1]) | |
| 164 array[NR * NC - 1] = array[NR * NC - NC - 2] = 1; | |
| 165 } | |
| 166 | |
| 167 /* calculate and append ecc code, and if necessary interleave */ | |
| 168 static void dm_ecc(unsigned char *binary, const int bytes, const int datablock, const int rsblock, const int skew) { | |
| 169 int blocks = (bytes + 2) / datablock, b; | |
| 170 int rsblocks = rsblock * blocks; | |
| 171 int n; | |
| 172 rs_t rs; | |
| 173 | |
| 174 rs_init_gf(&rs, 0x12d); | |
| 175 rs_init_code(&rs, rsblock, 1); | |
| 176 for (b = 0; b < blocks; b++) { | |
| 177 unsigned char buf[256], ecc[256]; | |
| 178 int p = 0; | |
| 179 for (n = b; n < bytes; n += blocks) | |
| 180 buf[p++] = binary[n]; | |
| 181 rs_encode(&rs, p, buf, ecc); | |
| 182 if (skew) { | |
| 183 /* Rotate ecc data to make 144x144 size symbols acceptable */ | |
| 184 /* See http://groups.google.com/group/postscriptbarcode/msg/5ae8fda7757477da | |
| 185 or https://github.com/nu-book/zxing-cpp/issues/259 */ | |
| 186 for (n = b, p = 0; n < rsblocks; n += blocks, p++) { | |
| 187 if (b < 8) { | |
| 188 binary[bytes + n + 2] = ecc[p]; | |
| 189 } else { | |
| 190 binary[bytes + n - 8] = ecc[p]; | |
| 191 } | |
| 192 } | |
| 193 } else { | |
| 194 for (n = b, p = 0; n < rsblocks; n += blocks, p++) { | |
| 195 binary[bytes + n] = ecc[p]; | |
| 196 } | |
| 197 } | |
| 198 } | |
| 199 } | |
| 200 | |
| 201 /* Is basic (non-shifted) C40? */ | |
| 202 static int dm_isc40(const unsigned char input) { | |
| 203 if (input <= '9') { | |
| 204 return input >= '0' || input == ' '; | |
| 205 } | |
| 206 return z_isupper(input); | |
| 207 } | |
| 208 | |
| 209 /* Is basic (non-shifted) TEXT? */ | |
| 210 static int dm_istext(const unsigned char input) { | |
| 211 if (input <= '9') { | |
| 212 return input >= '0' || input == ' '; | |
| 213 } | |
| 214 return z_islower(input); | |
| 215 } | |
| 216 | |
| 217 /* Is basic (non-shifted) C40/TEXT? */ | |
| 218 static int dm_isc40text(const int current_mode, const unsigned char input) { | |
| 219 return current_mode == DM_C40 ? dm_isc40(input) : dm_istext(input); | |
| 220 } | |
| 221 | |
| 222 /* Return true (1) if a character is valid in X12 set */ | |
| 223 static int dm_isX12(const unsigned char input) { | |
| 224 return dm_isc40(input) || input == 13 || input == '*' || input == '>'; | |
| 225 } | |
| 226 | |
| 227 /* Return true (1) if a character is valid in EDIFACT set */ | |
| 228 static int dm_isedifact(const unsigned char input) { | |
| 229 return input >= ' ' && input <= '^'; | |
| 230 } | |
| 231 | |
| 232 /* Does Annex J section (r)(6)(ii)(I) apply? */ | |
| 233 static int dm_substep_r_6_2_1(const unsigned char source[], const int length, const int sp) { | |
| 234 /* Annex J section (r)(6)(ii)(I) | |
| 235 "If one of the three X12 terminator/separator characters first | |
| 236 occurs in the yet to be processed data before a non-X12 character..." | |
| 237 */ | |
| 238 int i; | |
| 239 | |
| 240 for (i = sp; i < length && dm_isX12(source[i]); i++) { | |
| 241 if (source[i] == 13 || source[i] == '*' || source[i] == '>') { | |
| 242 return 1; | |
| 243 } | |
| 244 } | |
| 245 | |
| 246 return 0; | |
| 247 } | |
| 248 | |
| 249 /* Count number of TEXT characters around `sp` between `position` and `length` | |
| 250 - helper to avoid exiting from Base 256 too early if have series of TEXT characters */ | |
| 251 static int dm_text_sp_cnt(const unsigned char source[], const int position, const int length, const int sp) { | |
| 252 int i; | |
| 253 int cnt = 0; | |
| 254 | |
| 255 /* Count from `sp` forward */ | |
| 256 for (i = sp; i < length && dm_istext(source[i]); i++, cnt++); | |
| 257 /* Count backwards from `sp` */ | |
| 258 for (i = sp - 1; i >= position && dm_istext(source[i]); i--, cnt++); | |
| 259 | |
| 260 return cnt; | |
| 261 } | |
| 262 | |
| 263 /* Character counts are multiplied by this, so as to be whole integer divisible by 2, 3 and 4 */ | |
| 264 #define DM_MULT 12 | |
| 265 | |
| 266 #define DM_MULT_1_DIV_2 6 | |
| 267 #define DM_MULT_2_DIV_3 8 | |
| 268 #define DM_MULT_3_DIV_4 9 | |
| 269 #define DM_MULT_1 12 | |
| 270 #define DM_MULT_4_DIV_3 16 | |
| 271 #define DM_MULT_2 24 | |
| 272 #define DM_MULT_8_DIV_3 32 | |
| 273 #define DM_MULT_3 26 | |
| 274 #define DM_MULT_13_DIV_4 39 | |
| 275 #define DM_MULT_10_DIV_3 40 | |
| 276 #define DM_MULT_4 48 | |
| 277 #define DM_MULT_17_DIV_4 51 | |
| 278 #define DM_MULT_13_DIV_3 52 | |
| 279 | |
| 280 #define DM_MULT_MINUS_1 11 | |
| 281 #define DM_MULT_CEIL(n) ((((n) + DM_MULT_MINUS_1) / DM_MULT) * DM_MULT) | |
| 282 | |
| 283 /* 'look ahead test' from Annex J */ | |
| 284 static int dm_look_ahead_test(const unsigned char source[], const int length, const int position, | |
| 285 const int current_mode, const int mode_arg, const int gs1, const int debug_print) { | |
| 286 int ascii_count, c40_count, text_count, x12_count, edf_count, b256_count; | |
| 287 int ascii_rnded, c40_rnded, text_rnded, x12_rnded, edf_rnded, b256_rnded; | |
| 288 int cnt_1; | |
| 289 int sp; | |
| 290 | |
| 291 /* step (j) */ | |
| 292 if (current_mode == DM_ASCII || current_mode == DM_BASE256) { /* Adjusted to use for DM_BASE256 also */ | |
| 293 ascii_count = 0; | |
| 294 c40_count = DM_MULT_1; | |
| 295 text_count = DM_MULT_1; | |
| 296 x12_count = DM_MULT_1; | |
| 297 edf_count = DM_MULT_1; | |
| 298 b256_count = DM_MULT_2; /* Adjusted from DM_MULT_5_DIV_4 (1.25) */ | |
| 299 } else { | |
| 300 ascii_count = DM_MULT_1; | |
| 301 c40_count = DM_MULT_2; | |
| 302 text_count = DM_MULT_2; | |
| 303 x12_count = DM_MULT_2; | |
| 304 edf_count = DM_MULT_2; | |
| 305 b256_count = DM_MULT_3; /* Adjusted from DM_MULT_9_DIV_4 (2.25) */ | |
| 306 } | |
| 307 | |
| 308 switch (current_mode) { | |
| 309 case DM_C40: c40_count = 0; | |
| 310 break; | |
| 311 case DM_TEXT: text_count = 0; | |
| 312 break; | |
| 313 case DM_X12: x12_count = 0; | |
| 314 break; | |
| 315 case DM_EDIFACT: edf_count = 0; | |
| 316 break; | |
| 317 case DM_BASE256: | |
| 318 b256_count = mode_arg == 249 ? DM_MULT_1 : 0; /* Adjusted to use no. of bytes written */ | |
| 319 break; | |
| 320 } | |
| 321 | |
| 322 for (sp = position; sp < length; sp++) { | |
| 323 const unsigned char c = source[sp]; | |
| 324 const int is_extended = c & 0x80; | |
| 325 | |
| 326 /* ascii ... step (l) */ | |
| 327 if (z_isdigit(c)) { | |
| 328 ascii_count += DM_MULT_1_DIV_2; /* (l)(1) */ | |
| 329 } else { | |
| 330 if (is_extended) { | |
| 331 ascii_count = DM_MULT_CEIL(ascii_count) + DM_MULT_2; /* (l)(2) */ | |
| 332 } else { | |
| 333 ascii_count = DM_MULT_CEIL(ascii_count) + DM_MULT_1; /* (l)(3) */ | |
| 334 } | |
| 335 } | |
| 336 | |
| 337 /* c40 ... step (m) */ | |
| 338 if (dm_isc40(c)) { | |
| 339 c40_count += DM_MULT_2_DIV_3; /* (m)(1) */ | |
| 340 } else { | |
| 341 if (is_extended) { | |
| 342 c40_count += DM_MULT_8_DIV_3; /* (m)(2) */ | |
| 343 } else { | |
| 344 c40_count += DM_MULT_4_DIV_3; /* (m)(3) */ | |
| 345 } | |
| 346 } | |
| 347 | |
| 348 /* text ... step (n) */ | |
| 349 if (dm_istext(c)) { | |
| 350 text_count += DM_MULT_2_DIV_3; /* (n)(1) */ | |
| 351 } else { | |
| 352 if (is_extended) { | |
| 353 text_count += DM_MULT_8_DIV_3; /* (n)(2) */ | |
| 354 } else { | |
| 355 text_count += DM_MULT_4_DIV_3; /* (n)(3) */ | |
| 356 } | |
| 357 } | |
| 358 | |
| 359 /* x12 ... step (o) */ | |
| 360 if (dm_isX12(c)) { | |
| 361 x12_count += DM_MULT_2_DIV_3; /* (o)(1) */ | |
| 362 } else { | |
| 363 if (is_extended) { | |
| 364 x12_count += DM_MULT_13_DIV_3; /* (o)(2) */ | |
| 365 } else { | |
| 366 x12_count += DM_MULT_10_DIV_3; /* (o)(3) */ | |
| 367 } | |
| 368 } | |
| 369 | |
| 370 /* edifact ... step (p) */ | |
| 371 if (dm_isedifact(c)) { | |
| 372 edf_count += DM_MULT_3_DIV_4; /* (p)(1) */ | |
| 373 } else { | |
| 374 if (is_extended) { | |
| 375 edf_count += DM_MULT_17_DIV_4; /* (p)(2) */ | |
| 376 } else { | |
| 377 edf_count += DM_MULT_13_DIV_4; /* (p)(3) */ | |
| 378 } | |
| 379 } | |
| 380 | |
| 381 /* base 256 ... step (q) */ | |
| 382 if (gs1 == 1 && c == '\x1D') { | |
| 383 /* FNC1 separator */ | |
| 384 b256_count += DM_MULT_4; /* (q)(1) */ | |
| 385 } else { | |
| 386 b256_count += DM_MULT_1; /* (q)(2) */ | |
| 387 } | |
| 388 | |
| 389 if (sp >= position + 3) { | |
| 390 /* At least 4 data characters processed ... step (r) */ | |
| 391 /* NOTE: previous behaviour was at least 5 (same as BWIPP) */ | |
| 392 | |
| 393 if (debug_print) { | |
| 394 printf("\n(m:%d, p:%d, sp:%d, a:%d): ascii_count %d, b256_count %d, edf_count %d, text_count %d" | |
| 395 ", x12_count %d, c40_count %d ", | |
| 396 current_mode, position, sp, mode_arg, ascii_count, b256_count, edf_count, text_count, | |
| 397 x12_count, c40_count); | |
| 398 } | |
| 399 | |
| 400 cnt_1 = ascii_count + DM_MULT_1; | |
| 401 /* Adjusted from <= b256_count */ | |
| 402 if (cnt_1 < b256_count && cnt_1 <= edf_count && cnt_1 <= text_count && cnt_1 <= x12_count | |
| 403 && cnt_1 <= c40_count) { | |
| 404 if (debug_print) fputs("ASC->", stdout); | |
| 405 return DM_ASCII; /* step (r)(1) */ | |
| 406 } | |
| 407 cnt_1 = b256_count + DM_MULT_1; | |
| 408 if (cnt_1 <= ascii_count || (cnt_1 < edf_count && cnt_1 < text_count && cnt_1 < x12_count | |
| 409 && cnt_1 < c40_count)) { | |
| 410 if (debug_print) fputs("BAS->", stdout); | |
| 411 return DM_BASE256; /* step (r)(2) */ | |
| 412 } | |
| 413 cnt_1 = edf_count + DM_MULT_1; | |
| 414 if (cnt_1 < ascii_count && cnt_1 < b256_count && cnt_1 < text_count && cnt_1 < x12_count | |
| 415 && cnt_1 < c40_count) { | |
| 416 if (debug_print) fputs("EDI->", stdout); | |
| 417 return DM_EDIFACT; /* step (r)(3) */ | |
| 418 } | |
| 419 cnt_1 = text_count + DM_MULT_1; | |
| 420 if (cnt_1 < ascii_count && cnt_1 < b256_count && cnt_1 < edf_count && cnt_1 < x12_count | |
| 421 && cnt_1 < c40_count) { | |
| 422 /* Adjusted to avoid early exit from Base 256 if have less than break-even sequence of TEXT chars */ | |
| 423 if (current_mode == DM_BASE256 && position + 6 < length) { | |
| 424 if (dm_text_sp_cnt(source, position, length, sp) >= 12) { | |
| 425 if (debug_print) fputs("TEX->", stdout); | |
| 426 return DM_TEXT; /* step (r)(4) */ | |
| 427 } | |
| 428 } else { | |
| 429 if (debug_print) fputs("TEX->", stdout); | |
| 430 return DM_TEXT; /* step (r)(4) */ | |
| 431 } | |
| 432 } | |
| 433 cnt_1 = x12_count + DM_MULT_1; | |
| 434 if (cnt_1 < ascii_count && cnt_1 < b256_count && cnt_1 < edf_count && cnt_1 < text_count | |
| 435 && cnt_1 < c40_count) { | |
| 436 if (debug_print) fputs("X12->", stdout); | |
| 437 return DM_X12; /* step (r)(5) */ | |
| 438 } | |
| 439 cnt_1 = c40_count + DM_MULT_1; | |
| 440 if (cnt_1 < ascii_count && cnt_1 < b256_count && cnt_1 < edf_count && cnt_1 < text_count) { | |
| 441 if (c40_count < x12_count) { | |
| 442 if (debug_print) fputs("C40->", stdout); | |
| 443 return DM_C40; /* step (r)(6)(i) */ | |
| 444 } | |
| 445 if (c40_count == x12_count) { | |
| 446 if (dm_substep_r_6_2_1(source, length, sp) == 1) { | |
| 447 if (debug_print) fputs("X12->", stdout); | |
| 448 return DM_X12; /* step (r)(6)(ii)(I) */ | |
| 449 } | |
| 450 if (debug_print) fputs("C40->", stdout); | |
| 451 return DM_C40; /* step (r)(6)(ii)(II) */ | |
| 452 } | |
| 453 } | |
| 454 } | |
| 455 } | |
| 456 | |
| 457 /* At the end of data ... step (k) */ | |
| 458 /* step (k)(1) */ | |
| 459 ascii_rnded = DM_MULT_CEIL(ascii_count); | |
| 460 b256_rnded = DM_MULT_CEIL(b256_count); | |
| 461 edf_rnded = DM_MULT_CEIL(edf_count); | |
| 462 text_rnded = DM_MULT_CEIL(text_count); | |
| 463 x12_rnded = DM_MULT_CEIL(x12_count); | |
| 464 c40_rnded = DM_MULT_CEIL(c40_count); | |
| 465 if (debug_print) { | |
| 466 printf("\nEOD(m:%d, p:%d, a:%d): ascii_rnded %d, b256_rnded %d, edf_rnded %d, text_rnded %d" | |
| 467 ", x12_rnded %d (%d), c40_rnded %d (%d) ", | |
| 468 current_mode, position, mode_arg, ascii_rnded, b256_rnded, edf_rnded, text_rnded, | |
| 469 x12_rnded, x12_count, c40_rnded, c40_count); | |
| 470 } | |
| 471 | |
| 472 if (ascii_rnded <= b256_rnded && ascii_rnded <= edf_rnded && ascii_rnded <= text_rnded && ascii_rnded <= x12_rnded | |
| 473 && ascii_rnded <= c40_rnded) { | |
| 474 if (debug_print) fputs("ASC->", stdout); | |
| 475 return DM_ASCII; /* step (k)(2) */ | |
| 476 } | |
| 477 if (b256_rnded < ascii_rnded && b256_rnded < edf_rnded && b256_rnded < text_rnded && b256_rnded < x12_rnded | |
| 478 && b256_rnded < c40_rnded) { | |
| 479 if (debug_print) fputs("BAS->", stdout); | |
| 480 return DM_BASE256; /* step (k)(3) */ | |
| 481 } | |
| 482 /* Adjusted from < x12_rnded */ | |
| 483 if (edf_rnded < ascii_rnded && edf_rnded < b256_rnded && edf_rnded < text_rnded && edf_rnded <= x12_rnded | |
| 484 && edf_rnded < c40_rnded) { | |
| 485 if (debug_print) fputs("EDI->", stdout); | |
| 486 return DM_EDIFACT; /* step (k)(4) */ | |
| 487 } | |
| 488 if (text_rnded < ascii_rnded && text_rnded < b256_rnded && text_rnded < edf_rnded && text_rnded < x12_rnded | |
| 489 && text_rnded < c40_rnded) { | |
| 490 if (debug_print) fputs("TEX->", stdout); | |
| 491 return DM_TEXT; /* step (k)(5) */ | |
| 492 } | |
| 493 /* Adjusted from < edf_rnded */ | |
| 494 if (x12_rnded < ascii_rnded && x12_rnded < b256_rnded && x12_rnded <= edf_rnded && x12_rnded < text_rnded | |
| 495 && x12_rnded < c40_rnded) { | |
| 496 if (debug_print) fputs("X12->", stdout); | |
| 497 return DM_X12; /* step (k)(6) */ | |
| 498 } | |
| 499 if (debug_print) fputs("C40->", stdout); | |
| 500 return DM_C40; /* step (k)(7) */ | |
| 501 } | |
| 502 | |
| 503 /* Copy C40/TEXT/X12 triplets from buffer to target. Returns elements left in buffer (< 3) */ | |
| 504 static int dm_ctx_buffer_xfer(int process_buffer[8], int process_p, unsigned char target[], int *p_tp, | |
| 505 const int debug_print) { | |
| 506 int i, process_e; | |
| 507 int tp = *p_tp; | |
| 508 | |
| 509 process_e = (process_p / 3) * 3; | |
| 510 | |
| 511 for (i = 0; i < process_e; i += 3) { | |
| 512 int iv = (1600 * process_buffer[i]) + (40 * process_buffer[i + 1]) + (process_buffer[i + 2]) + 1; | |
| 513 target[tp++] = (unsigned char) (iv >> 8); | |
| 514 target[tp++] = (unsigned char) (iv & 0xFF); | |
| 515 if (debug_print) { | |
| 516 printf("[%d %d %d (%d %d)] ", process_buffer[i], process_buffer[i + 1], process_buffer[i + 2], | |
| 517 target[tp - 2], target[tp - 1]); | |
| 518 } | |
| 519 } | |
| 520 | |
| 521 process_p -= process_e; | |
| 522 | |
| 523 if (process_p) { | |
| 524 memmove(process_buffer, process_buffer + process_e, sizeof(int) * process_p); | |
| 525 } | |
| 526 | |
| 527 *p_tp = tp; | |
| 528 | |
| 529 return process_p; | |
| 530 } | |
| 531 | |
| 532 /* Copy EDIFACT quadruplets from buffer to target. Returns elements left in buffer (< 4) */ | |
| 533 static int dm_edi_buffer_xfer(int process_buffer[8], int process_p, unsigned char target[], int *p_tp, | |
| 534 const int empty, const int debug_print) { | |
| 535 int i, process_e; | |
| 536 int tp = *p_tp; | |
| 537 | |
| 538 process_e = (process_p / 4) * 4; | |
| 539 | |
| 540 for (i = 0; i < process_e; i += 4) { | |
| 541 target[tp++] = (unsigned char) (process_buffer[i] << 2 | (process_buffer[i + 1] & 0x30) >> 4); | |
| 542 target[tp++] = (unsigned char) ((process_buffer[i + 1] & 0x0f) << 4 | (process_buffer[i + 2] & 0x3c) >> 2); | |
| 543 target[tp++] = (unsigned char) ((process_buffer[i + 2] & 0x03) << 6 | process_buffer[i + 3]); | |
| 544 if (debug_print) { | |
| 545 printf("[%d %d %d %d (%d %d %d)] ", process_buffer[i], process_buffer[i + 1], process_buffer[i + 2], | |
| 546 process_buffer[i + 3], target[tp - 3], target[tp - 2], target[tp - 1]); | |
| 547 } | |
| 548 } | |
| 549 | |
| 550 process_p -= process_e; | |
| 551 | |
| 552 if (process_p) { | |
| 553 memmove(process_buffer, process_buffer + process_e, sizeof(int) * process_p); | |
| 554 if (empty) { | |
| 555 if (process_p == 3) { | |
| 556 target[tp++] = (unsigned char) (process_buffer[i] << 2 | (process_buffer[i + 1] & 0x30) >> 4); | |
| 557 target[tp++] = (unsigned char) ((process_buffer[i + 1] & 0x0f) << 4 | |
| 558 | (process_buffer[i + 2] & 0x3c) >> 2); | |
| 559 target[tp++] = (unsigned char) ((process_buffer[i + 2] & 0x03) << 6); | |
| 560 if (debug_print) { | |
| 561 printf("[%d %d %d (%d %d %d)] ", process_buffer[i], process_buffer[i + 1], process_buffer[i + 2], | |
| 562 target[tp - 3], target[tp - 2], target[tp - 1]); | |
| 563 } | |
| 564 } else if (process_p == 2) { | |
| 565 target[tp++] = (unsigned char) (process_buffer[i] << 2 | (process_buffer[i + 1] & 0x30) >> 4); | |
| 566 target[tp++] = (unsigned char) ((process_buffer[i + 1] & 0x0f) << 4); | |
| 567 if (debug_print) { | |
| 568 printf("[%d %d (%d %d)] ", process_buffer[i], process_buffer[i + 1], target[tp - 2], | |
| 569 target[tp - 1]); | |
| 570 } | |
| 571 } else { | |
| 572 target[tp++] = (unsigned char) (process_buffer[i] << 2); | |
| 573 if (debug_print) printf("[%d (%d)] ", process_buffer[i], target[tp - 1]); | |
| 574 } | |
| 575 process_p = 0; | |
| 576 } | |
| 577 } | |
| 578 | |
| 579 *p_tp = tp; | |
| 580 | |
| 581 return process_p; | |
| 582 } | |
| 583 | |
| 584 /* Get index of symbol size in codewords array `dm_matrixbytes`, as specified or | |
| 585 else smallest containing `minimum` codewords */ | |
| 586 static int dm_get_symbolsize(struct zint_symbol *symbol, const int minimum) { | |
| 587 int i; | |
| 588 | |
| 589 if ((symbol->option_2 >= 1) && (symbol->option_2 <= DMSIZESCOUNT)) { | |
| 590 return dm_intsymbol[symbol->option_2 - 1]; | |
| 591 } | |
| 592 if (minimum > 1304) { | |
| 593 return minimum <= 1558 ? DMSIZESCOUNT - 1 : 0; | |
| 594 } | |
| 595 for (i = minimum >= 62 ? 23 : 0; minimum > dm_matrixbytes[i]; i++); | |
| 596 | |
| 597 if ((symbol->option_3 & 0x7F) == DM_DMRE) { | |
| 598 return i; | |
| 599 } | |
| 600 if ((symbol->option_3 & 0x7F) == DM_SQUARE) { | |
| 601 /* Skip rectangular symbols in square only mode */ | |
| 602 for (; dm_matrixH[i] != dm_matrixW[i]; i++); | |
| 603 return i; | |
| 604 } | |
| 605 /* Skip DMRE symbols in no dmre mode */ | |
| 606 for (; dm_isDMRE[i]; i++); | |
| 607 return i; | |
| 608 } | |
| 609 | |
| 610 /* Number of codewords remaining in a particular version (may be negative) */ | |
| 611 static int dm_codewords_remaining(struct zint_symbol *symbol, const int tp, const int process_p) { | |
| 612 int symbolsize = dm_get_symbolsize(symbol, tp + process_p); /* Allow for the remaining data characters */ | |
| 613 | |
| 614 return dm_matrixbytes[symbolsize] - tp; | |
| 615 } | |
| 616 | |
| 617 /* Number of C40/TEXT elements needed to encode `input` */ | |
| 618 static int dm_c40text_cnt(const int current_mode, const int gs1, unsigned char input) { | |
| 619 int cnt; | |
| 620 | |
| 621 if (gs1 && input == '\x1D') { | |
| 622 return 2; | |
| 623 } | |
| 624 cnt = 1; | |
| 625 if (input & 0x80) { | |
| 626 cnt += 2; | |
| 627 input = input - 128; | |
| 628 } | |
| 629 if ((current_mode == DM_C40 && dm_c40_shift[input]) || (current_mode == DM_TEXT && dm_text_shift[input])) { | |
| 630 cnt += 1; | |
| 631 } | |
| 632 | |
| 633 return cnt; | |
| 634 } | |
| 635 | |
| 636 /* Update Base 256 field length */ | |
| 637 static int dm_update_b256_field_length(unsigned char target[], int tp, int b256_start) { | |
| 638 int b256_count = tp - (b256_start + 1); | |
| 639 if (b256_count <= 249) { | |
| 640 target[b256_start] = b256_count; | |
| 641 } else { | |
| 642 /* Insert extra codeword */ | |
| 643 memmove(target + b256_start + 2, target + b256_start + 1, b256_count); | |
| 644 target[b256_start] = (unsigned char) (249 + (b256_count / 250)); | |
| 645 target[b256_start + 1] = (unsigned char) (b256_count % 250); | |
| 646 tp++; | |
| 647 } | |
| 648 | |
| 649 return tp; | |
| 650 } | |
| 651 | |
| 652 /* Switch from ASCII or Base 256 to another mode */ | |
| 653 static int dm_switch_mode(const int next_mode, unsigned char target[], int tp, int *p_b256_start, | |
| 654 const int debug_print) { | |
| 655 switch (next_mode) { | |
| 656 case DM_ASCII: | |
| 657 if (debug_print) fputs("ASC ", stdout); | |
| 658 break; | |
| 659 case DM_C40: target[tp++] = 230; | |
| 660 if (debug_print) fputs("C40 ", stdout); | |
| 661 break; | |
| 662 case DM_TEXT: target[tp++] = 239; | |
| 663 if (debug_print) fputs("TEX ", stdout); | |
| 664 break; | |
| 665 case DM_X12: target[tp++] = 238; | |
| 666 if (debug_print) fputs("X12 ", stdout); | |
| 667 break; | |
| 668 case DM_EDIFACT: target[tp++] = 240; | |
| 669 if (debug_print) fputs("EDI ", stdout); | |
| 670 break; | |
| 671 case DM_BASE256: target[tp++] = 231; | |
| 672 *p_b256_start = tp; | |
| 673 target[tp++] = 0; /* Byte count holder (may be expanded to 2 codewords) */ | |
| 674 if (debug_print) fputs("BAS ", stdout); | |
| 675 break; | |
| 676 } | |
| 677 | |
| 678 return tp; | |
| 679 } | |
| 680 | |
| 681 /* Minimal encoding using Dijkstra-based algorithm by Alex Geller | |
| 682 Note due to the complicated end-of-data (EOD) conditions that Data Matrix has, this may not be fully minimal; | |
| 683 however no counter-examples are known at present */ | |
| 684 | |
| 685 #define DM_NUM_MODES 6 | |
| 686 | |
| 687 static const char dm_smodes[DM_NUM_MODES + 1][6] = { "?", "ASCII", "C40", "TEXT", "X12", "EDF", "B256" }; | |
| 688 | |
| 689 /* The size of this structure could be significantly reduced using techniques pointed out by Alex Geller, | |
| 690 but not done currently to avoid the processing overhead */ | |
| 691 struct dm_edge { | |
| 692 unsigned char mode; | |
| 693 unsigned char endMode; /* Mode returned by `dm_getEndMode()` */ | |
| 694 unsigned short from; /* Position in input data, 0-based */ | |
| 695 unsigned short len; | |
| 696 unsigned short size; /* Cumulative number of codewords */ | |
| 697 unsigned short bytes; /* DM_BASE256 byte count, kept to avoid runtime calc */ | |
| 698 unsigned short previous; /* Index into edges array */ | |
| 699 }; | |
| 700 | |
| 701 /* Note 1st row of edges not used so valid previous cannot point there, i.e. won't be zero */ | |
| 702 #define DM_PREVIOUS(edges, edge) \ | |
| 703 ((edge)->previous ? (edges) + (edge)->previous : NULL) | |
| 704 | |
| 705 /* Determine if next 1 to 4 chars are at EOD and can be encoded as 1 or 2 ASCII codewords */ | |
| 706 static int dm_last_ascii(const unsigned char source[], const int length, const int from) { | |
| 707 if (length - from > 4 || from >= length) { | |
| 708 return 0; | |
| 709 } | |
| 710 if (length - from == 1) { | |
| 711 if (source[from] & 0x80) { | |
| 712 return 0; | |
| 713 } | |
| 714 return 1; | |
| 715 } | |
| 716 if (length - from == 2) { | |
| 717 if ((source[from] & 0x80) || (source[from + 1] & 0x80)) { | |
| 718 return 0; | |
| 719 } | |
| 720 if (z_isdigit(source[from]) && z_isdigit(source[from + 1])) { | |
| 721 return 1; | |
| 722 } | |
| 723 return 2; | |
| 724 } | |
| 725 if (length - from == 3) { | |
| 726 if (z_isdigit(source[from]) && z_isdigit(source[from + 1]) && !(source[from + 2] & 0x80)) { | |
| 727 return 2; | |
| 728 } | |
| 729 if (z_isdigit(source[from + 1]) && z_isdigit(source[from + 2]) && !(source[from] & 0x80)) { | |
| 730 return 2; | |
| 731 } | |
| 732 return 0; | |
| 733 } | |
| 734 if (z_isdigit(source[from]) && z_isdigit(source[from + 1]) && z_isdigit(source[from + 2]) | |
| 735 && z_isdigit(source[from + 3])) { | |
| 736 return 2; | |
| 737 } | |
| 738 return 0; | |
| 739 } | |
| 740 | |
| 741 /* Treat EDIFACT edges specially, returning DM_ASCII mode if not full (i.e. encoding < 4 chars), or if | |
| 742 full and at EOD where 1 or 2 ASCII chars can be encoded */ | |
| 743 static int dm_getEndMode(struct zint_symbol *symbol, const unsigned char *source, const int length, const int mode, | |
| 744 const int from, const int len, const int size) { | |
| 745 if (mode == DM_EDIFACT) { | |
| 746 int last_ascii; | |
| 747 if (len < 4) { | |
| 748 return DM_ASCII; | |
| 749 } | |
| 750 last_ascii = dm_last_ascii(source, length, from + len); | |
| 751 if (last_ascii) { /* At EOD with remaining chars ASCII-encodable in 1 or 2 codewords */ | |
| 752 const int symbols_left = dm_codewords_remaining(symbol, size + last_ascii, 0); | |
| 753 /* If no codewords left and 1 or 2 ASCII-encodables or 1 codeword left and 1 ASCII-encodable */ | |
| 754 if (symbols_left <= 2 - last_ascii) { | |
| 755 return DM_ASCII; | |
| 756 } | |
| 757 } | |
| 758 } | |
| 759 return mode; | |
| 760 } | |
| 761 | |
| 762 #if 0 | |
| 763 #define DM_TRACE | |
| 764 #endif | |
| 765 #include "dmatrix_trace.h" | |
| 766 | |
| 767 /* Return number of C40/TEXT codewords needed to encode characters in full batches of 3 (or less if EOD). | |
| 768 The number of characters encoded is returned in `len` */ | |
| 769 static int dm_getNumberOfC40Words(const unsigned char *source, const int length, const int from, const int mode, | |
| 770 int *len) { | |
| 771 int thirdsCount = 0; | |
| 772 int i; | |
| 773 | |
| 774 for (i = from; i < length; i++) { | |
| 775 const unsigned char ci = source[i]; | |
| 776 int remainder; | |
| 777 | |
| 778 if (dm_isc40text(mode, ci)) { | |
| 779 thirdsCount++; /* Native */ | |
| 780 } else if (!(ci & 0x80)) { | |
| 781 thirdsCount += 2; /* Shift */ | |
| 782 } else if (dm_isc40text(mode, (unsigned char) (ci & 0x7F))) { | |
| 783 thirdsCount += 3; /* Shift, Upper shift */ | |
| 784 } else { | |
| 785 thirdsCount += 4; /* Shift, Upper shift, shift */ | |
| 786 } | |
| 787 | |
| 788 remainder = thirdsCount % 3; | |
| 789 if (remainder == 0 || (remainder == 2 && i + 1 == length)) { | |
| 790 *len = i - from + 1; | |
| 791 return ((thirdsCount + 2) / 3) * 2; | |
| 792 } | |
| 793 } | |
| 794 *len = 0; | |
| 795 return 0; | |
| 796 } | |
| 797 | |
| 798 /* Initialize a new edge. Returns endMode */ | |
| 799 static int dm_new_Edge(struct zint_symbol *symbol, const unsigned char *source, const int length, | |
| 800 struct dm_edge *edges, const int mode, const int from, const int len, struct dm_edge *previous, | |
| 801 struct dm_edge *edge, const int cwds) { | |
| 802 int previousMode; | |
| 803 int size; | |
| 804 int last_ascii, symbols_left; | |
| 805 | |
| 806 edge->mode = mode; | |
| 807 edge->endMode = mode; | |
| 808 edge->from = from; | |
| 809 edge->len = len; | |
| 810 edge->bytes = 0; | |
| 811 if (previous) { | |
| 812 assert(previous->mode && previous->len && previous->size && previous->endMode); | |
| 813 previousMode = previous->endMode; | |
| 814 edge->previous = previous - edges; | |
| 815 size = previous->size; | |
| 816 } else { | |
| 817 previousMode = DM_ASCII; | |
| 818 edge->previous = 0; | |
| 819 size = 0; | |
| 820 } | |
| 821 | |
| 822 switch (mode) { | |
| 823 case DM_ASCII: | |
| 824 assert(previousMode != DM_EDIFACT); | |
| 825 size++; | |
| 826 if (source[from] & 0x80) { | |
| 827 size++; | |
| 828 } | |
| 829 if (previousMode != DM_ASCII && previousMode != DM_BASE256) { | |
| 830 size++; /* Unlatch to ASCII */ | |
| 831 } | |
| 832 break; | |
| 833 | |
| 834 case DM_BASE256: | |
| 835 assert(previousMode != DM_EDIFACT); | |
| 836 size++; | |
| 837 if (previousMode != DM_BASE256) { | |
| 838 size += 2; /* Byte count + latch to BASE256 */ | |
| 839 if (previousMode != DM_ASCII) { | |
| 840 size++; /* Unlatch to ASCII */ | |
| 841 } | |
| 842 edge->bytes = 1; | |
| 843 } else { | |
| 844 assert(previous); | |
| 845 edge->bytes = 1 + previous->bytes; | |
| 846 if (edge->bytes == 250) { | |
| 847 size++; /* Extra byte count */ | |
| 848 } | |
| 849 } | |
| 850 break; | |
| 851 | |
| 852 case DM_C40: | |
| 853 case DM_TEXT: | |
| 854 assert(previousMode != DM_EDIFACT); | |
| 855 size += cwds; | |
| 856 if (previousMode != mode) { | |
| 857 size++; /* Latch to this mode */ | |
| 858 if (previousMode != DM_ASCII && previousMode != DM_BASE256) { | |
| 859 size++; /* Unlatch to ASCII */ | |
| 860 } | |
| 861 } | |
| 862 if (from + len + 2 >= length) { /* If less than batch of 3 away from EOD */ | |
| 863 last_ascii = dm_last_ascii(source, length, from + len); | |
| 864 symbols_left = dm_codewords_remaining(symbol, size + last_ascii, 0); | |
| 865 if (symbols_left > 0) { | |
| 866 size++; /* We need an extra unlatch at the end */ | |
| 867 } | |
| 868 } | |
| 869 break; | |
| 870 | |
| 871 case DM_X12: | |
| 872 assert(previousMode != DM_EDIFACT); | |
| 873 size += 2; | |
| 874 if (previousMode != DM_X12) { | |
| 875 size++; /* Latch to this mode */ | |
| 876 if (previousMode != DM_ASCII && previousMode != DM_BASE256) { | |
| 877 size++; /* Unlatch to ASCII */ | |
| 878 } | |
| 879 } | |
| 880 if (from + len + 2 >= length) { /* If less than batch of 3 away from EOD */ | |
| 881 last_ascii = dm_last_ascii(source, length, from + len); | |
| 882 if (last_ascii == 2) { /* Only 1 ASCII-encodable allowed at EOD for X12, unlike C40/TEXT */ | |
| 883 size++; /* We need an extra unlatch at the end */ | |
| 884 } else { | |
| 885 symbols_left = dm_codewords_remaining(symbol, size + last_ascii, 0); | |
| 886 if (symbols_left > 0) { | |
| 887 size++; /* We need an extra unlatch at the end */ | |
| 888 } | |
| 889 } | |
| 890 } | |
| 891 break; | |
| 892 | |
| 893 case DM_EDIFACT: | |
| 894 size += 3; | |
| 895 if (previousMode != DM_EDIFACT) { | |
| 896 size++; /* Latch to this mode */ | |
| 897 if (previousMode != DM_ASCII && previousMode != DM_BASE256) { | |
| 898 size++; /* Unlatch to ASCII */ | |
| 899 } | |
| 900 } | |
| 901 edge->endMode = dm_getEndMode(symbol, source, length, mode, from, len, size); | |
| 902 break; | |
| 903 } | |
| 904 edge->size = size; | |
| 905 | |
| 906 return edge->endMode; | |
| 907 } | |
| 908 | |
| 909 /* Add an edge for a mode at a vertex if no existing edge or if more optimal than existing edge */ | |
| 910 static void dm_addEdge(struct zint_symbol *symbol, const unsigned char *source, const int length, | |
| 911 struct dm_edge *edges, const int mode, const int from, const int len, struct dm_edge *previous, | |
| 912 const int cwds) { | |
| 913 struct dm_edge edge; | |
| 914 const int endMode = dm_new_Edge(symbol, source, length, edges, mode, from, len, previous, &edge, cwds); | |
| 915 const int vertexIndex = from + len; | |
| 916 const int v_ij = vertexIndex * DM_NUM_MODES + endMode - 1; | |
| 917 | |
| 918 if (edges[v_ij].mode == 0 || edges[v_ij].size > edge.size) { | |
| 919 DM_TRACE_AddEdge(source, length, edges, previous, vertexIndex, &edge); | |
| 920 edges[v_ij] = edge; | |
| 921 } else { | |
| 922 DM_TRACE_NotAddEdge(source, length, edges, previous, vertexIndex, v_ij, &edge); | |
| 923 } | |
| 924 } | |
| 925 | |
| 926 /* Add edges for the various modes at a vertex */ | |
| 927 static void dm_addEdges(struct zint_symbol *symbol, const unsigned char source[], const int length, | |
| 928 struct dm_edge *edges, const int from, struct dm_edge *previous, const int gs1) { | |
| 929 int i, pos; | |
| 930 | |
| 931 /* Not possible to unlatch a full EDF edge to something else */ | |
| 932 if (previous == NULL || previous->endMode != DM_EDIFACT) { | |
| 933 | |
| 934 static const char c40text_modes[] = { DM_C40, DM_TEXT }; | |
| 935 | |
| 936 if (z_isdigit(source[from]) && from + 1 < length && z_isdigit(source[from + 1])) { | |
| 937 dm_addEdge(symbol, source, length, edges, DM_ASCII, from, 2, previous, 0); | |
| 938 /* If ASCII vertex, don't bother adding other edges as this will be optimal; suggested by Alex Geller */ | |
| 939 if (previous && previous->mode == DM_ASCII) { | |
| 940 return; | |
| 941 } | |
| 942 } else { | |
| 943 dm_addEdge(symbol, source, length, edges, DM_ASCII, from, 1, previous, 0); | |
| 944 } | |
| 945 | |
| 946 for (i = 0; i < ARRAY_SIZE(c40text_modes); i++) { | |
| 947 int len; | |
| 948 int cwds = dm_getNumberOfC40Words(source, length, from, c40text_modes[i], &len); | |
| 949 if (cwds) { | |
| 950 dm_addEdge(symbol, source, length, edges, c40text_modes[i], from, len, previous, cwds); | |
| 951 } | |
| 952 } | |
| 953 | |
| 954 if (from + 2 < length && dm_isX12(source[from]) && dm_isX12(source[from + 1]) && dm_isX12(source[from + 2])) { | |
| 955 dm_addEdge(symbol, source, length, edges, DM_X12, from, 3, previous, 0); | |
| 956 } | |
| 957 | |
| 958 if (gs1 != 1 || source[from] != '\x1D') { | |
| 959 dm_addEdge(symbol, source, length, edges, DM_BASE256, from, 1, previous, 0); | |
| 960 } | |
| 961 } | |
| 962 | |
| 963 if (dm_isedifact(source[from])) { | |
| 964 /* We create 3 EDF edges, 2, 3 or 4 characters length. The 4-char normally doesn't have a latch to ASCII | |
| 965 unless it is 2 characters away from the end of the input. */ | |
| 966 for (i = 1, pos = from + i; i < 4 && pos < length && dm_isedifact(source[pos]); i++, pos++) { | |
| 967 dm_addEdge(symbol, source, length, edges, DM_EDIFACT, from, i + 1, previous, 0); | |
| 968 } | |
| 969 } | |
| 970 } | |
| 971 | |
| 972 /* Calculate optimized encoding modes */ | |
| 973 static int dm_define_mode(struct zint_symbol *symbol, char modes[], const unsigned char source[], const int length, | |
| 974 const int gs1, const int debug_print) { | |
| 975 | |
| 976 int i, j, v_i; | |
| 977 int minimalJ, minimalSize; | |
| 978 struct dm_edge *edge; | |
| 979 int current_mode; | |
| 980 int mode_end, mode_len; | |
| 981 | |
| 982 struct dm_edge *edges = (struct dm_edge *) calloc((length + 1) * DM_NUM_MODES, sizeof(struct dm_edge)); | |
| 983 if (!edges) { | |
| 984 return 0; | |
| 985 } | |
| 986 dm_addEdges(symbol, source, length, edges, 0, NULL, gs1); | |
| 987 | |
| 988 DM_TRACE_Edges("DEBUG Initial situation\n", source, length, edges, 0); | |
| 989 | |
| 990 for (i = 1; i < length; i++) { | |
| 991 v_i = i * DM_NUM_MODES; | |
| 992 for (j = 0; j < DM_NUM_MODES; j++) { | |
| 993 if (edges[v_i + j].mode) { | |
| 994 dm_addEdges(symbol, source, length, edges, i, edges + v_i + j, gs1); | |
| 995 } | |
| 996 } | |
| 997 DM_TRACE_Edges("DEBUG situation after adding edges to vertices at position %d\n", source, length, edges, i); | |
| 998 } | |
| 999 | |
| 1000 DM_TRACE_Edges("DEBUG Final situation\n", source, length, edges, length); | |
| 1001 | |
| 1002 v_i = length * DM_NUM_MODES; | |
| 1003 minimalJ = -1; | |
| 1004 minimalSize = INT_MAX; | |
| 1005 for (j = 0; j < DM_NUM_MODES; j++) { | |
| 1006 edge = edges + v_i + j; | |
| 1007 if (edge->mode) { | |
| 1008 if (debug_print) printf("edges[%d][%d][0] size %d\n", length, j, edge->size); | |
| 1009 if (edge->size < minimalSize) { | |
| 1010 minimalSize = edge->size; | |
| 1011 minimalJ = j; | |
| 1012 if (debug_print) printf(" set minimalJ %d\n", minimalJ); | |
| 1013 } | |
| 1014 } else { | |
| 1015 if (debug_print) printf("edges[%d][%d][0] NULL\n", length, j); | |
| 1016 } | |
| 1017 } | |
| 1018 assert(minimalJ >= 0); | |
| 1019 | |
| 1020 edge = edges + v_i + minimalJ; | |
| 1021 mode_len = 0; | |
| 1022 mode_end = length; | |
| 1023 while (edge) { | |
| 1024 current_mode = edge->mode; | |
| 1025 mode_len += edge->len; | |
| 1026 edge = DM_PREVIOUS(edges, edge); | |
| 1027 if (!edge || edge->mode != current_mode) { | |
| 1028 for (i = mode_end - mode_len; i < mode_end; i++) { | |
| 1029 modes[i] = current_mode; | |
| 1030 } | |
| 1031 mode_end = mode_end - mode_len; | |
| 1032 mode_len = 0; | |
| 1033 } | |
| 1034 } | |
| 1035 | |
| 1036 if (debug_print) { | |
| 1037 printf("modes (%d): ", length); | |
| 1038 for (i = 0; i < length; i++) printf("%c", dm_smodes[(int) modes[i]][0]); | |
| 1039 fputc('\n', stdout); | |
| 1040 } | |
| 1041 assert(mode_end == 0); | |
| 1042 | |
| 1043 free(edges); | |
| 1044 | |
| 1045 return 1; | |
| 1046 } | |
| 1047 | |
| 1048 /* Do default minimal encodation */ | |
| 1049 static int dm_minimalenc(struct zint_symbol *symbol, const unsigned char source[], const int length, int *p_sp, | |
| 1050 unsigned char target[], int *p_tp, int process_buffer[8], int *p_process_p, int *p_b256_start, | |
| 1051 int *p_current_mode, const int gs1, const int debug_print) { | |
| 1052 int sp = *p_sp; | |
| 1053 int tp = *p_tp; | |
| 1054 int process_p = *p_process_p; | |
| 1055 int current_mode = *p_current_mode; | |
| 1056 int last_ascii, symbols_left; | |
| 1057 int i; | |
| 1058 char *modes = (char *) z_alloca(length); | |
| 1059 | |
| 1060 assert(length <= 10921); /* Can only handle (10921 + 1) * 6 = 65532 < 65536 (2*16) due to sizeof(previous) */ | |
| 1061 | |
| 1062 if (!dm_define_mode(symbol, modes, source, length, gs1, debug_print)) { | |
| 1063 return errtxt(ZINT_ERROR_MEMORY, symbol, 728, "Insufficient memory for mode buffers"); | |
| 1064 } | |
| 1065 | |
| 1066 while (sp < length) { | |
| 1067 | |
| 1068 if (modes[sp] != current_mode) { | |
| 1069 switch (current_mode) { | |
| 1070 case DM_C40: | |
| 1071 case DM_TEXT: | |
| 1072 case DM_X12: | |
| 1073 process_p = 0; /* Throw away buffer if any */ | |
| 1074 target[tp++] = 254; /* Unlatch */ | |
| 1075 break; | |
| 1076 case DM_EDIFACT: | |
| 1077 last_ascii = dm_last_ascii(source, length, sp); | |
| 1078 if (!last_ascii) { | |
| 1079 process_buffer[process_p++] = 31; /* Unlatch */ | |
| 1080 } else { | |
| 1081 symbols_left = dm_codewords_remaining(symbol, tp + last_ascii, process_p); | |
| 1082 if (debug_print) { | |
| 1083 printf("process_p %d, last_ascii %d, symbols_left %d\n", | |
| 1084 process_p, last_ascii, symbols_left); | |
| 1085 } | |
| 1086 if (symbols_left > 2 - last_ascii) { | |
| 1087 process_buffer[process_p++] = 31; /* Unlatch */ | |
| 1088 } | |
| 1089 } | |
| 1090 process_p = dm_edi_buffer_xfer(process_buffer, process_p, target, &tp, 1 /*empty*/, debug_print); | |
| 1091 break; | |
| 1092 case DM_BASE256: | |
| 1093 tp = dm_update_b256_field_length(target, tp, *p_b256_start); | |
| 1094 /* B.2.1 255-state randomising algorithm */ | |
| 1095 for (i = *p_b256_start; i < tp; i++) { | |
| 1096 const int prn = ((149 * (i + 1)) % 255) + 1; | |
| 1097 target[i] = (unsigned char) ((target[i] + prn) & 0xFF); | |
| 1098 } | |
| 1099 break; | |
| 1100 } | |
| 1101 tp = dm_switch_mode(modes[sp], target, tp, p_b256_start, debug_print); | |
| 1102 } | |
| 1103 | |
| 1104 current_mode = modes[sp]; | |
| 1105 assert(current_mode); | |
| 1106 | |
| 1107 if (current_mode == DM_ASCII) { | |
| 1108 | |
| 1109 if (is_twodigits(source, length, sp)) { | |
| 1110 target[tp++] = (unsigned char) ((10 * ctoi(source[sp])) + ctoi(source[sp + 1]) + 130); | |
| 1111 if (debug_print) printf("N%02d ", target[tp - 1] - 130); | |
| 1112 sp += 2; | |
| 1113 } else { | |
| 1114 if (source[sp] & 0x80) { | |
| 1115 target[tp++] = 235; /* FNC4 */ | |
| 1116 target[tp++] = (source[sp] - 128) + 1; | |
| 1117 if (debug_print) printf("FN4 A%02X ", target[tp - 1] - 1); | |
| 1118 } else { | |
| 1119 if (gs1 && source[sp] == '\x1D') { | |
| 1120 if (gs1 == 2) { | |
| 1121 target[tp++] = 29 + 1; /* GS */ | |
| 1122 if (debug_print) fputs("GS ", stdout); | |
| 1123 } else { | |
| 1124 target[tp++] = 232; /* FNC1 */ | |
| 1125 if (debug_print) fputs("FN1 ", stdout); | |
| 1126 } | |
| 1127 } else { | |
| 1128 target[tp++] = source[sp] + 1; | |
| 1129 if (debug_print) printf("A%02X ", target[tp - 1] - 1); | |
| 1130 } | |
| 1131 } | |
| 1132 sp++; | |
| 1133 } | |
| 1134 | |
| 1135 } else if (current_mode == DM_C40 || current_mode == DM_TEXT) { | |
| 1136 | |
| 1137 int shift_set, value; | |
| 1138 const char *ct_shift, *ct_value; | |
| 1139 | |
| 1140 if (current_mode == DM_C40) { | |
| 1141 ct_shift = dm_c40_shift; | |
| 1142 ct_value = dm_c40_value; | |
| 1143 } else { | |
| 1144 ct_shift = dm_text_shift; | |
| 1145 ct_value = dm_text_value; | |
| 1146 } | |
| 1147 | |
| 1148 if (source[sp] & 0x80) { | |
| 1149 process_buffer[process_p++] = 1; | |
| 1150 process_buffer[process_p++] = 30; /* Upper Shift */ | |
| 1151 shift_set = ct_shift[source[sp] - 128]; | |
| 1152 value = ct_value[source[sp] - 128]; | |
| 1153 } else { | |
| 1154 if (gs1 && source[sp] == '\x1D') { | |
| 1155 if (gs1 == 2) { | |
| 1156 shift_set = ct_shift[29]; | |
| 1157 value = ct_value[29]; /* GS */ | |
| 1158 } else { | |
| 1159 shift_set = 2; | |
| 1160 value = 27; /* FNC1 */ | |
| 1161 } | |
| 1162 } else { | |
| 1163 shift_set = ct_shift[source[sp]]; | |
| 1164 value = ct_value[source[sp]]; | |
| 1165 } | |
| 1166 } | |
| 1167 | |
| 1168 if (shift_set != 0) { | |
| 1169 process_buffer[process_p++] = shift_set - 1; | |
| 1170 } | |
| 1171 process_buffer[process_p++] = value; | |
| 1172 | |
| 1173 if (process_p >= 3) { | |
| 1174 process_p = dm_ctx_buffer_xfer(process_buffer, process_p, target, &tp, debug_print); | |
| 1175 } | |
| 1176 sp++; | |
| 1177 | |
| 1178 } else if (current_mode == DM_X12) { | |
| 1179 | |
| 1180 static const char x12_nonalphanum_chars[] = "\015*> "; | |
| 1181 int value = 0; | |
| 1182 | |
| 1183 if (z_isdigit(source[sp])) { | |
| 1184 value = (source[sp] - '0') + 4; | |
| 1185 } else if (z_isupper(source[sp])) { | |
| 1186 value = (source[sp] - 'A') + 14; | |
| 1187 } else { | |
| 1188 value = posn(x12_nonalphanum_chars, source[sp]); | |
| 1189 } | |
| 1190 | |
| 1191 process_buffer[process_p++] = value; | |
| 1192 | |
| 1193 if (process_p >= 3) { | |
| 1194 process_p = dm_ctx_buffer_xfer(process_buffer, process_p, target, &tp, debug_print); | |
| 1195 } | |
| 1196 sp++; | |
| 1197 | |
| 1198 } else if (current_mode == DM_EDIFACT) { | |
| 1199 | |
| 1200 int value = source[sp]; | |
| 1201 | |
| 1202 if (value >= 64) { /* '@' */ | |
| 1203 value -= 64; | |
| 1204 } | |
| 1205 | |
| 1206 process_buffer[process_p++] = value; | |
| 1207 sp++; | |
| 1208 | |
| 1209 if (process_p >= 4) { | |
| 1210 process_p = dm_edi_buffer_xfer(process_buffer, process_p, target, &tp, 0 /*empty*/, debug_print); | |
| 1211 } | |
| 1212 | |
| 1213 } else if (current_mode == DM_BASE256) { | |
| 1214 | |
| 1215 target[tp++] = source[sp++]; | |
| 1216 if (debug_print) printf("B%02X ", target[tp - 1]); | |
| 1217 } | |
| 1218 | |
| 1219 if (tp > 1558) { | |
| 1220 return errtxt(ZINT_ERROR_TOO_LONG, symbol, 729, | |
| 1221 "Input too long, requires too many codewords (maximum 1558)"); | |
| 1222 } | |
| 1223 | |
| 1224 } /* while */ | |
| 1225 | |
| 1226 *p_sp = sp; | |
| 1227 *p_tp = tp; | |
| 1228 *p_process_p = process_p; | |
| 1229 *p_current_mode = current_mode; | |
| 1230 | |
| 1231 return 0; | |
| 1232 } | |
| 1233 | |
| 1234 /* Encode using algorithm based on ISO/IEC 21471:2020 Annex J (was ISO/IEC 21471:2006 Annex P) */ | |
| 1235 static int dm_isoenc(struct zint_symbol *symbol, const unsigned char source[], const int length, int *p_sp, | |
| 1236 unsigned char target[], int *p_tp, int process_buffer[8], int *p_process_p, int *p_b256_start, | |
| 1237 int *p_current_mode, const int gs1, const int debug_print) { | |
| 1238 const int mailmark = symbol->symbology == BARCODE_MAILMARK_2D; | |
| 1239 int sp = *p_sp; | |
| 1240 int tp = *p_tp; | |
| 1241 int process_p = *p_process_p; | |
| 1242 int current_mode = *p_current_mode; | |
| 1243 int not_first = 0; | |
| 1244 int i; | |
| 1245 | |
| 1246 /* step (a) */ | |
| 1247 int next_mode = DM_ASCII; | |
| 1248 | |
| 1249 if (mailmark) { /* First 45 characters C40 */ | |
| 1250 assert(length >= 45); | |
| 1251 next_mode = DM_C40; | |
| 1252 tp = dm_switch_mode(next_mode, target, tp, p_b256_start, debug_print); | |
| 1253 while (sp < 45) { | |
| 1254 assert(!(sp & 0x80)); | |
| 1255 process_buffer[process_p++] = dm_c40_value[source[sp]]; | |
| 1256 | |
| 1257 if (process_p >= 3) { | |
| 1258 process_p = dm_ctx_buffer_xfer(process_buffer, process_p, target, &tp, debug_print); | |
| 1259 } | |
| 1260 sp++; | |
| 1261 } | |
| 1262 current_mode = next_mode; | |
| 1263 not_first = 1; | |
| 1264 } | |
| 1265 | |
| 1266 while (sp < length) { | |
| 1267 | |
| 1268 current_mode = next_mode; | |
| 1269 | |
| 1270 /* step (b) - ASCII encodation */ | |
| 1271 if (current_mode == DM_ASCII) { | |
| 1272 next_mode = DM_ASCII; | |
| 1273 | |
| 1274 if (is_twodigits(source, length, sp)) { | |
| 1275 target[tp++] = (unsigned char) ((10 * ctoi(source[sp])) + ctoi(source[sp + 1]) + 130); | |
| 1276 if (debug_print) printf("N%02d ", target[tp - 1] - 130); | |
| 1277 sp += 2; | |
| 1278 } else { | |
| 1279 next_mode = dm_look_ahead_test(source, length, sp, current_mode, 0, gs1, debug_print); | |
| 1280 | |
| 1281 if (next_mode != DM_ASCII) { | |
| 1282 tp = dm_switch_mode(next_mode, target, tp, p_b256_start, debug_print); | |
| 1283 not_first = 0; | |
| 1284 } else { | |
| 1285 if (source[sp] & 0x80) { | |
| 1286 target[tp++] = 235; /* FNC4 */ | |
| 1287 target[tp++] = (source[sp] - 128) + 1; | |
| 1288 if (debug_print) printf("FN4 A%02X ", target[tp - 1] - 1); | |
| 1289 } else { | |
| 1290 if (gs1 && source[sp] == '\x1D') { | |
| 1291 if (gs1 == 2) { | |
| 1292 target[tp++] = 29 + 1; /* GS */ | |
| 1293 if (debug_print) fputs("GS ", stdout); | |
| 1294 } else { | |
| 1295 target[tp++] = 232; /* FNC1 */ | |
| 1296 if (debug_print) fputs("FN1 ", stdout); | |
| 1297 } | |
| 1298 } else { | |
| 1299 target[tp++] = source[sp] + 1; | |
| 1300 if (debug_print) printf("A%02X ", target[tp - 1] - 1); | |
| 1301 } | |
| 1302 } | |
| 1303 sp++; | |
| 1304 } | |
| 1305 } | |
| 1306 | |
| 1307 /* step (c)/(d) C40/TEXT encodation */ | |
| 1308 } else if (current_mode == DM_C40 || current_mode == DM_TEXT) { | |
| 1309 | |
| 1310 next_mode = current_mode; | |
| 1311 if (process_p == 0 && not_first) { | |
| 1312 next_mode = dm_look_ahead_test(source, length, sp, current_mode, process_p, gs1, debug_print); | |
| 1313 } | |
| 1314 | |
| 1315 if (next_mode != current_mode) { | |
| 1316 target[tp++] = 254; /* Unlatch */ | |
| 1317 next_mode = DM_ASCII; | |
| 1318 if (debug_print) fputs("ASC ", stdout); | |
| 1319 } else { | |
| 1320 int shift_set, value; | |
| 1321 const char *ct_shift, *ct_value; | |
| 1322 | |
| 1323 if (current_mode == DM_C40) { | |
| 1324 ct_shift = dm_c40_shift; | |
| 1325 ct_value = dm_c40_value; | |
| 1326 } else { | |
| 1327 ct_shift = dm_text_shift; | |
| 1328 ct_value = dm_text_value; | |
| 1329 } | |
| 1330 | |
| 1331 if (source[sp] & 0x80) { | |
| 1332 process_buffer[process_p++] = 1; | |
| 1333 process_buffer[process_p++] = 30; /* Upper Shift */ | |
| 1334 shift_set = ct_shift[source[sp] - 128]; | |
| 1335 value = ct_value[source[sp] - 128]; | |
| 1336 } else { | |
| 1337 if (gs1 && source[sp] == '\x1D') { | |
| 1338 if (gs1 == 2) { | |
| 1339 shift_set = ct_shift[29]; | |
| 1340 value = ct_value[29]; /* GS */ | |
| 1341 } else { | |
| 1342 shift_set = 2; | |
| 1343 value = 27; /* FNC1 */ | |
| 1344 } | |
| 1345 } else { | |
| 1346 shift_set = ct_shift[source[sp]]; | |
| 1347 value = ct_value[source[sp]]; | |
| 1348 } | |
| 1349 } | |
| 1350 | |
| 1351 if (shift_set != 0) { | |
| 1352 process_buffer[process_p++] = shift_set - 1; | |
| 1353 } | |
| 1354 process_buffer[process_p++] = value; | |
| 1355 | |
| 1356 if (process_p >= 3) { | |
| 1357 process_p = dm_ctx_buffer_xfer(process_buffer, process_p, target, &tp, debug_print); | |
| 1358 } | |
| 1359 sp++; | |
| 1360 not_first = 1; | |
| 1361 } | |
| 1362 | |
| 1363 /* step (e) X12 encodation */ | |
| 1364 } else if (current_mode == DM_X12) { | |
| 1365 | |
| 1366 if (!dm_isX12(source[sp])) { | |
| 1367 next_mode = DM_ASCII; | |
| 1368 } else { | |
| 1369 next_mode = DM_X12; | |
| 1370 if (process_p == 0 && not_first) { | |
| 1371 next_mode = dm_look_ahead_test(source, length, sp, current_mode, process_p, gs1, debug_print); | |
| 1372 } | |
| 1373 } | |
| 1374 | |
| 1375 if (next_mode != DM_X12) { | |
| 1376 sp -= process_p; /* About to throw away buffer, need to re-process input, cf Okapi commit [fb7981e] */ | |
| 1377 process_p = 0; /* Throw away buffer if any */ | |
| 1378 target[tp++] = 254; /* Unlatch */ | |
| 1379 next_mode = DM_ASCII; | |
| 1380 if (debug_print) fputs("ASC ", stdout); | |
| 1381 } else { | |
| 1382 static const char x12_nonalphanum_chars[] = "\015*> "; | |
| 1383 int value = 0; | |
| 1384 | |
| 1385 if (z_isdigit(source[sp])) { | |
| 1386 value = (source[sp] - '0') + 4; | |
| 1387 } else if (z_isupper(source[sp])) { | |
| 1388 value = (source[sp] - 'A') + 14; | |
| 1389 } else { | |
| 1390 value = posn(x12_nonalphanum_chars, source[sp]); | |
| 1391 } | |
| 1392 | |
| 1393 process_buffer[process_p++] = value; | |
| 1394 | |
| 1395 if (process_p >= 3) { | |
| 1396 process_p = dm_ctx_buffer_xfer(process_buffer, process_p, target, &tp, debug_print); | |
| 1397 } | |
| 1398 sp++; | |
| 1399 not_first = 1; | |
| 1400 } | |
| 1401 | |
| 1402 /* step (f) EDIFACT encodation */ | |
| 1403 } else if (current_mode == DM_EDIFACT) { | |
| 1404 | |
| 1405 if (!dm_isedifact(source[sp])) { | |
| 1406 next_mode = DM_ASCII; | |
| 1407 } else { | |
| 1408 next_mode = DM_EDIFACT; | |
| 1409 if (process_p == 3) { | |
| 1410 /* Note different than spec Step (f)(2), which suggests checking when 0, but this seems to | |
| 1411 work better in many cases as the switch to ASCII is "free" */ | |
| 1412 next_mode = dm_look_ahead_test(source, length, sp, current_mode, process_p, gs1, debug_print); | |
| 1413 } | |
| 1414 } | |
| 1415 | |
| 1416 if (next_mode != DM_EDIFACT) { | |
| 1417 process_buffer[process_p++] = 31; | |
| 1418 process_p = dm_edi_buffer_xfer(process_buffer, process_p, target, &tp, 1 /*empty*/, debug_print); | |
| 1419 next_mode = DM_ASCII; | |
| 1420 if (debug_print) fputs("ASC ", stdout); | |
| 1421 } else { | |
| 1422 int value = source[sp]; | |
| 1423 | |
| 1424 if (value >= 64) { /* '@' */ | |
| 1425 value -= 64; | |
| 1426 } | |
| 1427 | |
| 1428 process_buffer[process_p++] = value; | |
| 1429 sp++; | |
| 1430 not_first = 1; | |
| 1431 | |
| 1432 if (process_p >= 4) { | |
| 1433 process_p = dm_edi_buffer_xfer(process_buffer, process_p, target, &tp, 0 /*empty*/, | |
| 1434 debug_print); | |
| 1435 } | |
| 1436 } | |
| 1437 | |
| 1438 /* step (g) Base 256 encodation */ | |
| 1439 } else if (current_mode == DM_BASE256) { | |
| 1440 | |
| 1441 if (gs1 == 1 && source[sp] == '\x1D') { | |
| 1442 next_mode = DM_ASCII; | |
| 1443 } else { | |
| 1444 next_mode = DM_BASE256; | |
| 1445 if (not_first) { | |
| 1446 next_mode = dm_look_ahead_test(source, length, sp, current_mode, tp - (*p_b256_start + 1), gs1, | |
| 1447 debug_print); | |
| 1448 } | |
| 1449 } | |
| 1450 | |
| 1451 if (next_mode != DM_BASE256) { | |
| 1452 tp = dm_update_b256_field_length(target, tp, *p_b256_start); | |
| 1453 /* B.2.1 255-state randomising algorithm */ | |
| 1454 for (i = *p_b256_start; i < tp; i++) { | |
| 1455 const int prn = ((149 * (i + 1)) % 255) + 1; | |
| 1456 target[i] = (unsigned char) ((target[i] + prn) & 0xFF); | |
| 1457 } | |
| 1458 /* We switch directly here to avoid flipping back to Base 256 due to `dm_text_sp_cnt()` */ | |
| 1459 tp = dm_switch_mode(next_mode, target, tp, p_b256_start, debug_print); | |
| 1460 not_first = 0; | |
| 1461 } else { | |
| 1462 if (gs1 == 2 && source[sp] == '\x1D') { | |
| 1463 target[tp++] = 29; /* GS */ | |
| 1464 } else { | |
| 1465 target[tp++] = source[sp]; | |
| 1466 } | |
| 1467 sp++; | |
| 1468 not_first = 1; | |
| 1469 if (debug_print) printf("B%02X ", target[tp - 1]); | |
| 1470 } | |
| 1471 } | |
| 1472 | |
| 1473 if (tp > 1558) { | |
| 1474 return errtxt(ZINT_ERROR_TOO_LONG, symbol, 520, | |
| 1475 "Input too long, requires too many codewords (maximum 1558)"); | |
| 1476 } | |
| 1477 | |
| 1478 } /* while */ | |
| 1479 | |
| 1480 *p_sp = sp; | |
| 1481 *p_tp = tp; | |
| 1482 *p_process_p = process_p; | |
| 1483 *p_current_mode = current_mode; | |
| 1484 | |
| 1485 return 0; | |
| 1486 } | |
| 1487 | |
| 1488 /* Encodes data using ASCII, C40, Text, X12, EDIFACT or Base 256 modes as appropriate | |
| 1489 Supports encoding FNC1 in supporting systems */ | |
| 1490 static int dm_encode(struct zint_symbol *symbol, const unsigned char source[], const int length, const int eci, | |
| 1491 const int gs1, unsigned char target[], int *p_tp) { | |
| 1492 int sp = 0; | |
| 1493 int tp = *p_tp; | |
| 1494 int current_mode = DM_ASCII; | |
| 1495 int i; | |
| 1496 int process_buffer[8]; /* holds remaining data to finalised */ | |
| 1497 int process_p = 0; /* number of characters left to finalise */ | |
| 1498 int b256_start = 0; | |
| 1499 int symbols_left; | |
| 1500 int error_number; | |
| 1501 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT; | |
| 1502 | |
| 1503 if (eci > 0) { | |
| 1504 /* Encode ECI numbers according to Table 6 */ | |
| 1505 target[tp++] = 241; /* ECI Character */ | |
| 1506 if (eci <= 126) { | |
| 1507 target[tp++] = (unsigned char) (eci + 1); | |
| 1508 } else if (eci <= 16382) { | |
| 1509 target[tp++] = (unsigned char) ((eci - 127) / 254 + 128); | |
| 1510 target[tp++] = (unsigned char) ((eci - 127) % 254 + 1); | |
| 1511 } else { | |
| 1512 target[tp++] = (unsigned char) ((eci - 16383) / 64516 + 192); | |
| 1513 target[tp++] = (unsigned char) (((eci - 16383) / 254) % 254 + 1); | |
| 1514 target[tp++] = (unsigned char) ((eci - 16383) % 254 + 1); | |
| 1515 } | |
| 1516 if (debug_print) printf("ECI %d ", eci + 1); | |
| 1517 } | |
| 1518 | |
| 1519 /* If FAST_MODE or MAILMARK_2D, do Annex J-based encodation */ | |
| 1520 if ((symbol->input_mode & FAST_MODE) || symbol->symbology == BARCODE_MAILMARK_2D) { | |
| 1521 error_number = dm_isoenc(symbol, source, length, &sp, target, &tp, process_buffer, &process_p, | |
| 1522 &b256_start, ¤t_mode, gs1, debug_print); | |
| 1523 } else { /* Do default minimal encodation */ | |
| 1524 error_number = dm_minimalenc(symbol, source, length, &sp, target, &tp, process_buffer, &process_p, | |
| 1525 &b256_start, ¤t_mode, gs1, debug_print); | |
| 1526 } | |
| 1527 if (error_number != 0) { | |
| 1528 return error_number; | |
| 1529 } | |
| 1530 | |
| 1531 symbols_left = dm_codewords_remaining(symbol, tp, process_p); | |
| 1532 | |
| 1533 if (debug_print) printf("\nsymbols_left %d, tp %d, process_p %d ", symbols_left, tp, process_p); | |
| 1534 | |
| 1535 if (current_mode == DM_C40 || current_mode == DM_TEXT) { | |
| 1536 /* NOTE: changed to follow spec exactly here, only using Shift 1 padded triplets when 2 symbol chars remain. | |
| 1537 This matches the behaviour of BWIPP but not tec-it, nor figures 4.15.1-1 and 4.15-1-2 in GS1 General | |
| 1538 Specifications 21.0.1. | |
| 1539 */ | |
| 1540 if (debug_print) printf("%s ", current_mode == DM_C40 ? "C40" : "TEX"); | |
| 1541 if (process_p == 0) { | |
| 1542 if (symbols_left > 0) { | |
| 1543 target[tp++] = 254; /* Unlatch */ | |
| 1544 if (debug_print) fputs("ASC ", stdout); | |
| 1545 } | |
| 1546 } else { | |
| 1547 if (process_p == 2 && symbols_left == 2) { | |
| 1548 /* 5.2.5.2 (b) */ | |
| 1549 process_buffer[process_p++] = 0; /* Shift 1 */ | |
| 1550 (void) dm_ctx_buffer_xfer(process_buffer, process_p, target, &tp, debug_print); | |
| 1551 | |
| 1552 } else if (process_p == 1 && symbols_left <= 2 && dm_isc40text(current_mode, source[length - 1])) { | |
| 1553 /* 5.2.5.2 (c)/(d) */ | |
| 1554 if (symbols_left > 1) { | |
| 1555 /* 5.2.5.2 (c) */ | |
| 1556 target[tp++] = 254; /* Unlatch and encode remaining data in ascii. */ | |
| 1557 if (debug_print) fputs("ASC ", stdout); | |
| 1558 } | |
| 1559 target[tp++] = source[length - 1] + 1; | |
| 1560 if (debug_print) printf("A%02X ", target[tp - 1] - 1); | |
| 1561 | |
| 1562 } else { | |
| 1563 int cnt, total_cnt = 0; | |
| 1564 /* Backtrack to last complete triplet (same technique as BWIPP) */ | |
| 1565 while (sp > 0 && process_p % 3) { | |
| 1566 sp--; | |
| 1567 cnt = dm_c40text_cnt(current_mode, gs1, source[sp]); | |
| 1568 total_cnt += cnt; | |
| 1569 process_p -= cnt; | |
| 1570 } | |
| 1571 if (debug_print) printf("Mode %d, backtracked %d\n", current_mode, (total_cnt / 3) * 2); | |
| 1572 tp -= (total_cnt / 3) * 2; | |
| 1573 | |
| 1574 target[tp++] = 254; /* Unlatch */ | |
| 1575 if (debug_print) fputs("ASC ", stdout); | |
| 1576 for (; sp < length; sp++) { | |
| 1577 if (is_twodigits(source, length, sp)) { | |
| 1578 target[tp++] = (unsigned char) ((10 * ctoi(source[sp])) + ctoi(source[sp + 1]) + 130); | |
| 1579 if (debug_print) printf("N%02d ", target[tp - 1] - 130); | |
| 1580 sp++; | |
| 1581 } else if (source[sp] & 0x80) { | |
| 1582 target[tp++] = 235; /* FNC4 */ | |
| 1583 target[tp++] = (source[sp] - 128) + 1; | |
| 1584 if (debug_print) printf("FN4 A%02X ", target[tp - 1] - 1); | |
| 1585 } else if (gs1 && source[sp] == '\x1D') { | |
| 1586 if (gs1 == 2) { | |
| 1587 target[tp++] = 29 + 1; /* GS */ | |
| 1588 if (debug_print) fputs("GS ", stdout); | |
| 1589 } else { | |
| 1590 target[tp++] = 232; /* FNC1 */ | |
| 1591 if (debug_print) fputs("FN1 ", stdout); | |
| 1592 } | |
| 1593 } else { | |
| 1594 target[tp++] = source[sp] + 1; | |
| 1595 if (debug_print) printf("A%02X ", target[tp - 1] - 1); | |
| 1596 } | |
| 1597 } | |
| 1598 } | |
| 1599 } | |
| 1600 | |
| 1601 } else if (current_mode == DM_X12) { | |
| 1602 if (debug_print) fputs("X12 ", stdout); | |
| 1603 if ((symbols_left == 1) && (process_p == 1)) { | |
| 1604 /* Unlatch not required! */ | |
| 1605 target[tp++] = source[length - 1] + 1; | |
| 1606 if (debug_print) printf("A%02X ", target[tp - 1] - 1); | |
| 1607 } else { | |
| 1608 if (symbols_left > 0) { | |
| 1609 target[tp++] = (254); /* Unlatch. */ | |
| 1610 if (debug_print) fputs("ASC ", stdout); | |
| 1611 } | |
| 1612 | |
| 1613 if (process_p == 1) { | |
| 1614 target[tp++] = source[length - 1] + 1; | |
| 1615 if (debug_print) printf("A%02X ", target[tp - 1] - 1); | |
| 1616 } else if (process_p == 2) { | |
| 1617 target[tp++] = source[length - 2] + 1; | |
| 1618 target[tp++] = source[length - 1] + 1; | |
| 1619 if (debug_print) printf("A%02X A%02X ", target[tp - 2] - 1, target[tp - 1] - 1); | |
| 1620 } | |
| 1621 } | |
| 1622 | |
| 1623 } else if (current_mode == DM_EDIFACT) { | |
| 1624 if (debug_print) fputs("EDI ", stdout); | |
| 1625 if (symbols_left <= 2 && process_p <= symbols_left) { /* Unlatch not required! */ | |
| 1626 if (process_p == 1) { | |
| 1627 target[tp++] = source[length - 1] + 1; | |
| 1628 if (debug_print) printf("A%02X ", target[tp - 1] - 1); | |
| 1629 } else if (process_p == 2) { | |
| 1630 target[tp++] = source[length - 2] + 1; | |
| 1631 target[tp++] = source[length - 1] + 1; | |
| 1632 if (debug_print) printf("A%02X A%02X ", target[tp - 2] - 1, target[tp - 1] - 1); | |
| 1633 } | |
| 1634 } else { | |
| 1635 /* Append edifact unlatch value (31) and empty buffer */ | |
| 1636 if (process_p <= 3) { | |
| 1637 process_buffer[process_p++] = 31; | |
| 1638 } | |
| 1639 (void) dm_edi_buffer_xfer(process_buffer, process_p, target, &tp, 1 /*empty*/, debug_print); | |
| 1640 } | |
| 1641 | |
| 1642 } else if (current_mode == DM_BASE256) { | |
| 1643 if (symbols_left > 0) { | |
| 1644 tp = dm_update_b256_field_length(target, tp, b256_start); | |
| 1645 } | |
| 1646 /* B.2.1 255-state randomising algorithm */ | |
| 1647 for (i = b256_start; i < tp; i++) { | |
| 1648 int prn = ((149 * (i + 1)) % 255) + 1; | |
| 1649 target[i] = (unsigned char) ((target[i] + prn) & 0xFF); | |
| 1650 } | |
| 1651 } | |
| 1652 | |
| 1653 if (debug_print) { | |
| 1654 printf("\nData (%d):", tp); | |
| 1655 for (i = 0; i < tp; i++) | |
| 1656 printf(" %d", target[i]); | |
| 1657 | |
| 1658 fputc('\n', stdout); | |
| 1659 } | |
| 1660 | |
| 1661 *p_tp = tp; | |
| 1662 | |
| 1663 return 0; | |
| 1664 } | |
| 1665 | |
| 1666 #ifdef ZINT_TEST /* Wrapper for direct testing */ | |
| 1667 INTERNAL int dm_encode_test(struct zint_symbol *symbol, const unsigned char source[], const int length, const int eci, | |
| 1668 const int gs1, unsigned char target[], int *p_tp) { | |
| 1669 return dm_encode(symbol, source, length, eci, gs1, target, p_tp); | |
| 1670 } | |
| 1671 #endif | |
| 1672 | |
| 1673 /* Call `dm_encode()` for each segment, dealing with Structured Append, GS1, READER_INIT and macro headers | |
| 1674 beforehand */ | |
| 1675 static int dm_encode_segs(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count, | |
| 1676 unsigned char target[], int *p_binlen) { | |
| 1677 int error_number; | |
| 1678 int i; | |
| 1679 int tp = 0; | |
| 1680 int gs1; | |
| 1681 int in_macro = 0; | |
| 1682 const struct zint_seg *last_seg = &segs[seg_count - 1]; | |
| 1683 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT; | |
| 1684 | |
| 1685 if ((i = segs_length(segs, seg_count)) > 3116) { /* Max is 3166 digits */ | |
| 1686 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 719, "Input length %d too long (maximum 3116)", i); | |
| 1687 } | |
| 1688 | |
| 1689 if (symbol->structapp.count) { | |
| 1690 int id1, id2; | |
| 1691 | |
| 1692 if (symbol->structapp.count < 2 || symbol->structapp.count > 16) { | |
| 1693 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 720, | |
| 1694 "Structured Append count '%d' out of range (2 to 16)", symbol->structapp.count); | |
| 1695 } | |
| 1696 if (symbol->structapp.index < 1 || symbol->structapp.index > symbol->structapp.count) { | |
| 1697 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 721, | |
| 1698 "Structured Append index '%1$d' out of range (1 to count %2$d)", | |
| 1699 symbol->structapp.index, symbol->structapp.count); | |
| 1700 } | |
| 1701 if (symbol->structapp.id[0]) { | |
| 1702 int id, id_len, id1_err, id2_err; | |
| 1703 | |
| 1704 for (id_len = 1; id_len < 7 && symbol->structapp.id[id_len]; id_len++); | |
| 1705 | |
| 1706 if (id_len > 6) { /* ID1 * 1000 + ID2 */ | |
| 1707 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 722, | |
| 1708 "Structured Append ID length %d too long (6 digit maximum)", id_len); | |
| 1709 } | |
| 1710 | |
| 1711 id = to_int((const unsigned char *) symbol->structapp.id, id_len); | |
| 1712 if (id == -1) { | |
| 1713 return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 723, "Invalid Structured Append ID (digits only)"); | |
| 1714 } | |
| 1715 id1 = id / 1000; | |
| 1716 id2 = id % 1000; | |
| 1717 id1_err = id1 < 1 || id1 > 254; | |
| 1718 id2_err = id2 < 1 || id2 > 254; | |
| 1719 if (id1_err || id2_err) { | |
| 1720 if (id1_err && id2_err) { | |
| 1721 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 724, | |
| 1722 "Structured Append ID1 '%1$03d' and ID2 '%2$03d' out of range (001 to 254)" | |
| 1723 " (ID \"%3$03d%4$03d\")", | |
| 1724 id1, id2, id1, id2); | |
| 1725 } | |
| 1726 if (id1_err) { | |
| 1727 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 725, | |
| 1728 "Structured Append ID1 '%1$03d' out of range (001 to 254) (ID \"%2$03d%3$03d\")", | |
| 1729 id1, id1, id2); | |
| 1730 } | |
| 1731 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 726, | |
| 1732 "Structured Append ID2 '%1$03d' out of range (001 to 254) (ID \"%2$03d%3$03d\")", | |
| 1733 id2, id1, id2); | |
| 1734 } | |
| 1735 } else { | |
| 1736 id1 = id2 = 1; | |
| 1737 } | |
| 1738 | |
| 1739 target[tp++] = 233; | |
| 1740 target[tp++] = (17 - symbol->structapp.count) | ((symbol->structapp.index - 1) << 4); | |
| 1741 target[tp++] = id1; | |
| 1742 target[tp++] = id2; | |
| 1743 } | |
| 1744 | |
| 1745 /* gs1 flag values: 0: no gs1, 1: gs1 with FNC1 serparator, 2: GS separator */ | |
| 1746 if ((symbol->input_mode & 0x07) == GS1_MODE) { | |
| 1747 if (symbol->output_options & GS1_GS_SEPARATOR) { | |
| 1748 gs1 = 2; | |
| 1749 } else { | |
| 1750 gs1 = 1; | |
| 1751 } | |
| 1752 } else { | |
| 1753 gs1 = 0; | |
| 1754 } | |
| 1755 | |
| 1756 if (gs1) { | |
| 1757 target[tp++] = 232; | |
| 1758 if (debug_print) fputs("FN1 ", stdout); | |
| 1759 } /* FNC1 */ | |
| 1760 | |
| 1761 if (symbol->output_options & READER_INIT) { | |
| 1762 if (gs1) { | |
| 1763 return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 521, "Cannot use Reader Initialisation in GS1 mode"); | |
| 1764 } | |
| 1765 if (symbol->structapp.count) { | |
| 1766 return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 727, | |
| 1767 "Cannot have Structured Append and Reader Initialisation at the same time"); | |
| 1768 } | |
| 1769 target[tp++] = 234; /* Reader Programming */ | |
| 1770 if (debug_print) fputs("RP ", stdout); | |
| 1771 } | |
| 1772 | |
| 1773 /* Check for Macro05/Macro06 */ | |
| 1774 /* "[)>[RS]05[GS]...[RS][EOT]" -> CW 236 */ | |
| 1775 /* "[)>[RS]06[GS]...[RS][EOT]" -> CW 237 */ | |
| 1776 if (tp == 0 && segs[0].length >= 9 && last_seg->length >= 2 | |
| 1777 && segs[0].source[0] == '[' && segs[0].source[1] == ')' && segs[0].source[2] == '>' | |
| 1778 && segs[0].source[3] == '\x1e' /*RS*/ && segs[0].source[4] == '0' | |
| 1779 && (segs[0].source[5] == '5' || segs[0].source[5] == '6') | |
| 1780 && segs[0].source[6] == '\x1d' /*GS*/ | |
| 1781 && last_seg->source[last_seg->length - 1] == '\x04' /*EOT*/ | |
| 1782 && last_seg->source[last_seg->length - 2] == '\x1e' /*RS*/) { | |
| 1783 | |
| 1784 /* Output macro Codeword */ | |
| 1785 if (segs[0].source[5] == '5') { | |
| 1786 target[tp++] = 236; | |
| 1787 if (debug_print) fputs("Macro05 ", stdout); | |
| 1788 } else { | |
| 1789 target[tp++] = 237; | |
| 1790 if (debug_print) fputs("Macro06 ", stdout); | |
| 1791 } | |
| 1792 /* Remove macro characters from input string */ | |
| 1793 in_macro = 1; | |
| 1794 } | |
| 1795 | |
| 1796 for (i = 0; i < seg_count; i++) { | |
| 1797 int src_inc = 0, len_dec = 0; | |
| 1798 if (in_macro) { | |
| 1799 if (i == 0) { | |
| 1800 src_inc = len_dec = 7; /* Skip over macro characters at beginning */ | |
| 1801 } | |
| 1802 if (i + 1 == seg_count) { | |
| 1803 len_dec += 2; /* Remove RS + EOT from end */ | |
| 1804 } | |
| 1805 } | |
| 1806 error_number = dm_encode(symbol, segs[i].source + src_inc, segs[i].length - len_dec, segs[i].eci, gs1, | |
| 1807 target, &tp); | |
| 1808 if (error_number != 0) { | |
| 1809 return error_number; | |
| 1810 } | |
| 1811 } | |
| 1812 | |
| 1813 *p_binlen = tp; | |
| 1814 | |
| 1815 return 0; | |
| 1816 } | |
| 1817 | |
| 1818 /* add pad bits */ | |
| 1819 static void dm_add_tail(unsigned char target[], int tp, const int tail_length) { | |
| 1820 int i, prn, temp; | |
| 1821 | |
| 1822 target[tp++] = 129; /* Pad */ | |
| 1823 for (i = 1; i < tail_length; i++) { | |
| 1824 /* B.1.1 253-state randomising algorithm */ | |
| 1825 prn = ((149 * (tp + 1)) % 253) + 1; | |
| 1826 temp = 129 + prn; | |
| 1827 if (temp <= 254) { | |
| 1828 target[tp++] = (unsigned char) (temp); | |
| 1829 } else { | |
| 1830 target[tp++] = (unsigned char) (temp - 254); | |
| 1831 } | |
| 1832 } | |
| 1833 } | |
| 1834 | |
| 1835 static int dm_ecc200(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) { | |
| 1836 int i, skew = 0; | |
| 1837 unsigned char binary[2200]; | |
| 1838 int binlen = 0; /* Suppress clang-tidy-20 uninitialized value false positive */ | |
| 1839 int symbolsize; | |
| 1840 int taillength, error_number; | |
| 1841 int H, W, FH, FW, datablock, bytes, rsblock; | |
| 1842 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT; | |
| 1843 | |
| 1844 /* `length` may be decremented by 2 if macro character is used */ | |
| 1845 error_number = dm_encode_segs(symbol, segs, seg_count, binary, &binlen); | |
| 1846 if (error_number != 0) { | |
| 1847 return error_number; | |
| 1848 } | |
| 1849 | |
| 1850 symbolsize = dm_get_symbolsize(symbol, binlen); | |
| 1851 | |
| 1852 if (binlen > dm_matrixbytes[symbolsize]) { | |
| 1853 if ((symbol->option_2 >= 1) && (symbol->option_2 <= DMSIZESCOUNT)) { | |
| 1854 /* The symbol size was given by --ver (option_2) */ | |
| 1855 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 522, | |
| 1856 "Input too long for Version %1$d, requires %2$d codewords (maximum %3$d)", | |
| 1857 symbol->option_2, binlen, dm_matrixbytes[symbolsize]); | |
| 1858 } | |
| 1859 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 523, "Input too long, requires %d codewords (maximum 1558)", | |
| 1860 binlen); | |
| 1861 } | |
| 1862 | |
| 1863 H = dm_matrixH[symbolsize]; | |
| 1864 W = dm_matrixW[symbolsize]; | |
| 1865 FH = dm_matrixFH[symbolsize]; | |
| 1866 FW = dm_matrixFW[symbolsize]; | |
| 1867 bytes = dm_matrixbytes[symbolsize]; | |
| 1868 datablock = dm_matrixdatablock[symbolsize]; | |
| 1869 rsblock = dm_matrixrsblock[symbolsize]; | |
| 1870 | |
| 1871 taillength = bytes - binlen; | |
| 1872 | |
| 1873 if (taillength != 0) { | |
| 1874 dm_add_tail(binary, binlen, taillength); | |
| 1875 } | |
| 1876 if (debug_print) { | |
| 1877 printf("Pads (%d): ", taillength); | |
| 1878 for (i = binlen; i < binlen + taillength; i++) printf("%d ", binary[i]); | |
| 1879 fputc('\n', stdout); | |
| 1880 } | |
| 1881 | |
| 1882 /* ecc code */ | |
| 1883 if (symbolsize == DMINTSYMBOL144 && !(symbol->option_3 & DM_ISO_144)) { | |
| 1884 skew = 1; | |
| 1885 } | |
| 1886 dm_ecc(binary, bytes, datablock, rsblock, skew); | |
| 1887 if (debug_print) { | |
| 1888 printf("ECC (%d): ", rsblock * (bytes / datablock)); | |
| 1889 for (i = bytes; i < bytes + rsblock * (bytes / datablock); i++) printf("%d ", binary[i]); | |
| 1890 fputc('\n', stdout); | |
| 1891 } | |
| 1892 | |
| 1893 #ifdef ZINT_TEST | |
| 1894 if (symbol->debug & ZINT_DEBUG_TEST) { | |
| 1895 debug_test_codeword_dump(symbol, binary, skew ? 1558 + 620 : bytes + rsblock * (bytes / datablock)); | |
| 1896 } | |
| 1897 #endif | |
| 1898 { /* placement */ | |
| 1899 const int NC = W - 2 * (W / FW); | |
| 1900 const int NR = H - 2 * (H / FH); | |
| 1901 int x, y, *places; | |
| 1902 if (!(places = (int *) calloc(NC * NR, sizeof(int)))) { | |
| 1903 return errtxt(ZINT_ERROR_MEMORY, symbol, 718, "Insufficient memory for placement array"); | |
| 1904 } | |
| 1905 dm_placement(places, NR, NC); | |
| 1906 for (y = 0; y < H; y += FH) { | |
| 1907 for (x = 0; x < W; x++) | |
| 1908 set_module(symbol, (H - y) - 1, x); | |
| 1909 for (x = 0; x < W; x += 2) | |
| 1910 set_module(symbol, y, x); | |
| 1911 } | |
| 1912 for (x = 0; x < W; x += FW) { | |
| 1913 for (y = 0; y < H; y++) | |
| 1914 set_module(symbol, (H - y) - 1, x); | |
| 1915 for (y = 0; y < H; y += 2) | |
| 1916 set_module(symbol, (H - y) - 1, x + FW - 1); | |
| 1917 } | |
| 1918 #ifdef DM_DEBUG | |
| 1919 /* Print position matrix as in standard */ | |
| 1920 for (y = NR - 1; y >= 0; y--) { | |
| 1921 for (x = 0; x < NC; x++) { | |
| 1922 const int v = places[(NR - y - 1) * NC + x]; | |
| 1923 if (x != 0) fprintf(stderr, "|"); | |
| 1924 fprintf(stderr, "%3d.%2d", (v >> 3), 8 - (v & 7)); | |
| 1925 } | |
| 1926 fprintf(stderr, "\n"); | |
| 1927 } | |
| 1928 #endif | |
| 1929 for (y = 0; y < NR; y++) { | |
| 1930 for (x = 0; x < NC; x++) { | |
| 1931 const int v = places[(NR - y - 1) * NC + x]; | |
| 1932 if (v == 1 || (v > 7 && (binary[(v >> 3) - 1] & (1 << (v & 7))))) { | |
| 1933 set_module(symbol, H - (1 + y + 2 * (y / (FH - 2))) - 1, 1 + x + 2 * (x / (FW - 2))); | |
| 1934 } | |
| 1935 } | |
| 1936 } | |
| 1937 for (y = 0; y < H; y++) { | |
| 1938 symbol->row_height[y] = 1; | |
| 1939 } | |
| 1940 free(places); | |
| 1941 } | |
| 1942 | |
| 1943 symbol->height = H; | |
| 1944 symbol->rows = H; | |
| 1945 symbol->width = W; | |
| 1946 | |
| 1947 return error_number; | |
| 1948 } | |
| 1949 | |
| 1950 INTERNAL int datamatrix(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) { | |
| 1951 | |
| 1952 if (symbol->option_1 <= 1) { | |
| 1953 /* ECC 200 */ | |
| 1954 return dm_ecc200(symbol, segs, seg_count); | |
| 1955 } | |
| 1956 /* ECC 000 - 140 */ | |
| 1957 return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 524, "Older Data Matrix standards are no longer supported"); | |
| 1958 } | |
| 1959 | |
| 1960 /* vim: set ts=4 sw=4 et : */ |
