comparison mupdf-source/thirdparty/zint/backend/aztec.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 /* aztec.c - Handles Aztec 2D Symbols */
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 #include <assert.h>
34 #include <stdio.h>
35 #include "common.h"
36 #include "aztec.h"
37 #include "reedsol.h"
38
39 #define AZTEC_MAX_CAPACITY 19968 /* ISO/IEC 24778:2008 5.3 Table 1 Maximum Symbol Bit Capacity */
40 /* Allow up to absolute minimum 3 ECC codewords, but now warn if results in less than the 5% minimum (ISO/IEC
41 24778:2008 4.1.e) - previously could go down to 3 ECC codewords anyway if version given, due to bit-stuffing */
42 #define AZTEC_BIN_CAPACITY 19932 /* AZTEC_MAX_CAPACITY less 3 * 12 = 36 */
43 #define AZTEC_MAP_SIZE 22801 /* AztecMap Version 32 151 x 151 */
44 #define AZTEC_MAP_POSN_MAX 20039 /* Maximum position index in AztecMap */
45
46 #define AZ_BIN_CAP_CWDS_S "1661" /* String version of (AZTEC_BIN_CAPACITY / 12) */
47
48 /* Count number of consecutive (. SP) or (, SP) Punct mode doubles for comparison against Digit mode encoding */
49 static int az_count_doubles(const unsigned char source[], int i, const int length) {
50 int c = 0;
51
52 while ((i + 1 < length) && ((source[i] == '.') || (source[i] == ',')) && (source[i + 1] == ' ')) {
53 c++;
54 i += 2;
55 }
56
57 return c;
58 }
59
60 /* Count number of consecutive full stops or commas (can be encoded in Punct or Digit mode) */
61 static int az_count_dotcomma(const unsigned char source[], int i, const int length) {
62 int c = 0;
63
64 while (i < length && ((source[i] == '.') || (source[i] == ','))) {
65 c++;
66 i++;
67 }
68
69 return c;
70 }
71
72 /* Count number of consecutive `chr`s */
73 static int az_count_chr(const unsigned char source[], int i, const int length, const unsigned char chr) {
74 int c = 0;
75
76 while (i < length && source[i] == chr) {
77 c++;
78 i++;
79 }
80
81 return c;
82 }
83
84 /* Return mode following current, or 'E' if none */
85 static char az_get_next_mode(const char encode_mode[], const int src_len, int i) {
86 int current_mode = encode_mode[i];
87
88 do {
89 i++;
90 } while ((i < src_len) && (encode_mode[i] == current_mode));
91 if (i >= src_len) {
92 return 'E';
93 } else {
94 return encode_mode[i];
95 }
96 }
97
98 /* Same as `bin_append_posn()`, except check for buffer overflow first */
99 static int az_bin_append_posn(const int arg, const int length, char *binary, const int bin_posn) {
100
101 if (bin_posn + length > AZTEC_BIN_CAPACITY) {
102 return 0; /* Fail */
103 }
104 return bin_append_posn(arg, length, binary, bin_posn);
105 }
106
107 /* Determine encoding modes and encode */
108 static int aztec_text_process(const unsigned char source[], int src_len, int bp, char binary_string[], const int gs1,
109 const int eci, char *p_current_mode, int *data_length, const int debug_print) {
110
111 int i, j;
112 const char initial_mode = p_current_mode ? *p_current_mode : 'U';
113 char current_mode;
114 int count;
115 char next_mode;
116 int reduced_length;
117 char *encode_mode = (char *) z_alloca(src_len + 1);
118 unsigned char *reduced_source = (unsigned char *) z_alloca(src_len + 1);
119 char *reduced_encode_mode = (char *) z_alloca(src_len + 1);
120
121 for (i = 0; i < src_len; i++) {
122 if (source[i] >= 128) {
123 encode_mode[i] = 'B';
124 } else if (gs1 && source[i] == '\x1D') {
125 encode_mode[i] = 'P'; /* For FLG(n) & FLG(0) = FNC1 */
126 } else {
127 encode_mode[i] = AztecModes[source[i]];
128 }
129 }
130
131 /* Deal first with letter combinations which can be combined to one codeword
132 Combinations are (CR LF) (. SP) (, SP) (: SP) in Punct mode */
133 current_mode = initial_mode;
134 for (i = 0; i + 1 < src_len; i++) {
135 /* Combination (CR LF) should always be in Punct mode */
136 if ((source[i] == 13) && (source[i + 1] == 10)) {
137 encode_mode[i] = 'P';
138 encode_mode[i + 1] = 'P';
139
140 /* Combination (: SP) should always be in Punct mode */
141 } else if ((source[i] == ':') && (source[i + 1] == ' ')) {
142 encode_mode[i + 1] = 'P';
143
144 /* Combinations (. SP) and (, SP) sometimes use fewer bits in Digit mode */
145 } else if (((source[i] == '.') || (source[i] == ',')) && (source[i + 1] == ' ') && (encode_mode[i] == 'X')) {
146 count = az_count_doubles(source, i, src_len);
147 next_mode = az_get_next_mode(encode_mode, src_len, i);
148
149 if (current_mode == 'U') {
150 if ((next_mode == 'D') && (count <= 5)) {
151 memset(encode_mode + i, 'D', 2 * count);
152 }
153
154 } else if (current_mode == 'L') {
155 if ((next_mode == 'D') && (count <= 4)) {
156 memset(encode_mode + i, 'D', 2 * count);
157 }
158
159 } else if (current_mode == 'M') {
160 if ((next_mode == 'D') && (count == 1)) {
161 encode_mode[i] = 'D';
162 encode_mode[i + 1] = 'D';
163 }
164
165 } else if (current_mode == 'D') {
166 if ((next_mode != 'D') && (count <= 4)) {
167 memset(encode_mode + i, 'D', 2 * count);
168 } else if ((next_mode == 'D') && (count <= 7)) {
169 memset(encode_mode + i, 'D', 2 * count);
170 }
171 }
172
173 /* Default is Punct mode */
174 if (encode_mode[i] == 'X') {
175 encode_mode[i] = 'P';
176 encode_mode[i + 1] = 'P';
177 }
178 }
179
180 if ((encode_mode[i] != 'X') && (encode_mode[i] != 'B')) {
181 current_mode = encode_mode[i];
182 }
183 }
184
185 if (debug_print) {
186 fputs("First Pass:\n", stdout);
187 printf("%.*s\n", src_len, encode_mode);
188 }
189
190 /* Reduce two letter combinations to one codeword marked as [abcd] in Punct mode */
191 i = 0;
192 j = 0;
193 while (i < src_len) {
194 reduced_encode_mode[j] = encode_mode[i];
195 if (i + 1 < src_len) {
196 if ((source[i] == 13) && (source[i + 1] == 10)) { /* CR LF */
197 reduced_source[j] = 'a';
198 i += 2;
199 } else if ((source[i] == '.') && (source[i + 1] == ' ') && (encode_mode[i] == 'P')) {
200 reduced_source[j] = 'b';
201 i += 2;
202 } else if ((source[i] == ',') && (source[i + 1] == ' ') && (encode_mode[i] == 'P')) {
203 reduced_source[j] = 'c';
204 i += 2;
205 } else if ((source[i] == ':') && (source[i + 1] == ' ')) {
206 reduced_source[j] = 'd';
207 i += 2;
208 } else {
209 reduced_source[j] = source[i++];
210 }
211 } else {
212 reduced_source[j] = source[i++];
213 }
214 j++;
215 }
216
217 reduced_length = j;
218
219 current_mode = initial_mode;
220 for (i = 0; i < reduced_length; i++) {
221 /* Resolve Carriage Return (CR) which can be Punct or Mixed mode */
222 if (reduced_source[i] == 13) {
223 count = az_count_chr(reduced_source, i, reduced_length, 13);
224 next_mode = az_get_next_mode(reduced_encode_mode, reduced_length, i);
225
226 if ((current_mode == 'U') && ((next_mode == 'U') || (next_mode == 'B')) && (count == 1)) {
227 reduced_encode_mode[i] = 'P';
228
229 } else if ((current_mode == 'L') && ((next_mode == 'L') || (next_mode == 'B')) && (count == 1)) {
230 reduced_encode_mode[i] = 'P';
231
232 } else if ((current_mode == 'P') || (next_mode == 'P')) {
233 reduced_encode_mode[i] = 'P';
234 }
235
236 if (current_mode == 'D') {
237 if (((next_mode == 'E') || (next_mode == 'U') || (next_mode == 'D') || (next_mode == 'B'))
238 && (count <= 2)) {
239 memset(reduced_encode_mode + i, 'P', count);
240 } else if ((next_mode == 'L') && (count == 1)) {
241 reduced_encode_mode[i] = 'P';
242 }
243 }
244
245 /* Default is Mixed mode */
246 if (reduced_encode_mode[i] == 'X') {
247 reduced_encode_mode[i] = 'M';
248 }
249
250 /* Resolve full stop and comma which can be in Punct or Digit mode */
251 } else if ((reduced_source[i] == '.') || (reduced_source[i] == ',')) {
252 count = az_count_dotcomma(reduced_source, i, reduced_length);
253 next_mode = az_get_next_mode(reduced_encode_mode, reduced_length, i);
254
255 if (current_mode == 'U') {
256 if (((next_mode == 'U') || (next_mode == 'L') || (next_mode == 'M') || (next_mode == 'B'))
257 && (count == 1)) {
258 reduced_encode_mode[i] = 'P';
259 }
260
261 } else if (current_mode == 'L') {
262 if ((next_mode == 'L') && (count <= 2)) {
263 memset(reduced_encode_mode + i, 'P', count);
264 } else if (((next_mode == 'M') || (next_mode == 'B')) && (count == 1)) {
265 reduced_encode_mode[i] = 'P';
266 }
267
268 } else if (current_mode == 'M') {
269 if (((next_mode == 'E') || (next_mode == 'U') || (next_mode == 'L') || (next_mode == 'M'))
270 && (count <= 4)) {
271 memset(reduced_encode_mode + i, 'P', count);
272 } else if ((next_mode == 'B') && (count <= 2)) {
273 memset(reduced_encode_mode + i, 'P', count);
274 }
275
276 } else if ((current_mode == 'P') && (next_mode != 'D') && (count <= 9)) {
277 memset(reduced_encode_mode + i, 'P', count);
278 }
279
280 /* Default is Digit mode */
281 if (reduced_encode_mode[i] == 'X') {
282 reduced_encode_mode[i] = 'D';
283 }
284
285 /* Resolve Space (SP) which can be any mode except Punct */
286 } else if (reduced_source[i] == ' ') {
287 count = az_count_chr(reduced_source, i, reduced_length, ' ');
288 next_mode = az_get_next_mode(reduced_encode_mode, reduced_length, i);
289
290 if (current_mode == 'U') {
291 if ((next_mode == 'E') && (count <= 5)) {
292 memset(reduced_encode_mode + i, 'U', count);
293 } else if (((next_mode == 'U') || (next_mode == 'L') || (next_mode == 'M') || (next_mode == 'P')
294 || (next_mode == 'B')) && (count <= 9)) {
295 memset(reduced_encode_mode + i, 'U', count);
296 }
297
298 } else if (current_mode == 'L') {
299 if ((next_mode == 'E') && (count <= 5)) {
300 memset(reduced_encode_mode + i, 'L', count);
301
302 } else if ((next_mode == 'U') && (count == 1)) {
303 reduced_encode_mode[i] = 'L';
304
305 } else if ((next_mode == 'L') && (count <= 14)) {
306 memset(reduced_encode_mode + i, 'L', count);
307
308 } else if (((next_mode == 'M') || (next_mode == 'P') || (next_mode == 'B')) && (count <= 9)) {
309 memset(reduced_encode_mode + i, 'L', count);
310 }
311
312 } else if (current_mode == 'M') {
313 if (((next_mode == 'E') || (next_mode == 'U')) && (count <= 9)) {
314 memset(reduced_encode_mode + i, 'M', count);
315
316 } else if (((next_mode == 'L') || (next_mode == 'B')) && (count <= 14)) {
317 memset(reduced_encode_mode + i, 'M', count);
318
319 } else if (((next_mode == 'M') || (next_mode == 'P')) && (count <= 19)) {
320 memset(reduced_encode_mode + i, 'M', count);
321 }
322
323 } else if (current_mode == 'P') {
324 if ((next_mode == 'E') && (count <= 5)) {
325 memset(reduced_encode_mode + i, 'U', count);
326
327 } else if (((next_mode == 'U') || (next_mode == 'L') || (next_mode == 'M') || (next_mode == 'P')
328 || (next_mode == 'B')) && (count <= 9)) {
329 memset(reduced_encode_mode + i, 'U', count);
330 }
331 }
332
333 /* Default is Digit mode */
334 if (reduced_encode_mode[i] == 'X') {
335 reduced_encode_mode[i] = 'D';
336 }
337 }
338
339 if (reduced_encode_mode[i] != 'B') {
340 current_mode = reduced_encode_mode[i];
341 }
342 }
343
344 /* Decide when to use P/S instead of P/L and U/S instead of U/L */
345 current_mode = initial_mode;
346 for (i = 0; i < reduced_length; i++) {
347
348 if (reduced_encode_mode[i] != current_mode) {
349
350 for (count = 0; ((i + count) < reduced_length)
351 && (reduced_encode_mode[i + count] == reduced_encode_mode[i]); count++);
352 next_mode = az_get_next_mode(reduced_encode_mode, reduced_length, i);
353
354 if (reduced_encode_mode[i] == 'P') {
355 if ((current_mode == 'U') && (count <= 2)) {
356 memset(reduced_encode_mode + i, 'p', count);
357
358 } else if ((current_mode == 'L') && (next_mode != 'U') && (count <= 2)) {
359 memset(reduced_encode_mode + i, 'p', count);
360
361 } else if ((current_mode == 'L') && (next_mode == 'U') && (count == 1)) {
362 reduced_encode_mode[i] = 'p';
363
364 } else if ((current_mode == 'M') && (next_mode != 'M') && (count == 1)) {
365 reduced_encode_mode[i] = 'p';
366
367 } else if ((current_mode == 'M') && (next_mode == 'M') && (count <= 2)) {
368 memset(reduced_encode_mode + i, 'p', count);
369
370 } else if ((current_mode == 'D') && (next_mode != 'D') && (count <= 3)) {
371 memset(reduced_encode_mode + i, 'p', count);
372
373 } else if ((current_mode == 'D') && (next_mode == 'D') && (count <= 6)) {
374 memset(reduced_encode_mode + i, 'p', count);
375 }
376
377 } else if (reduced_encode_mode[i] == 'U') {
378 if ((current_mode == 'L') && ((next_mode == 'L') || (next_mode == 'M')) && (count <= 2)) {
379 memset(reduced_encode_mode + i, 'u', count);
380
381 } else if ((current_mode == 'L') && ((next_mode == 'E') || (next_mode == 'D') || (next_mode == 'B')
382 || (next_mode == 'P')) && (count == 1)) {
383 reduced_encode_mode[i] = 'u';
384
385 } else if ((current_mode == 'D') && (next_mode == 'D') && (count == 1)) {
386 reduced_encode_mode[i] = 'u';
387
388 } else if ((current_mode == 'D') && (next_mode == 'P') && (count <= 2)) {
389 memset(reduced_encode_mode + i, 'u', count);
390 }
391 }
392 }
393
394 if ((reduced_encode_mode[i] != 'p') && (reduced_encode_mode[i] != 'u') && (reduced_encode_mode[i] != 'B')) {
395 current_mode = reduced_encode_mode[i];
396 }
397 }
398
399 if (debug_print) {
400 printf("%.*s\n", reduced_length, reduced_source);
401 printf("%.*s\n", reduced_length, reduced_encode_mode);
402 }
403
404 if (bp == 0 && gs1) {
405 bp = bin_append_posn(0, 5, binary_string, bp); /* P/S */
406 bp = bin_append_posn(0, 5, binary_string, bp); /* FLG(n) */
407 bp = bin_append_posn(0, 3, binary_string, bp); /* FLG(0) */
408 }
409
410 if (eci != 0) {
411 bp = bin_append_posn(0, initial_mode == 'D' ? 4 : 5, binary_string, bp); /* P/S */
412 bp = bin_append_posn(0, 5, binary_string, bp); /* FLG(n) */
413 if (eci < 10) {
414 bp = bin_append_posn(1, 3, binary_string, bp); /* FLG(1) */
415 bp = bin_append_posn(2 + eci, 4, binary_string, bp);
416 } else if (eci <= 99) {
417 bp = bin_append_posn(2, 3, binary_string, bp); /* FLG(2) */
418 bp = bin_append_posn(2 + (eci / 10), 4, binary_string, bp);
419 bp = bin_append_posn(2 + (eci % 10), 4, binary_string, bp);
420 } else if (eci <= 999) {
421 bp = bin_append_posn(3, 3, binary_string, bp); /* FLG(3) */
422 bp = bin_append_posn(2 + (eci / 100), 4, binary_string, bp);
423 bp = bin_append_posn(2 + ((eci % 100) / 10), 4, binary_string, bp);
424 bp = bin_append_posn(2 + (eci % 10), 4, binary_string, bp);
425 } else if (eci <= 9999) {
426 bp = bin_append_posn(4, 3, binary_string, bp); /* FLG(4) */
427 bp = bin_append_posn(2 + (eci / 1000), 4, binary_string, bp);
428 bp = bin_append_posn(2 + ((eci % 1000) / 100), 4, binary_string, bp);
429 bp = bin_append_posn(2 + ((eci % 100) / 10), 4, binary_string, bp);
430 bp = bin_append_posn(2 + (eci % 10), 4, binary_string, bp);
431 } else if (eci <= 99999) {
432 bp = bin_append_posn(5, 3, binary_string, bp); /* FLG(5) */
433 bp = bin_append_posn(2 + (eci / 10000), 4, binary_string, bp);
434 bp = bin_append_posn(2 + ((eci % 10000) / 1000), 4, binary_string, bp);
435 bp = bin_append_posn(2 + ((eci % 1000) / 100), 4, binary_string, bp);
436 bp = bin_append_posn(2 + ((eci % 100) / 10), 4, binary_string, bp);
437 bp = bin_append_posn(2 + (eci % 10), 4, binary_string, bp);
438 } else {
439 bp = bin_append_posn(6, 3, binary_string, bp); /* FLG(6) */
440 bp = bin_append_posn(2 + (eci / 100000), 4, binary_string, bp);
441 bp = bin_append_posn(2 + ((eci % 100000) / 10000), 4, binary_string, bp);
442 bp = bin_append_posn(2 + ((eci % 10000) / 1000), 4, binary_string, bp);
443 bp = bin_append_posn(2 + ((eci % 1000) / 100), 4, binary_string, bp);
444 bp = bin_append_posn(2 + ((eci % 100) / 10), 4, binary_string, bp);
445 bp = bin_append_posn(2 + (eci % 10), 4, binary_string, bp);
446 }
447 }
448
449 current_mode = initial_mode;
450 for (i = 0; i < reduced_length; i++) {
451
452 if (reduced_encode_mode[i] != current_mode) {
453 /* Change mode */
454 if (current_mode == 'U') {
455 switch (reduced_encode_mode[i]) {
456 case 'L':
457 if (!(bp = az_bin_append_posn(28, 5, binary_string, bp))) return 0; /* L/L */
458 break;
459 case 'M':
460 if (!(bp = az_bin_append_posn(29, 5, binary_string, bp))) return 0; /* M/L */
461 break;
462 case 'P':
463 if (!(bp = az_bin_append_posn(29, 5, binary_string, bp))) return 0; /* M/L */
464 if (!(bp = az_bin_append_posn(30, 5, binary_string, bp))) return 0; /* P/L */
465 break;
466 case 'p':
467 if (!(bp = az_bin_append_posn(0, 5, binary_string, bp))) return 0; /* P/S */
468 break;
469 case 'D':
470 if (!(bp = az_bin_append_posn(30, 5, binary_string, bp))) return 0; /* D/L */
471 break;
472 case 'B':
473 if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* B/S */
474 break;
475 }
476 } else if (current_mode == 'L') {
477 switch (reduced_encode_mode[i]) {
478 case 'U':
479 if (!(bp = az_bin_append_posn(30, 5, binary_string, bp))) return 0; /* D/L */
480 if (!(bp = az_bin_append_posn(14, 4, binary_string, bp))) return 0; /* U/L */
481 break;
482 case 'u':
483 if (!(bp = az_bin_append_posn(28, 5, binary_string, bp))) return 0; /* U/S */
484 break;
485 case 'M':
486 if (!(bp = az_bin_append_posn(29, 5, binary_string, bp))) return 0; /* M/L */
487 break;
488 case 'P':
489 if (!(bp = az_bin_append_posn(29, 5, binary_string, bp))) return 0; /* M/L */
490 if (!(bp = az_bin_append_posn(30, 5, binary_string, bp))) return 0; /* P/L */
491 break;
492 case 'p':
493 if (!(bp = az_bin_append_posn(0, 5, binary_string, bp))) return 0; /* P/S */
494 break;
495 case 'D':
496 if (!(bp = az_bin_append_posn(30, 5, binary_string, bp))) return 0; /* D/L */
497 break;
498 case 'B':
499 if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* B/S */
500 break;
501 }
502 } else if (current_mode == 'M') {
503 switch (reduced_encode_mode[i]) {
504 case 'U':
505 if (!(bp = az_bin_append_posn(29, 5, binary_string, bp))) return 0; /* U/L */
506 break;
507 case 'L':
508 if (!(bp = az_bin_append_posn(28, 5, binary_string, bp))) return 0; /* L/L */
509 break;
510 case 'P':
511 if (!(bp = az_bin_append_posn(30, 5, binary_string, bp))) return 0; /* P/L */
512 break;
513 case 'p':
514 if (!(bp = az_bin_append_posn(0, 5, binary_string, bp))) return 0; /* P/S */
515 break;
516 case 'D':
517 if (!(bp = az_bin_append_posn(29, 5, binary_string, bp))) return 0; /* U/L */
518 if (!(bp = az_bin_append_posn(30, 5, binary_string, bp))) return 0; /* D/L */
519 break;
520 case 'B':
521 if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* B/S */
522 break;
523 }
524 } else if (current_mode == 'P') {
525 switch (reduced_encode_mode[i]) {
526 case 'U':
527 if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* U/L */
528 break;
529 case 'L':
530 if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* U/L */
531 if (!(bp = az_bin_append_posn(28, 5, binary_string, bp))) return 0; /* L/L */
532 break;
533 case 'M':
534 if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* U/L */
535 if (!(bp = az_bin_append_posn(29, 5, binary_string, bp))) return 0; /* M/L */
536 break;
537 case 'D':
538 if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* U/L */
539 if (!(bp = az_bin_append_posn(30, 5, binary_string, bp))) return 0; /* D/L */
540 break;
541 case 'B':
542 if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* U/L */
543 current_mode = 'U';
544 if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* B/S */
545 break;
546 }
547 } else if (current_mode == 'D') {
548 switch (reduced_encode_mode[i]) {
549 case 'U':
550 if (!(bp = az_bin_append_posn(14, 4, binary_string, bp))) return 0; /* U/L */
551 break;
552 case 'u':
553 if (!(bp = az_bin_append_posn(15, 4, binary_string, bp))) return 0; /* U/S */
554 break;
555 case 'L':
556 if (!(bp = az_bin_append_posn(14, 4, binary_string, bp))) return 0; /* U/L */
557 if (!(bp = az_bin_append_posn(28, 5, binary_string, bp))) return 0; /* L/L */
558 break;
559 case 'M':
560 if (!(bp = az_bin_append_posn(14, 4, binary_string, bp))) return 0; /* U/L */
561 if (!(bp = az_bin_append_posn(29, 5, binary_string, bp))) return 0; /* M/L */
562 break;
563 case 'P':
564 if (!(bp = az_bin_append_posn(14, 4, binary_string, bp))) return 0; /* U/L */
565 if (!(bp = az_bin_append_posn(29, 5, binary_string, bp))) return 0; /* M/L */
566 if (!(bp = az_bin_append_posn(30, 5, binary_string, bp))) return 0; /* P/L */
567 break;
568 case 'p':
569 if (!(bp = az_bin_append_posn(0, 4, binary_string, bp))) return 0; /* P/S */
570 break;
571 case 'B':
572 if (!(bp = az_bin_append_posn(14, 4, binary_string, bp))) return 0; /* U/L */
573 current_mode = 'U';
574 if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* B/S */
575 break;
576 }
577 }
578
579 /* Byte mode - process full block here */
580 if (reduced_encode_mode[i] == 'B') {
581 int big_batch = 0;
582 for (count = 0; ((i + count) < reduced_length) && (reduced_encode_mode[i + count] == 'B'); count++);
583
584 if (count > 2047 + 2078) { /* Can't be more than 19968 / 8 = 2496 */
585 return 0;
586 }
587
588 if (count > 2047) { /* Max 11-bit number */
589 big_batch = count > 2078 ? 2078 : count;
590 /* Put 00000 followed by 11-bit number of bytes less 31 */
591 if (!(bp = az_bin_append_posn(big_batch - 31, 16, binary_string, bp))) return 0;
592 for (j = 0; j < big_batch; j++) {
593 if (!(bp = az_bin_append_posn(reduced_source[i++], 8, binary_string, bp))) return 0;
594 }
595 count -= big_batch;
596 }
597 if (count) {
598 if (big_batch) {
599 if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* B/S */
600 }
601 if (count > 31) {
602 assert(count <= 2078);
603 /* Put 00000 followed by 11-bit number of bytes less 31 */
604 if (!(bp = az_bin_append_posn(count - 31, 16, binary_string, bp))) return 0;
605 } else {
606 /* Put 5-bit number of bytes */
607 if (!(bp = az_bin_append_posn(count, 5, binary_string, bp))) return 0;
608 }
609 for (j = 0; j < count; j++) {
610 if (!(bp = az_bin_append_posn(reduced_source[i++], 8, binary_string, bp))) return 0;
611 }
612 }
613 i--;
614 continue;
615 }
616
617 if ((reduced_encode_mode[i] != 'u') && (reduced_encode_mode[i] != 'p')) {
618 current_mode = reduced_encode_mode[i];
619 }
620 }
621
622 if ((reduced_encode_mode[i] == 'U') || (reduced_encode_mode[i] == 'u')) {
623 if (reduced_source[i] == ' ') {
624 if (!(bp = az_bin_append_posn(1, 5, binary_string, bp))) return 0; /* SP */
625 } else {
626 if (!(bp = az_bin_append_posn(AztecSymbolChar[reduced_source[i]], 5, binary_string, bp))) return 0;
627 }
628 } else if (reduced_encode_mode[i] == 'L') {
629 if (reduced_source[i] == ' ') {
630 if (!(bp = az_bin_append_posn(1, 5, binary_string, bp))) return 0; /* SP */
631 } else {
632 if (!(bp = az_bin_append_posn(AztecSymbolChar[reduced_source[i]], 5, binary_string, bp))) return 0;
633 }
634 } else if (reduced_encode_mode[i] == 'M') {
635 if (reduced_source[i] == ' ') {
636 if (!(bp = az_bin_append_posn(1, 5, binary_string, bp))) return 0; /* SP */
637 } else if (reduced_source[i] == 13) {
638 if (!(bp = az_bin_append_posn(14, 5, binary_string, bp))) return 0; /* CR */
639 } else {
640 if (!(bp = az_bin_append_posn(AztecSymbolChar[reduced_source[i]], 5, binary_string, bp))) return 0;
641 }
642 } else if ((reduced_encode_mode[i] == 'P') || (reduced_encode_mode[i] == 'p')) {
643 if (gs1 && reduced_source[i] == '\x1D') {
644 if (!(bp = az_bin_append_posn(0, 5, binary_string, bp))) return 0; /* FLG(n) */
645 if (!(bp = az_bin_append_posn(0, 3, binary_string, bp))) return 0; /* FLG(0) = FNC1 */
646 } else if (reduced_source[i] == 13) {
647 if (!(bp = az_bin_append_posn(1, 5, binary_string, bp))) return 0; /* CR */
648 } else if (reduced_source[i] == 'a') {
649 if (!(bp = az_bin_append_posn(2, 5, binary_string, bp))) return 0; /* CR LF */
650 } else if (reduced_source[i] == 'b') {
651 if (!(bp = az_bin_append_posn(3, 5, binary_string, bp))) return 0; /* . SP */
652 } else if (reduced_source[i] == 'c') {
653 if (!(bp = az_bin_append_posn(4, 5, binary_string, bp))) return 0; /* , SP */
654 } else if (reduced_source[i] == 'd') {
655 if (!(bp = az_bin_append_posn(5, 5, binary_string, bp))) return 0; /* : SP */
656 } else if (reduced_source[i] == ',') {
657 if (!(bp = az_bin_append_posn(17, 5, binary_string, bp))) return 0; /* Comma */
658 } else if (reduced_source[i] == '.') {
659 if (!(bp = az_bin_append_posn(19, 5, binary_string, bp))) return 0; /* Full stop */
660 } else {
661 if (!(bp = az_bin_append_posn(AztecSymbolChar[reduced_source[i]], 5, binary_string, bp))) return 0;
662 }
663 } else if (reduced_encode_mode[i] == 'D') {
664 if (reduced_source[i] == ' ') {
665 if (!(bp = az_bin_append_posn(1, 4, binary_string, bp))) return 0; /* SP */
666 } else if (reduced_source[i] == ',') {
667 if (!(bp = az_bin_append_posn(12, 4, binary_string, bp))) return 0; /* Comma */
668 } else if (reduced_source[i] == '.') {
669 if (!(bp = az_bin_append_posn(13, 4, binary_string, bp))) return 0; /* Full stop */
670 } else {
671 if (!(bp = az_bin_append_posn(AztecSymbolChar[reduced_source[i]], 4, binary_string, bp))) return 0;
672 }
673 }
674 }
675
676 if (debug_print) {
677 printf("Binary String (%d): %.*s\n", bp, bp, binary_string);
678 }
679
680 *data_length = bp;
681 if (p_current_mode) {
682 *p_current_mode = current_mode;
683 }
684
685 return 1;
686 }
687
688 /* Call `aztec_text_process()` for each segment */
689 static int aztec_text_process_segs(struct zint_seg segs[], const int seg_count, int bp, char binary_string[],
690 const int gs1, int *data_length, const int debug_print) {
691 int i;
692
693 char current_mode = 'U';
694
695 for (i = 0; i < seg_count; i++) {
696 if (!aztec_text_process(segs[i].source, segs[i].length, bp, binary_string, gs1, segs[i].eci, &current_mode,
697 &bp, debug_print)) {
698 return 0;
699 }
700 }
701
702 *data_length = bp;
703
704 return 1;
705 }
706
707 /* Prevent data from obscuring reference grid */
708 static int az_avoidReferenceGrid(int output) {
709
710 if (output > 10) {
711 output += (output - 11) / 15 + 1;
712 }
713
714 return output;
715 }
716
717 /* Calculate the position of the bits in the grid (non-compact) */
718 static void az_populate_map(short AztecMap[], const int layers) {
719 int layer;
720 int x, y;
721 const int offset = AztecOffset[layers - 1];
722 const int endoffset = 151 - offset;
723
724 for (layer = 0; layer < layers; layer++) {
725 const int start = (112 * layer) + (16 * layer * layer) + 2;
726 const int length = 28 + (layer * 4) + (layer + 1) * 4;
727 int av0, av1;
728 int n = start, end;
729 /* Top */
730 x = 64 - (layer * 2);
731 y = 63 - (layer * 2);
732 av0 = az_avoidReferenceGrid(y) * 151;
733 av1 = az_avoidReferenceGrid(y - 1) * 151;
734 end = start + length;
735 while (n < end) {
736 const int avxi = az_avoidReferenceGrid(x++);
737 AztecMap[av0 + avxi] = n++;
738 AztecMap[av1 + avxi] = n++;
739 }
740 /* Right */
741 x = 78 + (layer * 2);
742 y = 64 - (layer * 2);
743 av0 = az_avoidReferenceGrid(x);
744 av1 = az_avoidReferenceGrid(x + 1);
745 end += length;
746 while (n < end) {
747 const int avyi = az_avoidReferenceGrid(y++) * 151;
748 AztecMap[avyi + av0] = n++;
749 AztecMap[avyi + av1] = n++;
750 }
751 /* Bottom */
752 x = 77 + (layer * 2);
753 y = 78 + (layer * 2);
754 av0 = az_avoidReferenceGrid(y) * 151;
755 av1 = az_avoidReferenceGrid(y + 1) * 151;
756 end += length;
757 while (n < end) {
758 const int avxi = az_avoidReferenceGrid(x--);
759 AztecMap[av0 + avxi] = n++;
760 AztecMap[av1 + avxi] = n++;
761 }
762 /* Left */
763 x = 63 - (layer * 2);
764 y = 77 + (layer * 2);
765 av0 = az_avoidReferenceGrid(x);
766 av1 = az_avoidReferenceGrid(x - 1);
767 end += length;
768 while (n < end) {
769 const int avyi = az_avoidReferenceGrid(y--) * 151;
770 AztecMap[avyi + av0] = n++;
771 AztecMap[avyi + av1] = n++;
772 }
773 }
774
775 /* Copy "Core Symbol" (finder, descriptor, orientation) */
776 for (y = 0; y < 15; y++) {
777 memcpy(AztecMap + (y + 68) * 151 + 68, AztecMapCore[y], sizeof(short) * 15);
778 }
779
780 /* Reference grid guide bars */
781 for (y = offset <= 11 ? 11 : AztecMapGridYOffsets[(offset - 11) / 16]; y < endoffset; y += 16) {
782 for (x = offset; x < endoffset; x++) {
783 AztecMap[(x * 151) + y] = x & 1;
784 AztecMap[(y * 151) + x] = x & 1;
785 }
786 }
787 }
788
789 /* Helper to insert dummy '0' or '1's into runs of same bits. See ISO/IEC 24778:2008 7.3.1.2 */
790 static int az_bitrun_stuff(const char *binary_string, const int data_length, const int codeword_size,
791 const int data_maxsize, char adjusted_string[AZTEC_MAX_CAPACITY]) {
792 int i, j = 0, count = 0;
793
794 for (i = 0; i < data_length; i++) {
795
796 if ((j + 1) % codeword_size == 0) {
797 /* Last bit of codeword */
798 /* 7.3.1.2 "whenever the first B-1 bits ... are all “0”s, then a dummy “1” is inserted..."
799 "Similarly a message codeword that starts with B-1 “1”s has a dummy “0” inserted..." */
800
801 if (count == 0 || count == (codeword_size - 1)) {
802 /* Codeword of B-1 '0's or B-1 '1's */
803 if (j > data_maxsize) {
804 return 0; /* Fail */
805 }
806 adjusted_string[j++] = count == 0 ? '1' : '0';
807 count = binary_string[i] == '1' ? 1 : 0;
808 } else {
809 count = 0;
810 }
811
812 } else if (binary_string[i] == '1') { /* Skip B so only counting B-1 */
813 count++;
814 }
815 if (j > data_maxsize) {
816 return 0; /* Fail */
817 }
818 adjusted_string[j++] = binary_string[i];
819 }
820
821 return j;
822 }
823
824 /* Helper to add padding, accounting for bitrun stuffing */
825 static int az_add_padding(const int padbits, const int codeword_size, char adjusted_string[AZTEC_MAX_CAPACITY],
826 int adjusted_length) {
827 int i, count = 0;
828
829 for (i = 0; i < padbits; i++) {
830 adjusted_string[adjusted_length++] = '1';
831 }
832
833 for (i = (adjusted_length - codeword_size); i < adjusted_length; i++) {
834 count += adjusted_string[i] == '1';
835 }
836 if (count == codeword_size) {
837 adjusted_string[adjusted_length - 1] = '0';
838 }
839
840 return adjusted_length;
841 }
842
843 /* Determine codeword bitlength - Table 3 */
844 static int az_codeword_size(const int layers) {
845 int codeword_size;
846
847 if (layers <= 2) {
848 codeword_size = 6;
849 } else if (layers <= 8) {
850 codeword_size = 8;
851 } else if (layers <= 22) {
852 codeword_size = 10;
853 } else {
854 codeword_size = 12;
855 }
856 return codeword_size;
857 }
858
859 INTERNAL int aztec(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
860 int x, y, i, p, data_blocks, ecc_blocks, layers, total_bits;
861 char bit_pattern[AZTEC_MAP_POSN_MAX + 1]; /* Note AZTEC_MAP_POSN_MAX > AZTEC_BIN_CAPACITY */
862 /* To lessen stack usage, share binary_string buffer with bit_pattern, as accessed separately */
863 char *binary_string = bit_pattern;
864 char descriptor[42];
865 char adjusted_string[AZTEC_MAX_CAPACITY];
866 short AztecMap[AZTEC_MAP_SIZE];
867 unsigned char desc_data[4], desc_ecc[6];
868 int error_number = 0;
869 int compact, data_length, data_maxsize, codeword_size, adjusted_length;
870 int remainder, padbits, adjustment_size;
871 int bp = 0;
872 const int gs1 = (symbol->input_mode & 0x07) == GS1_MODE;
873 const int reader_init = symbol->output_options & READER_INIT;
874 const int compact_loop_start = reader_init ? 1 : 4; /* Compact 2-4 excluded from Reader Initialisation */
875 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
876 rs_t rs;
877 rs_uint_t rs_uint;
878 unsigned int *data_part;
879 unsigned int *ecc_part;
880
881 if (gs1 && reader_init) {
882 return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 501, "Cannot use Reader Initialisation in GS1 mode");
883 }
884
885 if (symbol->structapp.count) {
886 /* Structured Append info as string <SP> + ID + <SP> + index + count + NUL */
887 unsigned char sa_src[1 + sizeof(symbol->structapp.id) + 1 + 1 + 1 + 1] = {0};
888 int sa_len;
889 int id_len;
890
891 if (symbol->structapp.count < 2 || symbol->structapp.count > 26) {
892 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 701,
893 "Structured Append count '%d' out of range (2 to 26)", symbol->structapp.count);
894 }
895 if (symbol->structapp.index < 1 || symbol->structapp.index > symbol->structapp.count) {
896 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 702,
897 "Structured Append index '%1$d' out of range (1 to count %2$d)",
898 symbol->structapp.index, symbol->structapp.count);
899 }
900
901 for (id_len = 0; id_len < 32 && symbol->structapp.id[id_len]; id_len++);
902
903 if (id_len && chr_cnt((const unsigned char *) symbol->structapp.id, id_len, ' ')) {
904 /* Note ID can contain any old chars apart from space so don't print in error message */
905 return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 703, "Structured Append ID cannot contain spaces");
906 }
907
908 bp = bin_append_posn(29, 5, binary_string, bp); /* M/L */
909 bp = bin_append_posn(29, 5, binary_string, bp); /* U/L */
910
911 sa_len = 0;
912 if (id_len) { /* ID has a space on either side */
913 sa_src[sa_len++] = ' ';
914 memcpy(sa_src + sa_len, symbol->structapp.id, id_len);
915 sa_len += id_len;
916 sa_src[sa_len++] = ' ';
917 }
918 sa_src[sa_len++] = 'A' + symbol->structapp.index - 1;
919 sa_src[sa_len++] = 'A' + symbol->structapp.count - 1;
920 if (debug_print) {
921 printf("Structured Append Count: %d, Index: %d, ID: %.32s, String: %s\n",
922 symbol->structapp.count, symbol->structapp.index, symbol->structapp.id, sa_src);
923 }
924
925 (void) aztec_text_process(sa_src, sa_len, bp, binary_string, 0 /*gs1*/, 0 /*eci*/, NULL /*p_current_mode*/,
926 &bp, debug_print);
927 /* Will be in U/L due to uppercase A-Z index/count indicators at end */
928 }
929
930 if (!aztec_text_process_segs(segs, seg_count, bp, binary_string, gs1, &data_length, debug_print)) {
931 return errtxt(ZINT_ERROR_TOO_LONG, symbol, 502,
932 "Input too long, requires too many codewords (maximum " AZ_BIN_CAP_CWDS_S ")");
933 }
934 assert(data_length > 0); /* Suppress clang-tidy warning: clang-analyzer-core.UndefinedBinaryOperatorResult */
935
936 if (symbol->option_1 < -1 || symbol->option_1 > 4) {
937 errtxtf(0, symbol, 503, "Error correction level '%d' out of range (1 to 4)", symbol->option_1);
938 if (symbol->warn_level == WARN_FAIL_ALL) {
939 return ZINT_ERROR_INVALID_OPTION;
940 }
941 error_number = errtxt_adj(ZINT_WARN_INVALID_OPTION, symbol, "%1$s%2$s", ", ignoring");
942 symbol->option_1 = -1;
943 }
944
945 data_maxsize = 0; /* Keep compiler happy! */
946 adjustment_size = 0;
947 if (symbol->option_2 == 0) { /* The size of the symbol can be determined by Zint */
948 int ecc_level = symbol->option_1;
949
950 if (ecc_level <= 0) {
951 ecc_level = 2;
952 }
953
954 do {
955 /* Decide what size symbol to use - the smallest that fits the data */
956 compact = 0; /* 1 = Aztec Compact, 0 = Normal Aztec */
957 layers = 0;
958
959 /* For each level of error correction work out the smallest symbol which the data will fit in */
960 for (i = compact_loop_start; i > 0; i--) {
961 if ((data_length + adjustment_size) <= AztecCompactDataSizes[ecc_level - 1][i - 1]) {
962 layers = i;
963 compact = 1;
964 data_maxsize = AztecCompactDataSizes[ecc_level - 1][i - 1];
965 }
966 }
967 if (!compact) {
968 for (i = 32; i > 0; i--) {
969 if ((data_length + adjustment_size) <= AztecDataSizes[ecc_level - 1][i - 1]) {
970 layers = i;
971 compact = 0;
972 data_maxsize = AztecDataSizes[ecc_level - 1][i - 1];
973 }
974 }
975 }
976
977 if (layers == 0) { /* Couldn't find a symbol which fits the data */
978 if (adjustment_size == 0) {
979 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 707,
980 "Input too long for ECC level %1$d, requires too many codewords (maximum %2$d)",
981 ecc_level, AztecDataSizes[ecc_level - 1][31] / 12);
982 }
983 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 504,
984 "Input too long for ECC level %1$d, requires %2$d codewords (maximum %3$d)",
985 ecc_level, (data_length + adjustment_size + 11) / 12,
986 AztecDataSizes[ecc_level - 1][31] / 12);
987 }
988
989 codeword_size = az_codeword_size(layers);
990
991 adjusted_length = az_bitrun_stuff(binary_string, data_length, codeword_size,
992 adjustment_size ? data_maxsize : AZTEC_BIN_CAPACITY, adjusted_string);
993 if (adjusted_length == 0) {
994 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 705,
995 "Input too long for ECC level %1$d, requires too many codewords (maximum %2$d)",
996 ecc_level, (adjustment_size ? data_maxsize : AZTEC_BIN_CAPACITY) / codeword_size);
997 }
998 adjustment_size = adjusted_length - data_length;
999
1000 /* Add padding */
1001 remainder = adjusted_length % codeword_size;
1002
1003 padbits = codeword_size - remainder;
1004 if (padbits == codeword_size) {
1005 padbits = 0;
1006 }
1007 if (debug_print) printf("Remainder: %d Pad bits: %d\n", remainder, padbits);
1008
1009 assert(adjusted_length <= AZTEC_BIN_CAPACITY);
1010
1011 adjusted_length = az_add_padding(padbits, codeword_size, adjusted_string, adjusted_length);
1012
1013 if (debug_print) printf("Adjusted Length: %d, Data Max Size %d\n", adjusted_length, data_maxsize);
1014
1015 } while (adjusted_length > data_maxsize);
1016 /* This loop will only repeat on the rare occasions when the rule about not having all 1s or all 0s
1017 means that the binary string has had to be lengthened beyond the maximum number of bits that can
1018 be encoded in a symbol of the selected size */
1019
1020 } else { /* The size of the symbol has been specified by the user */
1021 if ((symbol->option_2 < 0) || (symbol->option_2 > 36)) {
1022 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 510, "Version '%d' out of range (1 to 36)",
1023 symbol->option_2);
1024 }
1025 if (reader_init) {
1026 /* For back-compatibility, silently ignore compact 2-4 requests but error on layers > 22 */
1027 if (symbol->option_2 >= 2 && symbol->option_2 <= 4) {
1028 symbol->option_2 = 5;
1029 } else if (symbol->option_2 > 26) {
1030 /* Caught below anyway but catch here also for better feedback */
1031 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 709,
1032 "Version '%d' out of range for Reader Initialisation symbols (maximum 26)",
1033 symbol->option_2);
1034 }
1035 }
1036 if (symbol->option_2 <= 4) {
1037 compact = 1;
1038 layers = symbol->option_2;
1039 } else {
1040 compact = 0;
1041 layers = symbol->option_2 - 4;
1042 }
1043
1044 codeword_size = az_codeword_size(layers);
1045 if (compact) {
1046 data_maxsize = codeword_size * (AztecCompactSizes[layers - 1] - 3);
1047 } else {
1048 data_maxsize = codeword_size * (AztecSizes[layers - 1] - 3);
1049 }
1050
1051 adjusted_length = az_bitrun_stuff(binary_string, data_length, codeword_size, data_maxsize, adjusted_string);
1052 if (adjusted_length == 0) {
1053 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 704,
1054 "Input too long for Version %1$d, requires too many codewords (maximum %2$d)",
1055 symbol->option_2, data_maxsize / codeword_size);
1056 }
1057
1058 /* Add padding */
1059 remainder = adjusted_length % codeword_size;
1060
1061 padbits = codeword_size - remainder;
1062 if (padbits == codeword_size) {
1063 padbits = 0;
1064 }
1065 if (debug_print) printf("Remainder: %d Pad bits: %d\n", remainder, padbits);
1066
1067 /* Check if the data actually fits into the selected symbol size */
1068
1069 if (adjusted_length + padbits > data_maxsize) {
1070 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 505,
1071 "Input too long for Version %1$d, requires %2$d codewords (maximum %3$d)",
1072 symbol->option_2, (adjusted_length + padbits) / codeword_size,
1073 data_maxsize / codeword_size);
1074 }
1075
1076 adjusted_length = az_add_padding(padbits, codeword_size, adjusted_string, adjusted_length);
1077
1078 if (debug_print) printf("Adjusted Length: %d\n", adjusted_length);
1079 }
1080
1081 if (debug_print) {
1082 printf("Codewords (%d):\n", adjusted_length / codeword_size);
1083 for (i = 0; i < (adjusted_length / codeword_size); i++) {
1084 printf(" %.*s", codeword_size, adjusted_string + i * codeword_size);
1085 }
1086 fputc('\n', stdout);
1087 }
1088
1089 if (reader_init && (layers > 22)) {
1090 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 506,
1091 "Input too long for Reader Initialisation, requires %d layers (maximum 22)", layers);
1092 }
1093
1094 data_blocks = adjusted_length / codeword_size;
1095
1096 if (compact) {
1097 ecc_blocks = AztecCompactSizes[layers - 1] - data_blocks;
1098 if (layers == 4) { /* Can use spare blocks for ECC (76 available - 64 max data blocks) */
1099 ecc_blocks += 12;
1100 }
1101 } else {
1102 ecc_blocks = AztecSizes[layers - 1] - data_blocks;
1103 }
1104 if (ecc_blocks < data_blocks / 20) {
1105 error_number = errtxtf(ZINT_WARN_NONCOMPLIANT, symbol, 708,
1106 "Number of ECC codewords %1$d less than %2$d (5%% of data codewords %3$d)",
1107 ecc_blocks, data_blocks / 20, data_blocks);
1108 }
1109
1110 if (debug_print) {
1111 printf("Generating a %s symbol with %d layers\n", compact ? "compact" : "full-size", layers);
1112 printf("Requires %d codewords of %d-bits\n", data_blocks + ecc_blocks, codeword_size);
1113 printf(" (%d data words, %d ecc words)\n", data_blocks, ecc_blocks);
1114 }
1115
1116 data_part = (unsigned int *) z_alloca(sizeof(unsigned int) * data_blocks);
1117 ecc_part = (unsigned int *) z_alloca(sizeof(unsigned int) * ecc_blocks);
1118
1119 /* Copy across data into separate integers */
1120 memset(data_part, 0, sizeof(unsigned int) * data_blocks);
1121 memset(ecc_part, 0, sizeof(unsigned int) * ecc_blocks);
1122
1123 /* Split into codewords and calculate reed-solomon error correction codes */
1124 for (i = 0; i < data_blocks; i++) {
1125 for (p = 0; p < codeword_size; p++) {
1126 if (adjusted_string[i * codeword_size + p] == '1') {
1127 data_part[i] |= 0x01 << (codeword_size - (p + 1));
1128 }
1129 }
1130 }
1131
1132 switch (codeword_size) {
1133 case 6:
1134 rs_init_gf(&rs, 0x43);
1135 rs_init_code(&rs, ecc_blocks, 1);
1136 rs_encode_uint(&rs, data_blocks, data_part, ecc_part);
1137 break;
1138 case 8:
1139 rs_init_gf(&rs, 0x12d);
1140 rs_init_code(&rs, ecc_blocks, 1);
1141 rs_encode_uint(&rs, data_blocks, data_part, ecc_part);
1142 break;
1143 case 10:
1144 if (!rs_uint_init_gf(&rs_uint, 0x409, 1023)) { /* Can fail on malloc() */
1145 return errtxt(ZINT_ERROR_MEMORY, symbol, 500, "Insufficient memory for Reed-Solomon log tables");
1146 }
1147 rs_uint_init_code(&rs_uint, ecc_blocks, 1);
1148 rs_uint_encode(&rs_uint, data_blocks, data_part, ecc_part);
1149 rs_uint_free(&rs_uint);
1150 break;
1151 case 12:
1152 if (!rs_uint_init_gf(&rs_uint, 0x1069, 4095)) { /* Can fail on malloc() */
1153 /* Note using AUSPOST error nos range as out of 50x ones & 51x taken by CODEONE */
1154 return errtxt(ZINT_ERROR_MEMORY, symbol, 700, "Insufficient memory for Reed-Solomon log tables");
1155 }
1156 rs_uint_init_code(&rs_uint, ecc_blocks, 1);
1157 rs_uint_encode(&rs_uint, data_blocks, data_part, ecc_part);
1158 rs_uint_free(&rs_uint);
1159 break;
1160 }
1161
1162 for (i = 0; i < ecc_blocks; i++) {
1163 adjusted_length = bin_append_posn(ecc_part[i], codeword_size, adjusted_string, adjusted_length);
1164 }
1165
1166 /* Invert the data so that actual data is on the outside and reed-solomon on the inside */
1167 memset(bit_pattern, '0', AZTEC_MAP_POSN_MAX + 1);
1168
1169 total_bits = (data_blocks + ecc_blocks) * codeword_size;
1170 for (i = 0; i < total_bits; i++) {
1171 bit_pattern[i] = adjusted_string[total_bits - i - 1];
1172 }
1173
1174 /* Now add the symbol descriptor */
1175 memset(desc_data, 0, 4);
1176 memset(desc_ecc, 0, 6);
1177 memset(descriptor, 0, 42);
1178
1179 if (compact) {
1180 /* The first 2 bits represent the number of layers minus 1 */
1181 descriptor[0] = ((layers - 1) & 0x02) ? '1' : '0';
1182 descriptor[1] = ((layers - 1) & 0x01) ? '1' : '0';
1183
1184 /* The next 6 bits represent the number of data blocks minus 1 */
1185 descriptor[2] = reader_init || ((data_blocks - 1) & 0x20) ? '1' : '0';
1186 for (i = 3; i < 8; i++) {
1187 descriptor[i] = ((data_blocks - 1) & (0x10 >> (i - 3))) ? '1' : '0';
1188 }
1189 if (debug_print) printf("Mode Message = %.8s\n", descriptor);
1190 } else {
1191 /* The first 5 bits represent the number of layers minus 1 */
1192 for (i = 0; i < 5; i++) {
1193 descriptor[i] = ((layers - 1) & (0x10 >> i)) ? '1' : '0';
1194 }
1195
1196 /* The next 11 bits represent the number of data blocks minus 1 */
1197 descriptor[5] = reader_init || ((data_blocks - 1) & 0x400) ? '1' : '0';
1198 for (i = 6; i < 16; i++) {
1199 descriptor[i] = ((data_blocks - 1) & (0x200 >> (i - 6))) ? '1' : '0';
1200 }
1201 if (debug_print) printf("Mode Message = %.16s\n", descriptor);
1202 }
1203
1204 /* Split into 4-bit codewords */
1205 for (i = 0; i < 4; i++) {
1206 desc_data[i] = ((descriptor[i * 4] == '1') << 3) | ((descriptor[(i * 4) + 1] == '1') << 2)
1207 | ((descriptor[(i * 4) + 2] == '1') << 1) | (descriptor[(i * 4) + 3] == '1');
1208 }
1209
1210 /* Add Reed-Solomon error correction with Galois field GF(16) and prime modulus x^4 + x + 1 (section 7.2.3) */
1211
1212 rs_init_gf(&rs, 0x13);
1213 if (compact) {
1214 rs_init_code(&rs, 5, 1);
1215 rs_encode(&rs, 2, desc_data, desc_ecc);
1216 for (i = 0; i < 5; i++) {
1217 descriptor[(i * 4) + 8] = (desc_ecc[i] & 0x08) ? '1' : '0';
1218 descriptor[(i * 4) + 9] = (desc_ecc[i] & 0x04) ? '1' : '0';
1219 descriptor[(i * 4) + 10] = (desc_ecc[i] & 0x02) ? '1' : '0';
1220 descriptor[(i * 4) + 11] = (desc_ecc[i] & 0x01) ? '1' : '0';
1221 }
1222 } else {
1223 rs_init_code(&rs, 6, 1);
1224 rs_encode(&rs, 4, desc_data, desc_ecc);
1225 for (i = 0; i < 6; i++) {
1226 descriptor[(i * 4) + 16] = (desc_ecc[i] & 0x08) ? '1' : '0';
1227 descriptor[(i * 4) + 17] = (desc_ecc[i] & 0x04) ? '1' : '0';
1228 descriptor[(i * 4) + 18] = (desc_ecc[i] & 0x02) ? '1' : '0';
1229 descriptor[(i * 4) + 19] = (desc_ecc[i] & 0x01) ? '1' : '0';
1230 }
1231 }
1232
1233 /* Merge descriptor with the rest of the symbol */
1234 if (compact) {
1235 memcpy(bit_pattern + 2000 - 2, descriptor, 40);
1236 } else {
1237 memcpy(bit_pattern + 20000 - 2, descriptor, 40);
1238 }
1239
1240 /* Plot all of the data into the symbol in pre-defined spiral pattern */
1241 if (compact) {
1242 const int offset = AztecCompactOffset[layers - 1];
1243 const int end_offset = 27 - offset;
1244 for (y = offset; y < end_offset; y++) {
1245 const int y_map = y * 27;
1246 for (x = offset; x < end_offset; x++) {
1247 const int map = AztecCompactMap[y_map + x];
1248 if (map == 1 || (map >= 2 && bit_pattern[map - 2] == '1')) {
1249 set_module(symbol, y - offset, x - offset);
1250 }
1251 }
1252 symbol->row_height[y - offset] = 1;
1253 }
1254 symbol->height = 27 - (2 * offset);
1255 symbol->rows = 27 - (2 * offset);
1256 symbol->width = 27 - (2 * offset);
1257 } else {
1258 const int offset = AztecOffset[layers - 1];
1259 const int end_offset = 151 - offset;
1260 az_populate_map(AztecMap, layers);
1261 for (y = offset; y < end_offset; y++) {
1262 const int y_map = y * 151;
1263 for (x = offset; x < end_offset; x++) {
1264 const int map = AztecMap[y_map + x];
1265 if (map == 1 || (map >= 2 && bit_pattern[map - 2] == '1')) {
1266 set_module(symbol, y - offset, x - offset);
1267 }
1268 }
1269 symbol->row_height[y - offset] = 1;
1270 }
1271 symbol->height = 151 - (2 * offset);
1272 symbol->rows = 151 - (2 * offset);
1273 symbol->width = 151 - (2 * offset);
1274 }
1275
1276 return error_number;
1277 }
1278
1279 /* Encodes Aztec runes as specified in ISO/IEC 24778:2008 Annex A */
1280 INTERNAL int azrune(struct zint_symbol *symbol, unsigned char source[], int length) {
1281 unsigned int input_value;
1282 int i, y, x, r;
1283 char binary_string[28];
1284 unsigned char data_codewords[3], ecc_codewords[6];
1285 int bp = 0;
1286 const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
1287 rs_t rs;
1288
1289 input_value = 0;
1290 if (length > 3) {
1291 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 507, "Input length %d too long (maximum 3)", length);
1292 }
1293 if ((i = not_sane(NEON_F, source, length))) {
1294 return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 508,
1295 "Invalid character at position %d in input (digits only)", i);
1296 }
1297 switch (length) {
1298 case 3:
1299 input_value = 100 * ctoi(source[0]) + 10 * ctoi(source[1]) + ctoi(source[2]);
1300 break;
1301 case 2:
1302 input_value = 10 * ctoi(source[0]) + ctoi(source[1]);
1303 break;
1304 case 1:
1305 input_value = ctoi(source[0]);
1306 break;
1307 }
1308
1309 if (input_value > 255) {
1310 return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 509, "Input value out of range (0 to 255)");
1311 }
1312
1313 bp = bin_append_posn(input_value, 8, binary_string, bp);
1314
1315 data_codewords[0] = (unsigned char) (input_value >> 4);
1316 data_codewords[1] = (unsigned char) (input_value & 0xF);
1317
1318 rs_init_gf(&rs, 0x13);
1319 rs_init_code(&rs, 5, 1);
1320 rs_encode(&rs, 2, data_codewords, ecc_codewords);
1321
1322 for (i = 0; i < 5; i++) {
1323 bp = bin_append_posn(ecc_codewords[i], 4, binary_string, bp);
1324 }
1325
1326 for (i = 0; i < 28; i += 2) {
1327 binary_string[i] = '0' + (binary_string[i] != '1');
1328 }
1329
1330 if (debug_print) {
1331 printf("Binary String: %.28s\n", binary_string);
1332 }
1333
1334 for (y = 8; y < 19; y++) {
1335 r = y * 27;
1336 for (x = 8; x < 19; x++) {
1337 if (AztecCompactMap[r + x] == 1) {
1338 set_module(symbol, y - 8, x - 8);
1339 } else if (AztecCompactMap[r + x] && binary_string[AztecCompactMap[r + x] - 2000] == '1') {
1340 set_module(symbol, y - 8, x - 8);
1341 }
1342 }
1343 symbol->row_height[y - 8] = 1;
1344 }
1345 symbol->height = 11;
1346 symbol->rows = 11;
1347 symbol->width = 11;
1348
1349 return 0;
1350 }
1351
1352 /* vim: set ts=4 sw=4 et : */