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 : */