Mercurial > hgrepos > Python2 > PyMuPDF
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, ¤t_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 ¤t_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 : */ |
