Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/zint/backend/codablock.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 /* codablock.c - Handles Codablock-F */ | |
| 2 /* | |
| 3 libzint - the open source barcode library | |
| 4 Copyright (C) 2016-2024 Harald Oehlmann | |
| 5 | |
| 6 Redistribution and use in source and binary forms, with or without | |
| 7 modification, are permitted provided that the following conditions | |
| 8 are met: | |
| 9 | |
| 10 1. Redistributions of source code must retain the above copyright | |
| 11 notice, this list of conditions and the following disclaimer. | |
| 12 2. Redistributions in binary form must reproduce the above copyright | |
| 13 notice, this list of conditions and the following disclaimer in the | |
| 14 documentation and/or other materials provided with the distribution. | |
| 15 3. Neither the name of the project nor the names of its contributors | |
| 16 may be used to endorse or promote products derived from this software | |
| 17 without specific prior written permission. | |
| 18 | |
| 19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
| 20 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | |
| 23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 25 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 26 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 27 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 28 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 29 SUCH DAMAGE. | |
| 30 */ | |
| 31 /* SPDX-License-Identifier: BSD-3-Clause */ | |
| 32 | |
| 33 #include <assert.h> | |
| 34 #include <math.h> | |
| 35 #include <stdio.h> | |
| 36 #include "common.h" | |
| 37 #include "code128.h" | |
| 38 | |
| 39 #define uchar unsigned char | |
| 40 | |
| 41 /* FTab C128 flags - may be added */ | |
| 42 #define CodeA 1 | |
| 43 #define CodeB 2 | |
| 44 #define CodeC 4 | |
| 45 #define CEnd 8 | |
| 46 #define CShift 16 | |
| 47 #define CFill 32 | |
| 48 #define CodeFNC1 64 | |
| 49 #define CodeFNC4 128 | |
| 50 #define ZTNum (CodeA + CodeB + CodeC) | |
| 51 #define ZTFNC1 (CodeA + CodeB + CodeC + CodeFNC1) | |
| 52 | |
| 53 /* ASCII-Extension for Codablock-F */ | |
| 54 #define aFNC1 ((uchar) 128) | |
| 55 #define aFNC2 ((uchar) 129) | |
| 56 #define aFNC3 ((uchar) 130) | |
| 57 #define aFNC4 ((uchar) 131) | |
| 58 #define aCodeA ((uchar) 132) | |
| 59 #define aCodeB ((uchar) 133) | |
| 60 #define aCodeC ((uchar) 134) | |
| 61 #define aShift ((uchar) 135) | |
| 62 | |
| 63 /* Code F Analysing-Chart */ | |
| 64 typedef struct sCharacterSetTable { | |
| 65 int CharacterSet; /* Still possible character sets for actual*/ | |
| 66 int AFollowing; /* Still following Characters in Charset A */ | |
| 67 int BFollowing; /* Still following Characters in Charset B */ | |
| 68 int CFollowing; /* Still following Characters in Charset C */ | |
| 69 } CharacterSetTable; | |
| 70 | |
| 71 /* Find the possible Code-128 Character sets for a character | |
| 72 * The result is an or of CodeA, CodeB, CodeC, CodeFNC1, CodeFNC4 depending on the | |
| 73 * possible Code 128 character sets. | |
| 74 */ | |
| 75 static int GetPossibleCharacterSet(unsigned char C) { | |
| 76 if (C <= '\x1f') /* Control chars */ | |
| 77 return CodeA; | |
| 78 if (z_isdigit(C)) | |
| 79 return ZTNum; /* ZTNum=CodeA+CodeB+CodeC */ | |
| 80 if (C == aFNC1) /* FNC1s (GS1) not used */ | |
| 81 return ZTFNC1; /* ZTFNC1=CodeA+CodeB+CodeC+CodeFNC1 */ /* Not reached */ | |
| 82 if (C == aFNC4) | |
| 83 return (CodeA | CodeB | CodeFNC4); | |
| 84 if (C >= '\x60' && C <= '\x7f') /* 60 to 127 */ | |
| 85 return CodeB; | |
| 86 return CodeA + CodeB; | |
| 87 } | |
| 88 | |
| 89 /* Create a Table with the following information for each Data character: | |
| 90 * int CharacterSet is an or of CodeA, CodeB, CodeC, CodeFNC1, CodeFNC4, | |
| 91 * depending on which character set is applicable. | |
| 92 * (Result of GetPossibleCharacterSet) | |
| 93 * int AFollowing,BFollowing The number of source characters you still may encode | |
| 94 * in this character set. | |
| 95 * int CFollowing The number of characters encodable in CodeC if we | |
| 96 * start here. | |
| 97 */ | |
| 98 static void CreateCharacterSetTable(CharacterSetTable T[], unsigned char *data, const int dataLength) { | |
| 99 int charCur; | |
| 100 int runChar; | |
| 101 | |
| 102 /* Treat the Data backwards */ | |
| 103 charCur = dataLength - 1; | |
| 104 T[charCur].CharacterSet = GetPossibleCharacterSet(data[charCur]); | |
| 105 T[charCur].AFollowing = ((T[charCur].CharacterSet & CodeA) == 0) ? 0 : 1; | |
| 106 T[charCur].BFollowing = ((T[charCur].CharacterSet & CodeB) == 0) ? 0 : 1; | |
| 107 T[charCur].CFollowing = 0; | |
| 108 | |
| 109 for (charCur--; charCur >= 0; charCur--) { | |
| 110 T[charCur].CharacterSet = GetPossibleCharacterSet(data[charCur]); | |
| 111 T[charCur].AFollowing = ((T[charCur].CharacterSet & CodeA) == 0) ? 0 : T[charCur + 1].AFollowing + 1; | |
| 112 T[charCur].BFollowing = ((T[charCur].CharacterSet & CodeB) == 0) ? 0 : T[charCur + 1].BFollowing + 1; | |
| 113 T[charCur].CFollowing = 0; | |
| 114 } | |
| 115 /* Find the CodeC-chains */ | |
| 116 for (charCur = 0; charCur < dataLength; charCur++) { | |
| 117 T[charCur].CFollowing = 0; | |
| 118 if ((T[charCur].CharacterSet & CodeC) != 0) { | |
| 119 /* CodeC possible */ | |
| 120 runChar = charCur; | |
| 121 do { | |
| 122 /* Whether this is FNC1, whether next is */ | |
| 123 /* numeric */ | |
| 124 if (T[runChar].CharacterSet == ZTFNC1) /* FNC1s (GS1) not used */ | |
| 125 ++(T[charCur].CFollowing); /* Not reached */ | |
| 126 else { | |
| 127 ++runChar; | |
| 128 if (runChar >= dataLength) | |
| 129 break; | |
| 130 /* Only a Number may follow */ | |
| 131 if (T[runChar].CharacterSet == ZTNum) | |
| 132 T[charCur].CFollowing += 2; | |
| 133 else | |
| 134 break; | |
| 135 } | |
| 136 ++runChar; | |
| 137 } while (runChar < dataLength); | |
| 138 } | |
| 139 } | |
| 140 } | |
| 141 | |
| 142 /* Find the amount of numerical characters in pairs which will fit in | |
| 143 * one bundle into the line (up to here). This is calculated online because | |
| 144 * it depends on the space in the line. | |
| 145 */ | |
| 146 static int RemainingDigits(CharacterSetTable *T, int charCur, int emptyColumns) { | |
| 147 int digitCount; /* Numerical digits fitting in the line */ | |
| 148 int runChar; | |
| 149 runChar = charCur; | |
| 150 digitCount = 0; | |
| 151 while (emptyColumns > 0 && runChar < charCur + T[charCur].CFollowing) { | |
| 152 if (T[runChar].CharacterSet != ZTFNC1) { | |
| 153 /* NOT FNC1 */ | |
| 154 digitCount += 2; | |
| 155 runChar++; | |
| 156 } | |
| 157 runChar++; | |
| 158 emptyColumns--; | |
| 159 } | |
| 160 return digitCount; | |
| 161 } | |
| 162 | |
| 163 /* Find the Character distribution at a given column count. | |
| 164 * If too many rows (>44) are requested the columns are extended. | |
| 165 * Parameters : | |
| 166 * T Pointer on the Characters which fit in the row | |
| 167 * If a different count is calculated it is corrected | |
| 168 * in the callers workspace. | |
| 169 * pFillings Output of filling characters | |
| 170 * pSet Output of the character sets used, allocated by me. | |
| 171 * Return value Resulting row count | |
| 172 */ | |
| 173 static int Columns2Rows(struct zint_symbol *symbol, CharacterSetTable *T, const int dataLength, int *pRows, | |
| 174 int *pUseColumns, int *pSet, int *pFillings) { | |
| 175 int useColumns; /* Usable Characters per line */ | |
| 176 int fillings = 0; /* Number of filling characters */ | |
| 177 int rowsCur; | |
| 178 int runChar; | |
| 179 int emptyColumns; /* Number of codes still empty in line. */ | |
| 180 int emptyColumns2; /* Alternative emptyColumns to compare */ | |
| 181 int CPaires; /* Number of digit pairs which may fit in the line */ | |
| 182 int characterSetCur; /* Current Character Set */ | |
| 183 int isFNC4; /* Set if current character FNC4 */ | |
| 184 | |
| 185 useColumns = *pUseColumns; | |
| 186 | |
| 187 /* >>> Loop until rowsCur <= 44 */ | |
| 188 do { | |
| 189 int charCur = 0; | |
| 190 memset(pSet, 0, sizeof(int) * dataLength); | |
| 191 rowsCur = 0; | |
| 192 | |
| 193 /* >>> Line Loop */ | |
| 194 do { | |
| 195 /* >> Start Character */ | |
| 196 emptyColumns = useColumns; /* Remained place in Line */ | |
| 197 | |
| 198 /* >>Choose in Set A or B */ | |
| 199 /* (C is changed as an option later on) */ | |
| 200 | |
| 201 pSet[charCur] = characterSetCur = (T[charCur].AFollowing > T[charCur].BFollowing) ? CodeA : CodeB; | |
| 202 | |
| 203 /* >> Test on Numeric Mode C */ | |
| 204 CPaires = RemainingDigits(T, charCur, emptyColumns); | |
| 205 if (CPaires >= 4) { | |
| 206 /* 4 Digits in Numeric compression ->OK */ | |
| 207 /* > May an odd start find more ? */ | |
| 208 /* Skip leading <FNC1>'s */ | |
| 209 /* Typical structure : <FNC1><FNC1>12... */ | |
| 210 /* Test if numeric after one isn't better.*/ | |
| 211 runChar = charCur; | |
| 212 emptyColumns2 = emptyColumns; | |
| 213 while (T[runChar].CharacterSet == ZTFNC1) { /* FNC1s (GS1) not used */ | |
| 214 ++runChar; /* Not reached */ | |
| 215 --emptyColumns2; | |
| 216 } | |
| 217 if (CPaires >= RemainingDigits(T, runChar + 1, emptyColumns2 - 1)) { | |
| 218 /* Start odd is not better */ | |
| 219 /* We start in C */ | |
| 220 pSet[charCur] = characterSetCur = CodeC; | |
| 221 /* Increment charCur */ | |
| 222 if (T[charCur].CharacterSet != ZTFNC1) | |
| 223 ++charCur; /* 2 Num.Digits */ | |
| 224 } | |
| 225 } | |
| 226 ++charCur; | |
| 227 --emptyColumns; | |
| 228 | |
| 229 /* >> Following characters */ | |
| 230 while (emptyColumns > 0 && charCur < dataLength) { | |
| 231 isFNC4 = (T[charCur].CharacterSet & CodeFNC4); | |
| 232 switch (characterSetCur) { | |
| 233 case CodeA: | |
| 234 case CodeB: | |
| 235 /* >> Check switching to CodeC */ | |
| 236 /* Switch if : | |
| 237 * - Character not FNC1 | |
| 238 * - 4 real Digits will fit in line | |
| 239 * - an odd Start will not be better | |
| 240 */ | |
| 241 if (T[charCur].CharacterSet == ZTNum | |
| 242 && (CPaires = RemainingDigits(T, charCur, emptyColumns - 1)) >= 4 | |
| 243 && CPaires > RemainingDigits(T, charCur + 1, emptyColumns - 2)) { | |
| 244 /* > Change to C */ | |
| 245 pSet[charCur] = characterSetCur = CodeC; | |
| 246 charCur += 2; /* 2 Digit */ | |
| 247 emptyColumns -= 2; /* <SwitchC>12 */ | |
| 248 } else if (characterSetCur == CodeA) { | |
| 249 if (T[charCur].AFollowing == 0 || (isFNC4 && T[charCur].AFollowing == 1)) { | |
| 250 /* Must change to B */ | |
| 251 if (emptyColumns == 1 || (isFNC4 && emptyColumns == 2)) { | |
| 252 /* Can't switch: */ | |
| 253 pSet[charCur - 1] |= CEnd + CFill; | |
| 254 emptyColumns = 0; | |
| 255 } else { | |
| 256 /* <Shift> or <switchB>? */ | |
| 257 if (T[charCur].BFollowing == 1 || (isFNC4 && T[charCur].BFollowing == 2)) { | |
| 258 /* Note using order "FNC4 shift char" (same as CODE128) not "shift FNC4 char" | |
| 259 as given in Table B.1 and Table B.2 */ | |
| 260 if (isFNC4) { /* So skip FNC4 and shift value instead */ | |
| 261 --emptyColumns; | |
| 262 ++charCur; | |
| 263 } | |
| 264 pSet[charCur] |= CShift; | |
| 265 } else { | |
| 266 pSet[charCur] |= CodeB; | |
| 267 characterSetCur = CodeB; | |
| 268 } | |
| 269 emptyColumns -= 2; | |
| 270 ++charCur; | |
| 271 } | |
| 272 } else if (isFNC4 && emptyColumns == 1) { | |
| 273 /* Can't fit extended ASCII on same line */ | |
| 274 pSet[charCur - 1] |= CEnd + CFill; | |
| 275 emptyColumns = 0; | |
| 276 } else { | |
| 277 --emptyColumns; | |
| 278 ++charCur; | |
| 279 } | |
| 280 } else { /* Last possibility : CodeB */ | |
| 281 if (T[charCur].BFollowing == 0 || (isFNC4 && T[charCur].BFollowing == 1)) { | |
| 282 /* Must change to A */ | |
| 283 if (emptyColumns == 1 || (isFNC4 && emptyColumns == 2)) { | |
| 284 /* Can't switch: */ | |
| 285 pSet[charCur - 1] |= CEnd + CFill; | |
| 286 emptyColumns = 0; | |
| 287 } else { | |
| 288 /* <Shift> or <switchA>? */ | |
| 289 if (T[charCur].AFollowing == 1 || (isFNC4 && T[charCur].AFollowing == 2)) { | |
| 290 /* Note using order "FNC4 shift char" (same as CODE128) not "shift FNC4 char" | |
| 291 as given in Table B.1 and Table B.2 */ | |
| 292 if (isFNC4) { /* So skip FNC4 and shift value instead */ | |
| 293 --emptyColumns; | |
| 294 ++charCur; | |
| 295 } | |
| 296 pSet[charCur] |= CShift; | |
| 297 } else { | |
| 298 pSet[charCur] |= CodeA; | |
| 299 characterSetCur = CodeA; | |
| 300 } | |
| 301 emptyColumns -= 2; | |
| 302 ++charCur; | |
| 303 } | |
| 304 } else if (isFNC4 && emptyColumns == 1) { | |
| 305 /* Can't fit extended ASCII on same line */ | |
| 306 pSet[charCur - 1] |= CEnd + CFill; | |
| 307 emptyColumns = 0; | |
| 308 } else { | |
| 309 --emptyColumns; | |
| 310 ++charCur; | |
| 311 } | |
| 312 } | |
| 313 break; | |
| 314 case CodeC: | |
| 315 if (T[charCur].CFollowing > 0) { | |
| 316 charCur += (T[charCur].CharacterSet == ZTFNC1) ? 1 : 2; | |
| 317 emptyColumns--; | |
| 318 } else { | |
| 319 /* Must change to A or B */ | |
| 320 if (emptyColumns == 1 || (isFNC4 && emptyColumns == 2)) { | |
| 321 /* Can't switch: */ | |
| 322 pSet[charCur - 1] |= CEnd + CFill; | |
| 323 emptyColumns = 0; | |
| 324 } else { | |
| 325 /*<SwitchA> or <switchA>?*/ | |
| 326 characterSetCur = pSet[charCur] | |
| 327 = (T[charCur].AFollowing > T[charCur].BFollowing) ? CodeA : CodeB; | |
| 328 emptyColumns -= 2; | |
| 329 ++charCur; | |
| 330 } | |
| 331 } | |
| 332 break; | |
| 333 } /* switch */ | |
| 334 } /* while */ | |
| 335 | |
| 336 /* > End of Codeline */ | |
| 337 pSet[charCur - 1] |= CEnd; | |
| 338 ++rowsCur; | |
| 339 } while (charCur < dataLength); /* <= Data.Len-1 */ | |
| 340 | |
| 341 /* Allow for check characters K1, K2 */ | |
| 342 switch (emptyColumns) { | |
| 343 case 1: | |
| 344 pSet[charCur - 1] |= CFill; | |
| 345 /* fall through */ | |
| 346 case 0: | |
| 347 ++rowsCur; | |
| 348 fillings = useColumns - 2 + emptyColumns; | |
| 349 break; | |
| 350 case 2: fillings = 0; break; | |
| 351 default: pSet[charCur - 1] |= CFill; fillings = emptyColumns - 2; | |
| 352 } | |
| 353 | |
| 354 if (rowsCur > 44) { | |
| 355 ++useColumns; | |
| 356 if (useColumns > 62) { | |
| 357 return ZINT_ERROR_TOO_LONG; | |
| 358 } | |
| 359 } else if (rowsCur == 1) { | |
| 360 rowsCur = 2; | |
| 361 fillings += useColumns; | |
| 362 } | |
| 363 } while (rowsCur > 44); | |
| 364 if (symbol->debug & ZINT_DEBUG_PRINT) { | |
| 365 printf(" -> out: rowsCur <%d>, useColumns <%d>, fillings <%d>\n", rowsCur, useColumns, fillings); | |
| 366 } | |
| 367 *pUseColumns = useColumns; | |
| 368 *pRows = rowsCur; | |
| 369 *pFillings = fillings; | |
| 370 return 0; | |
| 371 } | |
| 372 | |
| 373 /* Find columns if row count is given. | |
| 374 */ | |
| 375 static int Rows2Columns(struct zint_symbol *symbol, CharacterSetTable *T, const int dataLength, int *pRows, | |
| 376 int *pUseColumns, int *pSet, int *pFillings) { | |
| 377 int rowsCur; | |
| 378 int rowsRequested; /* Number of requested rows */ | |
| 379 int columnsRequested; /* Number of requested columns (if any) */ | |
| 380 int fillings; | |
| 381 int useColumns; | |
| 382 int testColumns; /* To enter into Width2Rows */ | |
| 383 int testListSize = 0; | |
| 384 int pTestList[62 + 1]; | |
| 385 int *pBackupSet = (int *) z_alloca(sizeof(int) * dataLength); | |
| 386 | |
| 387 rowsRequested = *pRows; | |
| 388 columnsRequested = *pUseColumns >= 4 ? *pUseColumns : 0; | |
| 389 | |
| 390 if (symbol->debug & ZINT_DEBUG_PRINT) { | |
| 391 printf("Optimizer : Searching <%d> rows\n", rowsRequested); | |
| 392 } | |
| 393 | |
| 394 if (columnsRequested) { | |
| 395 testColumns = columnsRequested; | |
| 396 } else { | |
| 397 /* First guess */ | |
| 398 testColumns = dataLength / rowsRequested; | |
| 399 if (testColumns > 62) | |
| 400 testColumns = 62; | |
| 401 else if (testColumns < 4) | |
| 402 testColumns = 4; | |
| 403 } | |
| 404 | |
| 405 for (;;) { | |
| 406 int errorCur; | |
| 407 pTestList[testListSize] = testColumns; | |
| 408 testListSize++; | |
| 409 useColumns = testColumns; /* Make a copy because it may be modified */ | |
| 410 errorCur = Columns2Rows(symbol, T, dataLength, &rowsCur, &useColumns, pSet, &fillings); | |
| 411 if (errorCur != 0) | |
| 412 return errorCur; | |
| 413 if (rowsCur <= rowsRequested) { | |
| 414 /* Less or exactly line number found */ | |
| 415 /* check if column count below already tested or at smallest/requested */ | |
| 416 int fInTestList = (rowsCur == 2 || testColumns == 4 || testColumns == columnsRequested); | |
| 417 int posCur; | |
| 418 for (posCur = 0; posCur < testListSize && !fInTestList; posCur++) { | |
| 419 if (pTestList[posCur] == testColumns - 1) | |
| 420 fInTestList = 1; | |
| 421 } | |
| 422 if (fInTestList) { | |
| 423 /* >> Smaller Width already tested | |
| 424 */ | |
| 425 if (rowsCur < rowsRequested) { | |
| 426 fillings += useColumns * (rowsRequested - rowsCur); | |
| 427 rowsCur = rowsRequested; | |
| 428 } | |
| 429 /* Exit with actual */ | |
| 430 *pFillings = fillings; | |
| 431 *pRows = rowsCur; | |
| 432 *pUseColumns = useColumns; | |
| 433 return 0; | |
| 434 } | |
| 435 /* > Test more rows (shorter CDB) */ | |
| 436 memcpy(pBackupSet, pSet, sizeof(int) * dataLength); | |
| 437 --testColumns; | |
| 438 } else { | |
| 439 /* > Too many rows */ | |
| 440 /* > Test less rows (longer code) */ | |
| 441 memcpy(pBackupSet, pSet, sizeof(int) * dataLength); | |
| 442 if (++testColumns > 62) { | |
| 443 return ZINT_ERROR_TOO_LONG; | |
| 444 } | |
| 445 } | |
| 446 } | |
| 447 } | |
| 448 | |
| 449 /* Print a character in character set A | |
| 450 */ | |
| 451 static void A2C128_A(uchar **ppOutPos, uchar c) { | |
| 452 uchar *pOutPos = *ppOutPos; | |
| 453 switch (c) { | |
| 454 case aCodeB: *pOutPos = 100; break; | |
| 455 case aFNC4: *pOutPos = 101; break; | |
| 456 case aFNC1: *pOutPos = 102; break; /* FNC1s (GS1) not used */ /* Not reached */ | |
| 457 case aFNC2: *pOutPos = 97; break; /* FNC2s (Message Append) not used */ /* Not reached */ | |
| 458 case aFNC3: *pOutPos = 96; break; | |
| 459 case aCodeC: *pOutPos = 99; break; | |
| 460 case aShift: *pOutPos = 98; break; | |
| 461 default: | |
| 462 /* +++ HaO 13.11.98 c>' ' && c < '\x1F' corrected */ | |
| 463 if (c >= ' ' && c <= '_') | |
| 464 *pOutPos = (uchar) (c - ' '); | |
| 465 else | |
| 466 *pOutPos = (uchar) (c + 64); | |
| 467 break; | |
| 468 } | |
| 469 (*ppOutPos)++; | |
| 470 } | |
| 471 | |
| 472 /* Output c in Set B | |
| 473 */ | |
| 474 static void A2C128_B(uchar **ppOutPos, uchar c) { | |
| 475 uchar *pOutPos = *ppOutPos; | |
| 476 switch (c) { | |
| 477 case aFNC1: *pOutPos = 102; break; /* FNC1s (GS1) not used */ /* Not reached */ | |
| 478 case aFNC2: *pOutPos = 97; break; /* FNC2s (Message Append) not used */ /* Not reached */ | |
| 479 case aFNC3: *pOutPos = 96; break; | |
| 480 case aFNC4: *pOutPos = 100; break; | |
| 481 case aCodeA: *pOutPos = 101; break; | |
| 482 case aCodeC: *pOutPos = 99; break; | |
| 483 case aShift: *pOutPos = 98; break; | |
| 484 default: *pOutPos = (uchar) (c - ' '); break; | |
| 485 } | |
| 486 ++(*ppOutPos); | |
| 487 } | |
| 488 | |
| 489 /* Output c1, c2 in Set C | |
| 490 */ | |
| 491 static void A2C128_C(uchar **ppOutPos, uchar c1, uchar c2) { | |
| 492 uchar *pOutPos = *ppOutPos; | |
| 493 switch (c1) { | |
| 494 case aFNC1: *pOutPos = 102; break; /* FNC1s (GS1) not used */ /* Not reached */ | |
| 495 case aCodeB: *pOutPos = 100; break; | |
| 496 case aCodeA: *pOutPos = 101; break; | |
| 497 default: *pOutPos = (uchar) (10 * (c1 - '0') + (c2 - '0')); break; | |
| 498 } | |
| 499 (*ppOutPos)++; | |
| 500 } | |
| 501 | |
| 502 /* Output a character in Characterset | |
| 503 */ | |
| 504 static void ASCIIZ128(uchar **ppOutPos, int CharacterSet, uchar c1, uchar c2) { | |
| 505 if (CharacterSet == CodeA) | |
| 506 A2C128_A(ppOutPos, c1); | |
| 507 else if (CharacterSet == CodeB) | |
| 508 A2C128_B(ppOutPos, c1); | |
| 509 else | |
| 510 A2C128_C(ppOutPos, c1, c2); | |
| 511 } | |
| 512 | |
| 513 /* XLate Tables D.2, D.3 and F.1 of Codablock-F Specification and call output | |
| 514 */ | |
| 515 static void SumASCII(uchar **ppOutPos, int Sum, int CharacterSet) { | |
| 516 switch (CharacterSet) { | |
| 517 case CodeA: /* Row # Indicators and Data Check Characters K1/K2 for CodeA and CodeB are the same */ | |
| 518 case CodeB: | |
| 519 if (Sum <= 31) | |
| 520 A2C128_B(ppOutPos, (uchar) (Sum + 96)); | |
| 521 else if (Sum <= 47) | |
| 522 A2C128_B(ppOutPos, (uchar) Sum); | |
| 523 else | |
| 524 A2C128_B(ppOutPos, (uchar) (Sum + 10)); | |
| 525 break; | |
| 526 case CodeC: | |
| 527 A2C128_C(ppOutPos, (uchar) (Sum / 10 + '0'), (uchar) (Sum % 10 + '0')); | |
| 528 break; | |
| 529 } | |
| 530 } | |
| 531 | |
| 532 /* Main function called by zint framework | |
| 533 */ | |
| 534 INTERNAL int codablockf(struct zint_symbol *symbol, unsigned char source[], int length) { | |
| 535 int charCur, dataLength; | |
| 536 int error_number; | |
| 537 int rows, columns, useColumns; | |
| 538 int fillings; | |
| 539 int Sum1, Sum2; | |
| 540 uchar *pOutPos; | |
| 541 int rowCur; | |
| 542 int characterSetCur; | |
| 543 int emptyColumns; | |
| 544 char dest[1000]; | |
| 545 int r, c; | |
| 546 CharacterSetTable *T; | |
| 547 unsigned char *data; | |
| 548 int *pSet; | |
| 549 uchar *pOutput; | |
| 550 | |
| 551 /* Suppresses clang-analyzer-core.VLASize warning */ | |
| 552 assert(length > 0); | |
| 553 | |
| 554 /* Parameter check */ | |
| 555 /* option1: rows <= 0: automatic, 1..44 */ | |
| 556 rows = symbol->option_1; | |
| 557 if (rows == 1) { | |
| 558 error_number = code128(symbol, source, length); | |
| 559 if (error_number < ZINT_ERROR) { | |
| 560 symbol->output_options |= BARCODE_BIND; | |
| 561 if (symbol->border_width == 0) { /* Allow override if non-zero */ | |
| 562 symbol->border_width = 1; /* AIM ISS-X-24 Section 4.6.1 b) (note change from previous default 2) */ | |
| 563 } | |
| 564 symbol->text[0] = '\0'; /* Disable HRT for compatibility with CODABLOCKF */ | |
| 565 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 566 /* AIM ISS-X-24 Section 4.6.1 minimum row height 8X (for compatibility with CODABLOCKF, not specced | |
| 567 for CODE128) */ | |
| 568 if (error_number == 0) { | |
| 569 error_number = set_height(symbol, 8.0f, 10.0f, 0.0f, 0 /*no_errtxt*/); | |
| 570 } else { | |
| 571 (void) set_height(symbol, 8.0f, 10.0f, 0.0f, 1 /*no_errtxt*/); | |
| 572 } | |
| 573 } else { | |
| 574 (void) set_height(symbol, 0.0f, 5.0f, 0.0f, 1 /*no_errtxt*/); | |
| 575 } | |
| 576 } | |
| 577 return error_number; | |
| 578 } | |
| 579 if (rows > 44) { | |
| 580 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 410, "Number of rows '%d' out of range (0 to 44)", rows); | |
| 581 } | |
| 582 /* option_2: (usable data) columns: <= 0: automatic, 9..67 (min 9 == 4 data, max 67 == 62 data) */ | |
| 583 columns = symbol->option_2; | |
| 584 if (!(columns <= 0 || (columns >= 9 && columns <= 67))) { | |
| 585 return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 411, "Number of columns '%d' out of range (9 to 67)", | |
| 586 columns); | |
| 587 } | |
| 588 if (columns < 0) { /* Protect against negative overflow (ticket #300 (#9) Andre Maute) */ | |
| 589 columns = 0; | |
| 590 } | |
| 591 | |
| 592 data = (unsigned char *) z_alloca(length * 2 + 1); | |
| 593 | |
| 594 dataLength = 0; | |
| 595 if (symbol->output_options & READER_INIT) { | |
| 596 data[dataLength] = aFNC3; | |
| 597 dataLength++; | |
| 598 } | |
| 599 /* Replace all Codes>127 with <fnc4>Code-128 */ | |
| 600 for (charCur = 0; charCur < length; charCur++) { | |
| 601 if (source[charCur] > 127) { | |
| 602 data[dataLength] = aFNC4; | |
| 603 dataLength++; | |
| 604 data[dataLength] = (unsigned char) (source[charCur] & 127); | |
| 605 } else | |
| 606 data[dataLength] = source[charCur]; | |
| 607 dataLength++; | |
| 608 } | |
| 609 | |
| 610 /* Build character set table */ | |
| 611 T = (CharacterSetTable *) z_alloca(sizeof(CharacterSetTable) * dataLength); | |
| 612 pSet = (int *) z_alloca(sizeof(int) * dataLength); | |
| 613 CreateCharacterSetTable(T, data, dataLength); | |
| 614 | |
| 615 /* Find final row and column count */ | |
| 616 /* nor row nor column count given */ | |
| 617 if (rows <= 0 && columns <= 0) { | |
| 618 /* use 1/1 aspect/ratio Codablock */ | |
| 619 columns = (int) floor(sqrt(dataLength)) + 5; | |
| 620 if (columns > 67) { | |
| 621 columns = 67; | |
| 622 } else if (columns < 9) { | |
| 623 columns = 9; | |
| 624 } | |
| 625 if (symbol->debug & ZINT_DEBUG_PRINT) { | |
| 626 printf("Auto column count for %d characters:%d\n", dataLength, columns); | |
| 627 } | |
| 628 } | |
| 629 /* There are 5 Codewords for Organisation Start(2),row(1),CheckSum,Stop */ | |
| 630 useColumns = columns - 5; | |
| 631 if (rows > 0) { | |
| 632 /* row count given */ | |
| 633 error_number = Rows2Columns(symbol, T, dataLength, &rows, &useColumns, pSet, &fillings); | |
| 634 } else { | |
| 635 /* column count given */ | |
| 636 error_number = Columns2Rows(symbol, T, dataLength, &rows, &useColumns, pSet, &fillings); | |
| 637 } | |
| 638 if (error_number != 0) { | |
| 639 return errtxt(error_number, symbol, 413, | |
| 640 "Input too long, requires too many symbol characters (maximum 2726)"); | |
| 641 } | |
| 642 /* Suppresses clang-analyzer-core.VLASize warning */ | |
| 643 assert(rows >= 2 && useColumns >= 4); | |
| 644 | |
| 645 /* Data Check Characters K1 and K2, Annex F */ | |
| 646 Sum1 = Sum2 = 0; | |
| 647 for (charCur = 0; charCur < length; charCur++) { | |
| 648 Sum1 = (Sum1 + (charCur + 1) * source[charCur]) % 86; /* Mod as we go along to avoid overflow */ | |
| 649 Sum2 = (Sum2 + charCur * source[charCur]) % 86; | |
| 650 } | |
| 651 | |
| 652 if (symbol->debug & ZINT_DEBUG_PRINT) { /* start a new level of local variables */ | |
| 653 int DPos; | |
| 654 fputs("\nData:", stdout); | |
| 655 for (DPos = 0; DPos < dataLength; DPos++) | |
| 656 fputc(data[DPos], stdout); | |
| 657 fputs("\n Set:", stdout); | |
| 658 for (DPos = 0; DPos < dataLength; DPos++) { | |
| 659 switch (pSet[DPos] & (CodeA + CodeB + CodeC)) { | |
| 660 case CodeA: fputc('A', stdout); break; | |
| 661 case CodeB: fputc('B', stdout); break; | |
| 662 case CodeC: fputc('C', stdout); break; | |
| 663 default: fputc('.', stdout); break; | |
| 664 } | |
| 665 } | |
| 666 fputs("\nFNC1:", stdout); | |
| 667 for (DPos = 0; DPos < dataLength; DPos++) | |
| 668 fputc((pSet[DPos] & CodeFNC1) == 0 ? '.' : 'X', stdout); | |
| 669 fputs("\n END:", stdout); | |
| 670 for (DPos = 0; DPos < dataLength; DPos++) | |
| 671 fputc((pSet[DPos] & CEnd) == 0 ? '.' : 'X', stdout); | |
| 672 fputs("\nShif:", stdout); | |
| 673 for (DPos = 0; DPos < dataLength; DPos++) | |
| 674 fputc((pSet[DPos] & CShift) == 0 ? '.' : 'X', stdout); | |
| 675 fputs("\nFILL:", stdout); | |
| 676 for (DPos = 0; DPos < dataLength; DPos++) | |
| 677 fputc((pSet[DPos] & CFill) == 0 ? '.' : 'X', stdout); | |
| 678 fputc('\n', stdout); | |
| 679 printf("K1 %d, K2 %d\n", Sum1, Sum2); | |
| 680 } | |
| 681 | |
| 682 columns = useColumns + 5; | |
| 683 | |
| 684 /* >>> Build C128 code numbers */ | |
| 685 /* The C128 column count contains Start (2CW), Row ID, Checksum, Stop */ | |
| 686 pOutput = (unsigned char *) z_alloca(columns * rows); | |
| 687 pOutPos = pOutput; | |
| 688 charCur = 0; | |
| 689 /* >> Loop over rows */ | |
| 690 for (rowCur = 0; rowCur < rows; rowCur++) { | |
| 691 if (charCur >= dataLength) { | |
| 692 /* >> Empty line with StartA, aCodeB, row #, and then filler aCodeC aCodeB etc */ | |
| 693 *pOutPos = '\x67'; | |
| 694 pOutPos++; | |
| 695 *pOutPos = 100; /* aCodeB */ | |
| 696 pOutPos++; | |
| 697 characterSetCur = CodeB; | |
| 698 SumASCII(&pOutPos, rowCur + 42, characterSetCur); /* Row # */ | |
| 699 emptyColumns = useColumns; | |
| 700 if (rowCur == rows - 1) { | |
| 701 emptyColumns -= 2; | |
| 702 } | |
| 703 while (emptyColumns > 0) { | |
| 704 if (characterSetCur == CodeC) { | |
| 705 A2C128_C(&pOutPos, aCodeB, '\0'); | |
| 706 characterSetCur = CodeB; | |
| 707 } else { | |
| 708 A2C128_B(&pOutPos, aCodeC); | |
| 709 characterSetCur = CodeC; | |
| 710 } | |
| 711 --emptyColumns; | |
| 712 } | |
| 713 } else { | |
| 714 /* >> Normal Line */ | |
| 715 /* > Startcode */ | |
| 716 switch (pSet[charCur] & (CodeA + CodeB + CodeC)) { | |
| 717 case CodeA: | |
| 718 *pOutPos = '\x67'; | |
| 719 pOutPos++; | |
| 720 *pOutPos = '\x62'; | |
| 721 pOutPos++; | |
| 722 characterSetCur = CodeA; | |
| 723 break; | |
| 724 case CodeB: | |
| 725 *pOutPos = '\x67'; | |
| 726 pOutPos++; | |
| 727 *pOutPos = '\x64'; | |
| 728 pOutPos++; | |
| 729 characterSetCur = CodeB; | |
| 730 break; | |
| 731 case CodeC: | |
| 732 default: | |
| 733 *pOutPos = '\x67'; | |
| 734 pOutPos++; | |
| 735 *pOutPos = '\x63'; | |
| 736 pOutPos++; | |
| 737 characterSetCur = CodeC; | |
| 738 break; | |
| 739 } | |
| 740 /* > Set F1 */ | |
| 741 /* In first line : # of rows */ | |
| 742 SumASCII(&pOutPos, rowCur == 0 ? rows - 2 : rowCur + 42, characterSetCur); | |
| 743 /* >>> Data */ | |
| 744 emptyColumns = useColumns; | |
| 745 /* >> Character loop */ | |
| 746 while (emptyColumns > 0 && charCur < dataLength) { | |
| 747 /* ? Change character set */ | |
| 748 if (emptyColumns < useColumns) { | |
| 749 if ((pSet[charCur] & CodeA) != 0) { | |
| 750 /* Change to A */ | |
| 751 ASCIIZ128(&pOutPos, characterSetCur, aCodeA, '\0'); | |
| 752 --emptyColumns; | |
| 753 characterSetCur = CodeA; | |
| 754 } else if ((pSet[charCur] & CodeB) != 0) { | |
| 755 /* Change to B */ | |
| 756 ASCIIZ128(&pOutPos, characterSetCur, aCodeB, '\0'); | |
| 757 --emptyColumns; | |
| 758 characterSetCur = CodeB; | |
| 759 } else if ((pSet[charCur] & CodeC) != 0) { | |
| 760 /* Change to C */ | |
| 761 ASCIIZ128(&pOutPos, characterSetCur, aCodeC, '\0'); | |
| 762 --emptyColumns; | |
| 763 characterSetCur = CodeC; | |
| 764 } | |
| 765 } | |
| 766 if ((pSet[charCur] & CShift) != 0) { | |
| 767 /* >> Shift it and put out the shifted character */ | |
| 768 ASCIIZ128(&pOutPos, characterSetCur, aShift, '\0'); | |
| 769 emptyColumns -= 2; | |
| 770 characterSetCur = (characterSetCur == CodeB) ? CodeA : CodeB; | |
| 771 ASCIIZ128(&pOutPos, characterSetCur, data[charCur], '\0'); | |
| 772 characterSetCur = (characterSetCur == CodeB) ? CodeA : CodeB; | |
| 773 } else { | |
| 774 /* Normal Character */ | |
| 775 if (characterSetCur == CodeC) { | |
| 776 if (data[charCur] == aFNC1) /* FNC1s (GS1) not used */ | |
| 777 A2C128_C(&pOutPos, aFNC1, '\0'); /* Not reached */ | |
| 778 else { | |
| 779 A2C128_C(&pOutPos, data[charCur], | |
| 780 (uchar) (charCur + 1 < dataLength ? data[charCur + 1] : 0)); | |
| 781 ++charCur; | |
| 782 /* We need this here to get the good index */ | |
| 783 /* for the termination flags in Set. */ | |
| 784 } | |
| 785 } else | |
| 786 ASCIIZ128(&pOutPos, characterSetCur, data[charCur], '\0'); | |
| 787 --emptyColumns; | |
| 788 } | |
| 789 /* >> End Criteria */ | |
| 790 if ((pSet[charCur] & CFill) || (pSet[charCur] & CEnd)) { | |
| 791 /* Fill Line but leave space for checks in last line */ | |
| 792 if (rowCur == rows - 1) { | |
| 793 emptyColumns -= 2; | |
| 794 } | |
| 795 while (emptyColumns > 0) { | |
| 796 switch (characterSetCur) { | |
| 797 case CodeC: | |
| 798 A2C128_C(&pOutPos, aCodeB, '\0'); | |
| 799 characterSetCur = CodeB; | |
| 800 break; | |
| 801 case CodeB: | |
| 802 A2C128_B(&pOutPos, aCodeC); | |
| 803 characterSetCur = CodeC; | |
| 804 break; | |
| 805 case CodeA: | |
| 806 A2C128_A(&pOutPos, aCodeC); | |
| 807 characterSetCur = CodeC; | |
| 808 break; | |
| 809 } | |
| 810 --emptyColumns; | |
| 811 } | |
| 812 } | |
| 813 ++charCur; | |
| 814 } /* Loop over characters */ | |
| 815 } /* if filling-Line / normal */ | |
| 816 | |
| 817 /* Add checksum in last line */ | |
| 818 if (rowCur == rows - 1) { | |
| 819 SumASCII(&pOutPos, Sum1, characterSetCur); | |
| 820 SumASCII(&pOutPos, Sum2, characterSetCur); | |
| 821 } | |
| 822 /* Add Code 128 checksum */ | |
| 823 { | |
| 824 int Sum = pOutput[columns * rowCur] % 103; | |
| 825 int Pos = 1; | |
| 826 for (; Pos < useColumns + 3; Pos++) { | |
| 827 Sum = (Sum + pOutput[columns * rowCur + Pos] * Pos) % 103; | |
| 828 } | |
| 829 *pOutPos = (uchar) Sum; | |
| 830 pOutPos++; | |
| 831 } | |
| 832 /* Add end character */ | |
| 833 *pOutPos = 106; | |
| 834 pOutPos++; | |
| 835 } /* End Lineloop */ | |
| 836 | |
| 837 if (symbol->debug & ZINT_DEBUG_PRINT) { | |
| 838 /* Dump the output to the screen | |
| 839 */ | |
| 840 fputs("\nCode 128 Code Numbers:\n", stdout); | |
| 841 { /* start a new level of local variables */ | |
| 842 int DPos, DPos2; | |
| 843 for (DPos = 0; DPos < rows; DPos++) { | |
| 844 for (DPos2 = 0; DPos2 < columns; DPos2++) { | |
| 845 printf("%3d ", (int) (pOutput[DPos * columns + DPos2])); | |
| 846 } | |
| 847 fputc('\n', stdout); | |
| 848 } | |
| 849 } | |
| 850 printf("rows=%d columns=%d (%d data) fillings=%d\n", rows, columns, columns - 5, fillings); | |
| 851 } | |
| 852 #ifdef ZINT_TEST | |
| 853 if (symbol->debug & ZINT_DEBUG_TEST) { | |
| 854 debug_test_codeword_dump(symbol, pOutput, rows * columns); | |
| 855 } | |
| 856 #endif | |
| 857 | |
| 858 /* Paint the C128 patterns */ | |
| 859 for (r = 0; r < rows; r++) { | |
| 860 const int rc = r * columns; | |
| 861 char *d = dest; | |
| 862 for (c = 0; c < columns - 1; c++, d += 6) { | |
| 863 memcpy(d, C128Table[pOutput[rc + c]], 6); | |
| 864 } | |
| 865 memcpy(d, "2331112", 7); /* Stop character (106, not in C128Table) */ | |
| 866 d += 7; | |
| 867 expand(symbol, dest, d - dest); | |
| 868 } | |
| 869 | |
| 870 if (symbol->output_options & COMPLIANT_HEIGHT) { | |
| 871 /* AIM ISS-X-24 Section 4.6.1 minimum row height; use 10 * rows as default */ | |
| 872 float min_row_height = stripf(0.55f * useColumns + 3.0f); | |
| 873 if (min_row_height < 8.0f) { | |
| 874 min_row_height = 8.0f; | |
| 875 } | |
| 876 error_number = set_height(symbol, min_row_height, (min_row_height > 10.0f ? min_row_height : 10.0f) * rows, | |
| 877 0.0f, 0 /*no_errtxt*/); | |
| 878 } else { | |
| 879 (void) set_height(symbol, 0.0f, 10.0f * rows, 0.0f, 1 /*no_errtxt*/); | |
| 880 } | |
| 881 | |
| 882 symbol->output_options |= BARCODE_BIND; | |
| 883 | |
| 884 if (symbol->border_width == 0) { /* Allow override if non-zero */ | |
| 885 symbol->border_width = 1; /* AIM ISS-X-24 Section 4.6.1 b) (note change from previous default 2) */ | |
| 886 } | |
| 887 | |
| 888 return error_number; | |
| 889 } | |
| 890 | |
| 891 /* vim: set ts=4 sw=4 et : */ |
