comparison mupdf-source/thirdparty/zint/backend/ultra.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 /* ultra.c - Ultracode */
2 /*
3 libzint - the open source barcode library
4 Copyright (C) 2020-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 version was developed using AIMD/TSC15032-43 v0.99c Edit 60, dated 4th Nov 2015 */
34
35 #include <stdio.h>
36 #include "common.h"
37
38 #define ULT_EIGHTBIT_MODE 10
39 #define ULT_ASCII_MODE 20
40 #define ULT_C43_MODE 30
41
42 #define ULT_PREDICT_WINDOW 12
43
44 #define ULT_GFMUL(i, j) ((((i) == 0)||((j) == 0)) ? 0 : gfPwr[(gfLog[i] + gfLog[j])])
45
46 static const char *const ult_fragment[27] = {
47 "http://", "https://", "http://www.", "https://www.",
48 "ftp://", "www.", ".com", ".edu", ".gov", ".int", ".mil", ".net", ".org",
49 ".mobi", ".coop", ".biz", ".info", "mailto:", "tel:", ".cgi", ".asp",
50 ".aspx", ".php", ".htm", ".html", ".shtml", "file:"
51 };
52
53 static const char ult_c43_set1[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 .,%";
54 static const char ult_c43_set2[] = "abcdefghijklmnopqrstuvwxyz:/?#[]@=_~!.,-";
55 static const char ult_c43_set3[] = "{}`()\"+'<>|$;&\\^*";
56 static const char ult_digit[] = "0123456789,/";
57 static const char ult_colour[] = "0CBMRYGKW";
58
59 /* Max size and min cols adjusted to BWIPP values as updated 2021-07-14
60 https://github.com/bwipp/postscriptbarcode/commit/4255810845fa8d45c6192dd30aee1fdad1aaf0cc */
61 static const short ult_maxsize[] = { 37, 84, 161, 282 };
62
63 static const char ult_mincols[] = { 5, 13, 22, 29 };
64
65 static const char ult_kec[] = { 0, 1, 2, 4, 6, 8 }; /* Value K(EC) from Table 12 */
66
67 /* Taken from BWIPP - change in DCCU/DCCL tiles for revision 2 2021-09-28 */
68 static const unsigned short ult_dccu[2][32] = {
69 { /* Revision 1 */
70 051363, 051563, 051653, 053153, 053163, 053513, 053563, 053613, /* 0-7 */
71 053653, 056153, 056163, 056313, 056353, 056363, 056513, 056563, /* 8-15 */
72 051316, 051356, 051536, 051616, 053156, 053516, 053536, 053616, /* 16-23 */
73 053636, 053656, 056136, 056156, 056316, 056356, 056516, 056536 /* 24-31 */
74 },
75 { /* Revision 2 (inversion of DCCL Revision 1) */
76 015316, 016316, 013516, 016516, 013616, 015616, 013136, 015136, /* 0-7 */
77 016136, 013536, 016536, 013636, 013156, 016156, 015356, 013656, /* 8-15 */
78 015313, 016313, 013513, 016513, 013613, 015613, 013153, 015153, /* 16-23 */
79 016153, 016353, 013653, 015653, 013163, 015163, 015363, 013563 /* 24-31 */
80 },
81 };
82
83 static const unsigned short ult_dccl[2][32] = {
84 { /* Revision 1 */
85 061351, 061361, 061531, 061561, 061631, 061651, 063131, 063151, /* 0-7 */
86 063161, 063531, 063561, 063631, 065131, 065161, 065351, 065631, /* 8-15 */
87 031351, 031361, 031531, 031561, 031631, 031651, 035131, 035151, /* 16-23 */
88 035161, 035361, 035631, 035651, 036131, 036151, 036351, 036531 /* 24-31 */
89 },
90 { /* Revision 2 (inversion of DCCU Revision 1) */
91 036315, 036515, 035615, 035135, 036135, 031535, 036535, 031635, /* 0-7 */
92 035635, 035165, 036165, 031365, 035365, 036365, 031565, 036565, /* 8-15 */
93 061315, 065315, 063515, 061615, 065135, 061535, 063535, 061635, /* 16-23 */
94 063635, 065635, 063165, 065165, 061365, 065365, 061565, 063565 /* 24-31 */
95 },
96 };
97
98 static const unsigned short ult_tiles[] = {
99 013135, 013136, 013153, 013156, 013163, 013165, 013513, 013515, 013516, 013531, /* 0-9 */
100 013535, 013536, 013561, 013563, 013565, 013613, 013615, 013616, 013631, 013635, /* 10-19 */
101 013636, 013651, 013653, 013656, 015135, 015136, 015153, 015163, 015165, 015313, /* 20-29 */
102 015315, 015316, 015351, 015353, 015356, 015361, 015363, 015365, 015613, 015615, /* 30-39 */
103 015616, 015631, 015635, 015636, 015651, 015653, 015656, 016135, 016136, 016153, /* 40-49 */
104 016156, 016165, 016313, 016315, 016316, 016351, 016353, 016356, 016361, 016363, /* 50-59 */
105 016365, 016513, 016515, 016516, 016531, 016535, 016536, 016561, 016563, 016565, /* 60-69 */
106 031315, 031316, 031351, 031356, 031361, 031365, 031513, 031515, 031516, 031531, /* 70-79 */
107 031535, 031536, 031561, 031563, 031565, 031613, 031615, 031631, 031635, 031636, /* 80-89 */
108 031651, 031653, 031656, 035131, 035135, 035136, 035151, 035153, 035156, 035161, /* 90-99 */
109 035163, 035165, 035315, 035316, 035351, 035356, 035361, 035365, 035613, 035615, /* 100-109 */
110 035616, 035631, 035635, 035636, 035651, 035653, 035656, 036131, 036135, 036136, /* 110-119 */
111 036151, 036153, 036156, 036163, 036165, 036315, 036316, 036351, 036356, 036361, /* 120-129 */
112 036365, 036513, 036515, 036516, 036531, 036535, 036536, 036561, 036563, 036565, /* 130-139 */
113 051313, 051315, 051316, 051351, 051353, 051356, 051361, 051363, 051365, 051513, /* 140-149 */
114 051516, 051531, 051536, 051561, 051563, 051613, 051615, 051616, 051631, 051635, /* 150-159 */
115 051636, 051651, 051653, 051656, 053131, 053135, 053136, 053151, 053153, 053156, /* 160-169 */
116 053161, 053163, 053165, 053513, 053516, 053531, 053536, 053561, 053563, 053613, /* 170-179 */
117 053615, 053616, 053631, 053635, 053636, 053651, 053653, 053656, 056131, 056135, /* 180-189 */
118 056136, 056151, 056153, 056156, 056161, 056163, 056165, 056313, 056315, 056316, /* 190-199 */
119 056351, 056353, 056356, 056361, 056363, 056365, 056513, 056516, 056531, 056536, /* 200-209 */
120 056561, 056563, 061313, 061315, 061316, 061351, 061353, 061356, 061361, 061363, /* 210-219 */
121 061365, 061513, 061515, 061516, 061531, 061535, 061536, 061561, 061563, 061565, /* 220-229 */
122 061615, 061631, 061635, 061651, 061653, 063131, 063135, 063136, 063151, 063153, /* 230-239 */
123 063156, 063161, 063163, 063165, 063513, 063515, 063516, 063531, 063535, 063536, /* 240-249 */
124 063561, 063563, 063565, 063613, 063615, 063631, 063635, 063651, 063653, 065131, /* 250-259 */
125 065135, 065136, 065151, 065153, 065156, 065161, 065163, 065165, 065313, 065315, /* 260-269 */
126 065316, 065351, 065353, 065356, 065361, 065363, 065365, 065613, 065615, 065631, /* 270-279 */
127 065635, 065651, 065653, 056565, 051515 /* 280-284 */
128 };
129
130 /* The following adapted from ECC283.C "RSEC codeword generator"
131 * from Annex B of Ultracode draft
132 * originally written by Ted Williams of Symbol Vision Corp.
133 * Dated 2001-03-09
134 * Corrected thanks to input from Terry Burton */
135
136 /*
137 * NOTE: Included here is an attempt to allow code compression within Ultracode. Unfortunately
138 * the copy of the standard this was written from was an early draft which includes self
139 * contradictions, so this is a "best guess" implementation. Because it is not guaranteed
140 * to be correct this compression is not applied by default. To enable compression set
141 *
142 * symbol->option_3 = ULTRA_COMPRESSION;
143 *
144 * Code compression should be enabled by default when it has been implemented according to
145 * a more reliable version of the specification.
146 */
147
148 /* Generate divisor polynomial gQ(x) for GF283() given the required ECC size, 3 to 101 */
149 static void ult_genPoly(const short EccSize, unsigned short gPoly[], const unsigned short gfPwr[],
150 const unsigned short gfLog[]) {
151 int i, j;
152
153 gPoly[0] = 1;
154 for (i = 1; i < (EccSize + 1); i++) gPoly[i] = 0;
155
156 for (i = 0; i < EccSize; i++) {
157 for (j = i; j >= 0; j--)
158 gPoly[j + 1] = (gPoly[j] + ULT_GFMUL(gPoly[j + 1], gfPwr[i + 1])) % 283;
159 gPoly[0] = ULT_GFMUL(gPoly[0], gfPwr[i + 1]);
160 }
161 for (i = EccSize - 1; i >= 0; i -= 2) gPoly[i] = 283 - gPoly[i];
162
163 /* gPoly[i] is > 0 so modulo operation not needed */
164 }
165
166 /* Generate the log and antilog tables for GF283() multiplication & division */
167 static void ult_initLogTables(unsigned short gfPwr[], unsigned short gfLog[]) {
168 int i, j;
169
170 for (j = 0; j < 283; j++) gfLog[j] = 0;
171 i = 1;
172 for (j = 0; j < 282; j++) {
173 /* j + 282 indices save doing the modulo operation in ULT_GFMUL */
174 gfPwr[j + 282] = gfPwr[j] = (short) i;
175 gfLog[i] = (short) j;
176 i = (i * 3) % 283;
177 }
178 }
179
180 static void ult_gf283(const short DataSize, const short EccSize, int Message[]) {
181 /* Input is complete message codewords in array Message[282]
182 * DataSize is number of message codewords
183 * EccSize is number of Reed-Solomon GF(283) check codewords to generate
184 *
185 * Upon exit, Message[282] contains complete 282 codeword Symbol Message
186 * including leading zeroes corresponding to each truncated codeword */
187
188 unsigned short gPoly[283], gfPwr[(282 * 2)], gfLog[283];
189 int i, j, n;
190 unsigned short t;
191
192 /* first build the log & antilog tables used in multiplication & division */
193 ult_initLogTables(gfPwr, gfLog);
194
195 /* then generate the division polynomial of length EccSize */
196 ult_genPoly(EccSize, gPoly, gfPwr, gfLog);
197
198 /* zero all EccSize codeword values */
199 for (j = 281; (j > (281 - EccSize)); j--) Message[j] = 0;
200
201 /* shift message codewords to the right, leave space for ECC checkwords */
202 for (i = DataSize - 1; (i >= 0); j--, i--) Message[j] = Message[i];
203
204 /* add zeroes to pad left end Message[] for truncated codewords */
205 j++;
206 for (i = 0; i < j; i++) Message[i] = 0;
207
208 /* generate (EccSize) Reed-Solomon checkwords */
209 for (n = j; n < (j + DataSize); n++) {
210 t = (Message[j + DataSize] + Message[n]) % 283;
211 for (i = 0; i < (EccSize - 1); i++) {
212 Message[j + DataSize + i] = (Message[j + DataSize + i + 1] + 283
213 - ULT_GFMUL(t, gPoly[EccSize - 1 - i])) % 283;
214 }
215 Message[j + DataSize + EccSize - 1] = (283 - ULT_GFMUL(t, gPoly[0])) % 283;
216 }
217 for (i = j + DataSize; i < (j + DataSize + EccSize); i++)
218 Message[i] = (283 - Message[i]) % 283;
219 }
220
221 /* End of Ted Williams code */
222
223 static int ult_find_fragment(const unsigned char source[], const int length, const int position) {
224 int retval = -1;
225 int j, k, latch, fraglen;
226
227 for (j = 0; j < 27; j++) {
228 latch = 0;
229 fraglen = (int) strlen(ult_fragment[j]);
230 if ((position + fraglen) <= length) {
231 latch = 1;
232 for (k = 0; k < fraglen; k++) {
233 if (source[position + k] != ult_fragment[j][k]) {
234 latch = 0;
235 break;
236 }
237 }
238 }
239
240 if (latch) {
241 retval = j;
242 }
243 }
244
245 return retval;
246 }
247
248 /* Encode characters in 8-bit mode */
249 static float ult_look_ahead_eightbit(const unsigned char source[], const int length, const int in_locn,
250 const int current_mode, const int end_char, int cw[], int *cw_len, const int gs1) {
251 int codeword_count = 0;
252 int i;
253 int letters_encoded = 0;
254
255 if (current_mode != ULT_EIGHTBIT_MODE) {
256 cw[codeword_count] = 282; /* Unlatch */
257 codeword_count += 1;
258 }
259
260 i = in_locn;
261 while ((i < length) && (i < end_char)) {
262 if (gs1 && source[i] == '\x1D') {
263 cw[codeword_count] = 268; /* FNC1 */
264 } else {
265 cw[codeword_count] = source[i];
266 }
267 i++;
268 codeword_count++;
269 }
270
271 letters_encoded = i - in_locn;
272
273 *cw_len = codeword_count;
274
275 if (codeword_count == 0) {
276 return 0.0f;
277 }
278 return (float) letters_encoded / (float) codeword_count;
279 }
280
281 /* Encode character in the ASCII mode/submode (including numeric compression) */
282 static float ult_look_ahead_ascii(unsigned char source[], const int length, const int in_locn,
283 const int current_mode, const int symbol_mode, const int end_char, int cw[], int *cw_len, int *encoded,
284 const int gs1) {
285 int codeword_count = 0;
286 int i;
287 int first_digit, second_digit, done;
288 int letters_encoded = 0;
289
290 if (current_mode == ULT_EIGHTBIT_MODE) {
291 cw[codeword_count] = 267; /* Latch ASCII Submode */
292 codeword_count++;
293 }
294
295 if (current_mode == ULT_C43_MODE) {
296 cw[codeword_count] = 282; /* Unlatch */
297 codeword_count++;
298 if (symbol_mode == ULT_EIGHTBIT_MODE) {
299 cw[codeword_count] = 267; /* Latch ASCII Submode */
300 codeword_count++;
301 }
302 }
303
304 i = in_locn;
305 do {
306 /* Check for double digits */
307 done = 0;
308 if (i + 1 < length) {
309 first_digit = posn(ult_digit, source[i]);
310 second_digit = posn(ult_digit, source[i + 1]);
311 if ((first_digit != -1) && (second_digit != -1)) {
312 /* Double digit can be encoded */
313 if ((first_digit >= 0) && (first_digit <= 9) && (second_digit >= 0) && (second_digit <= 9)) {
314 /* Double digit numerics */
315 cw[codeword_count] = (10 * first_digit) + second_digit + 128;
316 codeword_count++;
317 i += 2;
318 done = 1;
319 } else if ((first_digit >= 0) && (first_digit <= 9) && (second_digit == 10)) {
320 /* Single digit followed by selected decimal point character */
321 cw[codeword_count] = first_digit + 228;
322 codeword_count++;
323 i += 2;
324 done = 1;
325 } else if ((first_digit == 10) && (second_digit >= 0) && (second_digit <= 9)) {
326 /* Selected decimal point character followed by single digit */
327 cw[codeword_count] = second_digit + 238;
328 codeword_count++;
329 i += 2;
330 done = 1;
331 } else if ((first_digit >= 0) && (first_digit <= 9) && (second_digit == 11)) {
332 /* Single digit or decimal point followed by field deliminator */
333 cw[codeword_count] = first_digit + 248;
334 codeword_count++;
335 i += 2;
336 done = 1;
337 } else if ((first_digit == 11) && (second_digit >= 0) && (second_digit <= 9)) {
338 /* Field deliminator followed by single digit or decimal point */
339 cw[codeword_count] = second_digit + 259;
340 codeword_count++;
341 i += 2;
342 done = 1;
343 }
344 }
345 }
346
347 if (!done && source[i] < 0x80) {
348 if (gs1 && source[i] == '\x1D') {
349 cw[codeword_count] = 272; /* FNC1 */
350 } else {
351 cw[codeword_count] = source[i];
352 }
353 codeword_count++;
354 i++;
355 }
356 } while ((i < length) && (i < end_char) && (source[i] < 0x80));
357
358 letters_encoded = i - in_locn;
359 if (encoded != NULL) {
360 *encoded = letters_encoded;
361 }
362
363 *cw_len = codeword_count;
364
365 if (codeword_count == 0) {
366 return 0.0f;
367 }
368 return (float) letters_encoded / (float) codeword_count;
369 }
370
371 /* Returns true if should latch to subset other than given `subset` */
372 static int ult_c43_should_latch_other(const unsigned char source[], const int length, const int locn,
373 const int subset) {
374 int i, fraglen, predict_window;
375 int cnt, alt_cnt, fragno;
376 const char *const set = subset == 1 ? ult_c43_set1 : ult_c43_set2;
377 const char *const alt_set = subset == 2 ? ult_c43_set1 : ult_c43_set2;
378
379 if (locn + 3 > length) {
380 return 0;
381 }
382 predict_window = locn + 3;
383
384 for (i = locn, cnt = 0, alt_cnt = 0; i < predict_window; i++) {
385 if (source[i] <= 0x1F || source[i] >= 0x7F) {
386 break;
387 }
388
389 fragno = ult_find_fragment(source, length, i);
390 if (fragno != -1 && fragno != 26) {
391 fraglen = (int) strlen(ult_fragment[fragno]);
392 predict_window += fraglen;
393 if (predict_window > length) {
394 predict_window = length;
395 }
396 i += fraglen - 1;
397 } else {
398 if (posn(set, source[i]) != -1) {
399 cnt++;
400 }
401 if (posn(alt_set, source[i]) != -1) {
402 alt_cnt++;
403 }
404 }
405 }
406
407 return alt_cnt > cnt;
408 }
409
410 static int ult_get_subset(const unsigned char source[], const int length, const int in_locn,
411 const int current_subset) {
412 int fragno;
413 int subset = 0;
414
415 fragno = ult_find_fragment(source, length, in_locn);
416 if ((fragno != -1) && (fragno != 26)) {
417 subset = 3;
418 } else if (current_subset == 2) {
419 if (posn(ult_c43_set2, source[in_locn]) != -1) {
420 subset = 2;
421 } else if (posn(ult_c43_set1, source[in_locn]) != -1) {
422 subset = 1;
423 }
424 } else {
425 if (posn(ult_c43_set1, source[in_locn]) != -1) {
426 subset = 1;
427 } else if (posn(ult_c43_set2, source[in_locn]) != -1) {
428 subset = 2;
429 }
430 }
431
432 if (subset == 0) {
433 if (posn(ult_c43_set3, source[in_locn]) != -1) {
434 subset = 3;
435 }
436 }
437
438 return subset;
439 }
440
441 /* Encode characters in the C43 compaction submode */
442 static float ult_look_ahead_c43(const unsigned char source[], const int length, const int in_locn,
443 const int current_mode, const int end_char, int subset, int cw[], int *cw_len, int *encoded,
444 const int gs1, const int debug_print) {
445 int codeword_count = 0;
446 int subcodeword_count = 0;
447 int i;
448 int fragno;
449 int sublocn = in_locn;
450 int new_subset;
451 int unshift_set;
452 int base43_value;
453 int letters_encoded = 0;
454 int pad;
455 int *subcw = (int *) z_alloca(sizeof(int) * (length + 3) * 2);
456
457 if (current_mode == ULT_EIGHTBIT_MODE) {
458 /* Check for permissable URL C43 macro sequences, otherwise encode directly */
459 fragno = ult_find_fragment(source, length, sublocn);
460
461 if ((fragno == 2) || (fragno == 3)) {
462 /* http://www. > http:// */
463 /* https://www. > https:// */
464 fragno -= 2;
465 }
466
467 switch (fragno) {
468 case 17: /* mailto: */
469 cw[codeword_count] = 276;
470 sublocn += (int) strlen(ult_fragment[fragno]);
471 codeword_count++;
472 break;
473 case 18: /* tel: */
474 cw[codeword_count] = 277;
475 sublocn += (int) strlen(ult_fragment[fragno]);
476 codeword_count++;
477 break;
478 case 26: /* file: */
479 cw[codeword_count] = 278;
480 sublocn += (int) strlen(ult_fragment[fragno]);
481 codeword_count++;
482 break;
483 case 0: /* http:// */
484 cw[codeword_count] = 279;
485 sublocn += (int) strlen(ult_fragment[fragno]);
486 codeword_count++;
487 break;
488 case 1: /* https:// */
489 cw[codeword_count] = 280;
490 sublocn += (int) strlen(ult_fragment[fragno]);
491 codeword_count++;
492 break;
493 case 4: /* ftp:// */
494 cw[codeword_count] = 281;
495 sublocn += (int) strlen(ult_fragment[fragno]);
496 codeword_count++;
497 break;
498 default:
499 if (subset == 1) {
500 cw[codeword_count] = 260; /* C43 Compaction Submode C1 */
501 codeword_count++;
502 } else if ((subset == 2) || (subset == 3)) {
503 cw[codeword_count] = 266; /* C43 Compaction Submode C2 */
504 codeword_count++;
505 }
506 break;
507 }
508
509 } else if (current_mode == ULT_ASCII_MODE) {
510 if (subset == 1) {
511 cw[codeword_count] = 278; /* C43 Compaction Submode C1 */
512 codeword_count++;
513 } else if ((subset == 2) || (subset == 3)) {
514 cw[codeword_count] = 280; /* C43 Compaction Submode C2 */
515 codeword_count++;
516 }
517 }
518 unshift_set = subset;
519
520 while ((sublocn < length) && (sublocn < end_char)) {
521 /* Check for FNC1 */
522 if (gs1 && source[sublocn] == '\x1D') {
523 break;
524 }
525
526 new_subset = ult_get_subset(source, length, sublocn, subset);
527
528 if (new_subset == 0) {
529 break;
530 }
531
532 if ((new_subset != subset) && ((new_subset == 1) || (new_subset == 2))) {
533 if (ult_c43_should_latch_other(source, length, sublocn, subset)) {
534 subcw[subcodeword_count] = 42; /* Latch to other C43 set */
535 subcodeword_count++;
536 unshift_set = new_subset;
537 } else {
538 subcw[subcodeword_count] = 40; /* Shift to other C43 set for 1 char */
539 subcodeword_count++;
540 subcw[subcodeword_count] = posn(new_subset == 1 ? ult_c43_set1 : ult_c43_set2, source[sublocn]);
541 subcodeword_count++;
542 sublocn++;
543 continue;
544 }
545 }
546
547 subset = new_subset;
548
549 if (subset == 1) {
550 subcw[subcodeword_count] = posn(ult_c43_set1, source[sublocn]);
551 subcodeword_count++;
552 sublocn++;
553 } else if (subset == 2) {
554 subcw[subcodeword_count] = posn(ult_c43_set2, source[sublocn]);
555 subcodeword_count++;
556 sublocn++;
557 } else if (subset == 3) {
558 subcw[subcodeword_count] = 41; /* Shift to set 3 */
559 subcodeword_count++;
560
561 fragno = ult_find_fragment(source, length, sublocn);
562 if (fragno != -1 && fragno != 26) {
563 if (fragno <= 18) {
564 subcw[subcodeword_count] = fragno; /* C43 Set 3 codewords 0 to 18 */
565 subcodeword_count++;
566 sublocn += (int) strlen(ult_fragment[fragno]);
567 } else {
568 subcw[subcodeword_count] = fragno + 17; /* C43 Set 3 codewords 36 to 42 */
569 subcodeword_count++;
570 sublocn += (int) strlen(ult_fragment[fragno]);
571 }
572 } else {
573 /* C43 Set 3 codewords 19 to 35 */
574 subcw[subcodeword_count] = posn(ult_c43_set3, source[sublocn]) + 19;
575 subcodeword_count++;
576 sublocn++;
577 }
578 subset = unshift_set;
579 }
580 }
581
582 pad = 3 - (subcodeword_count % 3);
583 if (pad == 3) {
584 pad = 0;
585 }
586
587 for (i = 0; i < pad; i++) {
588 subcw[subcodeword_count] = 42; /* Latch to other C43 set used as pad */
589 subcodeword_count++;
590 }
591
592 if (debug_print) {
593 printf("C43 codewords %.*s: (%d)", length, source + in_locn, subcodeword_count);
594 for (i = 0; i < subcodeword_count; i++) printf( " %d", subcw[i]);
595 fputc('\n', stdout);
596 }
597
598 letters_encoded = sublocn - in_locn;
599 if (encoded != NULL) {
600 *encoded = letters_encoded;
601 }
602
603 for (i = 0; i < subcodeword_count; i += 3) {
604 base43_value = (43 * 43 * subcw[i]) + (43 * subcw[i + 1]) + subcw[i + 2];
605 cw[codeword_count] = base43_value / 282;
606 codeword_count++;
607 cw[codeword_count] = base43_value % 282;
608 codeword_count++;
609 }
610
611 *cw_len = codeword_count;
612
613 if (codeword_count == 0) {
614 return 0.0f;
615 }
616 return (float) letters_encoded / (float) codeword_count;
617 }
618
619 /* Produces a set of codewords which are "somewhat" optimised - this could be improved on */
620 static int ult_generate_codewords(struct zint_symbol *symbol, const unsigned char source[], const int length,
621 const int eci, const int gs1, const int symbol_mode, int *p_current_mode, int codewords[],
622 int codeword_count) {
623 int i;
624 int crop_length;
625 int input_locn = 0;
626 int current_mode;
627 int subset;
628 float eightbit_score;
629 float ascii_score;
630 float c43_score;
631 int end_char;
632 int block_length;
633 int fragment_length;
634 int ascii_encoded, c43_encoded;
635 const int debug_print = (symbol->debug & ZINT_DEBUG_PRINT);
636 unsigned char *crop_source = (unsigned char *) z_alloca(length + 1);
637 char *mode = (char *) z_alloca(length + 1);
638 int *cw_fragment = (int *) z_alloca(sizeof(int) * (length * 2 + 1));
639
640 /* Check for 06 Macro Sequence and crop accordingly */
641 if (length >= 9
642 && source[0] == '[' && source[1] == ')' && source[2] == '>' && source[3] == '\x1e'
643 && source[4] == '0' && source[5] == '6' && source[6] == '\x1d'
644 && source[length - 2] == '\x1e' && source[length - 1] == '\x04') {
645
646 if (symbol_mode == ULT_EIGHTBIT_MODE) {
647 codewords[codeword_count] = 271; /* 06 Macro */
648 } else {
649 codewords[codeword_count] = 273; /* 06 Macro */
650 }
651 codeword_count++;
652
653 for (i = 7; i < (length - 2); i++) {
654 crop_source[i - 7] = source[i];
655 }
656 crop_length = length - 9;
657 crop_source[crop_length] = '\0';
658 } else {
659 /* Make a cropped version of input data - removes http:// and https:// if needed */
660 for (i = input_locn; i < length; i++) {
661 crop_source[i - input_locn] = source[i];
662 }
663 crop_length = length - input_locn;
664 crop_source[crop_length] = '\0';
665 }
666
667 /* Attempt encoding in all three modes to see which offers best compaction and store results */
668 if (symbol->option_3 == ULTRA_COMPRESSION || gs1) {
669 current_mode = symbol_mode;
670 input_locn = 0;
671 do {
672 end_char = input_locn + ULT_PREDICT_WINDOW;
673 eightbit_score = ult_look_ahead_eightbit(crop_source, crop_length, input_locn, current_mode, end_char,
674 cw_fragment, &fragment_length, gs1);
675 ascii_score = ult_look_ahead_ascii(crop_source, crop_length, input_locn, current_mode, symbol_mode,
676 end_char, cw_fragment, &fragment_length, &ascii_encoded, gs1);
677 subset = ult_c43_should_latch_other(crop_source, crop_length, input_locn, 1 /*subset*/) ? 2 : 1;
678 c43_score = ult_look_ahead_c43(crop_source, crop_length, input_locn, current_mode, end_char,
679 subset, cw_fragment, &fragment_length, &c43_encoded, gs1, 0 /*debug_print*/);
680
681 mode[input_locn] = 'a';
682 current_mode = ULT_ASCII_MODE;
683
684 if ((c43_score > ascii_score) && (c43_score > eightbit_score)) {
685 mode[input_locn] = 'c';
686 current_mode = ULT_C43_MODE;
687 } else if ((eightbit_score > ascii_score) && (eightbit_score > c43_score)) {
688 mode[input_locn] = '8';
689 current_mode = ULT_EIGHTBIT_MODE;
690 }
691 if (mode[input_locn] == 'a') {
692 for (i = 0; i < ascii_encoded; i++) {
693 mode[input_locn + i] = 'a';
694 }
695 input_locn += ascii_encoded;
696 } else if (mode[input_locn] == 'c') {
697 for (i = 0; i < c43_encoded; i++) {
698 mode[input_locn + i] = 'c';
699 }
700 input_locn += c43_encoded;
701 } else {
702 input_locn++;
703 }
704 } while (input_locn < crop_length);
705 } else {
706 /* Force eight-bit mode */
707 for (input_locn = 0; input_locn < crop_length; input_locn++) {
708 mode[input_locn] = '8';
709 }
710 }
711 mode[crop_length] = '\0';
712
713 if (debug_print) {
714 printf("Mode (%d): %s\n", (int) strlen(mode), mode);
715 }
716
717 if (symbol_mode == ULT_EIGHTBIT_MODE && *p_current_mode != ULT_EIGHTBIT_MODE) {
718 codewords[codeword_count++] = 282; /* Unlatch to 8-bit mode */
719 }
720
721 if (eci) {
722 if (eci < 899) {
723 codewords[codeword_count++] = 272;
724 codewords[codeword_count++] = eci / 256;
725 codewords[codeword_count++] = eci % 256;
726 } else if (eci < 10000) {
727 codewords[codeword_count++] = 274;
728 codewords[codeword_count++] = eci / 100 + 128;
729 codewords[codeword_count++] = eci % 100 + 128;
730 } else {
731 codewords[codeword_count++] = 275;
732 codewords[codeword_count++] = eci / 10000 + 128;
733 codewords[codeword_count++] = (eci % 10000) / 100 + 128;
734 codewords[codeword_count++] = eci % 100 + 128;
735 }
736 }
737
738 /* Use results from test to perform actual mode switching */
739 current_mode = symbol_mode;
740 input_locn = 0;
741 do {
742 fragment_length = 0;
743 block_length = 0;
744 while (input_locn + block_length < crop_length && mode[input_locn + block_length] == mode[input_locn]) {
745 block_length++;
746 }
747
748 switch (mode[input_locn]) {
749 case 'a':
750 ult_look_ahead_ascii(crop_source, crop_length, input_locn, current_mode, symbol_mode,
751 input_locn + block_length, cw_fragment, &fragment_length, NULL, gs1);
752 current_mode = ULT_ASCII_MODE;
753 break;
754 case 'c':
755 subset = ult_c43_should_latch_other(crop_source, crop_length, input_locn, 1 /*subset*/) ? 2 : 1;
756 ult_look_ahead_c43(crop_source, crop_length, input_locn, current_mode, input_locn + block_length,
757 subset, cw_fragment, &fragment_length, NULL, gs1, debug_print);
758
759 /* Substitute temporary latch if possible */
760 if (current_mode == ULT_EIGHTBIT_MODE && cw_fragment[0] == 260 && fragment_length >= 5
761 && fragment_length <= 11) {
762 cw_fragment[0] = 256 + (fragment_length - 5) / 2; /* Temporary latch to submode 1 from Table 11 */
763 } else if (current_mode == ULT_EIGHTBIT_MODE && cw_fragment[0] == 266 && fragment_length >= 5
764 && fragment_length <= 11) {
765 cw_fragment[0] = 262 + (fragment_length - 5) / 2; /* Temporary latch to submode 2 from Table 11 */
766 } else if (current_mode == ULT_ASCII_MODE && cw_fragment[0] == 278 && fragment_length >= 5
767 && fragment_length <= 11) {
768 cw_fragment[0] = 274 + (fragment_length - 5) / 2; /* Temporary latch to submode 1 from Table 9 */
769 } else {
770 current_mode = ULT_C43_MODE;
771 }
772 break;
773 case '8':
774 ult_look_ahead_eightbit(crop_source, crop_length, input_locn, current_mode, input_locn + block_length,
775 cw_fragment, &fragment_length, gs1);
776 current_mode = ULT_EIGHTBIT_MODE;
777 break;
778 }
779
780 for (i = 0; i < fragment_length; i++) {
781 codewords[codeword_count + i] = cw_fragment[i];
782 }
783 codeword_count += fragment_length;
784
785 input_locn += block_length;
786 } while (input_locn < crop_length);
787
788 *p_current_mode = current_mode;
789
790 return codeword_count;
791 }
792
793 /* Call `ult_generate_codewords()` for each segment, dealing with symbol mode and start codeword beforehand */
794 static int ult_generate_codewords_segs(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count,
795 int codewords[]) {
796 int i;
797 int codeword_count = 0;
798 int symbol_mode;
799 int current_mode;
800 int have_eci = 0;
801 const unsigned char *source = segs[0].source;
802 int length = segs[0].length;
803 const int eci = segs[0].eci;
804 const int gs1 = (symbol->input_mode & 0x07) == GS1_MODE;
805
806 for (i = 0; i < seg_count; i++) {
807 if (segs[i].eci) {
808 have_eci = 1;
809 break;
810 }
811 }
812
813 if (have_eci || (symbol->option_3 != ULTRA_COMPRESSION && !gs1)) {
814 /* Force eight-bit mode by default as other modes are poorly documented */
815 symbol_mode = ULT_EIGHTBIT_MODE;
816 } else {
817 /* Decide start character codeword (from Table 5) */
818 symbol_mode = ULT_ASCII_MODE;
819 for (i = 0; i < length; i++) {
820 if (source[i] >= 0x80) {
821 symbol_mode = ULT_EIGHTBIT_MODE;
822 break;
823 }
824 }
825 }
826
827 if (symbol->output_options & READER_INIT) {
828 /* Reader Initialisation mode */
829 codeword_count = 2;
830 if (symbol_mode == ULT_ASCII_MODE) {
831 codewords[0] = 272; /* 7-bit ASCII mode */
832 codewords[1] = 271; /* FNC3 */
833 } else {
834 codewords[0] = 257; /* 8859-1 */
835 codewords[1] = 269; /* FNC3 */
836 }
837 } else {
838 /* Calculate start character codeword */
839 codeword_count = 1;
840 if (symbol_mode == ULT_ASCII_MODE) {
841 if (gs1) {
842 codewords[0] = 273;
843 } else {
844 codewords[0] = 272;
845 }
846 } else {
847 if ((eci >= 3) && (eci <= 18) && (eci != 14)) {
848 /* ECI indicates use of character set within ISO/IEC 8859 */
849 codewords[0] = 257 + (eci - 3);
850 if (codewords[0] > 267) {
851 /* Avoids ECI 14 for non-existant ISO/IEC 8859-12 */
852 codewords[0]--;
853 }
854 } else if ((eci > 18) && (eci <= 898)) {
855 /* ECI indicates use of character set outside ISO/IEC 8859 */
856 codewords[0] = 275 + (eci / 256);
857 codewords[1] = eci % 256;
858 codeword_count = 2;
859 } else if (eci == 899) {
860 /* Non-language byte data */
861 codewords[0] = 280;
862 } else if ((eci > 899) && (eci <= 9999)) {
863 /* ECI beyond 899 needs to use fixed length encodable ECI invocation (section 7.6.2) */
864 /* Encode as 3 codewords */
865 codewords[0] = 257; /* ISO/IEC 8859-1 used to enter 8-bit mode */
866 codewords[1] = 274; /* Encode ECI as 3 codewords */
867 codewords[2] = (eci / 100) + 128;
868 codewords[3] = (eci % 100) + 128;
869 codeword_count = 4;
870 } else if (eci >= 10000) {
871 /* Encode as 4 codewords */
872 codewords[0] = 257; /* ISO/IEC 8859-1 used to enter 8-bit mode */
873 codewords[1] = 275; /* Encode ECI as 4 codewords */
874 codewords[2] = (eci / 10000) + 128;
875 codewords[3] = ((eci % 10000) / 100) + 128;
876 codewords[4] = (eci % 100) + 128;
877 codeword_count = 5;
878 } else {
879 codewords[0] = 257; /* Default is assumed to be ISO/IEC 8859-1 (ECI 3) */
880 }
881 }
882
883 if ((codewords[0] == 257) || (codewords[0] == 272)) {
884 int fragno = ult_find_fragment(source, length, 0);
885
886 /* Check for http:// at start of input */
887 if ((fragno == 0) || (fragno == 2)) {
888 codewords[0] = 281;
889 source += 7;
890 length -= 7;
891 symbol_mode = ULT_EIGHTBIT_MODE;
892
893 /* Check for https:// at start of input */
894 } else if ((fragno == 1) || (fragno == 3)) {
895 codewords[0] = 282;
896 source += 8;
897 length -= 8;
898 symbol_mode = ULT_EIGHTBIT_MODE;
899 }
900 }
901 }
902
903 current_mode = symbol_mode;
904 codeword_count = ult_generate_codewords(symbol, source, length, 0 /*eci*/, gs1, symbol_mode, &current_mode,
905 codewords, codeword_count);
906
907 for (i = 1; i < seg_count; i++) {
908 codeword_count = ult_generate_codewords(symbol, segs[i].source, segs[i].length, segs[i].eci, gs1, symbol_mode,
909 &current_mode, codewords, codeword_count);
910 }
911
912 return codeword_count;
913 }
914
915 INTERNAL int ultra(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
916 int data_cw_count = 0;
917 int acc, qcc;
918 int scr[3] = {0}, scr_cw_count = 0; /* Symbol Control Region (only if have Structured Append) */
919 int dr_count;
920 int ecc_level;
921 int rows, columns;
922 int total_cws;
923 int pads;
924 int cw_memalloc;
925 /* Allow for 3 pads in final 57th (60th incl. clock tracks) column of 5-row symbol (57 * 5 == 285) */
926 int codeword[282 + 3];
927 int i, j, locn;
928 int total_height, total_width;
929 char tilepat[6];
930 int tilex, tiley;
931 int dcc;
932 int revision_idx = 0;
933 const int debug_print = (symbol->debug & ZINT_DEBUG_PRINT);
934 int *data_codewords;
935 char *pattern;
936
937 (void)seg_count;
938
939 if (symbol->eci > 811799) {
940 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 590, "ECI code '%d' out of range (0 to 811799)",
941 symbol->eci);
942 }
943
944 if (symbol->structapp.count) {
945 int link2 = 2; /* Draft Table 7, Structured Append Group (SAG) with no File Number */
946
947 if (symbol->structapp.count < 2 || symbol->structapp.count > 8) {
948 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 596,
949 "Structured Append count '%d' out of range (2 to 8)", symbol->structapp.count);
950 }
951 if (symbol->structapp.index < 1 || symbol->structapp.index > symbol->structapp.count) {
952 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 597,
953 "Structured Append index '%1$d' out of range (1 to count %2$d)",
954 symbol->structapp.index, symbol->structapp.count);
955 }
956 scr_cw_count = 1;
957
958 if (symbol->structapp.id[0]) {
959 int id, id_len;
960
961 for (id_len = 1; id_len < 6 && symbol->structapp.id[id_len]; id_len++);
962
963 if (id_len > 5) { /* 282 * 283 + 282 = 80088 */
964 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 593,
965 "Structured Append ID length %d too long (5 digit maximum)", id_len);
966 }
967
968 id = to_int((const unsigned char *) symbol->structapp.id, id_len);
969 if (id == -1) {
970 return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 594, "Invalid Structured Append ID (digits only)");
971 }
972 if (id > 80088) {
973 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 595,
974 "Structured Append ID value '%d' out of range (1 to 80088)", id);
975 }
976 if (id) {
977 link2 = 3; /* Missing from draft Table 7 but mentioned 7.4.3 - SAG with File Number */
978 scr[1] = id / 283;
979 scr[2] = id % 283; /* 7.4.3.2 says 1-282 but can be 0 if id >= 283 */
980 scr_cw_count += 2;
981 }
982 }
983
984 scr[0] = link2 * 70 + (symbol->structapp.count - 1) * 8 + symbol->structapp.index - 1;
985 }
986
987 cw_memalloc = segs_length(segs, seg_count) * 2;
988 if (cw_memalloc < 283) {
989 cw_memalloc = 283;
990 }
991
992 data_codewords = (int *) z_alloca(sizeof(int) * cw_memalloc);
993
994 data_cw_count = ult_generate_codewords_segs(symbol, segs, seg_count, data_codewords);
995
996 if (debug_print) {
997 printf("Codewords (%d):", data_cw_count);
998 for (i = 0; i < data_cw_count; i++) {
999 printf(" %d", data_codewords[i]);
1000 }
1001 fputc('\n', stdout);
1002 }
1003 #ifdef ZINT_TEST
1004 if (symbol->debug & ZINT_DEBUG_TEST) {
1005 debug_test_codeword_dump_int(symbol, data_codewords, data_cw_count);
1006 }
1007 #endif
1008
1009 data_cw_count += 2 + scr_cw_count; /* 2 == MCC + ACC (data codeword count includes start char) */
1010
1011 if (symbol->option_2 > 0) {
1012 if (symbol->option_2 > 2) {
1013 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 592, "Revision '%d' out of range (1 or 2 only)",
1014 symbol->option_2);
1015 }
1016 if (symbol->option_2 == 2) { /* Revision 2, swop and inversion of DCCU/DCCL tiles */
1017 revision_idx = 1;
1018 }
1019 }
1020
1021 /* Default ECC level is EC2 */
1022 if ((symbol->option_1 <= 0) || (symbol->option_1 > 6)) {
1023 ecc_level = 2;
1024 } else {
1025 ecc_level = symbol->option_1 - 1;
1026 }
1027
1028 /* ECC calculation from section 7.7.2 */
1029 if (ecc_level == 0) {
1030 qcc = 3;
1031 } else {
1032 if ((data_cw_count % 25) == 0) {
1033 qcc = ult_kec[ecc_level] * (data_cw_count / 25) + 3 + 2;
1034 } else {
1035 qcc = ult_kec[ecc_level] * ((data_cw_count / 25) + 1) + 3 + 2;
1036 }
1037
1038 }
1039 if (debug_print) {
1040 printf("EC%d codewords: %d\n", ecc_level, qcc);
1041 }
1042
1043 acc = qcc - 3;
1044 if (scr_cw_count) {
1045 acc += 70; /* Link1 = 1 (* 70) means SCR present */
1046 }
1047 if (debug_print) {
1048 printf("MCC: %d, ACC: %d, SCR: %d", data_cw_count, acc, scr_cw_count);
1049 if (scr_cw_count) {
1050 printf(", SCR0: %d", scr[0]);
1051 if (scr_cw_count > 1) {
1052 printf(", SCR1: %d, SCR2: %d", scr[1], scr[2]);
1053 }
1054 }
1055 fputc('\n', stdout);
1056 }
1057
1058 /* Maximum capacity is 282 codewords */
1059 total_cws = data_cw_count + qcc + 3; /* 3 == TCC pattern + RSEC pattern + QCC pattern */
1060 if (total_cws - 3 > 282) {
1061 static const int max_data_cws_by_ecc[6] = { 279, 266, 255, 237, 223, 205 };
1062 return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 591,
1063 "Input too long for ECC level EC%1$d, requires %2$d codewords (maximum %3$d)",
1064 ecc_level, data_cw_count, max_data_cws_by_ecc[ecc_level]);
1065 }
1066
1067 rows = 5;
1068 for (i = 2; i >= 0; i--) {
1069 /* Total codewords less 6 (+ SCR) overhead (Start + MCC + ACC (+ SCR) + 3 TCC/RSEC/QCC patterns) */
1070 if (total_cws - (6 + scr_cw_count) <= ult_maxsize[i]) {
1071 rows--;
1072 }
1073 }
1074
1075 if ((total_cws % rows) == 0) {
1076 pads = 0;
1077 columns = total_cws / rows;
1078 } else {
1079 pads = rows - (total_cws % rows);
1080 columns = (total_cws / rows) + 1;
1081 }
1082 columns += columns / 15; /* Secondary vertical clock tracks */
1083
1084 if (debug_print) {
1085 printf("Calculated size is %d rows by %d columns (pads %d)\n", rows, columns, pads);
1086 }
1087
1088 /* Insert MCC and ACC and possibly SCR into data codewords */
1089 for (i = 282; i > 2 + scr_cw_count; i--) {
1090 data_codewords[i] = data_codewords[i - (2 + scr_cw_count)];
1091 }
1092 data_codewords[1] = data_cw_count; /* MCC */
1093 data_codewords[2] = acc; /* ACC */
1094 for (i = 0; i < scr_cw_count; i++) { /* SCR */
1095 data_codewords[3 + i] = scr[i];
1096 }
1097
1098 /* Calculate error correction codewords (RSEC) */
1099
1100 ult_gf283((short) data_cw_count, (short) qcc, data_codewords);
1101
1102 if (debug_print) {
1103 printf("ECCs (%d):", qcc);
1104 for (i = 0; i < qcc; i++) {
1105 printf(" %d", data_codewords[(282 - qcc) + i]);
1106 }
1107 fputc('\n', stdout);
1108 }
1109
1110 /* Rearrange to make final codeword sequence */
1111 locn = 0;
1112 codeword[locn++] = data_codewords[282 - (data_cw_count + qcc)]; /* Start Character */
1113 codeword[locn++] = data_cw_count; /* MCC */
1114 for (i = 0; i < qcc; i++) {
1115 codeword[locn++] = data_codewords[(282 - qcc) + i]; /* RSEC Region */
1116 }
1117 codeword[locn++] = data_cw_count + qcc; /* TCC = C + Q - section 6.11.4 */
1118 codeword[locn++] = 283; /* Separator */
1119 codeword[locn++] = acc; /* ACC */
1120 for (i = 0; i < scr_cw_count; i++) { /* SCR */
1121 codeword[locn++] = scr[i];
1122 }
1123 dr_count = data_cw_count - (3 + scr_cw_count);
1124 for (i = 0; i < dr_count; i++) {
1125 codeword[locn++] = data_codewords[(282 - (dr_count + qcc)) + i]; /* Data Region */
1126 }
1127 for (i = 0; i < pads; i++) {
1128 codeword[locn++] = 284; /* Pad pattern */
1129 }
1130 codeword[locn++] = qcc; /* QCC */
1131
1132 if (debug_print) {
1133 printf("Rearranged codewords with ECC (%d):\n", locn);
1134 for (i = 0; i < locn; i++) {
1135 printf(" %d", codeword[i]);
1136 }
1137 fputc('\n', stdout);
1138 }
1139
1140 total_height = (rows * 6) + 1;
1141 total_width = columns + 6;
1142
1143 /* Build symbol */
1144 pattern = (char *) z_alloca(total_height * total_width);
1145
1146 for (i = 0; i < (total_height * total_width); i++) {
1147 pattern[i] = 'W';
1148 }
1149
1150 /* Border */
1151 for (i = 0; i < total_width; i++) {
1152 pattern[i] = 'K'; /* Top */
1153 pattern[(total_height * total_width) - i - 1] = 'K'; /* Bottom */
1154 }
1155 for (i = 0; i < total_height; i++) {
1156 pattern[total_width * i] = 'K'; /* Left */
1157 pattern[(total_width * i) + 3] = 'K';
1158 pattern[(total_width * i) + (total_width - 1)] = 'K'; /* Right */
1159 }
1160
1161 /* Clock tracks */
1162 for (i = 0; i < total_height; i += 2) {
1163 pattern[(total_width * i) + 1] = 'K'; /* Primary vertical clock track */
1164 if (total_width > 20) {
1165 pattern[(total_width * i) + 19] = 'K'; /* Secondary vertical clock track */
1166 }
1167 if (total_width > 36) {
1168 pattern[(total_width * i) + 35] = 'K'; /* Secondary vertical clock track */
1169 }
1170 if (total_width > 52) {
1171 pattern[(total_width * i) + 51] = 'K'; /* Secondary vertical clock track */
1172 }
1173 }
1174 for (i = 6; i < total_height; i += 6) {
1175 for (j = 5; j < total_width; j += 2) {
1176 pattern[(total_width * i) + j] = 'K'; /* Horizontal clock track */
1177 }
1178 }
1179
1180 /* Place tiles */
1181 tilepat[5] = '\0';
1182 tilex = 0;
1183 tiley = 0;
1184 for (i = 0; i < locn; i++) {
1185 for (j = 0; j < 5; j++) {
1186 tilepat[4 - j] = ult_colour[(ult_tiles[codeword[i]] >> (3 * j)) & 0x07];
1187 }
1188 if ((tiley + 1) >= total_height) {
1189 tiley = 0;
1190 tilex++;
1191
1192 if (tilex == 14) {
1193 tilex++;
1194 } else if (tilex == 30) {
1195 tilex++;
1196 } else if (tilex == 46) {
1197 tilex++;
1198 }
1199 }
1200
1201 for (j = 0; j < 5; j++) {
1202 pattern[((tiley + j + 1) * total_width) + (tilex + 5)] = tilepat[j];
1203 }
1204 tiley += 6;
1205 }
1206
1207 /* Add data column count */
1208 dcc = columns - ult_mincols[rows - 2];
1209 tilex = 2;
1210 tiley = (total_height - 11) / 2;
1211 /* DCCU */
1212 for (j = 0; j < 5; j++) {
1213 tilepat[4 - j] = ult_colour[(ult_dccu[revision_idx][dcc] >> (3 * j)) & 0x07];
1214 }
1215 for (j = 0; j < 5; j++) {
1216 pattern[((tiley + j) * total_width) + tilex] = tilepat[j];
1217 }
1218 /* DCCL */
1219 tiley += 6;
1220 for (j = 0; j < 5; j++) {
1221 tilepat[4 - j] = ult_colour[(ult_dccl[revision_idx][dcc] >> (3 * j)) & 0x07];
1222 }
1223 for (j = 0; j < 5; j++) {
1224 pattern[((tiley + j) * total_width) + tilex] = tilepat[j];
1225 }
1226
1227 if (debug_print) {
1228 printf("DCC: %d\n", dcc);
1229
1230 for (i = 0; i < (total_height * total_width); i++) {
1231 printf("%c", pattern[i]);
1232 if ((i + 1) % total_width == 0) {
1233 fputc('\n', stdout);
1234 }
1235 }
1236 }
1237
1238 /* Put pattern into symbol */
1239 symbol->rows = total_height;
1240 symbol->width = total_width;
1241
1242 for (i = 0; i < total_height; i++) {
1243 symbol->row_height[i] = 1;
1244 for (j = 0; j < total_width; j++) {
1245 set_module_colour(symbol, i, j, posn(ult_colour, pattern[(i * total_width) + j]));
1246 }
1247 }
1248 symbol->height = total_height;
1249
1250 return 0;
1251 }
1252
1253 /* vim: set ts=4 sw=4 et : */