1 /*
2 libzint - the open source barcode library
3 Copyright (C) 2019 - 2021 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 /* vim: set ts=4 sw=4 et : */
31 /*
32 * Adapted from qrencode/tests/common.c
33 * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org>
34 */
35
36 #include "testcommon.h"
37
38 #ifdef _MSC_VER
39 #include <malloc.h>
40 #define testutil_alloca(nmemb) _alloca(nmemb)
41 #else
42 #define testutil_alloca(nmemb) alloca(nmemb)
43 #endif
44
45 #ifdef _WIN32
46 #include <windows.h>
47 #include <direct.h>
48 #endif
49
50 #include "../eci.h"
51 #ifndef NO_PNG
52 #include <png.h>
53 #include <zlib.h>
54 #include <setjmp.h>
55 #endif
56 #include <assert.h>
57 #include <errno.h>
58 #include <getopt.h>
59 #include <limits.h>
60 #include <sys/stat.h>
61
62 static int tests = 0;
63 static int failed = 0;
64 static int skipped = 0;
65 int assertionFailed = 0;
66 int assertionNum = 0;
67 const char *assertionFilename = "";
68 static const char *testName = NULL;
69 static const char *testFunc = NULL;
70
71 /* Visual C++ 6 doesn't support variadic args to macros, so make do with functions, which have inferior behaviour,
72 e.g. don't exit on failure, `assert_equal()` type-specific */
73 #if _MSC_VER == 1200 /* VC6 */
74 #include <stdarg.h>
assert_zero(int exp,const char * fmt,...)75 void assert_zero(int exp, const char *fmt, ...) {
76 assertionNum++;
77 if (exp != 0) {
78 va_list args; assertionFailed++; va_start(args, fmt); vprintf(fmt, args); va_end(args); testFinish();
79 }
80 }
assert_nonzero(int exp,const char * fmt,...)81 void assert_nonzero(int exp, const char *fmt, ...) {
82 assertionNum++;
83 if (exp == 0) {
84 va_list args; assertionFailed++; va_start(args, fmt); vprintf(fmt, args); va_end(args); testFinish();
85 }
86 }
assert_null(void * exp,const char * fmt,...)87 void assert_null(void *exp, const char *fmt, ...) {
88 assertionNum++;
89 if (exp != NULL) {
90 va_list args; assertionFailed++; va_start(args, fmt); vprintf(fmt, args); va_end(args); testFinish();
91 }
92 }
assert_nonnull(void * exp,const char * fmt,...)93 void assert_nonnull(void *exp, const char *fmt, ...) {
94 assertionNum++;
95 if (exp == NULL) {
96 va_list args; assertionFailed++; va_start(args, fmt); vprintf(fmt, args); va_end(args); testFinish();
97 }
98 }
assert_equal(int e1,int e2,const char * fmt,...)99 void assert_equal(int e1, int e2, const char *fmt, ...) {
100 assertionNum++;
101 if (e1 != e2) {
102 va_list args; assertionFailed++; va_start(args, fmt); vprintf(fmt, args); va_end(args); testFinish();
103 }
104 }
assert_equalu64(uint64_t e1,uint64_t e2,const char * fmt,...)105 void assert_equalu64(uint64_t e1, uint64_t e2, const char *fmt, ...) {
106 assertionNum++;
107 if (e1 != e2) {
108 va_list args; assertionFailed++; va_start(args, fmt); vprintf(fmt, args); va_end(args); testFinish();
109 }
110 }
assert_notequal(int e1,int e2,const char * fmt,...)111 void assert_notequal(int e1, int e2, const char *fmt, ...) {
112 assertionNum++;
113 if (e1 == e2) {
114 va_list args; assertionFailed++; va_start(args, fmt); vprintf(fmt, args); va_end(args); testFinish();
115 }
116 }
117 #endif
118
119 /* Begin individual test function */
testStartReal(const char * func,const char * name)120 void testStartReal(const char *func, const char *name) {
121 tests++;
122 if (func && *func && name && *name && strcmp(func, name) == 0) {
123 testName = "";
124 } else {
125 testName = name;
126 }
127 testFunc = func ? func : "";
128 assertionFailed = 0;
129 assertionNum = 0;
130 printf("_____%d: %s: %s...\n", tests, testFunc, testName ? testName : "");
131 }
132
133 /* End individual test function */
testFinish(void)134 void testFinish(void) {
135 if (testName && *testName) {
136 printf(".....%d: %s: %s ", tests, testFunc, testName);
137 } else {
138 printf(".....%d: %s: ", tests, testFunc);
139 }
140 if (assertionFailed) {
141 printf("FAILED. (%d assertions failed.)\n", assertionFailed);
142 failed++;
143 } else {
144 printf("PASSED. (%d assertions passed.)\n", assertionNum);
145 }
146 }
147
148 /* Skip (and end) individual test function */
testSkip(const char * msg)149 void testSkip(const char *msg) {
150 skipped++;
151 if (testName && *testName) {
152 printf(".....%d: %s: %s ", tests, testFunc, testName);
153 } else {
154 printf(".....%d: %s: ", tests, testFunc);
155 }
156 if (assertionFailed) {
157 printf("FAILED. (%d assertions failed.)\n", assertionFailed);
158 failed++;
159 } else {
160 printf("SKIPPED. %s. (%d assertions passed.)\n", msg, assertionNum);
161 }
162 }
163
164 /* End test program */
testReport()165 void testReport() {
166 if (failed && skipped) {
167 printf("Total %d tests, %d skipped, %d fails.\n", tests, skipped, failed);
168 exit(-1);
169 }
170 if (failed) {
171 printf("Total %d tests, %d fails.\n", tests, failed);
172 exit(-1);
173 }
174 if (skipped) {
175 printf("Total %d tests, %d skipped.\n", tests, skipped);
176 } else if (tests) {
177 printf("Total %d tests, all passed.\n", tests);
178 } else {
179 printf("Total %d tests.\n", tests);
180 }
181 }
182
183 /* Begin test program, parse args */
testRun(int argc,char * argv[],testFunction funcs[],int funcs_size)184 void testRun(int argc, char *argv[], testFunction funcs[], int funcs_size) {
185 int i, opt, ran;
186 long long_opt;
187 char *optarg_endptr = NULL;
188 int debug = 0;
189 char *func = NULL;
190 char func_buf[256 + 5];
191 int index = -1;
192 int generate = 0;
193
194 typedef void (*func_void)(void);
195 typedef void (*func_debug)(int debug);
196 typedef void (*func_index)(int index);
197 typedef void (*func_index_debug)(int index, int debug);
198 typedef void (*func_generate)(int generate);
199 typedef void (*func_generate_debug)(int generate, int debug);
200 typedef void (*func_index_generate)(int index, int generate);
201 typedef void (*func_index_generate_debug)(int index, int generate, int debug);
202
203 if (argc) {
204 char *filename = strrchr(argv[0], '/');
205 #ifdef _WIN32
206 if (filename == NULL) {
207 filename = strrchr(argv[0], '\\');
208 }
209 #endif
210 if (filename) {
211 assertionFilename = filename + 1;
212 } else {
213 assertionFilename = argv[0];
214 }
215 }
216
217 while ((opt = getopt(argc, argv, "d:f:gi:")) != -1) {
218 switch (opt) {
219 case 'd':
220 errno = 0;
221 long_opt = strtol(optarg, &optarg_endptr, 10);
222 if (errno || optarg_endptr == optarg || long_opt < 0 || long_opt > INT_MAX) {
223 fprintf(stderr, "testRun: -d debug value invalid\n");
224 debug = 0;
225 } else {
226 debug = long_opt;
227 }
228 break;
229 case 'f':
230 if (strlen(optarg) < 256) {
231 if (strncmp(optarg, "test_", 5) == 0) {
232 strcpy(func_buf, optarg);
233 } else {
234 strcpy(func_buf, "test_");
235 strcat(func_buf, optarg);
236 }
237 func = func_buf;
238 } else {
239 fprintf(stderr, "testRun: -f func value too long\n");
240 func = NULL;
241 }
242 break;
243 case 'g':
244 generate = 1;
245 break;
246 case 'i':
247 errno = 0;
248 long_opt = strtol(optarg, &optarg_endptr, 10);
249 if (errno || optarg_endptr == optarg || long_opt < 0 || long_opt > INT_MAX) {
250 fprintf(stderr, "testRun: -i index value invalid\n");
251 index = -1;
252 } else {
253 index = long_opt;
254 }
255 break;
256 }
257 }
258
259 ran = 0;
260 for (i = 0; i < funcs_size; i++) {
261 if (func && strcmp(func, funcs[i].name) != 0) {
262 continue;
263 }
264 if (funcs[i].has_index && funcs[i].has_generate && funcs[i].has_debug) {
265 (*(func_index_generate_debug)funcs[i].func)(index, generate, debug);
266 } else if (funcs[i].has_index && funcs[i].has_generate) {
267 if (debug) fprintf(stderr, "testRun %s: -d ignored\n", funcs[i].name);
268 (*(func_index_generate)funcs[i].func)(index, generate);
269 } else if (funcs[i].has_index && funcs[i].has_debug) {
270 if (generate) fprintf(stderr, "testRun %s: -g ignored\n", funcs[i].name);
271 (*(func_index_debug)funcs[i].func)(index, debug);
272 } else if (funcs[i].has_index) {
273 if (generate) fprintf(stderr, "testRun %s: -g ignored\n", funcs[i].name);
274 if (debug) fprintf(stderr, "testRun %s: -d ignored\n", funcs[i].name);
275 (*(func_index)funcs[i].func)(index);
276 } else if (funcs[i].has_generate && funcs[i].has_debug) {
277 if (index != -1) fprintf(stderr, "testRun %s: -i index ignored\n", funcs[i].name);
278 (*(func_generate_debug)funcs[i].func)(generate, debug);
279 } else if (funcs[i].has_generate) {
280 if (index != -1) fprintf(stderr, "testRun %s: -i index ignored\n", funcs[i].name);
281 if (debug) fprintf(stderr, "testRun %s: -d ignored\n", funcs[i].name);
282 (*(func_generate)funcs[i].func)(generate);
283 } else if (funcs[i].has_debug) {
284 if (index != -1) fprintf(stderr, "testRun %s: -i index ignored\n", funcs[i].name);
285 if (generate) fprintf(stderr, "testRun %s -g ignored\n", funcs[i].name);
286 (*(func_debug)funcs[i].func)(debug);
287 } else {
288 if (index != -1) fprintf(stderr, "testRun %s: -i index ignored\n", funcs[i].name);
289 if (generate) fprintf(stderr, "testRun %s -g ignored\n", funcs[i].name);
290 if (debug) fprintf(stderr, "testRun %s: -d ignored\n", funcs[i].name);
291 (*(func_void)funcs[i].func)();
292 }
293 ran++;
294 }
295
296 if (func && !ran) {
297 fprintf(stderr, "testRun: unknown -f func arg '%s'\n", func);
298 }
299 }
300
301 /* Helper to set common symbol fields */
testUtilSetSymbol(struct zint_symbol * symbol,int symbology,int input_mode,int eci,int option_1,int option_2,int option_3,int output_options,char * data,int length,int debug)302 int testUtilSetSymbol(struct zint_symbol *symbol, int symbology, int input_mode, int eci, int option_1, int option_2,
303 int option_3, int output_options, char *data, int length, int debug) {
304 symbol->symbology = symbology;
305 if (input_mode != -1) {
306 symbol->input_mode = input_mode;
307 }
308 if (eci != -1) {
309 symbol->eci = eci;
310 }
311 if (option_1 != -1) {
312 symbol->option_1 = option_1;
313 }
314 if (option_2 != -1) {
315 symbol->option_2 = option_2;
316 }
317 if (option_3 != -1) {
318 symbol->option_3 = option_3;
319 }
320 if (output_options != -1) {
321 symbol->output_options = output_options;
322 }
323 symbol->debug |= debug;
324 if (length == -1) {
325 length = (int) strlen(data);
326 }
327
328 return length;
329 }
330
331 /* Pretty name for symbology */
testUtilBarcodeName(int symbology)332 const char *testUtilBarcodeName(int symbology) {
333 struct item {
334 const char *name;
335 int define;
336 int val;
337 };
338 static const struct item data[] = {
339 { "", -1, 0 },
340 { "BARCODE_CODE11", BARCODE_CODE11, 1 },
341 { "BARCODE_C25STANDARD", BARCODE_C25STANDARD, 2 },
342 { "BARCODE_C25INTER", BARCODE_C25INTER, 3 },
343 { "BARCODE_C25IATA", BARCODE_C25IATA, 4 },
344 { "", -1, 5 },
345 { "BARCODE_C25LOGIC", BARCODE_C25LOGIC, 6 },
346 { "BARCODE_C25IND", BARCODE_C25IND, 7 },
347 { "BARCODE_CODE39", BARCODE_CODE39, 8 },
348 { "BARCODE_EXCODE39", BARCODE_EXCODE39, 9 },
349 { "", -1, 10 },
350 { "", -1, 11 },
351 { "", -1, 12 },
352 { "BARCODE_EANX", BARCODE_EANX, 13 },
353 { "BARCODE_EANX_CHK", BARCODE_EANX_CHK, 14 },
354 { "", -1, 15 },
355 { "BARCODE_GS1_128", BARCODE_GS1_128, 16 },
356 { "", -1, 17 },
357 { "BARCODE_CODABAR", BARCODE_CODABAR, 18 },
358 { "", -1, 19 },
359 { "BARCODE_CODE128", BARCODE_CODE128, 20 },
360 { "BARCODE_DPLEIT", BARCODE_DPLEIT, 21 },
361 { "BARCODE_DPIDENT", BARCODE_DPIDENT, 22 },
362 { "BARCODE_CODE16K", BARCODE_CODE16K, 23 },
363 { "BARCODE_CODE49", BARCODE_CODE49, 24 },
364 { "BARCODE_CODE93", BARCODE_CODE93, 25 },
365 { "", -1, 26 },
366 { "", -1, 27 },
367 { "BARCODE_FLAT", BARCODE_FLAT, 28 },
368 { "BARCODE_DBAR_OMN", BARCODE_DBAR_OMN, 29 },
369 { "BARCODE_DBAR_LTD", BARCODE_DBAR_LTD, 30 },
370 { "BARCODE_DBAR_EXP", BARCODE_DBAR_EXP, 31 },
371 { "BARCODE_TELEPEN", BARCODE_TELEPEN, 32 },
372 { "", -1, 33 },
373 { "BARCODE_UPCA", BARCODE_UPCA, 34 },
374 { "BARCODE_UPCA_CHK", BARCODE_UPCA_CHK, 35 },
375 { "", -1, 36 },
376 { "BARCODE_UPCE", BARCODE_UPCE, 37 },
377 { "BARCODE_UPCE_CHK", BARCODE_UPCE_CHK, 38 },
378 { "", -1, 39 },
379 { "BARCODE_POSTNET", BARCODE_POSTNET, 40 },
380 { "", -1, 41 },
381 { "", -1, 42 },
382 { "", -1, 43 },
383 { "", -1, 44 },
384 { "", -1, 45 },
385 { "", -1, 46 },
386 { "BARCODE_MSI_PLESSEY", BARCODE_MSI_PLESSEY, 47 },
387 { "", -1, 48 },
388 { "BARCODE_FIM", BARCODE_FIM, 49 },
389 { "BARCODE_LOGMARS", BARCODE_LOGMARS, 50 },
390 { "BARCODE_PHARMA", BARCODE_PHARMA, 51 },
391 { "BARCODE_PZN", BARCODE_PZN, 52 },
392 { "BARCODE_PHARMA_TWO", BARCODE_PHARMA_TWO, 53 },
393 { "", -1, 54 },
394 { "BARCODE_PDF417", BARCODE_PDF417, 55 },
395 { "BARCODE_PDF417COMP", BARCODE_PDF417COMP, 56 },
396 { "BARCODE_MAXICODE", BARCODE_MAXICODE, 57 },
397 { "BARCODE_QRCODE", BARCODE_QRCODE, 58 },
398 { "", -1, 59 },
399 { "BARCODE_CODE128B", BARCODE_CODE128B, 60 },
400 { "", -1, 61 },
401 { "", -1, 62 },
402 { "BARCODE_AUSPOST", BARCODE_AUSPOST, 63 },
403 { "", -1, 64 },
404 { "", -1, 65 },
405 { "BARCODE_AUSREPLY", BARCODE_AUSREPLY, 66 },
406 { "BARCODE_AUSROUTE", BARCODE_AUSROUTE, 67 },
407 { "BARCODE_AUSREDIRECT", BARCODE_AUSREDIRECT, 68 },
408 { "BARCODE_ISBNX", BARCODE_ISBNX, 69 },
409 { "BARCODE_RM4SCC", BARCODE_RM4SCC, 70 },
410 { "BARCODE_DATAMATRIX", BARCODE_DATAMATRIX, 71 },
411 { "BARCODE_EAN14", BARCODE_EAN14, 72 },
412 { "BARCODE_VIN", BARCODE_VIN, 73 },
413 { "BARCODE_CODABLOCKF", BARCODE_CODABLOCKF, 74 },
414 { "BARCODE_NVE18", BARCODE_NVE18, 75 },
415 { "BARCODE_JAPANPOST", BARCODE_JAPANPOST, 76 },
416 { "BARCODE_KOREAPOST", BARCODE_KOREAPOST, 77 },
417 { "", -1, 78 },
418 { "BARCODE_DBAR_STK", BARCODE_DBAR_STK, 79 },
419 { "BARCODE_DBAR_OMNSTK", BARCODE_DBAR_OMNSTK, 80 },
420 { "BARCODE_DBAR_EXPSTK", BARCODE_DBAR_EXPSTK, 81 },
421 { "BARCODE_PLANET", BARCODE_PLANET, 82 },
422 { "", -1, 83 },
423 { "BARCODE_MICROPDF417", BARCODE_MICROPDF417, 84 },
424 { "BARCODE_USPS_IMAIL", BARCODE_USPS_IMAIL, 85 },
425 { "BARCODE_PLESSEY", BARCODE_PLESSEY, 86 },
426 { "BARCODE_TELEPEN_NUM", BARCODE_TELEPEN_NUM, 87 },
427 { "", -1, 88 },
428 { "BARCODE_ITF14", BARCODE_ITF14, 89 },
429 { "BARCODE_KIX", BARCODE_KIX, 90 },
430 { "", -1, 91 },
431 { "BARCODE_AZTEC", BARCODE_AZTEC, 92 },
432 { "BARCODE_DAFT", BARCODE_DAFT, 93 },
433 { "", -1, 94 },
434 { "", -1, 95 },
435 { "BARCODE_DPD", BARCODE_DPD, 96 },
436 { "BARCODE_MICROQR", BARCODE_MICROQR, 97 },
437 { "BARCODE_HIBC_128", BARCODE_HIBC_128, 98 },
438 { "BARCODE_HIBC_39", BARCODE_HIBC_39, 99 },
439 { "", -1, 100 },
440 { "", -1, 101 },
441 { "BARCODE_HIBC_DM", BARCODE_HIBC_DM, 102 },
442 { "", -1, 103 },
443 { "BARCODE_HIBC_QR", BARCODE_HIBC_QR, 104 },
444 { "", -1, 105 },
445 { "BARCODE_HIBC_PDF", BARCODE_HIBC_PDF, 106 },
446 { "", -1, 107 },
447 { "BARCODE_HIBC_MICPDF", BARCODE_HIBC_MICPDF, 108 },
448 { "", -1, 109 },
449 { "BARCODE_HIBC_BLOCKF", BARCODE_HIBC_BLOCKF, 110 },
450 { "", -1, 111 },
451 { "BARCODE_HIBC_AZTEC", BARCODE_HIBC_AZTEC, 112 },
452 { "", -1, 113 },
453 { "", -1, 114 },
454 { "BARCODE_DOTCODE", BARCODE_DOTCODE, 115 },
455 { "BARCODE_HANXIN", BARCODE_HANXIN, 116 },
456 { "", -1, 117 },
457 { "", -1, 118 },
458 { "", -1, 119 },
459 { "", -1, 120 },
460 { "BARCODE_MAILMARK", BARCODE_MAILMARK, 121 },
461 { "", -1, 122 },
462 { "", -1, 123 },
463 { "", -1, 124 },
464 { "", -1, 125 },
465 { "", -1, 126 },
466 { "", -1, 127 },
467 { "BARCODE_AZRUNE", BARCODE_AZRUNE, 128 },
468 { "BARCODE_CODE32", BARCODE_CODE32, 129 },
469 { "BARCODE_EANX_CC", BARCODE_EANX_CC, 130 },
470 { "BARCODE_GS1_128_CC", BARCODE_GS1_128_CC, 131 },
471 { "BARCODE_DBAR_OMN_CC", BARCODE_DBAR_OMN_CC, 132 },
472 { "BARCODE_DBAR_LTD_CC", BARCODE_DBAR_LTD_CC, 133 },
473 { "BARCODE_DBAR_EXP_CC", BARCODE_DBAR_EXP_CC, 134 },
474 { "BARCODE_UPCA_CC", BARCODE_UPCA_CC, 135 },
475 { "BARCODE_UPCE_CC", BARCODE_UPCE_CC, 136 },
476 { "BARCODE_DBAR_STK_CC", BARCODE_DBAR_STK_CC, 137 },
477 { "BARCODE_DBAR_OMNSTK_CC", BARCODE_DBAR_OMNSTK_CC, 138 },
478 { "BARCODE_DBAR_EXPSTK_CC", BARCODE_DBAR_EXPSTK_CC, 139 },
479 { "BARCODE_CHANNEL", BARCODE_CHANNEL, 140 },
480 { "BARCODE_CODEONE", BARCODE_CODEONE, 141 },
481 { "BARCODE_GRIDMATRIX", BARCODE_GRIDMATRIX, 142 },
482 { "BARCODE_UPNQR", BARCODE_UPNQR, 143 },
483 { "BARCODE_ULTRA", BARCODE_ULTRA, 144 },
484 { "BARCODE_RMQR", BARCODE_RMQR, 145 },
485 };
486 static const int data_size = ARRAY_SIZE(data);
487
488 if (symbology < 0 || symbology >= data_size) {
489 return "";
490 }
491 // Self-check
492 if (data[symbology].val != symbology || (data[symbology].define != -1 && data[symbology].define != symbology)) {
493 fprintf(stderr, "testUtilBarcodeName: data table out of sync (%d)\n", symbology);
494 abort();
495 }
496 return data[symbology].name;
497 }
498
499 /* Pretty name for error/warning */
testUtilErrorName(int error_number)500 const char *testUtilErrorName(int error_number) {
501 struct item {
502 const char *name;
503 int define;
504 int val;
505 };
506 static const struct item data[] = {
507 { "0", 0, 0 },
508 { "", -1, 1 },
509 { "ZINT_WARN_INVALID_OPTION", ZINT_WARN_INVALID_OPTION, 2 },
510 { "ZINT_WARN_USES_ECI", ZINT_WARN_USES_ECI, 3 },
511 { "ZINT_WARN_NONCOMPLIANT", ZINT_WARN_NONCOMPLIANT, 4 },
512 { "ZINT_ERROR_TOO_LONG", ZINT_ERROR_TOO_LONG, 5 },
513 { "ZINT_ERROR_INVALID_DATA", ZINT_ERROR_INVALID_DATA, 6 },
514 { "ZINT_ERROR_INVALID_CHECK", ZINT_ERROR_INVALID_CHECK, 7 },
515 { "ZINT_ERROR_INVALID_OPTION", ZINT_ERROR_INVALID_OPTION, 8 },
516 { "ZINT_ERROR_ENCODING_PROBLEM", ZINT_ERROR_ENCODING_PROBLEM, 9 },
517 { "ZINT_ERROR_FILE_ACCESS", ZINT_ERROR_FILE_ACCESS, 10 },
518 { "ZINT_ERROR_MEMORY", ZINT_ERROR_MEMORY, 11 },
519 };
520 static const int data_size = ARRAY_SIZE(data);
521
522 if (error_number < 0 || error_number >= data_size) {
523 return "";
524 }
525 // Self-check
526 if (data[error_number].val != error_number
527 || (data[error_number].define != -1 && data[error_number].define != error_number)) {
528 fprintf(stderr, "testUtilErrorName: data table out of sync (%d)\n", error_number);
529 abort();
530 }
531 return data[error_number].name;
532 }
533
534 /* Pretty name for input mode */
testUtilInputModeName(int input_mode)535 const char *testUtilInputModeName(int input_mode) {
536 static char buf[512];
537
538 struct item {
539 const char *name;
540 int define;
541 int val;
542 };
543 static const struct item data[] = {
544 { "ESCAPE_MODE", ESCAPE_MODE, 8 },
545 { "GS1PARENS_MODE", GS1PARENS_MODE, 16 },
546 { "GS1NOCHECK_MODE", GS1NOCHECK_MODE, 32 },
547 };
548 static const int data_size = ARRAY_SIZE(data);
549 int set, i;
550
551 if (input_mode < 0) {
552 return "-1";
553 }
554 *buf = '\0';
555 if ((input_mode & 0x7) & UNICODE_MODE) {
556 strcpy(buf, "UNICODE_MODE");
557 set = UNICODE_MODE;
558 } else if ((input_mode & 0x7) & GS1_MODE) {
559 strcpy(buf, "GS1_MODE");
560 set = GS1_MODE;
561 } else {
562 set = DATA_MODE;
563 }
564 for (i = 0; i < data_size; i++) {
565 if (data[i].define != data[i].val) { // Self-check
566 fprintf(stderr, "testUtilInputModeName: data table out of sync (%d)\n", i);
567 abort();
568 }
569 if (input_mode & data[i].define) {
570 if (*buf) {
571 strcat(buf, " | ");
572 }
573 strcat(buf, data[i].name);
574 set |= data[i].define;
575 }
576 }
577 if (set != input_mode) {
578 fprintf(stderr, "testUtilInputModeName: unknown input mode %d (%d)\n", input_mode & set, input_mode);
579 abort();
580 }
581 if (set == DATA_MODE && *buf == '\0') {
582 strcpy(buf, "DATA_MODE");
583 }
584 return buf;
585 }
586
587 /* Pretty name for option 3 */
testUtilOption3Name(int option_3)588 const char *testUtilOption3Name(int option_3) {
589 static char buffer[64];
590
591 const char *name = NULL;
592 unsigned int high_byte = option_3 == -1 ? 0 : (option_3 >> 8) & 0xFF;
593
594 switch (option_3 & 0xFF) {
595 case DM_SQUARE:
596 name = "DM_SQUARE";
597 break;
598 case DM_DMRE:
599 name = "DM_DMRE";
600 break;
601 case ZINT_FULL_MULTIBYTE:
602 name = "ZINT_FULL_MULTIBYTE";
603 break;
604 case ULTRA_COMPRESSION:
605 name = "ULTRA_COMPRESSION";
606 break;
607 default:
608 if (option_3 != -1 && (option_3 & 0xFF) != 0) {
609 fprintf(stderr, "testUtilOption3Name: unknown value (%d)\n", option_3);
610 abort();
611 }
612 name = (option_3 & 0xFF) ? "-1" : "0";
613 break;
614 }
615
616 if (high_byte) {
617 if (option_3 & 0xFF) {
618 sprintf(buffer, "%s | (%d << 8)", name, (int) high_byte);
619 } else {
620 sprintf(buffer, "%d << 8", (int) high_byte);
621 }
622 return buffer;
623 }
624
625 return name;
626 }
627
628 /* Pretty name for output options */
testUtilOutputOptionsName(int output_options)629 const char *testUtilOutputOptionsName(int output_options) {
630 static char buf[512];
631
632 struct item {
633 const char *name;
634 int define;
635 int val;
636 };
637 static const struct item data[] = {
638 { "BARCODE_NO_ASCII", BARCODE_NO_ASCII, 1 },
639 { "BARCODE_BIND", BARCODE_BIND, 2 },
640 { "BARCODE_BOX", BARCODE_BOX, 4 },
641 { "BARCODE_STDOUT", BARCODE_STDOUT, 8 },
642 { "READER_INIT", READER_INIT, 16 },
643 { "SMALL_TEXT", SMALL_TEXT, 32 },
644 { "BOLD_TEXT", BOLD_TEXT, 64 },
645 { "CMYK_COLOUR", CMYK_COLOUR, 128 },
646 { "BARCODE_DOTTY_MODE", BARCODE_DOTTY_MODE, 256 },
647 { "GS1_GS_SEPARATOR", GS1_GS_SEPARATOR, 512 },
648 { "OUT_BUFFER_INTERMEDIATE", OUT_BUFFER_INTERMEDIATE, 1024 },
649 };
650 static int const data_size = ARRAY_SIZE(data);
651 int set = 0;
652 int i;
653
654 if (output_options == -1) {
655 return "-1";
656 }
657 if (output_options == 0) {
658 return "0";
659 }
660 buf[0] = '\0';
661 for (i = 0; i < data_size; i++) {
662 if (data[i].define != data[i].val) { // Self-check
663 fprintf(stderr, "testUtilOutputOptionsName: data table out of sync (%d)\n", i);
664 abort();
665 }
666 if (output_options & data[i].define) {
667 if (set) {
668 strcat(buf, " | ");
669 }
670 strcat(buf, data[i].name);
671 set |= data[i].define;
672 }
673 }
674 if (set != output_options) {
675 fprintf(stderr, "testUtilOutputOptionsName: unknown output option(s) %d (%d)\n",
676 output_options & set, output_options);
677 abort();
678 }
679 return buf;
680 }
681
682 /* Convert modules spanning 3 rows to DAFT equivalents */
testUtilDAFTConvert(const struct zint_symbol * symbol,char * buffer,int buffer_size)683 int testUtilDAFTConvert(const struct zint_symbol *symbol, char *buffer, int buffer_size) {
684 int i;
685 char *b = buffer;
686 *b = '\0';
687 for (i = 0; i < symbol->width && b < buffer + buffer_size; i += 2) {
688 if (module_is_set(symbol, 0, i) && module_is_set(symbol, 2, i)) {
689 *b++ = 'F';
690 } else if (module_is_set(symbol, 0, i)) {
691 *b++ = 'A';
692 } else if (module_is_set(symbol, 2, i)) {
693 *b++ = 'D';
694 } else {
695 *b++ = 'T';
696 }
697 }
698 if (b == buffer + buffer_size) {
699 return FALSE;
700 }
701 *b = '\0';
702 return TRUE;
703 }
704
705 /* Is string valid UTF-8? */
testUtilIsValidUTF8(const unsigned char str[],const int length)706 int testUtilIsValidUTF8(const unsigned char str[], const int length) {
707 int i;
708 unsigned int codepoint, state = 0;
709
710 for (i = 0; i < length; i++) {
711 if (decode_utf8(&state, &codepoint, str[i]) == 12) {
712 return 0;
713 }
714 }
715
716 return state == 0;
717 }
718
719 /* Escape data for printing on generate test. Has a number of issues, e.g. need to use octal escapes */
testUtilEscape(char * buffer,int length,char * escaped,int escaped_size)720 char *testUtilEscape(char *buffer, int length, char *escaped, int escaped_size) {
721 int i;
722 unsigned char *b = (unsigned char *) buffer;
723 unsigned char *be = b + length;
724 int non_utf8 = !testUtilIsValidUTF8(b, length);
725 int chunk = -1;
726
727 for (i = 0; b < be && i < escaped_size; b++) {
728 // For VC6-compatibility need to split literal strings into <= 2K chunks
729 if (i > 2040 && i / 2040 != chunk) {
730 chunk = i / 2040;
731 if (i + 3 < escaped_size) {
732 escaped[i] = '"';
733 escaped[i + 1] = ' ';
734 escaped[i + 2] = '"';
735 }
736 i += 3;
737 }
738 if (non_utf8 || *b < ' ' || *b == '\177') {
739 if (i + 4 < escaped_size) {
740 sprintf(escaped + i, "\\%.3o", *b);
741 }
742 i += 4;
743 } else if (*b == '\\' || *b == '"') {
744 if (i + 2 < escaped_size) {
745 escaped[i] = '\\';
746 escaped[i + 1] = *b;
747 }
748 i += 2;
749 } else if (b + 1 < be && *b == 0xC2 && *(b + 1) < 0xA0) {
750 if (i + 8 < escaped_size) {
751 sprintf(escaped + i, "\\%.3o\\%.3o", *b, *(b + 1));
752 }
753 i += 8;
754 b++;
755 } else {
756 escaped[i++] = *b;
757 }
758 }
759 if (i >= escaped_size) {
760 return NULL;
761 }
762 escaped[i] = '\0';
763 return escaped;
764 }
765
766 /* Helper to read a CSV field */
testUtilReadCSVField(char * buffer,char * field,int field_size)767 char *testUtilReadCSVField(char *buffer, char *field, int field_size) {
768 int i;
769 char *b = buffer;
770 for (i = 0; i < field_size && *b && *b != ',' && *b != '\n' && *b != '\r'; i++) {
771 field[i] = *b++;
772 }
773 if (i == field_size) {
774 return NULL;
775 }
776 field[i] = '\0';
777 return b;
778 }
779
780 /* Helper to fill a buffer (for "large" tests) - single-byte filler only */
testUtilStrCpyRepeat(char * buffer,char * repeat,int size)781 void testUtilStrCpyRepeat(char *buffer, char *repeat, int size) {
782 int i;
783 int len = (int) strlen(repeat);
784 int max = size - len;
785 if (len == 0) {
786 fprintf(stderr, "testUtilStrCpyRepeat: only use non-empty, non-NUL single-byte data for repeat pattern\n");
787 abort();
788 }
789 for (i = 0; i < max; i += len) {
790 memcpy(buffer + i, repeat, len);
791 }
792 memcpy(buffer + i, repeat, size - i);
793 buffer[size] = '\0';
794 }
795
796 /* Compare some "important" symbol fields for equality */
testUtilSymbolCmp(const struct zint_symbol * a,const struct zint_symbol * b)797 int testUtilSymbolCmp(const struct zint_symbol *a, const struct zint_symbol *b) {
798 int i, j;
799 if (a->symbology != b->symbology) {
800 return 1;
801 }
802 if (a->rows != b->rows) {
803 return 2;
804 }
805 if (a->width != b->width) {
806 return 3;
807 }
808 if (a->symbology == BARCODE_ULTRA) {
809 for (i = 0; i < a->rows; i++) {
810 for (j = 0; j < a->width; j++) {
811 if (module_colour_is_set(a, i, j) != module_colour_is_set(b, i, j)) {
812 return 4;
813 }
814 }
815 }
816 } else {
817 for (i = 0; i < a->rows; i++) {
818 for (j = 0; j < a->width; j++) {
819 if (module_is_set(a, i, j) != module_is_set(b, i, j)) {
820 return 4;
821 }
822 }
823 }
824 }
825 if (a->height != b->height) {
826 return 5;
827 }
828 if (a->whitespace_width != b->whitespace_width) {
829 return 6;
830 }
831 if (a->whitespace_height != b->whitespace_height) {
832 return 7;
833 }
834 if (a->border_width != b->border_width) {
835 return 8;
836 }
837 if (a->output_options != b->output_options) {
838 return 9;
839 }
840 if (a->scale != b->scale) {
841 return 10;
842 }
843
844 return 0;
845 }
846
847 /* Copy a full vector structure (for later comparison) */
testUtilVectorCpy(const struct zint_vector * in)848 struct zint_vector *testUtilVectorCpy(const struct zint_vector *in) {
849 struct zint_vector_rect *rect;
850 struct zint_vector_string *string;
851 struct zint_vector_circle *circle;
852 struct zint_vector_hexagon *hexagon;
853
854 struct zint_vector_rect **outrect;
855 struct zint_vector_string **outstring;
856 struct zint_vector_circle **outcircle;
857 struct zint_vector_hexagon **outhexagon;
858
859 struct zint_vector *out = malloc(sizeof(struct zint_vector));
860 assert(out != NULL);
861 out->width = in->width;
862 out->height = in->height;
863 out->rectangles = NULL;
864 out->strings = NULL;
865 out->circles = NULL;
866 out->hexagons = NULL;
867
868 // Copy rectangles
869 rect = in->rectangles;
870 outrect = &(out->rectangles);
871 while (rect) {
872 *outrect = malloc(sizeof(struct zint_vector_rect));
873 assert(*outrect != NULL);
874 memcpy(*outrect, rect, sizeof(struct zint_vector_rect));
875 outrect = &((*outrect)->next);
876 rect = rect->next;
877 }
878 *outrect = NULL;
879
880 // Copy Strings
881 string = in->strings;
882 outstring = &(out->strings);
883 while (string) {
884 *outstring = malloc(sizeof(struct zint_vector_string));
885 assert(*outstring != NULL);
886 memcpy(*outstring, string, sizeof(struct zint_vector_string));
887 (*outstring)->text = malloc(ustrlen(string->text) + 1);
888 assert((*outstring)->text != NULL);
889 ustrcpy((*outstring)->text, string->text);
890 outstring = &((*outstring)->next);
891 string = string->next;
892 }
893 *outstring = NULL;
894
895 // Copy Circles
896 circle = in->circles;
897 outcircle = &(out->circles);
898 while (circle) {
899 *outcircle = malloc(sizeof(struct zint_vector_circle));
900 assert(*outcircle != NULL);
901 memcpy(*outcircle, circle, sizeof(struct zint_vector_circle));
902 outcircle = &((*outcircle)->next);
903 circle = circle->next;
904 }
905 *outcircle = NULL;
906
907 // Copy Hexagons
908 hexagon = in->hexagons;
909 outhexagon = &(out->hexagons);
910 while (hexagon) {
911 *outhexagon = malloc(sizeof(struct zint_vector_hexagon));
912 assert(*outhexagon != NULL);
913 memcpy(*outhexagon, hexagon, sizeof(struct zint_vector_hexagon));
914 outhexagon = &((*outhexagon)->next);
915 hexagon = hexagon->next;
916 }
917 *outhexagon = NULL;
918
919 return out;
920 }
921
922 /* Compare 2 full vector structures */
testUtilVectorCmp(const struct zint_vector * a,const struct zint_vector * b)923 int testUtilVectorCmp(const struct zint_vector *a, const struct zint_vector *b) {
924 struct zint_vector_rect *arect;
925 struct zint_vector_string *astring;
926 struct zint_vector_circle *acircle;
927 struct zint_vector_hexagon *ahexagon;
928
929 struct zint_vector_rect *brect;
930 struct zint_vector_string *bstring;
931 struct zint_vector_circle *bcircle;
932 struct zint_vector_hexagon *bhexagon;
933
934 if (a->width != b->width) {
935 return 1;
936 }
937 if (a->height != b->height) {
938 return 2;
939 }
940
941 // Compare rectangles
942 arect = a->rectangles;
943 brect = b->rectangles;
944 while (arect) {
945 if (!brect) {
946 return 11;
947 }
948 if (arect->x != brect->x) {
949 return 12;
950 }
951 if (arect->y != brect->y) {
952 return 13;
953 }
954 if (arect->height != brect->height) {
955 return 14;
956 }
957 if (arect->width != brect->width) {
958 return 15;
959 }
960 if (arect->colour != brect->colour) {
961 return 16;
962 }
963 arect = arect->next;
964 brect = brect->next;
965 }
966 if (brect) {
967 return 10;
968 }
969
970 // Compare strings
971 astring = a->strings;
972 bstring = b->strings;
973 while (astring) {
974 if (!bstring) {
975 return 21;
976 }
977 if (astring->x != bstring->x) {
978 return 22;
979 }
980 if (astring->y != bstring->y) {
981 return 23;
982 }
983 if (astring->fsize != bstring->fsize) {
984 return 24;
985 }
986 if (astring->width != bstring->width) {
987 return 25;
988 }
989 if (astring->length != bstring->length) {
990 return 26;
991 }
992 if (ustrlen(astring->text) != ustrlen(bstring->text)) {
993 return 27;
994 }
995 if (strcmp((const char *) astring->text, (const char *) bstring->text) != 0) {
996 return 28;
997 }
998 astring = astring->next;
999 bstring = bstring->next;
1000 }
1001 if (bstring) {
1002 return 20;
1003 }
1004
1005 // Compare circles
1006 acircle = a->circles;
1007 bcircle = b->circles;
1008 while (acircle) {
1009 if (!bcircle) {
1010 return 31;
1011 }
1012 if (acircle->x != bcircle->x) {
1013 return 32;
1014 }
1015 if (acircle->y != bcircle->y) {
1016 return 33;
1017 }
1018 if (acircle->diameter != bcircle->diameter) {
1019 return 34;
1020 }
1021 if (acircle->colour != bcircle->colour) {
1022 return 35;
1023 }
1024 acircle = acircle->next;
1025 bcircle = bcircle->next;
1026 }
1027 if (bcircle) {
1028 return 30;
1029 }
1030
1031 // Compare hexagons
1032 ahexagon = a->hexagons;
1033 bhexagon = b->hexagons;
1034 while (ahexagon) {
1035 if (!bhexagon) {
1036 return 41;
1037 }
1038 if (ahexagon->x != bhexagon->x) {
1039 return 42;
1040 }
1041 if (ahexagon->y != bhexagon->y) {
1042 return 43;
1043 }
1044 if (ahexagon->diameter != bhexagon->diameter) {
1045 return 44;
1046 }
1047 ahexagon = ahexagon->next;
1048 bhexagon = bhexagon->next;
1049 }
1050 if (bhexagon) {
1051 return 40;
1052 }
1053
1054 return 0;
1055 }
1056
1057 /* Dump modules into buffer as '0'/'1' (or colours '0', '1', '2' etc if Ultra) */
testUtilModulesDump(const struct zint_symbol * symbol,char dump[],int dump_size)1058 int testUtilModulesDump(const struct zint_symbol *symbol, char dump[], int dump_size) {
1059 int r, w;
1060 char *d = dump;
1061 char *de = dump + dump_size;
1062
1063 for (r = 0; r < symbol->rows && d < de; r++) {
1064 if (symbol->symbology == BARCODE_ULTRA) {
1065 for (w = 0; w < symbol->width && d < de; w++) {
1066 *d++ = module_colour_is_set(symbol, r, w) + '0';
1067 }
1068 } else {
1069 for (w = 0; w < symbol->width && d < de; w++) {
1070 *d++ = module_is_set(symbol, r, w) + '0';
1071 }
1072 }
1073 }
1074 if (d == de) {
1075 return -1;
1076 }
1077 *d = '\0';
1078 return d - dump;
1079 }
1080
1081 /* Print out module dump (for generate tests) */
testUtilModulesPrint(const struct zint_symbol * symbol,const char * prefix,const char * postfix)1082 void testUtilModulesPrint(const struct zint_symbol *symbol, const char *prefix, const char *postfix) {
1083 int r;
1084 for (r = 0; r < symbol->rows; r++) {
1085 testUtilModulesPrintRow(symbol, r, prefix, postfix);
1086 }
1087 }
1088
1089 /* Print out a single row of a module dump (for generate tests where rows all the same, to avoid large dumps of
1090 duplicate data) */
testUtilModulesPrintRow(const struct zint_symbol * symbol,int row,const char * prefix,const char * postfix)1091 void testUtilModulesPrintRow(const struct zint_symbol *symbol, int row, const char *prefix, const char *postfix) {
1092 int w;
1093 if (*prefix) {
1094 fputs(prefix, stdout);
1095 }
1096 putchar('"');
1097 if (symbol->symbology == BARCODE_ULTRA) {
1098 for (w = 0; w < symbol->width; w++) {
1099 putchar(module_colour_is_set(symbol, row, w) + '0');
1100 }
1101 } else {
1102 for (w = 0; w < symbol->width; w++) {
1103 putchar(module_is_set(symbol, row, w) + '0');
1104 }
1105 }
1106 putchar('"');
1107 if (*postfix) {
1108 fputs(postfix, stdout);
1109 }
1110 }
1111
1112 /* Whether 2 module dumps are the same */
testUtilModulesCmp(const struct zint_symbol * symbol,const char * expected,int * width,int * row)1113 int testUtilModulesCmp(const struct zint_symbol *symbol, const char *expected, int *width, int *row) {
1114 const char *e = expected;
1115 const char *ep = expected + strlen(expected);
1116 int r, w = 0;
1117 if (symbol->symbology == BARCODE_ULTRA) {
1118 for (r = 0; r < symbol->rows && e < ep; r++) {
1119 for (w = 0; w < symbol->width && e < ep; w++) {
1120 if (module_colour_is_set(symbol, r, w) + '0' != *e) {
1121 *row = r;
1122 *width = w;
1123 return 1 /*fail*/;
1124 }
1125 e++;
1126 }
1127 }
1128 } else {
1129 for (r = 0; r < symbol->rows && e < ep; r++) {
1130 for (w = 0; w < symbol->width && e < ep; w++) {
1131 if (module_is_set(symbol, r, w) + '0' != *e) {
1132 *row = r;
1133 *width = w;
1134 return 1 /*fail*/;
1135 }
1136 e++;
1137 }
1138 }
1139 }
1140 *row = r;
1141 *width = w;
1142 return e != ep || r != symbol->rows || w != symbol->width ? 1 /*fail*/ : 0 /*success*/;
1143 }
1144
1145 /* Whether 2 module row dumps are the same */
testUtilModulesCmpRow(const struct zint_symbol * symbol,int row,const char * expected,int * width)1146 int testUtilModulesCmpRow(const struct zint_symbol *symbol, int row, const char *expected, int *width) {
1147 const char *e = expected;
1148 const char *ep = expected + strlen(expected);
1149 int w;
1150 if (symbol->symbology == BARCODE_ULTRA) {
1151 for (w = 0; w < symbol->width && e < ep; w++) {
1152 if (module_colour_is_set(symbol, row, w) + '0' != *e) {
1153 *width = w;
1154 return 1 /*fail*/;
1155 }
1156 e++;
1157 }
1158 } else {
1159 for (w = 0; w < symbol->width && e < ep; w++) {
1160 if (module_is_set(symbol, row, w) + '0' != *e) {
1161 *width = w;
1162 return 1 /*fail*/;
1163 }
1164 e++;
1165 }
1166 }
1167 *width = w;
1168 return e != ep || w != symbol->width ? 1 /*fail*/ : 0 /*success*/;
1169 }
1170
1171 /* Dump an unsigned int array as hex */
testUtilUIntArrayDump(unsigned int * array,int size,char * dump,int dump_size)1172 char *testUtilUIntArrayDump(unsigned int *array, int size, char *dump, int dump_size) {
1173 int i, cnt_len = 0;
1174
1175 for (i = 0; i < size; i++) {
1176 cnt_len += sprintf(dump + cnt_len, "%X ", array[i]);
1177 if (cnt_len + 17 >= dump_size) {
1178 break;
1179 }
1180 }
1181 dump[cnt_len ? cnt_len - 1 : 0] = '\0';
1182 return dump;
1183 }
1184
1185 /* Dump an unsigned char array as hex */
testUtilUCharArrayDump(unsigned char * array,int size,char * dump,int dump_size)1186 char *testUtilUCharArrayDump(unsigned char *array, int size, char *dump, int dump_size) {
1187 int i, cnt_len = 0;
1188
1189 for (i = 0; i < size; i++) {
1190 cnt_len += sprintf(dump + cnt_len, "%X ", array[i]);
1191 if (cnt_len + 3 >= dump_size) {
1192 break;
1193 }
1194 }
1195 dump[cnt_len ? cnt_len - 1 : 0] = '\0';
1196 return dump;
1197 }
1198
1199 /* Dump a bitmap to stdout, for generate tests. Also useful for debugging */
testUtilBitmapPrint(const struct zint_symbol * symbol,const char * prefix,const char * postfix)1200 void testUtilBitmapPrint(const struct zint_symbol *symbol, const char *prefix, const char *postfix) {
1201 static const char colour[] = { '0', 'C', 'M', 'B', 'Y', 'G', 'R', '1' };
1202 int row, column, i, j;
1203
1204 if (!prefix) {
1205 fputs(" ", stdout);
1206 for (column = 0; column < symbol->bitmap_width; column += 10) printf("%-3d ", column);
1207 fputs("\n ", stdout);
1208 for (column = 0; column < symbol->bitmap_width; column++) printf("%d", column % 10);
1209 putchar('\n');
1210 }
1211
1212 for (row = 0; row < symbol->bitmap_height; row++) {
1213 if (!prefix) {
1214 printf("%3d: ", row);
1215 } else {
1216 if (*prefix) {
1217 fputs(prefix, stdout);
1218 }
1219 putchar('"');
1220 }
1221 for (column = 0; column < symbol->bitmap_width; column++) {
1222 if (symbol->output_options & OUT_BUFFER_INTERMEDIATE) {
1223 putchar(symbol->bitmap[(row * symbol->bitmap_width) + column]);
1224 } else {
1225 i = ((row * symbol->bitmap_width) + column) * 3;
1226 if ((symbol->bitmap[i] == 0 || symbol->bitmap[i] == 0xff)
1227 && (symbol->bitmap[i + 1] == 0 || symbol->bitmap[i + 1] == 0xff)
1228 && (symbol->bitmap[i + 2] == 0 || symbol->bitmap[i + 2] == 0xff)) {
1229 j = !symbol->bitmap[i] + !symbol->bitmap[i + 1] * 2 + !symbol->bitmap[i + 2] * 4;
1230 putchar(colour[j]);
1231 } else {
1232 printf("%02X%02X%02X", symbol->bitmap[i], symbol->bitmap[i + 1], symbol->bitmap[i + 2]);
1233 }
1234 }
1235 }
1236 if (!postfix) {
1237 putchar('\n');
1238 } else {
1239 putchar('"');
1240 if (*postfix) {
1241 fputs(postfix, stdout);
1242 }
1243 }
1244 }
1245
1246 if (!postfix) {
1247 fputs(" ", stdout);
1248 for (column = 0; column < symbol->bitmap_width; column++) printf("%d", column % 10);
1249 fputs("\n ", stdout);
1250 for (column = 0; column < symbol->bitmap_width; column += 10) printf("%-3d ", column);
1251 putchar('\n');
1252 }
1253 }
1254
1255 /* Compare a bitmap to a dump */
testUtilBitmapCmp(const struct zint_symbol * symbol,const char * expected,int * row,int * column)1256 int testUtilBitmapCmp(const struct zint_symbol *symbol, const char *expected, int *row, int *column) {
1257 static const char colour[] = { '0', 'C', 'M', 'B', 'Y', 'G', 'R', '1' };
1258 int r, c = -1, i, j;
1259 const char *e = expected;
1260 const char *ep = expected + strlen(expected);
1261 char buf[7];
1262
1263 for (r = 0; r < symbol->bitmap_height; r++) {
1264 for (c = 0; c < symbol->bitmap_width; c++) {
1265 if (symbol->output_options & OUT_BUFFER_INTERMEDIATE) {
1266 if (*e != symbol->bitmap[(r * symbol->bitmap_width) + c]) {
1267 *row = r;
1268 *column = c;
1269 return 1 /*fail*/;
1270 }
1271 e++;
1272 } else {
1273 i = ((r * symbol->bitmap_width) + c) * 3;
1274 if ((symbol->bitmap[i] == 0 || symbol->bitmap[i] == 0xff)
1275 && (symbol->bitmap[i + 1] == 0 || symbol->bitmap[i + 1] == 0xff)
1276 && (symbol->bitmap[i + 2] == 0 || symbol->bitmap[i + 2] == 0xff)) {
1277 j = !symbol->bitmap[i] + !symbol->bitmap[i + 1] * 2 + !symbol->bitmap[i + 2] * 4;
1278 if (*e != colour[j]) {
1279 *row = r;
1280 *column = c;
1281 return 1 /*fail*/;
1282 }
1283 e++;
1284 } else {
1285 sprintf(buf, "%02X%02X%02X", symbol->bitmap[i], symbol->bitmap[i + 1], symbol->bitmap[i + 2]);
1286 if (strncmp(buf, e, 6) != 0) {
1287 *row = r;
1288 *column = c;
1289 return 1 /*fail*/;
1290 }
1291 e += 6;
1292 }
1293 }
1294 }
1295 }
1296
1297 *row = r;
1298 *column = c;
1299 return e != ep || r != symbol->bitmap_height || c != symbol->bitmap_width ? 1 /*fail*/ : 0 /*success*/;
1300 }
1301
1302 /* Determine the location of test data relative to where the test is being run */
testUtilDataPath(char * buffer,int buffer_size,const char * subdir,const char * filename)1303 int testUtilDataPath(char *buffer, int buffer_size, const char *subdir, const char *filename) {
1304 int subdir_len = subdir ? (int) strlen(subdir) : 0;
1305 int filename_len = filename ? (int) strlen(filename) : 0;
1306 char *s, *s2;
1307 int len;
1308 char *cmake_src_dir;
1309 #ifdef _WIN32
1310 int i;
1311 #endif
1312
1313 if ((cmake_src_dir = getenv("CMAKE_CURRENT_SOURCE_DIR")) != NULL) {
1314 len = (int) strlen(cmake_src_dir);
1315 if (len <= 0 || len >= buffer_size) {
1316 fprintf(stderr, "testUtilDataPath: warning CMAKE_CURRENT_SOURCE_DIR len %d, ignoring\n", len);
1317 cmake_src_dir = NULL;
1318 } else {
1319 strcpy(buffer, cmake_src_dir);
1320 }
1321 }
1322
1323 if (cmake_src_dir == NULL) {
1324 if (getcwd(buffer, buffer_size) == NULL) {
1325 fprintf(stderr, "testUtilDataPath: getcwd NULL buffer_size %d\n", buffer_size);
1326 return 0;
1327 }
1328 len = (int) strlen(buffer);
1329
1330 if (len <= 0) {
1331 fprintf(stderr, "testUtilDataPath: strlen <= 0\n");
1332 return 0;
1333 }
1334 }
1335 #ifdef _WIN32
1336 for (i = 0; i < len; i++) {
1337 if (buffer[i] == '\\') {
1338 buffer[i] = '/';
1339 }
1340 }
1341 #endif
1342 if (buffer[len - 1] == '/') {
1343 buffer[len--] = '\0';
1344 }
1345 if (len == 0) {
1346 fprintf(stderr, "testUtilDataPath: len == 0\n");
1347 return 0;
1348 }
1349
1350 if ((s = strstr(buffer, "/tests")) != NULL) {
1351 while ((s2 = strstr(s + 1, "/tests")) != NULL) { // Find rightmost
1352 s = s2;
1353 }
1354 *s = '\0';
1355 len = s - buffer;
1356 }
1357 if ((s = strstr(buffer, "/backend")) != NULL) {
1358 while ((s2 = strstr(s + 1, "/backend")) != NULL) { // Find rightmost
1359 s = s2;
1360 }
1361 *s = '\0';
1362 len = s - buffer;
1363 } else if ((s = strstr(buffer, "/frontend")) != NULL) {
1364 while ((s2 = strstr(s + 1, "/frontend")) != NULL) { // Find rightmost
1365 s = s2;
1366 }
1367 *s = '\0';
1368 len = s - buffer;
1369 }
1370 if (cmake_src_dir == NULL && (s = strrchr(buffer, '/')) != NULL) { // Remove "build" dir
1371 *s = '\0';
1372 len = s - buffer;
1373 }
1374
1375 if (subdir_len) {
1376 if (*subdir != '/' && buffer[len - 1] != '/') {
1377 if (len + 1 >= buffer_size) {
1378 fprintf(stderr, "testUtilDataPath: subdir len (%d) + 1 >= buffer_size (%d)\n", len, buffer_size);
1379 return 0;
1380 }
1381 buffer[len++] = '/';
1382 buffer[len] = '\0';
1383 }
1384 if (len + subdir_len >= buffer_size) {
1385 fprintf(stderr, "testUtilDataPath: len (%d) + subdir_len (%d) >= buffer_size (%d)\n",
1386 len, subdir_len, buffer_size);
1387 return 0;
1388 }
1389 strcpy(buffer + len, subdir);
1390 len += subdir_len;
1391 }
1392
1393 if (filename_len) {
1394 if (*filename != '/' && buffer[len - 1] != '/') {
1395 if (len + 1 >= buffer_size) {
1396 fprintf(stderr, "testUtilDataPath: filename len (%d) + 1 >= buffer_size (%d)\n", len, buffer_size);
1397 return 0;
1398 }
1399 buffer[len++] = '/';
1400 buffer[len] = '\0';
1401 }
1402 if (len + filename_len >= buffer_size) {
1403 fprintf(stderr, "testUtilDataPath: len (%d) + filename_len (%d) >= buffer_size (%d)\n",
1404 len, filename_len, buffer_size);
1405 return 0;
1406 }
1407 strcpy(buffer + len, filename);
1408 }
1409
1410 return 1;
1411 }
1412
1413 /* Does file exist? */
testUtilExists(const char * filename)1414 int testUtilExists(const char *filename) {
1415 FILE *fp = fopen(filename, "r");
1416 if (fp == NULL) {
1417 return 0;
1418 }
1419 fclose(fp);
1420 return 1;
1421 }
1422
1423 /* Does directory exist? (Windows compatibility) */
testUtilDirExists(const char * dirname)1424 int testUtilDirExists(const char *dirname) {
1425 #ifdef _WIN32
1426 DWORD dwAttrib = GetFileAttributes(dirname);
1427 return dwAttrib != (DWORD) -1 && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY);
1428 #else
1429 return testUtilExists(dirname);
1430 #endif
1431 }
1432
1433 /* Make a directory (Windows compatibility). Returns 0 if successful, non-zero if not */
testUtilMkDir(const char * dirname)1434 int testUtilMkDir(const char *dirname) {
1435 #ifdef _WIN32
1436 return CreateDirectory(dirname, NULL) == 0;
1437 #else
1438 return mkdir(dirname, S_IRWXU);
1439 #endif
1440 }
1441
1442 /* Remove a directory (Windows compatibility). Returns 0 if successful, non-zero if not */
testUtilRmDir(const char * dirname)1443 int testUtilRmDir(const char *dirname) {
1444 #ifdef _WIN32
1445 return RemoveDirectory(dirname) == 0;
1446 #else
1447 return rmdir(dirname);
1448 #endif
1449 }
1450
1451 /* Rename a file (Windows compatibility). */
testUtilRename(const char * oldpath,const char * newpath)1452 int testUtilRename(const char *oldpath, const char *newpath) {
1453 #ifdef _MSVC
1454 int ret = remove(newpath);
1455 if (ret != 0) return ret;
1456 #endif
1457 return rename(oldpath, newpath);
1458 }
1459
1460 /* Compare 2 PNG files */
testUtilCmpPngs(const char * png1,const char * png2)1461 int testUtilCmpPngs(const char *png1, const char *png2) {
1462 int ret = -1;
1463 #ifdef NO_PNG
1464 (void)png1; (void)png2;
1465 #else
1466 FILE *fp1;
1467 FILE *fp2;
1468 png_structp png_ptr1, png_ptr2;
1469 png_infop info_ptr1, info_ptr2;
1470 int width1, height1, width2, height2;
1471 png_byte color_type1, color_type2;
1472 png_byte bit_depth1, bit_depth2;
1473 png_bytep row1 = NULL, row2 = NULL;
1474 size_t rowbytes1, rowbytes2;
1475 int r;
1476
1477 fp1 = fopen(png1, "rb");
1478 if (!fp1) {
1479 return 2;
1480 }
1481 fp2 = fopen(png2, "rb");
1482 if (!fp2) {
1483 fclose(fp1);
1484 return 3;
1485 }
1486
1487 png_ptr1 = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, NULL, NULL);
1488 if (!png_ptr1) {
1489 fclose(fp1);
1490 fclose(fp2);
1491 return 4;
1492 }
1493 info_ptr1 = png_create_info_struct(png_ptr1);
1494 if (!info_ptr1) {
1495 png_destroy_read_struct(&png_ptr1, (png_infopp) NULL, (png_infopp) NULL);
1496 fclose(fp1);
1497 fclose(fp2);
1498 return 5;
1499 }
1500
1501 png_ptr2 = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL, NULL, NULL);
1502 if (!png_ptr2) {
1503 png_destroy_read_struct(&png_ptr1, &info_ptr1, (png_infopp) NULL);
1504 fclose(fp1);
1505 fclose(fp2);
1506 return 6;
1507 }
1508 info_ptr2 = png_create_info_struct(png_ptr2);
1509 if (!info_ptr2) {
1510 png_destroy_read_struct(&png_ptr1, &info_ptr1, (png_infopp) NULL);
1511 png_destroy_read_struct(&png_ptr2, (png_infopp) NULL, (png_infopp) NULL);
1512 fclose(fp1);
1513 fclose(fp2);
1514 return 7;
1515 }
1516
1517 if (setjmp(png_jmpbuf(png_ptr1))) {
1518 if (row1) {
1519 free(row1);
1520 }
1521 if (row2) {
1522 free(row2);
1523 }
1524 png_destroy_read_struct(&png_ptr1, &info_ptr1, (png_infopp) NULL);
1525 png_destroy_read_struct(&png_ptr2, &info_ptr2, (png_infopp) NULL);
1526 fclose(fp1);
1527 fclose(fp2);
1528 return 8;
1529 }
1530 if (setjmp(png_jmpbuf(png_ptr2))) {
1531 if (row1) {
1532 free(row1);
1533 }
1534 if (row2) {
1535 free(row2);
1536 }
1537 png_destroy_read_struct(&png_ptr1, &info_ptr1, (png_infopp) NULL);
1538 png_destroy_read_struct(&png_ptr2, &info_ptr2, (png_infopp) NULL);
1539 fclose(fp1);
1540 fclose(fp2);
1541 return 9;
1542 }
1543
1544 png_init_io(png_ptr1, fp1);
1545 png_init_io(png_ptr2, fp2);
1546
1547 png_read_info(png_ptr1, info_ptr1);
1548 png_read_info(png_ptr2, info_ptr2);
1549
1550 width1 = png_get_image_width(png_ptr1, info_ptr1);
1551 height1 = png_get_image_height(png_ptr1, info_ptr1);
1552 width2 = png_get_image_width(png_ptr2, info_ptr2);
1553 height2 = png_get_image_height(png_ptr2, info_ptr2);
1554
1555 if (width1 != width2 || height1 != height2) {
1556 printf("width1 %d, width2 %d, height1 %d, height2 %d\n", width1, width2, height1, height2);
1557 png_destroy_read_struct(&png_ptr1, &info_ptr1, (png_infopp) NULL);
1558 png_destroy_read_struct(&png_ptr2, &info_ptr2, (png_infopp) NULL);
1559 fclose(fp1);
1560 fclose(fp2);
1561 return 10;
1562 }
1563
1564 color_type1 = png_get_color_type(png_ptr1, info_ptr1);
1565 bit_depth1 = png_get_bit_depth(png_ptr1, info_ptr1);
1566 if (bit_depth1 == 16) {
1567 png_set_scale_16(png_ptr1);
1568 }
1569 if (color_type1 == PNG_COLOR_TYPE_PALETTE) {
1570 png_set_palette_to_rgb(png_ptr1);
1571 }
1572 if (color_type1 == PNG_COLOR_TYPE_GRAY && bit_depth1 < 8) {
1573 png_set_expand_gray_1_2_4_to_8(png_ptr1);
1574 }
1575 if (png_get_valid(png_ptr1, info_ptr1, PNG_INFO_tRNS)) {
1576 png_set_tRNS_to_alpha(png_ptr1);
1577 }
1578 if (color_type1 == PNG_COLOR_TYPE_RGB || color_type1 == PNG_COLOR_TYPE_GRAY
1579 || color_type1 == PNG_COLOR_TYPE_PALETTE) {
1580 png_set_filler(png_ptr1, 0xFF, PNG_FILLER_AFTER);
1581 }
1582 if (color_type1 == PNG_COLOR_TYPE_GRAY || color_type1 == PNG_COLOR_TYPE_GRAY_ALPHA) {
1583 png_set_gray_to_rgb(png_ptr1);
1584 }
1585
1586 color_type2 = png_get_color_type(png_ptr2, info_ptr2);
1587 bit_depth2 = png_get_bit_depth(png_ptr2, info_ptr2);
1588 if (bit_depth2 == 16) {
1589 png_set_scale_16(png_ptr2);
1590 }
1591 if (color_type2 == PNG_COLOR_TYPE_PALETTE) {
1592 png_set_palette_to_rgb(png_ptr2);
1593 }
1594 if (color_type2 == PNG_COLOR_TYPE_GRAY && bit_depth2 < 8) {
1595 png_set_expand_gray_1_2_4_to_8(png_ptr2);
1596 }
1597 if (png_get_valid(png_ptr2, info_ptr2, PNG_INFO_tRNS)) {
1598 png_set_tRNS_to_alpha(png_ptr2);
1599 }
1600 if (color_type2 == PNG_COLOR_TYPE_RGB || color_type2 == PNG_COLOR_TYPE_GRAY
1601 || color_type2 == PNG_COLOR_TYPE_PALETTE) {
1602 png_set_filler(png_ptr2, 0xFF, PNG_FILLER_AFTER);
1603 }
1604 if (color_type2 == PNG_COLOR_TYPE_GRAY || color_type2 == PNG_COLOR_TYPE_GRAY_ALPHA) {
1605 png_set_gray_to_rgb(png_ptr2);
1606 }
1607
1608 png_read_update_info(png_ptr1, info_ptr1);
1609 png_read_update_info(png_ptr2, info_ptr2);
1610
1611 rowbytes1 = png_get_rowbytes(png_ptr1, info_ptr1);
1612 rowbytes2 = png_get_rowbytes(png_ptr2, info_ptr2);
1613 if (rowbytes1 != rowbytes2) {
1614 png_destroy_read_struct(&png_ptr1, &info_ptr1, (png_infopp)NULL);
1615 png_destroy_read_struct(&png_ptr2, &info_ptr2, (png_infopp)NULL);
1616 fclose(fp1);
1617 fclose(fp2);
1618 return 11;
1619 }
1620
1621 row1 = malloc(rowbytes1);
1622 if (!row1) {
1623 png_destroy_read_struct(&png_ptr1, &info_ptr1, (png_infopp)NULL);
1624 png_destroy_read_struct(&png_ptr2, &info_ptr2, (png_infopp)NULL);
1625 fclose(fp1);
1626 fclose(fp2);
1627 return 12;
1628 }
1629 row2 = malloc(rowbytes2);
1630 if (!row2) {
1631 free(row1);
1632 png_destroy_read_struct(&png_ptr1, &info_ptr1, (png_infopp)NULL);
1633 png_destroy_read_struct(&png_ptr2, &info_ptr2, (png_infopp)NULL);
1634 fclose(fp1);
1635 fclose(fp2);
1636 return 13;
1637 }
1638
1639 for (r = 0; r < height1; r++) {
1640 png_read_row(png_ptr1, row1, NULL);
1641 png_read_row(png_ptr2, row2, NULL);
1642 if (memcmp(row1, row2, rowbytes1) != 0) {
1643 break;
1644 }
1645 }
1646 ret = r == height1 ? 0 : 20;
1647
1648 free(row1);
1649 free(row2);
1650 png_destroy_read_struct(&png_ptr1, &info_ptr1, (png_infopp)NULL);
1651 png_destroy_read_struct(&png_ptr2, &info_ptr2, (png_infopp)NULL);
1652 fclose(fp1);
1653 fclose(fp2);
1654 #endif
1655 return ret;
1656 }
1657
1658 /* Compare 2 TXT files */
testUtilCmpTxts(const char * txt1,const char * txt2)1659 int testUtilCmpTxts(const char *txt1, const char *txt2) {
1660 int ret = -1;
1661 FILE *fp1;
1662 FILE *fp2;
1663 char buf1[1024];
1664 char buf2[1024];
1665 size_t len1 = 0, len2 = 0;
1666
1667 fp1 = fopen(txt1, "r");
1668 if (!fp1) {
1669 return 2;
1670 }
1671 fp2 = fopen(txt2, "r");
1672 if (!fp2) {
1673 fclose(fp1);
1674 return 3;
1675 }
1676
1677 while (1) {
1678 if (fgets(buf1, sizeof(buf1), fp1) == NULL) {
1679 if (fgets(buf2, sizeof(buf2), fp2) != NULL) {
1680 ret = 4;
1681 break;
1682 }
1683 break;
1684 }
1685 if (fgets(buf2, sizeof(buf2), fp2) == NULL) {
1686 ret = 5;
1687 break;
1688 }
1689 len1 = strlen(buf1);
1690 len2 = strlen(buf2);
1691 if (len1 != len2) {
1692 ret = 6;
1693 break;
1694 }
1695 if (strcmp(buf1, buf2) != 0) {
1696 ret = 7;
1697 break;
1698 }
1699 }
1700 if (ret == -1) {
1701 ret = feof(fp1) && feof(fp2) ? 0 : 20;
1702 }
1703 fclose(fp1);
1704 fclose(fp2);
1705
1706 return ret;
1707 }
1708
1709 /* Compare 2 binary files */
testUtilCmpBins(const char * bin1,const char * bin2)1710 int testUtilCmpBins(const char *bin1, const char *bin2) {
1711 int ret = -1;
1712 FILE *fp1;
1713 FILE *fp2;
1714 char buf1[1024];
1715 char buf2[1024];
1716 size_t len1 = 0, len2 = 0;
1717
1718 fp1 = fopen(bin1, "rb");
1719 if (!fp1) {
1720 return 2;
1721 }
1722 fp2 = fopen(bin2, "rb");
1723 if (!fp2) {
1724 fclose(fp1);
1725 return 3;
1726 }
1727
1728 do {
1729 len1 = fread(buf1, 1, sizeof(buf1), fp1);
1730 len2 = fread(buf2, 1, sizeof(buf2), fp2);
1731 if (len1 != len2) {
1732 ret = 6;
1733 break;
1734 }
1735 if (memcmp(buf1, buf2, len1) != 0) {
1736 ret = 7;
1737 break;
1738 }
1739 } while (!feof(fp1) && !feof(fp2));
1740
1741 if (ret == -1) {
1742 ret = feof(fp1) && feof(fp2) ? 0 : 20;
1743 }
1744 fclose(fp1);
1745 fclose(fp2);
1746
1747 return ret;
1748 }
1749
1750 /* Compare 2 SVG files */
testUtilCmpSvgs(const char * svg1,const char * svg2)1751 int testUtilCmpSvgs(const char *svg1, const char *svg2) {
1752 return testUtilCmpTxts(svg1, svg2);
1753 }
1754
1755 /* Compare 2 EPS files */
testUtilCmpEpss(const char * eps1,const char * eps2)1756 int testUtilCmpEpss(const char *eps1, const char *eps2) {
1757 int ret = -1;
1758 FILE *fp1;
1759 FILE *fp2;
1760 char buf1[1024];
1761 char buf2[1024];
1762 size_t len1 = 0, len2 = 0;
1763 char first_line[] = "%!PS-Adobe-3.0 EPSF-3.0\n";
1764 char second_line_start[] = "%%Creator: Zint ";
1765
1766 fp1 = fopen(eps1, "r");
1767 if (!fp1) {
1768 return 2;
1769 }
1770 fp2 = fopen(eps2, "r");
1771 if (!fp2) {
1772 fclose(fp1);
1773 return 3;
1774 }
1775
1776 // Preprocess the 1st 2 lines to avoid comparing changeable Zint version in 2nd line
1777 if (fgets(buf1, sizeof(buf1), fp1) == NULL || strcmp(buf1, first_line) != 0
1778 || fgets(buf2, sizeof(buf2), fp2) == NULL || strcmp(buf2, first_line) != 0) {
1779 ret = 10;
1780 } else if (fgets(buf1, sizeof(buf1), fp1) == NULL
1781 || strncmp(buf1, second_line_start, sizeof(second_line_start) - 1) != 0
1782 || fgets(buf2, sizeof(buf2), fp2) == NULL
1783 || strncmp(buf2, second_line_start, sizeof(second_line_start) - 1) != 0) {
1784 ret = 11;
1785 }
1786
1787 if (ret == -1) {
1788 while (1) {
1789 if (fgets(buf1, sizeof(buf1), fp1) == NULL) {
1790 if (fgets(buf2, sizeof(buf2), fp2) != NULL) {
1791 ret = 4;
1792 break;
1793 }
1794 break;
1795 }
1796 if (fgets(buf2, sizeof(buf2), fp2) == NULL) {
1797 ret = 5;
1798 break;
1799 }
1800 len1 = strlen(buf1);
1801 len2 = strlen(buf2);
1802 if (len1 != len2) {
1803 ret = 6;
1804 break;
1805 }
1806 if (strcmp(buf1, buf2) != 0) {
1807 ret = 7;
1808 break;
1809 }
1810 }
1811 if (ret == -1) {
1812 ret = feof(fp1) && feof(fp2) ? 0 : 20;
1813 }
1814 }
1815 fclose(fp1);
1816 fclose(fp2);
1817
1818 return ret;
1819 }
1820
1821 #ifdef _WIN32
1822 #define DEV_NULL "> NUL"
1823 #define DEV_NULL_STDERR "> NUL 2>&1"
1824 #else
1825 #define DEV_NULL "> /dev/null"
1826 #define DEV_NULL_STDERR "> /dev/null 2>&1"
1827 #endif
1828
1829 /* Whether ImageMagick's identify utility available on system */
testUtilHaveIdentify()1830 int testUtilHaveIdentify() {
1831 return system("magick -version " DEV_NULL) == 0;
1832 }
1833
1834 /* Check raster files */
testUtilVerifyIdentify(const char * filename,int debug)1835 int testUtilVerifyIdentify(const char *filename, int debug) {
1836 char cmd[512 + 128];
1837
1838 if (strlen(filename) > 512) {
1839 return -1;
1840 }
1841 // Verbose option does a more thorough check
1842 if (debug & ZINT_DEBUG_TEST_PRINT) {
1843 // Verbose very noisy though so for quick check just return default output
1844 if (debug & ZINT_DEBUG_TEST_LESS_NOISY) {
1845 sprintf(cmd, "magick identify %s", filename);
1846 } else {
1847 sprintf(cmd, "magick identify -verbose %s", filename);
1848 }
1849 } else {
1850 sprintf(cmd, "magick identify -verbose %s " DEV_NULL, filename);
1851 }
1852
1853 return system(cmd);
1854 }
1855
1856 /* Whether Libre Office available on system */
testUtilHaveLibreOffice()1857 int testUtilHaveLibreOffice() {
1858 return system("libreoffice --version " DEV_NULL) == 0;
1859 }
1860
1861 /* Check SVG files, very hacky to evoke. Will fail if Libre package that is not LibreOffice Draw is running */
testUtilVerifyLibreOffice(const char * filename,int debug)1862 int testUtilVerifyLibreOffice(const char *filename, int debug) {
1863 char cmd[512 + 128];
1864 char svg[512];
1865 char *slash, *dot;
1866 char buf[16384];
1867 char *b = buf, *be = buf + sizeof(buf) - 1;
1868 FILE *fp;
1869 int len;
1870
1871 /* Hack to read SVG produced by LibreOffice and search for 'x="-32767"' which indicates it didn't load barcode
1872 file */
1873 if (strlen(filename) > 512) {
1874 return -1;
1875 }
1876 slash = strrchr(filename, '/');
1877 if (slash) {
1878 strcpy(svg, slash + 1);
1879 } else {
1880 strcpy(svg, filename);
1881 }
1882 dot = strrchr(svg, '.');
1883 if (dot) {
1884 strcpy(dot, ".svg");
1885 } else {
1886 strcat(svg, ".svg");
1887 }
1888 if (strcmp(svg, filename) == 0) {
1889 fprintf(stderr, "testUtilVerifyLibreOffice: input '%s' same as svg '%s'\n", filename, svg);
1890 return -1;
1891 }
1892
1893 sprintf(cmd, "libreoffice --convert-to svg %s " DEV_NULL_STDERR, filename);
1894 if (debug & ZINT_DEBUG_TEST_PRINT) {
1895 printf("%s\n", cmd);
1896 }
1897 if (system(cmd) != 0) {
1898 fprintf(stderr, "testUtilVerifyLibreOffice: failed to run '%s'\n", cmd);
1899 return -1;
1900 }
1901
1902 fp = fopen(svg, "r");
1903 if (!fp) {
1904 fprintf(stderr, "testUtilVerifyLibreOffice: failed to open '%s' (%s)\n", svg, cmd);
1905 return -1;
1906 }
1907 while (!feof(fp) && b < be) {
1908 if (fgets(b, be - b, fp) == NULL) {
1909 fprintf(stderr, "testUtilVerifyLibreOffice: failed to get line from '%s' (%s)\n", svg, cmd);
1910 fclose(fp);
1911 return -1;
1912 }
1913 len = (int) strlen(b);
1914 if (len == 0) {
1915 break;
1916 }
1917 b += len;
1918 }
1919 *b = '\0';
1920 fclose(fp);
1921
1922 if (strlen(buf) < 1024) {
1923 fprintf(stderr, "testUtilVerifyLibreOffice: failed to get much input from '%s' (%s)\n", svg, cmd);
1924 return -1;
1925 }
1926 if (strstr(buf, "x=\"-32767\"") != NULL) {
1927 return -1;
1928 }
1929 remove(svg);
1930
1931 return 0;
1932 }
1933
1934 #ifdef _WIN32
1935 #define GS_FILENAME "gswin64c"
1936 #else
1937 #define GS_FILENAME "gs"
1938 #endif
1939
1940 /* Whether Ghostscript available on system */
testUtilHaveGhostscript()1941 int testUtilHaveGhostscript() {
1942 return system(GS_FILENAME " -v " DEV_NULL) == 0;
1943 }
1944
1945 /* Check EPS files */
testUtilVerifyGhostscript(const char * filename,int debug)1946 int testUtilVerifyGhostscript(const char *filename, int debug) {
1947 char cmd[512 + 128];
1948
1949 if (strlen(filename) > 512) {
1950 return -1;
1951 }
1952 if (debug & ZINT_DEBUG_TEST_PRINT) {
1953 // Prints nothing of interest with or without -q unless bad
1954 sprintf(cmd, GS_FILENAME " -dNOPAUSE -dBATCH -dNODISPLAY -q %s", filename);
1955 printf("%s\n", cmd);
1956 } else {
1957 sprintf(cmd, GS_FILENAME " -dNOPAUSE -dBATCH -dNODISPLAY -q %s", filename);
1958 }
1959
1960 return system(cmd);
1961 }
1962
1963 /* Whether vnu validator available on system. v.Nu https://github.com/validator/validator
1964 Needs "$INSTALL_DIR/vnu-runtime-image/bin" in PATH */
testUtilHaveVnu()1965 int testUtilHaveVnu() {
1966 return system("vnu --version " DEV_NULL_STDERR) == 0;
1967 }
1968
1969 /* Check SVG files, very full but very slow */
testUtilVerifyVnu(const char * filename,int debug)1970 int testUtilVerifyVnu(const char *filename, int debug) {
1971 char buf[512 + 128];
1972
1973 if (strlen(filename) > 512) {
1974 return -1;
1975 }
1976 if (debug & ZINT_DEBUG_TEST_PRINT) {
1977 sprintf(buf, "vnu --svg --verbose %s", filename);
1978 printf("%s\n", buf);
1979 } else {
1980 sprintf(buf, "vnu --svg %s", filename);
1981 }
1982
1983 return system(buf);
1984 }
1985
1986 /* Whether tiffinfo available on system. Requires libtiff 4.2.0 http://www.libtiff.org to be installed */
testUtilHaveTiffInfo()1987 int testUtilHaveTiffInfo() {
1988 return system("tiffinfo -h " DEV_NULL) == 0;
1989 }
1990
1991 /* Check TIF files */
testUtilVerifyTiffInfo(const char * filename,int debug)1992 int testUtilVerifyTiffInfo(const char *filename, int debug) {
1993 char cmd[512 + 128];
1994
1995 if (strlen(filename) > 512) {
1996 return -1;
1997 }
1998 if (debug & ZINT_DEBUG_TEST_PRINT) {
1999 sprintf(cmd, "tiffinfo -D %s", filename);
2000 } else {
2001 sprintf(cmd, "tiffinfo -D %s " DEV_NULL_STDERR, filename);
2002 }
2003
2004 return system(cmd);
2005 }
2006
2007 /* Map Zint symbology to BWIPP routine */
testUtilBwippName(int index,const struct zint_symbol * symbol,int option_1,int option_2,int option_3,int debug,int * linear_row_height,int * gs1_cvt)2008 static const char *testUtilBwippName(int index, const struct zint_symbol *symbol, int option_1, int option_2,
2009 int option_3, int debug, int *linear_row_height, int *gs1_cvt) {
2010 struct item {
2011 const char *name;
2012 int define;
2013 int val;
2014 int can_option_1;
2015 int can_option_2;
2016 int can_option_3;
2017 int linear_row_height;
2018 int gs1_cvt;
2019 };
2020 static const struct item data[] = {
2021 { "", -1, 0, 0, 0, 0, 0, 0, },
2022 { "code11", BARCODE_CODE11, 1, 0, 1, 0, 0, 0, },
2023 { "matrix2of5", BARCODE_C25STANDARD, 2, 0, 1, 0, 0, 0, },
2024 { "interleaved2of5", BARCODE_C25INTER, 3, 0, 1, 0, 0, 0, },
2025 { "iata2of5", BARCODE_C25IATA, 4, 0, 1, 0, 0, 0, },
2026 { "", -1, 5, 0, 0, 0, 0, 0, },
2027 { "datalogic2of5", BARCODE_C25LOGIC, 6, 0, 1, 0, 0, 0, },
2028 { "industrial2of5", BARCODE_C25IND, 7, 0, 1, 0, 0, 0, },
2029 { "code39", BARCODE_CODE39, 8, 0, 1, 0, 0, 0, },
2030 { "code39ext", BARCODE_EXCODE39, 9, 0, 1, 0, 0, 0, },
2031 { "", -1, 10, 0, 0, 0, 0, 0, },
2032 { "", -1, 11, 0, 0, 0, 0, 0, },
2033 { "", -1, 12, 0, 0, 0, 0, 0, },
2034 { "ean13", BARCODE_EANX, 13, 0, 1, 0, 0, 1 /*gs1_cvt*/, },
2035 { "ean13", BARCODE_EANX_CHK, 14, 0, 1, 0, 0, 1, },
2036 { "", -1, 15, 0, 0, 0, 0, 0, },
2037 { "gs1-128", BARCODE_GS1_128, 16, 0, 0, 0, 0, 1 /*gs1_cvt*/, },
2038 { "", -1, 17, 0, 0, 0, 0, 0, },
2039 { "rationalizedCodabar", BARCODE_CODABAR, 18, 0, 1, 0, 0, 0, },
2040 { "", -1, 19, 0, 0, 0, 0, 0, },
2041 { "code128", BARCODE_CODE128, 20, 0, 0, 0, 0, 0, },
2042 { "leitcode", BARCODE_DPLEIT, 21, 0, 0, 0, 0, 0, },
2043 { "identcode", BARCODE_DPIDENT, 22, 0, 0, 0, 0, 0, },
2044 { "code16k", BARCODE_CODE16K, 23, 0, 0, 0, 8 /*linear_row_height*/, 0, },
2045 { "code49", BARCODE_CODE49, 24, 0, 0, 0, 8 /*linear_row_height*/, 0, },
2046 { "code93", BARCODE_CODE93, 25, 0, 0, 0, 0, 0, },
2047 { "", -1, 26, 0, 0, 0, 0, 0, },
2048 { "", -1, 27, 0, 0, 0, 0, 0, },
2049 { "flattermarken", BARCODE_FLAT, 28, 0, 0, 0, 0, 0, },
2050 { "databaromni", BARCODE_DBAR_OMN, 29, 0, 0, 0, 0, 1 /*gs1_cvt*/, },
2051 { "databarlimited", BARCODE_DBAR_LTD, 30, 0, 0, 0, 0, 1, },
2052 { "databarexpanded", BARCODE_DBAR_EXP, 31, 0, 1, 0, 1 /*linear_row_height*/, 1, },
2053 { "telepen", BARCODE_TELEPEN, 32, 0, 0, 0, 0, 0, },
2054 { "", -1, 33, 0, 0, 0, 0, 0, },
2055 { "upca", BARCODE_UPCA, 34, 0, 1, 0, 0, 1 /*gs1_cvt*/, },
2056 { "upca", BARCODE_UPCA_CHK, 35, 0, 1, 0, 0, 1, },
2057 { "", -1, 36, 0, 0, 0, 0, 0, },
2058 { "upce", BARCODE_UPCE, 37, 0, 1, 0, 0, 1 /*gs1_cvt*/, },
2059 { "upce", BARCODE_UPCE_CHK, 38, 0, 1, 0, 0, 1, },
2060 { "", -1, 39, 0, 0, 0, 0, 0, },
2061 { "postnet", BARCODE_POSTNET, 40, 0, 0, 0, 0, 0, },
2062 { "", -1, 41, 0, 0, 0, 0, 0, },
2063 { "", -1, 42, 0, 0, 0, 0, 0, },
2064 { "", -1, 43, 0, 0, 0, 0, 0, },
2065 { "", -1, 44, 0, 0, 0, 0, 0, },
2066 { "", -1, 45, 0, 0, 0, 0, 0, },
2067 { "", -1, 46, 0, 0, 0, 0, 0, },
2068 { "msi", BARCODE_MSI_PLESSEY, 47, 0, 1, 0, 0, 0, },
2069 { "", -1, 48, 0, 0, 0, 0, 0, },
2070 { "symbol", BARCODE_FIM, 49, 0, 0, 0, 0, 0, },
2071 { "code39", BARCODE_LOGMARS, 50, 0, 1, 0, 0, 0, },
2072 { "pharmacode", BARCODE_PHARMA, 51, 0, 0, 0, 1 /*linear_row_height*/, 0, },
2073 { "pzn", BARCODE_PZN, 52, 0, 0, 0, 0, 0, },
2074 { "pharmacode2", BARCODE_PHARMA_TWO, 53, 0, 0, 0, 0, 0, },
2075 { "", -1, 54, 0, 0, 0, 0, 0, },
2076 { "pdf417", BARCODE_PDF417, 55, 1, 1, 0, 0, 0, },
2077 { "pdf417compact", BARCODE_PDF417COMP, 56, 1, 1, 0, 0, 0, },
2078 { "maxicode", BARCODE_MAXICODE, 57, 1, 1, 0, 0, 0, },
2079 { "qrcode", BARCODE_QRCODE, 58, 0, 0, 0, 0, 0, },
2080 { "", -1, 59, 0, 0, 0, 0, 0, },
2081 { "", BARCODE_CODE128B, 60, 0, 0, 0, 0, 0, },
2082 { "", -1, 61, 0, 0, 0, 0, 0, },
2083 { "", -1, 62, 0, 0, 0, 0, 0, },
2084 { "auspost", BARCODE_AUSPOST, 63, 0, 0, 0, 0, 0, },
2085 { "", -1, 64, 0, 0, 0, 0, 0, },
2086 { "", -1, 65, 0, 0, 0, 0, 0, },
2087 { "", BARCODE_AUSREPLY, 66, 0, 0, 0, 0, 0, },
2088 { "", BARCODE_AUSROUTE, 67, 0, 0, 0, 0, 0, },
2089 { "", BARCODE_AUSREDIRECT, 68, 0, 0, 0, 0, 0, },
2090 { "isbn", BARCODE_ISBNX, 69, 0, 1, 0, 0, 1 /*gs1_cvt*/, },
2091 { "royalmail", BARCODE_RM4SCC, 70, 0, 0, 0, 0, 0, },
2092 { "datamatrix", BARCODE_DATAMATRIX, 71, 0, 1, 1, 1, 0, },
2093 { "ean14", BARCODE_EAN14, 72, 0, 0, 0, 0, 1 /*gs1_cvt*/, },
2094 { "code39", BARCODE_VIN, 73, 0, 0, 0, 0, 0, },
2095 { "codablockf", BARCODE_CODABLOCKF, 74, 1, 1, 0, 10 /*linear_row_height*/, 0, },
2096 { "sscc18", BARCODE_NVE18, 75, 0, 0, 0, 0, 1 /*gs1_cvt*/, },
2097 { "japanpost", BARCODE_JAPANPOST, 76, 0, 0, 0, 0, 0, },
2098 { "", BARCODE_KOREAPOST, 77, 0, 0, 0, 0, 0, },
2099 { "", -1, 78, 0, 0, 0, 0, 0, },
2100 { "databarstacked", BARCODE_DBAR_STK, 79, 0, 0, 0, 0, 1 /*gs1_cvt*/, },
2101 { "databarstackedomni", BARCODE_DBAR_OMNSTK, 80, 0, 0, 0, 33 /*linear_row_height*/, 1, },
2102 { "databarexpandedstacked", BARCODE_DBAR_EXPSTK, 81, 0, 1, 0, 34 /*linear_row_height*/, 1, },
2103 { "planet", BARCODE_PLANET, 82, 0, 0, 0, 0, 0, },
2104 { "", -1, 83, 0, 0, 0, 0, 0, },
2105 { "micropdf417", BARCODE_MICROPDF417, 84, 0, 1, 0, 0, 0, },
2106 { "onecode", BARCODE_USPS_IMAIL, 85, 0, 0, 0, 0, 0, },
2107 { "plessey", BARCODE_PLESSEY, 86, 0, 0, 0, 0, 0, },
2108 { "telepennumeric", BARCODE_TELEPEN_NUM, 87, 0, 0, 0, 0, 0, },
2109 { "", -1, 88, 0, 0, 0, 0, 0, },
2110 { "itf14", BARCODE_ITF14, 89, 0, 0, 0, 0, 0, },
2111 { "kix", BARCODE_KIX, 90, 0, 0, 0, 0, 0, },
2112 { "", -1, 91, 0, 0, 0, 0, 0, },
2113 { "azteccode", BARCODE_AZTEC, 92, 1, 1, 0, 0, 0, },
2114 { "daft", BARCODE_DAFT, 93, 0, 0, 0, 0, 0, },
2115 { "", -1, 94, 0, 0, 0, 0, 0, },
2116 { "", -1, 95, 0, 0, 0, 0, 0, },
2117 { "", BARCODE_DPD, 96, 0, 0, 0, 0, 0, },
2118 { "microqrcode", BARCODE_MICROQR, 97, 1, 1, 1, 0, 0, },
2119 { "hibccode128", BARCODE_HIBC_128, 98, 0, 0, 0, 0, 0, },
2120 { "hibccode39", BARCODE_HIBC_39, 99, 0, 0, 0, 0, 0, },
2121 { "", -1, 100, 0, 0, 0, 0, 0, },
2122 { "", -1, 101, 0, 0, 0, 0, 0, },
2123 { "hibcdatamatrix", BARCODE_HIBC_DM, 102, 0, 1, 1, 0, 0, },
2124 { "", -1, 103, 0, 0, 0, 0, 0, },
2125 { "hibcqrcode", BARCODE_HIBC_QR, 104, 0, 0, 0, 0, 0, },
2126 { "", -1, 105, 0, 0, 0, 0, 0, },
2127 { "hibcpdf417", BARCODE_HIBC_PDF, 106, 1, 1, 0, 0, 0, },
2128 { "", -1, 107, 0, 0, 0, 0, 0, },
2129 { "hibcmicropdf417", BARCODE_HIBC_MICPDF, 108, 0, 1, 0, 0, 0, },
2130 { "", -1, 109, 0, 0, 0, 0, 0, },
2131 { "hibccodablockf", BARCODE_HIBC_BLOCKF, 110, 1, 1, 0, 10 /*linear_row_height*/, 0, },
2132 { "", -1, 111, 0, 0, 0, 0, 0, },
2133 { "hibcazteccode", BARCODE_HIBC_AZTEC, 112, 1, 0, 1, 0, 0, },
2134 { "", -1, 113, 0, 0, 0, 0, 0, },
2135 { "", -1, 114, 0, 0, 0, 0, 0, },
2136 { "dotcode", BARCODE_DOTCODE, 115, 0, 1, 1, 0, 0, },
2137 { "hanxin", BARCODE_HANXIN, 116, 0, 0, 0, 0, 0, },
2138 { "", -1, 117, 0, 0, 0, 0, 0, },
2139 { "", -1, 118, 0, 0, 0, 0, 0, },
2140 { "", -1, 119, 0, 0, 0, 0, 0, },
2141 { "", -1, 120, 0, 0, 0, 0, 0, },
2142 { "", BARCODE_MAILMARK, 121, 0, 0, 0, 0, 0, }, /* Note BWIPP mailmark is Data Matrix variant */
2143 { "", -1, 122, 0, 0, 0, 0, 0, },
2144 { "", -1, 123, 0, 0, 0, 0, 0, },
2145 { "", -1, 124, 0, 0, 0, 0, 0, },
2146 { "", -1, 125, 0, 0, 0, 0, 0, },
2147 { "", -1, 126, 0, 0, 0, 0, 0, },
2148 { "", -1, 127, 0, 0, 0, 0, 0, },
2149 { "aztecrune", BARCODE_AZRUNE, 128, 0, 0, 0, 0, 0, },
2150 { "code32", BARCODE_CODE32, 129, 0, 0, 0, 0, 0, },
2151 { "ean13composite", BARCODE_EANX_CC, 130, 1, 1, 0, 72 /*linear_row_height*/, 1 /*gs1_cvt*/, },
2152 { "gs1-128composite", BARCODE_GS1_128_CC, 131, 1, 0, 0, 36, 1, },
2153 { "databaromnicomposite", BARCODE_DBAR_OMN_CC, 132, 1, 0, 0, 33, 1, },
2154 { "databarlimitedcomposite", BARCODE_DBAR_LTD_CC, 133, 1, 0, 0, 10 /*linear_row_height*/, 1, },
2155 { "databarexpandedcomposite", BARCODE_DBAR_EXP_CC, 134, 1, 1, 0, 34 /*linear_row_height*/, 1, },
2156 { "upcacomposite", BARCODE_UPCA_CC, 135, 1, 1, 0, 72, 1, },
2157 { "upcecomposite", BARCODE_UPCE_CC, 136, 1, 1, 0, 72, 1, },
2158 { "databarstackedcomposite", BARCODE_DBAR_STK_CC, 137, 1, 0, 0, 0, 1, },
2159 { "databarstackedomnicomposite", BARCODE_DBAR_OMNSTK_CC, 138, 1, 0, 0, 33 /*linear_row_height*/, 1, },
2160 { "databarexpandedstackedcomposite", BARCODE_DBAR_EXPSTK_CC, 139, 1, 1, 0, 34 /*linear_row_height*/, 1, },
2161 { "channelcode", BARCODE_CHANNEL, 140, 0, 0, 0, 0, 0, },
2162 { "codeone", BARCODE_CODEONE, 141, 0, 1, 0, 0, 0, },
2163 { "", BARCODE_GRIDMATRIX, 142, 0, 0, 0, 0, 0, },
2164 { "", BARCODE_UPNQR, 143, 0, 0, 0, 0, 0, },
2165 { "ultracode", BARCODE_ULTRA, 144, 1, 0, 0, 0, 0, },
2166 { "rectangularmicroqrcode", BARCODE_RMQR, 145, 1, 1, 0, 0, 0, },
2167 };
2168 static const int data_size = ARRAY_SIZE(data);
2169
2170 int symbology = symbol->symbology;
2171 int gs1 = (symbol->input_mode & 0x07) == GS1_MODE;
2172
2173 if (symbology < 0 || symbology >= data_size) {
2174 fprintf(stderr, "testUtilBwippName: unknown symbology (%d)\n", symbology);
2175 abort();
2176 }
2177 // Self-check
2178 if (data[symbology].val != symbology || (data[symbology].define != -1 && data[symbology].define != symbology)) {
2179 fprintf(stderr, "testUtilBwippName: data table out of sync (%d)\n", symbology);
2180 abort();
2181 }
2182 if (data[symbology].name[0] == '\0') {
2183 if (debug & ZINT_DEBUG_TEST_PRINT) {
2184 printf("i:%d %s no BWIPP mapping\n", index, testUtilBarcodeName(symbology));
2185 }
2186 return NULL;
2187 }
2188 if ((option_1 != -1 && !data[symbology].can_option_1) || (option_2 != -1 && !data[symbology].can_option_2)
2189 || (option_3 != -1 && !data[symbology].can_option_3)) {
2190 if (debug & ZINT_DEBUG_TEST_PRINT) {
2191 printf("i:%d %s not BWIPP compatible, options not supported, option_1 %d, option_2 %d, option_3 %d\n",
2192 index, testUtilBarcodeName(symbology), option_1, option_2, option_3);
2193 }
2194 return NULL;
2195 }
2196
2197 if (symbology == BARCODE_CODE11) {
2198 if (option_2 != 1 && option_2 != 2) { /* 2 check digits (Zint default) not supported */
2199 if (debug & ZINT_DEBUG_TEST_PRINT) {
2200 printf("i:%d %s not BWIPP compatible, 2 check digits not supported, option_1 %d, option_2 %d\n",
2201 index, testUtilBarcodeName(symbology), option_1, option_2);
2202 }
2203 return NULL;
2204 }
2205 } else if (symbology == BARCODE_CODABLOCKF || symbology == BARCODE_HIBC_BLOCKF) {
2206 if (option_1 == 1) { /* Single row i.e. CODE128 not supported */
2207 if (debug & ZINT_DEBUG_TEST_PRINT) {
2208 printf("i:%d %s not BWIPP compatible, single row not supported, option_1 %d\n",
2209 index, testUtilBarcodeName(symbology), option_1);
2210 }
2211 return NULL;
2212 }
2213 } else if (symbology == BARCODE_AZTEC) {
2214 if (option_1 > 0 && option_2 > 0) {
2215 if (debug & ZINT_DEBUG_TEST_PRINT) {
2216 printf("i:%d %s not BWIPP compatible, cannot specify both option_1 %d and option_2 %d\n",
2217 index, testUtilBarcodeName(symbology), option_1, option_2);
2218 }
2219 return NULL;
2220 }
2221 } else if (symbology == BARCODE_RMQR) {
2222 if (option_2 < 1) {
2223 if (debug & ZINT_DEBUG_TEST_PRINT) {
2224 printf("i:%d %s not BWIPP compatible, version (option_2) must be specified\n",
2225 index, testUtilBarcodeName(symbology));
2226 }
2227 return NULL;
2228 }
2229 if (option_2 > 32) {
2230 if (debug & ZINT_DEBUG_TEST_PRINT) {
2231 printf("i:%d %s not BWIPP compatible, auto width (option_2 > 32) not supported\n",
2232 index, testUtilBarcodeName(symbology));
2233 }
2234 return NULL;
2235 }
2236 }
2237
2238 if (linear_row_height) {
2239 *linear_row_height = data[symbology].linear_row_height;
2240 }
2241 if (gs1_cvt) {
2242 *gs1_cvt = data[symbology].gs1_cvt;
2243 }
2244 if (gs1) {
2245 if (symbology == BARCODE_DATAMATRIX) {
2246 if (gs1_cvt) {
2247 *gs1_cvt = 1;
2248 }
2249 return "gs1datamatrix";
2250 } else if (symbology == BARCODE_AZTEC || symbology == BARCODE_ULTRA) {
2251 if (debug & ZINT_DEBUG_TEST_PRINT) {
2252 printf("i:%d %s not BWIPP compatible, GS1_MODE not supported\n",
2253 index, testUtilBarcodeName(symbology));
2254 }
2255 return NULL;
2256 } else if (symbology == BARCODE_DOTCODE) {
2257 if (gs1_cvt) {
2258 *gs1_cvt = 1;
2259 }
2260 return "gs1dotcode";
2261 }
2262 }
2263
2264 return data[symbology].name;
2265 }
2266
2267 /* Whether can use BWIPP to check a symbology with given options */
testUtilCanBwipp(int index,const struct zint_symbol * symbol,int option_1,int option_2,int option_3,int debug)2268 int testUtilCanBwipp(int index, const struct zint_symbol *symbol, int option_1, int option_2, int option_3,
2269 int debug) {
2270 return testUtilBwippName(index, symbol, option_1, option_2, option_3, debug, NULL, NULL) != NULL;
2271 }
2272
2273 /* Convert Zint GS1 and add-on format to BWIPP's */
testUtilBwippCvtGS1Data(char * bwipp_data,int upcean,int * addon_posn)2274 static void testUtilBwippCvtGS1Data(char *bwipp_data, int upcean, int *addon_posn) {
2275 char *b;
2276 int pipe = 0;
2277
2278 *addon_posn = 0;
2279 for (b = bwipp_data; *b; b++) {
2280 if (upcean && *b == '|') {
2281 pipe = 1;
2282 }
2283 if (*b == '[') {
2284 *b = '(';
2285 } else if (*b == ']') {
2286 *b = ')';
2287 } else if (*b == '+' && upcean && !pipe) {
2288 *b = ' ';
2289 *addon_posn = b - bwipp_data;
2290 }
2291 }
2292 }
2293
2294 /* Convert data to Ghostscript format for passing to bwipp_dump.ps */
testUtilBwippEscape(char * bwipp_data,int bwipp_data_size,const char * data,int length,int zint_escape_mode,int eci,int * parse,int * parsefnc)2295 static char *testUtilBwippEscape(char *bwipp_data, int bwipp_data_size, const char *data, int length,
2296 int zint_escape_mode, int eci, int *parse, int *parsefnc) {
2297 char *b = bwipp_data;
2298 char *be = b + bwipp_data_size;
2299 unsigned char *d = (unsigned char *) data;
2300 unsigned char *de = (unsigned char *) data + length;
2301
2302 *parse = *parsefnc = 0;
2303
2304 if (eci) {
2305 sprintf(bwipp_data, "^ECI%06d", eci);
2306 *parsefnc = 1;
2307 b = bwipp_data + 10;
2308 }
2309
2310 while (b < be && d < de) {
2311 /* Have to escape double quote otherwise Ghostscript gives "Unterminated quote in @-file" for some reason */
2312 /* Escape single quote also to avoid having to do proper shell escaping TODO: proper shell escaping */
2313 if (*d < 0x20 || *d >= 0x7F || *d == '^' || *d == '"' || *d == '\'') {
2314 if (b + 4 >= be) {
2315 fprintf(stderr, "testUtilBwippEscape: double quote bwipp_data buffer full (%d)\n", bwipp_data_size);
2316 return NULL;
2317 }
2318 sprintf(b, "^%03u", *d++);
2319 b += 4;
2320 *parse = 1;
2321 } else if (zint_escape_mode && *d == '\\' && d + 1 < de) {
2322 int val;
2323 switch (*++d) {
2324 case '0': val = 0x00; /* Null */ break;
2325 case 'E': val = 0x04; /* End of Transmission */ break;
2326 case 'a': val = 0x07; /* Bell */ break;
2327 case 'b': val = 0x08; /* Backspace */ break;
2328 case 't': val = 0x09; /* Horizontal tab */ break;
2329 case 'n': val = 0x0a; /* Line feed */ break;
2330 case 'v': val = 0x0b; /* Vertical tab */ break;
2331 case 'f': val = 0x0c; /* Form feed */ break;
2332 case 'r': val = 0x0d; /* Carriage return */ break;
2333 case 'e': val = 0x1b; /* Escape */ break;
2334 case 'G': val = 0x1d; /* Group Separator */ break;
2335 case 'R': val = 0x1e; /* Record Separator */ break;
2336 //case 'x': val = 0; /* TODO: implement */ break;
2337 case '\\': val = '\\'; break;
2338 //case 'u': val = 0; /* TODO: implement */ break;
2339 default: fprintf(stderr, "testUtilBwippEscape: unknown escape %c\n", *d); return NULL; break;
2340 }
2341 if (b + 4 >= be) {
2342 fprintf(stderr, "testUtilBwippEscape: loop bwipp_data buffer full (%d)\n", bwipp_data_size);
2343 return NULL;
2344 }
2345 sprintf(b, "^%03d", val);
2346 b += 4;
2347 d++;
2348 *parse = 1;
2349 } else {
2350 *b++ = *d++;
2351 }
2352 }
2353
2354 if (b == be && d < de) {
2355 fprintf(stderr, "testUtilBwippEscape: end bwipp_data buffer full (%d)\n", bwipp_data_size);
2356 return NULL;
2357 }
2358 *b = '\0';
2359
2360 return bwipp_data;
2361 }
2362
2363 /* Convert ISBN to BWIPP format */
testUtilISBNHyphenate(char * bwipp_data,int addon_posn)2364 static void testUtilISBNHyphenate(char *bwipp_data, int addon_posn) {
2365 /* Hack in 4 hyphens in fixed format, wrong for many ISBNs */
2366 char temp[13 + 4 + 1 + 5 + 1];
2367 int len = (int) strlen(bwipp_data);
2368 int i, j;
2369
2370 if (len < 13 || (addon_posn && addon_posn < 13 ) || len >= (int) sizeof(temp)) {
2371 return;
2372 }
2373 for (i = 0, j = 0; i <= len; i++, j++) {
2374 if (i == 3 || i == 5 || i == 10 || i == 12) {
2375 temp[j++] = '-';
2376 }
2377 temp[j] = bwipp_data[i];
2378 }
2379 strcpy(bwipp_data, temp);
2380 }
2381
2382 #define GS_INITIAL_LEN 35 /* Length of cmd up to -q */
2383
2384 /* Create bwipp_dump.ps command and run */
testUtilBwipp(int index,const struct zint_symbol * symbol,int option_1,int option_2,int option_3,const char * data,int length,const char * primary,char * buffer,int buffer_size)2385 int testUtilBwipp(int index, const struct zint_symbol *symbol, int option_1, int option_2, int option_3,
2386 const char *data, int length, const char *primary, char *buffer, int buffer_size) {
2387 const char *cmd_fmt = "gs -dNOPAUSE -dBATCH -dNODISPLAY -q -sb=%s -sd='%s' backend/tests/tools/bwipp_dump.ps";
2388 const char *cmd_opts_fmt = "gs -dNOPAUSE -dBATCH -dNODISPLAY -q -sb=%s -sd='%s' -so='%s'"
2389 " backend/tests/tools/bwipp_dump.ps";
2390 // If data > 2K
2391 const char *cmd_fmt2 = "gs -dNOPAUSE -dBATCH -dNODISPLAY -q -sb=%s -sd='%.2043s' -sd2='%s'"
2392 " backend/tests/tools/bwipp_dump.ps";
2393 const char *cmd_opts_fmt2 = "gs -dNOPAUSE -dBATCH -dNODISPLAY -q -sb=%s -sd='%.2043s' -sd2='%s' -so='%s'"
2394 " backend/tests/tools/bwipp_dump.ps";
2395
2396 int symbology = symbol->symbology;
2397 int data_len = length == -1 ? (int) strlen(data) : length;
2398 int primary_len = primary ? (int) strlen(primary) : 0;
2399 /* 4 AI prefix + primary + '|' + leading zero + escaped data + fudge */
2400 int max_data_len = 4 + primary_len + 1 + 1 + data_len * 4 + 64;
2401
2402 int eci_length = get_eci_length(symbol->eci, (const unsigned char *) data, data_len);
2403 char *converted = (char *) testutil_alloca(eci_length + 1);
2404 char *cmd = (char *) testutil_alloca(max_data_len + 1024);
2405 const char *bwipp_barcode = NULL;
2406 char *bwipp_opts = NULL;
2407 int bwipp_data_size = max_data_len + 1;
2408 char *bwipp_data = (char *) testutil_alloca(bwipp_data_size);
2409 char bwipp_opts_buf[512];
2410 int *bwipp_row_height = (int *) testutil_alloca(sizeof(int) * symbol->rows);
2411 int linear_row_height;
2412 int gs1_cvt;
2413 int user_mask;
2414
2415 FILE *fp = NULL;
2416 int cnt;
2417
2418 char *b = buffer;
2419 char *be = buffer + buffer_size;
2420 int r, h;
2421 int parse, parsefnc;
2422
2423 int upcean = is_extendable(symbology);
2424 int upca = symbology == BARCODE_UPCA || symbology == BARCODE_UPCA_CHK || symbology == BARCODE_UPCA_CC;
2425 char obracket = symbol->input_mode & GS1PARENS_MODE ? '(' : '[';
2426 char cbracket = symbol->input_mode & GS1PARENS_MODE ? ')' : ']';
2427 int addon_posn;
2428 int eci;
2429 int i, j, len;
2430
2431 bwipp_data[0] = bwipp_opts_buf[0] = '\0';
2432
2433 bwipp_barcode = testUtilBwippName(index, symbol, option_1, option_2, option_3, 0, &linear_row_height, &gs1_cvt);
2434 if (!bwipp_barcode) {
2435 fprintf(stderr, "i:%d testUtilBwipp: no mapping for %s, option_1 %d, option_2 %d, option_3 %d\n",
2436 index, testUtilBarcodeName(symbology), option_1, option_2, option_3);
2437 return -1;
2438 }
2439
2440 for (r = 0; r < symbol->rows; r++) {
2441 if (symbology == BARCODE_MAXICODE) {
2442 bwipp_row_height[r] = 1;
2443 } else {
2444 bwipp_row_height[r] = symbol->row_height[r] ? symbol->row_height[r] : linear_row_height;
2445 }
2446 if ((symbol->debug & ZINT_DEBUG_TEST_PRINT) && !(symbol->debug & ZINT_DEBUG_TEST_LESS_NOISY)) {
2447 fprintf(stderr, "bwipp_row_height[%d] %d, symbol->row_height[%d] %g\n",
2448 r, bwipp_row_height[r], r, symbol->row_height[r]);
2449 }
2450 }
2451
2452 if ((symbol->input_mode & 0x07) == UNICODE_MODE && ZBarcode_Cap(symbology, ZINT_CAP_ECI)
2453 && is_eci_convertible(symbol->eci)) {
2454 if (utf8_to_eci(symbol->eci, (const unsigned char *) data, (unsigned char *) converted, &data_len) == 0) {
2455 eci = symbol->eci;
2456 } else {
2457 if (symbol->eci != 0) {
2458 eci = get_best_eci((const unsigned char *) data, data_len);
2459 if (utf8_to_eci(eci, (const unsigned char *) data, (unsigned char *) converted, &data_len) != 0) {
2460 fprintf(stderr, "i:%d testUtilBwipp: failed to convert Unicode data for %s\n",
2461 index, testUtilBarcodeName(symbology));
2462 return -1;
2463 }
2464 } else {
2465 fprintf(stderr, "i:%d testUtilBwipp: failed to convert Unicode data for %s\n",
2466 index, testUtilBarcodeName(symbology));
2467 return -1;
2468 }
2469 }
2470 data = converted;
2471 } else {
2472 eci = symbol->eci >= 3 && ZBarcode_Cap(symbology, ZINT_CAP_ECI) ? symbol->eci : 0;
2473 }
2474
2475 if (is_composite(symbology)) {
2476 if (!primary) {
2477 fprintf(stderr, "i:%d testUtilBwipp: no primary data given %s\n", index, testUtilBarcodeName(symbology));
2478 return -1;
2479 }
2480 if (*primary != obracket && !upcean) {
2481 strcat(bwipp_data, "(01)");
2482 }
2483 strcat(bwipp_data, primary);
2484 strcat(bwipp_data, "|");
2485 strcat(bwipp_data, data);
2486 testUtilBwippCvtGS1Data(bwipp_data, upcean, &addon_posn);
2487
2488 if (upcean) {
2489 if (symbology == BARCODE_EANX_CC && (primary_len <= 8 || (addon_posn && addon_posn <= 8))) {
2490 bwipp_barcode = "ean8composite";
2491 }
2492 if (addon_posn) {
2493 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%saddongap=%d",
2494 strlen(bwipp_opts_buf) ? " " : "", option_2 > 0 ? option_2 : upca ? 9 : 7);
2495 bwipp_opts = bwipp_opts_buf;
2496 }
2497 bwipp_row_height[symbol->rows - 1] = 72;
2498 }
2499
2500 if (option_1 > 0) {
2501 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sccversion=%c",
2502 strlen(bwipp_opts_buf) ? " " : "", option_1 == 1 ? 'a' : option_1 == 2 ? 'b' : 'c');
2503 bwipp_opts = bwipp_opts_buf;
2504 }
2505 if (option_2 > 0) {
2506 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%ssegments=%d",
2507 strlen(bwipp_opts_buf) ? " " : "", option_2 * 2);
2508 bwipp_opts = bwipp_opts_buf;
2509 }
2510
2511 if (symbol->input_mode & GS1NOCHECK_MODE) {
2512 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sdontlint", strlen(bwipp_opts_buf) ? " " : "");
2513 bwipp_opts = bwipp_opts_buf;
2514 }
2515 } else {
2516 if (gs1_cvt) {
2517 if (*data != obracket && !upcean) {
2518 strcat(bwipp_data, symbology == BARCODE_NVE18 ? "(00)" : "(01)");
2519 }
2520 strcat(bwipp_data, data);
2521 testUtilBwippCvtGS1Data(bwipp_data, upcean, &addon_posn);
2522
2523 if (upcean) {
2524 if ((symbology == BARCODE_EANX || symbology == BARCODE_EANX_CHK)
2525 && (data_len <= 8 || (addon_posn && addon_posn <= 8))) {
2526 bwipp_barcode = data_len <= 3 ? "ean2" : data_len <= 5 ? "ean5" : "ean8";
2527 }
2528 if (symbology == BARCODE_ISBNX) {
2529 testUtilISBNHyphenate(bwipp_data, addon_posn);
2530 }
2531 if (addon_posn) {
2532 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%saddongap=%d",
2533 strlen(bwipp_opts_buf) ? " " : "", option_2 > 0 ? option_2 : upca ? 9 : 7);
2534 bwipp_opts = bwipp_opts_buf;
2535 }
2536 }
2537
2538 if (option_2 > 0) {
2539 if (symbology == BARCODE_DBAR_EXP || symbology == BARCODE_DBAR_EXPSTK) {
2540 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%ssegments=%d",
2541 strlen(bwipp_opts_buf) ? " " : "", option_2 * 2);
2542 bwipp_opts = bwipp_opts_buf;
2543 }
2544 }
2545
2546 if (symbol->input_mode & GS1NOCHECK_MODE) {
2547 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sdontlint", strlen(bwipp_opts_buf) ? " " : "");
2548 bwipp_opts = bwipp_opts_buf;
2549 }
2550 } else {
2551 if (testUtilBwippEscape(bwipp_data, bwipp_data_size, data, data_len, symbol->input_mode & ESCAPE_MODE,
2552 eci, &parse, &parsefnc) == NULL) {
2553 return -1;
2554 }
2555 if (parse) {
2556 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sparse", strlen(bwipp_opts_buf) ? " " : "");
2557 bwipp_opts = bwipp_opts_buf;
2558 }
2559 if (parsefnc) {
2560 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sparsefnc",
2561 strlen(bwipp_opts_buf) ? " " : "");
2562 bwipp_opts = bwipp_opts_buf;
2563 }
2564
2565 if (symbology == BARCODE_C25STANDARD || symbology == BARCODE_C25INTER || symbology == BARCODE_C25IATA
2566 || symbology == BARCODE_C25LOGIC || symbology == BARCODE_C25IND) {
2567 if (option_2 == 1 || option_2 == 2) { // Add check digit without or with HRT suppression
2568 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sincludecheck",
2569 strlen(bwipp_opts_buf) ? " " : "");
2570 bwipp_opts = bwipp_opts_buf;
2571 }
2572 } else if (symbology == BARCODE_CODE93) {
2573 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sincludecheck",
2574 strlen(bwipp_opts_buf) ? " " : "");
2575 if (parse) {
2576 bwipp_barcode = "code93ext";
2577 }
2578 bwipp_opts = bwipp_opts_buf;
2579 } else if (symbology == BARCODE_PZN) {
2580 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%spzn8", strlen(bwipp_opts_buf) ? " " : "");
2581 bwipp_opts = bwipp_opts_buf;
2582 } else if (symbology == BARCODE_TELEPEN_NUM) {
2583 if (data_len & 1) { // Add leading zero
2584 memmove(bwipp_data + 1, bwipp_data, strlen(bwipp_data) + 1);
2585 *bwipp_data = '0';
2586 }
2587 } else if (symbology == BARCODE_CODABLOCKF || symbology == BARCODE_HIBC_BLOCKF) {
2588 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%ssepheight=0", strlen(bwipp_opts_buf) ? " " : "");
2589 if (option_1 > 0) {
2590 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%srows=%d",
2591 strlen(bwipp_opts_buf) ? " " : "", option_1);
2592 }
2593 if (option_2 > 0) {
2594 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%scolumns=%d",
2595 strlen(bwipp_opts_buf) ? " " : "", option_2 - 5);
2596 } else {
2597 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%scolumns=%d",
2598 strlen(bwipp_opts_buf) ? " " : "", (symbol->width - 57) / 11);
2599 }
2600 bwipp_opts = bwipp_opts_buf;
2601 } else if (symbology == BARCODE_CODE11 || symbology == BARCODE_CODE39 || symbology == BARCODE_EXCODE39
2602 || symbology == BARCODE_LOGMARS || symbology == BARCODE_CODABAR) {
2603 if (option_2 > 0) {
2604 if (option_2 == 1) {
2605 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sincludecheck",
2606 strlen(bwipp_opts_buf) ? " " : "");
2607 }
2608 bwipp_opts = bwipp_opts_buf; /* Set always as option_2 == 2 is bwipp default */
2609 }
2610 } else if (symbology == BARCODE_PLESSEY) {
2611 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sincludecheck", strlen(bwipp_opts_buf) ? " " : "");
2612 bwipp_opts = bwipp_opts_buf;
2613 } else if (symbology == BARCODE_MSI_PLESSEY) {
2614 if (option_2 > 0) {
2615 const char *checktype = NULL;
2616 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sincludecheck",
2617 strlen(bwipp_opts_buf) ? " " : "");
2618
2619 if (option_2 >= 11 && option_2 <= 16) {
2620 option_2 -= 10; /* Remove no-check indicator */
2621 }
2622 if (option_2 == 2) {
2623 checktype = "mod1010";
2624 } else if (option_2 == 3) {
2625 checktype = "mod11 badmod11";
2626 } else if (option_2 == 4) {
2627 checktype = "mod1110 badmod11";
2628 } else if (option_2 == 5) {
2629 checktype = "ncrmod11 badmod11";
2630 } else if (option_2 == 6) {
2631 checktype = "ncrmod1110 badmod11";
2632 }
2633 if (checktype) {
2634 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%schecktype=%s",
2635 strlen(bwipp_opts_buf) ? " " : "", checktype);
2636 }
2637 bwipp_opts = bwipp_opts_buf;
2638 }
2639 } else if (symbology == BARCODE_PDF417 || symbology == BARCODE_PDF417COMP || symbology == BARCODE_HIBC_PDF
2640 || symbology == BARCODE_MICROPDF417 || symbology == BARCODE_HIBC_MICPDF) {
2641 for (r = 0; r < symbol->rows; r++) bwipp_row_height[r] = 1; /* Change from 3 */
2642 if (option_1 >= 0) {
2643 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%seclevel=%d",
2644 strlen(bwipp_opts_buf) ? " " : "", option_1);
2645 bwipp_opts = bwipp_opts_buf;
2646 }
2647 if (option_2 > 0) {
2648 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%scolumns=%d",
2649 strlen(bwipp_opts_buf) ? " " : "", option_2);
2650 bwipp_opts = bwipp_opts_buf;
2651 }
2652 } else if (symbology == BARCODE_POSTNET || symbology == BARCODE_PLANET || symbology == BARCODE_RM4SCC
2653 || symbology == BARCODE_JAPANPOST || symbology == BARCODE_KIX || symbology == BARCODE_DAFT
2654 || symbology == BARCODE_USPS_IMAIL || symbology == BARCODE_AUSPOST
2655 || symbology == BARCODE_PHARMA_TWO) {
2656 for (r = 0; r < symbol->rows; r++) bwipp_row_height[r] = 1; /* Zap */
2657 if (symbology == BARCODE_KIX) {
2658 to_upper((unsigned char *) bwipp_data);
2659 } else if (symbology == BARCODE_USPS_IMAIL) {
2660 char *dash = strchr(bwipp_data, '-');
2661 if (dash) {
2662 memmove(dash, dash + 1, strlen(dash));
2663 }
2664 } else if (symbology == BARCODE_AUSPOST) {
2665 const char *prefix;
2666 if (data_len == 8) {
2667 prefix = "11";
2668 } else if (data_len == 13 || data_len == 16) {
2669 prefix = "59";
2670 if (data_len == 16) {
2671 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%scustinfoenc=numeric",
2672 strlen(bwipp_opts_buf) ? " " : "");
2673 bwipp_opts = bwipp_opts_buf;
2674 }
2675 } else {
2676 prefix = "62";
2677 if (data_len == 23) {
2678 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%scustinfoenc=numeric",
2679 strlen(bwipp_opts_buf) ? " " : "");
2680 bwipp_opts = bwipp_opts_buf;
2681 }
2682 }
2683 memmove(bwipp_data + 2, bwipp_data, data_len + 1);
2684 memmove(bwipp_data, prefix, 2);
2685 }
2686 } else if (symbology == BARCODE_FIM) {
2687 strcpy(bwipp_data, "fima");
2688 bwipp_data[3] = data[0] - 'A' + 'a';
2689 } else if (symbology == BARCODE_CODE16K || symbology == BARCODE_CODE49) {
2690 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%ssepheight=0", strlen(bwipp_opts_buf) ? " " : "");
2691 bwipp_opts = bwipp_opts_buf;
2692 } else if (symbology == BARCODE_AZTEC || symbology == BARCODE_HIBC_AZTEC) {
2693 int compact = 0, full = 0;
2694 if (option_1 >= 1 && option_1 <= 4) {
2695 int eclevel;
2696 if (option_1 == 1) {
2697 eclevel = 10;
2698 } else if (option_1 == 2) {
2699 eclevel = 23;
2700 } else if (option_1 == 3) {
2701 eclevel = 36;
2702 } else {
2703 eclevel = 50;
2704 }
2705 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%seclevel=%d",
2706 strlen(bwipp_opts_buf) ? " " : "", eclevel);
2707 bwipp_opts = bwipp_opts_buf;
2708 }
2709 if (option_2 >= 1) {
2710 int layers;
2711 if (option_2 <= 4) {
2712 compact = 1;
2713 layers = option_2;
2714 } else {
2715 layers = option_2 - 4;
2716 full = layers <= 4;
2717 }
2718 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%slayers=%d",
2719 strlen(bwipp_opts_buf) ? " " : "", layers);
2720 bwipp_opts = bwipp_opts_buf;
2721 }
2722 if (symbol->output_options & READER_INIT) {
2723 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sreaderinit",
2724 strlen(bwipp_opts_buf) ? " " : "");
2725 bwipp_opts = bwipp_opts_buf;
2726 }
2727 if (symbology == BARCODE_HIBC_AZTEC) {
2728 compact = 1;
2729 }
2730 if (compact || full) {
2731 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sformat=%s",
2732 strlen(bwipp_opts_buf) ? " " : "", compact ? "compact" : "full");
2733 bwipp_opts = bwipp_opts_buf;
2734 }
2735 } else if (symbology == BARCODE_CODEONE) {
2736 if ((symbol->input_mode & 0x07) == GS1_MODE) { /* Hack pseudo-GS1 support */
2737 int last_ai, ai_latch = 0;
2738 /* Reduce square brackets (include NUL) */
2739 for (i = 0, j = 0, len = (int) strlen(bwipp_data); i <= len; i++) {
2740 if (bwipp_data[i] == obracket) {
2741 if (ai_latch == 0) {
2742 bwipp_data[j++] = '[';
2743 }
2744 last_ai = atoi(bwipp_data + i + 1);
2745 if ((last_ai >= 0 && last_ai <= 4) || (last_ai >= 11 && last_ai <= 20) || last_ai == 23
2746 || (last_ai >= 31 && last_ai <= 36) || last_ai == 41) {
2747 ai_latch = 1;
2748 }
2749 } else if (bwipp_data[i] != cbracket) {
2750 bwipp_data[j++] = bwipp_data[i];
2751 }
2752 }
2753 /* Replace square brackets with ^FNC1 */
2754 for (len = (int) strlen(bwipp_data), i = len - 1; i >= 0; i--) {
2755 if (bwipp_data[i] == '[') {
2756 memmove(bwipp_data + i + 5, bwipp_data + i + 1, len - i);
2757 memcpy(bwipp_data + i, "^FNC1", 5);
2758 len += 4;
2759 }
2760 }
2761 if (symbol->eci == 0) { /* If not already done for ECI */
2762 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sparsefnc",
2763 strlen(bwipp_opts_buf) ? " " : "");
2764 bwipp_opts = bwipp_opts_buf;
2765 }
2766 }
2767 if (option_2 >= 1 && option_2 <= 10) {
2768 static const char *codeone_versions[] = { "A", "B", "C", "D", "E", "F", "G", "H" };
2769 const char *codeone_version;
2770 if (option_2 == 9) {
2771 codeone_version = length <= 6 ? "S-10" : length <= 12 ? "S-20" : "S-30";
2772 } else if (option_2 == 10) {
2773 // TODO: Properly allow for different T sizes
2774 codeone_version = length <= 22 ? "T-16" : length <= 34 ? "T-32" : "T-48";
2775 } else {
2776 codeone_version = codeone_versions[option_2 - 1];
2777 }
2778 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sversion=%s",
2779 strlen(bwipp_opts_buf) ? " " : "", codeone_version);
2780 bwipp_opts = bwipp_opts_buf;
2781 }
2782 } else if (symbology == BARCODE_MAXICODE) {
2783 int have_scm = memcmp(bwipp_data, "[)>^03001^02996", 15) == 0;
2784 int mode = option_1;
2785 if (mode <= 0) {
2786 if (primary_len == 0) {
2787 mode = 4;
2788 } else {
2789 for (i = 0; i < primary_len - 6; i++) {
2790 if (((symbol->primary[i] < '0') || (symbol->primary[i] > '9'))
2791 && (symbol->primary[i] != ' ')) {
2792 mode = 3;
2793 break;
2794 }
2795 }
2796 }
2797 }
2798 if (mode > 0) {
2799 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%smode=%d",
2800 strlen(bwipp_opts_buf) ? " " : "", mode);
2801 bwipp_opts = bwipp_opts_buf;
2802 }
2803 if (primary_len) {
2804 char prefix_buf[30];
2805 int prefix_len;
2806 int postcode_len = primary_len - 6;
2807 char postcode[10];
2808 if (postcode_len >= 10) postcode_len = 9;
2809 memcpy(postcode, primary, postcode_len);
2810 postcode[postcode_len] = '\0';
2811 if (mode == 2) {
2812 for (i = 0; i < postcode_len; i++) {
2813 if (postcode[i] == ' ') {
2814 postcode[i] = '\0';
2815 }
2816 }
2817 } else {
2818 postcode[6] = '\0';
2819 for (i = postcode_len; i < 6; i++) {
2820 postcode[i] = ' ';
2821 }
2822 }
2823 sprintf(prefix_buf, "%s^029%.3s^029%.3s^029",
2824 postcode, primary + primary_len - 6, primary + primary_len - 3);
2825 prefix_len = (int) strlen(prefix_buf);
2826 if (have_scm) {
2827 memmove(bwipp_data + 15 + prefix_len, bwipp_data, strlen(bwipp_data) - 15 + 1);
2828 memcpy(bwipp_data + 15, prefix_buf, prefix_len);
2829 } else {
2830 memmove(bwipp_data + prefix_len, bwipp_data, strlen(bwipp_data) + 1);
2831 memcpy(bwipp_data, prefix_buf, prefix_len);
2832 }
2833 if (!parse) {
2834 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sparse",
2835 strlen(bwipp_opts_buf) ? " " : "");
2836 bwipp_opts = bwipp_opts_buf;
2837 parse = 1;
2838 }
2839 }
2840 if (option_2 > 0) {
2841 char scm_vv_buf[32];
2842 sprintf(scm_vv_buf, "[)>^03001^029%02d", option_2); /* [)>\R01\Gvv */
2843 memmove(bwipp_data + 15, bwipp_data, strlen(bwipp_data) + 1);
2844 memcpy(bwipp_data, scm_vv_buf, 15);
2845 if (!parse) {
2846 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sparse",
2847 strlen(bwipp_opts_buf) ? " " : "");
2848 bwipp_opts = bwipp_opts_buf;
2849 parse = 1;
2850 }
2851 }
2852 }
2853 }
2854
2855 if (symbology == BARCODE_DATAMATRIX || symbology == BARCODE_HIBC_DM) {
2856 int added_dmre = 0;
2857 #include "../dmatrix.h"
2858 (void)matrixrsblock; (void)matrixdatablock; (void)matrixbytes; (void)matrixFW; (void)matrixFH;
2859 (void)isDMRE; (void)text_value; (void)text_shift; (void)c40_value; (void)c40_shift;
2860
2861 if (symbol->output_options & GS1_GS_SEPARATOR) {
2862 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sgssep", strlen(bwipp_opts_buf) ? " " : "");
2863 bwipp_opts = bwipp_opts_buf;
2864 }
2865 if (option_2 >= 1 && option_2 <= ARRAY_SIZE(intsymbol)) {
2866 int idx = intsymbol[option_2 - 1];
2867 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%srows=%d columns=%d",
2868 strlen(bwipp_opts_buf) ? " " : "", matrixH[idx], matrixW[idx]);
2869 bwipp_opts = bwipp_opts_buf;
2870 if (option_2 >= 31) {
2871 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sdmre", strlen(bwipp_opts_buf) ? " " : "");
2872 added_dmre = 1;
2873 }
2874 }
2875 if (option_3 != DM_SQUARE && symbol->width != symbol->height) {
2876 if (option_3 == DM_DMRE && !added_dmre) {
2877 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sdmre", strlen(bwipp_opts_buf) ? " " : "");
2878 //added_dmre = 1;
2879 }
2880 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sformat=rectangle",
2881 strlen(bwipp_opts_buf) ? " " : "");
2882 bwipp_opts = bwipp_opts_buf;
2883 }
2884 if (option_3 != -1) {
2885 bwipp_opts = bwipp_opts_buf;
2886 }
2887 } else if (symbology == BARCODE_DOTCODE) {
2888 if (option_2 > 0) {
2889 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%scolumns=%d",
2890 strlen(bwipp_opts_buf) ? " " : "", symbol->option_2);
2891 bwipp_opts = bwipp_opts_buf;
2892 }
2893 if (option_3 != -1) {
2894 user_mask = (option_3 >> 8) & 0x0F; /* User mask is pattern + 1, so >= 1 and <= 8 */
2895 if (user_mask >= 1 && user_mask <= 8) {
2896 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%smask=%d",
2897 strlen(bwipp_opts_buf) ? " " : "", (user_mask - 1) % 4);
2898 bwipp_opts = bwipp_opts_buf;
2899 }
2900 }
2901 } else if (symbology == BARCODE_MICROQR || symbology == BARCODE_RMQR) {
2902 if (option_1 >= 1 && option_1 <= 4) {
2903 static const char eccs[4] = { 'L', 'M', 'Q', 'H' };
2904 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%seclevel=%c",
2905 strlen(bwipp_opts_buf) ? " " : "", eccs[option_1 - 1]);
2906 bwipp_opts = bwipp_opts_buf;
2907 }
2908 if (symbology == BARCODE_MICROQR) {
2909 if (option_2 >= 1 && option_2 <= 4) {
2910 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sversion=M%d",
2911 strlen(bwipp_opts_buf) ? " " : "", option_2);
2912 bwipp_opts = bwipp_opts_buf;
2913 }
2914 if (option_3 != -1) {
2915 int mask = (symbol->option_3 >> 8) & 0x0F;
2916 if (mask >= 1 && mask <= 4) {
2917 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%smask=%d",
2918 strlen(bwipp_opts_buf) ? " " : "", ((symbol->option_3 >> 8) & 0x0F));
2919 bwipp_opts = bwipp_opts_buf;
2920 }
2921 }
2922 } else if (symbology == BARCODE_RMQR) {
2923 if (option_2 >= 1 && option_2 <= 32) {
2924 static const char *vers[] = {
2925 "R7x43", "R7x59", "R7x77", "R7x99", "R7x139", "R9x43", "R9x59", "R9x77", "R9x99", "R9x139",
2926 "R11x27", "R11x43", "R11x59", "R11x77", "R11x99", "R11x139", "R13x27", "R13x43", "R13x59", "R13x77",
2927 "R13x99", "R13x139", "R15x43", "R15x59", "R15x77", "R15x99", "R15x139", "R17x43", "R17x59", "R17x77",
2928 "R17x99", "R17x139",
2929 };
2930 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%sversion=%s",
2931 strlen(bwipp_opts_buf) ? " " : "", vers[option_2 - 1]);
2932 bwipp_opts = bwipp_opts_buf;
2933 }
2934 }
2935 } else if (symbology == BARCODE_ULTRA) {
2936 if (option_1 >= 1 && option_1 <= 6) {
2937 sprintf(bwipp_opts_buf + strlen(bwipp_opts_buf), "%seclevel=EC%d",
2938 strlen(bwipp_opts_buf) ? " " : "", option_1 - 1);
2939 bwipp_opts = bwipp_opts_buf;
2940 }
2941 }
2942 }
2943
2944 if ((option_1 != -1 || option_2 != -1 || option_3 != -1) && !bwipp_opts) {
2945 fprintf(stderr,
2946 "i:%d testUtilBwipp: no BWIPP options set option_1 %d, option_2 %d, option_3 %d for symbology %s\n",
2947 index, option_1, option_2, option_3, testUtilBarcodeName(symbology));
2948 return -1;
2949 }
2950
2951 if (bwipp_opts && strlen(bwipp_opts)) {
2952 if (strlen(bwipp_data) >= 2043) { /* Ghostscript's `arg_str_max` 2048 less "-sd=" */
2953 sprintf(cmd, cmd_opts_fmt2, bwipp_barcode, bwipp_data, bwipp_data + 2043, bwipp_opts);
2954 } else {
2955 sprintf(cmd, cmd_opts_fmt, bwipp_barcode, bwipp_data, bwipp_opts);
2956 }
2957 } else {
2958 if (strlen(bwipp_data) >= 2043) {
2959 sprintf(cmd, cmd_fmt2, bwipp_barcode, bwipp_data, bwipp_data + 2043);
2960 } else {
2961 sprintf(cmd, cmd_fmt, bwipp_barcode, bwipp_data);
2962 }
2963 }
2964
2965 /* Hack in various adjustments */
2966 if (symbology == BARCODE_DBAR_OMN || symbology == BARCODE_DBAR_LTD || symbology == BARCODE_DBAR_EXP) {
2967 /* Begin with space */
2968 char adj[5] = " -sbs";
2969 memmove(cmd + GS_INITIAL_LEN + sizeof(adj), cmd + GS_INITIAL_LEN, strlen(cmd) + 1 - GS_INITIAL_LEN);
2970 memcpy(cmd + GS_INITIAL_LEN, adj, sizeof(adj));
2971 }
2972 if (symbology == BARCODE_CODE11 || symbology == BARCODE_CODE39 || symbology == BARCODE_EXCODE39
2973 || symbology == BARCODE_CODABAR || symbology == BARCODE_PHARMA || symbology == BARCODE_PZN
2974 || symbology == BARCODE_CODE32 || symbology == BARCODE_VIN) {
2975 /* Ratio 3 width bar/space -> 2 width */
2976 char adj[8] = " -sr=0.6";
2977 memmove(cmd + GS_INITIAL_LEN + sizeof(adj), cmd + GS_INITIAL_LEN, strlen(cmd) + 1 - GS_INITIAL_LEN);
2978 memcpy(cmd + GS_INITIAL_LEN, adj, sizeof(adj));
2979 }
2980 if (symbology == BARCODE_C25INTER || symbology == BARCODE_DPLEIT || symbology == BARCODE_DPIDENT
2981 || symbology == BARCODE_ITF14) {
2982 /* Ratio 2 width bar/space -> 3 width */
2983 char adj[8] = " -sr=1.3";
2984 memmove(cmd + GS_INITIAL_LEN + sizeof(adj), cmd + GS_INITIAL_LEN, strlen(cmd) + 1 - GS_INITIAL_LEN);
2985 memcpy(cmd + GS_INITIAL_LEN, adj, sizeof(adj));
2986 }
2987 if (symbology == BARCODE_FIM) {
2988 /* Ratio 2 width bar/space -> 1 width */
2989 char adj[8] = " -sr=0.5";
2990 memmove(cmd + GS_INITIAL_LEN + sizeof(adj), cmd + GS_INITIAL_LEN, strlen(cmd) + 1 - GS_INITIAL_LEN);
2991 memcpy(cmd + GS_INITIAL_LEN, adj, sizeof(adj));
2992 }
2993 if (symbology == BARCODE_PLESSEY) {
2994 /* Ceiling ratio 3/4/5 width bar/space -> 2 width then round ratio 2 width bar/space -> 3 width */
2995 char adj[16] = " -sc=0.4 -sr=1.3";
2996 memmove(cmd + GS_INITIAL_LEN + sizeof(adj), cmd + GS_INITIAL_LEN, strlen(cmd) + 1 - GS_INITIAL_LEN);
2997 memcpy(cmd + GS_INITIAL_LEN, adj, sizeof(adj));
2998 }
2999 if (symbology == BARCODE_CODE11 || symbology == BARCODE_CODE39 || symbology == BARCODE_EXCODE39
3000 || symbology == BARCODE_HIBC_39 || symbology == BARCODE_LOGMARS || symbology == BARCODE_PHARMA
3001 || symbology == BARCODE_PZN || symbology == BARCODE_CODE32 || symbology == BARCODE_VIN
3002 || symbology == BARCODE_C25INTER || symbology == BARCODE_DPLEIT || symbology == BARCODE_DPIDENT
3003 || symbology == BARCODE_ITF14 || symbology == BARCODE_PHARMA_TWO) {
3004 /* End sbs loop on bar */
3005 char adj[6] = " -selb";
3006 memmove(cmd + GS_INITIAL_LEN + sizeof(adj), cmd + GS_INITIAL_LEN, strlen(cmd) + 1 - GS_INITIAL_LEN);
3007 memcpy(cmd + GS_INITIAL_LEN, adj, sizeof(adj));
3008 }
3009 if (symbology == BARCODE_C25STANDARD) {
3010 /* Zint uses 4X start/stop wides while BWIPP uses 3X - convert */
3011 char adj[91] = " -sp='i 0 eq i limit 4 sub eq or sbs i get 3 eq and { (1111) print true } { false } ifelse'";
3012 memmove(cmd + GS_INITIAL_LEN + sizeof(adj), cmd + GS_INITIAL_LEN, strlen(cmd) + 1 - GS_INITIAL_LEN);
3013 memcpy(cmd + GS_INITIAL_LEN, adj, sizeof(adj));
3014 }
3015 if (symbology == BARCODE_POSTNET || symbology == BARCODE_PLANET || symbology == BARCODE_RM4SCC
3016 || symbology == BARCODE_JAPANPOST || symbology == BARCODE_KIX || symbology == BARCODE_DAFT
3017 || symbology == BARCODE_USPS_IMAIL || symbology == BARCODE_AUSPOST || symbology == BARCODE_PHARMA_TWO) {
3018 /* Emulate rows with BWIPP heights. */
3019 char adj[5] = " -shs";
3020 memmove(cmd + GS_INITIAL_LEN + sizeof(adj), cmd + GS_INITIAL_LEN, strlen(cmd) + 1 - GS_INITIAL_LEN);
3021 memcpy(cmd + GS_INITIAL_LEN, adj, sizeof(adj));
3022 }
3023 if (symbology == BARCODE_CODE16K || symbology == BARCODE_CODE49) {
3024 char adj[15] = " -sxs=10 -sxe=1"; /* Strip first 10 and last zero */
3025 memmove(cmd + GS_INITIAL_LEN + sizeof(adj), cmd + GS_INITIAL_LEN, strlen(cmd) + 1 - GS_INITIAL_LEN);
3026 memcpy(cmd + GS_INITIAL_LEN, adj, sizeof(adj));
3027 }
3028
3029 if (symbol->debug & ZINT_DEBUG_TEST_PRINT) {
3030 printf("i:%d testUtilBwipp: cmd %s\n", index, cmd);
3031 }
3032
3033 fp = testutil_popen(cmd, "r");
3034 if (!fp) {
3035 fprintf(stderr, "i:%d testUtilBwipp: failed to run '%s'\n", index, cmd);
3036 return -1;
3037 }
3038
3039 for (r = 0; r < symbol->rows; r++) {
3040 if (b + symbol->width > be) {
3041 fprintf(stderr, "i:%d testUtilBwipp: row %d, width %d, row width iteration overrun (%s)\n",
3042 index, r, symbol->width, cmd);
3043 testutil_pclose(fp);
3044 return -1;
3045 }
3046 cnt = (int) fread(b, 1, symbol->width, fp);
3047 if (cnt != symbol->width) {
3048 fprintf(stderr, "i:%d testUtilBwipp: failed to read symbol->width %d bytes, cnt %d (%s)\n",
3049 index, symbol->width, cnt, cmd);
3050 testutil_pclose(fp);
3051 return -1;
3052 }
3053 b += cnt;
3054 for (h = bwipp_row_height[r]; h > 1; h--) { /* Ignore row copies if any */
3055 cnt = (int) fread(b, 1, symbol->width, fp);
3056 if (cnt != symbol->width) {
3057 fprintf(stderr,
3058 "i:%d testUtilBwipp: failed to read/ignore symbol->width %d bytes, cnt %d, h %d"
3059 ", bwipp_row_height[%d] %d, symbol->row_height[%d] %g (%s)\n",
3060 index, symbol->width, cnt, h, r, bwipp_row_height[r], r, symbol->row_height[r], cmd);
3061 testutil_pclose(fp);
3062 return -1;
3063 }
3064 }
3065 }
3066 *b = '\0';
3067
3068 if (fgetc(fp) != EOF) {
3069 fprintf(stderr, "i:%d testUtilBwipp: failed to read full stream (%s)\n", index, cmd);
3070 testutil_pclose(fp);
3071 return -1;
3072 }
3073
3074 testutil_pclose(fp);
3075
3076 return 0;
3077 }
3078
3079 /* Compare bwipp_dump.ps output to test suite module dump */
testUtilBwippCmp(const struct zint_symbol * symbol,char * msg,char * bwipp_buf,const char * expected)3080 int testUtilBwippCmp(const struct zint_symbol *symbol, char *msg, char *bwipp_buf, const char *expected) {
3081 int bwipp_len = (int) strlen(bwipp_buf);
3082 int expected_len = (int) strlen(expected);
3083 int ret_memcmp;
3084 int i;
3085
3086 (void)symbol;
3087
3088 if (bwipp_len != expected_len) {
3089 sprintf(msg, "bwipp_len %d != expected_len %d", bwipp_len, expected_len);
3090 return 2;
3091 }
3092
3093 if (symbol->symbology == BARCODE_ULTRA) {
3094 static const char map[] = { '8', '1', '2', '3', '4', '5', '6', '7', '8', '7' };
3095 for (i = 0; i < bwipp_len; i++) {
3096 if (bwipp_buf[i] >= '0' && bwipp_buf[i] <= '9') {
3097 bwipp_buf[i] = map[bwipp_buf[i] - '0'];
3098 }
3099 }
3100 }
3101 ret_memcmp = memcmp(bwipp_buf, expected, expected_len);
3102 if (ret_memcmp != 0) {
3103 for (i = 0; i < expected_len; i++) {
3104 if (bwipp_buf[i] != expected[i]) {
3105 break;
3106 }
3107 }
3108 sprintf(msg, "bwipp memcmp %d != 0, at %d, len %d", ret_memcmp, i, expected_len);
3109 return ret_memcmp;
3110 }
3111
3112 return 0;
3113 }
3114
3115 /* Compare bwipp_dump.ps output to single row module dump (see testUtilModulesPrintRow) */
testUtilBwippCmpRow(const struct zint_symbol * symbol,int row,char * msg,const char * bwipp_buf,const char * expected)3116 int testUtilBwippCmpRow(const struct zint_symbol *symbol, int row, char *msg, const char *bwipp_buf,
3117 const char *expected) {
3118 int bwipp_len = (int) strlen(bwipp_buf);
3119 int expected_len = (int) strlen(expected);
3120 int ret_memcmp;
3121 int i, j;
3122
3123 (void)symbol;
3124
3125 if (bwipp_len != expected_len * symbol->rows) {
3126 sprintf(msg, "bwipp_len %d != expected_len %d * symbol->rows %d", bwipp_len, expected_len, symbol->rows);
3127 return 2;
3128 }
3129
3130 ret_memcmp = memcmp(bwipp_buf + expected_len * row, expected, expected_len);
3131 if (ret_memcmp != 0) {
3132 for (i = 0, j = expected_len * row; i < expected_len; i++, j++) {
3133 if (bwipp_buf[j] != expected[i]) {
3134 break;
3135 }
3136 }
3137 sprintf(msg, "bwipp memcmp %d != 0, at %d (%d), len %d", ret_memcmp, i, j, expected_len);
3138 return ret_memcmp;
3139 }
3140
3141 return 0;
3142 }
3143