Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/zint/backend/rss.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 /* rss.c - GS1 DataBar (formerly Reduced Space Symbology) */ | |
| 2 /* | |
| 3 libzint - the open source barcode library | |
| 4 Copyright (C) 2008-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 /* The functions "rss_combins" and "getRSSwidths" are copyright BSI and are | |
| 34 released with permission under the following terms: | |
| 35 | |
| 36 "Copyright subsists in all BSI publications. BSI also holds the copyright, in the | |
| 37 UK, of the international standardisation bodies. Except as | |
| 38 permitted under the Copyright, Designs and Patents Act 1988 no extract may be | |
| 39 reproduced, stored in a retrieval system or transmitted in any form or by any | |
| 40 means - electronic, photocopying, recording or otherwise - without prior written | |
| 41 permission from BSI. | |
| 42 | |
| 43 "This does not preclude the free use, in the course of implementing the standard, | |
| 44 of necessary details such as symbols, and size, type or grade designations. If these | |
| 45 details are to be used for any other purpose than implementation then the prior | |
| 46 written permission of BSI must be obtained." | |
| 47 | |
| 48 The date of publication for these functions is 30 November 2006 | |
| 49 */ | |
| 50 | |
| 51 /* Includes numerous bugfixes thanks to Pablo Orduña @ the PIRAmIDE project */ | |
| 52 | |
| 53 /* Note: This code reflects the symbol names as used in ISO/IEC 24724:2006. These names | |
| 54 * were updated in ISO/IEC 24724:2011 as follows: | |
| 55 * | |
| 56 * RSS-14 > GS1 DataBar Omnidirectional | |
| 57 * RSS-14 Truncated > GS1 DataBar Truncated | |
| 58 * RSS-14 Stacked > GS1 DataBar Stacked | |
| 59 * RSS-14 Stacked Omnidirectional > GS1 DataBar Stacked Omnidirectional | |
| 60 * RSS Limited > GS1 DataBar Limited | |
| 61 * RSS Expanded > GS1 DataBar Expanded Omnidirectional | |
| 62 * RSS Expanded Stacked > GS1 DataBar Expanded Stacked Omnidirectional | |
| 63 */ | |
| 64 | |
| 65 #include <stdio.h> | |
| 66 #include "common.h" | |
| 67 #include "large.h" | |
| 68 #include "rss.h" | |
| 69 #include "gs1.h" | |
| 70 #include "general_field.h" | |
| 71 | |
| 72 /**************************************************************************** | |
| 73 * rss_combins(n,r): returns the number of Combinations of r selected from n: | |
| 74 * Combinations = n! / ((n - r)! * r!) | |
| 75 ****************************************************************************/ | |
| 76 static int rss_combins(const int n, const int r) { | |
| 77 int i, j; | |
| 78 int maxDenom, minDenom; | |
| 79 int val; | |
| 80 | |
| 81 if (n - r > r) { | |
| 82 minDenom = r; | |
| 83 maxDenom = n - r; | |
| 84 } else { | |
| 85 minDenom = n - r; | |
| 86 maxDenom = r; | |
| 87 } | |
| 88 val = 1; | |
| 89 j = 1; | |
| 90 for (i = n; i > maxDenom; i--) { | |
| 91 val *= i; | |
| 92 if (j <= minDenom) { | |
| 93 val /= j; | |
| 94 j++; | |
| 95 } | |
| 96 } | |
| 97 for (; j <= minDenom; j++) { | |
| 98 val /= j; | |
| 99 } | |
| 100 return (val); | |
| 101 } | |
| 102 | |
| 103 /********************************************************************** | |
| 104 * getRSSwidths | |
| 105 * routine to generate widths for RSS elements for a given value.# | |
| 106 * | |
| 107 * Calling arguments: | |
| 108 * int widths[] = element widths | |
| 109 * val = required value | |
| 110 * n = number of modules | |
| 111 * elements = elements in a set (RSS-14 & Expanded = 4; RSS Limited = 7) | |
| 112 * maxWidth = maximum module width of an element | |
| 113 * noNarrow = 0 will skip patterns without a one module wide element | |
| 114 * | |
| 115 **********************************************************************/ | |
| 116 static void getRSSwidths(int widths[], int val, int n, const int elements, const int maxWidth, const int noNarrow) { | |
| 117 int bar; | |
| 118 int elmWidth; | |
| 119 int mxwElement; | |
| 120 int subVal, lessVal; | |
| 121 int narrowMask = 0; | |
| 122 for (bar = 0; bar < elements - 1; bar++) { | |
| 123 for (elmWidth = 1, narrowMask |= (1 << bar); | |
| 124 ; | |
| 125 elmWidth++, narrowMask &= ~(1 << bar)) { | |
| 126 /* Get all combinations */ | |
| 127 subVal = rss_combins(n - elmWidth - 1, elements - bar - 2); | |
| 128 /* Less combinations with no single-module element */ | |
| 129 if ((!noNarrow) && (!narrowMask) | |
| 130 && (n - elmWidth - (elements - bar - 1) >= elements - bar - 1)) { | |
| 131 subVal -= rss_combins(n - elmWidth - (elements - bar), elements - bar - 2); | |
| 132 } | |
| 133 /* Less combinations with elements > maxVal */ | |
| 134 if (elements - bar - 1 > 1) { | |
| 135 lessVal = 0; | |
| 136 for (mxwElement = n - elmWidth - (elements - bar - 2); | |
| 137 mxwElement > maxWidth; | |
| 138 mxwElement--) { | |
| 139 lessVal += rss_combins(n - elmWidth - mxwElement - 1, elements - bar - 3); | |
| 140 } | |
| 141 subVal -= lessVal * (elements - 1 - bar); | |
| 142 } else if (n - elmWidth > maxWidth) { | |
| 143 subVal--; | |
| 144 } | |
| 145 val -= subVal; | |
| 146 if (val < 0) break; | |
| 147 } | |
| 148 val += subVal; | |
| 149 n -= elmWidth; | |
| 150 widths[bar] = elmWidth; | |
| 151 } | |
| 152 widths[bar] = n; | |
| 153 return; | |
| 154 } | |
| 155 | |
| 156 /* Set GTIN-14 human readable text */ | |
| 157 static void dbar_set_gtin14_hrt(struct zint_symbol *symbol, const unsigned char *source, const int length) { | |
| 158 unsigned char *hrt = symbol->text + 4; | |
| 159 const int leading_zeroes = 13 - length; | |
| 160 | |
| 161 ustrcpy(symbol->text, "(01)"); | |
| 162 if (leading_zeroes) { | |
| 163 memset(hrt, '0', leading_zeroes); | |
| 164 } | |
| 165 memcpy(hrt + leading_zeroes, source, length); | |
| 166 hrt[13] = gs1_check_digit(hrt, 13); | |
| 167 hrt[14] = '\0'; | |
| 168 } | |
| 169 | |
| 170 /* Expand from a width pattern to a bit pattern */ | |
| 171 static int dbar_expand(struct zint_symbol *symbol, int writer, int *p_latch, const int width) { | |
| 172 int j; | |
| 173 | |
| 174 if (*p_latch) { | |
| 175 for (j = 0; j < width; j++) { | |
| 176 set_module(symbol, symbol->rows, writer); | |
| 177 writer++; | |
| 178 } | |
| 179 } else { | |
| 180 for (j = 0; j < width; j++) { | |
| 181 unset_module(symbol, symbol->rows, writer); | |
| 182 writer++; | |
| 183 } | |
| 184 } | |
| 185 | |
| 186 *p_latch = !*p_latch; | |
| 187 | |
| 188 return writer; | |
| 189 } | |
| 190 | |
| 191 /* Adjust top/bottom separator for finder patterns */ | |
| 192 static void dbar_omn_finder_adjust(struct zint_symbol *symbol, const int separator_row, const int above_below, | |
| 193 const int finder_start) { | |
| 194 int i, finder_end; | |
| 195 int module_row = separator_row + above_below; | |
| 196 int latch; | |
| 197 | |
| 198 /* Alternation is always left-to-right for Omnidirectional separators (unlike for Expanded) */ | |
| 199 latch = 1; | |
| 200 for (i = finder_start, finder_end = finder_start + 13; i < finder_end; i++) { | |
| 201 if (!module_is_set(symbol, module_row, i)) { | |
| 202 if (latch) { | |
| 203 set_module(symbol, separator_row, i); | |
| 204 latch = 0; | |
| 205 } else { | |
| 206 unset_module(symbol, separator_row, i); | |
| 207 latch = 1; | |
| 208 } | |
| 209 } else { | |
| 210 unset_module(symbol, separator_row, i); | |
| 211 latch = 1; | |
| 212 } | |
| 213 } | |
| 214 } | |
| 215 | |
| 216 /* Top/bottom separator for DataBar */ | |
| 217 static void dbar_omn_separator(struct zint_symbol *symbol, int width, const int separator_row, const int above_below, | |
| 218 const int finder_start, const int finder2_start, const int bottom_finder_value_3) { | |
| 219 int i, finder_end, finder_value_3_set; | |
| 220 int module_row = separator_row + above_below; | |
| 221 | |
| 222 for (i = 4, width -= 4; i < width; i++) { | |
| 223 if (!module_is_set(symbol, module_row, i)) { | |
| 224 set_module(symbol, separator_row, i); | |
| 225 } | |
| 226 } | |
| 227 if (bottom_finder_value_3) { | |
| 228 /* ISO/IEC 24724:2011 5.3.2.2 "The single dark module that occurs in the 13 modules over finder value 3 is | |
| 229 shifted one module to the right so that it is over the start of the three module-wide finder bar." */ | |
| 230 finder_value_3_set = finder_start + 10; | |
| 231 for (i = finder_start, finder_end = finder_start + 13; i < finder_end; i++) { | |
| 232 if (i == finder_value_3_set) { | |
| 233 set_module(symbol, separator_row, i); | |
| 234 } else { | |
| 235 unset_module(symbol, separator_row, i); | |
| 236 } | |
| 237 } | |
| 238 } else { | |
| 239 if (finder_start) { | |
| 240 dbar_omn_finder_adjust(symbol, separator_row, above_below, finder_start); | |
| 241 } | |
| 242 if (finder2_start) { | |
| 243 dbar_omn_finder_adjust(symbol, separator_row, above_below, finder2_start); | |
| 244 } | |
| 245 } | |
| 246 } | |
| 247 | |
| 248 /* Set Databar Stacked height, maintaining 5:7 ratio of the 2 main row heights */ | |
| 249 INTERNAL int dbar_omnstk_set_height(struct zint_symbol *symbol, const int first_row) { | |
| 250 float fixed_height = 0.0f; | |
| 251 int second_row = first_row + 2; /* 2 row separator */ | |
| 252 int i; | |
| 253 | |
| 254 for (i = 0; i < symbol->rows; i++) { | |
| 255 if (i != first_row && i != second_row) { | |
| 256 fixed_height += symbol->row_height[i]; | |
| 257 } | |
| 258 } | |
| 259 if (symbol->height) { | |
| 260 symbol->row_height[first_row] = stripf((symbol->height - fixed_height) * symbol->row_height[first_row] / | |
| 261 (symbol->row_height[first_row] + symbol->row_height[second_row])); | |
| 262 if (symbol->row_height[first_row] < 0.5f) { /* Absolute minimum */ | |
| 263 symbol->row_height[first_row] = 0.5f; | |
| 264 symbol->row_height[second_row] = 0.7f; | |
| 265 } else { | |
| 266 symbol->row_height[second_row] = stripf(symbol->height - fixed_height - symbol->row_height[first_row]); | |
| 267 if (symbol->row_height[second_row] < 0.7f) { | |
| 268 symbol->row_height[second_row] = 0.7f; | |
| 269 } | |
| 270 } | |
| 271 } | |
| 272 symbol->height = stripf(stripf(symbol->row_height[first_row] + symbol->row_height[second_row]) + fixed_height); | |
| 273 | |
| 274 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 275 if (symbol->row_height[first_row] < 5.0f || symbol->row_height[second_row] < 7.0f) { | |
| 276 return errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 379, "Height not compliant with standards"); | |
| 277 } | |
| 278 } | |
| 279 | |
| 280 return 0; | |
| 281 } | |
| 282 | |
| 283 /* GS1 DataBar Omnidirectional/Truncated/Stacked, allowing for composite if `cc_rows` set */ | |
| 284 INTERNAL int dbar_omn_cc(struct zint_symbol *symbol, unsigned char source[], int length, const int cc_rows) { | |
| 285 int error_number = 0, i; | |
| 286 large_uint accum; | |
| 287 uint64_t left_pair, right_pair; | |
| 288 int data_character[4] = {0}, data_group[4] = {0}, v_odd[4], v_even[4]; | |
| 289 int data_widths[8][4], checksum, c_left, c_right, total_widths[46], writer; | |
| 290 int latch; | |
| 291 int separator_row; | |
| 292 int widths[4]; | |
| 293 | |
| 294 separator_row = 0; | |
| 295 | |
| 296 if (length > 14) { /* Allow check digit to be specified (will be verified and ignored) */ | |
| 297 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 380, "Input length %d too long (maximum 14)", length); | |
| 298 } | |
| 299 if ((i = not_sane(NEON_F, source, length))) { | |
| 300 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 381, | |
| 301 "Invalid character at position %d in input (digits only)", i); | |
| 302 } | |
| 303 | |
| 304 if (length == 14) { /* Verify check digit */ | |
| 305 if (gs1_check_digit(source, 13) != source[13]) { | |
| 306 return errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 388, "Invalid check digit '%1$c', expecting '%2$c'", | |
| 307 source[13], gs1_check_digit(source, 13)); | |
| 308 } | |
| 309 length--; /* Ignore */ | |
| 310 } | |
| 311 | |
| 312 /* Make some room for a separator row for composite symbols */ | |
| 313 switch (symbol->symbology) { | |
| 314 case BARCODE_DBAR_OMN_CC: | |
| 315 case BARCODE_DBAR_STK_CC: | |
| 316 case BARCODE_DBAR_OMNSTK_CC: | |
| 317 separator_row = symbol->rows; | |
| 318 symbol->row_height[separator_row] = 1; | |
| 319 symbol->rows += 1; | |
| 320 break; | |
| 321 } | |
| 322 | |
| 323 large_load_str_u64(&accum, source, length); | |
| 324 | |
| 325 if (cc_rows) { | |
| 326 /* Add symbol linkage flag */ | |
| 327 large_add_u64(&accum, 10000000000000); | |
| 328 } | |
| 329 | |
| 330 /* Calculate left and right pair values */ | |
| 331 | |
| 332 right_pair = large_div_u64(&accum, 4537077); | |
| 333 left_pair = large_lo(&accum); | |
| 334 | |
| 335 /* Calculate four data characters */ | |
| 336 | |
| 337 data_character[0] = (int) (left_pair / 1597); | |
| 338 data_character[1] = (int) (left_pair % 1597); | |
| 339 | |
| 340 data_character[2] = (int) (right_pair / 1597); | |
| 341 data_character[3] = (int) (right_pair % 1597); | |
| 342 | |
| 343 /* Calculate odd and even subset values */ | |
| 344 | |
| 345 if (data_character[0] <= 160) { | |
| 346 data_group[0] = 0; | |
| 347 } else if (data_character[0] <= 960) { | |
| 348 data_group[0] = 1; | |
| 349 } else if (data_character[0] <= 2014) { | |
| 350 data_group[0] = 2; | |
| 351 } else if (data_character[0] <= 2714) { | |
| 352 data_group[0] = 3; | |
| 353 } else { | |
| 354 data_group[0] = 4; | |
| 355 } | |
| 356 | |
| 357 if (data_character[1] <= 335) { | |
| 358 data_group[1] = 5; | |
| 359 } else if (data_character[1] <= 1035) { | |
| 360 data_group[1] = 6; | |
| 361 } else if (data_character[1] <= 1515) { | |
| 362 data_group[1] = 7; | |
| 363 } else { | |
| 364 data_group[1] = 8; | |
| 365 } | |
| 366 | |
| 367 if (data_character[3] <= 335) { | |
| 368 data_group[3] = 5; | |
| 369 } else if (data_character[3] <= 1035) { | |
| 370 data_group[3] = 6; | |
| 371 } else if (data_character[3] <= 1515) { | |
| 372 data_group[3] = 7; | |
| 373 } else { | |
| 374 data_group[3] = 8; | |
| 375 } | |
| 376 | |
| 377 if (data_character[2] <= 160) { | |
| 378 data_group[2] = 0; | |
| 379 } else if (data_character[2] <= 960) { | |
| 380 data_group[2] = 1; | |
| 381 } else if (data_character[2] <= 2014) { | |
| 382 data_group[2] = 2; | |
| 383 } else if (data_character[2] <= 2714) { | |
| 384 data_group[2] = 3; | |
| 385 } else { | |
| 386 data_group[2] = 4; | |
| 387 } | |
| 388 | |
| 389 v_odd[0] = (data_character[0] - dbar_g_sum_table[data_group[0]]) / dbar_t_table[data_group[0]]; | |
| 390 v_even[0] = (data_character[0] - dbar_g_sum_table[data_group[0]]) % dbar_t_table[data_group[0]]; | |
| 391 v_odd[1] = (data_character[1] - dbar_g_sum_table[data_group[1]]) % dbar_t_table[data_group[1]]; | |
| 392 v_even[1] = (data_character[1] - dbar_g_sum_table[data_group[1]]) / dbar_t_table[data_group[1]]; | |
| 393 v_odd[3] = (data_character[3] - dbar_g_sum_table[data_group[3]]) % dbar_t_table[data_group[3]]; | |
| 394 v_even[3] = (data_character[3] - dbar_g_sum_table[data_group[3]]) / dbar_t_table[data_group[3]]; | |
| 395 v_odd[2] = (data_character[2] - dbar_g_sum_table[data_group[2]]) / dbar_t_table[data_group[2]]; | |
| 396 v_even[2] = (data_character[2] - dbar_g_sum_table[data_group[2]]) % dbar_t_table[data_group[2]]; | |
| 397 | |
| 398 /* Use DataBar subset width algorithm */ | |
| 399 for (i = 0; i < 4; i++) { | |
| 400 if ((i == 0) || (i == 2)) { | |
| 401 getRSSwidths(widths, v_odd[i], dbar_modules_odd[data_group[i]], 4, dbar_widest_odd[data_group[i]], 1); | |
| 402 data_widths[0][i] = widths[0]; | |
| 403 data_widths[2][i] = widths[1]; | |
| 404 data_widths[4][i] = widths[2]; | |
| 405 data_widths[6][i] = widths[3]; | |
| 406 getRSSwidths(widths, v_even[i], dbar_modules_even[data_group[i]], 4, dbar_widest_even[data_group[i]], 0); | |
| 407 data_widths[1][i] = widths[0]; | |
| 408 data_widths[3][i] = widths[1]; | |
| 409 data_widths[5][i] = widths[2]; | |
| 410 data_widths[7][i] = widths[3]; | |
| 411 } else { | |
| 412 getRSSwidths(widths, v_odd[i], dbar_modules_odd[data_group[i]], 4, dbar_widest_odd[data_group[i]], 0); | |
| 413 data_widths[0][i] = widths[0]; | |
| 414 data_widths[2][i] = widths[1]; | |
| 415 data_widths[4][i] = widths[2]; | |
| 416 data_widths[6][i] = widths[3]; | |
| 417 getRSSwidths(widths, v_even[i], dbar_modules_even[data_group[i]], 4, dbar_widest_even[data_group[i]], 1); | |
| 418 data_widths[1][i] = widths[0]; | |
| 419 data_widths[3][i] = widths[1]; | |
| 420 data_widths[5][i] = widths[2]; | |
| 421 data_widths[7][i] = widths[3]; | |
| 422 } | |
| 423 } | |
| 424 | |
| 425 checksum = 0; | |
| 426 /* Calculate the checksum */ | |
| 427 for (i = 0; i < 8; i++) { | |
| 428 checksum += dbar_checksum_weight[i] * data_widths[i][0]; | |
| 429 checksum += dbar_checksum_weight[i + 8] * data_widths[i][1]; | |
| 430 checksum += dbar_checksum_weight[i + 16] * data_widths[i][2]; | |
| 431 checksum += dbar_checksum_weight[i + 24] * data_widths[i][3]; | |
| 432 } | |
| 433 checksum %= 79; | |
| 434 | |
| 435 /* Calculate the two check characters */ | |
| 436 if (checksum >= 8) { | |
| 437 checksum++; | |
| 438 } | |
| 439 if (checksum >= 72) { | |
| 440 checksum++; | |
| 441 } | |
| 442 c_left = checksum / 9; | |
| 443 c_right = checksum % 9; | |
| 444 | |
| 445 if (symbol->debug & ZINT_DEBUG_PRINT) { | |
| 446 printf("c_left: %d, c_right: %d\n", c_left, c_right); | |
| 447 } | |
| 448 | |
| 449 /* Put element widths together */ | |
| 450 total_widths[0] = 1; | |
| 451 total_widths[1] = 1; | |
| 452 total_widths[44] = 1; | |
| 453 total_widths[45] = 1; | |
| 454 for (i = 0; i < 8; i++) { | |
| 455 total_widths[i + 2] = data_widths[i][0]; | |
| 456 total_widths[i + 15] = data_widths[7 - i][1]; | |
| 457 total_widths[i + 23] = data_widths[i][3]; | |
| 458 total_widths[i + 36] = data_widths[7 - i][2]; | |
| 459 } | |
| 460 for (i = 0; i < 5; i++) { | |
| 461 total_widths[i + 10] = dbar_finder_pattern[i + (5 * c_left)]; | |
| 462 total_widths[i + 31] = dbar_finder_pattern[(4 - i) + (5 * c_right)]; | |
| 463 } | |
| 464 | |
| 465 /* Put this data into the symbol */ | |
| 466 if ((symbol->symbology == BARCODE_DBAR_OMN) || (symbol->symbology == BARCODE_DBAR_OMN_CC)) { | |
| 467 writer = 0; | |
| 468 latch = 0; | |
| 469 for (i = 0; i < 46; i++) { | |
| 470 writer = dbar_expand(symbol, writer, &latch, total_widths[i]); | |
| 471 } | |
| 472 if (symbol->width < writer) { | |
| 473 symbol->width = writer; | |
| 474 } | |
| 475 if (symbol->symbology == BARCODE_DBAR_OMN_CC) { | |
| 476 /* Separator pattern for composite symbol */ | |
| 477 dbar_omn_separator(symbol, 96, separator_row, 1 /*above*/, 18, 63, 0 /*bottom_finder_value_3*/); | |
| 478 } | |
| 479 symbol->rows = symbol->rows + 1; | |
| 480 | |
| 481 /* Set human readable text */ | |
| 482 dbar_set_gtin14_hrt(symbol, source, length); | |
| 483 | |
| 484 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 485 /* Minimum height is 13X for truncated symbol ISO/IEC 24724:2011 5.3.1 | |
| 486 Default height is 33X for DataBar Omnidirectional ISO/IEC 24724:2011 5.2 */ | |
| 487 if (symbol->symbology == BARCODE_DBAR_OMN_CC) { | |
| 488 symbol->height = symbol->height ? 13.0f : 33.0f; /* Pass back min row or default height */ | |
| 489 } else { | |
| 490 error_number = set_height(symbol, 13.0f, 33.0f, 0.0f, 0 /*no_errtxt*/); | |
| 491 } | |
| 492 } else { | |
| 493 if (symbol->symbology == BARCODE_DBAR_OMN_CC) { | |
| 494 symbol->height = 14.0f; /* 14X truncated min row height used (should be 13X) */ | |
| 495 } else { | |
| 496 (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); | |
| 497 } | |
| 498 } | |
| 499 | |
| 500 } else if ((symbol->symbology == BARCODE_DBAR_STK) || (symbol->symbology == BARCODE_DBAR_STK_CC)) { | |
| 501 /* Top row */ | |
| 502 writer = 0; | |
| 503 latch = 0; | |
| 504 for (i = 0; i < 23; i++) { | |
| 505 writer = dbar_expand(symbol, writer, &latch, total_widths[i]); | |
| 506 } | |
| 507 set_module(symbol, symbol->rows, writer); | |
| 508 unset_module(symbol, symbol->rows, writer + 1); | |
| 509 symbol->row_height[symbol->rows] = 5.0f; /* ISO/IEC 24724:2011 5.3.2.1 set to 5X */ | |
| 510 | |
| 511 /* Bottom row */ | |
| 512 symbol->rows = symbol->rows + 2; | |
| 513 set_module(symbol, symbol->rows, 0); | |
| 514 unset_module(symbol, symbol->rows, 1); | |
| 515 writer = 2; | |
| 516 latch = 1; | |
| 517 for (i = 23; i < 46; i++) { | |
| 518 writer = dbar_expand(symbol, writer, &latch, total_widths[i]); | |
| 519 } | |
| 520 symbol->row_height[symbol->rows] = 7.0f; /* ISO/IEC 24724:2011 5.3.2.1 set to 7X */ | |
| 521 | |
| 522 /* Separator pattern */ | |
| 523 /* See #183 for this interpretation of ISO/IEC 24724:2011 5.3.2.1 */ | |
| 524 for (i = 1; i < 46; i++) { | |
| 525 if (module_is_set(symbol, symbol->rows - 2, i) == module_is_set(symbol, symbol->rows, i)) { | |
| 526 if (!(module_is_set(symbol, symbol->rows - 2, i))) { | |
| 527 set_module(symbol, symbol->rows - 1, i); | |
| 528 } | |
| 529 } else { | |
| 530 if (!(module_is_set(symbol, symbol->rows - 1, i - 1))) { | |
| 531 set_module(symbol, symbol->rows - 1, i); | |
| 532 } | |
| 533 } | |
| 534 } | |
| 535 unset_module(symbol, symbol->rows - 1, 1); | |
| 536 unset_module(symbol, symbol->rows - 1, 2); | |
| 537 unset_module(symbol, symbol->rows - 1, 3); | |
| 538 symbol->row_height[symbol->rows - 1] = 1; | |
| 539 | |
| 540 if (symbol->symbology == BARCODE_DBAR_STK_CC) { | |
| 541 /* Separator pattern for composite symbol */ | |
| 542 dbar_omn_separator(symbol, 50, separator_row, 1 /*above*/, 18, 0, 0 /*bottom_finder_value_3*/); | |
| 543 } | |
| 544 symbol->rows = symbol->rows + 1; | |
| 545 if (symbol->width < 50) { | |
| 546 symbol->width = 50; | |
| 547 } | |
| 548 | |
| 549 if (symbol->symbology != BARCODE_DBAR_STK_CC) { /* Composite calls dbar_omnstk_set_height() itself */ | |
| 550 error_number = dbar_omnstk_set_height(symbol, 0 /*first_row*/); | |
| 551 } | |
| 552 | |
| 553 } else if ((symbol->symbology == BARCODE_DBAR_OMNSTK) || (symbol->symbology == BARCODE_DBAR_OMNSTK_CC)) { | |
| 554 /* Top row */ | |
| 555 writer = 0; | |
| 556 latch = 0; | |
| 557 for (i = 0; i < 23; i++) { | |
| 558 writer = dbar_expand(symbol, writer, &latch, total_widths[i]); | |
| 559 } | |
| 560 set_module(symbol, symbol->rows, writer); | |
| 561 unset_module(symbol, symbol->rows, writer + 1); | |
| 562 | |
| 563 /* Bottom row */ | |
| 564 symbol->rows = symbol->rows + 4; | |
| 565 set_module(symbol, symbol->rows, 0); | |
| 566 unset_module(symbol, symbol->rows, 1); | |
| 567 writer = 2; | |
| 568 latch = 1; | |
| 569 for (i = 23; i < 46; i++) { | |
| 570 writer = dbar_expand(symbol, writer, &latch, total_widths[i]); | |
| 571 } | |
| 572 | |
| 573 /* Middle separator */ | |
| 574 for (i = 5; i < 46; i += 2) { | |
| 575 set_module(symbol, symbol->rows - 2, i); | |
| 576 } | |
| 577 symbol->row_height[symbol->rows - 2] = 1; | |
| 578 | |
| 579 /* Top separator */ | |
| 580 dbar_omn_separator(symbol, 50, symbol->rows - 3, -1 /*below*/, 18, 0, 0 /*bottom_finder_value_3*/); | |
| 581 symbol->row_height[symbol->rows - 3] = 1; | |
| 582 | |
| 583 /* Bottom separator */ | |
| 584 /* 17 == 2 (guard) + 15 (inner char); +2 to skip over finder elements 4 & 5 (right to left) */ | |
| 585 dbar_omn_separator(symbol, 50, symbol->rows - 1, 1 /*above*/, 17 + 2, 0, c_right == 3); | |
| 586 symbol->row_height[symbol->rows - 1] = 1; | |
| 587 if (symbol->width < 50) { | |
| 588 symbol->width = 50; | |
| 589 } | |
| 590 | |
| 591 if (symbol->symbology == BARCODE_DBAR_OMNSTK_CC) { | |
| 592 /* Separator pattern for composite symbol */ | |
| 593 dbar_omn_separator(symbol, 50, separator_row, 1 /*above*/, 18, 0, 0 /*bottom_finder_value_3*/); | |
| 594 } | |
| 595 symbol->rows = symbol->rows + 1; | |
| 596 | |
| 597 /* ISO/IEC 24724:2011 5.3.2.2 minimum 33X height per row */ | |
| 598 if (symbol->symbology == BARCODE_DBAR_OMNSTK_CC) { | |
| 599 symbol->height = symbol->height ? 33.0f : 66.0f; /* Pass back min row or default height */ | |
| 600 } else { | |
| 601 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 602 error_number = set_height(symbol, 33.0f, 66.0f, 0.0f, 0 /*no_errtxt*/); | |
| 603 } else { | |
| 604 (void) set_height(symbol, 0.0f, 66.0f, 0.0f, 1 /*no_errtxt*/); | |
| 605 } | |
| 606 } | |
| 607 } | |
| 608 | |
| 609 return error_number; | |
| 610 } | |
| 611 | |
| 612 /* GS1 DataBar Omnidirectional/Truncated/Stacked */ | |
| 613 INTERNAL int dbar_omn(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 614 return dbar_omn_cc(symbol, source, length, 0 /*cc_rows*/); | |
| 615 } | |
| 616 | |
| 617 /* GS1 DataBar Limited, allowing for composite if `cc_rows` set */ | |
| 618 INTERNAL int dbar_ltd_cc(struct zint_symbol *symbol, unsigned char source[], int length, const int cc_rows) { | |
| 619 int error_number = 0, i; | |
| 620 large_uint accum; | |
| 621 uint64_t left_character, right_character; | |
| 622 int left_group, right_group, left_odd, left_even, right_odd, right_even; | |
| 623 int left_widths[14], right_widths[14]; | |
| 624 int checksum, check_elements[14], total_widths[47], writer; | |
| 625 int latch; | |
| 626 int separator_row; | |
| 627 int widths[7]; | |
| 628 | |
| 629 separator_row = 0; | |
| 630 | |
| 631 if (length > 14) { /* Allow check digit to be specified (will be verified and ignored) */ | |
| 632 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 382, "Input length %d too long (maximum 14)", length); | |
| 633 } | |
| 634 if ((i = not_sane(NEON_F, source, length))) { | |
| 635 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 383, | |
| 636 "Invalid character at position %d in input (digits only)", i); | |
| 637 } | |
| 638 | |
| 639 if (length == 14) { /* Verify check digit */ | |
| 640 if (gs1_check_digit(source, 13) != source[13]) { | |
| 641 return errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 389, "Invalid check digit '%1$c', expecting '%2$c'", | |
| 642 source[13], gs1_check_digit(source, 13)); | |
| 643 } | |
| 644 length--; /* Ignore */ | |
| 645 } | |
| 646 | |
| 647 if (length == 13) { | |
| 648 if ((source[0] != '0') && (source[0] != '1')) { | |
| 649 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 384, "Input value out of range (0 to 1999999999999)"); | |
| 650 } | |
| 651 } | |
| 652 | |
| 653 /* Make some room for a separator row for composite symbols */ | |
| 654 if (symbol->symbology == BARCODE_DBAR_LTD_CC) { | |
| 655 separator_row = symbol->rows; | |
| 656 symbol->row_height[separator_row] = 1; | |
| 657 symbol->rows += 1; | |
| 658 } | |
| 659 | |
| 660 large_load_str_u64(&accum, source, length); | |
| 661 | |
| 662 if (cc_rows) { | |
| 663 /* Add symbol linkage flag */ | |
| 664 large_add_u64(&accum, 2015133531096); | |
| 665 } | |
| 666 | |
| 667 /* Calculate left and right pair values */ | |
| 668 | |
| 669 right_character = large_div_u64(&accum, 2013571); | |
| 670 left_character = large_lo(&accum); | |
| 671 | |
| 672 if (left_character >= 1996939) { | |
| 673 left_group = 6; | |
| 674 left_character -= 1996939; | |
| 675 } else if (left_character >= 1979845) { | |
| 676 left_group = 5; | |
| 677 left_character -= 1979845; | |
| 678 } else if (left_character >= 1491021) { | |
| 679 left_group = 4; | |
| 680 left_character -= 1491021; | |
| 681 } else if (left_character >= 1000776) { | |
| 682 left_group = 3; | |
| 683 left_character -= 1000776; | |
| 684 } else if (left_character >= 820064) { | |
| 685 left_group = 2; | |
| 686 left_character -= 820064; | |
| 687 } else if (left_character >= 183064) { | |
| 688 left_group = 1; | |
| 689 left_character -= 183064; | |
| 690 } else { | |
| 691 left_group = 0; | |
| 692 } | |
| 693 | |
| 694 if (right_character >= 1996939) { | |
| 695 right_group = 6; | |
| 696 right_character -= 1996939; | |
| 697 } else if (right_character >= 1979845) { | |
| 698 right_group = 5; | |
| 699 right_character -= 1979845; | |
| 700 } else if (right_character >= 1491021) { | |
| 701 right_group = 4; | |
| 702 right_character -= 1491021; | |
| 703 } else if (right_character >= 1000776) { | |
| 704 right_group = 3; | |
| 705 right_character -= 1000776; | |
| 706 } else if (right_character >= 820064) { | |
| 707 right_group = 2; | |
| 708 right_character -= 820064; | |
| 709 } else if (right_character >= 183064) { | |
| 710 right_group = 1; | |
| 711 right_character -= 183064; | |
| 712 } else { | |
| 713 right_group = 0; | |
| 714 } | |
| 715 | |
| 716 left_odd = (int) (left_character / dbar_ltd_t_even[left_group]); | |
| 717 left_even = (int) (left_character % dbar_ltd_t_even[left_group]); | |
| 718 right_odd = (int) (right_character / dbar_ltd_t_even[right_group]); | |
| 719 right_even = (int) (right_character % dbar_ltd_t_even[right_group]); | |
| 720 | |
| 721 getRSSwidths(widths, left_odd, dbar_ltd_modules_odd[left_group], 7, dbar_ltd_widest_odd[left_group], 1); | |
| 722 for (i = 0; i <= 6; i++) { | |
| 723 left_widths[i * 2] = widths[i]; | |
| 724 } | |
| 725 getRSSwidths(widths, left_even, dbar_ltd_modules_even[left_group], 7, dbar_ltd_widest_even[left_group], 0); | |
| 726 for (i = 0; i <= 6; i++) { | |
| 727 left_widths[i * 2 + 1] = widths[i]; | |
| 728 } | |
| 729 getRSSwidths(widths, right_odd, dbar_ltd_modules_odd[right_group], 7, dbar_ltd_widest_odd[right_group], 1); | |
| 730 for (i = 0; i <= 6; i++) { | |
| 731 right_widths[i * 2] = widths[i]; | |
| 732 } | |
| 733 getRSSwidths(widths, right_even, dbar_ltd_modules_even[right_group], 7, dbar_ltd_widest_even[right_group], 0); | |
| 734 for (i = 0; i <= 6; i++) { | |
| 735 right_widths[i * 2 + 1] = widths[i]; | |
| 736 } | |
| 737 | |
| 738 checksum = 0; | |
| 739 /* Calculate the checksum */ | |
| 740 for (i = 0; i < 14; i++) { | |
| 741 #if defined(_MSC_VER) && _MSC_VER == 1900 && defined(_WIN64) /* MSVC 2015 x64 */ | |
| 742 checksum %= 89; /* Hack to get around optimizer bug */ | |
| 743 #endif | |
| 744 checksum += dbar_ltd_checksum_weight[i] * left_widths[i]; | |
| 745 checksum += dbar_ltd_checksum_weight[i + 14] * right_widths[i]; | |
| 746 } | |
| 747 checksum %= 89; | |
| 748 | |
| 749 for (i = 0; i < 14; i++) { | |
| 750 check_elements[i] = dbar_ltd_finder_pattern[i + (checksum * 14)]; | |
| 751 } | |
| 752 | |
| 753 total_widths[0] = 1; | |
| 754 total_widths[1] = 1; | |
| 755 total_widths[44] = 1; | |
| 756 total_widths[45] = 1; | |
| 757 total_widths[46] = 5; | |
| 758 for (i = 0; i < 14; i++) { | |
| 759 total_widths[i + 2] = left_widths[i]; | |
| 760 total_widths[i + 16] = check_elements[i]; | |
| 761 total_widths[i + 30] = right_widths[i]; | |
| 762 } | |
| 763 | |
| 764 writer = 0; | |
| 765 latch = 0; | |
| 766 for (i = 0; i < 47; i++) { | |
| 767 writer = dbar_expand(symbol, writer, &latch, total_widths[i]); | |
| 768 } | |
| 769 if (symbol->width < writer) { | |
| 770 symbol->width = writer; | |
| 771 } | |
| 772 symbol->rows = symbol->rows + 1; | |
| 773 | |
| 774 /* Add separator pattern if composite symbol */ | |
| 775 if (symbol->symbology == BARCODE_DBAR_LTD_CC) { | |
| 776 for (i = 4; i < 70; i++) { | |
| 777 if (!(module_is_set(symbol, separator_row + 1, i))) { | |
| 778 set_module(symbol, separator_row, i); | |
| 779 } | |
| 780 } | |
| 781 } | |
| 782 | |
| 783 /* Set human readable text */ | |
| 784 dbar_set_gtin14_hrt(symbol, source, length); | |
| 785 | |
| 786 /* ISO/IEC 24724:2011 6.2 10X minimum height, use as default also */ | |
| 787 if (symbol->symbology == BARCODE_DBAR_LTD_CC) { | |
| 788 symbol->height = 10.0f; /* Pass back min row == default height */ | |
| 789 } else { | |
| 790 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 791 error_number = set_height(symbol, 10.0f, 10.0f, 0.0f, 0 /*no_errtxt*/); | |
| 792 } else { | |
| 793 (void) set_height(symbol, 0.0f, 50.0f, 0.0f, 1 /*no_errtxt*/); | |
| 794 } | |
| 795 } | |
| 796 | |
| 797 return error_number; | |
| 798 } | |
| 799 | |
| 800 /* GS1 DataBar Limited */ | |
| 801 INTERNAL int dbar_ltd(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 802 return dbar_ltd_cc(symbol, source, length, 0 /*cc_rows*/); | |
| 803 } | |
| 804 | |
| 805 /* Check and convert date to DataBar date value */ | |
| 806 INTERNAL int dbar_date(const unsigned char source[], const int length, const int src_posn) { | |
| 807 int yy, mm, dd; | |
| 808 | |
| 809 if (src_posn + 4 + 2 > length) { | |
| 810 return -1; | |
| 811 } | |
| 812 yy = to_int(source + src_posn, 2); | |
| 813 mm = to_int(source + src_posn + 2, 2); | |
| 814 dd = to_int(source + src_posn + 4, 2); | |
| 815 | |
| 816 /* Month can't be zero but day can (means last day of month, | |
| 817 GS1 General Specifications Sections 3.4.2 to 3.4.7) */ | |
| 818 if (yy < 0 || mm <= 0 || mm > 12 || dd < 0 || dd > 31) { | |
| 819 return -1; | |
| 820 } | |
| 821 return yy * 384 + (mm - 1) * 32 + dd; | |
| 822 } | |
| 823 | |
| 824 /* Handles all data encodation from section 7.2.5 of ISO/IEC 24724 */ | |
| 825 static int dbar_exp_binary_string(struct zint_symbol *symbol, const unsigned char source[], char binary_string[], | |
| 826 int *p_cols_per_row, const int max_rows, int *p_bp) { | |
| 827 int encoding_method, i, j, read_posn, mode = NUMERIC; | |
| 828 char last_digit = '\0'; | |
| 829 int symbol_characters, characters_per_row = *p_cols_per_row * 2; | |
| 830 int min_cols_per_row = 0; | |
| 831 int length = (int) ustrlen(source); | |
| 832 const int debug_print = (symbol->debug & ZINT_DEBUG_PRINT); | |
| 833 char *general_field = (char *) z_alloca(length + 1); | |
| 834 int bp = *p_bp; | |
| 835 int remainder, d1, d2; | |
| 836 int cdf_bp_start; /* Compressed data field start - debug only */ | |
| 837 | |
| 838 if (length > 77) { /* ISO/IEC 24724:2011 4.2.d.2 */ | |
| 839 /* Caught below anyway but catch here also for better feedback */ | |
| 840 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 378, "Processed input length %d too long (maximum 77)", length); | |
| 841 } | |
| 842 | |
| 843 /* Decide whether a compressed data field is required and if so what | |
| 844 method to use - method 2 = no compressed data field */ | |
| 845 | |
| 846 if ((length >= 16) && ((source[0] == '0') && (source[1] == '1'))) { | |
| 847 /* (01) and other AIs */ | |
| 848 encoding_method = 1; | |
| 849 if (debug_print) fputs("Choosing Method 1\n", stdout); | |
| 850 } else { | |
| 851 /* Any AIs */ | |
| 852 encoding_method = 2; | |
| 853 if (debug_print) fputs("Choosing Method 2\n", stdout); | |
| 854 } | |
| 855 | |
| 856 if (((length >= 20) && (encoding_method == 1)) && ((source[2] == '9') && (source[16] == '3'))) { | |
| 857 /* Possibly encoding method > 2 */ | |
| 858 | |
| 859 if (debug_print) fputs("Checking for other methods\n", stdout); | |
| 860 | |
| 861 if ((length >= 26) && (source[17] == '1') && (source[18] == '0')) { | |
| 862 /* Methods 3, 7, 9, 11 and 13 */ | |
| 863 | |
| 864 /* (01) and (310x) */ | |
| 865 int weight = to_int(source + 20, 6); | |
| 866 | |
| 867 /* Maximum weight = 99999 for 7 to 14 (ISO/IEC 24724:2011 7.2.5.4.4) */ | |
| 868 if (weight >= 0 && weight <= 99999) { | |
| 869 | |
| 870 if (length == 26) { | |
| 871 if ((source[19] == '3') && weight <= 32767) { /* In grams, max 32.767 kilos */ | |
| 872 /* (01) and (3103) */ | |
| 873 encoding_method = 3; | |
| 874 } else { | |
| 875 /* (01), (310x) - use method 7 with dummy date 38400 */ | |
| 876 encoding_method = 7; | |
| 877 } | |
| 878 | |
| 879 } else if ((length == 34) && (source[26] == '1') | |
| 880 && (source[27] == '1' || source[27] == '3' || source[27] == '5' || source[27] == '7') | |
| 881 && dbar_date(source, length, 28) >= 0) { | |
| 882 | |
| 883 /* (01), (310x) and (11) - metric weight and production date */ | |
| 884 /* (01), (310x) and (13) - metric weight and packaging date */ | |
| 885 /* (01), (310x) and (15) - metric weight and "best before" date */ | |
| 886 /* (01), (310x) and (17) - metric weight and expiration date */ | |
| 887 encoding_method = 6 + (source[27] - '0'); | |
| 888 } | |
| 889 } | |
| 890 | |
| 891 } else if ((length >= 26) && (source[17] == '2') && (source[18] == '0')) { | |
| 892 /* Methods 4, 8, 10, 12 and 14 */ | |
| 893 | |
| 894 /* (01) and (320x) */ | |
| 895 int weight = to_int(source + 20, 6); | |
| 896 | |
| 897 /* Maximum weight = 99999 for 7 to 14 (ISO/IEC 24724:2011 7.2.5.4.4) */ | |
| 898 if (weight >= 0 && weight <= 99999) { | |
| 899 | |
| 900 /* (3202) in 0.01 pounds, max 99.99 pounds; (3203) in 0.001 pounds, max 22.767 pounds */ | |
| 901 if (length == 26) { | |
| 902 if ((source[19] == '2' && weight <= 9999) || (source[19] == '3' && weight <= 22767)) { | |
| 903 /* (01) and (3202)/(3203) */ | |
| 904 encoding_method = 4; | |
| 905 } else { | |
| 906 /* (01), (320x) - use method 8 with dummy date 38400 */ | |
| 907 encoding_method = 8; | |
| 908 } | |
| 909 | |
| 910 } else if ((length == 34) && (source[26] == '1') | |
| 911 && (source[27] == '1' || source[27] == '3' || source[27] == '5' || source[27] == '7') | |
| 912 && dbar_date(source, length, 28) >= 0) { | |
| 913 | |
| 914 /* (01), (320x) and (11) - English weight and production date */ | |
| 915 /* (01), (320x) and (13) - English weight and packaging date */ | |
| 916 /* (01), (320x) and (15) - English weight and "best before" date */ | |
| 917 /* (01), (320x) and (17) - English weight and expiration date */ | |
| 918 encoding_method = 7 + (source[27] - '0'); | |
| 919 } | |
| 920 } | |
| 921 | |
| 922 } else if ((source[17] == '9') && ((source[19] >= '0') && (source[19] <= '3'))) { | |
| 923 /* Methods 5 and 6 */ | |
| 924 if (source[18] == '2') { | |
| 925 /* (01) and (392x) */ | |
| 926 encoding_method = 5; | |
| 927 } else if (source[18] == '3' && to_int(source + 20, 3) >= 0) { /* Check 3-digit currency string */ | |
| 928 /* (01) and (393x) */ | |
| 929 encoding_method = 6; | |
| 930 } | |
| 931 } | |
| 932 | |
| 933 if (debug_print && encoding_method != 1) printf("Now using method %d\n", encoding_method); | |
| 934 } | |
| 935 | |
| 936 switch (encoding_method) { /* Encoding method - Table 10 */ | |
| 937 case 1: bp = bin_append_posn(4, 3, binary_string, bp); /* "1XX" */ | |
| 938 read_posn = 16; | |
| 939 break; | |
| 940 case 2: bp = bin_append_posn(0, 4, binary_string, bp); /* "00XX" */ | |
| 941 read_posn = 0; | |
| 942 break; | |
| 943 case 3: /* 0100 */ | |
| 944 case 4: /* 0101 */ | |
| 945 bp = bin_append_posn(4 + (encoding_method - 3), 4, binary_string, bp); | |
| 946 read_posn = 26; | |
| 947 break; | |
| 948 case 5: bp = bin_append_posn(0x30, 7, binary_string, bp); /* "01100XX" */ | |
| 949 read_posn = 20; | |
| 950 break; | |
| 951 case 6: bp = bin_append_posn(0x34, 7, binary_string, bp); /* "01101XX" */ | |
| 952 read_posn = 23; | |
| 953 break; | |
| 954 default: /* Modes 7 to 14 */ | |
| 955 bp = bin_append_posn(56 + (encoding_method - 7), 7, binary_string, bp); | |
| 956 read_posn = length; /* 34 or 26 */ | |
| 957 break; | |
| 958 } | |
| 959 if (debug_print) printf("Setting binary = %.*s\n", bp, binary_string); | |
| 960 | |
| 961 /* Variable length symbol bit field is just given a place holder (XX) for the time being */ | |
| 962 | |
| 963 /* Verify that the data to be placed in the compressed data field is all numeric data | |
| 964 before carrying out compression */ | |
| 965 for (i = 0; i < read_posn; i++) { | |
| 966 if (!z_isdigit(source[i])) { | |
| 967 if (source[i] != '\x1D') { | |
| 968 /* Something is wrong */ | |
| 969 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 385, | |
| 970 "Invalid character in Compressed Field data (digits only)"); | |
| 971 } | |
| 972 } | |
| 973 } | |
| 974 | |
| 975 /* Now encode the compressed data field */ | |
| 976 | |
| 977 if (debug_print) fputs("Proceeding to encode data\n", stdout); | |
| 978 cdf_bp_start = bp; /* Debug use only */ | |
| 979 | |
| 980 if (encoding_method == 1) { | |
| 981 /* Encoding method field "1" - general item identification data */ | |
| 982 | |
| 983 bp = bin_append_posn(ctoi(source[2]), 4, binary_string, bp); /* Leading digit after stripped "01" */ | |
| 984 | |
| 985 for (i = 3; i < 15; i += 3) { /* Next 12 digits, excluding final check digit */ | |
| 986 bp = bin_append_posn(to_int(source + i, 3), 10, binary_string, bp); | |
| 987 } | |
| 988 | |
| 989 } else if ((encoding_method == 3) || (encoding_method == 4)) { | |
| 990 /* Encoding method field "0100" - variable weight item (0,001 kilogram increments) */ | |
| 991 /* Encoding method field "0101" - variable weight item (0,01 or 0,001 pound increment) */ | |
| 992 | |
| 993 for (i = 3; i < 15; i += 3) { /* Leading "019" stripped, and final check digit excluded */ | |
| 994 bp = bin_append_posn(to_int(source + i, 3), 10, binary_string, bp); | |
| 995 } | |
| 996 | |
| 997 if ((encoding_method == 4) && (source[19] == '3')) { | |
| 998 bp = bin_append_posn(to_int(source + 20, 6) + 10000, 15, binary_string, bp); | |
| 999 } else { | |
| 1000 bp = bin_append_posn(to_int(source + 20, 6), 15, binary_string, bp); | |
| 1001 } | |
| 1002 | |
| 1003 } else if ((encoding_method == 5) || (encoding_method == 6)) { | |
| 1004 /* Encoding method "01100" - variable measure item and price */ | |
| 1005 /* Encoding method "01101" - variable measure item and price with ISO 4217 Currency Code */ | |
| 1006 | |
| 1007 for (i = 3; i < 15; i += 3) { /* Leading "019" stripped, and final check digit excluded */ | |
| 1008 bp = bin_append_posn(to_int(source + i, 3), 10, binary_string, bp); | |
| 1009 } | |
| 1010 | |
| 1011 bp = bin_append_posn(source[19] - '0', 2, binary_string, bp); /* 0-3 x of 392x/393x */ | |
| 1012 | |
| 1013 if (encoding_method == 6) { | |
| 1014 bp = bin_append_posn(to_int(source + 20, 3), 10, binary_string, bp); /* 3-digit currency */ | |
| 1015 } | |
| 1016 | |
| 1017 } else if ((encoding_method >= 7) && (encoding_method <= 14)) { | |
| 1018 /* Encoding method fields "0111000" through "0111111" - variable weight item plus date */ | |
| 1019 int group_val; | |
| 1020 char weight_str[8]; | |
| 1021 | |
| 1022 for (i = 3; i < 15; i += 3) { /* Leading "019" stripped, and final check digit excluded */ | |
| 1023 bp = bin_append_posn(to_int(source + i, 3), 10, binary_string, bp); | |
| 1024 } | |
| 1025 | |
| 1026 weight_str[0] = source[19]; /* 0-9 x of 310x/320x */ | |
| 1027 | |
| 1028 for (i = 1; i < 6; i++) { /* Leading "0" of weight excluded */ | |
| 1029 weight_str[i] = source[20 + i]; | |
| 1030 } | |
| 1031 weight_str[6] = '\0'; | |
| 1032 | |
| 1033 bp = bin_append_posn(atoi(weight_str), 20, binary_string, bp); | |
| 1034 | |
| 1035 if (length == 34) { | |
| 1036 /* Date information is included */ | |
| 1037 group_val = dbar_date(source, length, 28); | |
| 1038 } else { | |
| 1039 group_val = 38400; | |
| 1040 } | |
| 1041 | |
| 1042 bp = bin_append_posn((int) group_val, 16, binary_string, bp); | |
| 1043 } | |
| 1044 | |
| 1045 if (debug_print && bp > cdf_bp_start) { | |
| 1046 printf("Compressed data field (%d) = %.*s\n", bp - cdf_bp_start, bp - cdf_bp_start, | |
| 1047 binary_string + cdf_bp_start); | |
| 1048 } | |
| 1049 | |
| 1050 /* The compressed data field has been processed if appropriate - the | |
| 1051 rest of the data (if any) goes into a general-purpose data compaction field */ | |
| 1052 | |
| 1053 j = 0; | |
| 1054 for (i = read_posn; i < length; i++) { | |
| 1055 general_field[j] = source[i]; | |
| 1056 j++; | |
| 1057 } | |
| 1058 general_field[j] = '\0'; | |
| 1059 | |
| 1060 if (debug_print) printf("General field data = %s\n", general_field); | |
| 1061 | |
| 1062 if (j != 0) { /* If general field not empty */ | |
| 1063 if (!general_field_encode(general_field, j, &mode, &last_digit, binary_string, &bp)) { | |
| 1064 /* Will happen if character not in CSET 82 + space */ | |
| 1065 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 386, "Invalid character in General Field data"); | |
| 1066 } | |
| 1067 } | |
| 1068 | |
| 1069 if (debug_print) printf("Resultant binary (%d): %.*s\n", bp, bp, binary_string); | |
| 1070 | |
| 1071 remainder = 12 - (bp % 12); | |
| 1072 if (remainder == 12) { | |
| 1073 remainder = 0; | |
| 1074 } | |
| 1075 symbol_characters = ((bp + remainder) / 12) + 1; | |
| 1076 | |
| 1077 if (max_rows) { | |
| 1078 min_cols_per_row = ((symbol_characters + 1) / 2 + max_rows - 1) / max_rows; | |
| 1079 if (min_cols_per_row > *p_cols_per_row) { | |
| 1080 characters_per_row = min_cols_per_row * 2; | |
| 1081 } | |
| 1082 } | |
| 1083 | |
| 1084 if (characters_per_row && (symbol_characters % characters_per_row) == 1) { /* DBAR_EXPSTK */ | |
| 1085 symbol_characters++; | |
| 1086 } | |
| 1087 | |
| 1088 if (symbol_characters < 4) { | |
| 1089 symbol_characters = 4; | |
| 1090 } | |
| 1091 | |
| 1092 remainder = (12 * (symbol_characters - 1)) - bp; | |
| 1093 | |
| 1094 if (last_digit) { | |
| 1095 /* There is still one more numeric digit to encode */ | |
| 1096 if (debug_print) fputs("Adding extra (odd) numeric digit\n", stdout); | |
| 1097 | |
| 1098 if ((remainder >= 4) && (remainder <= 6)) { | |
| 1099 bp = bin_append_posn(ctoi(last_digit) + 1, 4, binary_string, bp); | |
| 1100 } else { | |
| 1101 d1 = ctoi(last_digit); | |
| 1102 d2 = 10; | |
| 1103 | |
| 1104 bp = bin_append_posn((11 * d1) + d2 + 8, 7, binary_string, bp); | |
| 1105 } | |
| 1106 | |
| 1107 remainder = 12 - (bp % 12); | |
| 1108 if (remainder == 12) { | |
| 1109 remainder = 0; | |
| 1110 } | |
| 1111 symbol_characters = ((bp + remainder) / 12) + 1; | |
| 1112 | |
| 1113 if (max_rows) { | |
| 1114 min_cols_per_row = ((symbol_characters + 1) / 2 + max_rows - 1) / max_rows; | |
| 1115 if (min_cols_per_row > *p_cols_per_row) { | |
| 1116 characters_per_row = min_cols_per_row * 2; | |
| 1117 } | |
| 1118 } | |
| 1119 | |
| 1120 if (characters_per_row && (symbol_characters % characters_per_row) == 1) { /* DBAR_EXPSTK */ | |
| 1121 symbol_characters++; | |
| 1122 } | |
| 1123 | |
| 1124 if (symbol_characters < 4) { | |
| 1125 symbol_characters = 4; | |
| 1126 } | |
| 1127 | |
| 1128 remainder = (12 * (symbol_characters - 1)) - bp; | |
| 1129 | |
| 1130 if (debug_print) printf(" Expanded binary (%d): %.*s\n", bp, bp, binary_string); | |
| 1131 } | |
| 1132 | |
| 1133 if (bp > 252) { /* 252 = (21 * 12) */ | |
| 1134 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 387, /* TODO: Better error message */ | |
| 1135 "Input too long, requires %d symbol characters (maximum 21)", (bp + 11) / 12); | |
| 1136 } | |
| 1137 | |
| 1138 if (min_cols_per_row && min_cols_per_row > *p_cols_per_row) { | |
| 1139 *p_cols_per_row = min_cols_per_row; | |
| 1140 } | |
| 1141 | |
| 1142 /* Now add padding to binary string (7.2.5.5.4) */ | |
| 1143 i = remainder; | |
| 1144 if (mode == NUMERIC) { | |
| 1145 bp = bin_append_posn(0, 4, binary_string, bp); /* "0000" */ | |
| 1146 i -= 4; | |
| 1147 } | |
| 1148 for (; i > 0; i -= 5) { | |
| 1149 bp = bin_append_posn(4, 5, binary_string, bp); /* "00100" */ | |
| 1150 } | |
| 1151 | |
| 1152 /* Patch variable length symbol bit field */ | |
| 1153 d1 = symbol_characters & 1; | |
| 1154 | |
| 1155 if (symbol_characters <= 14) { | |
| 1156 d2 = 0; | |
| 1157 } else { | |
| 1158 d2 = 1; | |
| 1159 } | |
| 1160 | |
| 1161 if (encoding_method == 1) { | |
| 1162 binary_string[2] = d1 ? '1' : '0'; | |
| 1163 binary_string[3] = d2 ? '1' : '0'; | |
| 1164 } else if (encoding_method == 2) { | |
| 1165 binary_string[3] = d1 ? '1' : '0'; | |
| 1166 binary_string[4] = d2 ? '1' : '0'; | |
| 1167 } else if ((encoding_method == 5) || (encoding_method == 6)) { | |
| 1168 binary_string[6] = d1 ? '1' : '0'; | |
| 1169 binary_string[7] = d2 ? '1' : '0'; | |
| 1170 } | |
| 1171 if (debug_print) { | |
| 1172 printf(" Final binary (%d): %.*s\n Symbol chars: %d, Remainder: %d\n", | |
| 1173 bp, bp, binary_string, symbol_characters, remainder); | |
| 1174 } | |
| 1175 | |
| 1176 *p_bp = bp; | |
| 1177 | |
| 1178 return 0; | |
| 1179 } | |
| 1180 | |
| 1181 /* Separator for DataBar Expanded Stacked and DataBar Expanded Composite */ | |
| 1182 static void dbar_exp_separator(struct zint_symbol *symbol, int width, const int cols, const int separator_row, | |
| 1183 const int above_below, const int special_case_row, const int left_to_right, const int odd_last_row, | |
| 1184 int *p_v2_latch) { | |
| 1185 int i, i_start, i_end, j, k; | |
| 1186 int module_row = separator_row + above_below; | |
| 1187 int v2_latch = p_v2_latch ? *p_v2_latch : 0; | |
| 1188 int space_latch = 0; | |
| 1189 | |
| 1190 for (j = 4 + special_case_row, width -= 4; j < width; j++) { | |
| 1191 if (module_is_set(symbol, module_row, j)) { | |
| 1192 unset_module(symbol, separator_row, j); | |
| 1193 } else { | |
| 1194 set_module(symbol, separator_row, j); | |
| 1195 } | |
| 1196 } | |
| 1197 | |
| 1198 /* Finder adjustment */ | |
| 1199 for (j = 0; j < cols; j++) { | |
| 1200 /* 49 == data (17) + finder (15) + data(17) triplet, 19 == 2 (guard) + 17 (initial check/data character) */ | |
| 1201 k = (49 * j) + 19 + special_case_row; | |
| 1202 if (left_to_right) { | |
| 1203 /* Last 13 modules of version 2 finder and first 13 modules of version 1 finder */ | |
| 1204 i_start = v2_latch ? 2 : 0; | |
| 1205 i_end = v2_latch ? 15 : 13; | |
| 1206 for (i = i_start; i < i_end; i++) { | |
| 1207 if (module_is_set(symbol, module_row, i + k)) { | |
| 1208 unset_module(symbol, separator_row, i + k); | |
| 1209 space_latch = 0; | |
| 1210 } else { | |
| 1211 if (space_latch) { | |
| 1212 unset_module(symbol, separator_row, i + k); | |
| 1213 } else { | |
| 1214 set_module(symbol, separator_row, i + k); | |
| 1215 } | |
| 1216 space_latch = !space_latch; | |
| 1217 } | |
| 1218 } | |
| 1219 } else { | |
| 1220 if (odd_last_row) { | |
| 1221 k -= 17; /* No data char at beginning of row, i.e. ends with finder */ | |
| 1222 } | |
| 1223 /* First 13 modules of version 1 finder and last 13 modules of version 2 finder */ | |
| 1224 i_start = v2_latch ? 14 : 12; | |
| 1225 i_end = v2_latch ? 2 : 0; | |
| 1226 for (i = i_start; i >= i_end; i--) { | |
| 1227 if (module_is_set(symbol, module_row, i + k)) { | |
| 1228 unset_module(symbol, separator_row, i + k); | |
| 1229 space_latch = 0; | |
| 1230 } else { | |
| 1231 if (space_latch) { | |
| 1232 unset_module(symbol, separator_row, i + k); | |
| 1233 } else { | |
| 1234 set_module(symbol, separator_row, i + k); | |
| 1235 } | |
| 1236 space_latch = !space_latch; | |
| 1237 } | |
| 1238 } | |
| 1239 } | |
| 1240 v2_latch = !v2_latch; | |
| 1241 } | |
| 1242 | |
| 1243 if (p_v2_latch && above_below == -1) { /* Only set if below */ | |
| 1244 *p_v2_latch = v2_latch; | |
| 1245 } | |
| 1246 } | |
| 1247 | |
| 1248 /* Set HRT for DataBar Expanded */ | |
| 1249 static void dbar_exp_hrt(struct zint_symbol *symbol, unsigned char source[], const int length) { | |
| 1250 | |
| 1251 /* Max possible length is 77 digits so will fit */ | |
| 1252 if (symbol->input_mode & GS1PARENS_MODE) { | |
| 1253 memcpy(symbol->text, source, length + 1); /* Include terminating NUL */ | |
| 1254 } else { | |
| 1255 int i; | |
| 1256 /* Can't have square brackets in content so bracket level not required */ | |
| 1257 for (i = 0; i <= length /* Include terminating NUL */; i++) { | |
| 1258 if (source[i] == '[') { | |
| 1259 symbol->text[i] = '('; | |
| 1260 } else if (source[i] == ']') { | |
| 1261 symbol->text[i] = ')'; | |
| 1262 } else { | |
| 1263 symbol->text[i] = source[i]; | |
| 1264 } | |
| 1265 } | |
| 1266 } | |
| 1267 } | |
| 1268 | |
| 1269 /* GS1 DataBar Expanded, setting linkage for composite if `cc_rows` set */ | |
| 1270 INTERNAL int dbar_exp_cc(struct zint_symbol *symbol, unsigned char source[], int length, const int cc_rows) { | |
| 1271 int error_number, warn_number; | |
| 1272 int i, j, k, p, codeblocks, data_chars, vs, group, v_odd, v_even; | |
| 1273 int latch; | |
| 1274 int char_widths[21][8], checksum, check_widths[8], c_group; | |
| 1275 int check_char, c_odd, c_even, elements[235], pattern_width, reader, writer; | |
| 1276 int separator_row; | |
| 1277 /* Allow for 8 bits + 5-bit latch per char + 200 bits overhead/padding */ | |
| 1278 unsigned int bin_len = 13 * length + 200 + 1; | |
| 1279 int widths[4]; | |
| 1280 int bp = 0; | |
| 1281 int cols_per_row = 0; | |
| 1282 int max_rows = 0; | |
| 1283 int stack_rows = 1; | |
| 1284 const int debug_print = (symbol->debug & ZINT_DEBUG_PRINT); | |
| 1285 unsigned char *reduced = (unsigned char *) z_alloca(length + 1); | |
| 1286 char *binary_string = (char *) z_alloca(bin_len); | |
| 1287 | |
| 1288 separator_row = 0; | |
| 1289 | |
| 1290 error_number = gs1_verify(symbol, source, length, reduced); | |
| 1291 if (error_number >= ZINT_ERROR) { | |
| 1292 return error_number; | |
| 1293 } | |
| 1294 warn_number = error_number; | |
| 1295 | |
| 1296 if (debug_print) { | |
| 1297 printf("Reduced (%d): %s\n", (int) ustrlen(reduced), reduced); | |
| 1298 } | |
| 1299 | |
| 1300 if ((symbol->symbology == BARCODE_DBAR_EXP_CC) || (symbol->symbology == BARCODE_DBAR_EXPSTK_CC)) { | |
| 1301 /* Make space for a composite separator pattern */ | |
| 1302 separator_row = symbol->rows; | |
| 1303 symbol->row_height[separator_row] = 1; | |
| 1304 symbol->rows += 1; | |
| 1305 } | |
| 1306 | |
| 1307 if (cc_rows) { /* The "component linkage" flag */ | |
| 1308 binary_string[bp++] = '1'; | |
| 1309 } else { | |
| 1310 binary_string[bp++] = '0'; | |
| 1311 } | |
| 1312 | |
| 1313 if ((symbol->symbology == BARCODE_DBAR_EXPSTK) || (symbol->symbology == BARCODE_DBAR_EXPSTK_CC)) { | |
| 1314 cols_per_row = 2; /* Default */ | |
| 1315 if (symbol->option_2 >= 1 && symbol->option_2 <= 11) { | |
| 1316 cols_per_row = symbol->option_2; | |
| 1317 if (cc_rows && (cols_per_row == 1)) { | |
| 1318 /* "There shall be a minimum of four symbol characters in the | |
| 1319 first row of an RSS Expanded Stacked symbol when it is the linear | |
| 1320 component of an EAN.UCC Composite symbol." */ | |
| 1321 cols_per_row = 2; | |
| 1322 } | |
| 1323 } else if (symbol->option_3 >= 2 && symbol->option_3 <= 11) { | |
| 1324 max_rows = symbol->option_3; | |
| 1325 } | |
| 1326 } | |
| 1327 | |
| 1328 error_number = dbar_exp_binary_string(symbol, reduced, binary_string, &cols_per_row, max_rows, &bp); | |
| 1329 if (error_number != 0) { | |
| 1330 return error_number; | |
| 1331 } | |
| 1332 | |
| 1333 data_chars = bp / 12; | |
| 1334 | |
| 1335 if (debug_print) fputs("Data:", stdout); | |
| 1336 for (i = 0; i < data_chars; i++) { | |
| 1337 k = i * 12; | |
| 1338 vs = 0; | |
| 1339 for (j = 0; j < 12; j++) { | |
| 1340 if (binary_string[k + j] == '1') { | |
| 1341 vs |= (0x800 >> j); | |
| 1342 } | |
| 1343 } | |
| 1344 | |
| 1345 if (vs <= 347) { | |
| 1346 group = 1; | |
| 1347 } else if (vs <= 1387) { | |
| 1348 group = 2; | |
| 1349 } else if (vs <= 2947) { | |
| 1350 group = 3; | |
| 1351 } else if (vs <= 3987) { | |
| 1352 group = 4; | |
| 1353 } else { | |
| 1354 group = 5; | |
| 1355 } | |
| 1356 v_odd = (vs - dbar_exp_g_sum[group - 1]) / dbar_exp_t_even[group - 1]; | |
| 1357 v_even = (vs - dbar_exp_g_sum[group - 1]) % dbar_exp_t_even[group - 1]; | |
| 1358 if (debug_print) printf("%s%d", i == 0 || (i & 1) ? " " : ",", vs); | |
| 1359 | |
| 1360 getRSSwidths(widths, v_odd, dbar_exp_modules_odd[group - 1], 4, dbar_exp_widest_odd[group - 1], 0); | |
| 1361 char_widths[i][0] = widths[0]; | |
| 1362 char_widths[i][2] = widths[1]; | |
| 1363 char_widths[i][4] = widths[2]; | |
| 1364 char_widths[i][6] = widths[3]; | |
| 1365 getRSSwidths(widths, v_even, dbar_exp_modules_even[group - 1], 4, dbar_exp_widest_even[group - 1], 1); | |
| 1366 char_widths[i][1] = widths[0]; | |
| 1367 char_widths[i][3] = widths[1]; | |
| 1368 char_widths[i][5] = widths[2]; | |
| 1369 char_widths[i][7] = widths[3]; | |
| 1370 } | |
| 1371 if (debug_print) fputc('\n', stdout); | |
| 1372 | |
| 1373 /* 7.2.6 Check character */ | |
| 1374 /* The checksum value is equal to the mod 211 residue of the weighted sum of the widths of the | |
| 1375 elements in the data characters. */ | |
| 1376 checksum = 0; | |
| 1377 for (i = 0; i < data_chars; i++) { | |
| 1378 int row = dbar_exp_weight_rows[(((data_chars - 2) / 2) * 21) + i]; | |
| 1379 for (j = 0; j < 8; j++) { | |
| 1380 checksum += (char_widths[i][j] * dbar_exp_checksum_weight[(row * 8) + j]); | |
| 1381 | |
| 1382 } | |
| 1383 } | |
| 1384 | |
| 1385 check_char = (211 * ((data_chars + 1) - 4)) + (checksum % 211); | |
| 1386 | |
| 1387 if (debug_print) { | |
| 1388 printf("Data chars: %d, Check char: %d\n", data_chars, check_char); | |
| 1389 } | |
| 1390 | |
| 1391 if (check_char <= 347) { | |
| 1392 c_group = 1; | |
| 1393 } else if (check_char <= 1387) { | |
| 1394 c_group = 2; | |
| 1395 } else if (check_char <= 2947) { | |
| 1396 c_group = 3; | |
| 1397 } else if (check_char <= 3987) { | |
| 1398 c_group = 4; | |
| 1399 } else { | |
| 1400 c_group = 5; | |
| 1401 } | |
| 1402 | |
| 1403 c_odd = (check_char - dbar_exp_g_sum[c_group - 1]) / dbar_exp_t_even[c_group - 1]; | |
| 1404 c_even = (check_char - dbar_exp_g_sum[c_group - 1]) % dbar_exp_t_even[c_group - 1]; | |
| 1405 | |
| 1406 getRSSwidths(widths, c_odd, dbar_exp_modules_odd[c_group - 1], 4, dbar_exp_widest_odd[c_group - 1], 0); | |
| 1407 check_widths[0] = widths[0]; | |
| 1408 check_widths[2] = widths[1]; | |
| 1409 check_widths[4] = widths[2]; | |
| 1410 check_widths[6] = widths[3]; | |
| 1411 getRSSwidths(widths, c_even, dbar_exp_modules_even[c_group - 1], 4, dbar_exp_widest_even[c_group - 1], 1); | |
| 1412 check_widths[1] = widths[0]; | |
| 1413 check_widths[3] = widths[1]; | |
| 1414 check_widths[5] = widths[2]; | |
| 1415 check_widths[7] = widths[3]; | |
| 1416 | |
| 1417 /* Initialise element array */ | |
| 1418 codeblocks = (data_chars + 1) / 2 + ((data_chars + 1) & 1); | |
| 1419 pattern_width = (codeblocks * 5) + ((data_chars + 1) * 8) + 4; | |
| 1420 memset(elements, 0, sizeof(int) * pattern_width); | |
| 1421 | |
| 1422 /* Put finder patterns in element array */ | |
| 1423 p = (((((data_chars + 1) - 2) / 2) + ((data_chars + 1) & 1)) - 1) * 11; | |
| 1424 for (i = 0; i < codeblocks; i++) { | |
| 1425 k = p + i; | |
| 1426 for (j = 0; j < 5; j++) { | |
| 1427 elements[(21 * i) + j + 10] = dbar_exp_finder_pattern[((dbar_exp_finder_sequence[k] - 1) * 5) + j]; | |
| 1428 } | |
| 1429 } | |
| 1430 | |
| 1431 /* Put check character in element array */ | |
| 1432 for (i = 0; i < 8; i++) { | |
| 1433 elements[i + 2] = check_widths[i]; | |
| 1434 } | |
| 1435 | |
| 1436 /* Put forward reading data characters in element array */ | |
| 1437 for (i = 1; i < data_chars; i += 2) { | |
| 1438 k = (((i - 1) / 2) * 21) + 23; | |
| 1439 for (j = 0; j < 8; j++) { | |
| 1440 elements[k + j] = char_widths[i][j]; | |
| 1441 } | |
| 1442 } | |
| 1443 | |
| 1444 /* Put reversed data characters in element array */ | |
| 1445 for (i = 0; i < data_chars; i += 2) { | |
| 1446 k = ((i / 2) * 21) + 15; | |
| 1447 for (j = 0; j < 8; j++) { | |
| 1448 elements[k + j] = char_widths[i][7 - j]; | |
| 1449 } | |
| 1450 } | |
| 1451 | |
| 1452 if ((symbol->symbology == BARCODE_DBAR_EXP) || (symbol->symbology == BARCODE_DBAR_EXP_CC)) { | |
| 1453 /* Copy elements into symbol */ | |
| 1454 | |
| 1455 elements[0] = 1; /* Left guard */ | |
| 1456 elements[1] = 1; | |
| 1457 | |
| 1458 elements[pattern_width - 2] = 1; /* Right guard */ | |
| 1459 elements[pattern_width - 1] = 1; | |
| 1460 | |
| 1461 writer = 0; | |
| 1462 latch = 0; | |
| 1463 for (i = 0; i < pattern_width; i++) { | |
| 1464 writer = dbar_expand(symbol, writer, &latch, elements[i]); | |
| 1465 } | |
| 1466 if (symbol->width < writer) { | |
| 1467 symbol->width = writer; | |
| 1468 } | |
| 1469 symbol->rows = symbol->rows + 1; | |
| 1470 | |
| 1471 dbar_exp_hrt(symbol, source, length); | |
| 1472 | |
| 1473 } else { | |
| 1474 int current_row, current_block, left_to_right; | |
| 1475 int v2_latch = 0; | |
| 1476 /* RSS Expanded Stacked */ | |
| 1477 | |
| 1478 /* Bug corrected: Character missing for message | |
| 1479 * [01]90614141999996[10]1234222222222221 | |
| 1480 * Patch by Daniel Frede | |
| 1481 */ | |
| 1482 | |
| 1483 stack_rows = codeblocks / cols_per_row; | |
| 1484 if (codeblocks % cols_per_row > 0) { | |
| 1485 stack_rows++; | |
| 1486 } | |
| 1487 | |
| 1488 current_block = 0; | |
| 1489 for (current_row = 1; current_row <= stack_rows; current_row++) { | |
| 1490 int special_case_row = 0; | |
| 1491 int elements_in_sub; | |
| 1492 int sub_elements[235] = {0}; | |
| 1493 int num_columns; | |
| 1494 | |
| 1495 /* Number of columns in current row */ | |
| 1496 if (current_row * cols_per_row > codeblocks) { | |
| 1497 num_columns = codeblocks - current_block; | |
| 1498 } else { | |
| 1499 num_columns = cols_per_row; | |
| 1500 } | |
| 1501 | |
| 1502 /* Row Start */ | |
| 1503 sub_elements[0] = 1; /* Left guard */ | |
| 1504 sub_elements[1] = 1; | |
| 1505 elements_in_sub = 2; | |
| 1506 | |
| 1507 /* If last row and is partial and even-numbered, and have even columns (segment pairs), | |
| 1508 and odd number of finders (== odd number of columns) */ | |
| 1509 if ((current_row == stack_rows) && (num_columns != cols_per_row) && !(current_row & 1) | |
| 1510 && !(cols_per_row & 1) && (num_columns & 1)) { | |
| 1511 /* Special case bottom row */ | |
| 1512 special_case_row = 1; | |
| 1513 sub_elements[0] = 2; /* Extra space (latch set below) */ | |
| 1514 } | |
| 1515 | |
| 1516 /* If odd number of columns or current row odd-numbered or special case last row then left-to-right, | |
| 1517 else right-to-left */ | |
| 1518 if ((cols_per_row & 1) || (current_row & 1) || special_case_row) { | |
| 1519 left_to_right = 1; | |
| 1520 } else { | |
| 1521 left_to_right = 0; | |
| 1522 } | |
| 1523 | |
| 1524 if (debug_print) { | |
| 1525 if (current_row == stack_rows) { | |
| 1526 printf("Last row: number of columns: %d / %d, left to right: %d, special case: %d\n", | |
| 1527 num_columns, cols_per_row, left_to_right, special_case_row); | |
| 1528 } | |
| 1529 } | |
| 1530 | |
| 1531 /* Row Data */ | |
| 1532 reader = 0; | |
| 1533 do { | |
| 1534 i = 2 + (current_block * 21); | |
| 1535 for (j = 0; j < 21; j++) { | |
| 1536 if ((i + j) < pattern_width) { | |
| 1537 if (left_to_right) { | |
| 1538 sub_elements[j + (reader * 21) + 2] = elements[i + j]; | |
| 1539 } else { | |
| 1540 sub_elements[(20 - j) + (num_columns - 1 - reader) * 21 + 2] = elements[i + j]; | |
| 1541 } | |
| 1542 } | |
| 1543 elements_in_sub++; | |
| 1544 } | |
| 1545 reader++; | |
| 1546 current_block++; | |
| 1547 } while ((reader < cols_per_row) && (current_block < codeblocks)); | |
| 1548 | |
| 1549 /* Row Stop */ | |
| 1550 sub_elements[elements_in_sub] = 1; /* Right guard */ | |
| 1551 sub_elements[elements_in_sub + 1] = 1; | |
| 1552 elements_in_sub += 2; | |
| 1553 | |
| 1554 latch = (current_row & 1) || special_case_row ? 0 : 1; | |
| 1555 | |
| 1556 writer = 0; | |
| 1557 for (i = 0; i < elements_in_sub; i++) { | |
| 1558 writer = dbar_expand(symbol, writer, &latch, sub_elements[i]); | |
| 1559 } | |
| 1560 if (symbol->width < writer) { | |
| 1561 symbol->width = writer; | |
| 1562 } | |
| 1563 | |
| 1564 if (current_row != 1) { | |
| 1565 int odd_last_row = (current_row == stack_rows) && (data_chars % 2 == 0); | |
| 1566 | |
| 1567 /* Middle separator pattern (above current row) */ | |
| 1568 for (j = 5; j < (49 * cols_per_row); j += 2) { | |
| 1569 set_module(symbol, symbol->rows - 2, j); | |
| 1570 } | |
| 1571 symbol->row_height[symbol->rows - 2] = 1; | |
| 1572 | |
| 1573 /* Bottom separator pattern (above current row) */ | |
| 1574 dbar_exp_separator(symbol, writer, reader, symbol->rows - 1, 1 /*above*/, special_case_row, | |
| 1575 left_to_right, odd_last_row, &v2_latch); | |
| 1576 symbol->row_height[symbol->rows - 1] = 1; | |
| 1577 } | |
| 1578 | |
| 1579 if (current_row != stack_rows) { | |
| 1580 /* Top separator pattern (below current row) */ | |
| 1581 dbar_exp_separator(symbol, writer, reader, symbol->rows + 1, -1 /*below*/, 0 /*special_case_row*/, | |
| 1582 left_to_right, 0 /*odd_last_row*/, &v2_latch); | |
| 1583 symbol->row_height[symbol->rows + 1] = 1; | |
| 1584 } | |
| 1585 | |
| 1586 symbol->rows = symbol->rows + 4; | |
| 1587 } | |
| 1588 symbol->rows = symbol->rows - 3; | |
| 1589 } | |
| 1590 | |
| 1591 if (symbol->symbology == BARCODE_DBAR_EXP_CC || symbol->symbology == BARCODE_DBAR_EXPSTK_CC) { | |
| 1592 /* Composite separator */ | |
| 1593 dbar_exp_separator(symbol, symbol->width, 4, separator_row, 1 /*above*/, 0 /*special_case_row*/, | |
| 1594 1 /*left_to_right*/, 0 /*odd_last_row*/, NULL); | |
| 1595 } | |
| 1596 | |
| 1597 /* DataBar Expanded ISO/IEC 24724:2011 7.2.1 and DataBar Expanded Stacked ISO/IEC 24724:2011 7.2.8 | |
| 1598 34X min per row */ | |
| 1599 if (symbol->symbology == BARCODE_DBAR_EXP_CC || symbol->symbology == BARCODE_DBAR_EXPSTK_CC) { | |
| 1600 symbol->height = symbol->height ? 34.0f : 34.0f * stack_rows; /* Pass back min row or default height */ | |
| 1601 } else { | |
| 1602 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 1603 if (warn_number == 0) { | |
| 1604 warn_number = set_height(symbol, 34.0f, 34.0f * stack_rows, 0.0f, 0 /*no_errtxt*/); | |
| 1605 } else { | |
| 1606 (void) set_height(symbol, 34.0f, 34.0f * stack_rows, 0.0f, 1 /*no_errtxt*/); | |
| 1607 } | |
| 1608 } else { | |
| 1609 (void) set_height(symbol, 0.0f, 34.0f * stack_rows, 0.0f, 1 /*no_errtxt*/); | |
| 1610 } | |
| 1611 } | |
| 1612 | |
| 1613 return warn_number; | |
| 1614 } | |
| 1615 | |
| 1616 /* GS1 DataBar Expanded */ | |
| 1617 INTERNAL int dbar_exp(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 1618 return dbar_exp_cc(symbol, source, length, 0 /*cc_rows*/); | |
| 1619 } | |
| 1620 | |
| 1621 /* vim: set ts=4 sw=4 et : */ |
