comparison mupdf-source/thirdparty/zint/backend/hanxin.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 /* hanxin.c - Han Xin Code */
2 /*
3 libzint - the open source barcode library
4 Copyright (C) 2009-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 /* This code attempts to implement Han Xin Code according to ISO/IEC 20830:2021
34 * (previously ISO/IEC 20830 (draft 2019-10-10) and AIMD-015:2010 (Rev 0.8)) */
35
36 #include <assert.h>
37 #include <stdio.h>
38 #include "common.h"
39 #include "reedsol.h"
40 #include "hanxin.h"
41 #include "eci.h"
42
43 /* Find which submode to use for a text character */
44 static int hx_getsubmode(const unsigned int input) {
45
46 if (z_isdigit(input)) {
47 return 1;
48 }
49
50 if (z_isupper(input)) {
51 return 1;
52 }
53
54 if (z_islower(input)) {
55 return 1;
56 }
57
58 return 2;
59 }
60
61 /* Return length of terminator for encoding mode */
62 static int hx_terminator_length(const char mode) {
63 int result = 0;
64
65 switch (mode) {
66 case 'n':
67 result = 10;
68 break;
69 case 't':
70 result = 6;
71 break;
72 case '1':
73 case '2':
74 result = 12;
75 break;
76 case 'd':
77 result = 15;
78 break;
79 }
80
81 return result;
82 }
83
84 /* Calculate the length of the binary string */
85 static int hx_calc_binlen(const char mode[], const unsigned int ddata[], const int length, const int eci) {
86 int i;
87 char lastmode = '\0';
88 int est_binlen = 0;
89 int submode = 1;
90 int numeric_run = 0;
91
92 if (eci != 0) {
93 est_binlen += 4;
94 if (eci <= 127) {
95 est_binlen += 8;
96 } else if (eci <= 16383) {
97 est_binlen += 16;
98 } else {
99 est_binlen += 24;
100 }
101 }
102
103 i = 0;
104 do {
105 if (mode[i] != lastmode) {
106 if (i > 0) {
107 est_binlen += hx_terminator_length(lastmode);
108 }
109 /* GB 4-byte has indicator for each character (and no terminator) so not included here */
110 /* Region1/Region2 have special terminator to go directly into each other's mode so not included here */
111 if (mode[i] != 'f' || ((mode[i] == '1' && lastmode == '2') || (mode[i] == '2' && lastmode == '1'))) {
112 est_binlen += 4;
113 }
114 if (mode[i] == 'b') { /* Byte mode has byte count (and no terminator) */
115 est_binlen += 13;
116 }
117 lastmode = mode[i];
118 submode = 1;
119 numeric_run = 0;
120 }
121 switch (mode[i]) {
122 case 'n':
123 if (numeric_run % 3 == 0) {
124 est_binlen += 10;
125 }
126 numeric_run++;
127 break;
128 case 't':
129 if (hx_getsubmode(ddata[i]) != submode) {
130 est_binlen += 6;
131 submode = hx_getsubmode(ddata[i]);
132 }
133 est_binlen += 6;
134 break;
135 case 'b':
136 est_binlen += ddata[i] > 0xFF ? 16 : 8;
137 break;
138 case '1':
139 case '2':
140 est_binlen += 12;
141 break;
142 case 'd':
143 est_binlen += 15;
144 break;
145 case 'f':
146 est_binlen += 25;
147 i++;
148 break;
149 }
150 i++;
151 } while (i < length);
152
153 est_binlen += hx_terminator_length(lastmode);
154
155 return est_binlen;
156 }
157
158 /* Call `hx_calc_binlen()` for each segment */
159 static int hx_calc_binlen_segs(const char mode[], const unsigned int ddata[], const struct zint_seg segs[],
160 const int seg_count) {
161 int i;
162 int count = 0;
163 const unsigned int *dd = ddata;
164 const char *m = mode;
165
166 for (i = 0; i < seg_count; i++) {
167 count += hx_calc_binlen(m, dd, segs[i].length, segs[i].eci);
168 m += segs[i].length;
169 dd += segs[i].length;
170 }
171
172 return count;
173 }
174
175 static int hx_isRegion1(const unsigned int glyph) {
176 unsigned int byte;
177
178 byte = glyph >> 8;
179
180 if ((byte >= 0xb0) && (byte <= 0xd7)) {
181 byte = glyph & 0xff;
182 if ((byte >= 0xa1) && (byte <= 0xfe)) {
183 return 1;
184 }
185 } else if ((byte >= 0xa1) && (byte <= 0xa3)) {
186 byte = glyph & 0xff;
187 if ((byte >= 0xa1) && (byte <= 0xfe)) {
188 return 1;
189 }
190 } else if ((glyph >= 0xa8a1) && (glyph <= 0xa8c0)) {
191 return 1;
192 }
193
194 return 0;
195 }
196
197 static int hx_isRegion2(const unsigned int glyph) {
198 unsigned int byte;
199
200 byte = glyph >> 8;
201
202 if ((byte >= 0xd8) && (byte <= 0xf7)) {
203 byte = glyph & 0xff;
204 if ((byte >= 0xa1) && (byte <= 0xfe)) {
205 return 1;
206 }
207 }
208
209 return 0;
210 }
211
212 static int hx_isDoubleByte(const unsigned int glyph) {
213 unsigned int byte;
214
215 byte = glyph >> 8;
216
217 if ((byte >= 0x81) && (byte <= 0xfe)) {
218 byte = glyph & 0xff;
219 if ((byte >= 0x40) && (byte <= 0x7e)) {
220 return 1;
221 }
222 if ((byte >= 0x80) && (byte <= 0xfe)) {
223 return 1;
224 }
225 }
226
227 return 0;
228 }
229
230 static int hx_isFourByte(const unsigned int glyph, const unsigned int glyph2) {
231 unsigned int byte;
232
233 byte = glyph >> 8;
234
235 if ((byte >= 0x81) && (byte <= 0xfe)) {
236 byte = glyph & 0xff;
237 if ((byte >= 0x30) && (byte <= 0x39)) {
238 byte = glyph2 >> 8;
239 if ((byte >= 0x81) && (byte <= 0xfe)) {
240 byte = glyph2 & 0xff;
241 if ((byte >= 0x30) && (byte <= 0x39)) {
242 return 1;
243 }
244 }
245 }
246 }
247
248 return 0;
249 }
250
251 /* Convert Text 1 sub-mode character to encoding value, as given in table 3 */
252 static int hx_lookup_text1(const unsigned int input) {
253
254 if (z_isdigit(input)) {
255 return input - '0';
256 }
257
258 if (z_isupper(input)) {
259 return input - 'A' + 10;
260 }
261
262 if (z_islower(input)) {
263 return input - 'a' + 36;
264 }
265
266 return -1;
267 }
268
269 /* Convert Text 2 sub-mode character to encoding value, as given in table 4 */
270 static int hx_lookup_text2(const unsigned int input) {
271
272 if (input <= 27) {
273 return input;
274 }
275
276 if ((input >= ' ') && (input <= '/')) {
277 return input - ' ' + 28;
278 }
279
280 if ((input >= ':') && (input <= '@')) {
281 return input - ':' + 44;
282 }
283
284 if ((input >= '[') && (input <= 96)) {
285 return input - '[' + 51;
286 }
287
288 if ((input >= '{') && (input <= 127)) {
289 return input - '{' + 57;
290 }
291
292 return -1;
293 }
294
295 /* hx_define_mode() stuff */
296
297 /* Bits multiplied by this for costs, so as to be whole integer divisible by 2 and 3 */
298 #define HX_MULT 6
299
300 /* Whether in numeric or not. If in numeric, *p_end is set to position after numeric,
301 * and *p_cost is set to per-numeric cost */
302 static int hx_in_numeric(const unsigned int ddata[], const int length, const int in_posn,
303 unsigned int *p_end, unsigned int *p_cost) {
304 int i, digit_cnt;
305
306 if (in_posn < (int) *p_end) {
307 return 1;
308 }
309
310 /* Attempt to calculate the average 'cost' of using numeric mode in number of bits (times HX_MULT) */
311 for (i = in_posn; i < length && i < in_posn + 3 && z_isdigit(ddata[i]); i++);
312
313 digit_cnt = i - in_posn;
314
315 if (digit_cnt == 0) {
316 *p_end = 0;
317 return 0;
318 }
319 *p_end = i;
320 *p_cost = digit_cnt == 1
321 ? 60 /* 10 * HX_MULT */ : digit_cnt == 2 ? 30 /* (10 / 2) * HX_MULT */ : 20 /* (10 / 3) * HX_MULT */;
322 return 1;
323 }
324
325 /* Whether in four-byte or not. If in four-byte, *p_fourbyte is set to position after four-byte,
326 * and *p_fourbyte_cost is set to per-position cost */
327 static int hx_in_fourbyte(const unsigned int ddata[], const int length, const int in_posn,
328 unsigned int *p_end, unsigned int *p_cost) {
329 if (in_posn < (int) *p_end) {
330 return 1;
331 }
332
333 if (in_posn == length - 1 || !hx_isFourByte(ddata[in_posn], ddata[in_posn + 1])) {
334 *p_end = 0;
335 return 0;
336 }
337 *p_end = in_posn + 2;
338 *p_cost = 75; /* ((4 + 21) / 2) * HX_MULT */
339 return 1;
340 }
341
342 /* Indexes into mode_types array */
343 #define HX_N 0 /* Numeric */
344 #define HX_T 1 /* Text */
345 #define HX_B 2 /* Binary */
346 #define HX_1 3 /* Common Chinese Region One */
347 #define HX_2 4 /* Common Chinese Region Two */
348 #define HX_D 5 /* GB 18030 2-byte Region */
349 #define HX_F 6 /* GB 18030 4-byte Region */
350 /* Note Unicode, GS1 and URI modes not implemented */
351
352 #define HX_NUM_MODES 7
353
354 /* Calculate optimized encoding modes. Adapted from Project Nayuki */
355 /* Copyright (c) Project Nayuki. (MIT License) See qr.c for detailed notice */
356 static void hx_define_mode(char *mode, const unsigned int ddata[], const int length, const int debug_print) {
357 /* Must be in same order as HX_N etc */
358 static const char mode_types[] = { 'n', 't', 'b', '1', '2', 'd', 'f', '\0' };
359
360 /* Initial mode costs */
361 static const unsigned int head_costs[HX_NUM_MODES] = {
362 /* N T B 1 2 D F */
363 4 * HX_MULT, 4 * HX_MULT, (4 + 13) * HX_MULT, 4 * HX_MULT, 4 * HX_MULT, 4 * HX_MULT, 0
364 };
365
366 /* Cost of switching modes from k to j */
367 static const unsigned char switch_costs[HX_NUM_MODES][HX_NUM_MODES] = {
368 /* N T B 1 2 D F */
369 /*N*/ { 0, (10 + 4) * HX_MULT, (10 + 4 + 13) * HX_MULT, (10 + 4) * HX_MULT, (10 + 4) * HX_MULT, (10 + 4) * HX_MULT, 10 * HX_MULT },
370 /*T*/ { (6 + 4) * HX_MULT, 0, (6 + 4 + 13) * HX_MULT, (6 + 4) * HX_MULT, (6 + 4) * HX_MULT, (6 + 4) * HX_MULT, 6 * HX_MULT },
371 /*B*/ { 4 * HX_MULT, 4 * HX_MULT, 0, 4 * HX_MULT, 4 * HX_MULT, 4 * HX_MULT, 0 },
372 /*1*/ { (12 + 4) * HX_MULT, (12 + 4) * HX_MULT, (12 + 4 + 13) * HX_MULT, 0, 12 * HX_MULT, (12 + 4) * HX_MULT, 12 * HX_MULT },
373 /*2*/ { (12 + 4) * HX_MULT, (12 + 4) * HX_MULT, (12 + 4 + 13) * HX_MULT, 12 * HX_MULT, 0, (12 + 4) * HX_MULT, 12 * HX_MULT },
374 /*D*/ { (15 + 4) * HX_MULT, (15 + 4) * HX_MULT, (15 + 4 + 13) * HX_MULT, (15 + 4) * HX_MULT, (15 + 4) * HX_MULT, 0, 15 * HX_MULT },
375 /*F*/ { 4 * HX_MULT, 4 * HX_MULT, (4 + 13) * HX_MULT, 4 * HX_MULT, 4 * HX_MULT, 4 * HX_MULT, 0 },
376 };
377
378 /* Final end-of-data costs */
379 static const unsigned char eod_costs[HX_NUM_MODES] = {
380 /* N T B 1 2 D F */
381 10 * HX_MULT, 6 * HX_MULT, 0, 12 * HX_MULT, 12 * HX_MULT, 15 * HX_MULT, 0
382 };
383
384 unsigned int numeric_end = 0, numeric_cost = 0, text_submode = 1, fourbyte_end = 0, fourbyte_cost = 0; /* State */
385 int text1, text2;
386
387 int i, j, k;
388 unsigned int min_cost;
389 char cur_mode;
390 unsigned int prev_costs[HX_NUM_MODES];
391 unsigned int cur_costs[HX_NUM_MODES];
392 char (*char_modes)[HX_NUM_MODES] = (char (*)[HX_NUM_MODES]) z_alloca(HX_NUM_MODES * length);
393
394 /* char_modes[i][j] represents the mode to encode the code point at index i such that the final segment
395 ends in mode_types[j] and the total number of bits is minimized over all possible choices */
396 memset(char_modes, 0, HX_NUM_MODES * length);
397
398 /* At the beginning of each iteration of the loop below, prev_costs[j] is the minimum number of 1/6 (1/XX_MULT)
399 * bits needed to encode the entire string prefix of length i, and end in mode_types[j] */
400 memcpy(prev_costs, head_costs, HX_NUM_MODES * sizeof(unsigned int));
401
402 /* Calculate costs using dynamic programming */
403 for (i = 0; i < length; i++) {
404 memset(cur_costs, 0, HX_NUM_MODES * sizeof(unsigned int));
405
406 if (hx_in_numeric(ddata, length, i, &numeric_end, &numeric_cost)) {
407 cur_costs[HX_N] = prev_costs[HX_N] + numeric_cost;
408 char_modes[i][HX_N] = 'n';
409 text1 = 1;
410 text2 = 0;
411 } else {
412 text1 = hx_lookup_text1(ddata[i]) != -1;
413 text2 = hx_lookup_text2(ddata[i]) != -1;
414 }
415
416 if (text1 || text2) {
417 if ((text_submode == 1 && text2) || (text_submode == 2 && text1)) {
418 cur_costs[HX_T] = prev_costs[HX_T] + 72; /* (6 + 6) * HX_MULT */
419 text_submode = text2 ? 2 : 1;
420 } else {
421 cur_costs[HX_T] = prev_costs[HX_T] + 36; /* 6 * HX_MULT */
422 }
423 char_modes[i][HX_T] = 't';
424 } else {
425 text_submode = 1;
426 }
427
428 /* Binary mode can encode anything */
429 cur_costs[HX_B] = prev_costs[HX_B] + (ddata[i] > 0xFF ? 96 : 48); /* (16 : 8) * HX_MULT */
430 char_modes[i][HX_B] = 'b';
431
432 if (hx_in_fourbyte(ddata, length, i, &fourbyte_end, &fourbyte_cost)) {
433 cur_costs[HX_F] = prev_costs[HX_F] + fourbyte_cost;
434 char_modes[i][HX_F] = 'f';
435 } else {
436 if (hx_isDoubleByte(ddata[i])) {
437 cur_costs[HX_D] = prev_costs[HX_D] + 90; /* 15 * HX_MULT */
438 char_modes[i][HX_D] = 'd';
439 if (hx_isRegion1(ddata[i])) { /* Subset */
440 cur_costs[HX_1] = prev_costs[HX_1] + 72; /* 12 * HX_MULT */
441 char_modes[i][HX_1] = '1';
442 } else if (hx_isRegion2(ddata[i])) { /* Subset */
443 cur_costs[HX_2] = prev_costs[HX_2] + 72; /* 12 * HX_MULT */
444 char_modes[i][HX_2] = '2';
445 }
446 }
447 }
448
449 if (i == length - 1) { /* Add end of data costs if last character */
450 for (j = 0; j < HX_NUM_MODES; j++) {
451 if (char_modes[i][j]) {
452 cur_costs[j] += eod_costs[j];
453 }
454 }
455 }
456
457 /* Start new segment at the end to switch modes */
458 for (j = 0; j < HX_NUM_MODES; j++) { /* To mode */
459 for (k = 0; k < HX_NUM_MODES; k++) { /* From mode */
460 if (j != k && char_modes[i][k]) {
461 const unsigned int new_cost = cur_costs[k] + switch_costs[k][j];
462 if (!char_modes[i][j] || new_cost < cur_costs[j]) {
463 cur_costs[j] = new_cost;
464 char_modes[i][j] = mode_types[k];
465 }
466 }
467 }
468 }
469
470 memcpy(prev_costs, cur_costs, HX_NUM_MODES * sizeof(unsigned int));
471 }
472
473 /* Find optimal ending mode */
474 min_cost = prev_costs[0];
475 cur_mode = mode_types[0];
476 for (i = 1; i < HX_NUM_MODES; i++) {
477 if (prev_costs[i] < min_cost) {
478 min_cost = prev_costs[i];
479 cur_mode = mode_types[i];
480 }
481 }
482
483 /* Get optimal mode for each code point by tracing backwards */
484 for (i = length - 1; i >= 0; i--) {
485 j = posn(mode_types, cur_mode);
486 cur_mode = char_modes[i][j];
487 mode[i] = cur_mode;
488 }
489
490 if (debug_print) {
491 printf(" Mode: %.*s\n", length, mode);
492 }
493 }
494
495 /* Call `hx_define_mode()` for each segment */
496 static void hx_define_mode_segs(char mode[], const unsigned int ddata[], const struct zint_seg segs[],
497 const int seg_count, const int debug_print) {
498 int i;
499 const unsigned int *dd = ddata;
500 char *m = mode;
501
502 for (i = 0; i < seg_count; i++) {
503 hx_define_mode(m, dd, segs[i].length, debug_print);
504 m += segs[i].length;
505 dd += segs[i].length;
506 }
507 }
508
509 /* Convert input data to binary stream */
510 static void hx_calculate_binary(char binary[], const char mode[], const unsigned int ddata[], const int length,
511 const int eci, int *p_bp, const int debug_print) {
512 int position = 0;
513 int i, count, encoding_value;
514 int first_byte, second_byte;
515 int third_byte, fourth_byte;
516 int glyph;
517 int submode;
518 int bp = *p_bp;
519
520 if (eci != 0) {
521 /* Encoding ECI assignment number, according to Table 5 */
522 bp = bin_append_posn(8, 4, binary, bp); /* ECI */
523 if (eci <= 127) {
524 bp = bin_append_posn(eci, 8, binary, bp);
525 } else if (eci <= 16383) {
526 bp = bin_append_posn(2, 2, binary, bp);
527 bp = bin_append_posn(eci, 14, binary, bp);
528 } else {
529 bp = bin_append_posn(6, 3, binary, bp);
530 bp = bin_append_posn(eci, 21, binary, bp);
531 }
532 }
533
534 do {
535 int block_length = 0;
536 int double_byte = 0;
537 do {
538 if (mode[position] == 'b' && ddata[position + block_length] > 0xFF) {
539 double_byte++;
540 }
541 block_length++;
542 } while (position + block_length < length && mode[position + block_length] == mode[position]);
543
544 switch (mode[position]) {
545 case 'n':
546 /* Numeric mode */
547 /* Mode indicator */
548 bp = bin_append_posn(1, 4, binary, bp);
549
550 if (debug_print) {
551 printf("Numeric (N%d): ", block_length);
552 }
553
554 count = 0; /* Suppress gcc -Wmaybe-uninitialized */
555 i = 0;
556
557 while (i < block_length) {
558 const int first = ctoi((const char) ddata[position + i]);
559 count = 1;
560 encoding_value = first;
561
562 if (i + 1 < block_length && mode[position + i + 1] == 'n') {
563 const int second = ctoi((const char) ddata[position + i + 1]);
564 count = 2;
565 encoding_value = (encoding_value * 10) + second;
566
567 if (i + 2 < block_length && mode[position + i + 2] == 'n') {
568 const int third = ctoi((const char) ddata[position + i + 2]);
569 count = 3;
570 encoding_value = (encoding_value * 10) + third;
571 }
572 }
573
574 bp = bin_append_posn(encoding_value, 10, binary, bp);
575
576 if (debug_print) {
577 printf(" 0x%3x(%d)", encoding_value, encoding_value);
578 }
579
580 i += count;
581 }
582
583 /* Mode terminator depends on number of characters in last group (Table 2) */
584 switch (count) {
585 case 1:
586 bp = bin_append_posn(1021, 10, binary, bp);
587 break;
588 case 2:
589 bp = bin_append_posn(1022, 10, binary, bp);
590 break;
591 case 3:
592 bp = bin_append_posn(1023, 10, binary, bp);
593 break;
594 }
595
596 if (debug_print) {
597 printf(" (TERM %d)\n", count);
598 }
599
600 break;
601 case 't':
602 /* Text mode */
603 /* Mode indicator */
604 bp = bin_append_posn(2, 4, binary, bp);
605
606 if (debug_print) {
607 printf("Text (T%d):", block_length);
608 }
609
610 submode = 1;
611
612 i = 0;
613
614 while (i < block_length) {
615
616 if (hx_getsubmode(ddata[i + position]) != submode) {
617 /* Change submode */
618 bp = bin_append_posn(62, 6, binary, bp);
619 submode = hx_getsubmode(ddata[i + position]);
620 if (debug_print) {
621 fputs(" SWITCH", stdout);
622 }
623 }
624
625 if (submode == 1) {
626 encoding_value = hx_lookup_text1(ddata[i + position]);
627 } else {
628 encoding_value = hx_lookup_text2(ddata[i + position]);
629 }
630
631 bp = bin_append_posn(encoding_value, 6, binary, bp);
632
633 if (debug_print) {
634 printf(" %.2x[ASC %.2x]", encoding_value, ddata[i + position]);
635 }
636 i++;
637 }
638
639 /* Terminator */
640 bp = bin_append_posn(63, 6, binary, bp);
641
642 if (debug_print) {
643 fputs("\n", stdout);
644 }
645 break;
646 case 'b':
647 /* Binary Mode */
648 /* Mode indicator */
649 bp = bin_append_posn(3, 4, binary, bp);
650
651 /* Count indicator */
652 bp = bin_append_posn(block_length + double_byte, 13, binary, bp);
653
654 if (debug_print) {
655 printf("Binary Mode (B%d):", block_length + double_byte);
656 }
657
658 i = 0;
659
660 while (i < block_length) {
661
662 /* 8-bit bytes with no conversion */
663 bp = bin_append_posn(ddata[i + position], ddata[i + position] > 0xFF ? 16 : 8, binary, bp);
664
665 if (debug_print) {
666 printf(" %02x", (int) ddata[i + position]);
667 }
668
669 i++;
670 }
671
672 if (debug_print) {
673 fputs("\n", stdout);
674 }
675 break;
676 case '1':
677 /* Region One encoding */
678 /* Mode indicator */
679 if (position == 0 || mode[position - 1] != '2') { /* Unless previous mode Region Two */
680 bp = bin_append_posn(4, 4, binary, bp);
681 }
682
683 if (debug_print) {
684 printf("Region One%s H(1)%d:",
685 position == 0 || mode[position - 1] != '2' ? "" : " (NO indicator)", block_length);
686 }
687
688 i = 0;
689
690 while (i < block_length) {
691 first_byte = (ddata[i + position] & 0xff00) >> 8;
692 second_byte = ddata[i + position] & 0xff;
693
694 /* Subset 1 */
695 glyph = (0x5e * (first_byte - 0xb0)) + (second_byte - 0xa1);
696
697 /* Subset 2 */
698 if ((first_byte >= 0xa1) && (first_byte <= 0xa3)) {
699 if ((second_byte >= 0xa1) && (second_byte <= 0xfe)) {
700 glyph = (0x5e * (first_byte - 0xa1)) + (second_byte - 0xa1) + 0xeb0;
701 }
702 }
703
704 /* Subset 3 */
705 if ((ddata[i + position] >= 0xa8a1) && (ddata[i + position] <= 0xa8c0)) {
706 glyph = (second_byte - 0xa1) + 0xfca;
707 }
708
709 if (debug_print) {
710 printf(" %.3x[GB %.4x]", glyph, ddata[i + position]);
711 }
712
713 bp = bin_append_posn(glyph, 12, binary, bp);
714 i++;
715 }
716
717 /* Terminator */
718 bp = bin_append_posn(position + block_length == length || mode[position + block_length] != '2'
719 ? 4095 : 4094, 12, binary, bp);
720
721 if (debug_print) {
722 printf(" (TERM %x)\n", position + block_length == length || mode[position + block_length] != '2'
723 ? 4095 : 4094);
724 }
725
726 break;
727 case '2':
728 /* Region Two encoding */
729 /* Mode indicator */
730 if (position == 0 || mode[position - 1] != '1') { /* Unless previous mode Region One */
731 bp = bin_append_posn(5, 4, binary, bp);
732 }
733
734 if (debug_print) {
735 printf("Region Two%s H(2)%d:",
736 position == 0 || mode[position - 1] != '1' ? "" : " (NO indicator)", block_length);
737 }
738
739 i = 0;
740
741 while (i < block_length) {
742 first_byte = (ddata[i + position] & 0xff00) >> 8;
743 second_byte = ddata[i + position] & 0xff;
744
745 glyph = (0x5e * (first_byte - 0xd8)) + (second_byte - 0xa1);
746
747 if (debug_print) {
748 printf(" %.3x[GB %.4x]", glyph, ddata[i + position]);
749 }
750
751 bp = bin_append_posn(glyph, 12, binary, bp);
752 i++;
753 }
754
755 /* Terminator */
756 bp = bin_append_posn(position + block_length == length || mode[position + block_length] != '1'
757 ? 4095 : 4094, 12, binary, bp);
758
759 if (debug_print) {
760 printf(" (TERM %x)\n", position + block_length == length || mode[position + block_length] != '1'
761 ? 4095 : 4094);
762 }
763
764 break;
765 case 'd':
766 /* Double byte encoding */
767 /* Mode indicator */
768 bp = bin_append_posn(6, 4, binary, bp);
769
770 if (debug_print) {
771 printf("Double byte (H(d)%d):", block_length);
772 }
773
774 i = 0;
775
776 while (i < block_length) {
777 first_byte = (ddata[i + position] & 0xff00) >> 8;
778 second_byte = ddata[i + position] & 0xff;
779
780 if (second_byte <= 0x7e) {
781 glyph = (0xbe * (first_byte - 0x81)) + (second_byte - 0x40);
782 } else {
783 glyph = (0xbe * (first_byte - 0x81)) + (second_byte - 0x41);
784 }
785
786 if (debug_print) {
787 printf("%.4x ", glyph);
788 }
789
790 bp = bin_append_posn(glyph, 15, binary, bp);
791 i++;
792 }
793
794 /* Terminator */
795 bp = bin_append_posn(32767, 15, binary, bp);
796 /* Terminator sequence of length 12 is a mistake
797 - confirmed by Wang Yi */
798
799 if (debug_print) {
800 fputc('\n', stdout);
801 }
802 break;
803 case 'f':
804 /* Four-byte encoding */
805 if (debug_print) {
806 printf("Four byte (H(f)%d):", block_length);
807 }
808
809 i = 0;
810
811 while (i < block_length) {
812
813 /* Mode indicator */
814 bp = bin_append_posn(7, 4, binary, bp);
815
816 first_byte = (ddata[i + position] & 0xff00) >> 8;
817 second_byte = ddata[i + position] & 0xff;
818 third_byte = (ddata[i + position + 1] & 0xff00) >> 8;
819 fourth_byte = ddata[i + position + 1] & 0xff;
820
821 glyph = (0x3138 * (first_byte - 0x81)) + (0x04ec * (second_byte - 0x30)) +
822 (0x0a * (third_byte - 0x81)) + (fourth_byte - 0x30);
823
824 if (debug_print) {
825 printf(" %d", glyph);
826 }
827
828 bp = bin_append_posn(glyph, 21, binary, bp);
829 i += 2;
830 }
831
832 /* No terminator */
833
834 if (debug_print) {
835 fputc('\n', stdout);
836 }
837 break;
838 }
839
840 position += block_length;
841
842 } while (position < length);
843
844 if (debug_print) printf("Binary (%d): %.*s\n", bp, bp, binary);
845
846 *p_bp = bp;
847 }
848
849 /* Call `hx_calculate_binary()` for each segment */
850 static void hx_calculate_binary_segs(char binary[], const char mode[], const unsigned int ddata[],
851 const struct zint_seg segs[], const int seg_count, int *p_bin_len, const int debug_print) {
852 int i;
853 const unsigned int *dd = ddata;
854 const char *m = mode;
855 int bp = 0;
856
857 for (i = 0; i < seg_count; i++) {
858 hx_calculate_binary(binary, m, dd, segs[i].length, segs[i].eci, &bp, debug_print);
859 m += segs[i].length;
860 dd += segs[i].length;
861 }
862
863 *p_bin_len = bp;
864 }
865
866 /* Finder pattern for top left of symbol */
867 static void hx_place_finder_top_left(unsigned char *grid, const int size) {
868 int xp, yp;
869 int x = 0, y = 0;
870 char finder[] = {0x7F, 0x40, 0x5F, 0x50, 0x57, 0x57, 0x57};
871
872 for (xp = 0; xp < 7; xp++) {
873 for (yp = 0; yp < 7; yp++) {
874 if (finder[yp] & 0x40 >> xp) {
875 grid[((yp + y) * size) + (xp + x)] = 0x11;
876 } else {
877 grid[((yp + y) * size) + (xp + x)] = 0x10;
878 }
879 }
880 }
881 }
882
883 /* Finder pattern for top right and bottom left of symbol */
884 static void hx_place_finder(unsigned char *grid, const int size, const int x, const int y) {
885 int xp, yp;
886 static const char finder[] = {0x7F, 0x01, 0x7D, 0x05, 0x75, 0x75, 0x75};
887
888 for (xp = 0; xp < 7; xp++) {
889 for (yp = 0; yp < 7; yp++) {
890 if (finder[yp] & 0x40 >> xp) {
891 grid[((yp + y) * size) + (xp + x)] = 0x11;
892 } else {
893 grid[((yp + y) * size) + (xp + x)] = 0x10;
894 }
895 }
896 }
897 }
898
899 /* Finder pattern for bottom right of symbol */
900 static void hx_place_finder_bottom_right(unsigned char *grid, const int size) {
901 int xp, yp;
902 const int x = size - 7;
903 const int y = x;
904 static const char finder[] = {0x75, 0x75, 0x75, 0x05, 0x7D, 0x01, 0x7F};
905
906 for (xp = 0; xp < 7; xp++) {
907 for (yp = 0; yp < 7; yp++) {
908 if (finder[yp] & 0x40 >> xp) {
909 grid[((yp + y) * size) + (xp + x)] = 0x11;
910 } else {
911 grid[((yp + y) * size) + (xp + x)] = 0x10;
912 }
913 }
914 }
915 }
916
917 /* Avoid plotting outside symbol or over finder patterns */
918 static void hx_safe_plot(unsigned char *grid, const int size, const int x, const int y, const int value) {
919 if ((x >= 0) && (x < size)) {
920 if ((y >= 0) && (y < size)) {
921 if (grid[(y * size) + x] == 0) {
922 grid[(y * size) + x] = value;
923 }
924 }
925 }
926 }
927
928 /* Plot an alignment pattern around top and right of a module */
929 static void hx_plot_alignment(unsigned char *grid, const int size, const int x, const int y, const int w,
930 const int h) {
931 int i;
932 hx_safe_plot(grid, size, x, y, 0x11);
933 hx_safe_plot(grid, size, x - 1, y + 1, 0x10);
934
935 for (i = 1; i <= w; i++) {
936 /* Top */
937 hx_safe_plot(grid, size, x - i, y, 0x11);
938 hx_safe_plot(grid, size, x - i - 1, y + 1, 0x10);
939 }
940
941 for (i = 1; i < h; i++) {
942 /* Right */
943 hx_safe_plot(grid, size, x, y + i, 0x11);
944 hx_safe_plot(grid, size, x - 1, y + i + 1, 0x10);
945 }
946 }
947
948 /* Plot assistant alignment patterns */
949 static void hx_plot_assistant(unsigned char *grid, const int size, const int x, const int y) {
950 hx_safe_plot(grid, size, x - 1, y - 1, 0x10);
951 hx_safe_plot(grid, size, x, y - 1, 0x10);
952 hx_safe_plot(grid, size, x + 1, y - 1, 0x10);
953 hx_safe_plot(grid, size, x - 1, y, 0x10);
954 hx_safe_plot(grid, size, x, y, 0x11);
955 hx_safe_plot(grid, size, x + 1, y, 0x10);
956 hx_safe_plot(grid, size, x - 1, y + 1, 0x10);
957 hx_safe_plot(grid, size, x, y + 1, 0x10);
958 hx_safe_plot(grid, size, x + 1, y + 1, 0x10);
959 }
960
961 /* Put static elements in the grid */
962 static void hx_setup_grid(unsigned char *grid, const int size, const int version) {
963 int i;
964
965 memset(grid, 0, (size_t) size * size);
966
967 /* Add finder patterns */
968 hx_place_finder_top_left(grid, size);
969 hx_place_finder(grid, size, 0, size - 7);
970 hx_place_finder(grid, size, size - 7, 0);
971 hx_place_finder_bottom_right(grid, size);
972
973 /* Add finder pattern separator region */
974 for (i = 0; i < 8; i++) {
975 /* Top left */
976 grid[(7 * size) + i] = 0x10;
977 grid[(i * size) + 7] = 0x10;
978
979 /* Top right */
980 grid[(7 * size) + (size - i - 1)] = 0x10;
981 grid[((size - i - 1) * size) + 7] = 0x10;
982
983 /* Bottom left */
984 grid[(i * size) + (size - 8)] = 0x10;
985 grid[((size - 8) * size) + i] = 0x10;
986
987 /* Bottom right */
988 grid[((size - 8) * size) + (size - i - 1)] = 0x10;
989 grid[((size - i - 1) * size) + (size - 8)] = 0x10;
990 }
991
992 /* Reserve function information region */
993 for (i = 0; i < 9; i++) {
994 /* Top left */
995 grid[(8 * size) + i] = 0x10;
996 grid[(i * size) + 8] = 0x10;
997
998 /* Top right */
999 grid[(8 * size) + (size - i - 1)] = 0x10;
1000 grid[((size - i - 1) * size) + 8] = 0x10;
1001
1002 /* Bottom left */
1003 grid[(i * size) + (size - 9)] = 0x10;
1004 grid[((size - 9) * size) + i] = 0x10;
1005
1006 /* Bottom right */
1007 grid[((size - 9) * size) + (size - i - 1)] = 0x10;
1008 grid[((size - i - 1) * size) + (size - 9)] = 0x10;
1009 }
1010
1011 if (version > 3) {
1012 const int k = hx_module_k[version - 1];
1013 const int r = hx_module_r[version - 1];
1014 const int m = hx_module_m[version - 1];
1015 int x, y, row_switch, column_switch;
1016 int module_height, module_width;
1017 int mod_x, mod_y;
1018
1019 /* Add assistant alignment patterns to left and right */
1020 y = 0;
1021 mod_y = 0;
1022 do {
1023 if (mod_y < m) {
1024 module_height = k;
1025 } else {
1026 module_height = r - 1;
1027 }
1028
1029 if ((mod_y & 1) == 0) {
1030 if ((m & 1) == 1) {
1031 hx_plot_assistant(grid, size, 0, y);
1032 }
1033 } else {
1034 if ((m & 1) == 0) {
1035 hx_plot_assistant(grid, size, 0, y);
1036 }
1037 hx_plot_assistant(grid, size, size - 1, y);
1038 }
1039
1040 mod_y++;
1041 y += module_height;
1042 } while (y < size);
1043
1044 /* Add assistant alignment patterns to top and bottom */
1045 x = (size - 1);
1046 mod_x = 0;
1047 do {
1048 if (mod_x < m) {
1049 module_width = k;
1050 } else {
1051 module_width = r - 1;
1052 }
1053
1054 if ((mod_x & 1) == 0) {
1055 if ((m & 1) == 1) {
1056 hx_plot_assistant(grid, size, x, (size - 1));
1057 }
1058 } else {
1059 if ((m & 1) == 0) {
1060 hx_plot_assistant(grid, size, x, (size - 1));
1061 }
1062 hx_plot_assistant(grid, size, x, 0);
1063 }
1064
1065 mod_x++;
1066 x -= module_width;
1067 } while (x >= 0);
1068
1069 /* Add alignment pattern */
1070 column_switch = 1;
1071 y = 0;
1072 mod_y = 0;
1073 do {
1074 if (mod_y < m) {
1075 module_height = k;
1076 } else {
1077 module_height = r - 1;
1078 }
1079
1080 if (column_switch == 1) {
1081 row_switch = 1;
1082 column_switch = 0;
1083 } else {
1084 row_switch = 0;
1085 column_switch = 1;
1086 }
1087
1088 x = (size - 1);
1089 mod_x = 0;
1090 do {
1091 if (mod_x < m) {
1092 module_width = k;
1093 } else {
1094 module_width = r - 1;
1095 }
1096
1097 if (row_switch == 1) {
1098 if (!(y == 0 && x == (size - 1))) {
1099 hx_plot_alignment(grid, size, x, y, module_width, module_height);
1100 }
1101 row_switch = 0;
1102 } else {
1103 row_switch = 1;
1104 }
1105 mod_x++;
1106 x -= module_width;
1107 } while (x >= 0);
1108
1109 mod_y++;
1110 y += module_height;
1111 } while (y < size);
1112 }
1113 }
1114
1115 /* Calculate error correction codes */
1116 static void hx_add_ecc(unsigned char fullstream[], const unsigned char datastream[], const int data_codewords,
1117 const int version, const int ecc_level) {
1118 unsigned char data_block[180];
1119 unsigned char ecc_block[36];
1120 int i, j, block;
1121 int input_position = 0;
1122 int output_position = 0;
1123 const int table_d1_pos = ((version - 1) * 36) + ((ecc_level - 1) * 9);
1124 rs_t rs;
1125
1126 rs_init_gf(&rs, 0x163); /* x^8 + x^6 + x^5 + x + 1 = 0 */
1127
1128 for (i = 0; i < 3; i++) {
1129 const int batch_size = hx_table_d1[table_d1_pos + (3 * i)];
1130 const int data_length = hx_table_d1[table_d1_pos + (3 * i) + 1];
1131 const int ecc_length = hx_table_d1[table_d1_pos + (3 * i) + 2];
1132
1133 rs_init_code(&rs, ecc_length, 1);
1134
1135 for (block = 0; block < batch_size; block++) {
1136 for (j = 0; j < data_length; j++) {
1137 data_block[j] = input_position < data_codewords ? datastream[input_position] : 0;
1138 fullstream[output_position++] = data_block[j];
1139 input_position++;
1140 }
1141
1142 rs_encode(&rs, data_length, data_block, ecc_block);
1143
1144 for (j = 0; j < ecc_length; j++) {
1145 fullstream[output_position++] = ecc_block[j];
1146 }
1147 }
1148 }
1149 }
1150
1151 static void hx_set_function_info(unsigned char *grid, const int size, const int version, const int ecc_level,
1152 const int bitmask, const int debug_print) {
1153 int i, j;
1154 char function_information[34];
1155 unsigned char fi_cw[3] = {0};
1156 unsigned char fi_ecc[4];
1157 int bp = 0;
1158 rs_t rs;
1159
1160 /* Form function information string */
1161
1162 bp = bin_append_posn(version + 20, 8, function_information, bp);
1163 bp = bin_append_posn(ecc_level - 1, 2, function_information, bp);
1164 bp = bin_append_posn(bitmask, 2, function_information, bp);
1165
1166 for (i = 0; i < 3; i++) {
1167 for (j = 0; j < 4; j++) {
1168 if (function_information[(i * 4) + j] == '1') {
1169 fi_cw[i] += (0x08 >> j);
1170 }
1171 }
1172 }
1173
1174 rs_init_gf(&rs, 0x13);
1175 rs_init_code(&rs, 4, 1);
1176 rs_encode(&rs, 3, fi_cw, fi_ecc);
1177
1178 for (i = 0; i < 4; i++) {
1179 bp = bin_append_posn(fi_ecc[i], 4, function_information, bp);
1180 }
1181
1182 /* Previously added alternating filler pattern here (as does BWIPP) but not mentioned in ISO/IEC 20830:2021 and
1183 does not appear in Figure 1 nor in the figures in Annex K (although does appear in Figure 2 and Figures 4-9)
1184 nor in the AIM ITS/04-023:2022 examples: so just clear */
1185 for (i = 28; i < 34; i++) {
1186 function_information[i] = '0';
1187 }
1188
1189 if (debug_print) {
1190 printf("Version: %d, ECC: %d, Mask: %d, Structural Info: %.34s\n", version, ecc_level, bitmask,
1191 function_information);
1192 }
1193
1194 /* Add function information to symbol */
1195 for (i = 0; i < 9; i++) {
1196 if (function_information[i] == '1') {
1197 grid[(8 * size) + i] = 0x01;
1198 grid[((size - 8 - 1) * size) + (size - i - 1)] = 0x01;
1199 }
1200 if (function_information[i + 8] == '1') {
1201 grid[((8 - i) * size) + 8] = 0x01;
1202 grid[((size - 8 - 1 + i) * size) + (size - 8 - 1)] = 0x01;
1203 }
1204 if (function_information[i + 17] == '1') {
1205 grid[(i * size) + (size - 1 - 8)] = 0x01;
1206 grid[((size - 1 - i) * size) + 8] = 0x01;
1207 }
1208 if (function_information[i + 25] == '1') {
1209 grid[(8 * size) + (size - 1 - 8 + i)] = 0x01;
1210 grid[((size - 1 - 8) * size) + (8 - i)] = 0x01;
1211 }
1212 }
1213 }
1214
1215 /* Rearrange data in batches of 13 codewords (section 5.8.2) */
1216 static void hx_make_picket_fence(const unsigned char fullstream[], unsigned char picket_fence[],
1217 const int streamsize) {
1218 int i, start;
1219 int output_position = 0;
1220
1221 for (start = 0; start < 13; start++) {
1222 for (i = start; i < streamsize; i += 13) {
1223 picket_fence[output_position] = fullstream[i];
1224 output_position++;
1225 }
1226 }
1227 }
1228
1229 /* Evaluate a bitmask according to table 9 */
1230 static int hx_evaluate(const unsigned char *local, const int size) {
1231 static const unsigned char h1010111[7] = { 1, 0, 1, 0, 1, 1, 1 };
1232 static const unsigned char h1110101[7] = { 1, 1, 1, 0, 1, 0, 1 };
1233
1234 int x, y, r, block;
1235 int result = 0;
1236 int state;
1237 int a, b, afterCount, beforeCount;
1238
1239 /* Test 1: 1:1:1:1:3 or 3:1:1:1:1 ratio pattern in row/column */
1240 /* Vertical */
1241 for (x = 0; x < size; x++) {
1242 for (y = 0; y <= (size - 7); y++) {
1243 if (local[y * size + x] && local[(y + 1) * size + x] != local[(y + 5) * size + x] &&
1244 local[(y + 2) * size + x] && !local[(y + 3) * size + x] &&
1245 local[(y + 4) * size + x] && local[(y + 6) * size + x]) {
1246 /* Pattern found, check before and after */
1247 beforeCount = 0;
1248 for (b = (y - 1); b >= (y - 3); b--) {
1249 if (b < 0) { /* Count < edge as whitespace */
1250 beforeCount = 3;
1251 break;
1252 }
1253 if (local[(b * size) + x]) {
1254 break;
1255 }
1256 beforeCount++;
1257 }
1258 if (beforeCount == 3) {
1259 /* Pattern is preceded by light area 3 modules wide */
1260 result += 50;
1261 } else {
1262 afterCount = 0;
1263 for (a = (y + 7); a <= (y + 9); a++) {
1264 if (a >= size) { /* Count > edge as whitespace */
1265 afterCount = 3;
1266 break;
1267 }
1268 if (local[(a * size) + x]) {
1269 break;
1270 }
1271 afterCount++;
1272 }
1273 if (afterCount == 3) {
1274 /* Pattern is followed by light area 3 modules wide */
1275 result += 50;
1276 }
1277 }
1278 y++; /* Skip to next possible match */
1279 }
1280 }
1281 }
1282
1283 /* Horizontal */
1284 for (y = 0; y < size; y++) {
1285 r = y * size;
1286 for (x = 0; x <= (size - 7); x++) {
1287 if (memcmp(local + r + x, h1010111, 7) == 0 || memcmp(local + r + x, h1110101, 7) == 0) {
1288 /* Pattern found, check before and after */
1289 beforeCount = 0;
1290 for (b = (x - 1); b >= (x - 3); b--) {
1291 if (b < 0) { /* Count < edge as whitespace */
1292 beforeCount = 3;
1293 break;
1294 }
1295 if (local[r + b]) {
1296 break;
1297 }
1298 beforeCount++;
1299 }
1300
1301 if (beforeCount == 3) {
1302 /* Pattern is preceded by light area 3 modules wide */
1303 result += 50;
1304 } else {
1305 afterCount = 0;
1306 for (a = (x + 7); a <= (x + 9); a++) {
1307 if (a >= size) { /* Count > edge as whitespace */
1308 afterCount = 3;
1309 break;
1310 }
1311 if (local[r + a]) {
1312 break;
1313 }
1314 afterCount++;
1315 }
1316 if (afterCount == 3) {
1317 /* Pattern is followed by light area 3 modules wide */
1318 result += 50;
1319 }
1320 }
1321 x++; /* Skip to next possible match */
1322 }
1323 }
1324 }
1325
1326 /* Test 2: Adjacent modules in row/column in same colour */
1327 /* In AIMD-15 section 5.8.3.2 it is stated... “In Table 9 below, i refers to the row
1328 * position of the module.” - however i being the length of the run of the
1329 * same colour (i.e. "block" below) in the same fashion as ISO/IEC 18004
1330 * makes more sense. -- Confirmed by Wang Yi */
1331 /* Fixed in ISO/IEC 20830 section 5.8.4.3 "In Table, i refers to the modules with
1332 same color." */
1333
1334 /* Vertical */
1335 for (x = 0; x < size; x++) {
1336 block = 0;
1337 state = 0;
1338 for (y = 0; y < size; y++) {
1339 if (local[(y * size) + x] == state) {
1340 block++;
1341 } else {
1342 if (block >= 3) {
1343 result += block * 4;
1344 }
1345 block = 1;
1346 state = local[(y * size) + x];
1347 }
1348 }
1349 if (block >= 3) {
1350 result += block * 4;
1351 }
1352 }
1353
1354 /* Horizontal */
1355 for (y = 0; y < size; y++) {
1356 r = y * size;
1357 block = 0;
1358 state = 0;
1359 for (x = 0; x < size; x++) {
1360 if (local[r + x] == state) {
1361 block++;
1362 } else {
1363 if (block >= 3) {
1364 result += block * 4;
1365 }
1366 block = 1;
1367 state = local[r + x];
1368 }
1369 }
1370 if (block >= 3) {
1371 result += block * 4;
1372 }
1373 }
1374
1375 return result;
1376 }
1377
1378 /* Apply the four possible bitmasks for evaluation */
1379 /* TODO: Haven't been able to replicate (or even get close to) the penalty scores in ISO/IEC 20830:2021
1380 * Annex K examples */
1381 static void hx_apply_bitmask(unsigned char *grid, const int size, const int version, const int ecc_level,
1382 const int user_mask, const int debug_print) {
1383 int x, y;
1384 int i, j, r, k;
1385 int pattern, penalty[4] = {0};
1386 int best_pattern;
1387 int bit;
1388 const int size_squared = size * size;
1389 unsigned char *mask = (unsigned char *) z_alloca(size_squared);
1390 unsigned char *local = (unsigned char *) z_alloca(size_squared);
1391
1392 /* Perform data masking */
1393 memset(mask, 0, size_squared);
1394 for (y = 0; y < size; y++) {
1395 r = y * size;
1396 for (x = 0; x < size; x++) {
1397 k = r + x;
1398
1399 if (!(grid[k] & 0xf0)) {
1400 j = x + 1;
1401 i = y + 1;
1402 if (((i + j) & 1) == 0) {
1403 mask[k] |= 0x02;
1404 }
1405 if (((((i + j) % 3) + (j % 3)) & 1) == 0) {
1406 mask[k] |= 0x04;
1407 }
1408 if ((((i % j) + (j % i) + (i % 3) + (j % 3)) & 1) == 0) {
1409 mask[k] |= 0x08;
1410 }
1411 }
1412 }
1413 }
1414
1415 if (user_mask) {
1416 best_pattern = user_mask - 1;
1417 } else {
1418 /* apply data masks to grid, result in local */
1419
1420 /* Do null pattern 00 separately first */
1421 pattern = 0;
1422 for (k = 0; k < size_squared; k++) {
1423 local[k] = grid[k] & 0x0f;
1424 }
1425 /* Set the Structural Info */
1426 hx_set_function_info(local, size, version, ecc_level, pattern, 0 /*debug_print*/);
1427
1428 /* Evaluate result */
1429 penalty[pattern] = hx_evaluate(local, size);
1430
1431 best_pattern = 0;
1432 for (pattern = 1; pattern < 4; pattern++) {
1433 bit = 1 << pattern;
1434 for (k = 0; k < size_squared; k++) {
1435 if (mask[k] & bit) {
1436 local[k] = grid[k] ^ 0x01;
1437 } else {
1438 local[k] = grid[k] & 0x0f;
1439 }
1440 }
1441 /* Set the Structural Info */
1442 hx_set_function_info(local, size, version, ecc_level, pattern, 0 /*debug_print*/);
1443
1444 /* Evaluate result */
1445 penalty[pattern] = hx_evaluate(local, size);
1446 if (penalty[pattern] < penalty[best_pattern]) {
1447 best_pattern = pattern;
1448 }
1449 }
1450 }
1451
1452 if (debug_print) {
1453 printf("Mask: %d (%s)", best_pattern, user_mask ? "specified" : "automatic");
1454 if (!user_mask) {
1455 for (pattern = 0; pattern < 4; pattern++) printf(" %d:%d", pattern, penalty[pattern]);
1456 }
1457 fputc('\n', stdout);
1458 }
1459
1460 /* Apply mask */
1461 if (best_pattern) { /* If not null mask */
1462 if (!user_mask && best_pattern == 3) { /* Reuse last */
1463 memcpy(grid, local, size_squared);
1464 } else {
1465 bit = 1 << best_pattern;
1466 for (k = 0; k < size_squared; k++) {
1467 if (mask[k] & bit) {
1468 grid[k] ^= 0x01;
1469 }
1470 }
1471 }
1472 }
1473 /* Set the Structural Info */
1474 hx_set_function_info(grid, size, version, ecc_level, best_pattern, debug_print);
1475 }
1476
1477 /* Han Xin Code - main */
1478 INTERNAL int hanxin(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
1479 int warn_number = 0;
1480 int est_binlen;
1481 int ecc_level = symbol->option_1;
1482 int i, j, j_max, version;
1483 int full_multibyte;
1484 int user_mask;
1485 int data_codewords = 0, size;
1486 int size_squared;
1487 int codewords;
1488 int bin_len;
1489 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
1490 const int eci_length_segs = get_eci_length_segs(segs, seg_count);
1491 struct zint_seg *local_segs = (struct zint_seg *) z_alloca(sizeof(struct zint_seg) * seg_count);
1492 unsigned int *ddata = (unsigned int *) z_alloca(sizeof(unsigned int) * eci_length_segs);
1493 char *mode = (char *) z_alloca(eci_length_segs);
1494 char *binary;
1495 unsigned char *datastream;
1496 unsigned char *fullstream;
1497 unsigned char *picket_fence;
1498 unsigned char *grid;
1499
1500 segs_cpy(symbol, segs, seg_count, local_segs); /* Shallow copy (needed to set default ECI & protect lengths) */
1501
1502 /* If ZINT_FULL_MULTIBYTE set use Hanzi mode in DATA_MODE or for non-GB 18030 in UNICODE_MODE */
1503 full_multibyte = (symbol->option_3 & 0xFF) == ZINT_FULL_MULTIBYTE;
1504 user_mask = (symbol->option_3 >> 8) & 0x0F; /* User mask is pattern + 1, so >= 1 and <= 4 */
1505 if (user_mask > 4) {
1506 user_mask = 0; /* Ignore */
1507 }
1508
1509 if ((symbol->input_mode & 0x07) == DATA_MODE) {
1510 gb18030_cpy_segs(local_segs, seg_count, ddata, full_multibyte);
1511 } else {
1512 unsigned int *dd = ddata;
1513 for (i = 0; i < seg_count; i++) {
1514 int done = 0;
1515 if (local_segs[i].eci != 32 || seg_count > 1) { /* Unless ECI 32 (GB 18030) or have multiple segments */
1516 /* Try other conversions (ECI 0 defaults to ISO/IEC 8859-1) */
1517 int error_number = gb18030_utf8_to_eci(local_segs[i].eci, local_segs[i].source, &local_segs[i].length,
1518 dd, full_multibyte);
1519 if (error_number == 0) {
1520 done = 1;
1521 } else if (local_segs[i].eci || seg_count > 1) {
1522 return errtxtf(error_number, symbol, 545, "Invalid character in input for ECI '%d'",
1523 local_segs[i].eci);
1524 }
1525 }
1526 if (!done) {
1527 /* Try GB 18030 */
1528 int error_number = gb18030_utf8(symbol, local_segs[i].source, &local_segs[i].length, dd);
1529 if (error_number != 0) {
1530 return error_number;
1531 }
1532 if (local_segs[i].eci != 32) {
1533 warn_number = errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 543,
1534 "Converted to GB 18030 but no ECI specified");
1535 }
1536 }
1537 dd += local_segs[i].length;
1538 }
1539 }
1540
1541 hx_define_mode_segs(mode, ddata, local_segs, seg_count, debug_print);
1542
1543 est_binlen = hx_calc_binlen_segs(mode, ddata, local_segs, seg_count);
1544 if (debug_print) {
1545 printf("Estimated binary length: %d\n", est_binlen);
1546 }
1547
1548 binary = (char *) malloc(est_binlen + 1);
1549
1550 if ((ecc_level <= 0) || (ecc_level >= 5)) {
1551 ecc_level = 1;
1552 }
1553
1554 hx_calculate_binary_segs(binary, mode, ddata, local_segs, seg_count, &bin_len, debug_print);
1555 codewords = bin_len >> 3;
1556 if (bin_len & 0x07) {
1557 codewords++;
1558 }
1559 if (debug_print) {
1560 printf("Num. of codewords: %d (%d padbits)\n", codewords, bin_len & 0x07);
1561 }
1562
1563 version = 85;
1564 for (i = 84; i > 0; i--) {
1565 if (hx_data_codewords[ecc_level - 1][i - 1] >= codewords) {
1566 version = i;
1567 data_codewords = hx_data_codewords[ecc_level - 1][i - 1];
1568 }
1569 }
1570
1571 if (version == 85) {
1572 free(binary);
1573 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 541, "Input too long, requires %d codewords (maximum 3264)",
1574 codewords);
1575 }
1576
1577 if ((symbol->option_2 < 0) || (symbol->option_2 > 84)) {
1578 symbol->option_2 = 0;
1579 }
1580
1581 if (symbol->option_2 > version) {
1582 version = symbol->option_2;
1583 }
1584
1585 if ((symbol->option_2 != 0) && (symbol->option_2 < version)) {
1586 free(binary);
1587 if (ecc_level == 1) {
1588 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 542,
1589 "Input too long for Version %1$d, requires %2$d codewords (maximum %3$d)",
1590 symbol->option_2, codewords, hx_data_codewords[ecc_level - 1][symbol->option_2 - 1]);
1591 }
1592 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 542,
1593 "Input too long for Version %1$d, ECC %2$d, requires %3$d codewords (maximum %4$d)",
1594 symbol->option_2, ecc_level, codewords,
1595 hx_data_codewords[ecc_level - 1][symbol->option_2 - 1]);
1596 }
1597
1598 /* If there is spare capacity, increase the level of ECC */
1599
1600 /* Unless explicitly specified (within min/max bounds) by user */
1601 if (symbol->option_1 == -1 || symbol->option_1 != ecc_level) {
1602 if (ecc_level == 1 && codewords <= hx_data_codewords[1][version - 1]) {
1603 ecc_level = 2;
1604 data_codewords = hx_data_codewords[1][version - 1];
1605 }
1606
1607 if (ecc_level == 2 && codewords <= hx_data_codewords[2][version - 1]) {
1608 ecc_level = 3;
1609 data_codewords = hx_data_codewords[2][version - 1];
1610 }
1611
1612 if (ecc_level == 3 && codewords <= hx_data_codewords[3][version - 1]) {
1613 ecc_level = 4;
1614 data_codewords = hx_data_codewords[3][version - 1];
1615 }
1616 }
1617
1618 size = (version * 2) + 21;
1619 size_squared = size * size;
1620
1621 datastream = (unsigned char *) z_alloca(data_codewords);
1622 fullstream = (unsigned char *) z_alloca(hx_total_codewords[version - 1]);
1623 picket_fence = (unsigned char *) z_alloca(hx_total_codewords[version - 1]);
1624 grid = (unsigned char *) z_alloca(size_squared);
1625
1626 memset(datastream, 0, data_codewords);
1627
1628 for (i = 0; i < bin_len; i++) {
1629 if (binary[i] == '1') {
1630 datastream[i >> 3] |= 0x80 >> (i & 0x07);
1631 }
1632 }
1633 free(binary);
1634
1635 if (debug_print) {
1636 printf("Datastream (%d):", data_codewords);
1637 for (i = 0; i < data_codewords; i++) {
1638 printf(" %.2x", datastream[i]);
1639 }
1640 fputc('\n', stdout);
1641 }
1642 #ifdef ZINT_TEST
1643 if (symbol->debug & ZINT_DEBUG_TEST) debug_test_codeword_dump(symbol, datastream, data_codewords);
1644 #endif
1645
1646 hx_setup_grid(grid, size, version);
1647
1648 hx_add_ecc(fullstream, datastream, data_codewords, version, ecc_level);
1649
1650 if (debug_print) {
1651 printf("Fullstream (%d):", hx_total_codewords[version - 1]);
1652 for (i = 0; i < hx_total_codewords[version - 1]; i++) {
1653 printf(" %.2x", fullstream[i]);
1654 }
1655 fputc('\n', stdout);
1656 }
1657
1658 hx_make_picket_fence(fullstream, picket_fence, hx_total_codewords[version - 1]);
1659
1660 /* Populate grid */
1661 j = 0;
1662 j_max = hx_total_codewords[version - 1] * 8;
1663 for (i = 0; i < size_squared; i++) {
1664 if (grid[i] == 0x00) {
1665 if (j < j_max) {
1666 if (picket_fence[(j >> 3)] & (0x80 >> (j & 0x07))) {
1667 grid[i] = 0x01;
1668 }
1669 j++;
1670 } else {
1671 break;
1672 }
1673 }
1674 }
1675
1676 hx_apply_bitmask(grid, size, version, ecc_level, user_mask, debug_print);
1677
1678 symbol->width = size;
1679 symbol->rows = size;
1680
1681 for (i = 0; i < size; i++) {
1682 const int r = i * size;
1683 for (j = 0; j < size; j++) {
1684 if (grid[r + j] & 0x01) {
1685 set_module(symbol, i, j);
1686 }
1687 }
1688 symbol->row_height[i] = 1;
1689 }
1690 symbol->height = size;
1691
1692 return warn_number;
1693 }
1694
1695 /* vim: set ts=4 sw=4 et : */