1 /* hanxin.c - Han Xin Code
2
3 libzint - the open source barcode library
4 Copyright (C) 2009-2017 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
32 /* This code attempts to implement Han Xin Code according to AIMD-015:2010 (Rev 0.8) */
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #ifdef _MSC_VER
38 #include <malloc.h>
39 #endif
40 #include "common.h"
41 #include "reedsol.h"
42 #include "hanxin.h"
43 #include "gb2312.h"
44 #include "gb18030.h"
45 #include "assert.h"
46
47 /* Find which submode to use for a text character */
getsubmode(char input)48 int getsubmode(char input) {
49 int submode = 2;
50
51 if ((input >= '0') && (input <= '9')) {
52 submode = 1;
53 }
54
55 if ((input >= 'A') && (input <= 'Z')) {
56 submode = 1;
57 }
58
59 if ((input >= 'a') && (input <= 'z')) {
60 submode = 1;
61 }
62
63 return submode;
64 }
65
66 /* Calculate the approximate length of the binary string */
calculate_binlength(char mode[],int source[],const size_t length,int eci)67 static int calculate_binlength(char mode[], int source[], const size_t length, int eci) {
68 size_t i;
69 char lastmode = 't';
70 int est_binlen = 0;
71 int submode = 1;
72
73 if (eci != 3) {
74 est_binlen += 12;
75 }
76
77 i = 0;
78 do {
79 switch (mode[i]) {
80 case 'n':
81 if (lastmode != 'n') {
82 est_binlen += 14;
83 lastmode = 'n';
84 }
85 est_binlen += 4;
86 break;
87 case 't':
88 if (lastmode != 't') {
89 est_binlen += 10;
90 lastmode = 't';
91 submode = 1;
92 }
93 if (getsubmode((char) source[i]) != submode) {
94 est_binlen += 6;
95 submode = getsubmode((char) source[i]);
96 }
97 est_binlen += 6;
98 break;
99 case 'b':
100 if (lastmode != 'b') {
101 est_binlen += 17;
102 lastmode = 'b';
103 }
104 est_binlen += 8;
105 break;
106 case '1':
107 if (lastmode != '1') {
108 est_binlen += 16;
109 lastmode = '1';
110 }
111 est_binlen += 12;
112 break;
113 case '2':
114 if (lastmode != '2') {
115 est_binlen += 16;
116 lastmode = '2';
117 }
118 est_binlen += 12;
119 break;
120 case 'd':
121 if (lastmode != 'd') {
122 est_binlen += 16;
123 lastmode = 'd';
124 }
125 est_binlen += 15;
126 break;
127 case 'f':
128 if (lastmode != 'f') {
129 est_binlen += 4;
130 lastmode = 'f';
131 }
132 est_binlen += 21;
133 i++;
134 break;
135 }
136 i++;
137 } while (i < length);
138
139 return est_binlen;
140 }
141
isRegion1(int glyph)142 int isRegion1(int glyph) {
143 int first_byte, second_byte;
144 int valid = 0;
145
146 first_byte = (glyph & 0xff00) >> 8;
147 second_byte = glyph & 0xff;
148
149 if ((first_byte >= 0xb0) && (first_byte <= 0xd7)) {
150 if ((second_byte >= 0xa1) && (second_byte <= 0xfe)) {
151 valid = 1;
152 }
153 }
154
155 if ((first_byte >= 0xa1) && (first_byte <= 0xa3)) {
156 if ((second_byte >= 0xa1) && (second_byte <= 0xfe)) {
157 valid = 1;
158 }
159 }
160
161 if ((glyph >= 0xa8a1) && (glyph <= 0xa8c0)) {
162 valid = 1;
163 }
164
165 return valid;
166 }
167
isRegion2(int glyph)168 int isRegion2(int glyph) {
169 int first_byte, second_byte;
170 int valid = 0;
171
172 first_byte = (glyph & 0xff00) >> 8;
173 second_byte = glyph & 0xff;
174
175 if ((first_byte >= 0xd8) && (first_byte <= 0xf7)) {
176 if ((second_byte >= 0xa1) && (second_byte <= 0xfe)) {
177 valid = 1;
178 }
179 }
180
181 return valid;
182 }
183
isDoubleByte(int glyph)184 int isDoubleByte(int glyph) {
185 int first_byte, second_byte;
186 int valid = 0;
187
188 first_byte = (glyph & 0xff00) >> 8;
189 second_byte = glyph & 0xff;
190
191 if ((first_byte >= 0x81) && (first_byte <= 0xfe)) {
192 if ((second_byte >= 0x40) && (second_byte <= 0x7e)) {
193 valid = 1;
194 }
195
196 if ((second_byte >= 0x80) && (second_byte <= 0xfe)) {
197 valid = 1;
198 }
199 }
200
201 return valid;
202 }
203
isFourByte(int glyph,int glyph2)204 int isFourByte(int glyph, int glyph2) {
205 int first_byte, second_byte;
206 int third_byte, fourth_byte;
207 int valid = 0;
208
209 first_byte = (glyph & 0xff00) >> 8;
210 second_byte = glyph & 0xff;
211 third_byte = (glyph2 & 0xff00) >> 8;
212 fourth_byte = glyph2 & 0xff;
213
214 if ((first_byte >= 0x81) && (first_byte <= 0xfe)) {
215 if ((second_byte >= 0x30) && (second_byte <= 0x39)) {
216 if ((third_byte >= 0x81) && (third_byte <= 0xfe)) {
217 if ((fourth_byte >= 0x30) && (fourth_byte <= 0x39)) {
218 valid = 1;
219 }
220 }
221 }
222 }
223
224 return valid;
225 }
226
227 /* Calculate mode switching */
hx_define_mode(char mode[],int source[],const size_t length)228 static void hx_define_mode(char mode[], int source[], const size_t length) {
229 size_t i;
230 char lastmode = 't';
231 int done;
232
233 i = 0;
234 do {
235 done = 0;
236
237 if (isRegion1(source[i])) {
238 mode[i] = '1';
239 done = 1;
240 i++;
241 }
242
243 if ((done == 0) && (isRegion2(source[i]))) {
244 mode[i] = '2';
245 done = 1;
246 i++;
247 }
248
249 if ((done == 0) && (isDoubleByte(source[i]))) {
250 mode[i] = 'd';
251 done = 1;
252 i++;
253 }
254
255 if ((done == 0) && (i < length - 1)) {
256 if (isFourByte(source[i], source[i + 1])) {
257 mode[i] = 'f';
258 mode[i + 1] = 'f';
259 done = 1;
260 i += 2;
261 }
262 }
263
264 if (done == 0) {
265 if ((source[i] >= '0') && (source[i] <= '9')) {
266 mode[i] = 'n';
267 if (lastmode != 'n') {
268 lastmode = 'n';
269 }
270 } else {
271 if ((source[i] <= 127) && ((source[i] <= 27) || (source[i] >= 32))) {
272 mode[i] = 't';
273 if (lastmode != 't') {
274 lastmode = 't';
275 }
276 } else {
277 mode[i] = 'b';
278 if (lastmode != 'b') {
279 lastmode = 'b';
280 }
281 }
282 }
283 i++;
284 }
285 } while (i < length);
286 mode[length] = '\0';
287 }
288
289 /* Convert Text 1 sub-mode character to encoding value, as given in table 3 */
lookup_text1(char input)290 int lookup_text1(char input) {
291 int encoding_value = 0;
292
293 if ((input >= '0') && (input <= '9')) {
294 encoding_value = input - '0';
295 }
296
297 if ((input >= 'A') && (input <= 'Z')) {
298 encoding_value = input - 'A' + 10;
299 }
300
301 if ((input >= 'a') && (input <= 'z')) {
302 encoding_value = input - 'a' + 36;
303 }
304
305 return encoding_value;
306 }
307
308 /* Convert Text 2 sub-mode character to encoding value, as given in table 4 */
lookup_text2(char input)309 int lookup_text2(char input) {
310 int encoding_value = 0;
311
312 if ((input >= 0) && (input <= 27)) {
313 encoding_value = input;
314 }
315
316 if ((input >= ' ') && (input <= '/')) {
317 encoding_value = input - ' ' + 28;
318 }
319
320 if ((input >= '[') && (input <= 96)) {
321 encoding_value = input - '[' + 51;
322 }
323
324 if ((input >= '{') && (input <= 127)) {
325 encoding_value = input - '{' + 57;
326 }
327
328 return encoding_value;
329 }
330
331 /* Convert input data to binary stream */
calculate_binary(char binary[],char mode[],int source[],const size_t length,const int eci,int debug)332 static void calculate_binary(char binary[], char mode[], int source[], const size_t length, const int eci, int debug) {
333 int block_length;
334 int position = 0;
335 int i, count, encoding_value;
336 int first_byte, second_byte;
337 int third_byte, fourth_byte;
338 int glyph;
339 int submode;
340
341 if (eci != 3) {
342 /* Encoding ECI assignment number, according to Table 5 */
343 bin_append(8, 4, binary); // ECI
344 if (eci <= 127) {
345 bin_append(eci, 8, binary);
346 }
347 if ((eci >= 128) && (eci <= 16383)) {
348 strcat(binary, "10");
349 bin_append(eci, 14, binary);
350 }
351 if (eci >= 16384) {
352 strcat(binary, "110");
353 bin_append(eci, 21, binary);
354 }
355 }
356
357 do {
358 block_length = 0;
359 do {
360 block_length++;
361 } while (mode[position + block_length] == mode[position]);
362
363 switch (mode[position]) {
364 case 'n':
365 /* Numeric mode */
366 /* Mode indicator */
367 bin_append(1, 4, binary);
368
369 if (debug) {
370 printf("Numeric\n");
371 }
372
373 i = 0;
374
375 while (i < block_length) {
376 int first = 0, second = 0, third = 0;
377
378 first = posn(NEON, (char) source[position + i]);
379 count = 1;
380 encoding_value = first;
381
382 if (i + 1 < block_length && mode[position + i + 1] == 'n') {
383 second = posn(NEON, (char) source[position + i + 1]);
384 count = 2;
385 encoding_value = (encoding_value * 10) + second;
386
387 if (i + 2 < block_length && mode[position + i + 2] == 'n') {
388 third = posn(NEON, (char) source[position + i + 2]);
389 count = 3;
390 encoding_value = (encoding_value * 10) + third;
391 }
392 }
393
394 bin_append(encoding_value, 10, binary);
395
396 if (debug) {
397 printf("0x%4x (%d)", encoding_value, encoding_value);
398 }
399
400 i += count;
401 }
402
403 /* Mode terminator depends on number of characters in last group (Table 2) */
404 switch (count) {
405 case 1:
406 bin_append(1021, 10, binary);
407 break;
408 case 2:
409 bin_append(1022, 10, binary);
410 break;
411 case 3:
412 bin_append(1023, 10, binary);
413 break;
414 }
415
416 if (debug) {
417 printf(" (TERM %d)\n", count);
418 }
419
420 break;
421 case 't':
422 /* Text mode */
423 if (position != 0) {
424 /* Mode indicator */
425 bin_append(2, 4, binary);
426
427 if (debug) {
428 printf("Text\n");
429 }
430 }
431
432 submode = 1;
433
434 i = 0;
435
436 while (i < block_length) {
437
438 if (getsubmode((char) source[i + position]) != submode) {
439 /* Change submode */
440 bin_append(62, 6, binary);
441 submode = getsubmode((char) source[i + position]);
442 if (debug) {
443 printf("SWITCH ");
444 }
445 }
446
447 if (submode == 1) {
448 encoding_value = lookup_text1((char) source[i + position]);
449 } else {
450 encoding_value = lookup_text2((char) source[i + position]);
451 }
452
453 bin_append(encoding_value, 6, binary);
454
455 if (debug) {
456 printf("%c (%d) ", (char) source[i], encoding_value);
457 }
458 i++;
459 }
460
461 /* Terminator */
462 bin_append(63, 6, binary);
463
464 if (debug) {
465 printf("\n");
466 }
467 break;
468 case 'b':
469 /* Binary Mode */
470 /* Mode indicator */
471 bin_append(3, 4, binary);
472
473 /* Count indicator */
474 bin_append(block_length, 13, binary);
475
476 if (debug) {
477 printf("Binary (length %d)\n", block_length);
478 }
479
480 i = 0;
481
482 while (i < block_length) {
483
484 /* 8-bit bytes with no conversion */
485 bin_append(source[i + position], 8, binary);
486
487 if (debug) {
488 printf("%d ", source[i + position]);
489 }
490
491 i++;
492 }
493
494 if (debug) {
495 printf("\n");
496 }
497 break;
498 case '1':
499 /* Region 1 encoding */
500 /* Mode indicator */
501 bin_append(4, 4, binary);
502
503 if (debug) {
504 printf("Region 1\n");
505 }
506
507 i = 0;
508
509 while (i < block_length) {
510 first_byte = (source[i + position] & 0xff00) >> 8;
511 second_byte = source[i + position] & 0xff;
512
513 /* Subset 1 */
514 glyph = (0x5e * (first_byte - 0xb0)) + (second_byte - 0xa1);
515
516 /* Subset 2 */
517 if ((first_byte >= 0xa1) && (first_byte <= 0xa3)) {
518 if ((second_byte >= 0xa1) && (second_byte <= 0xfe)) {
519 glyph = (0x5e * first_byte - 0xa1) + (second_byte - 0xa1) + 0xeb0;
520 }
521 }
522
523 /* Subset 3 */
524 if ((source[i + position] >= 0xa8a1) && (source[i + position] <= 0xa8c0)) {
525 glyph = (second_byte - 0xa1) + 0xfca;
526 }
527
528 if (debug) {
529 printf("%d ", glyph);
530 }
531
532 bin_append(glyph, 12, binary);
533 i++;
534 }
535
536 /* Terminator */
537 bin_append(4095, 12, binary);
538
539 if (debug) {
540 printf("\n");
541 }
542
543 break;
544 case '2':
545 /* Region 2 encoding */
546 /* Mode indicator */
547 bin_append(5, 4, binary);
548
549 if (debug) {
550 printf("Region 2\n");
551 }
552
553 i = 0;
554
555 while (i < block_length) {
556 first_byte = (source[i + position] & 0xff00) >> 8;
557 second_byte = source[i + position] & 0xff;
558
559 glyph = (0x5e * (first_byte - 0xd8)) + (second_byte - 0xa1);
560
561 if (debug) {
562 printf("%d ", glyph);
563 }
564
565 bin_append(glyph, 12, binary);
566 i++;
567 }
568
569 /* Terminator */
570 bin_append(4095, 12, binary);
571
572 if (debug) {
573 printf("\n");
574 }
575 break;
576 case 'd':
577 /* Double byte encoding */
578 /* Mode indicator */
579 bin_append(6, 4, binary);
580
581 if (debug) {
582 printf("Double byte\n");
583 }
584
585 i = 0;
586
587 while (i < block_length) {
588 first_byte = (source[i + position] & 0xff00) >> 8;
589 second_byte = source[i + position] & 0xff;
590
591 if (second_byte <= 0x7e) {
592 glyph = (0xbe * (first_byte - 0x81)) + (second_byte - 0x40);
593 } else {
594 glyph = (0xbe * (first_byte - 0x81)) + (second_byte - 0x41);
595 }
596
597 if (debug) {
598 printf("%d ", glyph);
599 }
600
601 bin_append(glyph, 15, binary);
602 i++;
603 }
604
605 /* Terminator */
606 bin_append(32767, 15, binary);
607 /* Terminator sequence of length 12 is a mistake
608 - confirmed by Wang Yi */
609
610 if (debug) {
611 printf("\n");
612 }
613 break;
614 case 'f':
615 /* Four-byte encoding */
616 if (debug) {
617 printf("Four byte\n");
618 }
619
620 i = 0;
621
622 while (i < block_length) {
623
624 /* Mode indicator */
625 bin_append(7, 4, binary);
626
627 first_byte = (source[i + position] & 0xff00) >> 8;
628 second_byte = source[i + position] & 0xff;
629 third_byte = (source[i + position + 1] & 0xff00) >> 8;
630 fourth_byte = source[i + position + 1] & 0xff;
631
632 glyph = (0x3138 * (first_byte - 0x81)) + (0x04ec * (second_byte - 0x30)) +
633 (0x0a * (third_byte - 0x81)) + (fourth_byte - 0x30);
634
635 if (debug) {
636 printf("%d ", glyph);
637 }
638
639 bin_append(glyph, 15, binary);
640 i += 2;
641 }
642
643 /* No terminator */
644
645 if (debug) {
646 printf("\n");
647 }
648 break;
649
650 }
651
652 position += block_length;
653
654 } while (position < length);
655 }
656
657 /* Finder pattern for top left of symbol */
hx_place_finder_top_left(unsigned char * grid,int size)658 void hx_place_finder_top_left(unsigned char* grid, int size) {
659 int xp, yp;
660 int x = 0, y = 0;
661 char finder[] = {0x7F, 0x40, 0x5F, 0x50, 0x57, 0x57, 0x57};
662
663 for (xp = 0; xp < 7; xp++) {
664 for (yp = 0; yp < 7; yp++) {
665 if (finder[yp] & 0x40 >> xp) {
666 grid[((yp + y) * size) + (xp + x)] = 0x11;
667 } else {
668 grid[((yp + y) * size) + (xp + x)] = 0x10;
669 }
670 }
671 }
672 }
673
674 /* Finder pattern for top right and bottom left of symbol */
hx_place_finder(unsigned char * grid,int size,int x,int y)675 void hx_place_finder(unsigned char* grid, int size, int x, int y) {
676 int xp, yp;
677 char finder[] = {0x7F, 0x01, 0x7D, 0x05, 0x75, 0x75, 0x75};
678
679 for (xp = 0; xp < 7; xp++) {
680 for (yp = 0; yp < 7; yp++) {
681 if (finder[yp] & 0x40 >> xp) {
682 grid[((yp + y) * size) + (xp + x)] = 0x11;
683 } else {
684 grid[((yp + y) * size) + (xp + x)] = 0x10;
685 }
686 }
687 }
688 }
689
690 /* Finder pattern for bottom right of symbol */
hx_place_finder_bottom_right(unsigned char * grid,int size)691 void hx_place_finder_bottom_right(unsigned char* grid, int size) {
692 int xp, yp;
693 int x = size - 7, y = size - 7;
694 char finder[] = {0x75, 0x75, 0x75, 0x05, 0x7D, 0x01, 0x7F};
695
696 for (xp = 0; xp < 7; xp++) {
697 for (yp = 0; yp < 7; yp++) {
698 if (finder[yp] & 0x40 >> xp) {
699 grid[((yp + y) * size) + (xp + x)] = 0x11;
700 } else {
701 grid[((yp + y) * size) + (xp + x)] = 0x10;
702 }
703 }
704 }
705 }
706
707 /* Avoid plotting outside symbol or over finder patterns */
hx_safe_plot(unsigned char * grid,int size,int x,int y,int value)708 void hx_safe_plot(unsigned char *grid, int size, int x, int y, int value) {
709 if ((x >= 0) && (x < size)) {
710 if ((y >= 0) && (y < size)) {
711 if (grid[(y * size) + x] == 0) {
712 grid[(y * size) + x] = value;
713 }
714 }
715 }
716 }
717
718 /* Plot an alignment pattern around top and right of a module */
hx_plot_alignment(unsigned char * grid,int size,int x,int y,int w,int h)719 void hx_plot_alignment(unsigned char *grid, int size, int x, int y, int w, int h) {
720 int i;
721 hx_safe_plot(grid, size, x, y, 0x11);
722 hx_safe_plot(grid, size, x - 1, y + 1, 0x10);
723
724 for (i = 1; i <= w; i++) {
725 /* Top */
726 hx_safe_plot(grid, size, x - i, y, 0x11);
727 hx_safe_plot(grid, size, x - i - 1, y + 1, 0x10);
728 }
729
730 for (i = 1; i < h; i++) {
731 /* Right */
732 hx_safe_plot(grid, size, x, y + i, 0x11);
733 hx_safe_plot(grid, size, x - 1, y + i + 1, 0x10);
734 }
735 }
736
737 /* Plot assistant alignment patterns */
hx_plot_assistant(unsigned char * grid,int size,int x,int y)738 void hx_plot_assistant(unsigned char *grid, int size, int x, int y) {
739 hx_safe_plot(grid, size, x - 1, y - 1, 0x10);
740 hx_safe_plot(grid, size, x, y - 1, 0x10);
741 hx_safe_plot(grid, size, x + 1, y - 1, 0x10);
742 hx_safe_plot(grid, size, x - 1, y, 0x10);
743 hx_safe_plot(grid, size, x, y, 0x11);
744 hx_safe_plot(grid, size, x + 1, y, 0x10);
745 hx_safe_plot(grid, size, x - 1, y + 1, 0x10);
746 hx_safe_plot(grid, size, x, y + 1, 0x10);
747 hx_safe_plot(grid, size, x + 1, y + 1, 0x10);
748 }
749
750 /* Put static elements in the grid */
hx_setup_grid(unsigned char * grid,int size,int version)751 void hx_setup_grid(unsigned char* grid, int size, int version) {
752 int i, j;
753
754 for (i = 0; i < size; i++) {
755 for (j = 0; j < size; j++) {
756 grid[(i * size) + j] = 0;
757 }
758 }
759
760 /* Add finder patterns */
761 hx_place_finder_top_left(grid, size);
762 hx_place_finder(grid, size, 0, size - 7);
763 hx_place_finder(grid, size, size - 7, 0);
764 hx_place_finder_bottom_right(grid, size);
765
766 /* Add finder pattern separator region */
767 for (i = 0; i < 8; i++) {
768 /* Top left */
769 grid[(7 * size) + i] = 0x10;
770 grid[(i * size) + 7] = 0x10;
771
772 /* Top right */
773 grid[(7 * size) + (size - i - 1)] = 0x10;
774 grid[((size - i - 1) * size) + 7] = 0x10;
775
776 /* Bottom left */
777 grid[(i * size) + (size - 8)] = 0x10;
778 grid[((size - 8) * size) + i] = 0x10;
779
780 /* Bottom right */
781 grid[((size - 8) * size) + (size - i - 1)] = 0x10;
782 grid[((size - i - 1) * size) + (size - 8)] = 0x10;
783 }
784
785 /* Reserve function information region */
786 for (i = 0; i < 9; i++) {
787 /* Top left */
788 grid[(8 * size) + i] = 0x10;
789 grid[(i * size) + 8] = 0x10;
790
791 /* Top right */
792 grid[(8 * size) + (size - i - 1)] = 0x10;
793 grid[((size - i - 1) * size) + 8] = 0x10;
794
795 /* Bottom left */
796 grid[(i * size) + (size - 9)] = 0x10;
797 grid[((size - 9) * size) + i] = 0x10;
798
799 /* Bottom right */
800 grid[((size - 9) * size) + (size - i - 1)] = 0x10;
801 grid[((size - i - 1) * size) + (size - 9)] = 0x10;
802 }
803
804 if (version > 3) {
805 int k = hx_module_k[version - 1];
806 int r = hx_module_r[version - 1];
807 int m = hx_module_m[version - 1];
808 int x, y, row_switch, column_switch;
809 int module_height, module_width;
810 int mod_x, mod_y;
811
812 /* Add assistant alignment patterns to left and right */
813 y = 0;
814 mod_y = 0;
815 do {
816 if (mod_y < m) {
817 module_height = k;
818 } else {
819 module_height = r - 1;
820 }
821
822 if ((mod_y % 2) == 0) {
823 if ((m % 2) == 1) {
824 hx_plot_assistant(grid, size, 0, y);
825 }
826 } else {
827 if ((m % 2) == 0) {
828 hx_plot_assistant(grid, size, 0, y);
829 }
830 hx_plot_assistant(grid, size, size - 1, y);
831 }
832
833 mod_y++;
834 y += module_height;
835 } while (y < size);
836
837 /* Add assistant alignment patterns to top and bottom */
838 x = (size - 1);
839 mod_x = 0;
840 do {
841 if (mod_x < m) {
842 module_width = k;
843 } else {
844 module_width = r - 1;
845 }
846
847 if ((mod_x % 2) == 0) {
848 if ((m % 2) == 1) {
849 hx_plot_assistant(grid, size, x, (size - 1));
850 }
851 } else {
852 if ((m % 2) == 0) {
853 hx_plot_assistant(grid, size, x, (size - 1));
854 }
855 hx_plot_assistant(grid, size, x, 0);
856 }
857
858 mod_x++;
859 x -= module_width;
860 } while (x >= 0);
861
862 /* Add alignment pattern */
863 column_switch = 1;
864 y = 0;
865 mod_y = 0;
866 do {
867 if (mod_y < m) {
868 module_height = k;
869 } else {
870 module_height = r - 1;
871 }
872
873 if (column_switch == 1) {
874 row_switch = 1;
875 column_switch = 0;
876 } else {
877 row_switch = 0;
878 column_switch = 1;
879 }
880
881 x = (size - 1);
882 mod_x = 0;
883 do {
884 if (mod_x < m) {
885 module_width = k;
886 } else {
887 module_width = r - 1;
888 }
889
890 if (row_switch == 1) {
891 if (!(y == 0 && x == (size - 1))) {
892 hx_plot_alignment(grid, size, x, y, module_width, module_height);
893 }
894 row_switch = 0;
895 } else {
896 row_switch = 1;
897 }
898 mod_x++;
899 x -= module_width;
900 } while (x >= 0);
901
902 mod_y++;
903 y += module_height;
904 } while (y < size);
905 }
906 }
907
908 /* Calculate error correction codes */
hx_add_ecc(unsigned char fullstream[],unsigned char datastream[],int version,int ecc_level)909 void hx_add_ecc(unsigned char fullstream[], unsigned char datastream[], int version, int ecc_level) {
910 unsigned char data_block[180];
911 unsigned char ecc_block[36];
912 int i, j, block;
913 int batch_size, data_length, ecc_length;
914 int input_position = -1;
915 int output_position = -1;
916 int table_d1_pos = ((version - 1) * 36) + ((ecc_level - 1) * 9);
917
918 for (i = 0; i < 3; i++) {
919 batch_size = hx_table_d1[table_d1_pos + (3 * i)];
920 data_length = hx_table_d1[table_d1_pos + (3 * i) + 1];
921 ecc_length = hx_table_d1[table_d1_pos + (3 * i) + 2];
922
923 for (block = 0; block < batch_size; block++) {
924 for (j = 0; j < data_length; j++) {
925 input_position++;
926 output_position++;
927 data_block[j] = datastream[input_position];
928 fullstream[output_position] = datastream[input_position];
929 }
930
931 rs_init_gf(0x163); // x^8 + x^6 + x^5 + x + 1 = 0
932 rs_init_code(ecc_length, 1);
933 rs_encode(data_length, data_block, ecc_block);
934 rs_free();
935
936 for (j = 0; j < ecc_length; j++) {
937 output_position++;
938 fullstream[output_position] = ecc_block[ecc_length - j - 1];
939 }
940 }
941 }
942 }
943
944 /* Rearrange data in batches of 13 codewords (section 5.8.2) */
make_picket_fence(unsigned char fullstream[],unsigned char picket_fence[],int streamsize)945 void make_picket_fence(unsigned char fullstream[], unsigned char picket_fence[], int streamsize) {
946 int i, start;
947 int output_position = 0;
948
949 for (start = 0; start < 13; start++) {
950 for (i = start; i < streamsize; i += 13) {
951 if (i < streamsize) {
952 picket_fence[output_position] = fullstream[i];
953 output_position++;
954 }
955 }
956 }
957 }
958
959 /* Evaluate a bitmask according to table 9 */
hx_evaluate(unsigned char * eval,int size,int pattern)960 int hx_evaluate(unsigned char *eval, int size, int pattern) {
961 int x, y, block, weight;
962 int result = 0;
963 char state;
964 int p;
965 int a, b, afterCount, beforeCount;
966 #ifndef _MSC_VER
967 char local[size * size];
968 #else
969 char* local = (char *) _alloca((size * size) * sizeof (char));
970 #endif
971
972 /* all four bitmask variants have been encoded in the 4 bits of the bytes
973 * that make up the grid array. select them for evaluation according to the
974 * desired pattern.*/
975 for (x = 0; x < size; x++) {
976 for (y = 0; y < size; y++) {
977 if ((eval[(y * size) + x] & (0x01 << pattern)) != 0) {
978 local[(y * size) + x] = '1';
979 } else {
980 local[(y * size) + x] = '0';
981 }
982 }
983 }
984
985 /* Test 1: 1:1:1:1:3 or 3:1:1:1:1 ratio pattern in row/column */
986 /* Vertical */
987 for (x = 0; x < size; x++) {
988 for (y = 0; y < (size - 7); y++) {
989 p = 0;
990 for (weight = 0; weight < 7; weight++) {
991 if (local[((y + weight) * size) + x] == '1') {
992 p += (0x40 >> weight);
993 }
994 }
995 if ((p == 0x57) || (p == 0x75)) {
996 /* Pattern found, check before and after */
997 beforeCount = 0;
998 for (b = (y - 3); b < y; b++) {
999 if (b < 0) {
1000 beforeCount++;
1001 } else {
1002 if (local[(b * size) + x] == '0') {
1003 beforeCount++;
1004 } else {
1005 beforeCount = 0;
1006 }
1007 }
1008 }
1009
1010 afterCount = 0;
1011 for (a = (y + 7); a <= (y + 9); a++) {
1012 if (a >= size) {
1013 afterCount++;
1014 } else {
1015 if (local[(a * size) + x] == '0') {
1016 afterCount++;
1017 } else {
1018 afterCount = 0;
1019 }
1020 }
1021 }
1022
1023 if ((beforeCount == 3) || (afterCount == 3)) {
1024 /* Pattern is preceeded or followed by light area
1025 3 modules wide */
1026 result += 50;
1027 }
1028 }
1029 }
1030 }
1031
1032 /* Horizontal */
1033 for (y = 0; y < size; y++) {
1034 for (x = 0; x < (size - 7); x++) {
1035 p = 0;
1036 for (weight = 0; weight < 7; weight++) {
1037 if (local[(y * size) + x + weight] == '1') {
1038 p += (0x40 >> weight);
1039 }
1040 }
1041 if ((p == 0x57) || (p == 0x75)) {
1042 /* Pattern found, check before and after */
1043 beforeCount = 0;
1044 for (b = (x - 3); b < x; b++) {
1045 if (b < 0) {
1046 beforeCount++;
1047 } else {
1048 if (local[(y * size) + b] == '0') {
1049 beforeCount++;
1050 } else {
1051 beforeCount = 0;
1052 }
1053 }
1054 }
1055
1056 afterCount = 0;
1057 for (a = (x + 7); a <= (x + 9); a++) {
1058 if (a >= size) {
1059 afterCount++;
1060 } else {
1061 if (local[(y * size) + a] == '0') {
1062 afterCount++;
1063 } else {
1064 afterCount = 0;
1065 }
1066 }
1067 }
1068
1069 if ((beforeCount == 3) || (afterCount == 3)) {
1070 /* Pattern is preceeded or followed by light area
1071 3 modules wide */
1072 result += 50;
1073 }
1074 }
1075 }
1076 }
1077
1078 /* Test 2: Adjacent modules in row/column in same colour */
1079 /* In AIMD-15 section 5.8.3.2 it is stated... “In Table 9 below, i refers to the row
1080 * position of the module.” - however i being the length of the run of the
1081 * same colour (i.e. "block" below) in the same fashion as ISO/IEC 18004
1082 * makes more sense. -- Confirmed by Wang Yi */
1083
1084 /* Vertical */
1085 for (x = 0; x < size; x++) {
1086 state = local[x];
1087 block = 0;
1088 for (y = 0; y < size; y++) {
1089 if (local[(y * size) + x] == state) {
1090 block++;
1091 } else {
1092 if (block > 3) {
1093 result += (3 + block) * 4;
1094 }
1095 block = 0;
1096 state = local[(y * size) + x];
1097 }
1098 }
1099 if (block > 3) {
1100 result += (3 + block) * 4;
1101 }
1102 }
1103
1104 /* Horizontal */
1105 for (y = 0; y < size; y++) {
1106 state = local[y * size];
1107 block = 0;
1108 for (x = 0; x < size; x++) {
1109 if (local[(y * size) + x] == state) {
1110 block++;
1111 } else {
1112 if (block > 3) {
1113 result += (3 + block) * 4;
1114 }
1115 block = 0;
1116 state = local[(y * size) + x];
1117 }
1118 }
1119 if (block > 3) {
1120 result += (3 + block) * 4;
1121 }
1122 }
1123
1124 return result;
1125 }
1126
1127 /* Apply the four possible bitmasks for evaluation */
hx_apply_bitmask(unsigned char * grid,int size)1128 int hx_apply_bitmask(unsigned char *grid, int size) {
1129 int x, y;
1130 int i, j;
1131 int pattern, penalty[4];
1132 int best_pattern, best_val;
1133 int bit;
1134 unsigned char p;
1135
1136 #ifndef _MSC_VER
1137 unsigned char mask[size * size];
1138 unsigned char eval[size * size];
1139 #else
1140 unsigned char* mask = (unsigned char *) _alloca((size * size) * sizeof (unsigned char));
1141 unsigned char* eval = (unsigned char *) _alloca((size * size) * sizeof (unsigned char));
1142 #endif
1143
1144 /* Perform data masking */
1145 for (x = 0; x < size; x++) {
1146 for (y = 0; y < size; y++) {
1147 mask[(y * size) + x] = 0x00;
1148 j = x + 1;
1149 i = y + 1;
1150
1151 if (!(grid[(y * size) + x] & 0xf0)) {
1152 if ((i + j) % 2 == 0) {
1153 mask[(y * size) + x] += 0x02;
1154 }
1155 if ((((i + j) % 3) + (j % 3)) % 2 == 0) {
1156 mask[(y * size) + x] += 0x04;
1157 }
1158 if (((i % j) + (j % i) + (i % 3) + (j % 3)) % 2 == 0) {
1159 mask[(y * size) + x] += 0x08;
1160 }
1161 }
1162 }
1163 }
1164
1165 // apply data masks to grid, result in eval
1166 for (x = 0; x < size; x++) {
1167 for (y = 0; y < size; y++) {
1168 if (grid[(y * size) + x] & 0x01) {
1169 p = 0xff;
1170 } else {
1171 p = 0x00;
1172 }
1173
1174 eval[(y * size) + x] = mask[(y * size) + x] ^ p;
1175 }
1176 }
1177
1178 /* Evaluate result */
1179 for (pattern = 0; pattern < 4; pattern++) {
1180 penalty[pattern] = hx_evaluate(eval, size, pattern);
1181 }
1182
1183 best_pattern = 0;
1184 best_val = penalty[0];
1185 for (pattern = 1; pattern < 4; pattern++) {
1186 if (penalty[pattern] < best_val) {
1187 best_pattern = pattern;
1188 best_val = penalty[pattern];
1189 }
1190 }
1191
1192 /* Apply mask */
1193 for (x = 0; x < size; x++) {
1194 for (y = 0; y < size; y++) {
1195 bit = 0;
1196 switch (best_pattern) {
1197 case 0: if (mask[(y * size) + x] & 0x01) {
1198 bit = 1;
1199 }
1200 break;
1201 case 1: if (mask[(y * size) + x] & 0x02) {
1202 bit = 1;
1203 }
1204 break;
1205 case 2: if (mask[(y * size) + x] & 0x04) {
1206 bit = 1;
1207 }
1208 break;
1209 case 3: if (mask[(y * size) + x] & 0x08) {
1210 bit = 1;
1211 }
1212 break;
1213 }
1214 if (bit == 1) {
1215 if (grid[(y * size) + x] & 0x01) {
1216 grid[(y * size) + x] = 0x00;
1217 } else {
1218 grid[(y * size) + x] = 0x01;
1219 }
1220 }
1221 }
1222 }
1223
1224 return best_pattern;
1225 }
1226
1227 /* Han Xin Code - main */
han_xin(struct zint_symbol * symbol,const unsigned char source[],size_t length)1228 int han_xin(struct zint_symbol *symbol, const unsigned char source[], size_t length) {
1229 int est_binlen;
1230 int ecc_level = symbol->option_1;
1231 int i, j, version, posn = 0;
1232 int data_codewords = 0, size;
1233 int codewords;
1234 int bitmask;
1235 int error_number;
1236 int bin_len;
1237 int done;
1238 char function_information[36];
1239 unsigned char fi_cw[3] = {0, 0, 0};
1240 unsigned char fi_ecc[4];
1241
1242 #ifndef _MSC_VER
1243 int utfdata[length + 1];
1244 int gbdata[(length + 1) * 2];
1245 char mode[length + 1];
1246 #else
1247 int* utfdata = (int *) _alloca((length + 1) * sizeof (int));
1248 int* gbdata = (int *) _alloca(((length + 1) * 2) * sizeof (int));
1249 char* mode = (char *) _alloca((length + 1) * sizeof (char));
1250 char* binary;
1251 unsigned char *datastream;
1252 unsigned char *fullstream;
1253 unsigned char *picket_fence;
1254 unsigned char *grid;
1255 #endif
1256
1257 if ((symbol->input_mode == DATA_MODE) || (symbol->eci != 3)) {
1258 for (i = 0; i < length; i++) {
1259 gbdata[i] = (int) source[i];
1260 }
1261 } else {
1262 /* Convert Unicode input to GB-18030 */
1263 error_number = utf8toutf16(symbol, source, utfdata, &length);
1264 if (error_number != 0) {
1265 return error_number;
1266 }
1267
1268 posn = 0;
1269 for (i = 0; i < length; i++) {
1270 done = 0;
1271 gbdata[posn] = 0;
1272
1273 /* Single byte characters in range U+0000 -> U+007F */
1274 if (utfdata[i] <= 0x7f) {
1275 gbdata[posn] = utfdata[i];
1276 posn++;
1277 done = 1;
1278 }
1279
1280 /* Two bytes characters in GB-2312 */
1281 if (done == 0) {
1282 j = 0;
1283 do {
1284 if (gb2312_lookup[j * 2] == utfdata[i]) {
1285 gbdata[posn] = gb2312_lookup[(j * 2) + 1];
1286 posn++;
1287 done = 1;
1288 }
1289 j++;
1290 } while ((j < 7445) && (done == 0));
1291 }
1292
1293 /* Two byte characters in GB-18030 */
1294 if (done == 0) {
1295 j = 0;
1296 do {
1297 if (gb18030_twobyte_lookup[j * 2] == utfdata[i]) {
1298 gbdata[posn] = gb18030_twobyte_lookup[(j * 2) + 1];
1299 posn++;
1300 done = 1;
1301 }
1302 j++;
1303 } while ((j < 16495) && (done == 0));
1304 }
1305
1306 /* Four byte characters in range U+0080 -> U+FFFF */
1307 if (done == 0) {
1308 j = 0;
1309 do {
1310 if (gb18030_fourbyte_lookup[j * 3] == utfdata[i]) {
1311 gbdata[posn] = gb18030_fourbyte_lookup[(j * 3) + 1];
1312 gbdata[posn + 1] = gb18030_fourbyte_lookup[(j * 3) + 2];
1313 posn += 2;
1314 done = 1;
1315 }
1316 j++;
1317 } while ((j < 6793) && (done == 0));
1318 }
1319
1320 /* Supplementary planes U+10000 -> U+1FFFF */
1321 if (done == 0) {
1322 if (utfdata[i] >= 0x10000 && utfdata[i] < 0x110000) {
1323 /* algorithm from libiconv-1.15\lib\gb18030.h */
1324 int j, r3, r2, r1, r0;
1325
1326 j = utfdata[i] - 0x10000;
1327 r3 = (j % 10) + 0x30; j = j / 10;
1328 r2 = (j % 126) + 0x81; j = j / 126;
1329 r1 = (j % 10) + 0x30; j = j / 10;
1330 r0 = j + 0x90;
1331 gbdata[posn] = (r0 << 8) + r1;
1332 gbdata[posn + 1] = (r2 << 8) + r3;
1333 posn += 2;
1334 done = 1;
1335 }
1336 }
1337
1338 /* Character not found */
1339 if (done == 0) {
1340 strcpy(symbol->errtxt, "540: Unknown character in input data");
1341 return ZINT_ERROR_INVALID_DATA;
1342 }
1343 }
1344 length = posn;
1345 }
1346
1347 hx_define_mode(mode, gbdata, length);
1348
1349 est_binlen = calculate_binlength(mode, gbdata, length, symbol->eci);
1350
1351 #ifndef _MSC_VER
1352 char binary[est_binlen + 10];
1353 #else
1354 binary = (char *) _alloca((est_binlen + 10) * sizeof (char));
1355 #endif
1356 memset(binary, 0, (est_binlen + 1) * sizeof (char));
1357
1358 if ((ecc_level <= 0) || (ecc_level >= 5)) {
1359 ecc_level = 1;
1360 }
1361
1362 calculate_binary(binary, mode, gbdata, length, symbol->eci, symbol->debug);
1363 bin_len = strlen(binary);
1364 codewords = bin_len / 8;
1365 if (bin_len % 8 != 0) {
1366 codewords++;
1367 }
1368
1369 version = 85;
1370 for (i = 84; i > 0; i--) {
1371 switch (ecc_level) {
1372 case 1:
1373 if (hx_data_codewords_L1[i - 1] > codewords) {
1374 version = i;
1375 data_codewords = hx_data_codewords_L1[i - 1];
1376 }
1377 break;
1378 case 2:
1379 if (hx_data_codewords_L2[i - 1] > codewords) {
1380 version = i;
1381 data_codewords = hx_data_codewords_L2[i - 1];
1382 }
1383 break;
1384 case 3:
1385 if (hx_data_codewords_L3[i - 1] > codewords) {
1386 version = i;
1387 data_codewords = hx_data_codewords_L3[i - 1];
1388 }
1389 break;
1390 case 4:
1391 if (hx_data_codewords_L4[i - 1] > codewords) {
1392 version = i;
1393 data_codewords = hx_data_codewords_L4[i - 1];
1394 }
1395 break;
1396 default:
1397 assert(0);
1398 break;
1399 }
1400 }
1401
1402 if (version == 85) {
1403 strcpy(symbol->errtxt, "541: Input too long for selected error correction level");
1404 return ZINT_ERROR_TOO_LONG;
1405 }
1406
1407 if ((symbol->option_2 < 0) || (symbol->option_2 > 84)) {
1408 symbol->option_2 = 0;
1409 }
1410
1411 if (symbol->option_2 > version) {
1412 version = symbol->option_2;
1413 }
1414
1415 if ((symbol->option_2 != 0) && (symbol->option_2 < version)) {
1416 strcpy(symbol->errtxt, "542: Input too long for selected symbol size");
1417 return ZINT_ERROR_TOO_LONG;
1418 }
1419
1420 /* If there is spare capacity, increase the level of ECC */
1421
1422 if ((ecc_level == 1) && (codewords < hx_data_codewords_L2[version - 1])) {
1423 ecc_level = 2;
1424 data_codewords = hx_data_codewords_L2[version - 1];
1425 }
1426
1427 if ((ecc_level == 2) && (codewords < hx_data_codewords_L3[version - 1])) {
1428 ecc_level = 3;
1429 data_codewords = hx_data_codewords_L3[version - 1];
1430 }
1431
1432 if ((ecc_level == 3) && (codewords < hx_data_codewords_L4[version - 1])) {
1433 ecc_level = 4;
1434 data_codewords = hx_data_codewords_L4[version - 1];
1435 }
1436
1437 //printf("Version %d, ECC %d\n", version, ecc_level);
1438
1439 size = (version * 2) + 21;
1440
1441 #ifndef _MSC_VER
1442 unsigned char datastream[data_codewords];
1443 unsigned char fullstream[hx_total_codewords[version - 1]];
1444 unsigned char picket_fence[hx_total_codewords[version - 1]];
1445 unsigned char grid[size * size];
1446 #else
1447 datastream = (unsigned char *) _alloca((data_codewords) * sizeof (unsigned char));
1448 fullstream = (unsigned char *) _alloca((hx_total_codewords[version - 1]) * sizeof (unsigned char));
1449 picket_fence = (unsigned char *) _alloca((hx_total_codewords[version - 1]) * sizeof (unsigned char));
1450 grid = (unsigned char *) _alloca((size * size) * sizeof (unsigned char));
1451 #endif
1452
1453 for (i = 0; i < data_codewords; i++) {
1454 datastream[i] = 0;
1455 }
1456
1457 for (i = 0; i < bin_len; i++) {
1458 if (binary[i] == '1') {
1459 datastream[i / 8] += 0x80 >> (i % 8);
1460 }
1461 }
1462
1463 hx_setup_grid(grid, size, version);
1464
1465 hx_add_ecc(fullstream, datastream, version, ecc_level);
1466
1467 make_picket_fence(fullstream, picket_fence, hx_total_codewords[version - 1]);
1468
1469 /* Populate grid */
1470 j = 0;
1471 for (i = 0; i < (size * size); i++) {
1472 if (grid[i] == 0x00) {
1473 if (j < (hx_total_codewords[version - 1] * 8)) {
1474 if (picket_fence[(j / 8)] & (0x80 >> (j % 8))) {
1475 grid[i] = 0x01;
1476 }
1477 j++;
1478 }
1479 }
1480 }
1481
1482 bitmask = hx_apply_bitmask(grid, size);
1483
1484 /* Form function information string */
1485 for (i = 0; i < 34; i++) {
1486 if (i % 2) {
1487 function_information[i] = '1';
1488 } else {
1489 function_information[i] = '0';
1490 }
1491 }
1492 function_information[34] = '\0';
1493
1494 for (i = 0; i < 8; i++) {
1495 if ((version + 20) & (0x80 >> i)) {
1496 function_information[i] = '1';
1497 } else {
1498 function_information[i] = '0';
1499 }
1500 }
1501
1502 for (i = 0; i < 2; i++) {
1503 if ((ecc_level - 1) & (0x02 >> i)) {
1504 function_information[i + 8] = '1';
1505 } else {
1506 function_information[i + 8] = '0';
1507 }
1508 }
1509
1510 for (i = 0; i < 2; i++) {
1511 if (bitmask & (0x02 >> i)) {
1512 function_information[i + 10] = '1';
1513 } else {
1514 function_information[i + 10] = '0';
1515 }
1516 }
1517
1518
1519
1520 for (i = 0; i < 3; i++) {
1521 for (j = 0; j < 4; j++) {
1522 if (function_information[(i * 4) + j] == '1') {
1523 fi_cw[i] += (0x08 >> j);
1524 }
1525 }
1526 }
1527
1528 rs_init_gf(0x13);
1529 rs_init_code(4, 1);
1530 rs_encode(3, fi_cw, fi_ecc);
1531 rs_free();
1532
1533 for (i = 0; i < 4; i++) {
1534 for (j = 0; j < 4; j++) {
1535 if (fi_ecc[3 - i] & (0x08 >> j)) {
1536 function_information[(i * 4) + j + 12] = '1';
1537 } else {
1538 function_information[(i * 4) + j + 12] = '0';
1539 }
1540 }
1541 }
1542
1543 /* Add function information to symbol */
1544 for (i = 0; i < 9; i++) {
1545 if (function_information[i] == '1') {
1546 grid[(8 * size) + i] = 0x01;
1547 grid[((size - 8 - 1) * size) + (size - i - 1)] = 0x01;
1548 }
1549 if (function_information[i + 8] == '1') {
1550 grid[((8 - i) * size) + 8] = 0x01;
1551 grid[((size - 8 - 1 + i) * size) + (size - 8 - 1)] = 0x01;
1552 }
1553 if (function_information[i + 17] == '1') {
1554 grid[(i * size) + (size - 1 - 8)] = 0x01;
1555 grid[((size - 1 - i) * size) + 8] = 0x01;
1556 }
1557 if (function_information[i + 25] == '1') {
1558 grid[(8 * size) + (size - 1 - 8 + i)] = 0x01;
1559 grid[((size - 1 - 8) * size) + (8 - i)] = 0x01;
1560 }
1561 }
1562
1563 symbol->width = size;
1564 symbol->rows = size;
1565
1566 for (i = 0; i < size; i++) {
1567 for (j = 0; j < size; j++) {
1568 if (grid[(i * size) + j] & 0x01) {
1569 set_module(symbol, i, j);
1570 }
1571 }
1572 symbol->row_height[i] = 1;
1573 }
1574
1575 return 0;
1576 }
1577