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 : */