Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/zint/backend/tests/testcommon.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 /* | |
| 2 libzint - the open source barcode library | |
| 3 Copyright (C) 2019-2024 Robin Stuart <rstuart114@gmail.com> | |
| 4 | |
| 5 Redistribution and use in source and binary forms, with or without | |
| 6 modification, are permitted provided that the following conditions | |
| 7 are met: | |
| 8 | |
| 9 1. Redistributions of source code must retain the above copyright | |
| 10 notice, this list of conditions and the following disclaimer. | |
| 11 2. Redistributions in binary form must reproduce the above copyright | |
| 12 notice, this list of conditions and the following disclaimer in the | |
| 13 documentation and/or other materials provided with the distribution. | |
| 14 3. Neither the name of the project nor the names of its contributors | |
| 15 may be used to endorse or promote products derived from this software | |
| 16 without specific prior written permission. | |
| 17 | |
| 18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
| 19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 20 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
| 21 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE | |
| 22 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 23 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
| 24 OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
| 25 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
| 26 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
| 27 OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 28 SUCH DAMAGE. | |
| 29 */ | |
| 30 /* | |
| 31 * Adapted from qrencode/tests/common.c | |
| 32 * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org> | |
| 33 */ | |
| 34 /* Due to above: */ | |
| 35 /* SPDX-License-Identifier: LGPL-2.1+ */ | |
| 36 | |
| 37 #ifdef _WIN32 | |
| 38 #include <windows.h> | |
| 39 #include <direct.h> | |
| 40 #include <wchar.h> | |
| 41 #endif | |
| 42 #ifndef ZINT_NO_PNG | |
| 43 #include <png.h> | |
| 44 #include <zlib.h> | |
| 45 #include <setjmp.h> | |
| 46 #endif | |
| 47 #include <assert.h> | |
| 48 #include <limits.h> | |
| 49 #include <sys/stat.h> | |
| 50 | |
| 51 #include "testcommon.h" | |
| 52 #include "../eci.h" | |
| 53 #include "../output.h" | |
| 54 | |
| 55 static int testTests = 0; | |
| 56 static int testFailed = 0; | |
| 57 static int testSkipped = 0; | |
| 58 static int testDataset = 0; | |
| 59 static int testDatasetNum = 0; | |
| 60 static int testDatasetTot = 0; | |
| 61 int testAssertFailed = 0; | |
| 62 int testAssertNum = 0; | |
| 63 static int testAssertTot = 0; | |
| 64 struct zint_symbol **testAssertPPSymbol = NULL; | |
| 65 const char *testAssertFilename = ""; | |
| 66 static const char *testName = NULL; | |
| 67 static const char *testFunc = NULL; | |
| 68 | |
| 69 /* Visual C++ 6 doesn't support variadic args to macros, so make do with functions, which have inferior behaviour, | |
| 70 e.g. don't exit on failure, `assert_equal()` type-specific */ | |
| 71 #if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(ZINT_IS_C89) /* VC6 or C89 */ | |
| 72 #include <stdarg.h> | |
| 73 void assert_zero(int exp, const char *fmt, ...) { | |
| 74 testAssertNum++; | |
| 75 if (exp != 0) { | |
| 76 va_list args; testAssertFailed++; va_start(args, fmt); vprintf(fmt, args); va_end(args); testFinish(); | |
| 77 if (testAssertPPSymbol) { ZBarcode_Delete(*testAssertPPSymbol); testAssertPPSymbol = NULL; }; | |
| 78 } | |
| 79 } | |
| 80 void assert_nonzero(int exp, const char *fmt, ...) { | |
| 81 testAssertNum++; | |
| 82 if (exp == 0) { | |
| 83 va_list args; testAssertFailed++; va_start(args, fmt); vprintf(fmt, args); va_end(args); testFinish(); | |
| 84 if (testAssertPPSymbol) { ZBarcode_Delete(*testAssertPPSymbol); testAssertPPSymbol = NULL; }; | |
| 85 } | |
| 86 } | |
| 87 void assert_null(const void *exp, const char *fmt, ...) { | |
| 88 testAssertNum++; | |
| 89 if (exp != NULL) { | |
| 90 va_list args; testAssertFailed++; va_start(args, fmt); vprintf(fmt, args); va_end(args); testFinish(); | |
| 91 if (testAssertPPSymbol) { ZBarcode_Delete(*testAssertPPSymbol); testAssertPPSymbol = NULL; }; | |
| 92 } | |
| 93 } | |
| 94 void assert_nonnull(const void *exp, const char *fmt, ...) { | |
| 95 testAssertNum++; | |
| 96 if (exp == NULL) { | |
| 97 va_list args; testAssertFailed++; va_start(args, fmt); vprintf(fmt, args); va_end(args); testFinish(); | |
| 98 if (testAssertPPSymbol) { ZBarcode_Delete(*testAssertPPSymbol); testAssertPPSymbol = NULL; }; | |
| 99 } | |
| 100 } | |
| 101 void assert_equal(int e1, int e2, const char *fmt, ...) { | |
| 102 testAssertNum++; | |
| 103 if (e1 != e2) { | |
| 104 va_list args; testAssertFailed++; va_start(args, fmt); vprintf(fmt, args); va_end(args); testFinish(); | |
| 105 if (testAssertPPSymbol) { ZBarcode_Delete(*testAssertPPSymbol); testAssertPPSymbol = NULL; }; | |
| 106 } | |
| 107 } | |
| 108 void assert_equalu64(uint64_t e1, uint64_t e2, const char *fmt, ...) { | |
| 109 testAssertNum++; | |
| 110 if (e1 != e2) { | |
| 111 va_list args; testAssertFailed++; va_start(args, fmt); vprintf(fmt, args); va_end(args); testFinish(); | |
| 112 if (testAssertPPSymbol) { ZBarcode_Delete(*testAssertPPSymbol); testAssertPPSymbol = NULL; }; | |
| 113 } | |
| 114 } | |
| 115 void assert_notequal(int e1, int e2, const char *fmt, ...) { | |
| 116 testAssertNum++; | |
| 117 if (e1 == e2) { | |
| 118 va_list args; testAssertFailed++; va_start(args, fmt); vprintf(fmt, args); va_end(args); testFinish(); | |
| 119 if (testAssertPPSymbol) { ZBarcode_Delete(*testAssertPPSymbol); testAssertPPSymbol = NULL; }; | |
| 120 } | |
| 121 } | |
| 122 #endif | |
| 123 | |
| 124 #ifdef _WIN32 | |
| 125 #define utf8_to_wide(u, w) \ | |
| 126 { \ | |
| 127 int lenW; /* Includes NUL terminator */ \ | |
| 128 if ((lenW = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u, -1, NULL, 0)) == 0) return 0; \ | |
| 129 w = (wchar_t *) z_alloca(sizeof(wchar_t) * lenW); \ | |
| 130 if (MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, u, -1, w, lenW) == 0) return 0; \ | |
| 131 } | |
| 132 #endif | |
| 133 | |
| 134 /* Begin individual test function */ | |
| 135 void testStartReal(const char *func, const char *name, struct zint_symbol **pp_symbol) { | |
| 136 testTests++; | |
| 137 if (func && *func && name && *name && strcmp(func, name) == 0) { | |
| 138 testName = ""; | |
| 139 } else { | |
| 140 testName = name; | |
| 141 } | |
| 142 testFunc = func ? func : ""; | |
| 143 testDataset = 0; | |
| 144 testDatasetNum = 0; | |
| 145 testAssertFailed = 0; | |
| 146 testAssertNum = 0; | |
| 147 testAssertPPSymbol = pp_symbol; | |
| 148 printf("_____%d: %s: %s...\n", testTests, testFunc, testName ? testName : ""); | |
| 149 } | |
| 150 | |
| 151 /* End individual test function */ | |
| 152 void testFinish(void) { | |
| 153 testAssertTot += testAssertNum; | |
| 154 testDatasetTot += testDatasetNum; | |
| 155 fputs(testAssertFailed ? "*****" : ".....", stdout); | |
| 156 if (testName && *testName) { | |
| 157 printf("%d: %s: %s ", testTests, testFunc, testName); | |
| 158 } else { | |
| 159 printf("%d: %s: ", testTests, testFunc); | |
| 160 } | |
| 161 if (testAssertFailed) { | |
| 162 printf("FAILED. (%d assertions failed)\n", testAssertFailed); | |
| 163 testFailed++; | |
| 164 } else if (testDataset) { | |
| 165 if (testAssertNum) { | |
| 166 printf("PASSED. (%d assertions, %d dataset items)\n", testAssertNum, testDatasetNum); | |
| 167 } else { | |
| 168 printf("EMPTY. (***No assertions executed***)\n"); | |
| 169 } | |
| 170 } else { | |
| 171 if (testAssertNum) { | |
| 172 printf("PASSED. (%d assertions)\n", testAssertNum); | |
| 173 } else { | |
| 174 printf("EMPTY. (***No assertions executed***)\n"); | |
| 175 } | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 /* Skip (and end) individual test function */ | |
| 180 void testSkip(const char *msg) { | |
| 181 testSkipped++; | |
| 182 testAssertTot += testAssertNum; | |
| 183 testDatasetTot += testDatasetNum; | |
| 184 fputs(testAssertFailed ? "*****" : ".....", stdout); | |
| 185 if (testName && *testName) { | |
| 186 printf("%d: %s: %s ", testTests, testFunc, testName); | |
| 187 } else { | |
| 188 printf("%d: %s: ", testTests, testFunc); | |
| 189 } | |
| 190 if (testAssertFailed) { | |
| 191 printf("FAILED. (%d assertions failed)\n", testAssertFailed); | |
| 192 testFailed++; | |
| 193 } else if (testDataset) { | |
| 194 printf("SKIPPED. %s. (%d assertions, %d dataset items)\n", msg, testAssertNum, testDatasetNum); | |
| 195 } else { | |
| 196 printf("SKIPPED. %s. (%d assertions)\n", msg, testAssertNum); | |
| 197 } | |
| 198 } | |
| 199 | |
| 200 /* End test program */ | |
| 201 void testReport(void) { | |
| 202 if (testFailed && testSkipped) { | |
| 203 printf("Total %d tests, %d skipped, %d **fails**.\n", testTests, testSkipped, testFailed); | |
| 204 exit(-1); | |
| 205 } | |
| 206 if (testFailed) { | |
| 207 printf("Total %d tests, %d **fails**.\n", testTests, testFailed); | |
| 208 exit(-1); | |
| 209 } | |
| 210 if (testSkipped) { | |
| 211 printf("Total %d tests, %d skipped.\n", testTests, testSkipped); | |
| 212 } else if (testTests) { | |
| 213 if (testAssertTot) { | |
| 214 if (testDatasetTot) { | |
| 215 printf("Total %d tests (%d assertions, %d dataset items), all passed.\n", | |
| 216 testTests, testAssertTot, testDatasetTot); | |
| 217 } else { | |
| 218 printf("Total %d tests (%d assertions), all passed.\n", testTests, testAssertTot); | |
| 219 } | |
| 220 } else { | |
| 221 printf("***No assertions executed in %d tests.***\n", testTests); | |
| 222 } | |
| 223 } else { | |
| 224 fputs("***No tests run.***\n", stdout); | |
| 225 } | |
| 226 } | |
| 227 | |
| 228 /* Verifies that a string `src` (length <= 9) only uses digits. On success returns value in `p_val` */ | |
| 229 static int validate_int(const char src[], int *p_val) { | |
| 230 int val = 0; | |
| 231 int i; | |
| 232 const int length = (int) strlen(src); | |
| 233 | |
| 234 if (length > 9) { /* Prevent overflow */ | |
| 235 return 0; | |
| 236 } | |
| 237 for (i = 0; i < length; i++) { | |
| 238 if (src[i] < '0' || src[i] > '9') { | |
| 239 return 0; | |
| 240 } | |
| 241 val *= 10; | |
| 242 val += src[i] - '0'; | |
| 243 } | |
| 244 *p_val = val; | |
| 245 | |
| 246 return 1; | |
| 247 } | |
| 248 | |
| 249 /* Verifies that a string `src` only uses digits or a hyphen-separated range of digits. | |
| 250 On success returns value in `p_val` and if present a range end value in `p_val_end` */ | |
| 251 static int validate_int_range(const char src[], int *p_val, int *p_val_end) { | |
| 252 int val = 0; | |
| 253 int val_end = -1; | |
| 254 const int length = (int) strlen(src); | |
| 255 int i, j; | |
| 256 | |
| 257 for (i = 0; i < length; i++) { | |
| 258 if (src[i] < '0' || src[i] > '9') { | |
| 259 if (src[i] != '-') { | |
| 260 return 0; | |
| 261 } | |
| 262 val_end = 0; | |
| 263 for (j = i + 1; j < length; j++) { | |
| 264 if (src[j] < '0' || src[j] > '9') { | |
| 265 return 0; | |
| 266 } | |
| 267 if (j - (i + 1) >= 9) { /* Prevent overflow */ | |
| 268 return 0; | |
| 269 } | |
| 270 val_end *= 10; | |
| 271 val_end += src[j] - '0'; | |
| 272 } | |
| 273 break; | |
| 274 } | |
| 275 if (i >= 9) { /* Prevent overflow */ | |
| 276 return 0; | |
| 277 } | |
| 278 val *= 10; | |
| 279 val += src[i] - '0'; | |
| 280 } | |
| 281 *p_val = val; | |
| 282 *p_val_end = val_end; | |
| 283 | |
| 284 return 1; | |
| 285 } | |
| 286 | |
| 287 /* Begin test program, parse args */ | |
| 288 void testRun(int argc, char *argv[], testFunction funcs[], int funcs_size) { | |
| 289 int i, ran; | |
| 290 char *optarg; | |
| 291 char *func = NULL; | |
| 292 char func_buf[256 + 5]; | |
| 293 char *func_not = NULL; | |
| 294 char func_not_buf[256 + 5]; | |
| 295 char *func_match = NULL; | |
| 296 int exclude_idx = 0; | |
| 297 testCtx ctx; | |
| 298 | |
| 299 ctx.index = ctx.index_end = -1; | |
| 300 for (i = 0; i < ZINT_TEST_CTX_EXC_MAX; i++) { | |
| 301 ctx.exclude[i] = ctx.exclude_end[i] = -1; | |
| 302 } | |
| 303 ctx.generate = ctx.debug = 0; | |
| 304 | |
| 305 if (argc) { | |
| 306 const char *filename; | |
| 307 #ifdef _WIN32 | |
| 308 if ((filename = strrchr(argv[0], '\\')) == NULL) { | |
| 309 filename = strrchr(argv[0], '/'); | |
| 310 } | |
| 311 #else | |
| 312 filename = strrchr(argv[0], '/'); | |
| 313 #endif | |
| 314 if (filename) { | |
| 315 testAssertFilename = filename + 1; | |
| 316 } else { | |
| 317 testAssertFilename = argv[0]; | |
| 318 } | |
| 319 } | |
| 320 | |
| 321 for (i = 1; i < argc; i++) { | |
| 322 if (strcmp(argv[i], "-d") == 0) { | |
| 323 if (i + 1 == argc) { | |
| 324 fprintf(stderr, "***testRun: -d debug value missing, ignoring***\n"); | |
| 325 } else { | |
| 326 int d; /* Allow multiple debug flags, OR-ing */ | |
| 327 optarg = argv[++i]; | |
| 328 if (!validate_int(optarg, &d)) { | |
| 329 fprintf(stderr, "***testRun: -d debug value invalid, ignoring***\n"); | |
| 330 } else { | |
| 331 ctx.debug |= d; | |
| 332 } | |
| 333 } | |
| 334 } else if (strcmp(argv[i], "-f") == 0) { | |
| 335 if (i + 1 == argc) { | |
| 336 fprintf(stderr, "***testRun: -f func value missing, ignoring***\n"); | |
| 337 } else { | |
| 338 optarg = argv[++i]; | |
| 339 if (strlen(optarg) < 256) { | |
| 340 if (strncmp(optarg, "test_", 5) == 0) { | |
| 341 strcpy(func_buf, optarg); | |
| 342 } else { | |
| 343 strcpy(func_buf, "test_"); | |
| 344 strcat(func_buf, optarg); | |
| 345 } | |
| 346 func = func_buf; | |
| 347 } else { | |
| 348 fprintf(stderr, "***testRun: -f func value too long, ignoring***\n"); | |
| 349 func = NULL; | |
| 350 } | |
| 351 } | |
| 352 } else if (strcmp(argv[i], "-n") == 0) { | |
| 353 if (i + 1 == argc) { | |
| 354 fprintf(stderr, "***testRun: -n func exclude value missing, ignoring***\n"); | |
| 355 } else { | |
| 356 optarg = argv[++i]; | |
| 357 if (strlen(optarg) < 256) { | |
| 358 if (strncmp(optarg, "test_", 5) == 0) { | |
| 359 strcpy(func_not_buf, optarg); | |
| 360 } else { | |
| 361 strcpy(func_not_buf, "test_"); | |
| 362 strcat(func_not_buf, optarg); | |
| 363 } | |
| 364 func_not = func_not_buf; | |
| 365 } else { | |
| 366 fprintf(stderr, "***testRun: -p func exclude value too long, ignoring***\n"); | |
| 367 func_not = NULL; | |
| 368 } | |
| 369 } | |
| 370 } else if (strcmp(argv[i], "-m") == 0) { | |
| 371 if (i + 1 == argc) { | |
| 372 fprintf(stderr, "***testRun: -m func match value missing, ignoring***\n"); | |
| 373 } else { | |
| 374 func_match = argv[++i]; | |
| 375 } | |
| 376 } else if (strcmp(argv[i], "-g") == 0) { | |
| 377 ctx.generate = 1; | |
| 378 } else if (strcmp(argv[i], "-i") == 0) { | |
| 379 if (i + 1 == argc) { | |
| 380 fprintf(stderr, "***testRun: -i index value missing, ignoring***\n"); | |
| 381 } else { | |
| 382 optarg = argv[++i]; | |
| 383 if (!validate_int_range(optarg, &ctx.index, &ctx.index_end)) { | |
| 384 fprintf(stderr, "***testRun: -i index value invalid, ignoring***\n"); | |
| 385 ctx.index = ctx.index_end = -1; | |
| 386 } | |
| 387 } | |
| 388 } else if (strcmp(argv[i], "-x") == 0) { | |
| 389 if (i + 1 == argc) { | |
| 390 fprintf(stderr, "***testRun: -x exclude value missing, ignoring***\n"); | |
| 391 } else { | |
| 392 optarg = argv[++i]; | |
| 393 if (exclude_idx + 1 == ZINT_TEST_CTX_EXC_MAX) { | |
| 394 fprintf(stderr, "***testRun: too many -x exclude values, ignoring***\n"); | |
| 395 } else if (!validate_int_range(optarg, &ctx.exclude[exclude_idx], &ctx.exclude_end[exclude_idx])) { | |
| 396 fprintf(stderr, "***testRun: -x exclude value invalid, ignoring***\n"); | |
| 397 ctx.exclude[exclude_idx] = ctx.exclude_end[exclude_idx] = -1; | |
| 398 } else { | |
| 399 exclude_idx++; | |
| 400 } | |
| 401 } | |
| 402 } else { | |
| 403 fprintf(stderr, "***testRun: unknown arg '%s', ignoring***\n", argv[i]); | |
| 404 } | |
| 405 } | |
| 406 | |
| 407 ran = 0; | |
| 408 for (i = 0; i < funcs_size; i++) { | |
| 409 if (func && strcmp(func, funcs[i].name) != 0) { | |
| 410 continue; | |
| 411 } | |
| 412 if (func_not && strcmp(func_not, funcs[i].name) == 0) { | |
| 413 continue; | |
| 414 } | |
| 415 if (func_match && strstr(funcs[i].name, func_match) == NULL) { | |
| 416 continue; | |
| 417 } | |
| 418 (*funcs[i].func)(&ctx); | |
| 419 ran++; | |
| 420 } | |
| 421 | |
| 422 if (func && !ran) { | |
| 423 fprintf(stderr, "***testRun: unknown -f func arg '%s'***\n", func); | |
| 424 } | |
| 425 if (func_match && !ran) { | |
| 426 fprintf(stderr, "***testRun: no funcs matched -m arg '%s'***\n", func_match); | |
| 427 } | |
| 428 } | |
| 429 | |
| 430 /* Call in a dataset loop to determine if a datum should be tested according to -i & -x args */ | |
| 431 int testContinue(const testCtx *const p_ctx, const int i) { | |
| 432 int j; | |
| 433 testDataset = 1; | |
| 434 if (p_ctx->index != -1) { | |
| 435 if (p_ctx->index_end != -1) { | |
| 436 if (i < p_ctx->index || (p_ctx->index_end && i > p_ctx->index_end)) { | |
| 437 return 1; | |
| 438 } | |
| 439 } else if (i != p_ctx->index) { | |
| 440 return 1; | |
| 441 } | |
| 442 } | |
| 443 for (j = 0; j < ZINT_TEST_CTX_EXC_MAX && p_ctx->exclude[j] != -1; j++) { | |
| 444 if (p_ctx->exclude_end[j] != -1) { | |
| 445 if (i >= p_ctx->exclude[j] && (p_ctx->exclude_end[j] == 0 || i <= p_ctx->exclude_end[j])) { | |
| 446 return 1; | |
| 447 } | |
| 448 } else if (i == p_ctx->exclude[j]) { | |
| 449 return 1; | |
| 450 } | |
| 451 } | |
| 452 if ((p_ctx->debug & ZINT_DEBUG_TEST_PRINT) && !(p_ctx->debug & ZINT_DEBUG_TEST_LESS_NOISY)) { | |
| 453 printf("i:%d\n", i); | |
| 454 fflush(stdout); /* For assertion failures */ | |
| 455 } | |
| 456 testDatasetNum++; | |
| 457 return 0; | |
| 458 } | |
| 459 | |
| 460 /* Helper to set common symbol fields */ | |
| 461 int testUtilSetSymbol(struct zint_symbol *symbol, int symbology, int input_mode, int eci, int option_1, int option_2, | |
| 462 int option_3, int output_options, const char *data, int length, int debug) { | |
| 463 symbol->symbology = symbology; | |
| 464 if (input_mode != -1) { | |
| 465 symbol->input_mode = input_mode; | |
| 466 } | |
| 467 if (eci != -1) { | |
| 468 symbol->eci = eci; | |
| 469 } | |
| 470 if (option_1 != -1) { | |
| 471 symbol->option_1 = option_1; | |
| 472 } | |
| 473 if (option_2 != -1) { | |
| 474 symbol->option_2 = option_2; | |
| 475 } | |
| 476 if (option_3 != -1) { | |
| 477 symbol->option_3 = option_3; | |
| 478 } | |
| 479 if (output_options != -1) { | |
| 480 symbol->output_options = output_options; | |
| 481 } | |
| 482 symbol->debug |= debug; | |
| 483 if (length == -1) { | |
| 484 length = (int) strlen(data); | |
| 485 } | |
| 486 | |
| 487 return length; | |
| 488 } | |
| 489 | |
| 490 /* Pretty name for symbology */ | |
| 491 const char *testUtilBarcodeName(int symbology) { | |
| 492 static char name[32]; | |
| 493 | |
| 494 if (ZBarcode_BarcodeName(symbology, name) == -1) { | |
| 495 fprintf(stderr, "testUtilBarcodeName: data table out of sync (%d)\n", symbology); | |
| 496 abort(); | |
| 497 } | |
| 498 return name; | |
| 499 } | |
| 500 | |
| 501 /* Pretty name for error/warning */ | |
| 502 const char *testUtilErrorName(int error_number) { | |
| 503 struct item { | |
| 504 const char *name; | |
| 505 int define; | |
| 506 int val; | |
| 507 }; | |
| 508 static const struct item data[] = { | |
| 509 { "0", 0, 0 }, | |
| 510 { "ZINT_WARN_HRT_TRUNCATED", ZINT_WARN_HRT_TRUNCATED, 1 }, | |
| 511 { "ZINT_WARN_INVALID_OPTION", ZINT_WARN_INVALID_OPTION, 2 }, | |
| 512 { "ZINT_WARN_USES_ECI", ZINT_WARN_USES_ECI, 3 }, | |
| 513 { "ZINT_WARN_NONCOMPLIANT", ZINT_WARN_NONCOMPLIANT, 4 }, | |
| 514 { "ZINT_ERROR_TOO_LONG", ZINT_ERROR_TOO_LONG, 5 }, | |
| 515 { "ZINT_ERROR_INVALID_DATA", ZINT_ERROR_INVALID_DATA, 6 }, | |
| 516 { "ZINT_ERROR_INVALID_CHECK", ZINT_ERROR_INVALID_CHECK, 7 }, | |
| 517 { "ZINT_ERROR_INVALID_OPTION", ZINT_ERROR_INVALID_OPTION, 8 }, | |
| 518 { "ZINT_ERROR_ENCODING_PROBLEM", ZINT_ERROR_ENCODING_PROBLEM, 9 }, | |
| 519 { "ZINT_ERROR_FILE_ACCESS", ZINT_ERROR_FILE_ACCESS, 10 }, | |
| 520 { "ZINT_ERROR_MEMORY", ZINT_ERROR_MEMORY, 11 }, | |
| 521 { "ZINT_ERROR_FILE_WRITE", ZINT_ERROR_FILE_WRITE, 12 }, | |
| 522 { "ZINT_ERROR_USES_ECI", ZINT_ERROR_USES_ECI, 13 }, | |
| 523 { "ZINT_ERROR_NONCOMPLIANT", ZINT_ERROR_NONCOMPLIANT, 14 }, | |
| 524 { "ZINT_ERROR_HRT_TRUNCATED", ZINT_ERROR_HRT_TRUNCATED, 15 }, | |
| 525 }; | |
| 526 const int data_size = ARRAY_SIZE(data); | |
| 527 | |
| 528 if (error_number < 0 || error_number >= data_size) { | |
| 529 return ""; | |
| 530 } | |
| 531 /* Self-check */ | |
| 532 if (data[error_number].val != error_number | |
| 533 || (data[error_number].define != -1 && data[error_number].define != error_number)) { | |
| 534 fprintf(stderr, "testUtilErrorName: data table out of sync (%d)\n", error_number); | |
| 535 abort(); | |
| 536 } | |
| 537 return data[error_number].name; | |
| 538 } | |
| 539 | |
| 540 /* Pretty name for input mode */ | |
| 541 const char *testUtilInputModeName(int input_mode) { | |
| 542 static char buf[512]; | |
| 543 | |
| 544 struct item { | |
| 545 const char *name; | |
| 546 int define; | |
| 547 int val; | |
| 548 }; | |
| 549 static const struct item data[] = { | |
| 550 { "ESCAPE_MODE", ESCAPE_MODE, 0x0008 }, | |
| 551 { "GS1PARENS_MODE", GS1PARENS_MODE, 0x0010 }, | |
| 552 { "GS1NOCHECK_MODE", GS1NOCHECK_MODE, 0x0020 }, | |
| 553 { "HEIGHTPERROW_MODE", HEIGHTPERROW_MODE, 0x0040 }, | |
| 554 { "FAST_MODE", FAST_MODE, 0x0080 }, | |
| 555 { "EXTRA_ESCAPE_MODE", EXTRA_ESCAPE_MODE, 0x0100 }, | |
| 556 }; | |
| 557 const int data_size = ARRAY_SIZE(data); | |
| 558 int set, i; | |
| 559 | |
| 560 if (input_mode < 0) { | |
| 561 return "-1"; | |
| 562 } | |
| 563 *buf = '\0'; | |
| 564 if ((input_mode & 0x7) & UNICODE_MODE) { | |
| 565 strcpy(buf, "UNICODE_MODE"); | |
| 566 set = UNICODE_MODE; | |
| 567 } else if ((input_mode & 0x7) & GS1_MODE) { | |
| 568 strcpy(buf, "GS1_MODE"); | |
| 569 set = GS1_MODE; | |
| 570 } else { | |
| 571 set = DATA_MODE; | |
| 572 } | |
| 573 for (i = 0; i < data_size; i++) { | |
| 574 if (data[i].define != data[i].val) { /* Self-check */ | |
| 575 fprintf(stderr, "testUtilInputModeName: data table out of sync (%d)\n", i); | |
| 576 abort(); | |
| 577 } | |
| 578 if (input_mode & data[i].define) { | |
| 579 if (*buf) { | |
| 580 strcat(buf, " | "); | |
| 581 } | |
| 582 strcat(buf, data[i].name); | |
| 583 set |= data[i].define; | |
| 584 } | |
| 585 } | |
| 586 if (set != input_mode) { | |
| 587 fprintf(stderr, "testUtilInputModeName: unknown input mode %d (%d)\n", input_mode & set, input_mode); | |
| 588 abort(); | |
| 589 } | |
| 590 if (set == DATA_MODE && *buf == '\0') { | |
| 591 strcpy(buf, "DATA_MODE"); | |
| 592 } | |
| 593 return buf; | |
| 594 } | |
| 595 | |
| 596 /* Pretty name for option 3 */ | |
| 597 const char *testUtilOption3Name(int symbology, int option_3) { | |
| 598 static char buffer[64]; | |
| 599 | |
| 600 const char *name = NULL; | |
| 601 const unsigned int high_byte = option_3 == -1 ? 0 : (option_3 >> 8) & 0xFF; | |
| 602 | |
| 603 if (symbology == BARCODE_DATAMATRIX || symbology == BARCODE_HIBC_DM) { | |
| 604 if ((option_3 & 0x7F) == DM_SQUARE) { | |
| 605 if ((option_3 & DM_ISO_144) == DM_ISO_144) { | |
| 606 name = "DM_SQUARE | DM_ISO_144"; | |
| 607 } else { | |
| 608 name = "DM_SQUARE"; | |
| 609 } | |
| 610 } else if ((option_3 & 0x7F) == DM_DMRE) { | |
| 611 if ((option_3 & DM_ISO_144) == DM_ISO_144) { | |
| 612 name = "DM_DMRE | DM_ISO_144"; | |
| 613 } else { | |
| 614 name = "DM_DMRE"; | |
| 615 } | |
| 616 } else if ((option_3 & DM_ISO_144) == DM_ISO_144) { | |
| 617 name = "DM_ISO_144"; | |
| 618 } else { | |
| 619 name = (option_3 & 0xFF) ? "-1" : "0"; | |
| 620 } | |
| 621 } else if (symbology == BARCODE_QRCODE || symbology == BARCODE_HIBC_QR || symbology == BARCODE_MICROQR | |
| 622 || symbology == BARCODE_RMQR || symbology == BARCODE_GRIDMATRIX || symbology == BARCODE_HANXIN) { | |
| 623 if ((option_3 & 0xFF) == ZINT_FULL_MULTIBYTE) { | |
| 624 name = "ZINT_FULL_MULTIBYTE"; | |
| 625 } else { | |
| 626 name = (option_3 & 0xFF) ? "-1" : "0"; | |
| 627 } | |
| 628 } else if (symbology == BARCODE_ULTRA) { | |
| 629 if ((option_3 & 0xFF) == ULTRA_COMPRESSION) { | |
| 630 name = "ULTRA_COMPRESSION"; | |
| 631 } else { | |
| 632 name = (option_3 & 0xFF) ? "-1" : "0"; | |
| 633 } | |
| 634 } else { | |
| 635 if (option_3 != -1 && (option_3 & 0xFF) != 0) { | |
| 636 fprintf(stderr, "testUtilOption3Name: unknown value (%d)\n", option_3); | |
| 637 abort(); | |
| 638 } | |
| 639 name = (option_3 & 0xFF) ? "-1" : "0"; | |
| 640 } | |
| 641 | |
| 642 if (high_byte) { | |
| 643 if (option_3 & 0xFF) { | |
| 644 sprintf(buffer, "%s | (%d << 8)", name, (int) high_byte); | |
| 645 } else { | |
| 646 sprintf(buffer, "%d << 8", (int) high_byte); | |
| 647 } | |
| 648 return buffer; | |
| 649 } | |
| 650 | |
| 651 return name; | |
| 652 } | |
| 653 | |
| 654 /* Pretty name for output options */ | |
| 655 const char *testUtilOutputOptionsName(int output_options) { | |
| 656 static char buf[512]; | |
| 657 | |
| 658 struct item { | |
| 659 const char *name; | |
| 660 int define; | |
| 661 int val; | |
| 662 }; | |
| 663 static const struct item data[] = { | |
| 664 { "BARCODE_BIND_TOP", BARCODE_BIND_TOP, 1 }, | |
| 665 { "BARCODE_BIND", BARCODE_BIND, 2 }, | |
| 666 { "BARCODE_BOX", BARCODE_BOX, 4 }, | |
| 667 { "BARCODE_STDOUT", BARCODE_STDOUT, 8 }, | |
| 668 { "READER_INIT", READER_INIT, 16 }, | |
| 669 { "SMALL_TEXT", SMALL_TEXT, 32 }, | |
| 670 { "BOLD_TEXT", BOLD_TEXT, 64 }, | |
| 671 { "CMYK_COLOUR", CMYK_COLOUR, 128 }, | |
| 672 { "BARCODE_DOTTY_MODE", BARCODE_DOTTY_MODE, 256 }, | |
| 673 { "GS1_GS_SEPARATOR", GS1_GS_SEPARATOR, 512 }, | |
| 674 { "OUT_BUFFER_INTERMEDIATE", OUT_BUFFER_INTERMEDIATE, 1024 }, | |
| 675 { "BARCODE_QUIET_ZONES", BARCODE_QUIET_ZONES, 2048 }, | |
| 676 { "BARCODE_NO_QUIET_ZONES", BARCODE_NO_QUIET_ZONES, 4096 }, | |
| 677 { "COMPLIANT_HEIGHT", COMPLIANT_HEIGHT, 0x2000 }, | |
| 678 { "EANUPC_GUARD_WHITESPACE", EANUPC_GUARD_WHITESPACE, 0x4000 }, | |
| 679 { "EMBED_VECTOR_FONT", EMBED_VECTOR_FONT, 0x8000 }, | |
| 680 }; | |
| 681 static int const data_size = ARRAY_SIZE(data); | |
| 682 int set = 0; | |
| 683 int i; | |
| 684 | |
| 685 if (output_options == -1) { | |
| 686 return "-1"; | |
| 687 } | |
| 688 if (output_options == 0) { | |
| 689 return "0"; | |
| 690 } | |
| 691 buf[0] = '\0'; | |
| 692 for (i = 0; i < data_size; i++) { | |
| 693 if (data[i].define != data[i].val) { /* Self-check */ | |
| 694 fprintf(stderr, "testUtilOutputOptionsName: data table out of sync (%d)\n", i); | |
| 695 abort(); | |
| 696 } | |
| 697 if (output_options & data[i].define) { | |
| 698 if (set) { | |
| 699 strcat(buf, " | "); | |
| 700 } | |
| 701 strcat(buf, data[i].name); | |
| 702 set |= data[i].define; | |
| 703 } | |
| 704 } | |
| 705 if (set != output_options) { | |
| 706 fprintf(stderr, "testUtilOutputOptionsName: unknown output option(s) %d (%d, 0x%X)\n", | |
| 707 output_options & set, output_options, output_options); | |
| 708 abort(); | |
| 709 } | |
| 710 return buf; | |
| 711 } | |
| 712 | |
| 713 /* Convert modules spanning 3 rows to DAFT equivalents */ | |
| 714 int testUtilDAFTConvert(const struct zint_symbol *symbol, char *buffer, const int buffer_size) { | |
| 715 int i; | |
| 716 char *b = buffer; | |
| 717 *b = '\0'; | |
| 718 for (i = 0; i < symbol->width && b < buffer + buffer_size; i += 2) { | |
| 719 if (module_is_set(symbol, 0, i) && module_is_set(symbol, 2, i)) { | |
| 720 *b++ = 'F'; | |
| 721 } else if (module_is_set(symbol, 0, i)) { | |
| 722 *b++ = 'A'; | |
| 723 } else if (module_is_set(symbol, 2, i)) { | |
| 724 *b++ = 'D'; | |
| 725 } else { | |
| 726 *b++ = 'T'; | |
| 727 } | |
| 728 } | |
| 729 if (b == buffer + buffer_size) { | |
| 730 return 0; | |
| 731 } | |
| 732 *b = '\0'; | |
| 733 return 1; | |
| 734 } | |
| 735 | |
| 736 /* Is string valid UTF-8? */ | |
| 737 int testUtilIsValidUTF8(const unsigned char str[], const int length) { | |
| 738 int i; | |
| 739 unsigned int codepoint, state = 0; | |
| 740 | |
| 741 for (i = 0; i < length; i++) { | |
| 742 if (decode_utf8(&state, &codepoint, str[i]) == 12) { | |
| 743 return 0; | |
| 744 } | |
| 745 } | |
| 746 | |
| 747 return state == 0; | |
| 748 } | |
| 749 | |
| 750 /* Escape data for printing on generate test. Has a number of issues, e.g. need to use octal escapes */ | |
| 751 char *testUtilEscape(const char *buffer, const int length, char *escaped, const int escaped_size) { | |
| 752 int i; | |
| 753 unsigned char *b = (unsigned char *) buffer; | |
| 754 unsigned char *be = b + length; | |
| 755 int non_utf8 = !testUtilIsValidUTF8(b, length); | |
| 756 int chunk = -1; | |
| 757 | |
| 758 for (i = 0; b < be && i < escaped_size; b++) { | |
| 759 /* For VC6-compatibility need to split literal strings into <= 2K chunks */ | |
| 760 if (i > 2040 && i / 2040 != chunk && (*b & 0xC0) != 0x80) { /* Avoid UTF-8 continuations */ | |
| 761 chunk = i / 2040; | |
| 762 if (i + 3 < escaped_size) { | |
| 763 escaped[i] = '"'; | |
| 764 escaped[i + 1] = ' '; | |
| 765 escaped[i + 2] = '"'; | |
| 766 } | |
| 767 i += 3; | |
| 768 } | |
| 769 if (non_utf8 || *b < ' ' || *b == '\177') { | |
| 770 if (i + 4 < escaped_size) { | |
| 771 sprintf(escaped + i, "\\%.3o", *b); | |
| 772 } | |
| 773 i += 4; | |
| 774 } else if (*b == '\\' || *b == '"') { | |
| 775 if (i + 2 < escaped_size) { | |
| 776 escaped[i] = '\\'; | |
| 777 escaped[i + 1] = *b; | |
| 778 } | |
| 779 i += 2; | |
| 780 } else if (b + 1 < be && *b == 0xC2 && *(b + 1) < 0xA0) { | |
| 781 if (i + 8 < escaped_size) { | |
| 782 sprintf(escaped + i, "\\%.3o\\%.3o", *b, *(b + 1)); | |
| 783 } | |
| 784 i += 8; | |
| 785 b++; | |
| 786 } else { | |
| 787 escaped[i++] = *b; | |
| 788 } | |
| 789 } | |
| 790 if (i >= escaped_size) { | |
| 791 return NULL; | |
| 792 } | |
| 793 escaped[i] = '\0'; | |
| 794 return escaped; | |
| 795 } | |
| 796 | |
| 797 /* Helper to read a CSV field */ | |
| 798 const char *testUtilReadCSVField(const char *buffer, char *field, const int field_size) { | |
| 799 int i; | |
| 800 const char *b = buffer; | |
| 801 for (i = 0; i < field_size && *b && *b != ',' && *b != '\n' && *b != '\r'; i++) { | |
| 802 field[i] = *b++; | |
| 803 } | |
| 804 if (i == field_size) { | |
| 805 return NULL; | |
| 806 } | |
| 807 field[i] = '\0'; | |
| 808 return b; | |
| 809 } | |
| 810 | |
| 811 /* Helper to fill a buffer (for "large" tests) - single-byte filler only */ | |
| 812 void testUtilStrCpyRepeat(char *buffer, const char *repeat, const int size) { | |
| 813 int i; | |
| 814 int len = (int) strlen(repeat); | |
| 815 int max = size - len; | |
| 816 if (len == 0) { | |
| 817 fprintf(stderr, "testUtilStrCpyRepeat: only use non-empty, non-NUL single-byte data for repeat pattern\n"); | |
| 818 abort(); | |
| 819 } | |
| 820 for (i = 0; i < max; i += len) { | |
| 821 memcpy(buffer + i, repeat, len); | |
| 822 } | |
| 823 memcpy(buffer + i, repeat, size - i); | |
| 824 buffer[size] = '\0'; | |
| 825 } | |
| 826 | |
| 827 /* Compare some "important" symbol fields for equality */ | |
| 828 int testUtilSymbolCmp(const struct zint_symbol *a, const struct zint_symbol *b) { | |
| 829 int i, j; | |
| 830 if (a->symbology != b->symbology) { | |
| 831 return 1; | |
| 832 } | |
| 833 if (a->rows != b->rows) { | |
| 834 return 2; | |
| 835 } | |
| 836 if (a->width != b->width) { | |
| 837 return 3; | |
| 838 } | |
| 839 if (a->symbology == BARCODE_ULTRA) { | |
| 840 for (i = 0; i < a->rows; i++) { | |
| 841 for (j = 0; j < a->width; j++) { | |
| 842 if (module_colour_is_set(a, i, j) != module_colour_is_set(b, i, j)) { | |
| 843 return 4; | |
| 844 } | |
| 845 } | |
| 846 } | |
| 847 } else { | |
| 848 for (i = 0; i < a->rows; i++) { | |
| 849 for (j = 0; j < a->width; j++) { | |
| 850 if (module_is_set(a, i, j) != module_is_set(b, i, j)) { | |
| 851 return 4; | |
| 852 } | |
| 853 } | |
| 854 } | |
| 855 } | |
| 856 if (a->height != b->height) { | |
| 857 return 5; | |
| 858 } | |
| 859 if (a->whitespace_width != b->whitespace_width) { | |
| 860 return 6; | |
| 861 } | |
| 862 if (a->whitespace_height != b->whitespace_height) { | |
| 863 return 7; | |
| 864 } | |
| 865 if (a->border_width != b->border_width) { | |
| 866 return 8; | |
| 867 } | |
| 868 if (a->output_options != b->output_options) { | |
| 869 return 9; | |
| 870 } | |
| 871 if (a->scale != b->scale) { | |
| 872 return 10; | |
| 873 } | |
| 874 | |
| 875 return 0; | |
| 876 } | |
| 877 | |
| 878 /* Copy a full vector structure (for later comparison) */ | |
| 879 struct zint_vector *testUtilVectorCpy(const struct zint_vector *in) { | |
| 880 struct zint_vector_rect *rect; | |
| 881 struct zint_vector_string *string; | |
| 882 struct zint_vector_circle *circle; | |
| 883 struct zint_vector_hexagon *hexagon; | |
| 884 | |
| 885 struct zint_vector_rect **outrect; | |
| 886 struct zint_vector_string **outstring; | |
| 887 struct zint_vector_circle **outcircle; | |
| 888 struct zint_vector_hexagon **outhexagon; | |
| 889 | |
| 890 struct zint_vector *out = malloc(sizeof(struct zint_vector)); | |
| 891 assert(out != NULL); | |
| 892 out->width = in->width; | |
| 893 out->height = in->height; | |
| 894 out->rectangles = NULL; | |
| 895 out->strings = NULL; | |
| 896 out->circles = NULL; | |
| 897 out->hexagons = NULL; | |
| 898 | |
| 899 /* Copy rectangles */ | |
| 900 rect = in->rectangles; | |
| 901 outrect = &(out->rectangles); | |
| 902 while (rect) { | |
| 903 *outrect = malloc(sizeof(struct zint_vector_rect)); | |
| 904 assert(*outrect != NULL); | |
| 905 memcpy(*outrect, rect, sizeof(struct zint_vector_rect)); | |
| 906 outrect = &((*outrect)->next); | |
| 907 rect = rect->next; | |
| 908 } | |
| 909 *outrect = NULL; | |
| 910 | |
| 911 /* Copy Strings */ | |
| 912 string = in->strings; | |
| 913 outstring = &(out->strings); | |
| 914 while (string) { | |
| 915 *outstring = malloc(sizeof(struct zint_vector_string)); | |
| 916 assert(*outstring != NULL); | |
| 917 memcpy(*outstring, string, sizeof(struct zint_vector_string)); | |
| 918 (*outstring)->text = malloc(ustrlen(string->text) + 1); | |
| 919 assert((*outstring)->text != NULL); | |
| 920 ustrcpy((*outstring)->text, string->text); | |
| 921 outstring = &((*outstring)->next); | |
| 922 string = string->next; | |
| 923 } | |
| 924 *outstring = NULL; | |
| 925 | |
| 926 /* Copy Circles */ | |
| 927 circle = in->circles; | |
| 928 outcircle = &(out->circles); | |
| 929 while (circle) { | |
| 930 *outcircle = malloc(sizeof(struct zint_vector_circle)); | |
| 931 assert(*outcircle != NULL); | |
| 932 memcpy(*outcircle, circle, sizeof(struct zint_vector_circle)); | |
| 933 outcircle = &((*outcircle)->next); | |
| 934 circle = circle->next; | |
| 935 } | |
| 936 *outcircle = NULL; | |
| 937 | |
| 938 /* Copy Hexagons */ | |
| 939 hexagon = in->hexagons; | |
| 940 outhexagon = &(out->hexagons); | |
| 941 while (hexagon) { | |
| 942 *outhexagon = malloc(sizeof(struct zint_vector_hexagon)); | |
| 943 assert(*outhexagon != NULL); | |
| 944 memcpy(*outhexagon, hexagon, sizeof(struct zint_vector_hexagon)); | |
| 945 outhexagon = &((*outhexagon)->next); | |
| 946 hexagon = hexagon->next; | |
| 947 } | |
| 948 *outhexagon = NULL; | |
| 949 | |
| 950 return out; | |
| 951 } | |
| 952 | |
| 953 /* Compare 2 full vector structures */ | |
| 954 int testUtilVectorCmp(const struct zint_vector *a, const struct zint_vector *b) { | |
| 955 struct zint_vector_rect *arect; | |
| 956 struct zint_vector_string *astring; | |
| 957 struct zint_vector_circle *acircle; | |
| 958 struct zint_vector_hexagon *ahexagon; | |
| 959 | |
| 960 struct zint_vector_rect *brect; | |
| 961 struct zint_vector_string *bstring; | |
| 962 struct zint_vector_circle *bcircle; | |
| 963 struct zint_vector_hexagon *bhexagon; | |
| 964 | |
| 965 if (a->width != b->width) { | |
| 966 return 1; | |
| 967 } | |
| 968 if (a->height != b->height) { | |
| 969 return 2; | |
| 970 } | |
| 971 | |
| 972 /* Compare rectangles */ | |
| 973 arect = a->rectangles; | |
| 974 brect = b->rectangles; | |
| 975 while (arect) { | |
| 976 if (!brect) { | |
| 977 return 11; | |
| 978 } | |
| 979 if (arect->x != brect->x) { | |
| 980 return 12; | |
| 981 } | |
| 982 if (arect->y != brect->y) { | |
| 983 return 13; | |
| 984 } | |
| 985 if (arect->height != brect->height) { | |
| 986 return 14; | |
| 987 } | |
| 988 if (arect->width != brect->width) { | |
| 989 return 15; | |
| 990 } | |
| 991 if (arect->colour != brect->colour) { | |
| 992 return 16; | |
| 993 } | |
| 994 arect = arect->next; | |
| 995 brect = brect->next; | |
| 996 } | |
| 997 if (brect) { | |
| 998 return 10; | |
| 999 } | |
| 1000 | |
| 1001 /* Compare strings */ | |
| 1002 astring = a->strings; | |
| 1003 bstring = b->strings; | |
| 1004 while (astring) { | |
| 1005 if (!bstring) { | |
| 1006 return 21; | |
| 1007 } | |
| 1008 if (astring->x != bstring->x) { | |
| 1009 return 22; | |
| 1010 } | |
| 1011 if (astring->y != bstring->y) { | |
| 1012 return 23; | |
| 1013 } | |
| 1014 if (astring->fsize != bstring->fsize) { | |
| 1015 return 24; | |
| 1016 } | |
| 1017 if (astring->width != bstring->width) { | |
| 1018 return 25; | |
| 1019 } | |
| 1020 if (astring->length != bstring->length) { | |
| 1021 return 26; | |
| 1022 } | |
| 1023 if (ustrlen(astring->text) != ustrlen(bstring->text)) { | |
| 1024 return 27; | |
| 1025 } | |
| 1026 if (strcmp((const char *) astring->text, (const char *) bstring->text) != 0) { | |
| 1027 return 28; | |
| 1028 } | |
| 1029 astring = astring->next; | |
| 1030 bstring = bstring->next; | |
| 1031 } | |
| 1032 if (bstring) { | |
| 1033 return 20; | |
| 1034 } | |
| 1035 | |
| 1036 /* Compare circles */ | |
| 1037 acircle = a->circles; | |
| 1038 bcircle = b->circles; | |
| 1039 while (acircle) { | |
| 1040 if (!bcircle) { | |
| 1041 return 31; | |
| 1042 } | |
| 1043 if (acircle->x != bcircle->x) { | |
| 1044 return 32; | |
| 1045 } | |
| 1046 if (acircle->y != bcircle->y) { | |
| 1047 return 33; | |
| 1048 } | |
| 1049 if (acircle->diameter != bcircle->diameter) { | |
| 1050 return 34; | |
| 1051 } | |
| 1052 if (acircle->colour != bcircle->colour) { | |
| 1053 return 35; | |
| 1054 } | |
| 1055 acircle = acircle->next; | |
| 1056 bcircle = bcircle->next; | |
| 1057 } | |
| 1058 if (bcircle) { | |
| 1059 return 30; | |
| 1060 } | |
| 1061 | |
| 1062 /* Compare hexagons */ | |
| 1063 ahexagon = a->hexagons; | |
| 1064 bhexagon = b->hexagons; | |
| 1065 while (ahexagon) { | |
| 1066 if (!bhexagon) { | |
| 1067 return 41; | |
| 1068 } | |
| 1069 if (ahexagon->x != bhexagon->x) { | |
| 1070 return 42; | |
| 1071 } | |
| 1072 if (ahexagon->y != bhexagon->y) { | |
| 1073 return 43; | |
| 1074 } | |
| 1075 if (ahexagon->diameter != bhexagon->diameter) { | |
| 1076 return 44; | |
| 1077 } | |
| 1078 ahexagon = ahexagon->next; | |
| 1079 bhexagon = bhexagon->next; | |
| 1080 } | |
| 1081 if (bhexagon) { | |
| 1082 return 40; | |
| 1083 } | |
| 1084 | |
| 1085 return 0; | |
| 1086 } | |
| 1087 | |
| 1088 /* Dump modules into buffer as '0'/'1' (or colours '0', '1', '2' etc if Ultra) */ | |
| 1089 int testUtilModulesDump(const struct zint_symbol *symbol, char dump[], int dump_size) { | |
| 1090 int r, w; | |
| 1091 char *d = dump; | |
| 1092 char *de = dump + dump_size; | |
| 1093 | |
| 1094 for (r = 0; r < symbol->rows && d < de; r++) { | |
| 1095 if (symbol->symbology == BARCODE_ULTRA) { | |
| 1096 for (w = 0; w < symbol->width && d < de; w++) { | |
| 1097 *d++ = module_colour_is_set(symbol, r, w) + '0'; | |
| 1098 } | |
| 1099 } else { | |
| 1100 for (w = 0; w < symbol->width && d < de; w++) { | |
| 1101 *d++ = module_is_set(symbol, r, w) + '0'; | |
| 1102 } | |
| 1103 } | |
| 1104 } | |
| 1105 if (d == de) { | |
| 1106 return -1; | |
| 1107 } | |
| 1108 *d = '\0'; | |
| 1109 return d - dump; | |
| 1110 } | |
| 1111 | |
| 1112 /* Print out module dump (for generate tests) */ | |
| 1113 void testUtilModulesPrint(const struct zint_symbol *symbol, const char *prefix, const char *postfix) { | |
| 1114 int r; | |
| 1115 for (r = 0; r < symbol->rows; r++) { | |
| 1116 testUtilModulesPrintRow(symbol, r, prefix, postfix); | |
| 1117 } | |
| 1118 } | |
| 1119 | |
| 1120 /* Print out a single row of a module dump (for generate tests where rows all the same, to avoid large dumps of | |
| 1121 duplicate data) */ | |
| 1122 void testUtilModulesPrintRow(const struct zint_symbol *symbol, int row, const char *prefix, const char *postfix) { | |
| 1123 int w; | |
| 1124 if (*prefix) { | |
| 1125 fputs(prefix, stdout); | |
| 1126 } | |
| 1127 putchar('"'); | |
| 1128 if (symbol->symbology == BARCODE_ULTRA) { | |
| 1129 for (w = 0; w < symbol->width; w++) { | |
| 1130 putchar(module_colour_is_set(symbol, row, w) + '0'); | |
| 1131 } | |
| 1132 } else { | |
| 1133 for (w = 0; w < symbol->width; w++) { | |
| 1134 putchar(module_is_set(symbol, row, w) + '0'); | |
| 1135 } | |
| 1136 } | |
| 1137 putchar('"'); | |
| 1138 if (*postfix) { | |
| 1139 fputs(postfix, stdout); | |
| 1140 } | |
| 1141 } | |
| 1142 | |
| 1143 /* Whether 2 module dumps are the same */ | |
| 1144 int testUtilModulesCmp(const struct zint_symbol *symbol, const char *expected, int *width, int *row) { | |
| 1145 const char *e = expected; | |
| 1146 const char *ep = expected + strlen(expected); | |
| 1147 int r, w = 0; | |
| 1148 if (symbol->symbology == BARCODE_ULTRA) { | |
| 1149 for (r = 0; r < symbol->rows && e < ep; r++) { | |
| 1150 for (w = 0; w < symbol->width && e < ep; w++) { | |
| 1151 if (module_colour_is_set(symbol, r, w) + '0' != *e) { | |
| 1152 *row = r; | |
| 1153 *width = w; | |
| 1154 return 1 /*fail*/; | |
| 1155 } | |
| 1156 e++; | |
| 1157 } | |
| 1158 } | |
| 1159 } else { | |
| 1160 for (r = 0; r < symbol->rows && e < ep; r++) { | |
| 1161 for (w = 0; w < symbol->width && e < ep; w++) { | |
| 1162 if (module_is_set(symbol, r, w) + '0' != *e) { | |
| 1163 *row = r; | |
| 1164 *width = w; | |
| 1165 return 1 /*fail*/; | |
| 1166 } | |
| 1167 e++; | |
| 1168 } | |
| 1169 } | |
| 1170 } | |
| 1171 *row = r; | |
| 1172 *width = w; | |
| 1173 return e != ep || r != symbol->rows || w != symbol->width ? 1 /*fail*/ : 0 /*success*/; | |
| 1174 } | |
| 1175 | |
| 1176 /* Whether 2 module row dumps are the same */ | |
| 1177 int testUtilModulesCmpRow(const struct zint_symbol *symbol, int row, const char *expected, int *width) { | |
| 1178 const char *e = expected; | |
| 1179 const char *ep = expected + strlen(expected); | |
| 1180 int w; | |
| 1181 if (symbol->symbology == BARCODE_ULTRA) { | |
| 1182 for (w = 0; w < symbol->width && e < ep; w++) { | |
| 1183 if (module_colour_is_set(symbol, row, w) + '0' != *e) { | |
| 1184 *width = w; | |
| 1185 return 1 /*fail*/; | |
| 1186 } | |
| 1187 e++; | |
| 1188 } | |
| 1189 } else { | |
| 1190 for (w = 0; w < symbol->width && e < ep; w++) { | |
| 1191 if (module_is_set(symbol, row, w) + '0' != *e) { | |
| 1192 *width = w; | |
| 1193 return 1 /*fail*/; | |
| 1194 } | |
| 1195 e++; | |
| 1196 } | |
| 1197 } | |
| 1198 *width = w; | |
| 1199 return e != ep || w != symbol->width ? 1 /*fail*/ : 0 /*success*/; | |
| 1200 } | |
| 1201 | |
| 1202 /* Dump an unsigned int array as hex */ | |
| 1203 char *testUtilUIntArrayDump(unsigned int *array, int size, char *dump, int dump_size) { | |
| 1204 int i, cnt_len = 0; | |
| 1205 | |
| 1206 for (i = 0; i < size; i++) { | |
| 1207 cnt_len += sprintf(dump + cnt_len, "%X ", array[i]); | |
| 1208 if (cnt_len + 17 >= dump_size) { | |
| 1209 break; | |
| 1210 } | |
| 1211 } | |
| 1212 dump[cnt_len ? cnt_len - 1 : 0] = '\0'; | |
| 1213 return dump; | |
| 1214 } | |
| 1215 | |
| 1216 /* Dump an unsigned char array as hex */ | |
| 1217 char *testUtilUCharArrayDump(unsigned char *array, int size, char *dump, int dump_size) { | |
| 1218 int i, cnt_len = 0; | |
| 1219 | |
| 1220 for (i = 0; i < size; i++) { | |
| 1221 cnt_len += sprintf(dump + cnt_len, "%X ", array[i]); | |
| 1222 if (cnt_len + 3 >= dump_size) { | |
| 1223 break; | |
| 1224 } | |
| 1225 } | |
| 1226 dump[cnt_len ? cnt_len - 1 : 0] = '\0'; | |
| 1227 return dump; | |
| 1228 } | |
| 1229 | |
| 1230 /* Dump a bitmap to stdout, for generate tests. Also useful for debugging */ | |
| 1231 void testUtilBitmapPrint(const struct zint_symbol *symbol, const char *prefix, const char *postfix) { | |
| 1232 static const char colour[] = { '0', 'C', 'M', 'B', 'Y', 'G', 'R', '1' }; | |
| 1233 int row, column, i, j; | |
| 1234 | |
| 1235 if (!prefix) { | |
| 1236 fputs(" ", stdout); | |
| 1237 for (column = 0; column < symbol->bitmap_width; column += 10) printf("%-3d ", column); | |
| 1238 fputs("\n ", stdout); | |
| 1239 for (column = 0; column < symbol->bitmap_width; column++) printf("%d", column % 10); | |
| 1240 putchar('\n'); | |
| 1241 } | |
| 1242 | |
| 1243 for (row = 0; row < symbol->bitmap_height; row++) { | |
| 1244 if (!prefix) { | |
| 1245 printf("%3d: ", row); | |
| 1246 } else { | |
| 1247 if (*prefix) { | |
| 1248 fputs(prefix, stdout); | |
| 1249 } | |
| 1250 putchar('"'); | |
| 1251 } | |
| 1252 for (column = 0; column < symbol->bitmap_width; column++) { | |
| 1253 if (symbol->output_options & OUT_BUFFER_INTERMEDIATE) { | |
| 1254 putchar(symbol->bitmap[(row * symbol->bitmap_width) + column]); | |
| 1255 } else { | |
| 1256 i = ((row * symbol->bitmap_width) + column) * 3; | |
| 1257 if ((symbol->bitmap[i] == 0 || symbol->bitmap[i] == 0xff) | |
| 1258 && (symbol->bitmap[i + 1] == 0 || symbol->bitmap[i + 1] == 0xff) | |
| 1259 && (symbol->bitmap[i + 2] == 0 || symbol->bitmap[i + 2] == 0xff)) { | |
| 1260 j = !symbol->bitmap[i] + !symbol->bitmap[i + 1] * 2 + !symbol->bitmap[i + 2] * 4; | |
| 1261 putchar(colour[j]); | |
| 1262 } else { | |
| 1263 printf("%02X%02X%02X", symbol->bitmap[i], symbol->bitmap[i + 1], symbol->bitmap[i + 2]); | |
| 1264 } | |
| 1265 } | |
| 1266 } | |
| 1267 if (!postfix) { | |
| 1268 putchar('\n'); | |
| 1269 } else { | |
| 1270 putchar('"'); | |
| 1271 if (*postfix) { | |
| 1272 fputs(postfix, stdout); | |
| 1273 } | |
| 1274 } | |
| 1275 } | |
| 1276 | |
| 1277 if (!postfix) { | |
| 1278 fputs(" ", stdout); | |
| 1279 for (column = 0; column < symbol->bitmap_width; column++) printf("%d", column % 10); | |
| 1280 fputs("\n ", stdout); | |
| 1281 for (column = 0; column < symbol->bitmap_width; column += 10) printf("%-3d ", column); | |
| 1282 putchar('\n'); | |
| 1283 } | |
| 1284 fflush(stdout); | |
| 1285 } | |
| 1286 | |
| 1287 /* Compare a bitmap to a dump */ | |
| 1288 int testUtilBitmapCmp(const struct zint_symbol *symbol, const char *expected, int *row, int *column) { | |
| 1289 static const char colour[] = { '0', 'C', 'M', 'B', 'Y', 'G', 'R', '1' }; | |
| 1290 int r, c = -1, i, j; | |
| 1291 const char *e = expected; | |
| 1292 const char *ep = expected + strlen(expected); | |
| 1293 char buf[7]; | |
| 1294 | |
| 1295 for (r = 0; r < symbol->bitmap_height; r++) { | |
| 1296 for (c = 0; c < symbol->bitmap_width; c++) { | |
| 1297 if (symbol->output_options & OUT_BUFFER_INTERMEDIATE) { | |
| 1298 if (*e != symbol->bitmap[(r * symbol->bitmap_width) + c]) { | |
| 1299 *row = r; | |
| 1300 *column = c; | |
| 1301 return 1 /*fail*/; | |
| 1302 } | |
| 1303 e++; | |
| 1304 } else { | |
| 1305 i = ((r * symbol->bitmap_width) + c) * 3; | |
| 1306 if ((symbol->bitmap[i] == 0 || symbol->bitmap[i] == 0xff) | |
| 1307 && (symbol->bitmap[i + 1] == 0 || symbol->bitmap[i + 1] == 0xff) | |
| 1308 && (symbol->bitmap[i + 2] == 0 || symbol->bitmap[i + 2] == 0xff)) { | |
| 1309 j = !symbol->bitmap[i] + !symbol->bitmap[i + 1] * 2 + !symbol->bitmap[i + 2] * 4; | |
| 1310 if (*e != colour[j]) { | |
| 1311 *row = r; | |
| 1312 *column = c; | |
| 1313 return 1 /*fail*/; | |
| 1314 } | |
| 1315 e++; | |
| 1316 } else { | |
| 1317 sprintf(buf, "%02X%02X%02X", symbol->bitmap[i], symbol->bitmap[i + 1], symbol->bitmap[i + 2]); | |
| 1318 if (strncmp(buf, e, 6) != 0) { | |
| 1319 *row = r; | |
| 1320 *column = c; | |
| 1321 return 1 /*fail*/; | |
| 1322 } | |
| 1323 e += 6; | |
| 1324 } | |
| 1325 } | |
| 1326 } | |
| 1327 } | |
| 1328 | |
| 1329 *row = r; | |
| 1330 *column = c; | |
| 1331 return e != ep || r != symbol->bitmap_height || c != symbol->bitmap_width ? 1 /*fail*/ : 0 /*success*/; | |
| 1332 } | |
| 1333 | |
| 1334 /* Dump vectors to stdout, for debugging */ | |
| 1335 void testUtilVectorPrint(const struct zint_symbol *symbol) { | |
| 1336 struct zint_vector_rect *rect; | |
| 1337 struct zint_vector_hexagon *hex; | |
| 1338 struct zint_vector_circle *circ; | |
| 1339 struct zint_vector_string *str; | |
| 1340 | |
| 1341 if (symbol->vector == NULL) { | |
| 1342 fputs("symbol->vector NULL\n", stdout); | |
| 1343 } else { | |
| 1344 for (rect = symbol->vector->rectangles; rect; rect = rect->next) { | |
| 1345 printf("rect(x %.9g, y %.9g, width %.9g, height %.9g, colour %d)\n", rect->x, rect->y, rect->width, | |
| 1346 rect->height, rect->colour); | |
| 1347 } | |
| 1348 for (hex = symbol->vector->hexagons; hex; hex = hex->next) { | |
| 1349 printf("hex(x %.9g, y %.9g, diameter %.9g, rotation %d)\n", hex->x, hex->y, hex->diameter, hex->rotation); | |
| 1350 } | |
| 1351 for (circ = symbol->vector->circles; circ; circ = circ->next) { | |
| 1352 printf("circ(x %.9g, y %.9g, diameter %.9g, width %.9g, colour %d)\n", circ->x, circ->y, circ->diameter, | |
| 1353 circ->width, circ->colour); | |
| 1354 } | |
| 1355 for (str = symbol->vector->strings; str; str = str->next) { | |
| 1356 printf("str(x %.9g, y %.9g, fsize %.9g, width %.9g, length %d, rotation %d, halign %d, \"%s\")\n", str->x, | |
| 1357 str->y, str->fsize, str->width, str->length, str->rotation, str->halign, str->text); | |
| 1358 } | |
| 1359 } | |
| 1360 fflush(stdout); | |
| 1361 } | |
| 1362 | |
| 1363 /* Determine the location of test data relative to where the test is being run */ | |
| 1364 int testUtilDataPath(char *buffer, int buffer_size, const char *subdir, const char *filename) { | |
| 1365 int subdir_len = subdir ? (int) strlen(subdir) : 0; | |
| 1366 int filename_len = filename ? (int) strlen(filename) : 0; | |
| 1367 char *s, *s2; | |
| 1368 int len; | |
| 1369 char *cmake_src_dir; | |
| 1370 #ifdef _WIN32 | |
| 1371 int i; | |
| 1372 #endif | |
| 1373 | |
| 1374 if ((cmake_src_dir = getenv("CMAKE_CURRENT_SOURCE_DIR")) != NULL) { | |
| 1375 len = (int) strlen(cmake_src_dir); | |
| 1376 if (len <= 0 || len >= buffer_size) { | |
| 1377 fprintf(stderr, "testUtilDataPath: warning CMAKE_CURRENT_SOURCE_DIR len %d, ignoring\n", len); | |
| 1378 cmake_src_dir = NULL; | |
| 1379 } else { | |
| 1380 strcpy(buffer, cmake_src_dir); | |
| 1381 } | |
| 1382 } | |
| 1383 | |
| 1384 if (cmake_src_dir == NULL) { | |
| 1385 if (getcwd(buffer, buffer_size) == NULL) { | |
| 1386 fprintf(stderr, "testUtilDataPath: getcwd NULL buffer_size %d\n", buffer_size); | |
| 1387 return 0; | |
| 1388 } | |
| 1389 len = (int) strlen(buffer); | |
| 1390 | |
| 1391 if (len <= 0) { | |
| 1392 fprintf(stderr, "testUtilDataPath: strlen <= 0\n"); | |
| 1393 return 0; | |
| 1394 } | |
| 1395 } | |
| 1396 #ifdef _WIN32 | |
| 1397 for (i = 0; i < len; i++) { | |
| 1398 if (buffer[i] == '\\') { | |
| 1399 buffer[i] = '/'; | |
| 1400 } | |
| 1401 } | |
| 1402 #endif | |
| 1403 if (buffer[len - 1] == '/') { | |
| 1404 buffer[len--] = '\0'; | |
| 1405 } | |
| 1406 if (len == 0) { | |
| 1407 fprintf(stderr, "testUtilDataPath: len == 0\n"); | |
| 1408 return 0; | |
| 1409 } | |
| 1410 | |
| 1411 if ((s = strstr(buffer, "/tests")) != NULL) { | |
| 1412 while ((s2 = strstr(s + 1, "/tests")) != NULL) { /* Find rightmost */ | |
| 1413 s = s2; | |
| 1414 } | |
| 1415 *s = '\0'; | |
| 1416 len = s - buffer; | |
| 1417 } | |
| 1418 if ((s = strstr(buffer, "/backend")) != NULL) { | |
| 1419 while ((s2 = strstr(s + 1, "/backend")) != NULL) { /* Find rightmost */ | |
| 1420 s = s2; | |
| 1421 } | |
| 1422 *s = '\0'; | |
| 1423 len = s - buffer; | |
| 1424 } else if ((s = strstr(buffer, "/frontend")) != NULL) { | |
| 1425 while ((s2 = strstr(s + 1, "/frontend")) != NULL) { /* Find rightmost */ | |
| 1426 s = s2; | |
| 1427 } | |
| 1428 *s = '\0'; | |
| 1429 len = s - buffer; | |
| 1430 } | |
| 1431 if (cmake_src_dir == NULL && (s = strrchr(buffer, '/')) != NULL) { /* Remove "build" dir */ | |
| 1432 *s = '\0'; | |
| 1433 len = s - buffer; | |
| 1434 } | |
| 1435 | |
| 1436 if (subdir_len) { | |
| 1437 if (*subdir != '/' && buffer[len - 1] != '/') { | |
| 1438 if (len + 1 >= buffer_size) { | |
| 1439 fprintf(stderr, "testUtilDataPath: subdir len (%d) + 1 >= buffer_size (%d)\n", len, buffer_size); | |
| 1440 return 0; | |
| 1441 } | |
| 1442 buffer[len++] = '/'; | |
| 1443 buffer[len] = '\0'; | |
| 1444 } | |
| 1445 if (len + subdir_len >= buffer_size) { | |
| 1446 fprintf(stderr, "testUtilDataPath: len (%d) + subdir_len (%d) >= buffer_size (%d)\n", | |
| 1447 len, subdir_len, buffer_size); | |
| 1448 return 0; | |
| 1449 } | |
| 1450 strcpy(buffer + len, subdir); | |
| 1451 len += subdir_len; | |
| 1452 } | |
| 1453 | |
| 1454 if (filename_len) { | |
| 1455 if (*filename != '/' && buffer[len - 1] != '/') { | |
| 1456 if (len + 1 >= buffer_size) { | |
| 1457 fprintf(stderr, "testUtilDataPath: filename len (%d) + 1 >= buffer_size (%d)\n", len, buffer_size); | |
| 1458 return 0; | |
| 1459 } | |
| 1460 buffer[len++] = '/'; | |
| 1461 buffer[len] = '\0'; | |
| 1462 } | |
| 1463 if (len + filename_len >= buffer_size) { | |
| 1464 fprintf(stderr, "testUtilDataPath: len (%d) + filename_len (%d) >= buffer_size (%d)\n", | |
| 1465 len, filename_len, buffer_size); | |
| 1466 return 0; | |
| 1467 } | |
| 1468 strcpy(buffer + len, filename); | |
| 1469 } | |
| 1470 | |
| 1471 return 1; | |
| 1472 } | |
| 1473 | |
| 1474 /* Open a file (Windows compatibility) */ | |
| 1475 FILE *testUtilOpen(const char *filename, const char *mode) { | |
| 1476 #ifdef _WIN32 | |
| 1477 FILE *fp = out_win_fopen(filename, mode); | |
| 1478 #else | |
| 1479 FILE *fp = fopen(filename, mode); | |
| 1480 #endif | |
| 1481 return fp; | |
| 1482 } | |
| 1483 | |
| 1484 /* Does file exist? */ | |
| 1485 int testUtilExists(const char *filename) { | |
| 1486 FILE *fp = testUtilOpen(filename, "r"); | |
| 1487 if (fp == NULL) { | |
| 1488 return 0; | |
| 1489 } | |
| 1490 fclose(fp); | |
| 1491 return 1; | |
| 1492 } | |
| 1493 | |
| 1494 /* Remove a file (Windows compatibility). Returns 0 if successful, non-zero if not */ | |
| 1495 int testUtilRemove(const char *filename) { | |
| 1496 #ifdef _WIN32 | |
| 1497 wchar_t *filenameW; | |
| 1498 utf8_to_wide(filename, filenameW); | |
| 1499 return DeleteFileW(filenameW) == 0; /* Non-zero on success */ | |
| 1500 #else | |
| 1501 return remove(filename); | |
| 1502 #endif | |
| 1503 } | |
| 1504 | |
| 1505 /* Does directory exist? (Windows compatibility) */ | |
| 1506 int testUtilDirExists(const char *dirname) { | |
| 1507 #ifdef _WIN32 | |
| 1508 DWORD dwAttrib; | |
| 1509 wchar_t *dirnameW; | |
| 1510 utf8_to_wide(dirname, dirnameW); | |
| 1511 dwAttrib = GetFileAttributesW(dirnameW); | |
| 1512 return dwAttrib != (DWORD) -1 && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY); | |
| 1513 #else | |
| 1514 return testUtilExists(dirname); | |
| 1515 #endif | |
| 1516 } | |
| 1517 | |
| 1518 /* Make a directory (Windows compatibility). Returns 0 if successful, non-zero if not */ | |
| 1519 int testUtilMkDir(const char *dirname) { | |
| 1520 #ifdef _WIN32 | |
| 1521 wchar_t *dirnameW; | |
| 1522 utf8_to_wide(dirname, dirnameW); | |
| 1523 return CreateDirectoryW(dirnameW, NULL) == 0; | |
| 1524 #else | |
| 1525 return mkdir(dirname, S_IRWXU); | |
| 1526 #endif | |
| 1527 } | |
| 1528 | |
| 1529 /* Remove a directory (Windows compatibility). Returns 0 if successful, non-zero if not */ | |
| 1530 int testUtilRmDir(const char *dirname) { | |
| 1531 #ifdef _WIN32 | |
| 1532 wchar_t *dirnameW; | |
| 1533 utf8_to_wide(dirname, dirnameW); | |
| 1534 return RemoveDirectoryW(dirnameW) == 0; | |
| 1535 #else | |
| 1536 return rmdir(dirname); | |
| 1537 #endif | |
| 1538 } | |
| 1539 | |
| 1540 /* Rename a file (Windows compatibility) */ | |
| 1541 int testUtilRename(const char *oldpath, const char *newpath) { | |
| 1542 #ifdef _WIN32 | |
| 1543 wchar_t *oldpathW, *newpathW; | |
| 1544 int ret = testUtilRemove(newpath); | |
| 1545 if (ret != 0) return ret; | |
| 1546 utf8_to_wide(oldpath, oldpathW); | |
| 1547 utf8_to_wide(newpath, newpathW); | |
| 1548 return _wrename(oldpathW, newpathW); | |
| 1549 #else | |
| 1550 return rename(oldpath, newpath); | |
| 1551 #endif | |
| 1552 } | |
| 1553 | |
| 1554 /* Create read-only file */ | |
| 1555 int testUtilCreateROFile(const char *filename) { | |
| 1556 #ifdef _WIN32 | |
| 1557 wchar_t *filenameW; | |
| 1558 #endif | |
| 1559 FILE *fp = testUtilOpen(filename, "w+"); | |
| 1560 if (fp == NULL) { | |
| 1561 return 0; | |
| 1562 } | |
| 1563 if (fclose(fp) != 0) { | |
| 1564 return 0; | |
| 1565 } | |
| 1566 #ifdef _WIN32 | |
| 1567 utf8_to_wide(filename, filenameW); | |
| 1568 if (SetFileAttributesW(filenameW, GetFileAttributesW(filenameW) | FILE_ATTRIBUTE_READONLY) == 0) { | |
| 1569 return 0; | |
| 1570 } | |
| 1571 #else | |
| 1572 if (chmod(filename, S_IRUSR | S_IRGRP | S_IROTH) != 0) { | |
| 1573 return 0; | |
| 1574 } | |
| 1575 #endif | |
| 1576 return 1; | |
| 1577 } | |
| 1578 | |
| 1579 /* Remove read-only file (Windows compatibility) */ | |
| 1580 int testUtilRmROFile(const char *filename) { | |
| 1581 #ifdef _WIN32 | |
| 1582 wchar_t *filenameW; | |
| 1583 utf8_to_wide(filename, filenameW); | |
| 1584 if (SetFileAttributesW(filenameW, GetFileAttributesW(filenameW) & ~FILE_ATTRIBUTE_READONLY) == 0) { | |
| 1585 return -1; | |
| 1586 } | |
| 1587 #endif | |
| 1588 return testUtilRemove(filename); | |
| 1589 } | |
| 1590 | |
| 1591 /* Read file into buffer */ | |
| 1592 int testUtilReadFile(const char *filename, unsigned char *buffer, int buffer_size, int *p_size) { | |
| 1593 long fileLen; | |
| 1594 size_t n; | |
| 1595 size_t nRead = 0; | |
| 1596 FILE *fp = testUtilOpen(filename, "rb"); | |
| 1597 if (!fp) { | |
| 1598 return 1; | |
| 1599 } | |
| 1600 if (fseek(fp, 0, SEEK_END) != 0) { | |
| 1601 (void) fclose(fp); | |
| 1602 return 2; | |
| 1603 } | |
| 1604 fileLen = ftell(fp); | |
| 1605 if (fileLen <= 0 || fileLen == LONG_MAX) { | |
| 1606 (void) fclose(fp); | |
| 1607 return 3; | |
| 1608 } | |
| 1609 if (fseek(fp, 0, SEEK_SET) != 0) { | |
| 1610 (void) fclose(fp); | |
| 1611 return 4; | |
| 1612 } | |
| 1613 if (fileLen > (long) buffer_size) { | |
| 1614 (void) fclose(fp); | |
| 1615 return 5; | |
| 1616 } | |
| 1617 do { | |
| 1618 n = fread(buffer + nRead, 1, fileLen - nRead, fp); | |
| 1619 if (ferror(fp)) { | |
| 1620 (void) fclose(fp); | |
| 1621 return 6; | |
| 1622 } | |
| 1623 nRead += n; | |
| 1624 } while (!feof(fp) && (0 < n) && ((long) nRead < fileLen)); | |
| 1625 | |
| 1626 if (fclose(fp) != 0) { | |
| 1627 return 7; | |
| 1628 } | |
| 1629 | |
| 1630 *p_size = (int) nRead; | |
| 1631 | |
| 1632 return 0; | |
| 1633 } | |
| 1634 | |
| 1635 /* Write file from buffer */ | |
| 1636 int testUtilWriteFile(const char *filename, const unsigned char *buffer, const int buffer_size, const char *mode) { | |
| 1637 FILE *fp = testUtilOpen(filename, mode); | |
| 1638 if (!fp) { | |
| 1639 return 1; | |
| 1640 } | |
| 1641 if (fwrite(buffer, 1, buffer_size, fp) == 0) { | |
| 1642 (void) fclose(fp); | |
| 1643 return 2; | |
| 1644 } | |
| 1645 if (fclose(fp) != 0) { | |
| 1646 return 3; | |
| 1647 } | |
| 1648 | |
| 1649 return 0; | |
| 1650 } | |
| 1651 | |
| 1652 /* Compare 2 PNG files */ | |
| 1653 int testUtilCmpPngs(const char *png1, const char *png2) { | |
| 1654 int ret = -1; | |
| 1655 #ifdef ZINT_NO_PNG | |
| 1656 (void)png1; (void)png2; | |
| 1657 #else | |
| 1658 FILE *fp1; | |
| 1659 FILE *fp2; | |
| 1660 png_structp png_ptr1, png_ptr2; | |
| 1661 png_infop info_ptr1, info_ptr2; | |
| 1662 int width1, height1, width2, height2; | |
| 1663 png_byte color_type1, color_type2; | |
| 1664 png_byte bit_depth1, bit_depth2; | |
| 1665 png_bytep row1, row2; | |
| 1666 size_t rowbytes1, rowbytes2; | |
| 1667 int r; | |
| 1668 | |
| 1669 fp1 = testUtilOpen(png1, "rb"); | |
| 1670 if (!fp1) { | |
| 1671 return 2; | |
| 1672 } | |
| 1673 fp2 = testUtilOpen(png2, "rb"); | |
| 1674 if (!fp2) { | |
| 1675 fclose(fp1); | |
| 1676 return 3; | |
| 1677 } | |
| 1678 | |
| 1679 png_ptr1 = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, NULL, NULL); | |
| 1680 if (!png_ptr1) { | |
| 1681 fclose(fp1); | |
| 1682 fclose(fp2); | |
| 1683 return 4; | |
| 1684 } | |
| 1685 info_ptr1 = png_create_info_struct(png_ptr1); | |
| 1686 if (!info_ptr1) { | |
| 1687 png_destroy_read_struct(&png_ptr1, (png_infopp) NULL, (png_infopp) NULL); | |
| 1688 fclose(fp1); | |
| 1689 fclose(fp2); | |
| 1690 return 5; | |
| 1691 } | |
| 1692 | |
| 1693 png_ptr2 = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, NULL, NULL); | |
| 1694 if (!png_ptr2) { | |
| 1695 png_destroy_read_struct(&png_ptr1, &info_ptr1, (png_infopp) NULL); | |
| 1696 fclose(fp1); | |
| 1697 fclose(fp2); | |
| 1698 return 6; | |
| 1699 } | |
| 1700 info_ptr2 = png_create_info_struct(png_ptr2); | |
| 1701 if (!info_ptr2) { | |
| 1702 png_destroy_read_struct(&png_ptr1, &info_ptr1, (png_infopp) NULL); | |
| 1703 png_destroy_read_struct(&png_ptr2, (png_infopp) NULL, (png_infopp) NULL); | |
| 1704 fclose(fp1); | |
| 1705 fclose(fp2); | |
| 1706 return 7; | |
| 1707 } | |
| 1708 | |
| 1709 row1 = row2 = NULL; /* Init here to avoid potential "clobbered" warning */ | |
| 1710 if (setjmp(png_jmpbuf(png_ptr1))) { | |
| 1711 if (row1) { | |
| 1712 free(row1); | |
| 1713 } | |
| 1714 if (row2) { | |
| 1715 free(row2); | |
| 1716 } | |
| 1717 png_destroy_read_struct(&png_ptr1, &info_ptr1, (png_infopp) NULL); | |
| 1718 png_destroy_read_struct(&png_ptr2, &info_ptr2, (png_infopp) NULL); | |
| 1719 fclose(fp1); | |
| 1720 fclose(fp2); | |
| 1721 return 8; | |
| 1722 } | |
| 1723 if (setjmp(png_jmpbuf(png_ptr2))) { | |
| 1724 if (row1) { | |
| 1725 free(row1); | |
| 1726 } | |
| 1727 if (row2) { | |
| 1728 free(row2); | |
| 1729 } | |
| 1730 png_destroy_read_struct(&png_ptr1, &info_ptr1, (png_infopp) NULL); | |
| 1731 png_destroy_read_struct(&png_ptr2, &info_ptr2, (png_infopp) NULL); | |
| 1732 fclose(fp1); | |
| 1733 fclose(fp2); | |
| 1734 return 9; | |
| 1735 } | |
| 1736 | |
| 1737 png_init_io(png_ptr1, fp1); | |
| 1738 png_init_io(png_ptr2, fp2); | |
| 1739 | |
| 1740 png_read_info(png_ptr1, info_ptr1); | |
| 1741 png_read_info(png_ptr2, info_ptr2); | |
| 1742 | |
| 1743 width1 = png_get_image_width(png_ptr1, info_ptr1); | |
| 1744 height1 = png_get_image_height(png_ptr1, info_ptr1); | |
| 1745 width2 = png_get_image_width(png_ptr2, info_ptr2); | |
| 1746 height2 = png_get_image_height(png_ptr2, info_ptr2); | |
| 1747 | |
| 1748 if (width1 != width2 || height1 != height2) { | |
| 1749 printf("width1 %d, width2 %d, height1 %d, height2 %d\n", width1, width2, height1, height2); | |
| 1750 png_destroy_read_struct(&png_ptr1, &info_ptr1, (png_infopp) NULL); | |
| 1751 png_destroy_read_struct(&png_ptr2, &info_ptr2, (png_infopp) NULL); | |
| 1752 fclose(fp1); | |
| 1753 fclose(fp2); | |
| 1754 return 10; | |
| 1755 } | |
| 1756 | |
| 1757 color_type1 = png_get_color_type(png_ptr1, info_ptr1); | |
| 1758 bit_depth1 = png_get_bit_depth(png_ptr1, info_ptr1); | |
| 1759 if (bit_depth1 == 16) { | |
| 1760 #if defined(PNG_LIBPNG_VER) && PNG_LIBPNG_VER >= 10504 | |
| 1761 png_set_scale_16(png_ptr1); | |
| 1762 #else | |
| 1763 png_set_strip_16(png_ptr1); | |
| 1764 #endif | |
| 1765 } | |
| 1766 if (color_type1 == PNG_COLOR_TYPE_PALETTE) { | |
| 1767 png_set_palette_to_rgb(png_ptr1); | |
| 1768 } | |
| 1769 if (color_type1 == PNG_COLOR_TYPE_GRAY && bit_depth1 < 8) { | |
| 1770 png_set_expand_gray_1_2_4_to_8(png_ptr1); | |
| 1771 } | |
| 1772 if (png_get_valid(png_ptr1, info_ptr1, PNG_INFO_tRNS)) { | |
| 1773 png_set_tRNS_to_alpha(png_ptr1); | |
| 1774 } | |
| 1775 if (color_type1 == PNG_COLOR_TYPE_RGB || color_type1 == PNG_COLOR_TYPE_GRAY | |
| 1776 || color_type1 == PNG_COLOR_TYPE_PALETTE) { | |
| 1777 png_set_filler(png_ptr1, 0xFF, PNG_FILLER_AFTER); | |
| 1778 } | |
| 1779 if (color_type1 == PNG_COLOR_TYPE_GRAY || color_type1 == PNG_COLOR_TYPE_GRAY_ALPHA) { | |
| 1780 png_set_gray_to_rgb(png_ptr1); | |
| 1781 } | |
| 1782 | |
| 1783 color_type2 = png_get_color_type(png_ptr2, info_ptr2); | |
| 1784 bit_depth2 = png_get_bit_depth(png_ptr2, info_ptr2); | |
| 1785 if (bit_depth2 == 16) { | |
| 1786 #if defined(PNG_LIBPNG_VER) && PNG_LIBPNG_VER >= 10504 | |
| 1787 png_set_scale_16(png_ptr2); | |
| 1788 #else | |
| 1789 png_set_strip_16(png_ptr2); | |
| 1790 #endif | |
| 1791 } | |
| 1792 if (color_type2 == PNG_COLOR_TYPE_PALETTE) { | |
| 1793 png_set_palette_to_rgb(png_ptr2); | |
| 1794 } | |
| 1795 if (color_type2 == PNG_COLOR_TYPE_GRAY && bit_depth2 < 8) { | |
| 1796 png_set_expand_gray_1_2_4_to_8(png_ptr2); | |
| 1797 } | |
| 1798 if (png_get_valid(png_ptr2, info_ptr2, PNG_INFO_tRNS)) { | |
| 1799 png_set_tRNS_to_alpha(png_ptr2); | |
| 1800 } | |
| 1801 if (color_type2 == PNG_COLOR_TYPE_RGB || color_type2 == PNG_COLOR_TYPE_GRAY | |
| 1802 || color_type2 == PNG_COLOR_TYPE_PALETTE) { | |
| 1803 png_set_filler(png_ptr2, 0xFF, PNG_FILLER_AFTER); | |
| 1804 } | |
| 1805 if (color_type2 == PNG_COLOR_TYPE_GRAY || color_type2 == PNG_COLOR_TYPE_GRAY_ALPHA) { | |
| 1806 png_set_gray_to_rgb(png_ptr2); | |
| 1807 } | |
| 1808 | |
| 1809 png_read_update_info(png_ptr1, info_ptr1); | |
| 1810 png_read_update_info(png_ptr2, info_ptr2); | |
| 1811 | |
| 1812 rowbytes1 = png_get_rowbytes(png_ptr1, info_ptr1); | |
| 1813 rowbytes2 = png_get_rowbytes(png_ptr2, info_ptr2); | |
| 1814 if (rowbytes1 != rowbytes2) { | |
| 1815 png_destroy_read_struct(&png_ptr1, &info_ptr1, (png_infopp)NULL); | |
| 1816 png_destroy_read_struct(&png_ptr2, &info_ptr2, (png_infopp)NULL); | |
| 1817 fclose(fp1); | |
| 1818 fclose(fp2); | |
| 1819 return 11; | |
| 1820 } | |
| 1821 | |
| 1822 row1 = malloc(rowbytes1); | |
| 1823 if (!row1) { | |
| 1824 png_destroy_read_struct(&png_ptr1, &info_ptr1, (png_infopp)NULL); | |
| 1825 png_destroy_read_struct(&png_ptr2, &info_ptr2, (png_infopp)NULL); | |
| 1826 fclose(fp1); | |
| 1827 fclose(fp2); | |
| 1828 return 12; | |
| 1829 } | |
| 1830 row2 = malloc(rowbytes2); | |
| 1831 if (!row2) { | |
| 1832 free(row1); | |
| 1833 png_destroy_read_struct(&png_ptr1, &info_ptr1, (png_infopp)NULL); | |
| 1834 png_destroy_read_struct(&png_ptr2, &info_ptr2, (png_infopp)NULL); | |
| 1835 fclose(fp1); | |
| 1836 fclose(fp2); | |
| 1837 return 13; | |
| 1838 } | |
| 1839 | |
| 1840 for (r = 0; r < height1; r++) { | |
| 1841 png_read_row(png_ptr1, row1, NULL); | |
| 1842 png_read_row(png_ptr2, row2, NULL); | |
| 1843 if (memcmp(row1, row2, rowbytes1) != 0) { | |
| 1844 break; | |
| 1845 } | |
| 1846 } | |
| 1847 ret = r == height1 ? 0 : 20; | |
| 1848 | |
| 1849 free(row1); | |
| 1850 free(row2); | |
| 1851 png_destroy_read_struct(&png_ptr1, &info_ptr1, (png_infopp)NULL); | |
| 1852 png_destroy_read_struct(&png_ptr2, &info_ptr2, (png_infopp)NULL); | |
| 1853 fclose(fp1); | |
| 1854 fclose(fp2); | |
| 1855 #endif | |
| 1856 return ret; | |
| 1857 } | |
| 1858 | |
| 1859 /* Compare 2 TXT files */ | |
| 1860 int testUtilCmpTxts(const char *txt1, const char *txt2) { | |
| 1861 int ret = -1; | |
| 1862 FILE *fp1; | |
| 1863 FILE *fp2; | |
| 1864 char buf1[1024]; | |
| 1865 char buf2[1024]; | |
| 1866 size_t len1 = 0, len2 = 0; | |
| 1867 | |
| 1868 fp1 = testUtilOpen(txt1, "r"); | |
| 1869 if (!fp1) { | |
| 1870 return 2; | |
| 1871 } | |
| 1872 fp2 = testUtilOpen(txt2, "r"); | |
| 1873 if (!fp2) { | |
| 1874 fclose(fp1); | |
| 1875 return 3; | |
| 1876 } | |
| 1877 | |
| 1878 while (1) { | |
| 1879 if (fgets(buf1, sizeof(buf1), fp1) == NULL) { | |
| 1880 if (fgets(buf2, sizeof(buf2), fp2) != NULL) { | |
| 1881 ret = 4; | |
| 1882 break; | |
| 1883 } | |
| 1884 break; | |
| 1885 } | |
| 1886 if (fgets(buf2, sizeof(buf2), fp2) == NULL) { | |
| 1887 ret = 5; | |
| 1888 break; | |
| 1889 } | |
| 1890 len1 = strlen(buf1); | |
| 1891 len2 = strlen(buf2); | |
| 1892 if (len1 != len2) { | |
| 1893 ret = 6; | |
| 1894 break; | |
| 1895 } | |
| 1896 if (strcmp(buf1, buf2) != 0) { | |
| 1897 ret = 7; | |
| 1898 break; | |
| 1899 } | |
| 1900 } | |
| 1901 if (ret == -1) { | |
| 1902 ret = feof(fp1) && feof(fp2) ? 0 : 20; | |
| 1903 } | |
| 1904 fclose(fp1); | |
| 1905 fclose(fp2); | |
| 1906 | |
| 1907 return ret; | |
| 1908 } | |
| 1909 | |
| 1910 /* Compare 2 binary files */ | |
| 1911 int testUtilCmpBins(const char *bin1, const char *bin2) { | |
| 1912 int ret = -1; | |
| 1913 FILE *fp1; | |
| 1914 FILE *fp2; | |
| 1915 char buf1[1024]; | |
| 1916 char buf2[1024]; | |
| 1917 size_t len1 = 0, len2 = 0; | |
| 1918 | |
| 1919 fp1 = testUtilOpen(bin1, "rb"); | |
| 1920 if (!fp1) { | |
| 1921 return 2; | |
| 1922 } | |
| 1923 fp2 = testUtilOpen(bin2, "rb"); | |
| 1924 if (!fp2) { | |
| 1925 fclose(fp1); | |
| 1926 return 3; | |
| 1927 } | |
| 1928 | |
| 1929 do { | |
| 1930 len1 = fread(buf1, 1, sizeof(buf1), fp1); | |
| 1931 len2 = fread(buf2, 1, sizeof(buf2), fp2); | |
| 1932 if (ferror(fp1) || ferror(fp2)) { | |
| 1933 ret = 4; | |
| 1934 break; | |
| 1935 } | |
| 1936 if (len1 != len2) { | |
| 1937 ret = 6; | |
| 1938 break; | |
| 1939 } | |
| 1940 if (memcmp(buf1, buf2, len1) != 0) { | |
| 1941 ret = 7; | |
| 1942 break; | |
| 1943 } | |
| 1944 } while (!feof(fp1) && !feof(fp2)); | |
| 1945 | |
| 1946 if (ret == -1) { | |
| 1947 ret = feof(fp1) && feof(fp2) ? 0 : 20; | |
| 1948 } | |
| 1949 fclose(fp1); | |
| 1950 fclose(fp2); | |
| 1951 | |
| 1952 return ret; | |
| 1953 } | |
| 1954 | |
| 1955 /* Compare 2 SVG files */ | |
| 1956 int testUtilCmpSvgs(const char *svg1, const char *svg2) { | |
| 1957 return testUtilCmpTxts(svg1, svg2); | |
| 1958 } | |
| 1959 | |
| 1960 /* Compare 2 EPS files */ | |
| 1961 int testUtilCmpEpss(const char *eps1, const char *eps2) { | |
| 1962 int ret = -1; | |
| 1963 FILE *fp1; | |
| 1964 FILE *fp2; | |
| 1965 char buf1[1024]; | |
| 1966 char buf2[1024]; | |
| 1967 size_t len1 = 0, len2 = 0; | |
| 1968 static char first_line[] = "%!PS-Adobe-3.0 EPSF-3.0\n"; | |
| 1969 static char second_line_start[] = "%%Creator: Zint "; | |
| 1970 | |
| 1971 fp1 = testUtilOpen(eps1, "r"); | |
| 1972 if (!fp1) { | |
| 1973 return 2; | |
| 1974 } | |
| 1975 fp2 = testUtilOpen(eps2, "r"); | |
| 1976 if (!fp2) { | |
| 1977 fclose(fp1); | |
| 1978 return 3; | |
| 1979 } | |
| 1980 | |
| 1981 /* Preprocess the 1st 2 lines to avoid comparing changeable Zint version in 2nd line */ | |
| 1982 if (fgets(buf1, sizeof(buf1), fp1) == NULL || strcmp(buf1, first_line) != 0 | |
| 1983 || fgets(buf2, sizeof(buf2), fp2) == NULL || strcmp(buf2, first_line) != 0) { | |
| 1984 ret = 10; | |
| 1985 } else if (fgets(buf1, sizeof(buf1), fp1) == NULL | |
| 1986 || strncmp(buf1, second_line_start, sizeof(second_line_start) - 1) != 0 | |
| 1987 || fgets(buf2, sizeof(buf2), fp2) == NULL | |
| 1988 || strncmp(buf2, second_line_start, sizeof(second_line_start) - 1) != 0) { | |
| 1989 ret = 11; | |
| 1990 } | |
| 1991 | |
| 1992 if (ret == -1) { | |
| 1993 while (1) { | |
| 1994 if (fgets(buf1, sizeof(buf1), fp1) == NULL) { | |
| 1995 if (fgets(buf2, sizeof(buf2), fp2) != NULL) { | |
| 1996 ret = 4; | |
| 1997 break; | |
| 1998 } | |
| 1999 break; | |
| 2000 } | |
| 2001 if (fgets(buf2, sizeof(buf2), fp2) == NULL) { | |
| 2002 ret = 5; | |
| 2003 break; | |
| 2004 } | |
| 2005 len1 = strlen(buf1); | |
| 2006 len2 = strlen(buf2); | |
| 2007 if (len1 != len2) { | |
| 2008 ret = 6; | |
| 2009 break; | |
| 2010 } | |
| 2011 if (strcmp(buf1, buf2) != 0) { | |
| 2012 ret = 7; | |
| 2013 break; | |
| 2014 } | |
| 2015 } | |
| 2016 if (ret == -1) { | |
| 2017 ret = feof(fp1) && feof(fp2) ? 0 : 20; | |
| 2018 } | |
| 2019 } | |
| 2020 fclose(fp1); | |
| 2021 fclose(fp2); | |
| 2022 | |
| 2023 return ret; | |
| 2024 } | |
| 2025 | |
| 2026 #ifdef _WIN32 | |
| 2027 #define DEV_NULL "> NUL" | |
| 2028 #define DEV_NULL_STDERR "> NUL 2>&1" | |
| 2029 #else | |
| 2030 #define DEV_NULL "> /dev/null" | |
| 2031 #define DEV_NULL_STDERR "> /dev/null 2>&1" | |
| 2032 #endif | |
| 2033 | |
| 2034 /* Whether ImageMagick's identify utility available on system */ | |
| 2035 const char *testUtilHaveIdentify(void) { | |
| 2036 static const char *progs[2] = { "magick identify", "identify" }; | |
| 2037 if (system("magick -version " DEV_NULL_STDERR) == 0) { | |
| 2038 return progs[0]; | |
| 2039 } | |
| 2040 if (system("identify -version " DEV_NULL_STDERR) == 0) { | |
| 2041 return progs[1]; | |
| 2042 } | |
| 2043 return NULL; | |
| 2044 } | |
| 2045 | |
| 2046 /* Check raster files */ | |
| 2047 int testUtilVerifyIdentify(const char *const prog, const char *filename, int debug) { | |
| 2048 char cmd[512 + 128]; | |
| 2049 | |
| 2050 if (strlen(filename) > 512) { | |
| 2051 return -1; | |
| 2052 } | |
| 2053 /* Verbose option does a more thorough check */ | |
| 2054 if (debug & ZINT_DEBUG_TEST_PRINT) { | |
| 2055 /* Verbose very noisy though so for quick check just return default output */ | |
| 2056 if (debug & ZINT_DEBUG_TEST_LESS_NOISY) { | |
| 2057 sprintf(cmd, "%s %s", prog, filename); | |
| 2058 } else { | |
| 2059 sprintf(cmd, "%s -verbose %s", prog, filename); | |
| 2060 } | |
| 2061 } else { | |
| 2062 sprintf(cmd, "%s -verbose %s " DEV_NULL, prog, filename); | |
| 2063 } | |
| 2064 | |
| 2065 return system(cmd); | |
| 2066 } | |
| 2067 | |
| 2068 /* Whether Libre Office available on system */ | |
| 2069 int testUtilHaveLibreOffice(void) { | |
| 2070 return system("libreoffice --version " DEV_NULL) == 0; | |
| 2071 } | |
| 2072 | |
| 2073 /* Check SVG files, very hacky to evoke. Will fail if Libre package that is not LibreOffice Draw is running */ | |
| 2074 int testUtilVerifyLibreOffice(const char *filename, int debug) { | |
| 2075 char cmd[512 + 128]; | |
| 2076 char svg[512]; | |
| 2077 char *slash, *dot; | |
| 2078 char buf[16384]; | |
| 2079 char *b = buf, *be = buf + sizeof(buf) - 1; | |
| 2080 FILE *fp; | |
| 2081 int len; | |
| 2082 | |
| 2083 /* Hack to read SVG produced by LibreOffice and search for 'x="-32767"' which indicates it didn't load barcode | |
| 2084 file */ | |
| 2085 if (strlen(filename) > 512) { | |
| 2086 return -1; | |
| 2087 } | |
| 2088 slash = strrchr(filename, '/'); | |
| 2089 if (slash) { | |
| 2090 strcpy(svg, slash + 1); | |
| 2091 } else { | |
| 2092 strcpy(svg, filename); | |
| 2093 } | |
| 2094 dot = strrchr(svg, '.'); | |
| 2095 if (dot) { | |
| 2096 strcpy(dot, ".svg"); | |
| 2097 } else { | |
| 2098 strcat(svg, ".svg"); | |
| 2099 } | |
| 2100 if (strcmp(svg, filename) == 0) { | |
| 2101 fprintf(stderr, "testUtilVerifyLibreOffice: input '%s' same as svg '%s'\n", filename, svg); | |
| 2102 return -1; | |
| 2103 } | |
| 2104 | |
| 2105 sprintf(cmd, "libreoffice --convert-to svg %s " DEV_NULL_STDERR, filename); | |
| 2106 if (debug & ZINT_DEBUG_TEST_PRINT) { | |
| 2107 printf("%s\n", cmd); | |
| 2108 } | |
| 2109 if (system(cmd) != 0) { | |
| 2110 fprintf(stderr, "testUtilVerifyLibreOffice: failed to run '%s'\n", cmd); | |
| 2111 return -1; | |
| 2112 } | |
| 2113 | |
| 2114 fp = testUtilOpen(svg, "r"); | |
| 2115 if (!fp) { | |
| 2116 fprintf(stderr, "testUtilVerifyLibreOffice: failed to open '%s' (%s)\n", svg, cmd); | |
| 2117 return -1; | |
| 2118 } | |
| 2119 while (!feof(fp) && b < be) { | |
| 2120 if (fgets(b, be - b, fp) == NULL) { | |
| 2121 fprintf(stderr, "testUtilVerifyLibreOffice: failed to get line from '%s' (%s)\n", svg, cmd); | |
| 2122 fclose(fp); | |
| 2123 return -1; | |
| 2124 } | |
| 2125 len = (int) strlen(b); | |
| 2126 if (len == 0) { | |
| 2127 break; | |
| 2128 } | |
| 2129 b += len; | |
| 2130 } | |
| 2131 *b = '\0'; | |
| 2132 fclose(fp); | |
| 2133 | |
| 2134 if (strlen(buf) < 1024) { | |
| 2135 fprintf(stderr, "testUtilVerifyLibreOffice: failed to get much input from '%s' (%s)\n", svg, cmd); | |
| 2136 return -1; | |
| 2137 } | |
| 2138 if (strstr(buf, "x=\"-32767\"") != NULL) { | |
| 2139 return -1; | |
| 2140 } | |
| 2141 testUtilRemove(svg); | |
| 2142 | |
| 2143 return 0; | |
| 2144 } | |
| 2145 | |
| 2146 #ifdef _WIN32 | |
| 2147 #define GS_FILENAME "gswin64c" | |
| 2148 #else | |
| 2149 #define GS_FILENAME "gs" | |
| 2150 #endif | |
| 2151 | |
| 2152 /* Whether Ghostscript available on system */ | |
| 2153 int testUtilHaveGhostscript(void) { | |
| 2154 return system(GS_FILENAME " -v " DEV_NULL) == 0; | |
| 2155 } | |
| 2156 | |
| 2157 /* Check EPS files */ | |
| 2158 int testUtilVerifyGhostscript(const char *filename, int debug) { | |
| 2159 char cmd[512 + 128]; | |
| 2160 | |
| 2161 if (strlen(filename) > 512) { | |
| 2162 return -1; | |
| 2163 } | |
| 2164 if (debug & ZINT_DEBUG_TEST_PRINT) { | |
| 2165 /* Prints nothing of interest with or without -q unless bad */ | |
| 2166 sprintf(cmd, GS_FILENAME " -dNOPAUSE -dBATCH -dNODISPLAY -q %s", filename); | |
| 2167 printf("%s\n", cmd); | |
| 2168 } else { | |
| 2169 sprintf(cmd, GS_FILENAME " -dNOPAUSE -dBATCH -dNODISPLAY -q %s", filename); | |
| 2170 } | |
| 2171 | |
| 2172 return system(cmd); | |
| 2173 } | |
| 2174 | |
| 2175 /* Whether vnu validator available on system. v.Nu https://github.com/validator/validator | |
| 2176 Needs "$INSTALL_DIR/vnu-runtime-image/bin" in PATH */ | |
| 2177 int testUtilHaveVnu(void) { | |
| 2178 return system("vnu --version " DEV_NULL_STDERR) == 0; | |
| 2179 } | |
| 2180 | |
| 2181 /* Check SVG files, very full but very slow */ | |
| 2182 int testUtilVerifyVnu(const char *filename, int debug) { | |
| 2183 char buf[512 + 128]; | |
| 2184 | |
| 2185 if (strlen(filename) > 512) { | |
| 2186 return -1; | |
| 2187 } | |
| 2188 if (debug & ZINT_DEBUG_TEST_PRINT) { | |
| 2189 sprintf(buf, "vnu --svg --verbose %s", filename); | |
| 2190 printf("%s\n", buf); | |
| 2191 } else { | |
| 2192 sprintf(buf, "vnu --svg %s", filename); | |
| 2193 } | |
| 2194 | |
| 2195 return system(buf); | |
| 2196 } | |
| 2197 | |
| 2198 /* Whether tiffinfo available on system. Requires libtiff 4.2.0 http://www.libtiff.org to be installed */ | |
| 2199 int testUtilHaveTiffInfo(void) { | |
| 2200 return system("tiffinfo -h " DEV_NULL) == 0; | |
| 2201 } | |
| 2202 | |
| 2203 /* Check TIF files */ | |
| 2204 int testUtilVerifyTiffInfo(const char *filename, int debug) { | |
| 2205 char cmd[512 + 128]; | |
| 2206 | |
| 2207 if (strlen(filename) > 512) { | |
| 2208 return -1; | |
| 2209 } | |
| 2210 if (debug & ZINT_DEBUG_TEST_PRINT) { | |
| 2211 sprintf(cmd, "tiffinfo -D %s", filename); | |
| 2212 } else { | |
| 2213 sprintf(cmd, "tiffinfo -D %s " DEV_NULL_STDERR, filename); | |
| 2214 } | |
| 2215 | |
| 2216 return system(cmd); | |
| 2217 } | |
| 2218 | |
| 2219 /* Map Zint symbology to BWIPP routine */ | |
| 2220 static const char *testUtilBwippName(int index, const struct zint_symbol *symbol, int option_1, int option_2, | |
| 2221 int option_3, int debug, int *linear_row_height, int *gs1_cvt) { | |
| 2222 struct item { | |
| 2223 const char *name; | |
| 2224 int define; | |
| 2225 int val; | |
| 2226 int can_option_1; | |
| 2227 int can_option_2; | |
| 2228 int can_option_3; | |
| 2229 int linear_row_height; | |
| 2230 int gs1_cvt; | |
| 2231 }; | |
| 2232 static const struct item data[] = { | |
| 2233 { "", -1, 0, 0, 0, 0, 0, 0, }, | |
| 2234 { "code11", BARCODE_CODE11, 1, 0, 1, 0, 0, 0, }, | |
| 2235 { "matrix2of5", BARCODE_C25STANDARD, 2, 0, 1, 0, 0, 0, }, | |
| 2236 { "interleaved2of5", BARCODE_C25INTER, 3, 0, 1, 0, 0, 0, }, | |
| 2237 { "iata2of5", BARCODE_C25IATA, 4, 0, 1, 0, 0, 0, }, | |
| 2238 { "", -1, 5, 0, 0, 0, 0, 0, }, | |
| 2239 { "datalogic2of5", BARCODE_C25LOGIC, 6, 0, 1, 0, 0, 0, }, | |
| 2240 { "industrial2of5", BARCODE_C25IND, 7, 0, 1, 0, 0, 0, }, | |
| 2241 { "code39", BARCODE_CODE39, 8, 0, 1, 0, 0, 0, }, | |
| 2242 { "code39ext", BARCODE_EXCODE39, 9, 0, 1, 0, 0, 0, }, | |
| 2243 { "", -1, 10, 0, 0, 0, 0, 0, }, | |
| 2244 { "", -1, 11, 0, 0, 0, 0, 0, }, | |
| 2245 { "", -1, 12, 0, 0, 0, 0, 0, }, | |
| 2246 { "ean13", BARCODE_EANX, 13, 0, 1, 0, 0, 1 /*gs1_cvt*/, }, | |
| 2247 { "ean13", BARCODE_EANX_CHK, 14, 0, 1, 0, 0, 1, }, | |
| 2248 { "", -1, 15, 0, 0, 0, 0, 0, }, | |
| 2249 { "gs1-128", BARCODE_GS1_128, 16, 0, 0, 0, 0, 1 /*gs1_cvt*/, }, | |
| 2250 { "", -1, 17, 0, 0, 0, 0, 0, }, | |
| 2251 { "rationalizedCodabar", BARCODE_CODABAR, 18, 0, 1, 0, 0, 0, }, | |
| 2252 { "", -1, 19, 0, 0, 0, 0, 0, }, | |
| 2253 { "code128", BARCODE_CODE128, 20, 0, 0, 0, 0, 0, }, | |
| 2254 { "leitcode", BARCODE_DPLEIT, 21, 0, 0, 0, 0, 0, }, | |
| 2255 { "identcode", BARCODE_DPIDENT, 22, 0, 0, 0, 0, 0, }, | |
| 2256 { "code16k", BARCODE_CODE16K, 23, 1, 0, 0, 8 /*linear_row_height*/, 0, }, | |
| 2257 { "code49", BARCODE_CODE49, 24, 1, 0, 0, 8 /*linear_row_height*/, 0, }, | |
| 2258 { "code93ext", BARCODE_CODE93, 25, 0, 0, 0, 0, 0, }, | |
| 2259 { "", -1, 26, 0, 0, 0, 0, 0, }, | |
| 2260 { "", -1, 27, 0, 0, 0, 0, 0, }, | |
| 2261 { "flattermarken", BARCODE_FLAT, 28, 0, 0, 0, 0, 0, }, | |
| 2262 { "databaromni", BARCODE_DBAR_OMN, 29, 0, 0, 0, 0, 1 /*gs1_cvt*/, }, | |
| 2263 { "databarlimited", BARCODE_DBAR_LTD, 30, 0, 0, 0, 0, 1, }, | |
| 2264 { "databarexpanded", BARCODE_DBAR_EXP, 31, 0, 1, 0, 1 /*linear_row_height*/, 1, }, | |
| 2265 { "telepen", BARCODE_TELEPEN, 32, 0, 0, 0, 0, 0, }, | |
| 2266 { "", -1, 33, 0, 0, 0, 0, 0, }, | |
| 2267 { "upca", BARCODE_UPCA, 34, 0, 1, 0, 0, 1 /*gs1_cvt*/, }, | |
| 2268 { "upca", BARCODE_UPCA_CHK, 35, 0, 1, 0, 0, 1, }, | |
| 2269 { "", -1, 36, 0, 0, 0, 0, 0, }, | |
| 2270 { "upce", BARCODE_UPCE, 37, 0, 1, 0, 0, 1 /*gs1_cvt*/, }, | |
| 2271 { "upce", BARCODE_UPCE_CHK, 38, 0, 1, 0, 0, 1, }, | |
| 2272 { "", -1, 39, 0, 0, 0, 0, 0, }, | |
| 2273 { "postnet", BARCODE_POSTNET, 40, 0, 0, 0, 0, 0, }, | |
| 2274 { "", -1, 41, 0, 0, 0, 0, 0, }, | |
| 2275 { "", -1, 42, 0, 0, 0, 0, 0, }, | |
| 2276 { "", -1, 43, 0, 0, 0, 0, 0, }, | |
| 2277 { "", -1, 44, 0, 0, 0, 0, 0, }, | |
| 2278 { "", -1, 45, 0, 0, 0, 0, 0, }, | |
| 2279 { "", -1, 46, 0, 0, 0, 0, 0, }, | |
| 2280 { "msi", BARCODE_MSI_PLESSEY, 47, 0, 1, 0, 0, 0, }, | |
| 2281 { "", -1, 48, 0, 0, 0, 0, 0, }, | |
| 2282 { "symbol", BARCODE_FIM, 49, 0, 0, 0, 0, 0, }, | |
| 2283 { "code39", BARCODE_LOGMARS, 50, 0, 1, 0, 0, 0, }, | |
| 2284 { "pharmacode", BARCODE_PHARMA, 51, 0, 0, 0, 1 /*linear_row_height*/, 0, }, | |
| 2285 { "pzn", BARCODE_PZN, 52, 0, 1, 0, 0, 0, }, | |
| 2286 { "pharmacode2", BARCODE_PHARMA_TWO, 53, 0, 0, 0, 0, 0, }, | |
| 2287 { "", BARCODE_CEPNET, 54, 0, 0, 0, 0, 0, }, | |
| 2288 { "pdf417", BARCODE_PDF417, 55, 1, 1, 1, 0, 0, }, | |
| 2289 { "pdf417compact", BARCODE_PDF417COMP, 56, 1, 1, 1, 0, 0, }, | |
| 2290 { "maxicode", BARCODE_MAXICODE, 57, 1, 1, 0, 0, 0, }, | |
| 2291 { "qrcode", BARCODE_QRCODE, 58, 1, 1, 1, 0, 0, }, | |
| 2292 { "", -1, 59, 0, 0, 0, 0, 0, }, | |
| 2293 { "code128", BARCODE_CODE128AB, 60, 0, 0, 0, 0, 0, }, | |
| 2294 { "", -1, 61, 0, 0, 0, 0, 0, }, | |
| 2295 { "", -1, 62, 0, 0, 0, 0, 0, }, | |
| 2296 { "auspost", BARCODE_AUSPOST, 63, 0, 0, 0, 0, 0, }, | |
| 2297 { "", -1, 64, 0, 0, 0, 0, 0, }, | |
| 2298 { "", -1, 65, 0, 0, 0, 0, 0, }, | |
| 2299 { "", BARCODE_AUSREPLY, 66, 0, 0, 0, 0, 0, }, | |
| 2300 { "", BARCODE_AUSROUTE, 67, 0, 0, 0, 0, 0, }, | |
| 2301 { "", BARCODE_AUSREDIRECT, 68, 0, 0, 0, 0, 0, }, | |
| 2302 { "isbn", BARCODE_ISBNX, 69, 0, 1, 0, 0, 1 /*gs1_cvt*/, }, | |
| 2303 { "royalmail", BARCODE_RM4SCC, 70, 0, 0, 0, 0, 0, }, | |
| 2304 { "datamatrix", BARCODE_DATAMATRIX, 71, 0, 1, 1, 1, 0, }, | |
| 2305 { "ean14", BARCODE_EAN14, 72, 0, 0, 0, 0, 1 /*gs1_cvt*/, }, | |
| 2306 { "code39", BARCODE_VIN, 73, 0, 0, 0, 0, 0, }, | |
| 2307 { "codablockf", BARCODE_CODABLOCKF, 74, 1, 1, 0, 10 /*linear_row_height*/, 0, }, | |
| 2308 { "sscc18", BARCODE_NVE18, 75, 0, 0, 0, 0, 1 /*gs1_cvt*/, }, | |
| 2309 { "japanpost", BARCODE_JAPANPOST, 76, 0, 0, 0, 0, 0, }, | |
| 2310 { "", BARCODE_KOREAPOST, 77, 0, 0, 0, 0, 0, }, | |
| 2311 { "", -1, 78, 0, 0, 0, 0, 0, }, | |
| 2312 { "databarstacked", BARCODE_DBAR_STK, 79, 0, 0, 0, 0, 1 /*gs1_cvt*/, }, | |
| 2313 { "databarstackedomni", BARCODE_DBAR_OMNSTK, 80, 0, 0, 0, 33 /*linear_row_height*/, 1, }, | |
| 2314 { "databarexpandedstacked", BARCODE_DBAR_EXPSTK, 81, 0, 1, 0, 34 /*linear_row_height*/, 1, }, | |
| 2315 { "planet", BARCODE_PLANET, 82, 0, 0, 0, 0, 0, }, | |
| 2316 { "", -1, 83, 0, 0, 0, 0, 0, }, | |
| 2317 { "micropdf417", BARCODE_MICROPDF417, 84, 0, 1, 0, 0, 0, }, | |
| 2318 { "onecode", BARCODE_USPS_IMAIL, 85, 0, 0, 0, 0, 0, }, | |
| 2319 { "plessey", BARCODE_PLESSEY, 86, 0, 0, 0, 0, 0, }, | |
| 2320 { "telepennumeric", BARCODE_TELEPEN_NUM, 87, 0, 0, 0, 0, 0, }, | |
| 2321 { "", -1, 88, 0, 0, 0, 0, 0, }, | |
| 2322 { "itf14", BARCODE_ITF14, 89, 0, 0, 0, 0, 0, }, | |
| 2323 { "kix", BARCODE_KIX, 90, 0, 0, 0, 0, 0, }, | |
| 2324 { "", -1, 91, 0, 0, 0, 0, 0, }, | |
| 2325 { "azteccode", BARCODE_AZTEC, 92, 1, 1, 0, 0, 0, }, | |
| 2326 { "daft", BARCODE_DAFT, 93, 0, 0, 0, 0, 0, }, | |
| 2327 { "", -1, 94, 0, 0, 0, 0, 0, }, | |
| 2328 { "", -1, 95, 0, 0, 0, 0, 0, }, | |
| 2329 { "code128", BARCODE_DPD, 96, 0, 1, 0, 0, 0, }, | |
| 2330 { "microqrcode", BARCODE_MICROQR, 97, 1, 1, 1, 0, 0, }, | |
| 2331 { "hibccode128", BARCODE_HIBC_128, 98, 0, 0, 0, 0, 0, }, | |
| 2332 { "hibccode39", BARCODE_HIBC_39, 99, 0, 0, 0, 0, 0, }, | |
| 2333 { "", -1, 100, 0, 0, 0, 0, 0, }, | |
| 2334 { "", -1, 101, 0, 0, 0, 0, 0, }, | |
| 2335 { "hibcdatamatrix", BARCODE_HIBC_DM, 102, 0, 1, 1, 0, 0, }, | |
| 2336 { "", -1, 103, 0, 0, 0, 0, 0, }, | |
| 2337 { "hibcqrcode", BARCODE_HIBC_QR, 104, 1, 1, 1, 0, 0, }, | |
| 2338 { "", -1, 105, 0, 0, 0, 0, 0, }, | |
| 2339 { "hibcpdf417", BARCODE_HIBC_PDF, 106, 1, 1, 1, 0, 0, }, | |
| 2340 { "", -1, 107, 0, 0, 0, 0, 0, }, | |
| 2341 { "hibcmicropdf417", BARCODE_HIBC_MICPDF, 108, 0, 1, 0, 0, 0, }, | |
| 2342 { "", -1, 109, 0, 0, 0, 0, 0, }, | |
| 2343 { "hibccodablockf", BARCODE_HIBC_BLOCKF, 110, 1, 1, 0, 10 /*linear_row_height*/, 0, }, | |
| 2344 { "", -1, 111, 0, 0, 0, 0, 0, }, | |
| 2345 { "hibcazteccode", BARCODE_HIBC_AZTEC, 112, 1, 0, 1, 0, 0, }, | |
| 2346 { "", -1, 113, 0, 0, 0, 0, 0, }, | |
| 2347 { "", -1, 114, 0, 0, 0, 0, 0, }, | |
| 2348 { "dotcode", BARCODE_DOTCODE, 115, 0, 1, 1, 0, 0, }, | |
| 2349 { "hanxin", BARCODE_HANXIN, 116, 0, 0, 0, 0, 0, }, | |
| 2350 { "", -1, 117, 0, 0, 0, 0, 0, }, | |
| 2351 { "", -1, 118, 0, 0, 0, 0, 0, }, | |
| 2352 { "mailmark", BARCODE_MAILMARK_2D, 119, 0, 1, 0, 0, 0, }, | |
| 2353 { "code128", BARCODE_UPU_S10, 120, 0, 0, 0, 0, 0, }, | |
| 2354 { "", BARCODE_MAILMARK_4S, 121, 0, 0, 0, 0, 0, }, /* Note BWIPP mailmark is BARCODE_MAILMARK_2D above */ | |
| 2355 { "", -1, 122, 0, 0, 0, 0, 0, }, | |
| 2356 { "", -1, 123, 0, 0, 0, 0, 0, }, | |
| 2357 { "", -1, 124, 0, 0, 0, 0, 0, }, | |
| 2358 { "", -1, 125, 0, 0, 0, 0, 0, }, | |
| 2359 { "", -1, 126, 0, 0, 0, 0, 0, }, | |
| 2360 { "", BARCODE_DXFILMEDGE, 127, 0, 0, 0, 0, 0, }, | |
| 2361 { "aztecrune", BARCODE_AZRUNE, 128, 0, 0, 0, 0, 0, }, | |
| 2362 { "code32", BARCODE_CODE32, 129, 0, 0, 0, 0, 0, }, | |
| 2363 { "ean13composite", BARCODE_EANX_CC, 130, 1, 1, 0, 72 /*linear_row_height*/, 1 /*gs1_cvt*/, }, | |
| 2364 { "gs1-128composite", BARCODE_GS1_128_CC, 131, 1, 0, 0, 36, 1, }, | |
| 2365 { "databaromnicomposite", BARCODE_DBAR_OMN_CC, 132, 1, 0, 0, 33, 1, }, | |
| 2366 { "databarlimitedcomposite", BARCODE_DBAR_LTD_CC, 133, 1, 0, 0, 10 /*linear_row_height*/, 1, }, | |
| 2367 { "databarexpandedcomposite", BARCODE_DBAR_EXP_CC, 134, 1, 1, 0, 34 /*linear_row_height*/, 1, }, | |
| 2368 { "upcacomposite", BARCODE_UPCA_CC, 135, 1, 1, 0, 72, 1, }, | |
| 2369 { "upcecomposite", BARCODE_UPCE_CC, 136, 1, 1, 0, 72, 1, }, | |
| 2370 { "databarstackedcomposite", BARCODE_DBAR_STK_CC, 137, 1, 0, 0, 0, 1, }, | |
| 2371 { "databarstackedomnicomposite", BARCODE_DBAR_OMNSTK_CC, 138, 1, 0, 0, 33 /*linear_row_height*/, 1, }, | |
| 2372 { "databarexpandedstackedcomposite", BARCODE_DBAR_EXPSTK_CC, 139, 1, 1, 0, 34 /*linear_row_height*/, 1, }, | |
| 2373 { "channelcode", BARCODE_CHANNEL, 140, 0, 0, 0, 0, 0, }, | |
| 2374 { "codeone", BARCODE_CODEONE, 141, 0, 1, 0, 0, 0, }, | |
| 2375 { "", BARCODE_GRIDMATRIX, 142, 0, 0, 0, 0, 0, }, | |
| 2376 { "qrcode", BARCODE_UPNQR, 143, 0, 0, 1, 0, 0, }, | |
| 2377 { "ultracode", BARCODE_ULTRA, 144, 1, 1, 0, 0, 0, }, | |
| 2378 { "rectangularmicroqrcode", BARCODE_RMQR, 145, 1, 1, 1, 0, 0, }, | |
| 2379 { "bc412", BARCODE_BC412, 146, 1, 1, 0, 0, 0, }, | |
| 2380 }; | |
| 2381 const int data_size = ARRAY_SIZE(data); | |
| 2382 | |
| 2383 const int symbology = symbol->symbology; | |
| 2384 const int gs1 = (symbol->input_mode & 0x07) == GS1_MODE; | |
| 2385 | |
| 2386 if (symbology < 0 || symbology >= data_size) { | |
| 2387 fprintf(stderr, "testUtilBwippName: unknown symbology (%d)\n", symbology); | |
| 2388 abort(); | |
| 2389 } | |
| 2390 /* Self-check */ | |
| 2391 if (data[symbology].val != symbology || (data[symbology].define != -1 && data[symbology].define != symbology)) { | |
| 2392 fprintf(stderr, "testUtilBwippName: data table out of sync (%d)\n", symbology); | |
| 2393 abort(); | |
| 2394 } | |
| 2395 if (data[symbology].name[0] == '\0') { | |
| 2396 if (debug & ZINT_DEBUG_TEST_PRINT) { | |
| 2397 printf("i:%d %s no BWIPP mapping\n", index, testUtilBarcodeName(symbology)); | |
| 2398 } | |
| 2399 return NULL; | |
| 2400 } | |
| 2401 if ((option_1 != -1 && !data[symbology].can_option_1) || (option_2 != -1 && !data[symbology].can_option_2) | |
| 2402 || (option_3 != -1 && !data[symbology].can_option_3)) { | |
| 2403 if (debug & ZINT_DEBUG_TEST_PRINT) { | |
| 2404 printf("i:%d %s not BWIPP compatible, options not supported, option_1 %d, option_2 %d, option_3 %d\n", | |
| 2405 index, testUtilBarcodeName(symbology), option_1, option_2, option_3); | |
| 2406 } | |
| 2407 return NULL; | |
| 2408 } | |
| 2409 if (symbol->structapp.count && symbology != BARCODE_MAXICODE) { | |
| 2410 if (debug & ZINT_DEBUG_TEST_PRINT) { | |
| 2411 printf("i:%d %s not BWIPP compatible, Structured Append not supported\n", | |
| 2412 index, testUtilBarcodeName(symbology)); | |
| 2413 } | |
| 2414 return NULL; | |
| 2415 } | |
| 2416 | |
| 2417 if (symbology == BARCODE_CODE11) { | |
| 2418 if (option_2 != 1 && option_2 != 2) { /* 2 check digits (Zint default) not supported */ | |
| 2419 if (debug & ZINT_DEBUG_TEST_PRINT) { | |
| 2420 printf("i:%d %s not BWIPP compatible, 2 check digits not supported, option_1 %d, option_2 %d\n", | |
| 2421 index, testUtilBarcodeName(symbology), option_1, option_2); | |
| 2422 } | |
| 2423 return NULL; | |
| 2424 } | |
| 2425 } else if (symbology == BARCODE_CODABLOCKF || symbology == BARCODE_HIBC_BLOCKF) { | |
| 2426 if (option_1 == 1) { /* Single row i.e. CODE128 not supported */ | |
| 2427 if (debug & ZINT_DEBUG_TEST_PRINT) { | |
| 2428 printf("i:%d %s not BWIPP compatible, single row not supported, option_1 %d\n", | |
| 2429 index, testUtilBarcodeName(symbology), option_1); | |
| 2430 } | |
| 2431 return NULL; | |
| 2432 } | |
| 2433 } else if (symbology == BARCODE_AZTEC) { | |
| 2434 if (option_1 > 0 && option_2 > 0) { | |
| 2435 if (debug & ZINT_DEBUG_TEST_PRINT) { | |
| 2436 printf("i:%d %s not BWIPP compatible, cannot specify both option_1 %d and option_2 %d\n", | |
| 2437 index, testUtilBarcodeName(symbology), option_1, option_2); | |
| 2438 } | |
| 2439 return NULL; | |
| 2440 } | |
| 2441 } else if (symbology == BARCODE_RMQR) { | |
| 2442 if (option_2 < 1) { | |
| 2443 if (debug & ZINT_DEBUG_TEST_PRINT) { | |
| 2444 printf("i:%d %s not BWIPP compatible, version (option_2) must be specified\n", | |
| 2445 index, testUtilBarcodeName(symbology)); | |
| 2446 } | |
| 2447 return NULL; | |
| 2448 } | |
| 2449 if (option_2 > 32) { | |
| 2450 if (debug & ZINT_DEBUG_TEST_PRINT) { | |
| 2451 printf("i:%d %s not BWIPP compatible, auto width (option_2 > 32) not supported\n", | |
| 2452 index, testUtilBarcodeName(symbology)); | |
| 2453 } | |
| 2454 return NULL; | |
| 2455 } | |
| 2456 } else if (symbology == BARCODE_MAILMARK_2D) { | |
| 2457 if (option_2 < 1) { | |
| 2458 if (debug & ZINT_DEBUG_TEST_PRINT) { | |
| 2459 printf("i:%d %s not BWIPP compatible, version (option_2) must be specified\n", | |
| 2460 index, testUtilBarcodeName(symbology)); | |
| 2461 } | |
| 2462 return NULL; | |
| 2463 } | |
| 2464 } | |
| 2465 | |
| 2466 if (linear_row_height) { | |
| 2467 *linear_row_height = data[symbology].linear_row_height; | |
| 2468 } | |
| 2469 if (gs1_cvt) { | |
| 2470 *gs1_cvt = data[symbology].gs1_cvt; | |
| 2471 } | |
| 2472 if (gs1) { | |
| 2473 if (symbology == BARCODE_DATAMATRIX) { | |
| 2474 if (gs1_cvt) { | |
| 2475 *gs1_cvt = 1; | |
| 2476 } | |
| 2477 return "gs1datamatrix"; | |
| 2478 } else if (symbology == BARCODE_AZTEC || symbology == BARCODE_CODE16K || symbology == BARCODE_ULTRA | |
| 2479 || symbology == BARCODE_CODE49) { | |
| 2480 if (debug & ZINT_DEBUG_TEST_PRINT) { | |
| 2481 printf("i:%d %s not BWIPP compatible, GS1_MODE not supported\n", | |
| 2482 index, testUtilBarcodeName(symbology)); | |
| 2483 } | |
| 2484 return NULL; | |
| 2485 } else if (symbology == BARCODE_QRCODE) { | |
| 2486 if (gs1_cvt) { | |
| 2487 *gs1_cvt = 1; | |
| 2488 } | |
| 2489 return "gs1qrcode"; | |
| 2490 } else if (symbology == BARCODE_DOTCODE) { | |
| 2491 if (gs1_cvt) { | |
| 2492 *gs1_cvt = 1; | |
| 2493 } | |
| 2494 return "gs1dotcode"; | |
| 2495 } | |
| 2496 } | |
| 2497 | |
| 2498 return data[symbology].name; | |
| 2499 } | |
| 2500 | |
| 2501 /* Whether can use BWIPP to check a symbology with given options */ | |
| 2502 int testUtilCanBwipp(int index, const struct zint_symbol *symbol, int option_1, int option_2, int option_3, | |
| 2503 int debug) { | |
| 2504 return testUtilBwippName(index, symbol, option_1, option_2, option_3, debug, NULL, NULL) != NULL; | |
| 2505 } | |
| 2506 | |
| 2507 /* Convert Zint GS1 and add-on format to BWIPP's */ | |
| 2508 static void testUtilBwippCvtGS1Data(char *bwipp_data, const int upcean, const int parens_mode, int *addon_posn) { | |
| 2509 char *b; | |
| 2510 int pipe = 0; | |
| 2511 | |
| 2512 *addon_posn = 0; | |
| 2513 for (b = bwipp_data; *b; b++) { | |
| 2514 if (upcean && *b == '|') { | |
| 2515 pipe = 1; | |
| 2516 } | |
| 2517 if (!parens_mode && *b == '[') { | |
| 2518 *b = '('; | |
| 2519 } else if (!parens_mode && *b == ']') { | |
| 2520 *b = ')'; | |
| 2521 } else if (*b == '+' && upcean && !pipe) { | |
| 2522 *b = ' '; | |
| 2523 *addon_posn = b - bwipp_data; | |
| 2524 } | |
| 2525 } | |
| 2526 } | |
| 2527 | |
| 2528 #define z_isxdigit(c) (z_isdigit(c) || ((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f')) | |
| 2529 #define z_isodigit(c) ((c) <= '7' && (c) >= '0') | |
| 2530 | |
| 2531 /* Convert data to Ghostscript format for passing to bwipp_dump.ps */ | |
| 2532 static char *testUtilBwippEscape(char *bwipp_data, int bwipp_data_size, const char *data, int length, | |
| 2533 int zint_escape_mode, int eci, int *parse, int *parsefnc) { | |
| 2534 const int init_parsefnc = *parsefnc == 1; | |
| 2535 char *b = bwipp_data; | |
| 2536 char *be = b + bwipp_data_size; | |
| 2537 unsigned char *d = (unsigned char *) data; | |
| 2538 unsigned char *de = (unsigned char *) data + length; | |
| 2539 | |
| 2540 if (eci && !init_parsefnc) { | |
| 2541 sprintf(bwipp_data, "^ECI%06d", eci); | |
| 2542 *parsefnc = 1; | |
| 2543 b = bwipp_data + 10; | |
| 2544 } | |
| 2545 | |
| 2546 while (b < be && d < de) { | |
| 2547 /* Have to escape double quote otherwise Ghostscript gives "Unterminated quote in @-file" for some reason */ | |
| 2548 /* Escape single quote also to avoid having to do proper shell escaping TODO: proper shell escaping */ | |
| 2549 if (*d < 0x20 || *d >= 0x7F || (*d == '^' && !init_parsefnc) || *d == '"' || *d == '\'' | |
| 2550 || *d == '(' || (*d == '\\' && !zint_escape_mode)) { | |
| 2551 if (b + 4 >= be) { | |
| 2552 fprintf(stderr, "testUtilBwippEscape: double quote bwipp_data buffer full (%d)\n", bwipp_data_size); | |
| 2553 return NULL; | |
| 2554 } | |
| 2555 sprintf(b, "^%03u", *d++); | |
| 2556 b += 4; | |
| 2557 *parse = 1; | |
| 2558 } else if (zint_escape_mode && *d == '\\' && d + 1 < de) { | |
| 2559 int val; | |
| 2560 switch (*++d) { | |
| 2561 case '0': val = 0x00; /* Null */ break; | |
| 2562 case 'E': val = 0x04; /* End of Transmission */ break; | |
| 2563 case 'a': val = 0x07; /* Bell */ break; | |
| 2564 case 'b': val = 0x08; /* Backspace */ break; | |
| 2565 case 't': val = 0x09; /* Horizontal tab */ break; | |
| 2566 case 'n': val = 0x0a; /* Line feed */ break; | |
| 2567 case 'v': val = 0x0b; /* Vertical tab */ break; | |
| 2568 case 'f': val = 0x0c; /* Form feed */ break; | |
| 2569 case 'r': val = 0x0d; /* Carriage return */ break; | |
| 2570 case 'e': val = 0x1b; /* Escape */ break; | |
| 2571 case 'G': val = 0x1d; /* Group Separator */ break; | |
| 2572 case 'R': val = 0x1e; /* Record Separator */ break; | |
| 2573 case 'x': | |
| 2574 val = d + 2 < de && z_isxdigit(d[1]) && z_isxdigit(d[2]) ? (ctoi(d[1]) << 4) | ctoi(d[2]) : -1; | |
| 2575 if (val != -1) d+= 2; | |
| 2576 break; | |
| 2577 case 'd': | |
| 2578 val = d + 3 < de ? to_int(d + 1, 3) : -1; | |
| 2579 if (val > 255) val = -1; | |
| 2580 if (val != -1) d += 3; | |
| 2581 break; | |
| 2582 case 'o': | |
| 2583 val = d + 3 < de && z_isodigit(d[1]) && z_isodigit(d[2]) && z_isodigit(d[3]) | |
| 2584 ? (ctoi(d[1]) << 6) | (ctoi(d[2]) << 3) | ctoi(d[3]) : -1; | |
| 2585 if (val > 255) val = -1; | |
| 2586 if (val != -1) d += 3; | |
| 2587 break; | |
| 2588 case '\\': val = '\\'; break; | |
| 2589 /*case 'u': val = 0; TODO: implement break; */ | |
| 2590 /*case 'U': val = 0; TODO: implement break; */ | |
| 2591 case '^': val = -1; break; /* Code 128 special escapes */ | |
| 2592 default: fprintf(stderr, "testUtilBwippEscape: unknown escape %c\n", *d); return NULL; break; | |
| 2593 } | |
| 2594 if (val >= 0) { | |
| 2595 if (b + 4 >= be) { | |
| 2596 fprintf(stderr, "testUtilBwippEscape: loop bwipp_data buffer full (%d)\n", bwipp_data_size); | |
| 2597 return NULL; | |
| 2598 } | |
| 2599 sprintf(b, "^%03d", val); | |
| 2600 b += 4; | |
| 2601 } else { | |
| 2602 if (*d == '^' && d + 1 < de && ((*(d + 1) >= '@' && *(d + 1) <= 'C') || *(d + 1) == '1')) { | |
| 2603 d++; | |
| 2604 if (*d == '1') { | |
| 2605 if (b + 5 >= be) { | |
| 2606 fprintf(stderr, "testUtilBwippEscape: FNC1 bwipp_data buffer full (%d)\n", bwipp_data_size); | |
| 2607 return NULL; | |
| 2608 } | |
| 2609 strcpy(b, "^FNC1"); | |
| 2610 b += 5; | |
| 2611 *parsefnc = 1; | |
| 2612 } | |
| 2613 } else { | |
| 2614 if (b + 8 >= be) { | |
| 2615 fprintf(stderr, "testUtilBwippEscape: loop bwipp_data buffer full (%d)\n", bwipp_data_size); | |
| 2616 return NULL; | |
| 2617 } | |
| 2618 sprintf(b, "^%03d^%03d", '\\', *d); | |
| 2619 b += 8; | |
| 2620 if (*d == '^' && d + 1 < de && *(d + 1) == '^') { | |
| 2621 d++; | |
| 2622 } | |
| 2623 } | |
| 2624 } | |
| 2625 d++; | |
| 2626 *parse = 1; | |
| 2627 } else { | |
| 2628 *b++ = *d++; | |
| 2629 } | |
| 2630 } | |
| 2631 | |
| 2632 if (b == be && d < de) { | |
| 2633 fprintf(stderr, "testUtilBwippEscape: end bwipp_data buffer full (%d)\n", bwipp_data_size); | |
| 2634 return NULL; | |
| 2635 } | |
| 2636 *b = '\0'; | |
| 2637 | |
| 2638 return bwipp_data; | |
| 2639 } | |
| 2640 | |
| 2641 /* Convert ISBN to BWIPP format */ | |
| 2642 static void testUtilISBNHyphenate(char *bwipp_data, int addon_posn) { | |
| 2643 /* Hack in 4 hyphens in fixed format, wrong for many ISBNs */ | |
| 2644 char temp[13 + 4 + 1 + 5 + 1]; | |
| 2645 int len = (int) strlen(bwipp_data); | |
| 2646 int i, j; | |
| 2647 | |
| 2648 if (len < 13 || (addon_posn && addon_posn < 13 ) || len >= (int) sizeof(temp)) { | |
| 2649 return; | |
| 2650 } | |
| 2651 for (i = 0, j = 0; i <= len; i++, j++) { | |
| 2652 if (i == 3 || i == 5 || i == 10 || i == 12) { | |
| 2653 temp[j++] = '-'; | |
| 2654 } | |
| 2655 temp[j] = bwipp_data[i]; | |
| 2656 } | |
| 2657 strcpy(bwipp_data, temp); | |
| 2658 } | |
| 2659 | |
| 2660 /* Helper to convert UTF-8 data */ | |
| 2661 static char *testUtilBwippUtf8Convert(const int index, const int symbology, const int try_sjis, int *p_eci, | |
| 2662 const unsigned char *data, int *p_data_len, unsigned char *converted) { | |
| 2663 int eci = *p_eci; | |
| 2664 | |
| 2665 if (eci == 0 && try_sjis | |
| 2666 && (symbology == BARCODE_QRCODE || symbology == BARCODE_MICROQR || symbology == BARCODE_RMQR || symbology == BARCODE_UPNQR)) { | |
| 2667 if (symbology == BARCODE_UPNQR) { /* Note need to add "force binary mode" to BWIPP for this to work */ | |
| 2668 if (utf8_to_eci(4, data, converted, p_data_len) != 0) { | |
| 2669 fprintf(stderr, "i:%d testUtilBwippUtf8Convert: failed to convert UTF-8 data for %s, ECI 4\n", | |
| 2670 index, testUtilBarcodeName(symbology)); | |
| 2671 return NULL; | |
| 2672 } | |
| 2673 *p_eci = 4; | |
| 2674 } else { | |
| 2675 if (utf8_to_eci(0, data, converted, p_data_len) != 0) { | |
| 2676 if (utf8_to_eci(20, data, converted, p_data_len) != 0) { | |
| 2677 fprintf(stderr, "i:%d testUtilBwippUtf8Convert: failed to convert UTF-8 data for %s, ECI 0/20\n", | |
| 2678 index, testUtilBarcodeName(symbology)); | |
| 2679 return NULL; | |
| 2680 } | |
| 2681 /* NOTE: not setting *p_eci = 20 */ | |
| 2682 } | |
| 2683 } | |
| 2684 return (char *) converted; | |
| 2685 } | |
| 2686 if (ZBarcode_Cap(symbology, ZINT_CAP_ECI)) { | |
| 2687 if (utf8_to_eci(eci, data, converted, p_data_len) != 0) { | |
| 2688 if (eci != 0) { | |
| 2689 fprintf(stderr, "i:%d testUtilBwippUtf8Convert: failed to convert UTF-8 data for %s, ECI %d\n", | |
| 2690 index, testUtilBarcodeName(symbology), eci); | |
| 2691 return NULL; | |
| 2692 } | |
| 2693 *p_eci = eci = get_best_eci(data, *p_data_len); | |
| 2694 if (utf8_to_eci(eci, data, converted, p_data_len) != 0) { | |
| 2695 fprintf(stderr, "i:%d testUtilBwippUtf8Convert: failed to convert UTF-8 data for %s, ECI %d\n", | |
| 2696 index, testUtilBarcodeName(symbology), eci); | |
| 2697 return NULL; | |
| 2698 } | |
| 2699 } | |
| 2700 return (char *) converted; | |
| 2701 } | |
| 2702 if (eci != 0) { | |
| 2703 fprintf(stderr, "i:%d testUtilBwippUtf8Convert: ECI %d but not supported for %s\n", | |
| 2704 index, eci, testUtilBarcodeName(symbology)); | |
| 2705 return NULL; | |
| 2706 } | |
| 2707 if (utf8_to_eci(eci, data, converted, p_data_len) != 0) { | |
| 2708 fprintf(stderr, "i:%d testUtilBwippUtf8Convert: failed to convert UTF-8 data for %s, default ECI %d\n", | |
| 2709 index, testUtilBarcodeName(symbology), eci); | |
| 2710 return NULL; | |
| 2711 } | |
| 2712 | |
| 2713 return (char *) converted; | |
| 2714 } | |
| 2715 | |
| 2716 #define GS_INITIAL_LEN 35 /* Length of cmd up to -q */ | |
| 2717 | |
| 2718 /* Create bwipp_dump.ps command and run */ | |
| 2719 int testUtilBwipp(int index, const struct zint_symbol *symbol, int option_1, int option_2, int option_3, | |
| 2720 const char *data, int length, const char *primary, char *buffer, int buffer_size, int *p_parsefnc) { | |
| 2721 static const char cmd_fmt[] = "gs -dNOPAUSE -dBATCH -dNODISPLAY -q -sb=%s -sd='%s'" | |
| 2722 " backend/tests/tools/bwipp_dump.ps"; | |
| 2723 static const char cmd_opts_fmt[] = "gs -dNOPAUSE -dBATCH -dNODISPLAY -q -sb=%s -sd='%s' -so='%s'" | |
| 2724 " backend/tests/tools/bwipp_dump.ps"; | |
| 2725 /* If data > 2K and < ~4K */ | |
| 2726 static const char cmd_fmt2[] = "gs -dNOPAUSE -dBATCH -dNODISPLAY -q -sb=%s -sd='%.2040s' -sd2='%s'" | |
| 2727 " backend/tests/tools/bwipp_dump.ps"; | |
| 2728 static const char cmd_opts_fmt2[] = "gs -dNOPAUSE -dBATCH -dNODISPLAY -q -sb=%s -sd='%.2040s' -sd2='%s' -so='%s'" | |
| 2729 " backend/tests/tools/bwipp_dump.ps"; | |
| 2730 /* If data > ~4K and < ~6K */ | |
| 2731 static const char cmd_fmt3[] = "gs -dNOPAUSE -dBATCH -dNODISPLAY -q -sb=%s -sd='%.2040s' -sd2='%.2040s' -sd3='%s'" | |
| 2732 " backend/tests/tools/bwipp_dump.ps"; | |
| 2733 static const char cmd_opts_fmt3[] = "gs -dNOPAUSE -dBATCH -dNODISPLAY -q -sb=%s -sd='%.2040s' -sd2='%.2040s' -sd3='%s'" | |
| 2734 " -so='%s' backend/tests/tools/bwipp_dump.ps"; | |
| 2735 /* If data > ~6K and < ~8K */ | |
| 2736 static const char cmd_fmt4[] = "gs -dNOPAUSE -dBATCH -dNODISPLAY -q -sb=%s -sd='%.2040s' -sd2='%.2040s' -sd3='%.2040s'" | |
| 2737 " -sd4='%s' backend/tests/tools/bwipp_dump.ps"; | |
| 2738 static const char cmd_opts_fmt4[] = "gs -dNOPAUSE -dBATCH -dNODISPLAY -q -sb=%s -sd='%.2040s' -sd2='%.2040s'" | |
| 2739 " -sd3='%.2040s' -sd4='%s' -so='%s' backend/tests/tools/bwipp_dump.ps"; | |
| 2740 | |
| 2741 const int symbology = symbol->symbology; | |
| 2742 int data_len = length == -1 ? (int) strlen(data) : length; | |
| 2743 int primary_len = primary ? (int) strlen(primary) : 0; | |
| 2744 /* 4 AI prefix + primary + '|' + leading zero + escaped data + fudge */ | |
| 2745 int max_data_len = 4 + primary_len + 1 + 1 + data_len * 4 + 64; | |
| 2746 | |
| 2747 int eci_length = get_eci_length(symbol->eci, (const unsigned char *) data, data_len); | |
| 2748 char *converted = (char *) z_alloca(eci_length + 1); | |
| 2749 char *cmd = (char *) z_alloca(max_data_len + 1024); | |
| 2750 const char *bwipp_barcode = NULL; | |
| 2751 char *bwipp_opts = NULL; | |
| 2752 int bwipp_data_size = max_data_len + 1; | |
| 2753 char *bwipp_data = (char *) z_alloca(bwipp_data_size); | |
| 2754 char bwipp_opts_buf[512]; | |
| 2755 int *bwipp_row_height = (int *) z_alloca(sizeof(int) * symbol->rows); | |
| 2756 int linear_row_height; | |
| 2757 int gs1_cvt; | |
| 2758 int user_mask; | |
| 2759 | |
| 2760 FILE *fp = NULL; | |
| 2761 int cnt; | |
| 2762 | |
| 2763 char *b = buffer; | |
| 2764 char *be = buffer + buffer_size; | |
| 2765 int r, h; | |
| 2766 int parse = 0, parsefnc = p_parsefnc ? *p_parsefnc : 0; | |
| 2767 | |
| 2768 const int upcean = (ZBarcode_Cap(symbology, ZINT_CAP_EANUPC) & ZINT_CAP_EANUPC) == ZINT_CAP_EANUPC; | |
| 2769 const int upca = symbology == BARCODE_UPCA || symbology == BARCODE_UPCA_CHK || symbology == BARCODE_UPCA_CC; | |
| 2770 const int parens_mode = symbol->input_mode & GS1PARENS_MODE; | |
| 2771 const char obracket = parens_mode ? '(' : '['; | |
| 2772 const char cbracket = parens_mode ? ')' : ']'; | |
| 2773 int addon_posn; | |
| 2774 int eci; | |
| 2775 int i, j, len; | |
| 2776 | |
| 2777 bwipp_data[0] = bwipp_opts_buf[0] = '\0'; | |
| 2778 | |
| 2779 bwipp_barcode = testUtilBwippName(index, symbol, option_1, option_2, option_3, 0, &linear_row_height, &gs1_cvt); | |
| 2780 if (!bwipp_barcode) { | |
| 2781 fprintf(stderr, "i:%d testUtilBwipp: no mapping for %s, option_1 %d, option_2 %d, option_3 %d\n", | |
| 2782 index, testUtilBarcodeName(symbology), option_1, option_2, option_3); | |
| 2783 return -1; | |
| 2784 } | |
| 2785 | |
| 2786 for (r = 0; r < symbol->rows; r++) { | |
| 2787 if (symbology == BARCODE_MAXICODE) { | |
| 2788 bwipp_row_height[r] = 1; | |
| 2789 } else { | |
| 2790 bwipp_row_height[r] = symbol->row_height[r] ? symbol->row_height[r] : linear_row_height; | |
| 2791 } | |
| 2792 if ((symbol->debug & ZINT_DEBUG_TEST_PRINT) && !(symbol->debug & ZINT_DEBUG_TEST_LESS_NOISY)) { | |
| 2793 fprintf(stderr, "bwipp_row_height[%d] %d, symbol->row_height[%d] %g\n", | |
| 2794 r, bwipp_row_height[r], r, symbol->row_height[r]); | |
| 2795 } | |
| 2796 } | |
| 2797 | |
| 2798 eci = symbol->eci >= 3 && ZBarcode_Cap(symbology, ZINT_CAP_ECI) ? symbol->eci : 0; | |
| 2799 | |
| 2800 if ((symbol->input_mode & 0x07) == UNICODE_MODE && is_eci_convertible(eci) | |
| 2801 && (data = testUtilBwippUtf8Convert(index, symbology, 1 /*try_sjis*/, &eci, (const unsigned char *) data, | |
| 2802 &data_len, (unsigned char *) converted)) == NULL) { | |
| 2803 fprintf(stderr, "i:%d testUtilBwipp: failed to convert UTF-8 data for %s\n", | |
| 2804 index, testUtilBarcodeName(symbology)); | |
| 2805 return -1; | |
| 2806 } | |
| 2807 | |
| 2808 if (is_composite(symbology)) { | |
| 2809 if (!primary) { | |
| 2810 fprintf(stderr, "i:%d testUtilBwipp: no primary data given %s\n", index, testUtilBarcodeName(symbology)); | |
| 2811 return -1; | |
| 2812 } | |
| 2813 if (*primary != obracket && !upcean) { | |
| 2814 strcat(bwipp_data, "(01)"); | |
| 2815 } | |
| 2816 strcat(bwipp_data, primary); | |
| 2817 strcat(bwipp_data, "|"); | |
| 2818 strcat(bwipp_data, data); | |
| 2819 testUtilBwippCvtGS1Data(bwipp_data, upcean, parens_mode, &addon_posn); | |
| 2820 | |
| 2821 /* Always set dontlint for now (until support for exclusive AIs check) */ | |
| 2822 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sdontlint", strlen(bwipp_opts_buf) ? " " : ""); | |
| 2823 bwipp_opts = bwipp_opts_buf; | |
| 2824 | |
| 2825 if (upcean) { | |
| 2826 if (symbology == BARCODE_EANX_CC && (primary_len <= 8 || (addon_posn && addon_posn <= 8))) { | |
| 2827 bwipp_barcode = "ean8composite"; | |
| 2828 } | |
| 2829 if (addon_posn) { | |
| 2830 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%saddongap=%d", | |
| 2831 strlen(bwipp_opts_buf) ? " " : "", option_2 > 0 ? option_2 : upca ? 9 : 7); | |
| 2832 } | |
| 2833 bwipp_row_height[symbol->rows - 1] = 72; | |
| 2834 } | |
| 2835 | |
| 2836 if (option_1 > 0) { | |
| 2837 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sccversion=%c", | |
| 2838 strlen(bwipp_opts_buf) ? " " : "", option_1 == 1 ? 'a' : option_1 == 2 ? 'b' : 'c'); | |
| 2839 } | |
| 2840 if (option_2 > 0) { | |
| 2841 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%ssegments=%d", | |
| 2842 strlen(bwipp_opts_buf) ? " " : "", option_2 * 2); | |
| 2843 } | |
| 2844 | |
| 2845 if (symbol->input_mode & GS1NOCHECK_MODE) { | |
| 2846 /* sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sdontlint", strlen(bwipp_opts_buf) ? " " : ""); */ | |
| 2847 } | |
| 2848 } else { | |
| 2849 if (gs1_cvt) { | |
| 2850 if (*data != obracket && !upcean) { | |
| 2851 strcat(bwipp_data, symbology == BARCODE_NVE18 ? "(00)" : "(01)"); | |
| 2852 } | |
| 2853 strcat(bwipp_data, data); | |
| 2854 testUtilBwippCvtGS1Data(bwipp_data, upcean, parens_mode, &addon_posn); | |
| 2855 | |
| 2856 /* Always set dontlint for now (until support for exclusive AIs check) */ | |
| 2857 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sdontlint", strlen(bwipp_opts_buf) ? " " : ""); | |
| 2858 bwipp_opts = bwipp_opts_buf; | |
| 2859 | |
| 2860 if (upcean) { | |
| 2861 if ((symbology == BARCODE_EANX || symbology == BARCODE_EANX_CHK) | |
| 2862 && (data_len <= 8 || (addon_posn && addon_posn <= 8))) { | |
| 2863 bwipp_barcode = data_len <= 3 ? "ean2" : data_len <= 5 ? "ean5" : "ean8"; | |
| 2864 } | |
| 2865 if (symbology == BARCODE_ISBNX) { | |
| 2866 testUtilISBNHyphenate(bwipp_data, addon_posn); | |
| 2867 } | |
| 2868 if (addon_posn) { | |
| 2869 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%saddongap=%d", | |
| 2870 strlen(bwipp_opts_buf) ? " " : "", option_2 > 0 ? option_2 : upca ? 9 : 7); | |
| 2871 } | |
| 2872 } | |
| 2873 | |
| 2874 if (option_2 > 0) { | |
| 2875 if (symbology == BARCODE_DBAR_EXP || symbology == BARCODE_DBAR_EXPSTK) { | |
| 2876 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%ssegments=%d", | |
| 2877 strlen(bwipp_opts_buf) ? " " : "", option_2 * 2); | |
| 2878 } | |
| 2879 } | |
| 2880 | |
| 2881 if (symbol->input_mode & GS1NOCHECK_MODE) { | |
| 2882 /* sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sdontlint", strlen(bwipp_opts_buf) ? " " : ""); */ | |
| 2883 } | |
| 2884 } else { | |
| 2885 const int is_extra_escaped = (symbol->input_mode & EXTRA_ESCAPE_MODE) | |
| 2886 && symbol->symbology == BARCODE_CODE128; | |
| 2887 const int is_escaped = (symbol->input_mode & ESCAPE_MODE) || is_extra_escaped; | |
| 2888 if (testUtilBwippEscape(bwipp_data, bwipp_data_size, data, data_len, is_escaped, eci, &parse, &parsefnc) | |
| 2889 == NULL) { | |
| 2890 return -1; | |
| 2891 } | |
| 2892 if (parse) { | |
| 2893 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sparse", strlen(bwipp_opts_buf) ? " " : ""); | |
| 2894 bwipp_opts = bwipp_opts_buf; | |
| 2895 } | |
| 2896 if (parsefnc) { | |
| 2897 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sparsefnc", | |
| 2898 strlen(bwipp_opts_buf) ? " " : ""); | |
| 2899 bwipp_opts = bwipp_opts_buf; | |
| 2900 } | |
| 2901 | |
| 2902 if (symbology == BARCODE_C25STANDARD || symbology == BARCODE_C25INTER || symbology == BARCODE_C25IATA | |
| 2903 || symbology == BARCODE_C25LOGIC || symbology == BARCODE_C25IND) { | |
| 2904 if (option_2 == 1 || option_2 == 2) { /* Add check digit without or with HRT suppression */ | |
| 2905 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sincludecheck", | |
| 2906 strlen(bwipp_opts_buf) ? " " : ""); | |
| 2907 bwipp_opts = bwipp_opts_buf; | |
| 2908 } | |
| 2909 } else if (symbology == BARCODE_CODE93) { | |
| 2910 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sincludecheck", | |
| 2911 strlen(bwipp_opts_buf) ? " " : ""); | |
| 2912 bwipp_opts = bwipp_opts_buf; | |
| 2913 } else if (symbology == BARCODE_PZN) { | |
| 2914 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%spzn%c", | |
| 2915 strlen(bwipp_opts_buf) ? " " : "", option_2 == 1 ? '7' : '8'); | |
| 2916 bwipp_opts = bwipp_opts_buf; | |
| 2917 } else if (symbology == BARCODE_TELEPEN_NUM) { | |
| 2918 if (data_len & 1) { /* Add leading zero */ | |
| 2919 memmove(bwipp_data + 1, bwipp_data, strlen(bwipp_data) + 1); | |
| 2920 *bwipp_data = '0'; | |
| 2921 } | |
| 2922 } else if (symbology == BARCODE_CODABLOCKF || symbology == BARCODE_HIBC_BLOCKF) { | |
| 2923 if (option_1 > 0) { | |
| 2924 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%srows=%d", | |
| 2925 strlen(bwipp_opts_buf) ? " " : "", option_1); | |
| 2926 } | |
| 2927 if (option_2 > 0) { | |
| 2928 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%scolumns=%d", | |
| 2929 strlen(bwipp_opts_buf) ? " " : "", option_2 - 5); | |
| 2930 } else { | |
| 2931 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%scolumns=%d", | |
| 2932 strlen(bwipp_opts_buf) ? " " : "", (symbol->width - 57) / 11); | |
| 2933 } | |
| 2934 bwipp_opts = bwipp_opts_buf; | |
| 2935 } else if (symbology == BARCODE_CODE11 || symbology == BARCODE_CODE39 || symbology == BARCODE_EXCODE39 | |
| 2936 || symbology == BARCODE_LOGMARS || symbology == BARCODE_CODABAR) { | |
| 2937 if (option_2 > 0) { | |
| 2938 if (option_2 == 1) { | |
| 2939 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sincludecheck", | |
| 2940 strlen(bwipp_opts_buf) ? " " : ""); | |
| 2941 } | |
| 2942 bwipp_opts = bwipp_opts_buf; /* Set always as option_2 == 2 is bwipp default */ | |
| 2943 } | |
| 2944 } else if (symbology == BARCODE_PLESSEY) { | |
| 2945 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sincludecheck", strlen(bwipp_opts_buf) ? " " : ""); | |
| 2946 bwipp_opts = bwipp_opts_buf; | |
| 2947 } else if (symbology == BARCODE_MSI_PLESSEY) { | |
| 2948 if (option_2 > 0) { | |
| 2949 const char *checktype = NULL; | |
| 2950 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sincludecheck", | |
| 2951 strlen(bwipp_opts_buf) ? " " : ""); | |
| 2952 | |
| 2953 if (option_2 >= 11 && option_2 <= 16) { | |
| 2954 option_2 -= 10; /* Remove no-check indicator */ | |
| 2955 } | |
| 2956 if (option_2 == 2) { | |
| 2957 checktype = "mod1010"; | |
| 2958 } else if (option_2 == 3) { | |
| 2959 checktype = "mod11 badmod11"; | |
| 2960 } else if (option_2 == 4) { | |
| 2961 checktype = "mod1110 badmod11"; | |
| 2962 } else if (option_2 == 5) { | |
| 2963 checktype = "ncrmod11 badmod11"; | |
| 2964 } else if (option_2 == 6) { | |
| 2965 checktype = "ncrmod1110 badmod11"; | |
| 2966 } | |
| 2967 if (checktype) { | |
| 2968 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%schecktype=%s", | |
| 2969 strlen(bwipp_opts_buf) ? " " : "", checktype); | |
| 2970 } | |
| 2971 bwipp_opts = bwipp_opts_buf; | |
| 2972 } | |
| 2973 } else if (symbology == BARCODE_PDF417 || symbology == BARCODE_PDF417COMP || symbology == BARCODE_HIBC_PDF | |
| 2974 || symbology == BARCODE_MICROPDF417 || symbology == BARCODE_HIBC_MICPDF) { | |
| 2975 const int row_height = symbology == BARCODE_MICROPDF417 || symbology == BARCODE_HIBC_MICPDF ? 2 : 3; | |
| 2976 for (r = 0; r < symbol->rows; r++) bwipp_row_height[r] = row_height; | |
| 2977 if (option_1 >= 0) { | |
| 2978 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%seclevel=%d fixedeclevel", | |
| 2979 strlen(bwipp_opts_buf) ? " " : "", option_1); | |
| 2980 bwipp_opts = bwipp_opts_buf; | |
| 2981 } | |
| 2982 if (option_2 > 0) { | |
| 2983 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%scolumns=%d", | |
| 2984 strlen(bwipp_opts_buf) ? " " : "", option_2); | |
| 2985 bwipp_opts = bwipp_opts_buf; | |
| 2986 } | |
| 2987 if (option_3 > 0) { | |
| 2988 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%srows=%d", | |
| 2989 strlen(bwipp_opts_buf) ? " " : "", option_3); | |
| 2990 bwipp_opts = bwipp_opts_buf; | |
| 2991 } | |
| 2992 } else if (symbology == BARCODE_POSTNET || symbology == BARCODE_PLANET || symbology == BARCODE_RM4SCC | |
| 2993 || symbology == BARCODE_JAPANPOST || symbology == BARCODE_KIX || symbology == BARCODE_DAFT | |
| 2994 || symbology == BARCODE_USPS_IMAIL || symbology == BARCODE_AUSPOST | |
| 2995 || symbology == BARCODE_PHARMA_TWO) { | |
| 2996 for (r = 0; r < symbol->rows; r++) bwipp_row_height[r] = 1; /* Zap */ | |
| 2997 if (symbology == BARCODE_RM4SCC || symbology == BARCODE_KIX || symbology == BARCODE_JAPANPOST || symbology == BARCODE_DAFT) { | |
| 2998 to_upper((unsigned char *) bwipp_data, (int) strlen(bwipp_data)); | |
| 2999 } else if (symbology == BARCODE_USPS_IMAIL) { | |
| 3000 char *dash = strchr(bwipp_data, '-'); | |
| 3001 if (dash) { | |
| 3002 memmove(dash, dash + 1, strlen(dash)); | |
| 3003 } | |
| 3004 } else if (symbology == BARCODE_AUSPOST) { | |
| 3005 const char *prefix; | |
| 3006 if (data_len == 8) { | |
| 3007 prefix = "11"; | |
| 3008 } else if (data_len == 13 || data_len == 16) { | |
| 3009 prefix = "59"; | |
| 3010 if (data_len == 16) { | |
| 3011 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%scustinfoenc=numeric", | |
| 3012 strlen(bwipp_opts_buf) ? " " : ""); | |
| 3013 bwipp_opts = bwipp_opts_buf; | |
| 3014 } | |
| 3015 } else { | |
| 3016 prefix = "62"; | |
| 3017 if (data_len == 23) { | |
| 3018 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%scustinfoenc=numeric", | |
| 3019 strlen(bwipp_opts_buf) ? " " : ""); | |
| 3020 bwipp_opts = bwipp_opts_buf; | |
| 3021 } | |
| 3022 } | |
| 3023 memmove(bwipp_data + 2, bwipp_data, data_len + 1); | |
| 3024 memmove(bwipp_data, prefix, 2); | |
| 3025 } | |
| 3026 } else if (symbology == BARCODE_CODE128AB) { | |
| 3027 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%ssuppressc", strlen(bwipp_opts_buf) ? " " : ""); | |
| 3028 bwipp_opts = bwipp_opts_buf; | |
| 3029 } else if (symbology == BARCODE_DPD) { | |
| 3030 if (data_len == 27 && option_2 != 1) { | |
| 3031 memmove(bwipp_data + 1, bwipp_data, data_len + 1); | |
| 3032 bwipp_data[0] = '%'; | |
| 3033 } | |
| 3034 bwipp_opts = bwipp_opts_buf; | |
| 3035 } else if (symbology == BARCODE_FIM) { | |
| 3036 strcpy(bwipp_data, "fima"); | |
| 3037 bwipp_data[3] = z_isupper(data[0]) ? data[0] - 'A' + 'a' : data[0]; | |
| 3038 } else if (symbology == BARCODE_CODE16K || symbology == BARCODE_CODE49) { | |
| 3039 if (option_1 >= 2) { | |
| 3040 if ((symbology == BARCODE_CODE16K && option_1 <= 16) | |
| 3041 || (symbology == BARCODE_CODE49 && option_1 <= 8 && option_1 >= symbol->rows)) { | |
| 3042 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%srows=%d", | |
| 3043 strlen(bwipp_opts_buf) ? " " : "", option_1); | |
| 3044 } | |
| 3045 bwipp_opts = bwipp_opts_buf; | |
| 3046 } | |
| 3047 } else if (symbology == BARCODE_AZTEC || symbology == BARCODE_HIBC_AZTEC) { | |
| 3048 int compact = 0, full = 0; | |
| 3049 if (option_1 >= 1 && option_1 <= 4) { | |
| 3050 int eclevel; | |
| 3051 if (option_1 == 1) { | |
| 3052 eclevel = 10; | |
| 3053 } else if (option_1 == 2) { | |
| 3054 eclevel = 23; | |
| 3055 } else if (option_1 == 3) { | |
| 3056 eclevel = 36; | |
| 3057 } else { | |
| 3058 eclevel = 50; | |
| 3059 } | |
| 3060 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%seclevel=%d", | |
| 3061 strlen(bwipp_opts_buf) ? " " : "", eclevel); | |
| 3062 bwipp_opts = bwipp_opts_buf; | |
| 3063 } | |
| 3064 if (option_2 >= 1) { | |
| 3065 int layers; | |
| 3066 if (option_2 <= 4) { | |
| 3067 compact = 1; | |
| 3068 layers = option_2; | |
| 3069 } else { | |
| 3070 layers = option_2 - 4; | |
| 3071 full = layers <= 4; | |
| 3072 } | |
| 3073 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%slayers=%d", | |
| 3074 strlen(bwipp_opts_buf) ? " " : "", layers); | |
| 3075 bwipp_opts = bwipp_opts_buf; | |
| 3076 } | |
| 3077 if (symbol->output_options & READER_INIT) { | |
| 3078 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sreaderinit", | |
| 3079 strlen(bwipp_opts_buf) ? " " : ""); | |
| 3080 bwipp_opts = bwipp_opts_buf; | |
| 3081 } | |
| 3082 if (symbology == BARCODE_HIBC_AZTEC) { | |
| 3083 compact = 1; | |
| 3084 } | |
| 3085 if (compact || full) { | |
| 3086 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sformat=%s", | |
| 3087 strlen(bwipp_opts_buf) ? " " : "", compact ? "compact" : "full"); | |
| 3088 bwipp_opts = bwipp_opts_buf; | |
| 3089 } | |
| 3090 } else if (symbology == BARCODE_CODEONE) { | |
| 3091 if ((symbol->input_mode & 0x07) == GS1_MODE) { /* Hack pseudo-GS1 support */ | |
| 3092 int last_ai, ai_latch = 0; | |
| 3093 /* Reduce square brackets (include NUL) */ | |
| 3094 for (i = 0, j = 0, len = (int) strlen(bwipp_data); i <= len; i++) { | |
| 3095 if (bwipp_data[i] == obracket) { | |
| 3096 if (ai_latch == 0) { | |
| 3097 bwipp_data[j++] = '\x1D'; | |
| 3098 } | |
| 3099 last_ai = to_int((unsigned char *) (bwipp_data + i + 1), 2); | |
| 3100 if ((last_ai >= 0 && last_ai <= 4) || (last_ai >= 11 && last_ai <= 20) || last_ai == 23 | |
| 3101 || (last_ai >= 31 && last_ai <= 36) || last_ai == 41) { | |
| 3102 ai_latch = 1; | |
| 3103 } | |
| 3104 } else if (bwipp_data[i] != cbracket) { | |
| 3105 bwipp_data[j++] = bwipp_data[i]; | |
| 3106 } | |
| 3107 } | |
| 3108 /* Replace square brackets with ^FNC1 */ | |
| 3109 for (len = (int) strlen(bwipp_data), i = len - 1; i >= 0; i--) { | |
| 3110 if (bwipp_data[i] == '\x1D') { | |
| 3111 memmove(bwipp_data + i + 5, bwipp_data + i + 1, len - i); | |
| 3112 memcpy(bwipp_data + i, "^FNC1", 5); | |
| 3113 len += 4; | |
| 3114 } | |
| 3115 } | |
| 3116 if (!parsefnc) { /* If not already done for ECI */ | |
| 3117 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sparsefnc", | |
| 3118 strlen(bwipp_opts_buf) ? " " : ""); | |
| 3119 bwipp_opts = bwipp_opts_buf; | |
| 3120 } | |
| 3121 } | |
| 3122 if (option_2 >= 1 && option_2 <= 10) { | |
| 3123 static const char *codeone_versions[] = { "A", "B", "C", "D", "E", "F", "G", "H" }; | |
| 3124 const char *codeone_version; | |
| 3125 if (option_2 == 9) { | |
| 3126 codeone_version = length <= 6 ? "S-10" : length <= 12 ? "S-20" : "S-30"; | |
| 3127 } else if (option_2 == 10) { | |
| 3128 /* TODO: Properly allow for different T sizes */ | |
| 3129 codeone_version = length <= 22 ? "T-16" : length <= 34 ? "T-32" : "T-48"; | |
| 3130 } else { | |
| 3131 codeone_version = codeone_versions[option_2 - 1]; | |
| 3132 } | |
| 3133 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sversion=%s", | |
| 3134 strlen(bwipp_opts_buf) ? " " : "", codeone_version); | |
| 3135 bwipp_opts = bwipp_opts_buf; | |
| 3136 } | |
| 3137 } else if (symbology == BARCODE_MAXICODE) { | |
| 3138 int have_eci = memcmp(bwipp_data, "^ECI", 4) == 0; | |
| 3139 int have_scm = memcmp(bwipp_data + have_eci * 10, "[)>^03001^029", 13) == 0 | |
| 3140 && z_isdigit(bwipp_data[13 + have_eci * 10]) | |
| 3141 && z_isdigit(bwipp_data[14 + have_eci * 10]); | |
| 3142 int mode = option_1; | |
| 3143 char prefix_buf[30]; | |
| 3144 int prefix_len = 0; | |
| 3145 if (mode <= 0) { | |
| 3146 if (primary_len == 0) { | |
| 3147 mode = 4; | |
| 3148 } else { | |
| 3149 mode = 2; | |
| 3150 for (i = 0; i < primary_len - 6; i++) { | |
| 3151 if (!z_isdigit(symbol->primary[i]) && (symbol->primary[i] != ' ')) { | |
| 3152 mode = 3; | |
| 3153 break; | |
| 3154 } | |
| 3155 } | |
| 3156 } | |
| 3157 } | |
| 3158 if (mode > 0) { | |
| 3159 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%smode=%d", | |
| 3160 strlen(bwipp_opts_buf) ? " " : "", mode); | |
| 3161 bwipp_opts = bwipp_opts_buf; | |
| 3162 } | |
| 3163 if (option_2 > 0) { | |
| 3164 char scm_vv_buf[40]; | |
| 3165 sprintf(scm_vv_buf, "[)>^03001^029%02d", option_2 - 1); /* [)>\R01\Gvv */ | |
| 3166 memmove(bwipp_data + 15, bwipp_data, strlen(bwipp_data) + 1); | |
| 3167 memcpy(bwipp_data, scm_vv_buf, 15); | |
| 3168 have_scm = 1; | |
| 3169 have_eci = 0; | |
| 3170 if (!parse) { | |
| 3171 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sparse", | |
| 3172 strlen(bwipp_opts_buf) ? " " : ""); | |
| 3173 bwipp_opts = bwipp_opts_buf; | |
| 3174 parse = 1; | |
| 3175 } | |
| 3176 } | |
| 3177 if (primary_len >= 6) { /* Keep gcc happy */ | |
| 3178 int postcode_len = primary_len - 6; | |
| 3179 char postcode[10]; | |
| 3180 if (postcode_len >= 10) postcode_len = 9; | |
| 3181 memcpy(postcode, primary, postcode_len); | |
| 3182 postcode[postcode_len] = '\0'; | |
| 3183 if (mode == 2) { | |
| 3184 for (i = 0; i < postcode_len; i++) { | |
| 3185 if (postcode[i] == ' ') { | |
| 3186 postcode[i] = '\0'; | |
| 3187 } | |
| 3188 } | |
| 3189 } else { | |
| 3190 postcode[6] = '\0'; | |
| 3191 for (i = postcode_len; i < 6; i++) { | |
| 3192 postcode[i] = ' '; | |
| 3193 } | |
| 3194 } | |
| 3195 sprintf(prefix_buf, "%s^029%.3s^029%.3s^029", | |
| 3196 postcode, primary + primary_len - 6, primary + primary_len - 3); | |
| 3197 prefix_len = (int) strlen(prefix_buf); | |
| 3198 } | |
| 3199 if (prefix_len || have_scm) { | |
| 3200 char eci_buf[10]; | |
| 3201 int offset = 15 * have_scm; | |
| 3202 if (have_eci) { | |
| 3203 memcpy(eci_buf, bwipp_data, 10); | |
| 3204 memmove(bwipp_data, bwipp_data + 10, strlen(bwipp_data) - 10 + 1); | |
| 3205 } | |
| 3206 memmove(bwipp_data + offset + prefix_len, bwipp_data + offset, strlen(bwipp_data) - offset + 1); | |
| 3207 memcpy(bwipp_data + offset, prefix_buf, prefix_len); | |
| 3208 if (have_eci) { | |
| 3209 memmove(bwipp_data + offset + prefix_len + 10, bwipp_data + offset + prefix_len, | |
| 3210 strlen(bwipp_data) - (offset + prefix_len) + 1); | |
| 3211 memcpy(bwipp_data + offset + prefix_len, eci_buf, 10); | |
| 3212 } | |
| 3213 } | |
| 3214 if (!parse) { | |
| 3215 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sparse", | |
| 3216 strlen(bwipp_opts_buf) ? " " : ""); | |
| 3217 bwipp_opts = bwipp_opts_buf; | |
| 3218 parse = 1; | |
| 3219 } | |
| 3220 if (symbol->structapp.count) { | |
| 3221 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%ssam=%c%c", | |
| 3222 strlen(bwipp_opts_buf) ? " " : "", itoc(symbol->structapp.index), | |
| 3223 itoc(symbol->structapp.count)); | |
| 3224 bwipp_opts = bwipp_opts_buf; | |
| 3225 } | |
| 3226 } else if (symbology == BARCODE_BC412) { | |
| 3227 to_upper((unsigned char *) bwipp_data, (int) strlen(bwipp_data)); | |
| 3228 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%ssemi", strlen(bwipp_opts_buf) ? " " : ""); | |
| 3229 bwipp_opts = bwipp_opts_buf; | |
| 3230 } else if (symbology == BARCODE_MAILMARK_2D) { | |
| 3231 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%stype=%d", | |
| 3232 strlen(bwipp_opts_buf) ? " " : "", option_2 - 1); | |
| 3233 bwipp_opts = bwipp_opts_buf; | |
| 3234 } | |
| 3235 } | |
| 3236 | |
| 3237 if (symbology == BARCODE_CODE128 || symbology == BARCODE_CODE128AB || symbology == BARCODE_HIBC_128 | |
| 3238 || symbology == BARCODE_GS1_128 || symbology == BARCODE_GS1_128_CC || symbology == BARCODE_NVE18 | |
| 3239 || symbology == BARCODE_EAN14 || symbology == BARCODE_UPU_S10 || symbology == BARCODE_MAXICODE) { | |
| 3240 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%snewencoder", strlen(bwipp_opts_buf) ? " " : ""); | |
| 3241 bwipp_opts = bwipp_opts_buf; | |
| 3242 } | |
| 3243 | |
| 3244 if (symbology == BARCODE_DATAMATRIX || symbology == BARCODE_HIBC_DM) { | |
| 3245 int added_dmre = 0; | |
| 3246 #include "../dmatrix.h" | |
| 3247 (void)dm_matrixrsblock; (void)dm_matrixdatablock; (void)dm_matrixbytes; | |
| 3248 (void)dm_matrixFW; (void)dm_matrixFH; | |
| 3249 (void)dm_isDMRE; (void)dm_text_value; (void)dm_text_shift; (void)dm_c40_value; (void)dm_c40_shift; | |
| 3250 | |
| 3251 if (symbol->output_options & GS1_GS_SEPARATOR) { | |
| 3252 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sgssep", strlen(bwipp_opts_buf) ? " " : ""); | |
| 3253 bwipp_opts = bwipp_opts_buf; | |
| 3254 } | |
| 3255 if (option_2 >= 1 && option_2 <= ARRAY_SIZE(dm_intsymbol)) { | |
| 3256 int idx = dm_intsymbol[option_2 - 1]; | |
| 3257 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%srows=%d columns=%d", | |
| 3258 strlen(bwipp_opts_buf) ? " " : "", dm_matrixH[idx], dm_matrixW[idx]); | |
| 3259 bwipp_opts = bwipp_opts_buf; | |
| 3260 if (option_2 >= 31) { | |
| 3261 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sdmre", strlen(bwipp_opts_buf) ? " " : ""); | |
| 3262 added_dmre = 1; | |
| 3263 } | |
| 3264 } | |
| 3265 if ((option_3 & 0x7F) != DM_SQUARE && symbol->width != symbol->height) { | |
| 3266 if ((option_3 & 0x7F) == DM_DMRE && !added_dmre) { | |
| 3267 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sdmre", strlen(bwipp_opts_buf) ? " " : ""); | |
| 3268 /*added_dmre = 1; */ | |
| 3269 } | |
| 3270 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sformat=rectangle", | |
| 3271 strlen(bwipp_opts_buf) ? " " : ""); | |
| 3272 bwipp_opts = bwipp_opts_buf; | |
| 3273 } | |
| 3274 if (option_3 != -1) { | |
| 3275 bwipp_opts = bwipp_opts_buf; | |
| 3276 } | |
| 3277 } else if (symbology == BARCODE_DOTCODE) { | |
| 3278 if (option_2 > 0) { | |
| 3279 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%scolumns=%d", | |
| 3280 strlen(bwipp_opts_buf) ? " " : "", symbol->option_2); | |
| 3281 bwipp_opts = bwipp_opts_buf; | |
| 3282 } | |
| 3283 if (option_3 != -1) { | |
| 3284 user_mask = (option_3 >> 8) & 0x0F; /* User mask is pattern + 1, so >= 1 and <= 8 */ | |
| 3285 if (user_mask >= 1 && user_mask <= 8) { | |
| 3286 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%smask=%d", | |
| 3287 strlen(bwipp_opts_buf) ? " " : "", (user_mask - 1) % 4); | |
| 3288 bwipp_opts = bwipp_opts_buf; | |
| 3289 } | |
| 3290 } | |
| 3291 /* Hack to place ECI after Macro header */ | |
| 3292 if (eci && length > 5 && memcmp("[)>\036", data, 4) == 0) { | |
| 3293 char macro_eci_buf[13]; | |
| 3294 if (length > 6 && data[6] == 29 /*GS*/ && ((data[4] == '0' && data[5] == '5') | |
| 3295 || (data[4] == '0' && data[5] == '6') || (data[4] == '1' && data[5] == '2'))) { | |
| 3296 memcpy(macro_eci_buf, bwipp_data + 10, 13); /* Macro */ | |
| 3297 memcpy(bwipp_data + 13, bwipp_data, 10); /* ECI */ | |
| 3298 memcpy(bwipp_data, macro_eci_buf, 13); | |
| 3299 } else if (z_isdigit(data[4]) && z_isdigit(data[5])) { | |
| 3300 memcpy(macro_eci_buf, bwipp_data, 10); /* ECI */ | |
| 3301 memcpy(bwipp_data, bwipp_data + 10, 9); /* Macro */ | |
| 3302 memcpy(bwipp_data + 9, macro_eci_buf, 10); | |
| 3303 } | |
| 3304 } | |
| 3305 } else if (symbology == BARCODE_QRCODE || symbology == BARCODE_HIBC_QR || symbology == BARCODE_MICROQR | |
| 3306 || symbology == BARCODE_RMQR) { | |
| 3307 if (option_1 >= 1 && option_1 <= 4) { | |
| 3308 static const char eccs[4] = { 'L', 'M', 'Q', 'H' }; | |
| 3309 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%seclevel=%c fixedeclevel", | |
| 3310 strlen(bwipp_opts_buf) ? " " : "", eccs[option_1 - 1]); | |
| 3311 bwipp_opts = bwipp_opts_buf; | |
| 3312 } | |
| 3313 if (symbology == BARCODE_RMQR) { | |
| 3314 if (option_2 >= 1 && option_2 <= 32) { | |
| 3315 static const char *vers[] = { | |
| 3316 "R7x43", "R7x59", "R7x77", "R7x99", "R7x139", | |
| 3317 "R9x43", "R9x59", "R9x77", "R9x99", "R9x139", | |
| 3318 "R11x27", "R11x43", "R11x59", "R11x77", "R11x99", "R11x139", | |
| 3319 "R13x27", "R13x43", "R13x59", "R13x77", "R13x99", "R13x139", | |
| 3320 "R15x43", "R15x59", "R15x77", "R15x99", "R15x139", | |
| 3321 "R17x43", "R17x59", "R17x77", "R17x99", "R17x139", | |
| 3322 }; | |
| 3323 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sversion=%s", | |
| 3324 strlen(bwipp_opts_buf) ? " " : "", vers[option_2 - 1]); | |
| 3325 bwipp_opts = bwipp_opts_buf; | |
| 3326 } | |
| 3327 } else { | |
| 3328 if (option_2 >= 1 && option_2 <= 40) { | |
| 3329 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sversion=%s%d", | |
| 3330 strlen(bwipp_opts_buf) ? " " : "", symbology == BARCODE_MICROQR ? "M" : "", option_2); | |
| 3331 bwipp_opts = bwipp_opts_buf; | |
| 3332 } | |
| 3333 if (option_3 != -1) { | |
| 3334 int mask = (symbol->option_3 >> 8) & 0x0F; | |
| 3335 if (mask >= 1 && ((symbology != BARCODE_MICROQR && mask <= 8) | |
| 3336 || (symbology == BARCODE_MICROQR && mask <= 4))) { | |
| 3337 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%smask=%d", | |
| 3338 strlen(bwipp_opts_buf) ? " " : "", ((symbol->option_3 >> 8) & 0x0F)); | |
| 3339 bwipp_opts = bwipp_opts_buf; | |
| 3340 } | |
| 3341 } | |
| 3342 } | |
| 3343 } else if (symbology == BARCODE_ULTRA) { | |
| 3344 const int rev = option_2 == 2 ? 2 : 1; | |
| 3345 if (option_1 >= 1 && option_1 <= 6) { | |
| 3346 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%seclevel=EC%d", | |
| 3347 strlen(bwipp_opts_buf) ? " " : "", option_1 - 1); | |
| 3348 } | |
| 3349 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%srev=%d", strlen(bwipp_opts_buf) ? " " : "", rev); | |
| 3350 bwipp_opts = bwipp_opts_buf; | |
| 3351 } | |
| 3352 } | |
| 3353 | |
| 3354 if ((option_1 != -1 || option_2 != -1 || option_3 != -1) && !bwipp_opts) { | |
| 3355 fprintf(stderr, | |
| 3356 "i:%d testUtilBwipp: no BWIPP options set option_1 %d, option_2 %d, option_3 %d for symbology %s\n", | |
| 3357 index, option_1, option_2, option_3, testUtilBarcodeName(symbology)); | |
| 3358 return -1; | |
| 3359 } | |
| 3360 | |
| 3361 if (bwipp_opts && strlen(bwipp_opts)) { | |
| 3362 if (strlen(bwipp_data) >= 2040) { /* Ghostscript's `arg_str_max` 2048 less "-sd?=" + quotes */ | |
| 3363 if (strlen(bwipp_data) >= 2040 * 2) { | |
| 3364 if (strlen(bwipp_data) >= 2040 * 3) { | |
| 3365 sprintf(cmd, cmd_opts_fmt4, bwipp_barcode, bwipp_data, bwipp_data + 2040, bwipp_data + 2040 * 2, | |
| 3366 bwipp_data + 2040 * 3, bwipp_opts); | |
| 3367 } else { | |
| 3368 sprintf(cmd, cmd_opts_fmt3, bwipp_barcode, bwipp_data, bwipp_data + 2040, bwipp_data + 2040 * 2, | |
| 3369 bwipp_opts); | |
| 3370 } | |
| 3371 } else { | |
| 3372 sprintf(cmd, cmd_opts_fmt2, bwipp_barcode, bwipp_data, bwipp_data + 2040, bwipp_opts); | |
| 3373 } | |
| 3374 } else { | |
| 3375 sprintf(cmd, cmd_opts_fmt, bwipp_barcode, bwipp_data, bwipp_opts); | |
| 3376 } | |
| 3377 } else { | |
| 3378 if (strlen(bwipp_data) >= 2040) { | |
| 3379 if (strlen(bwipp_data) >= 2040 * 2) { | |
| 3380 if (strlen(bwipp_data) >= 2040 * 3) { | |
| 3381 sprintf(cmd, cmd_fmt4, bwipp_barcode, bwipp_data, bwipp_data + 2040, bwipp_data + 2040 * 2, | |
| 3382 bwipp_data + 2040 * 3); | |
| 3383 } else { | |
| 3384 sprintf(cmd, cmd_fmt3, bwipp_barcode, bwipp_data, bwipp_data + 2040, bwipp_data + 2040 * 2); | |
| 3385 } | |
| 3386 } else { | |
| 3387 sprintf(cmd, cmd_fmt2, bwipp_barcode, bwipp_data, bwipp_data + 2040); | |
| 3388 } | |
| 3389 } else { | |
| 3390 sprintf(cmd, cmd_fmt, bwipp_barcode, bwipp_data); | |
| 3391 } | |
| 3392 } | |
| 3393 | |
| 3394 /* Hack in various adjustments */ | |
| 3395 if (symbology == BARCODE_DBAR_OMN || symbology == BARCODE_DBAR_LTD || symbology == BARCODE_DBAR_EXP) { | |
| 3396 /* Begin with space */ | |
| 3397 char adj[] = " -sbs"; | |
| 3398 memmove(cmd + GS_INITIAL_LEN + sizeof(adj) - 1, cmd + GS_INITIAL_LEN, strlen(cmd) + 1 - GS_INITIAL_LEN); | |
| 3399 memcpy(cmd + GS_INITIAL_LEN, adj, sizeof(adj) - 1); | |
| 3400 } | |
| 3401 if (symbology == BARCODE_CODE11 || symbology == BARCODE_CODE39 || symbology == BARCODE_EXCODE39 | |
| 3402 || symbology == BARCODE_CODABAR || symbology == BARCODE_PHARMA || symbology == BARCODE_PZN | |
| 3403 || symbology == BARCODE_CODE32 || symbology == BARCODE_VIN) { | |
| 3404 /* Ratio 3 width bar/space -> 2 width */ | |
| 3405 char adj[] = " -sr=0.6"; | |
| 3406 memmove(cmd + GS_INITIAL_LEN + sizeof(adj) - 1, cmd + GS_INITIAL_LEN, strlen(cmd) + 1 - GS_INITIAL_LEN); | |
| 3407 memcpy(cmd + GS_INITIAL_LEN, adj, sizeof(adj) - 1); | |
| 3408 } | |
| 3409 if (symbology == BARCODE_C25INTER || symbology == BARCODE_DPLEIT || symbology == BARCODE_DPIDENT | |
| 3410 || symbology == BARCODE_ITF14) { | |
| 3411 /* Ratio 2 width bar/space -> 3 width */ | |
| 3412 char adj[] = " -sr=1.3"; | |
| 3413 memmove(cmd + GS_INITIAL_LEN + sizeof(adj) - 1, cmd + GS_INITIAL_LEN, strlen(cmd) + 1 - GS_INITIAL_LEN); | |
| 3414 memcpy(cmd + GS_INITIAL_LEN, adj, sizeof(adj) - 1); | |
| 3415 } | |
| 3416 if (symbology == BARCODE_FIM) { | |
| 3417 /* Ratio 2.25 width bar/space -> 1 width */ | |
| 3418 char adj[] = " -sr=0.444"; | |
| 3419 memmove(cmd + GS_INITIAL_LEN + sizeof(adj) - 1, cmd + GS_INITIAL_LEN, strlen(cmd) + 1 - GS_INITIAL_LEN); | |
| 3420 memcpy(cmd + GS_INITIAL_LEN, adj, sizeof(adj) - 1); | |
| 3421 } | |
| 3422 if (symbology == BARCODE_PLESSEY) { | |
| 3423 /* Ceiling ratio 3/4/5 width bar/space -> 2 width then round ratio 2 width bar/space -> 3 width */ | |
| 3424 char adj[] = " -sc=0.4 -sr=1.3"; | |
| 3425 memmove(cmd + GS_INITIAL_LEN + sizeof(adj) - 1, cmd + GS_INITIAL_LEN, strlen(cmd) + 1 - GS_INITIAL_LEN); | |
| 3426 memcpy(cmd + GS_INITIAL_LEN, adj, sizeof(adj) - 1); | |
| 3427 } | |
| 3428 if (symbology == BARCODE_CODE11 || symbology == BARCODE_CODE39 || symbology == BARCODE_EXCODE39 | |
| 3429 || symbology == BARCODE_HIBC_39 || symbology == BARCODE_LOGMARS || symbology == BARCODE_PHARMA | |
| 3430 || symbology == BARCODE_PZN || symbology == BARCODE_CODE32 || symbology == BARCODE_VIN | |
| 3431 || symbology == BARCODE_C25INTER || symbology == BARCODE_DPLEIT || symbology == BARCODE_DPIDENT | |
| 3432 || symbology == BARCODE_ITF14 || symbology == BARCODE_PHARMA_TWO) { | |
| 3433 /* End sbs loop on bar */ | |
| 3434 char adj[] = " -selb"; | |
| 3435 memmove(cmd + GS_INITIAL_LEN + sizeof(adj) - 1, cmd + GS_INITIAL_LEN, strlen(cmd) + 1 - GS_INITIAL_LEN); | |
| 3436 memcpy(cmd + GS_INITIAL_LEN, adj, sizeof(adj) - 1); | |
| 3437 } | |
| 3438 if (symbology == BARCODE_C25STANDARD) { | |
| 3439 /* Zint uses 4X start/stop wides while BWIPP uses 3X - convert */ | |
| 3440 char adj[] = " -sp='i 0 eq i limit 4 sub eq or sbs i get 3 eq and { (1111) print true } { false } ifelse'"; | |
| 3441 memmove(cmd + GS_INITIAL_LEN + sizeof(adj) - 1, cmd + GS_INITIAL_LEN, strlen(cmd) + 1 - GS_INITIAL_LEN); | |
| 3442 memcpy(cmd + GS_INITIAL_LEN, adj, sizeof(adj) - 1); | |
| 3443 } | |
| 3444 if (symbology == BARCODE_POSTNET || symbology == BARCODE_PLANET || symbology == BARCODE_RM4SCC | |
| 3445 || symbology == BARCODE_JAPANPOST || symbology == BARCODE_KIX || symbology == BARCODE_DAFT | |
| 3446 || symbology == BARCODE_USPS_IMAIL || symbology == BARCODE_AUSPOST || symbology == BARCODE_PHARMA_TWO) { | |
| 3447 /* Emulate rows with BWIPP heights. */ | |
| 3448 char adj[] = " -shs"; | |
| 3449 memmove(cmd + GS_INITIAL_LEN + sizeof(adj) - 1, cmd + GS_INITIAL_LEN, strlen(cmd) + 1 - GS_INITIAL_LEN); | |
| 3450 memcpy(cmd + GS_INITIAL_LEN, adj, sizeof(adj) - 1); | |
| 3451 } | |
| 3452 if (symbology == BARCODE_CODE16K || symbology == BARCODE_CODE49) { | |
| 3453 char adj[] = " -sxs=10 -sxe=1"; /* Strip first 10 and last zero */ | |
| 3454 memmove(cmd + GS_INITIAL_LEN + sizeof(adj) - 1, cmd + GS_INITIAL_LEN, strlen(cmd) + 1 - GS_INITIAL_LEN); | |
| 3455 memcpy(cmd + GS_INITIAL_LEN, adj, sizeof(adj) - 1); | |
| 3456 } | |
| 3457 | |
| 3458 if (symbol->debug & ZINT_DEBUG_TEST_PRINT) { | |
| 3459 printf("i:%d testUtilBwipp: cmd %s\n", index, cmd); | |
| 3460 } | |
| 3461 | |
| 3462 fp = testutil_popen(cmd, "r"); | |
| 3463 if (!fp) { | |
| 3464 fprintf(stderr, "i:%d testUtilBwipp: failed to run '%s'\n", index, cmd); | |
| 3465 return -1; | |
| 3466 } | |
| 3467 | |
| 3468 if (symbol->rows == 0) { /* For testing BWIPP against ZXingC++ (`ZBarcode_Encode()` not called) */ | |
| 3469 cnt = (int) fread(b, 1, buffer_size - 1, fp); /* Just read the whole output */ | |
| 3470 b += cnt; | |
| 3471 } else { | |
| 3472 for (r = 0; r < symbol->rows; r++) { | |
| 3473 if (b + symbol->width > be) { | |
| 3474 fprintf(stderr, "i:%d testUtilBwipp: row %d, width %d, row width iteration overrun (%s)\n", | |
| 3475 index, r, symbol->width, cmd); | |
| 3476 testutil_pclose(fp); | |
| 3477 return -1; | |
| 3478 } | |
| 3479 cnt = (int) fread(b, 1, symbol->width, fp); | |
| 3480 if (cnt != symbol->width) { | |
| 3481 fprintf(stderr, "i:%d testUtilBwipp: failed to read row %d of %d, symbol->width %d bytes, cnt %d (%s)\n", | |
| 3482 index, r + 1, symbol->rows, symbol->width, cnt, cmd); | |
| 3483 testutil_pclose(fp); | |
| 3484 return -1; | |
| 3485 } | |
| 3486 b += cnt; | |
| 3487 for (h = bwipp_row_height[r]; h > 1; h--) { /* Ignore row copies if any */ | |
| 3488 cnt = (int) fread(b, 1, symbol->width, fp); | |
| 3489 if (cnt != symbol->width) { | |
| 3490 fprintf(stderr, | |
| 3491 "i:%d testUtilBwipp: failed to read/ignore symbol->width %d bytes, cnt %d, h %d" | |
| 3492 ", bwipp_row_height[%d] %d, symbol->row_height[%d] %g (%s)\n", | |
| 3493 index, symbol->width, cnt, h, r, bwipp_row_height[r], r, symbol->row_height[r], cmd); | |
| 3494 testutil_pclose(fp); | |
| 3495 return -1; | |
| 3496 } | |
| 3497 if (h * 2 == bwipp_row_height[r]) { /* Hack to use middle row (avoids add-on text offsets) */ | |
| 3498 memcpy(b - cnt, b, cnt); | |
| 3499 } | |
| 3500 } | |
| 3501 } | |
| 3502 } | |
| 3503 *b = '\0'; | |
| 3504 | |
| 3505 if (fgetc(fp) != EOF) { | |
| 3506 fprintf(stderr, "i:%d testUtilBwipp: failed to read full stream (%s)\n", index, cmd); | |
| 3507 testutil_pclose(fp); | |
| 3508 return -1; | |
| 3509 } | |
| 3510 | |
| 3511 testutil_pclose(fp); | |
| 3512 | |
| 3513 return 0; | |
| 3514 } | |
| 3515 | |
| 3516 /* Append multiple segments together and then call `testUtilBwipp()` */ | |
| 3517 int testUtilBwippSegs(int index, struct zint_symbol *symbol, int option_1, int option_2, int option_3, | |
| 3518 const struct zint_seg segs[], const int seg_count, const char *primary, char *buffer, int buffer_size) { | |
| 3519 const int symbology = symbol->symbology; | |
| 3520 const int unicode_mode = (symbol->input_mode & 0x7) == UNICODE_MODE; | |
| 3521 const int symbol_eci = symbol->eci; | |
| 3522 struct zint_seg *local_segs = (struct zint_seg *) z_alloca(sizeof(struct zint_seg) * seg_count); | |
| 3523 int total_len = 0; | |
| 3524 char *data, *d; | |
| 3525 int parsefnc = 1; | |
| 3526 int ret; | |
| 3527 int i; | |
| 3528 | |
| 3529 assert(ZBarcode_Cap(symbology, ZINT_CAP_ECI)); | |
| 3530 | |
| 3531 for (i = 0; i < seg_count; i++) { | |
| 3532 local_segs[i] = segs[i]; | |
| 3533 if (local_segs[i].length == -1) { | |
| 3534 local_segs[i].length = (int) ustrlen(local_segs[i].source); | |
| 3535 } | |
| 3536 if (unicode_mode) { | |
| 3537 total_len += get_eci_length(local_segs[i].eci, local_segs[i].source, local_segs[i].length); | |
| 3538 } else { | |
| 3539 total_len += local_segs[i].length; | |
| 3540 } | |
| 3541 } | |
| 3542 total_len += 10 * seg_count; | |
| 3543 d = data = (char *) z_alloca(total_len + 1); | |
| 3544 | |
| 3545 for (i = 0; i < seg_count; i++) { | |
| 3546 if (unicode_mode && is_eci_convertible(local_segs[i].eci)) { | |
| 3547 char *converted = testUtilBwippUtf8Convert(index, symbology, 0 /*try_sjis*/, &local_segs[i].eci, | |
| 3548 local_segs[i].source, &local_segs[i].length, (unsigned char *) d); | |
| 3549 if (converted == NULL) { | |
| 3550 return -1; | |
| 3551 } | |
| 3552 if (converted == d) { | |
| 3553 /* Ensure default ECI set if follows non-default ECI */ | |
| 3554 if (i != 0 && local_segs[i].eci == 0 && local_segs[i - 1].eci > 3) { | |
| 3555 local_segs[i].eci = 3; | |
| 3556 } | |
| 3557 if (local_segs[i].eci) { /* Note this will fail if have DotCode macro */ | |
| 3558 char eci_str[10 + 1]; | |
| 3559 sprintf(eci_str, "^ECI%06d", local_segs[i].eci); | |
| 3560 memmove(d + 10, d, local_segs[i].length); | |
| 3561 memcpy(d, eci_str, 10); | |
| 3562 d += 10; | |
| 3563 } | |
| 3564 d += local_segs[i].length; | |
| 3565 } else { | |
| 3566 /* Ensure default ECI set if follows non-default ECI */ | |
| 3567 if (i != 0 && local_segs[i].eci == 0 && local_segs[i - 1].eci > 3) { | |
| 3568 local_segs[i].eci = 3; | |
| 3569 } | |
| 3570 if (local_segs[i].eci) { | |
| 3571 d += sprintf(d, "^ECI%06d", local_segs[i].eci); | |
| 3572 } | |
| 3573 memcpy(d, local_segs[i].source, local_segs[i].length); | |
| 3574 d += local_segs[i].length; | |
| 3575 } | |
| 3576 } else { | |
| 3577 /* Ensure default ECI set if follows non-default ECI */ | |
| 3578 if (i != 0 && local_segs[i].eci == 0 && local_segs[i - 1].eci > 3) { | |
| 3579 local_segs[i].eci = 3; | |
| 3580 } | |
| 3581 if (local_segs[i].eci) { | |
| 3582 d += sprintf(d, "^ECI%06d", local_segs[i].eci); | |
| 3583 } | |
| 3584 memcpy(d, local_segs[i].source, local_segs[i].length); | |
| 3585 d += local_segs[i].length; | |
| 3586 } | |
| 3587 } | |
| 3588 total_len = d - data; | |
| 3589 | |
| 3590 if (unicode_mode) { | |
| 3591 symbol->input_mode = DATA_MODE; | |
| 3592 } | |
| 3593 symbol->eci = 0; | |
| 3594 | |
| 3595 ret = testUtilBwipp(index, symbol, option_1, option_2, option_3, data, total_len, primary, buffer, buffer_size, &parsefnc); | |
| 3596 | |
| 3597 if (unicode_mode) { | |
| 3598 symbol->input_mode = UNICODE_MODE; | |
| 3599 } | |
| 3600 symbol->eci = symbol_eci; | |
| 3601 | |
| 3602 return ret; | |
| 3603 } | |
| 3604 | |
| 3605 /* Compare bwipp_dump.ps output to test suite module dump */ | |
| 3606 int testUtilBwippCmp(const struct zint_symbol *symbol, char *msg, char *cmp_buf, const char *expected) { | |
| 3607 int cmp_len = (int) strlen(cmp_buf); | |
| 3608 int expected_len = (int) strlen(expected); | |
| 3609 int ret_memcmp; | |
| 3610 int i; | |
| 3611 | |
| 3612 (void)symbol; | |
| 3613 | |
| 3614 if (cmp_len != expected_len) { | |
| 3615 sprintf(msg, "cmp_len %d != expected_len %d", cmp_len, expected_len); | |
| 3616 return 2; | |
| 3617 } | |
| 3618 | |
| 3619 if (symbol->symbology == BARCODE_ULTRA) { | |
| 3620 static const char map[] = { '8', '1', '2', '3', '4', '5', '6', '7', '8', '7' }; | |
| 3621 for (i = 0; i < cmp_len; i++) { | |
| 3622 if (z_isdigit(cmp_buf[i])) { | |
| 3623 cmp_buf[i] = map[cmp_buf[i] - '0']; | |
| 3624 } | |
| 3625 } | |
| 3626 } | |
| 3627 ret_memcmp = memcmp(cmp_buf, expected, expected_len); | |
| 3628 if (ret_memcmp != 0) { | |
| 3629 for (i = 0; i < expected_len; i++) { | |
| 3630 if (cmp_buf[i] != expected[i]) { | |
| 3631 break; | |
| 3632 } | |
| 3633 } | |
| 3634 sprintf(msg, "memcmp %d != 0, at %d, len %d", ret_memcmp, i, expected_len); | |
| 3635 return ret_memcmp; | |
| 3636 } | |
| 3637 | |
| 3638 return 0; | |
| 3639 } | |
| 3640 | |
| 3641 /* Compare bwipp_dump.ps output to single row module dump (see testUtilModulesPrintRow) */ | |
| 3642 int testUtilBwippCmpRow(const struct zint_symbol *symbol, int row, char *msg, const char *cmp_buf, | |
| 3643 const char *expected) { | |
| 3644 int cmp_len = (int) strlen(cmp_buf); | |
| 3645 int expected_len = (int) strlen(expected); | |
| 3646 int ret_memcmp; | |
| 3647 int i, j; | |
| 3648 | |
| 3649 (void)symbol; | |
| 3650 | |
| 3651 if (cmp_len != expected_len * symbol->rows) { | |
| 3652 sprintf(msg, "cmp_len %d != expected_len %d * symbol->rows %d", cmp_len, expected_len, symbol->rows); | |
| 3653 return 2; | |
| 3654 } | |
| 3655 | |
| 3656 ret_memcmp = memcmp(cmp_buf + expected_len * row, expected, expected_len); | |
| 3657 if (ret_memcmp != 0) { | |
| 3658 for (i = 0, j = expected_len * row; i < expected_len; i++, j++) { | |
| 3659 if (cmp_buf[j] != expected[i]) { | |
| 3660 break; | |
| 3661 } | |
| 3662 } | |
| 3663 sprintf(msg, "memcmp %d != 0, at %d (%d), len %d", ret_memcmp, i, j, expected_len); | |
| 3664 return ret_memcmp; | |
| 3665 } | |
| 3666 | |
| 3667 return 0; | |
| 3668 } | |
| 3669 | |
| 3670 /* Whether ZXing-C++ Decoder available on system */ | |
| 3671 /* Requires the "diagnostics2" branch from https://github.com/gitlost/zxing-cpp built with BUILD_EXAMPLE_DECODER | |
| 3672 and "zxingcppdecoder" placed in PATH, e.g.: | |
| 3673 git clone --branch diagnostics2 https://github.com/gitlost/zxing-cpp zxing-cpp-diagnostics2 | |
| 3674 cd zxing-cpp-diagnostics2 | |
| 3675 mkdir build; cd build | |
| 3676 cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DBUILD_EXAMPLE_DECODER=ON .. | |
| 3677 make && sudo make install | |
| 3678 */ | |
| 3679 int testUtilHaveZXingCPPDecoder(void) { | |
| 3680 return system("zxingcppdecoder " DEV_NULL_STDERR) == 0; | |
| 3681 } | |
| 3682 | |
| 3683 /* Helper to test whether have non-ASCII */ | |
| 3684 static int testUtilHasNonASCII(const char *source, const int length) { | |
| 3685 int i; | |
| 3686 for (i = 0; i < length; i++) { | |
| 3687 if (source[i] & 0x80) { | |
| 3688 return 1; | |
| 3689 } | |
| 3690 } | |
| 3691 return 0; | |
| 3692 } | |
| 3693 | |
| 3694 /* Map Zint symbology to ZXing-C++ format name */ | |
| 3695 static const char *testUtilZXingCPPName(int index, const struct zint_symbol *symbol, const char *source, | |
| 3696 const int length, const int debug) { | |
| 3697 struct item { | |
| 3698 const char *name; | |
| 3699 int define; | |
| 3700 int val; | |
| 3701 }; | |
| 3702 static const struct item data[] = { | |
| 3703 { "", -1, 0, }, | |
| 3704 { "", BARCODE_CODE11, 1, }, | |
| 3705 { "", BARCODE_C25STANDARD, 2, }, | |
| 3706 { "ITF", BARCODE_C25INTER, 3, }, | |
| 3707 { "", BARCODE_C25IATA, 4, }, | |
| 3708 { "", -1, 5, }, | |
| 3709 { "", BARCODE_C25LOGIC, 6, }, | |
| 3710 { "", BARCODE_C25IND, 7, }, | |
| 3711 { "Code39", BARCODE_CODE39, 8, }, | |
| 3712 { "Code39", BARCODE_EXCODE39, 9, }, /* TODO: Code39 with specially encoded chars */ | |
| 3713 { "", -1, 10, }, | |
| 3714 { "", -1, 11, }, | |
| 3715 { "", -1, 12, }, | |
| 3716 { "EAN-13", BARCODE_EANX, 13, }, | |
| 3717 { "EAN-13", BARCODE_EANX_CHK, 14, }, | |
| 3718 { "", -1, 15, }, | |
| 3719 { "Code128", BARCODE_GS1_128, 16, }, | |
| 3720 { "", -1, 17, }, | |
| 3721 { "Codabar", BARCODE_CODABAR, 18, }, | |
| 3722 { "", -1, 19, }, | |
| 3723 { "Code128", BARCODE_CODE128, 20, }, | |
| 3724 { "ITF", BARCODE_DPLEIT, 21, }, | |
| 3725 { "ITF", BARCODE_DPIDENT, 22, }, | |
| 3726 { "Code16K", BARCODE_CODE16K, 23, }, | |
| 3727 { "", BARCODE_CODE49, 24, }, | |
| 3728 { "Code93", BARCODE_CODE93, 25, }, | |
| 3729 { "", -1, 26, }, | |
| 3730 { "", -1, 27, }, | |
| 3731 { "", BARCODE_FLAT, 28, }, | |
| 3732 { "DataBar", BARCODE_DBAR_OMN, 29, }, | |
| 3733 { "DataBarLimited", BARCODE_DBAR_LTD, 30, }, | |
| 3734 { "DataBarExpanded", BARCODE_DBAR_EXP, 31, }, | |
| 3735 { "", BARCODE_TELEPEN, 32, }, | |
| 3736 { "", -1, 33, }, | |
| 3737 { "UPC-A", BARCODE_UPCA, 34, }, | |
| 3738 { "UPC-A", BARCODE_UPCA_CHK, 35, }, | |
| 3739 { "", -1, 36, }, | |
| 3740 { "UPC-E", BARCODE_UPCE, 37, }, | |
| 3741 { "UPC-E", BARCODE_UPCE_CHK, 38, }, | |
| 3742 { "", -1, 39, }, | |
| 3743 { "", BARCODE_POSTNET, 40, }, | |
| 3744 { "", -1, 41, }, | |
| 3745 { "", -1, 42, }, | |
| 3746 { "", -1, 43, }, | |
| 3747 { "", -1, 44, }, | |
| 3748 { "", -1, 45, }, | |
| 3749 { "", -1, 46, }, | |
| 3750 { "", BARCODE_MSI_PLESSEY, 47, }, | |
| 3751 { "", -1, 48, }, | |
| 3752 { "", BARCODE_FIM, 49, }, | |
| 3753 { "Code39", BARCODE_LOGMARS, 50, }, | |
| 3754 { "", BARCODE_PHARMA, 51, }, | |
| 3755 { "Code39", BARCODE_PZN, 52, }, | |
| 3756 { "", BARCODE_PHARMA_TWO, 53, }, | |
| 3757 { "", -1, 54, }, | |
| 3758 { "PDF417", BARCODE_PDF417, 55, }, | |
| 3759 { "PDF417", BARCODE_PDF417COMP, 56, }, | |
| 3760 { "MaxiCode", BARCODE_MAXICODE, 57, }, | |
| 3761 { "QRCode", BARCODE_QRCODE, 58, }, | |
| 3762 { "", -1, 59, }, | |
| 3763 { "Code128", BARCODE_CODE128AB, 60, }, | |
| 3764 { "", -1, 61, }, | |
| 3765 { "", -1, 62, }, | |
| 3766 { "", BARCODE_AUSPOST, 63, }, | |
| 3767 { "", -1, 64, }, | |
| 3768 { "", -1, 65, }, | |
| 3769 { "", BARCODE_AUSREPLY, 66, }, | |
| 3770 { "", BARCODE_AUSROUTE, 67, }, | |
| 3771 { "", BARCODE_AUSREDIRECT, 68, }, | |
| 3772 { "EAN-13", BARCODE_ISBNX, 69, }, | |
| 3773 { "", BARCODE_RM4SCC, 70, }, | |
| 3774 { "DataMatrix", BARCODE_DATAMATRIX, 71, }, | |
| 3775 { "Code128", BARCODE_EAN14, 72, }, | |
| 3776 { "Code39", BARCODE_VIN, 73, }, | |
| 3777 { "CodablockF", BARCODE_CODABLOCKF, 74, }, | |
| 3778 { "Code128", BARCODE_NVE18, 75, }, | |
| 3779 { "", BARCODE_JAPANPOST, 76, }, | |
| 3780 { "", BARCODE_KOREAPOST, 77, }, | |
| 3781 { "", -1, 78, }, | |
| 3782 { "DataBar", BARCODE_DBAR_STK, 79, }, | |
| 3783 { "DataBar", BARCODE_DBAR_OMNSTK, 80, }, | |
| 3784 { "DataBarExpanded", BARCODE_DBAR_EXPSTK, 81, }, | |
| 3785 { "", BARCODE_PLANET, 82, }, | |
| 3786 { "", -1, 83, }, | |
| 3787 { "MicroPDF417", BARCODE_MICROPDF417, 84, }, | |
| 3788 { "", BARCODE_USPS_IMAIL, 85, }, | |
| 3789 { "", BARCODE_PLESSEY, 86, }, | |
| 3790 { "", BARCODE_TELEPEN_NUM, 87, }, | |
| 3791 { "", -1, 88, }, | |
| 3792 { "ITF", BARCODE_ITF14, 89, }, | |
| 3793 { "", BARCODE_KIX, 90, }, | |
| 3794 { "", -1, 91, }, | |
| 3795 { "Aztec", BARCODE_AZTEC, 92, }, | |
| 3796 { "", BARCODE_DAFT, 93, }, | |
| 3797 { "", -1, 94, }, | |
| 3798 { "", -1, 95, }, | |
| 3799 { "Code128", BARCODE_DPD, 96, }, | |
| 3800 { "MicroQRCode", BARCODE_MICROQR, 97, }, | |
| 3801 { "Code128", BARCODE_HIBC_128, 98, }, | |
| 3802 { "Code39", BARCODE_HIBC_39, 99, }, | |
| 3803 { "", -1, 100, }, | |
| 3804 { "", -1, 101, }, | |
| 3805 { "DataMatrix", BARCODE_HIBC_DM, 102, }, | |
| 3806 { "", -1, 103, }, | |
| 3807 { "QRCode", BARCODE_HIBC_QR, 104, }, | |
| 3808 { "", -1, 105, }, | |
| 3809 { "PDF417", BARCODE_HIBC_PDF, 106, }, | |
| 3810 { "", -1, 107, }, | |
| 3811 { "MicroPDF417", BARCODE_HIBC_MICPDF, 108, }, | |
| 3812 { "", -1, 109, }, | |
| 3813 { "CodablockF", BARCODE_HIBC_BLOCKF, 110, }, | |
| 3814 { "", -1, 111, }, | |
| 3815 { "Aztec", BARCODE_HIBC_AZTEC, 112, }, | |
| 3816 { "", -1, 113, }, | |
| 3817 { "", -1, 114, }, | |
| 3818 { "DotCode", BARCODE_DOTCODE, 115, }, | |
| 3819 { "HanXin", BARCODE_HANXIN, 116, }, | |
| 3820 { "", -1, 117, }, | |
| 3821 { "", -1, 118, }, | |
| 3822 { "DataMatrix", BARCODE_MAILMARK_2D, 119, }, | |
| 3823 { "Code128", BARCODE_UPU_S10, 120, }, | |
| 3824 { "", BARCODE_MAILMARK_4S, 121, }, | |
| 3825 { "", -1, 122, }, | |
| 3826 { "", -1, 123, }, | |
| 3827 { "", -1, 124, }, | |
| 3828 { "", -1, 125, }, | |
| 3829 { "", -1, 126, }, | |
| 3830 { "", -1, 127, }, | |
| 3831 { "", BARCODE_AZRUNE, 128, }, | |
| 3832 { "", BARCODE_CODE32, 129, }, /* Code39 based */ | |
| 3833 { "", BARCODE_EANX_CC, 130, }, | |
| 3834 { "", BARCODE_GS1_128_CC, 131, }, | |
| 3835 { "", BARCODE_DBAR_OMN_CC, 132, }, | |
| 3836 { "", BARCODE_DBAR_LTD_CC, 133, }, | |
| 3837 { "", BARCODE_DBAR_EXP_CC, 134, }, | |
| 3838 { "", BARCODE_UPCA_CC, 135, }, | |
| 3839 { "", BARCODE_UPCE_CC, 136, }, | |
| 3840 { "", BARCODE_DBAR_STK_CC, 137, }, | |
| 3841 { "", BARCODE_DBAR_OMNSTK_CC, 138, }, | |
| 3842 { "", BARCODE_DBAR_EXPSTK_CC, 139, }, | |
| 3843 { "", BARCODE_CHANNEL, 140, }, | |
| 3844 { "", BARCODE_CODEONE, 141, }, | |
| 3845 { "", BARCODE_GRIDMATRIX, 142, }, | |
| 3846 { "QRCode", BARCODE_UPNQR, 143, }, | |
| 3847 { "", BARCODE_ULTRA, 144, }, | |
| 3848 { "RMQRCode", BARCODE_RMQR, 145, }, | |
| 3849 { "", BARCODE_BC412, 146, }, | |
| 3850 { "DXFilmEdge", BARCODE_DXFILMEDGE, 147, }, | |
| 3851 }; | |
| 3852 const int data_size = ARRAY_SIZE(data); | |
| 3853 | |
| 3854 const int symbology = symbol->symbology; | |
| 3855 | |
| 3856 if (symbology < 0 || symbology >= data_size) { | |
| 3857 fprintf(stderr, "testUtilZXingCPPName: unknown symbology (%d)\n", symbology); | |
| 3858 abort(); | |
| 3859 } | |
| 3860 /* Self-check */ | |
| 3861 if (data[symbology].val != symbology || (data[symbology].define != -1 && data[symbology].define != symbology)) { | |
| 3862 fprintf(stderr, "testUtilZXingCPPName: data table out of sync (%d)\n", symbology); | |
| 3863 abort(); | |
| 3864 } | |
| 3865 if (data[symbology].name[0] == '\0') { | |
| 3866 if (debug & ZINT_DEBUG_TEST_PRINT) { | |
| 3867 printf("i:%d %s no ZXint-C++ mapping\n", index, testUtilBarcodeName(symbology)); | |
| 3868 } | |
| 3869 return NULL; | |
| 3870 } | |
| 3871 | |
| 3872 if (symbology == BARCODE_QRCODE || symbology == BARCODE_HIBC_QR || symbology == BARCODE_MICROQR | |
| 3873 || symbology == BARCODE_RMQR) { | |
| 3874 const int full_multibyte = (symbol->option_3 & 0xFF) == ZINT_FULL_MULTIBYTE; | |
| 3875 if (full_multibyte && testUtilHasNonASCII(source, length)) { /* TODO: Support in ZXing-C++ */ | |
| 3876 printf("i:%d %s not ZXing-C++ compatible, ZINT_FULL_MULTIBYTE not supported (with non-ASCII data)\n", | |
| 3877 index, testUtilBarcodeName(symbology)); | |
| 3878 return NULL; | |
| 3879 } | |
| 3880 } else if (symbology == BARCODE_CODABLOCKF || symbology == BARCODE_HIBC_BLOCKF) { | |
| 3881 if (symbol->rows == 1) { /* Single row i.e. CODE128 not supported */ | |
| 3882 if (debug & ZINT_DEBUG_TEST_PRINT) { | |
| 3883 printf("i:%d %s not ZXing-C++ compatible, single row not supported\n", | |
| 3884 index, testUtilBarcodeName(symbology)); | |
| 3885 } | |
| 3886 return NULL; | |
| 3887 } | |
| 3888 } else if ((ZBarcode_Cap(symbology, ZINT_CAP_EANUPC) & ZINT_CAP_EANUPC) == ZINT_CAP_EANUPC) { | |
| 3889 if (symbology == BARCODE_EANX || symbology == BARCODE_EANX_CHK) { | |
| 3890 if (length < 9) { | |
| 3891 if (length < 6) { | |
| 3892 printf("i:%d %s not ZXing-C++ compatible, EAN-5/EAN-2 not supported\n", | |
| 3893 index, testUtilBarcodeName(symbology)); | |
| 3894 return NULL; | |
| 3895 } | |
| 3896 return "EAN-8"; | |
| 3897 } | |
| 3898 if (strchr(source, '+') != NULL && length < 15) { | |
| 3899 return "EAN-8"; | |
| 3900 } | |
| 3901 } | |
| 3902 } | |
| 3903 | |
| 3904 return data[symbology].name; | |
| 3905 } | |
| 3906 | |
| 3907 /* Whether can use ZXing-C++ to check a symbology with given options */ | |
| 3908 int testUtilCanZXingCPP(int index, const struct zint_symbol *symbol, const char *source, const int length, | |
| 3909 const int debug) { | |
| 3910 return testUtilZXingCPPName(index, symbol, source, length, debug) != NULL; | |
| 3911 } | |
| 3912 | |
| 3913 /* Run "zxingcppdecoder", returning result in `buffer` */ | |
| 3914 int testUtilZXingCPP(int index, struct zint_symbol *symbol, const char *source, const int length, char *bits, | |
| 3915 char *buffer, const int buffer_size, int *p_cmp_len) { | |
| 3916 static const char cmd_fmt[] = "zxingcppdecoder -textonly -format %s -width %d -bits '%s'"; | |
| 3917 static const char opts_cmd_fmt[] = "zxingcppdecoder -textonly -format %s -opts '%s' -width %d -bits '%s'"; | |
| 3918 static const char cs_cmd_fmt[] = "zxingcppdecoder -textonly -format %s -charset %s -width %d -bits '%s'"; | |
| 3919 | |
| 3920 const int bits_len = (int) strlen(bits); | |
| 3921 const int width = symbol->width; | |
| 3922 const int symbology = symbol->symbology; | |
| 3923 char *cmd = (char *) z_alloca(bits_len + 1024); | |
| 3924 const char *zxingcpp_barcode = NULL; | |
| 3925 const int data_mode = (symbol->input_mode & 0x07) == DATA_MODE; | |
| 3926 int set_charset = 0; | |
| 3927 const char *opts = NULL; | |
| 3928 | |
| 3929 FILE *fp = NULL; | |
| 3930 int cnt; | |
| 3931 | |
| 3932 buffer[0] = '\0'; | |
| 3933 | |
| 3934 zxingcpp_barcode = testUtilZXingCPPName(index, symbol, source, length, 0 /*debug*/); | |
| 3935 if (!zxingcpp_barcode) { | |
| 3936 fprintf(stderr, "i:%d testUtilZXingCPP: no mapping for %s\n", index, testUtilBarcodeName(symbology)); | |
| 3937 return -1; | |
| 3938 } | |
| 3939 | |
| 3940 if (symbology == BARCODE_EXCODE39) { | |
| 3941 if (symbol->option_2 == 1) { | |
| 3942 opts = "tryCode39ExtendedMode,validateCode39CheckSum"; | |
| 3943 } else { | |
| 3944 opts = "tryCode39ExtendedMode"; | |
| 3945 } | |
| 3946 } else if ((symbology == BARCODE_CODE39 || symbology == BARCODE_LOGMARS) && symbol->option_2 == 1) { | |
| 3947 opts = "validateCode39CheckSum"; | |
| 3948 } | |
| 3949 | |
| 3950 if ((symbol->input_mode & 0x07) == UNICODE_MODE && symbol->eci == 0 | |
| 3951 && (symbology == BARCODE_QRCODE || symbology == BARCODE_MICROQR || symbology == BARCODE_HANXIN)) { | |
| 3952 int converted_len = length; | |
| 3953 unsigned char *converted_buf = (unsigned char *) z_alloca(converted_len + 1); | |
| 3954 if (symbology == BARCODE_HANXIN) { | |
| 3955 set_charset = utf8_to_eci(0, (const unsigned char *) source, converted_buf, &converted_len) != 0; | |
| 3956 } else { | |
| 3957 set_charset = utf8_to_eci(0, (const unsigned char *) source, converted_buf, &converted_len) == 0; | |
| 3958 } | |
| 3959 } | |
| 3960 if (set_charset) { | |
| 3961 const char *charset; | |
| 3962 if (symbology == BARCODE_HANXIN) { | |
| 3963 charset = "GB18030"; | |
| 3964 } else { | |
| 3965 charset = "ISO8859_1"; | |
| 3966 } | |
| 3967 sprintf(cmd, cs_cmd_fmt, zxingcpp_barcode, charset, width, bits); | |
| 3968 } else if (opts) { | |
| 3969 sprintf(cmd, opts_cmd_fmt, zxingcpp_barcode, opts, width, bits); | |
| 3970 } else { | |
| 3971 sprintf(cmd, cmd_fmt, zxingcpp_barcode, width, bits); | |
| 3972 } | |
| 3973 | |
| 3974 if (symbol->debug & ZINT_DEBUG_TEST_PRINT) { | |
| 3975 printf("i:%d testUtilZXingCPP: cmd %s\n", index, cmd); | |
| 3976 } | |
| 3977 | |
| 3978 fp = testutil_popen(cmd, "r"); | |
| 3979 if (!fp) { | |
| 3980 fprintf(stderr, "i:%d testUtilZXingCPP: failed to run '%s'\n", index, cmd); | |
| 3981 return -1; | |
| 3982 } | |
| 3983 | |
| 3984 cnt = (int) fread(buffer, 1, buffer_size, fp); | |
| 3985 if (cnt == buffer_size) { | |
| 3986 fprintf(stderr, "i:%d testUtilZXingCPP: buffer too small, %d bytes, cnt %d (%s)\n", | |
| 3987 index, buffer_size, cnt, cmd); | |
| 3988 testutil_pclose(fp); | |
| 3989 return -1; | |
| 3990 } | |
| 3991 | |
| 3992 if (fgetc(fp) != EOF) { | |
| 3993 fprintf(stderr, "i:%d testUtilZXingCPP: failed to read full stream (%s)\n", index, cmd); | |
| 3994 testutil_pclose(fp); | |
| 3995 return -1; | |
| 3996 } | |
| 3997 | |
| 3998 testutil_pclose(fp); | |
| 3999 | |
| 4000 if ((data_mode && is_eci_convertible(symbol->eci)) || symbol->eci >= 899) { | |
| 4001 const int eci = symbol->eci >= 899 ? 3 : symbol->eci; | |
| 4002 int error_number; | |
| 4003 const int eci_length = get_eci_length(eci, (const unsigned char *) buffer, cnt); | |
| 4004 unsigned char *preprocessed = (unsigned char *) z_alloca(eci_length + 1); | |
| 4005 | |
| 4006 if (eci_length >= buffer_size) { | |
| 4007 fprintf(stderr, "i:%d testUtilZXingCPP: buffer too small, %d bytes, eci_length %d (%s)\n", | |
| 4008 index, buffer_size, eci_length, cmd); | |
| 4009 return -1; | |
| 4010 } | |
| 4011 error_number = utf8_to_eci(eci, (const unsigned char *) buffer, preprocessed, &cnt); | |
| 4012 if (error_number == 0) { | |
| 4013 memcpy(buffer, preprocessed, cnt); | |
| 4014 } else { | |
| 4015 if (eci != 0 && symbol->eci < 899) { | |
| 4016 fprintf(stderr, "i:%d testUtilZXingCPP: utf8_to_eci(%d) == %d (%s)\n", index, eci, error_number, cmd); | |
| 4017 return -1; | |
| 4018 } else { | |
| 4019 int i; | |
| 4020 unsigned int *vals = (unsigned int *) z_alloca(sizeof(int) * (cnt + 1)); | |
| 4021 error_number = utf8_to_unicode(symbol, (const unsigned char *) buffer, vals, &cnt, 1); | |
| 4022 if (error_number != 0) { | |
| 4023 fprintf(stderr, "i:%d testUtilZXingCPP: utf8_to_unicode == %d (%s)\n", index, error_number, cmd); | |
| 4024 return -1; | |
| 4025 } | |
| 4026 for (i = 0; i < cnt; i++) { | |
| 4027 buffer[i] = (char) vals[i]; | |
| 4028 } | |
| 4029 buffer[cnt] = '\0'; | |
| 4030 } | |
| 4031 } | |
| 4032 } | |
| 4033 | |
| 4034 *p_cmp_len = cnt; | |
| 4035 | |
| 4036 return 0; | |
| 4037 } | |
| 4038 | |
| 4039 INTERNAL int escape_char_process_test(struct zint_symbol *symbol, const unsigned char *input_string, int *length, | |
| 4040 unsigned char *escaped_string); | |
| 4041 | |
| 4042 #include "../gs1.h" | |
| 4043 | |
| 4044 static const char TECHNETIUM[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%"; /* Same as SILVER (CODE39) */ | |
| 4045 | |
| 4046 /* Helper to strip leading zeroes (as long as have at least one non-zero digit) */ | |
| 4047 static const char *testUtilZXingCPPLeadingZeroes(const char *expected) { | |
| 4048 const char *stripped = expected; | |
| 4049 while (*stripped == '0') stripped++; | |
| 4050 return z_isdigit(*stripped) ? stripped : expected; | |
| 4051 } | |
| 4052 | |
| 4053 /* Helper to convert DX number from "NNNN"/"NNNNNN" format to "NNN-NN" format */ | |
| 4054 static int textUtilZXingCPPDX(const char *expected, const int expected_len, const char *cmp_buf, char *out) { | |
| 4055 if (strchr(cmp_buf, '-')) { | |
| 4056 const char *stripped; | |
| 4057 if (strchr(expected, '-') == NULL) { | |
| 4058 if (expected_len == 6) { | |
| 4059 const int dx = to_int((const unsigned char *) expected + 1, expected_len - 2); | |
| 4060 sprintf(out, "%d-%d", dx / 16, dx % 16); | |
| 4061 } else { | |
| 4062 const int dx = to_int((const unsigned char *) expected, expected_len); | |
| 4063 sprintf(out, "%d-%d", dx / 16, dx % 16); | |
| 4064 } | |
| 4065 return 1; | |
| 4066 } | |
| 4067 if ((stripped = testUtilZXingCPPLeadingZeroes(expected)) != expected) { | |
| 4068 memcpy(out, stripped, expected_len - (stripped - expected)); | |
| 4069 out[expected_len - (stripped - expected)] = '\0'; | |
| 4070 return 1; | |
| 4071 } | |
| 4072 } | |
| 4073 return 0; | |
| 4074 } | |
| 4075 | |
| 4076 /* Massage result from "zxingcppdecoder" so as can compare to Zint input */ | |
| 4077 int testUtilZXingCPPCmp(struct zint_symbol *symbol, char *msg, char *cmp_buf, int cmp_len, | |
| 4078 const char *expected, int expected_len, const char *primary, char *ret_buf, int *p_ret_len) { | |
| 4079 const int symbology = symbol->symbology; | |
| 4080 | |
| 4081 const int is_gs1_128_dbar_exp = symbology == BARCODE_GS1_128 || symbology == BARCODE_DBAR_EXP | |
| 4082 || symbology == BARCODE_DBAR_EXPSTK; | |
| 4083 const int gs1 = (symbol->input_mode & 0x07) == GS1_MODE || is_gs1_128_dbar_exp; | |
| 4084 const int is_extra_escaped = (symbol->input_mode & EXTRA_ESCAPE_MODE) && symbol->symbology == BARCODE_CODE128; | |
| 4085 const int is_escaped = (symbol->input_mode & ESCAPE_MODE) || is_extra_escaped; | |
| 4086 const int is_hibc = symbology >= BARCODE_HIBC_128 && symbology <= BARCODE_HIBC_AZTEC; | |
| 4087 const int have_c25checkdigit = symbol->option_2 == 1 || symbol->option_2 == 2; | |
| 4088 const int have_c25inter = (symbology == BARCODE_C25INTER && ((expected_len & 1) || have_c25checkdigit)) | |
| 4089 || symbology == BARCODE_ITF14 || symbology == BARCODE_DPLEIT | |
| 4090 || symbology == BARCODE_DPIDENT; | |
| 4091 const int is_upcean = (ZBarcode_Cap(symbology, ZINT_CAP_EANUPC) & ZINT_CAP_EANUPC) == ZINT_CAP_EANUPC; | |
| 4092 const int need_dpd_prefix = (symbology == BARCODE_DPD && expected_len == 27 && symbol->option_2 != 1); | |
| 4093 const int is_vin_international = symbology == BARCODE_VIN && (symbol->option_2 & 1); | |
| 4094 | |
| 4095 char *reduced = gs1 ? (char *) z_alloca(expected_len + 1) : NULL; | |
| 4096 char *escaped = is_escaped ? (char *) z_alloca(expected_len + 1) : NULL; | |
| 4097 char *hibc = is_hibc ? (char *) z_alloca(expected_len + 2 + 1) : NULL; | |
| 4098 char *maxi = symbology == BARCODE_MAXICODE && primary | |
| 4099 ? (char *) z_alloca(expected_len + strlen(primary) + 4 + 6 + 9 + 1) : NULL; | |
| 4100 char *vin = is_vin_international ? (char *) z_alloca(expected_len + 1 + 1) : NULL; | |
| 4101 char *c25inter = have_c25inter ? (char *) z_alloca(expected_len + 13 + 1 + 1) : NULL; | |
| 4102 char *upcean = is_upcean ? (char *) z_alloca(expected_len + 1 + 1) : NULL; | |
| 4103 char *ean14_nve18 = symbology == BARCODE_EAN14 || symbology == BARCODE_NVE18 | |
| 4104 ? (char *) z_alloca(expected_len + 3 + 19 + 1) : NULL; | |
| 4105 char *dpd = need_dpd_prefix ? (char *) z_alloca(28 + 1) : NULL; | |
| 4106 char *pzn = symbology == BARCODE_PZN ? (char *) z_alloca(expected_len + 1 + 1) : NULL; | |
| 4107 char *dxfe = symbology == BARCODE_DXFILMEDGE ? (char *) z_alloca(expected_len * 2 + 1) : NULL; | |
| 4108 | |
| 4109 int ret; | |
| 4110 int ret_memcmp; | |
| 4111 int i; | |
| 4112 | |
| 4113 if (ret_buf) { | |
| 4114 ret_buf[0] = '\0'; | |
| 4115 } | |
| 4116 if (p_ret_len) { | |
| 4117 *p_ret_len = 0; | |
| 4118 } | |
| 4119 | |
| 4120 if (is_escaped) { | |
| 4121 ret = escape_char_process_test(symbol, (unsigned char *) expected, &expected_len, | |
| 4122 (unsigned char *) escaped); | |
| 4123 if (ret != 0) { | |
| 4124 sprintf(msg, "escape_char_process %d != 0", ret); | |
| 4125 return 3; | |
| 4126 } | |
| 4127 if (is_extra_escaped) { | |
| 4128 /* Remove any Code 128 special escapes */ | |
| 4129 int j = 0; | |
| 4130 int have_manual_ab = 0; | |
| 4131 for (i = 0; i < expected_len; i++) { | |
| 4132 if (escaped[i] == '\\' && i + 2 < expected_len && escaped[i + 1] == '^' | |
| 4133 && ((escaped[i + 2] >= '@' && escaped[i + 2] <= 'C') || escaped[i + 2] == '1' | |
| 4134 || escaped[i + 2] == '^')) { | |
| 4135 if (escaped[i + 2] != '^') { | |
| 4136 i += 2; | |
| 4137 if (escaped[i] == 'A' || escaped[i] == 'B') { | |
| 4138 have_manual_ab = 1; /* Hack to help guess if in Code Set C for AIM exception below */ | |
| 4139 } else if (escaped[i] == '1') { | |
| 4140 /* FNC1 in 1st position treated as GS1 and in 2nd position AIM, neither transmitted - | |
| 4141 need to skip AIM (single alphabetic or Code Set C double digit) | |
| 4142 TODO: guessing about whether in Code Set C for double digit */ | |
| 4143 if (j > 2 || (j == 1 && !(z_isupper(escaped[0]) || z_islower(escaped[0]))) | |
| 4144 || (j == 2 && !(z_isdigit(escaped[0]) && z_isdigit(escaped[1]) | |
| 4145 && !have_manual_ab))) { | |
| 4146 /* Probably not AIM */ | |
| 4147 escaped[j++] = 29; /* GS */ | |
| 4148 } | |
| 4149 } | |
| 4150 } else { | |
| 4151 escaped[j++] = escaped[i++]; | |
| 4152 escaped[j++] = escaped[i++]; | |
| 4153 } | |
| 4154 } else { | |
| 4155 escaped[j++] = escaped[i]; | |
| 4156 } | |
| 4157 } | |
| 4158 expected_len = j; | |
| 4159 escaped[expected_len] = '\0'; | |
| 4160 } | |
| 4161 expected = escaped; | |
| 4162 } | |
| 4163 if (gs1 && symbology != BARCODE_EAN14 && symbology != BARCODE_NVE18) { | |
| 4164 ret = gs1_verify(symbol, (const unsigned char *) expected, expected_len, (unsigned char *) reduced); | |
| 4165 if (ret >= ZINT_ERROR) { | |
| 4166 sprintf(msg, "gs1_verify %d != 0", ret); | |
| 4167 return 4; | |
| 4168 } | |
| 4169 expected_len = (int) strlen(reduced); | |
| 4170 expected = reduced; | |
| 4171 if (primary) { | |
| 4172 /* TODO: */ | |
| 4173 } | |
| 4174 } else if (is_hibc) { | |
| 4175 int counter; | |
| 4176 int posns[110]; | |
| 4177 hibc[0] = '+'; | |
| 4178 memcpy(hibc + 1, expected, expected_len); | |
| 4179 to_upper((unsigned char *) (hibc + 1), expected_len); | |
| 4180 if (not_sane_lookup(TECHNETIUM, sizeof(TECHNETIUM) - 1, (unsigned char *) (hibc + 1), expected_len, posns)) { | |
| 4181 sprintf(msg, "HIBC not_sane_lookup(TECHNETIUM) failed"); | |
| 4182 return 5; | |
| 4183 } | |
| 4184 counter = 41; | |
| 4185 for (i = 0; i < expected_len && i < 110; i++) { | |
| 4186 counter += posns[i]; | |
| 4187 } | |
| 4188 counter = counter % 43; | |
| 4189 hibc[++expected_len] = TECHNETIUM[counter]; | |
| 4190 hibc[++expected_len] = '\0'; | |
| 4191 expected = hibc; | |
| 4192 } | |
| 4193 if (symbology == BARCODE_MAXICODE) { | |
| 4194 if (primary && primary[0]) { | |
| 4195 int primary_len = (int) strlen(primary); | |
| 4196 int maxi_len = 0; | |
| 4197 int have_manual_scm = 0; | |
| 4198 if (symbol->option_2 >= 1 && symbol->option_2 <= 100) { | |
| 4199 /* Suppress gcc warning null destination pointer [-Wformat-overflow=] false-positive */ | |
| 4200 #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 7 | |
| 4201 #pragma GCC diagnostic push | |
| 4202 #pragma GCC diagnostic ignored "-Wformat-overflow=" | |
| 4203 #endif | |
| 4204 sprintf(maxi, "[)>\03601\035%02d", symbol->option_2 - 1); | |
| 4205 #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 7 | |
| 4206 #pragma GCC diagnostic pop | |
| 4207 #endif | |
| 4208 maxi_len = (int) strlen(maxi); | |
| 4209 } else if (expected_len >= 9 && strncmp(expected, "[)>\03601\035", 7) == 0 | |
| 4210 && z_isdigit(expected[7]) && z_isdigit(expected[8])) { | |
| 4211 have_manual_scm = 1; | |
| 4212 } | |
| 4213 if (primary[0] > '9') { | |
| 4214 sprintf(maxi + maxi_len, "%-6.*s\035%.*s\035%.*s\035", primary_len - 6, primary, | |
| 4215 3, primary + primary_len - 6, 3, primary + primary_len - 3); | |
| 4216 } else { | |
| 4217 if (primary_len == 11 && primary[5] == '8' && primary[6] == '4' && primary[7] == '0') { | |
| 4218 sprintf(maxi + maxi_len, "%.*s0000\035%.*s\035%.*s\035", primary_len - 6, primary, | |
| 4219 3, primary + primary_len - 6, 3, primary + primary_len - 3); | |
| 4220 } else { | |
| 4221 sprintf(maxi + maxi_len, "%.*s\035%.*s\035%.*s\035", primary_len - 6, primary, | |
| 4222 3, primary + primary_len - 6, 3, primary + primary_len - 3); | |
| 4223 } | |
| 4224 } | |
| 4225 maxi_len = (int) strlen(maxi); | |
| 4226 if (have_manual_scm) { | |
| 4227 memmove(maxi + 9, maxi, maxi_len); | |
| 4228 memcpy(maxi, expected, 9); | |
| 4229 memcpy(maxi + maxi_len + 9, expected + 9, expected_len - 9); | |
| 4230 } else { | |
| 4231 memcpy(maxi + maxi_len, expected, expected_len); | |
| 4232 } | |
| 4233 expected = maxi; | |
| 4234 expected_len += maxi_len; | |
| 4235 maxi[expected_len] = '\0'; | |
| 4236 } | |
| 4237 } else if (symbology == BARCODE_CODABAR) { | |
| 4238 /* Ignore start A/B/C/D and stop A/B/C/D chars to avoid upper/lowercase issues */ | |
| 4239 cmp_buf++; | |
| 4240 cmp_len -= 2; | |
| 4241 expected++; | |
| 4242 expected_len -= 2; | |
| 4243 if (symbol->option_2 == 1 || symbol->option_2 == 2) { | |
| 4244 cmp_len--; /* Too messy to calc the check digit so ignore */ | |
| 4245 } | |
| 4246 } else if (is_vin_international) { | |
| 4247 vin[0] = 'I'; | |
| 4248 memcpy(vin + 1, expected, expected_len); | |
| 4249 vin[++expected_len] = '\0'; | |
| 4250 expected = vin; | |
| 4251 } else if (have_c25inter) { | |
| 4252 if (symbology == BARCODE_C25INTER) { | |
| 4253 if ((expected_len & 1) || have_c25checkdigit) { | |
| 4254 if (((expected_len & 1) && !have_c25checkdigit) || (!(expected_len & 1) && have_c25checkdigit)) { | |
| 4255 c25inter[0] = '0'; | |
| 4256 memcpy(c25inter + 1, expected, expected_len); | |
| 4257 expected_len++; | |
| 4258 } else { | |
| 4259 memcpy(c25inter, expected, expected_len); | |
| 4260 } | |
| 4261 if (have_c25checkdigit) { | |
| 4262 c25inter[expected_len] = gs1_check_digit((const unsigned char *) c25inter, expected_len); | |
| 4263 expected_len++; | |
| 4264 } | |
| 4265 c25inter[expected_len] = '\0'; | |
| 4266 expected = c25inter; | |
| 4267 } | |
| 4268 } else if (symbology == BARCODE_DPLEIT || symbology == BARCODE_DPIDENT) { | |
| 4269 const int len = symbology == BARCODE_DPLEIT ? 13 : 11; | |
| 4270 int zeroes = len - expected_len; | |
| 4271 unsigned int count = 0; | |
| 4272 int factor = 4; | |
| 4273 for (i = 0; i < zeroes; i++) { | |
| 4274 c25inter[i] = '0'; | |
| 4275 } | |
| 4276 memcpy(c25inter + zeroes, expected, expected_len); | |
| 4277 expected_len += zeroes; | |
| 4278 for (i = len - 1; i >= 0; i--) { | |
| 4279 count += factor * ctoi(c25inter[i]); | |
| 4280 factor ^= 0x0D; /* Toggles 4 and 9 */ | |
| 4281 } | |
| 4282 c25inter[expected_len] = itoc((10 - (count % 10)) % 10); | |
| 4283 c25inter[++expected_len] = '\0'; | |
| 4284 expected = c25inter; | |
| 4285 } else if (symbology == BARCODE_ITF14) { | |
| 4286 int zeroes = 13 - expected_len; | |
| 4287 for (i = 0; i < zeroes; i++) { | |
| 4288 c25inter[i] = '0'; | |
| 4289 } | |
| 4290 memcpy(c25inter + zeroes, expected, expected_len); | |
| 4291 expected_len += zeroes; | |
| 4292 c25inter[expected_len] = gs1_check_digit((const unsigned char *) c25inter, 13); | |
| 4293 c25inter[++expected_len] = '\0'; | |
| 4294 expected = c25inter; | |
| 4295 } | |
| 4296 } else if (symbology == BARCODE_DBAR_OMN || symbology == BARCODE_DBAR_LTD || symbology == BARCODE_DBAR_OMNSTK | |
| 4297 || symbology == BARCODE_DBAR_STK) { | |
| 4298 if (expected_len == 13) { | |
| 4299 cmp_len--; /* Too messy to calc the check digit so ignore */ | |
| 4300 } | |
| 4301 if (symbology == BARCODE_DBAR_LTD) { | |
| 4302 cmp_buf += 2; /* Ignore prefixed "01" */ | |
| 4303 cmp_len -= 2; | |
| 4304 } | |
| 4305 } else if (is_upcean) { | |
| 4306 if (symbology == BARCODE_UPCA && (expected_len == 11 || expected_len == 14 || expected_len == 17)) { | |
| 4307 memcpy(upcean, expected, 11); | |
| 4308 upcean[11] = gs1_check_digit((const unsigned char *) upcean, 11); | |
| 4309 if (expected_len == 14) { | |
| 4310 upcean[12] = ' '; | |
| 4311 memcpy(upcean + 13, expected + 12, 2); | |
| 4312 } else if (expected_len == 17) { | |
| 4313 upcean[12] = ' '; | |
| 4314 memcpy(upcean + 13, expected + 12, 5); | |
| 4315 } | |
| 4316 expected_len++; | |
| 4317 upcean[expected_len] = '\0'; | |
| 4318 expected = upcean; | |
| 4319 } else if (symbology == BARCODE_UPCA_CHK && (expected_len == 15 || expected_len == 18)) { | |
| 4320 memcpy(upcean, expected, expected_len); | |
| 4321 upcean[12] = ' '; | |
| 4322 expected = upcean; | |
| 4323 } else if (symbology == BARCODE_UPCE && (expected_len == 7 || expected_len == 10 || expected_len == 13)) { | |
| 4324 char equivalent[11]; | |
| 4325 memcpy(upcean, expected, 7); | |
| 4326 memcpy(equivalent, upcean, 3); | |
| 4327 memset(equivalent + 3, '0', 8); | |
| 4328 switch (upcean[6]) { | |
| 4329 case '0': case '1': case '2': | |
| 4330 equivalent[3] = upcean[6]; | |
| 4331 equivalent[8] = upcean[3]; | |
| 4332 equivalent[9] = upcean[4]; | |
| 4333 equivalent[10] = upcean[5]; | |
| 4334 break; | |
| 4335 case '3': | |
| 4336 equivalent[3] = upcean[3]; | |
| 4337 equivalent[9] = upcean[4]; | |
| 4338 equivalent[10] = upcean[5]; | |
| 4339 break; | |
| 4340 case '4': | |
| 4341 equivalent[3] = upcean[3]; | |
| 4342 equivalent[4] = upcean[4]; | |
| 4343 equivalent[10] = upcean[5]; | |
| 4344 break; | |
| 4345 case '5': case '6': case '7': case '8': case '9': | |
| 4346 equivalent[3] = upcean[3]; | |
| 4347 equivalent[4] = upcean[4]; | |
| 4348 equivalent[5] = upcean[5]; | |
| 4349 equivalent[10] = upcean[6]; | |
| 4350 break; | |
| 4351 } | |
| 4352 upcean[7] = gs1_check_digit((const unsigned char *) equivalent, 11); | |
| 4353 if (expected_len == 10) { | |
| 4354 upcean[8] = ' '; | |
| 4355 memcpy(upcean + 9, expected + 8, 2); | |
| 4356 } else if (expected_len == 13) { | |
| 4357 upcean[8] = ' '; | |
| 4358 memcpy(upcean + 9, expected + 8, 5); | |
| 4359 } | |
| 4360 expected_len++; | |
| 4361 upcean[expected_len] = '\0'; | |
| 4362 expected = upcean; | |
| 4363 } else if (symbology == BARCODE_UPCE_CHK && (expected_len == 11 || expected_len == 14)) { | |
| 4364 memcpy(upcean, expected, expected_len); | |
| 4365 upcean[8] = ' '; | |
| 4366 expected = upcean; | |
| 4367 } else if (symbology == BARCODE_EANX && (expected_len == 12 || expected_len == 15 || expected_len == 18)) { | |
| 4368 memcpy(upcean, expected, 12); | |
| 4369 upcean[12] = gs1_check_digit((const unsigned char *) upcean, 12); | |
| 4370 if (expected_len == 15) { | |
| 4371 upcean[13] = ' '; | |
| 4372 memcpy(upcean + 14, expected + 13, 2); | |
| 4373 } else if (expected_len == 18) { | |
| 4374 upcean[13] = ' '; | |
| 4375 memcpy(upcean + 14, expected + 13, 5); | |
| 4376 } | |
| 4377 expected_len++; | |
| 4378 upcean[expected_len] = '\0'; | |
| 4379 expected = upcean; | |
| 4380 } else if (symbology == BARCODE_EANX && (expected_len == 16 || expected_len == 19)) { | |
| 4381 memcpy(upcean, expected, expected_len); | |
| 4382 upcean[13] = ' '; | |
| 4383 expected = upcean; | |
| 4384 } else if (symbology == BARCODE_EANX && (expected_len == 7 | |
| 4385 || (strchr(expected, '+') != NULL && (expected_len == 10 || expected_len == 13)))) { | |
| 4386 memcpy(upcean, expected, 7); | |
| 4387 upcean[7] = gs1_check_digit((const unsigned char *) upcean, 7); | |
| 4388 if (expected_len == 10) { | |
| 4389 upcean[8] = ' '; | |
| 4390 memcpy(upcean + 9, expected + 8, 2); | |
| 4391 } else if (expected_len == 13) { | |
| 4392 upcean[8] = ' '; | |
| 4393 memcpy(upcean + 9, expected + 8, 5); | |
| 4394 } | |
| 4395 expected_len++; | |
| 4396 upcean[expected_len] = '\0'; | |
| 4397 expected = upcean; | |
| 4398 } else if ((symbology == BARCODE_EANX_CHK || symbology == BARCODE_ISBNX) | |
| 4399 && (expected_len == 16 || expected_len == 19)) { | |
| 4400 memcpy(upcean, expected, expected_len); | |
| 4401 upcean[13] = ' '; | |
| 4402 expected = upcean; | |
| 4403 } else if (symbology == BARCODE_EANX_CHK && strchr(expected, '+') != NULL | |
| 4404 && (expected_len == 11 || expected_len == 14)) { | |
| 4405 memcpy(upcean, expected, expected_len); | |
| 4406 upcean[8] = ' '; | |
| 4407 expected = upcean; | |
| 4408 } | |
| 4409 | |
| 4410 } else if (symbology == BARCODE_EAN14 || symbology == BARCODE_NVE18) { | |
| 4411 int len = symbology == BARCODE_NVE18 ? 17 : 13; | |
| 4412 int zeroes = expected_len < len ? len - expected_len: 0; | |
| 4413 ean14_nve18[0] = '0'; | |
| 4414 ean14_nve18[1] = symbology == BARCODE_NVE18 ? '0' : '1'; | |
| 4415 memset(ean14_nve18 + 2, '0', zeroes); | |
| 4416 memcpy(ean14_nve18 + 2 + zeroes, expected, expected_len); | |
| 4417 ean14_nve18[len + 2] = gs1_check_digit((unsigned char *) (ean14_nve18 + 2), len); | |
| 4418 expected = ean14_nve18; | |
| 4419 expected_len += zeroes + 3; | |
| 4420 | |
| 4421 } else if (need_dpd_prefix) { | |
| 4422 dpd[0] = '%'; | |
| 4423 memcpy(dpd + 1, expected, expected_len); | |
| 4424 expected = dpd; | |
| 4425 expected_len++; | |
| 4426 | |
| 4427 } else if (symbology == BARCODE_PZN) { | |
| 4428 /* Add hyphen at start */ | |
| 4429 pzn[0] = '-'; | |
| 4430 memcpy(pzn + 1, expected, expected_len); | |
| 4431 if ((symbol->option_2 == 0 && expected_len != 8) || (symbol->option_2 == 1 && expected_len != 7)) { | |
| 4432 cmp_len--; /* Don't bother with check digit */ | |
| 4433 } | |
| 4434 expected = pzn; | |
| 4435 expected_len++; | |
| 4436 | |
| 4437 } else if (symbology == BARCODE_DXFILMEDGE) { | |
| 4438 const int dx_info_len = posn(expected, '/'); | |
| 4439 if (dx_info_len != -1) { | |
| 4440 char frame_info[20]; | |
| 4441 assert(strlen(expected + dx_info_len + 1) < sizeof(frame_info)); | |
| 4442 strcpy(frame_info, expected + dx_info_len + 1); | |
| 4443 to_upper((unsigned char *) frame_info, (int) strlen(frame_info)); | |
| 4444 if (!textUtilZXingCPPDX(expected, dx_info_len, cmp_buf, dxfe)) { | |
| 4445 memcpy(dxfe, expected, dx_info_len); | |
| 4446 dxfe[dx_info_len] = '\0'; | |
| 4447 } | |
| 4448 if (strcmp(frame_info, "S") == 0 || strcmp(frame_info, "X") == 0) { | |
| 4449 strcat(dxfe, "/62"); | |
| 4450 } else if (strcmp(frame_info, "SA") == 0 || strcmp(frame_info, "XA") == 0) { | |
| 4451 strcat(dxfe, "/62A"); | |
| 4452 } else if (strcmp(frame_info, "K") == 0 || strcmp(frame_info, "00") == 0) { | |
| 4453 strcat(dxfe, "/63"); | |
| 4454 } else if (strcmp(frame_info, "KA") == 0 || strcmp(frame_info, "00A") == 0) { | |
| 4455 strcat(dxfe, "/63A"); | |
| 4456 } else if (strcmp(frame_info, "F") == 0) { | |
| 4457 strcat(dxfe, "/0"); | |
| 4458 } else if (strcmp(frame_info, "FA") == 0) { | |
| 4459 strcat(dxfe, "/0A"); | |
| 4460 } else { | |
| 4461 const char *stripped; | |
| 4462 if ((stripped = testUtilZXingCPPLeadingZeroes(frame_info)) != frame_info) { | |
| 4463 strcat(dxfe, "/"); | |
| 4464 strcat(dxfe, stripped); | |
| 4465 } else { | |
| 4466 strcat(dxfe, expected + dx_info_len); | |
| 4467 } | |
| 4468 } | |
| 4469 expected = dxfe; | |
| 4470 expected_len = (int) strlen(expected); | |
| 4471 to_upper((unsigned char *) expected, expected_len); | |
| 4472 } else { | |
| 4473 if (textUtilZXingCPPDX(expected, expected_len, cmp_buf, dxfe)) { | |
| 4474 expected = dxfe; | |
| 4475 expected_len = (int) strlen(expected); | |
| 4476 } | |
| 4477 } | |
| 4478 } | |
| 4479 | |
| 4480 if (ret_buf) { | |
| 4481 memcpy(ret_buf, expected, expected_len); | |
| 4482 } | |
| 4483 if (p_ret_len) { | |
| 4484 *p_ret_len = expected_len; | |
| 4485 } | |
| 4486 | |
| 4487 if (cmp_len != expected_len) { | |
| 4488 sprintf(msg, "cmp_len %d != expected_len %d", cmp_len, expected_len); | |
| 4489 return 2; | |
| 4490 } | |
| 4491 ret_memcmp = memcmp(cmp_buf, expected, expected_len); | |
| 4492 if (ret_memcmp != 0) { | |
| 4493 for (i = 0; i < expected_len; i++) { | |
| 4494 if (cmp_buf[i] != expected[i]) { | |
| 4495 break; | |
| 4496 } | |
| 4497 } | |
| 4498 sprintf(msg, "memcmp %d != 0, at %d, len %d", ret_memcmp, i, expected_len); | |
| 4499 return ret_memcmp; | |
| 4500 } | |
| 4501 | |
| 4502 return 0; | |
| 4503 } | |
| 4504 | |
| 4505 int testUtilZXingCPPCmpSegs(struct zint_symbol *symbol, char *msg, char *cmp_buf, int cmp_len, | |
| 4506 const struct zint_seg segs[], const int seg_count, const char *primary, char *ret_buf, int *p_ret_len) { | |
| 4507 int expected_len = segs_length(segs, seg_count); | |
| 4508 char *expected = (char *) z_alloca(expected_len + 1); | |
| 4509 char *s = expected; | |
| 4510 int i; | |
| 4511 | |
| 4512 for (i = 0; i < seg_count; i++) { | |
| 4513 int len = segs[i].length == -1 ? (int) ustrlen(segs[i].source) : segs[i].length; | |
| 4514 memcpy(s, segs[i].source, len); | |
| 4515 s += len; | |
| 4516 } | |
| 4517 *s = '\0'; | |
| 4518 | |
| 4519 return testUtilZXingCPPCmp(symbol, msg, cmp_buf, cmp_len, expected, expected_len, primary, ret_buf, p_ret_len); | |
| 4520 } | |
| 4521 | |
| 4522 /* vim: set ts=4 sw=4 et : */ |
