1 /*------------------------------------------------------------------------
2 * Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
3 *
4 * This file is part of the ZBar Bar Code Reader.
5 *
6 * The ZBar Bar Code Reader is free software; you can redistribute it
7 * and/or modify it under the terms of the GNU Lesser Public License as
8 * published by the Free Software Foundation; either version 2.1 of
9 * the License, or (at your option) any later version.
10 *
11 * The ZBar Bar Code Reader is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser Public License
17 * along with the ZBar Bar Code Reader; if not, write to the Free
18 * Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301 USA
20 *
21 * http://sourceforge.net/projects/zbar
22 *------------------------------------------------------------------------*/
23
24 #include <argp.h>
25 #include <assert.h>
26 #include <ctype.h>
27 #include <inttypes.h>
28 #include <limits.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <time.h>
33
34 #include <zbar.h>
35
36 zbar_decoder_t *decoder;
37
38 zbar_symbol_type_t expect_sym;
39 char *expect_data = NULL;
40
41 int rnd_size = 9; /* NB should be odd */
42 int wrong = 0, spurious = 0, missing = 0;
43
44 #define zprintf(level, format, ...) do { \
45 if(verbosity >= (level)) { \
46 fprintf(stderr, format , ##__VA_ARGS__); \
47 } \
48 } while(0)
49
50 #define PROGRAM_NAME "test_video"
51
52 static const char doc[] = "\nGenerate barcodes and decode them with ZBar decoding logic\n";
53
54 static const struct argp_option options[] = {
55 {"quiet", 'q', 0, 0, "Don't be verbose", 0},
56 {"verbose", 'v', 0, 0, "Increases verbosity level", 0},
57 {"random", 'r', 0, 0, "use a random seed", 0},
58 {"seed", 's', "seed", 0, "sets the random seed", 0},
59 {"number", 'n', "count", 0, "sets the number of interactions", 0},
60 {"help", '?', 0, 0, "Give this help list", -1},
61 {"usage", -3, 0, 0, "Give a short usage message", 0},
62 { 0 }
63 };
64
65 unsigned seed = 0, rand_seed = 0;
66 int verbosity = 1;
67 int iter = 0, num_iter = 0; /* test iteration */
68
parse_opt(int k,char * optarg,struct argp_state * state)69 static error_t parse_opt(int k, char *optarg, struct argp_state *state)
70 {
71 switch (k) {
72 case 'q':
73 verbosity = 0;
74 break;
75 case 'v':
76 verbosity++;
77 break;
78 case 'r':
79 rand_seed = 1;
80 break;
81 case 's':
82 seed = strtol(optarg, NULL, 0);
83 break;
84 case 'n':
85 num_iter = strtol(optarg, NULL, 0);
86 break;
87 case '?':
88 argp_state_help(state, state->out_stream,
89 ARGP_HELP_SHORT_USAGE | ARGP_HELP_LONG |
90 ARGP_HELP_DOC);
91 exit(0);
92 case -3:
93 argp_state_help(state, state->out_stream, ARGP_HELP_USAGE);
94 exit(0);
95 default:
96 return ARGP_ERR_UNKNOWN;
97 };
98 return 0;
99 }
100
101 static const struct argp argp = {
102 .options = options,
103 .parser = parse_opt,
104 .doc = doc,
105 };
106
print_sep(int level)107 static inline void print_sep (int level)
108 {
109 zprintf(level,
110 "----------------------------------------------------------\n");
111 }
112
symbol_handler(zbar_decoder_t * decoder)113 static void symbol_handler (zbar_decoder_t *decoder)
114 {
115 zbar_symbol_type_t sym = zbar_decoder_get_type(decoder);
116 if(sym <= ZBAR_PARTIAL || sym == ZBAR_QRCODE)
117 return;
118 const char *data = zbar_decoder_get_data(decoder);
119
120 if (sym != expect_sym) {
121 zprintf(0, "[%d] SEED=%d: warning: expecting %s, got spurious %s\n",
122 iter, seed,
123 zbar_get_symbol_name(expect_sym),
124 zbar_get_symbol_name(sym));
125 spurious++;
126 return;
127 }
128
129 int pass = (sym == expect_sym) && !strcmp(data, expect_data) &&
130 zbar_decoder_get_data_length(decoder) == strlen(data);
131 pass *= 3;
132
133 zprintf(pass, "decode %s:%s\n", zbar_get_symbol_name(sym), data);
134
135 if(!expect_sym)
136 zprintf(0, "UNEXPECTED!\n");
137 else
138 zprintf(pass, "expect %s:%s\n", zbar_get_symbol_name(expect_sym),
139 expect_data);
140 if(!pass) {
141 zprintf(0, "[%d] SEED=%d: ERROR: expecting %s (%s), got %s (%s)\n",
142 iter, seed,
143 expect_data, zbar_get_symbol_name(expect_sym),
144 data, zbar_get_symbol_name(sym));
145 wrong++;
146 }
147
148 expect_sym = ZBAR_NONE;
149 free(expect_data);
150 expect_data = NULL;
151 }
152
expect(zbar_symbol_type_t sym,const char * data)153 static void expect (zbar_symbol_type_t sym,
154 const char *data)
155 {
156 if(expect_sym) {
157 zprintf(0, "[%d] SEED=%d: missing decode: %s (%s)\n",
158 iter, seed,
159 zbar_get_symbol_name(expect_sym), expect_data);
160 missing++;
161 }
162 expect_sym = sym;
163 expect_data = (data) ? strdup(data) : NULL;
164 }
165
encode_junk(int n)166 static void encode_junk (int n)
167 {
168 if(n > 1)
169 zprintf(3, "encode random junk...\n");
170 int i;
171 for(i = 0; i < n; i++)
172 zbar_decode_width(decoder, 20. * (rand() / (RAND_MAX + 1.)) + 1);
173 }
174
175 #define FWD 1
176 #define REV 0
177
encode(uint64_t units,int fwd)178 static void encode (uint64_t units,
179 int fwd)
180 {
181 zprintf(3, " raw=%x%x%c\n", (unsigned)(units >> 32),
182 (unsigned)(units & 0xffffffff), (fwd) ? '<' : '>');
183 if(!fwd)
184 while(units && !(units >> 0x3c))
185 units <<= 4;
186
187 while(units) {
188 unsigned char w = (fwd) ? units & 0xf : units >> 0x3c;
189 zbar_decode_width(decoder, w);
190 if(fwd)
191 units >>= 4;
192 else
193 units <<= 4;
194 }
195 }
196
197
198 /*------------------------------------------------------------*/
199 /* Code 128 encoding */
200
201 typedef enum code128_char_e {
202 FNC3 = 0x60,
203 FNC2 = 0x61,
204 SHIFT = 0x62,
205 CODE_C = 0x63,
206 CODE_B = 0x64,
207 CODE_A = 0x65,
208 FNC1 = 0x66,
209 START_A = 0x67,
210 START_B = 0x68,
211 START_C = 0x69,
212 STOP = 0x6a,
213 } code128_char_t;
214
215 static const unsigned int code128[107] = {
216 0x212222, 0x222122, 0x222221, 0x121223, /* 00 */
217 0x121322, 0x131222, 0x122213, 0x122312,
218 0x132212, 0x221213, 0x221312, 0x231212, /* 08 */
219 0x112232, 0x122132, 0x122231, 0x113222,
220 0x123122, 0x123221, 0x223211, 0x221132, /* 10 */
221 0x221231, 0x213212, 0x223112, 0x312131,
222 0x311222, 0x321122, 0x321221, 0x312212, /* 18 */
223 0x322112, 0x322211, 0x212123, 0x212321,
224 0x232121, 0x111323, 0x131123, 0x131321, /* 20 */
225 0x112313, 0x132113, 0x132311, 0x211313,
226 0x231113, 0x231311, 0x112133, 0x112331, /* 28 */
227 0x132131, 0x113123, 0x113321, 0x133121,
228 0x313121, 0x211331, 0x231131, 0x213113, /* 30 */
229 0x213311, 0x213131, 0x311123, 0x311321,
230 0x331121, 0x312113, 0x312311, 0x332111, /* 38 */
231 0x314111, 0x221411, 0x431111, 0x111224,
232 0x111422, 0x121124, 0x121421, 0x141122, /* 40 */
233 0x141221, 0x112214, 0x112412, 0x122114,
234 0x122411, 0x142112, 0x142211, 0x241211, /* 48 */
235 0x221114, 0x413111, 0x241112, 0x134111,
236 0x111242, 0x121142, 0x121241, 0x114212, /* 50 */
237 0x124112, 0x124211, 0x411212, 0x421112,
238 0x421211, 0x212141, 0x214121, 0x412121, /* 58 */
239 0x111143, 0x111341, 0x131141, 0x114113,
240 0x114311, 0x411113, 0x411311, 0x113141, /* 60 */
241 0x114131, 0x311141, 0x411131,
242 0xa211412, 0xa211214, 0xa211232, /* START_A-START_C (67-69) */
243 0x2331112a, /* STOP (6a) */
244 };
245
encode_code128b(char * data)246 static void encode_code128b (char *data)
247 {
248 assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE);
249 print_sep(3);
250 zprintf(2, "CODE-128(B): %s\n", data);
251 zprintf(3, " encode START_B: %02x", START_B);
252 encode(code128[START_B], 0);
253 int i, chk = START_B;
254 for(i = 0; data[i]; i++) {
255 zprintf(3, " encode '%c': %02x", data[i], data[i] - 0x20);
256 encode(code128[data[i] - 0x20], 0);
257 chk += (i + 1) * (data[i] - 0x20);
258 }
259 chk %= 103;
260 zprintf(3, " encode checksum: %02x", chk);
261 encode(code128[chk], 0);
262 zprintf(3, " encode STOP: %02x", STOP);
263 encode(code128[STOP], 0);
264 print_sep(3);
265 }
266
encode_code128c(char * data)267 static void encode_code128c (char *data)
268 {
269 assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE);
270 print_sep(3);
271 zprintf(2, "CODE-128(C): %s\n", data);
272 zprintf(3, " encode START_C: %02x", START_C);
273 encode(code128[START_C], 0);
274 int i, chk = START_C;
275 for(i = 0; data[i]; i += 2) {
276 assert(data[i] >= '0');
277 assert(data[i + 1] >= '0');
278 unsigned char c = (data[i] - '0') * 10 + (data[i + 1] - '0');
279 zprintf(3, " encode '%c%c': %02d", data[i], data[i + 1], c);
280 encode(code128[c], 0);
281 chk += (i / 2 + 1) * c;
282 }
283 chk %= 103;
284 zprintf(3, " encode checksum: %02x", chk);
285 encode(code128[chk], 0);
286 zprintf(3, " encode STOP: %02x", STOP);
287 encode(code128[STOP], 0);
288 print_sep(3);
289 }
290
291 /*------------------------------------------------------------*/
292 /* Code 93 encoding */
293
294 #define CODE93_START_STOP 0x2f
295
296 static const unsigned int code93[47 + 1] = {
297 0x131112, 0x111213, 0x111312, 0x111411, /* 00 */
298 0x121113, 0x121212, 0x121311, 0x111114,
299 0x131211, 0x141111, 0x211113, 0x211212, /* 08 */
300 0x211311, 0x221112, 0x221211, 0x231111,
301 0x112113, 0x112212, 0x112311, 0x122112, /* 10 */
302 0x132111, 0x111123, 0x111222, 0x111321,
303 0x121122, 0x131121, 0x212112, 0x212211, /* 18 */
304 0x211122, 0x211221, 0x221121, 0x222111,
305 0x112122, 0x112221, 0x122121, 0x123111, /* 20 */
306 0x121131, 0x311112, 0x311211, 0x321111,
307 0x112131, 0x113121, 0x211131, 0x121221, /* 28 */
308 0x312111, 0x311121, 0x122211,
309 0x111141, /* START/STOP (2f) */
310 };
311
312 #define S1 0x2b00|
313 #define S2 0x2c00|
314 #define S3 0x2d00|
315 #define S4 0x2e00|
316
317 static const unsigned short code93_ext[0x80] = {
318 S2'U', S1'A', S1'B', S1'C', S1'D', S1'E', S1'F', S1'G',
319 S1'H', S1'I', S1'J', S1'K', S1'L', S1'M', S1'N', S1'O',
320 S1'P', S1'Q', S1'R', S1'S', S1'T', S1'U', S1'V', S1'W',
321 S1'X', S1'Y', S1'Z', S2'A', S2'B', S2'C', S2'D', S2'E',
322 0x26, S3'A', S3'B', S3'C', 0x27, 0x2a, S3'F', S3'G',
323 S3'H', S3'I', S3'J', 0x29, S3'L', 0x24, 0x25, 0x28,
324 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
325 0x08, 0x09, S3'Z', S2'F', S2'G', S2'H', S2'I', S2'J',
326 S2'V', 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
327 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
328 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
329 0x21, 0x22, 0x23, S2'K', S2'L', S2'M', S2'N', S2'O',
330 S2'W', S4'A', S4'B', S4'C', S4'D', S4'E', S4'F', S4'G',
331 S4'H', S4'I', S4'J', S4'K', S4'L', S4'M', S4'N', S4'O',
332 S4'P', S4'Q', S4'R', S4'S', S4'T', S4'U', S4'V', S4'W',
333 S4'X', S4'Y', S4'Z', S2'P', S2'Q', S2'R', S2'S', S2'T',
334 };
335
336 #undef S1
337 #undef S2
338 #undef S3
339 #undef S4
340
encode_char93(unsigned char c,int dir)341 static void encode_char93 (unsigned char c,
342 int dir)
343 {
344 unsigned ext = code93_ext[c];
345 unsigned shift = ext >> 8;
346 assert(shift < 0x30);
347 c = ext & 0xff;
348 if(shift) {
349 assert(c < 0x80);
350 c = code93_ext[c];
351 }
352 assert(c < 0x30);
353
354 if(shift) {
355 encode(code93[(dir) ? shift : c], dir ^ 1);
356 encode(code93[(dir) ? c : shift], dir ^ 1);
357 }
358 else
359 encode(code93[c], dir ^ 1);
360 }
361
encode_code93(char * data,int dir)362 static void encode_code93 (char *data,
363 int dir)
364 {
365 assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE);
366 print_sep(3);
367
368 /* calculate checksums */
369 int i, j, chk_c = 0, chk_k = 0, n = 0;
370 for(i = 0; data[i]; i++, n++) {
371 unsigned c = data[i], ext;
372 assert(c < 0x80);
373 ext = code93_ext[c];
374 n += ext >> 13;
375 }
376
377 for(i = 0, j = 0; data[i]; i++, j++) {
378 unsigned ext = code93_ext[(unsigned)data[i]];
379 unsigned shift = ext >> 8;
380 unsigned c = ext & 0xff;
381 if(shift) {
382 chk_c += shift * (((n - 1 - j) % 20) + 1);
383 chk_k += shift * (((n - j) % 15) + 1);
384 j++;
385 c = code93_ext[c];
386 }
387 chk_c += c * (((n - 1 - j) % 20) + 1);
388 chk_k += c * (((n - j) % 15) + 1);
389 }
390 chk_c %= 47;
391 chk_k += chk_c;
392 chk_k %= 47;
393
394 zprintf(2, "CODE-93: %s (n=%x C=%02x K=%02x)\n", data, n, chk_c, chk_k);
395 encode(0xa, 0); /* leading quiet */
396
397 zprintf(3, " encode %s:", (dir) ? "START" : "STOP");
398 if(!dir)
399 encode(0x1, REV);
400 encode(code93[CODE93_START_STOP], dir ^ 1);
401 if(!dir) {
402 zprintf(3, " encode checksum (K): %02x", chk_k);
403 encode(code93[chk_k], REV ^ 1);
404 zprintf(3, " encode checksum (C): %02x", chk_c);
405 encode(code93[chk_c], REV ^ 1);
406 }
407
408 n = strlen(data);
409 for(i = 0; i < n; i++) {
410 unsigned char c = data[(dir) ? i : (n - i - 1)];
411 zprintf(3, " encode '%c':", c);
412 encode_char93(c, dir);
413 }
414
415 if(dir) {
416 zprintf(3, " encode checksum (C): %02x", chk_c);
417 encode(code93[chk_c], FWD ^ 1);
418 zprintf(3, " encode checksum (K): %02x", chk_k);
419 encode(code93[chk_k], FWD ^ 1);
420 }
421 zprintf(3, " encode %s:", (dir) ? "STOP" : "START");
422 encode(code93[CODE93_START_STOP], dir ^ 1);
423 if(dir)
424 encode(0x1, FWD);
425
426 encode(0xa, 0); /* trailing quiet */
427 print_sep(3);
428 }
429
430 /*------------------------------------------------------------*/
431 /* Code 39 encoding */
432
433 static const unsigned int code39[91-32] = {
434 0x0c4, 0x000, 0x000, 0x000, 0x0a8, 0x02a, 0x000, 0x000, /* 20 */
435 0x000, 0x000, 0x094, 0x08a, 0x000, 0x085, 0x184, 0x0a2, /* 28 */
436 0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, /* 30 */
437 0x124, 0x064, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, /* 38 */
438 0x000, 0x109, 0x049, 0x148, 0x019, 0x118, 0x058, 0x00d, /* 40 */
439 0x10c, 0x04c, 0x01c, 0x103, 0x043, 0x142, 0x013, 0x112, /* 48 */
440 0x052, 0x007, 0x106, 0x046, 0x016, 0x181, 0x0c1, 0x1c0, /* 50 */
441 0x091, 0x190, 0x0d0, /* 58 */
442 };
443
444 /* FIXME configurable/randomized ratio, ics */
445 /* FIXME check digit option, ASCII escapes */
446
convert_code39(char * data)447 static void convert_code39 (char *data)
448 {
449 char *src, *dst;
450 for(src = data, dst = data; *src; src++) {
451 char c = *src;
452 if(c >= 'a' && c <= 'z')
453 *(dst++) = c - ('a' - 'A');
454 else if(c == ' ' ||
455 c == '$' || c == '%' ||
456 c == '+' || c == '-' ||
457 (c >= '.' && c <= '9') ||
458 (c >= 'A' && c <= 'Z'))
459 *(dst++) = c;
460 else
461 /* skip (FIXME) */;
462 }
463 *dst = 0;
464 }
465
encode_char39(unsigned char c,unsigned ics)466 static void encode_char39 (unsigned char c,
467 unsigned ics)
468 {
469 assert(0x20 <= c && c <= 0x5a);
470 unsigned int raw = code39[c - 0x20];
471 if(!raw)
472 return; /* skip (FIXME) */
473
474 uint64_t enc = 0;
475 int j;
476 for(j = 0; j < 9; j++) {
477 enc = (enc << 4) | ((raw & 0x100) ? 2 : 1);
478 raw <<= 1;
479 }
480 enc = (enc << 4) | ics;
481 zprintf(3, " encode '%c': %02x%08x: ", c,
482 (unsigned)(enc >> 32), (unsigned)(enc & 0xffffffff));
483 encode(enc, REV);
484 }
485
encode_code39(char * data)486 static void encode_code39 (char *data)
487 {
488 assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE);
489 print_sep(3);
490 zprintf(2, "CODE-39: %s\n", data);
491 encode(0xa, 0); /* leading quiet */
492 encode_char39('*', 1);
493 int i;
494 for(i = 0; data[i]; i++)
495 if(data[i] != '*') /* skip (FIXME) */
496 encode_char39(data[i], 1);
497 encode_char39('*', 0xa); /* w/trailing quiet */
498 print_sep(3);
499 }
500
501 #if 0
502 /*------------------------------------------------------------*/
503 /* PDF417 encoding */
504
505 /* hardcoded test message: "hello world" */
506 #define PDF417_ROWS 3
507 #define PDF417_COLS 3
508 static const unsigned pdf417_msg[PDF417_ROWS][PDF417_COLS] = {
509 { 007, 817, 131 },
510 { 344, 802, 437 },
511 { 333, 739, 194 },
512 };
513
514 #define PDF417_START UINT64_C(0x81111113)
515 #define PDF417_STOP UINT64_C(0x711311121)
516 #include "pdf417_encode.h"
517
518 static int calc_ind417 (int mod,
519 int r,
520 int cols)
521 {
522 mod = (mod + 3) % 3;
523 int cw = 30 * (r / 3);
524 if(!mod)
525 return(cw + cols - 1);
526 else if(mod == 1)
527 return(cw + (PDF417_ROWS - 1) % 3);
528 assert(mod == 2);
529 return(cw + (PDF417_ROWS - 1) / 3);
530 }
531
532 static void encode_row417 (int r,
533 const unsigned *cws,
534 int cols,
535 int dir)
536 {
537 int k = r % 3;
538
539 zprintf(3, " [%d] encode %s:", r, (dir) ? "stop" : "start");
540 encode((dir) ? PDF417_STOP : PDF417_START, dir);
541
542 int cw = calc_ind417(k + !dir, r, cols);
543 zprintf(3, " [%d,%c] encode %03d(%d): ", r, (dir) ? 'R' : 'L', cw, k);
544 encode(pdf417_encode[cw][k], dir);
545
546 int c;
547 for(c = 0; c < cols; c++) {
548 cw = cws[c];
549 zprintf(3, " [%d,%d] encode %03d(%d): ", r, c, cw, k);
550 encode(pdf417_encode[cw][k], dir);
551 }
552
553 cw = calc_ind417(k + dir, r, cols);
554 zprintf(3, " [%d,%c] encode %03d(%d): ", r, (dir) ? 'L' : 'R', cw, k);
555 encode(pdf417_encode[cw][k], dir);
556
557 zprintf(3, " [%d] encode %s:", r, (dir) ? "start" : "stop");
558 encode((dir) ? PDF417_START : PDF417_STOP, dir);
559 }
560
561 static void encode_pdf417 (char *data)
562 {
563 assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE);
564 print_sep(3);
565 zprintf(2, "PDF417: hello world\n");
566 encode(0xa, 0);
567
568 int r;
569 for(r = 0; r < PDF417_ROWS; r++) {
570 encode_row417(r, pdf417_msg[r], PDF417_COLS, r & 1);
571 encode(0xa, 0);
572 }
573
574 print_sep(3);
575 }
576 #endif
577
578 /*------------------------------------------------------------*/
579 /* Codabar encoding */
580
581 static const unsigned int codabar[20] = {
582 0x03, 0x06, 0x09, 0x60, 0x12, 0x42, 0x21, 0x24,
583 0x30, 0x48, 0x0c, 0x18, 0x45, 0x51, 0x54, 0x15,
584 0x1a, 0x29, 0x0b, 0x0e,
585 };
586
587 static const char codabar_char[0x14] =
588 "0123456789-$:/.+ABCD";
589
590 /* FIXME configurable/randomized ratio, ics */
591 /* FIXME check digit option */
592
convert_codabar(char * src)593 static char *convert_codabar (char *src)
594 {
595 unsigned len = strlen(src);
596 char tmp[4] = { 0, };
597 if(len < 2) {
598 unsigned delim = rand() >> 8;
599 tmp[0] = delim & 3;
600 if(len)
601 tmp[1] = src[0];
602 tmp[len + 1] = (delim >> 2) & 3;
603 len += 2;
604 src = tmp;
605 }
606
607 char *result = malloc(len + 1);
608 char *dst = result;
609 *(dst++) = ((*(src++) - 1) & 0x3) + 'A';
610 for(len--; len > 1; len--) {
611 char c = *(src++);
612 if(c >= '0' && c <= '9')
613 *(dst++) = c;
614 else if(c == '-' || c == '$' || c == ':' || c == '/' ||
615 c == '.' || c == '+')
616 *(dst++) = c;
617 else
618 *(dst++) = codabar_char[c % 0x10];
619 }
620 *(dst++) = ((*(src++) - 1) & 0x3) + 'A';
621 *dst = 0;
622 return(result);
623 }
624
encode_codachar(unsigned char c,unsigned ics,int dir)625 static void encode_codachar (unsigned char c,
626 unsigned ics,
627 int dir)
628 {
629 unsigned int idx;
630 if(c >= '0' && c <= '9')
631 idx = c - '0';
632 else if(c >= 'A' && c <= 'D')
633 idx = c - 'A' + 0x10;
634 else
635 switch(c)
636 {
637 case '-': idx = 0xa; break;
638 case '$': idx = 0xb; break;
639 case ':': idx = 0xc; break;
640 case '/': idx = 0xd; break;
641 case '.': idx = 0xe; break;
642 case '+': idx = 0xf; break;
643 default:
644 assert(0);
645 }
646
647 assert(idx < 0x14);
648 unsigned int raw = codabar[idx];
649
650 uint32_t enc = 0;
651 int j;
652 for(j = 0; j < 7; j++, raw <<= 1)
653 enc = (enc << 4) | ((raw & 0x40) ? 3 : 1);
654 zprintf(3, " encode '%c': %07x: ", c, enc);
655 if(dir)
656 enc = (enc << 4) | ics;
657 else
658 enc |= ics << 28;
659 encode(enc, 1 - dir);
660 }
661
encode_codabar(char * data,int dir)662 static void encode_codabar (char *data,
663 int dir)
664 {
665 assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE);
666 print_sep(3);
667 zprintf(2, "CODABAR: %s\n", data);
668 encode(0xa, 0); /* leading quiet */
669 int i, n = strlen(data);
670 for(i = 0; i < n; i++) {
671 int j = (dir) ? i : n - i - 1;
672 encode_codachar(data[j], (i < n - 1) ? 1 : 0xa, dir);
673 }
674 print_sep(3);
675 }
676
677 /*------------------------------------------------------------*/
678 /* Interleaved 2 of 5 encoding */
679
680 static const unsigned char i25[10] = {
681 0x06, 0x11, 0x09, 0x18, 0x05, 0x14, 0x0c, 0x03, 0x12, 0x0a,
682 };
683
encode_i25(char * data,int dir)684 static void encode_i25 (char *data,
685 int dir)
686 {
687 assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE);
688 print_sep(3);
689 zprintf(2, "Interleaved 2 of 5: %s\n", data);
690 zprintf(3, " encode start:");
691 encode((dir) ? 0xa1111 : 0xa112, 0);
692
693 /* FIXME rev case data reversal */
694 int i;
695 for(i = (strlen(data) & 1) ? -1 : 0; i < 0 || data[i]; i += 2) {
696 /* encode 2 digits */
697 unsigned char c0 = (i < 0) ? 0 : data[i] - '0';
698 unsigned char c1 = data[i + 1] - '0';
699 zprintf(3, " encode '%d%d':", c0, c1);
700 assert(c0 < 10);
701 assert(c1 < 10);
702
703 c0 = i25[c0];
704 c1 = i25[c1];
705
706 /* interleave */
707 uint64_t enc = 0;
708 int j;
709 for(j = 0; j < 5; j++) {
710 enc <<= 8;
711 enc |= (c0 & 1) ? 0x02 : 0x01;
712 enc |= (c1 & 1) ? 0x20 : 0x10;
713 c0 >>= 1;
714 c1 >>= 1;
715 }
716 encode(enc, dir);
717 }
718
719 zprintf(3, " encode end:");
720 encode((dir) ? 0x211a : 0x1111a, 0);
721 print_sep(3);
722 }
723
724 /*------------------------------------------------------------*/
725 /* DataBar encoding */
726
727
728 /* character encoder reference algorithm from ISO/IEC 24724:2009 */
729
730 struct rss_group {
731 int T_odd, T_even, n_odd, w_max;
732 };
733
734 static const struct rss_group databar_groups_outside[] = {
735 { 161, 1, 12, 8 },
736 { 80, 10, 10, 6 },
737 { 31, 34, 8, 4 },
738 { 10, 70, 6, 3 },
739 { 1, 126, 4, 1 },
740 { 0, }
741 };
742
743 static const struct rss_group databar_groups_inside[] = {
744 { 4, 84, 5, 2 },
745 { 20, 35, 7, 4 },
746 { 48, 10, 9, 6 },
747 { 81, 1, 11, 8 },
748 { 0, }
749 };
750
751 static const uint32_t databar_finders[9] = {
752 0x38211, 0x35511, 0x33711, 0x31911, 0x27411,
753 0x25611, 0x23811, 0x15711, 0x13911,
754 };
755
combins(int n,int r)756 int combins (int n,
757 int r)
758 {
759 int i, j;
760 int maxDenom, minDenom;
761 int val;
762 if(n-r > r) {
763 minDenom = r;
764 maxDenom = n-r;
765 }
766 else {
767 minDenom = n-r;
768 maxDenom = r;
769 }
770 val = 1;
771 j = 1;
772 for(i = n; i > maxDenom; i--) {
773 val *= i;
774 if(j <= minDenom) {
775 val /= j;
776 j++;
777 }
778 }
779 for(; j <= minDenom; j++)
780 val /= j;
781 return(val);
782 }
783
getRSSWidths(int val,int n,int elements,int maxWidth,int noNarrow,int * widths)784 void getRSSWidths (int val,
785 int n,
786 int elements,
787 int maxWidth,
788 int noNarrow,
789 int *widths)
790 {
791 int narrowMask = 0;
792 int bar;
793 for(bar = 0; bar < elements - 1; bar++) {
794 int elmWidth, subVal;
795 for(elmWidth = 1, narrowMask |= (1<<bar);
796 ;
797 elmWidth++, narrowMask &= ~(1<<bar))
798 {
799 subVal = combins(n-elmWidth-1, elements-bar-2);
800 if((!noNarrow) && !narrowMask &&
801 (n-elmWidth-(elements-bar-1) >= elements-bar-1))
802 subVal -= combins(n-elmWidth-(elements-bar), elements-bar-2);
803 if(elements-bar-1 > 1) {
804 int mxwElement, lessVal = 0;
805 for (mxwElement = n-elmWidth-(elements-bar-2);
806 mxwElement > maxWidth;
807 mxwElement--)
808 lessVal += combins(n-elmWidth-mxwElement-1, elements-bar-3);
809 subVal -= lessVal * (elements-1-bar);
810 }
811 else if (n-elmWidth > maxWidth)
812 subVal--;
813 val -= subVal;
814 if(val < 0)
815 break;
816 }
817 val += subVal;
818 n -= elmWidth;
819 widths[bar] = elmWidth;
820 }
821 widths[bar] = n;
822 }
823
encode_databar_char(unsigned val,const struct rss_group * grp,int nmodules,int nelems,int dir)824 static uint64_t encode_databar_char (unsigned val,
825 const struct rss_group *grp,
826 int nmodules,
827 int nelems,
828 int dir)
829 {
830 int G_sum = 0;
831 while(1) {
832 assert(grp->T_odd);
833 int sum = G_sum + grp->T_odd * grp->T_even;
834 if(val >= sum)
835 G_sum = sum;
836 else
837 break;
838 grp++;
839 }
840
841 zprintf(3, "char=%d", val);
842
843 int V_grp = val - G_sum;
844 int V_odd, V_even;
845 if(!dir) {
846 V_odd = V_grp / grp->T_even;
847 V_even = V_grp % grp->T_even;
848 }
849 else {
850 V_even = V_grp / grp->T_odd;
851 V_odd = V_grp % grp->T_odd;
852 }
853
854 zprintf(3, " G_sum=%d T_odd=%d T_even=%d n_odd=%d w_max=%d V_grp=%d\n",
855 G_sum, grp->T_odd, grp->T_even, grp->n_odd, grp->w_max, V_grp);
856
857 int odd[16];
858 getRSSWidths(V_odd, grp->n_odd, nelems, grp->w_max, !dir, odd);
859 zprintf(3, " V_odd=%d odd=%d%d%d%d",
860 V_odd, odd[0], odd[1], odd[2], odd[3]);
861
862 int even[16];
863 getRSSWidths(V_even, nmodules - grp->n_odd, nelems, 9 - grp->w_max,
864 dir, even);
865 zprintf(3, " V_even=%d even=%d%d%d%d",
866 V_even, even[0], even[1], even[2], even[3]);
867
868 uint64_t units = 0;
869 int i;
870 for(i = 0; i < nelems; i++)
871 units = (units << 8) | (odd[i] << 4) | even[i];
872
873 zprintf(3, " raw=%"PRIx64"\n", units);
874 return(units);
875 }
876
877 #define SWAP(a, b) do { \
878 uint32_t tmp = (a); \
879 (a) = (b); \
880 (b) = tmp; \
881 } while(0);
882
encode_databar(char * data,int dir)883 static void encode_databar (char *data,
884 int dir)
885 {
886 assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE);
887
888 print_sep(3);
889 zprintf(2, "DataBar: %s\n", data);
890
891 uint32_t v[4] = { 0, };
892 int i, j;
893 for(i = 0; i < 14; i++) {
894 for(j = 0; j < 4; j++)
895 v[j] *= 10;
896 assert(data[i]);
897 v[0] += data[i] - '0';
898 v[1] += v[0] / 1597;
899 v[0] %= 1597;
900 v[2] += v[1] / 2841;
901 v[1] %= 2841;
902 v[3] += v[2] / 1597;
903 v[2] %= 1597;
904 /*printf(" [%d] %c (%d,%d,%d,%d)\n",
905 i, data[i], v[0], v[1], v[2], v[3]);*/
906 }
907 zprintf(3, "chars=(%d,%d,%d,%d)\n", v[3], v[2], v[1], v[0]);
908
909 uint32_t c[4] = {
910 encode_databar_char(v[3], databar_groups_outside, 16, 4, 0),
911 encode_databar_char(v[2], databar_groups_inside, 15, 4, 1),
912 encode_databar_char(v[1], databar_groups_outside, 16, 4, 0),
913 encode_databar_char(v[0], databar_groups_inside, 15, 4, 1),
914 };
915
916 int chk = 0, w = 1;
917 for(i = 0; i < 4; i++, chk %= 79, w %= 79)
918 for(j = 0; j < 8; j++, w *= 3)
919 chk += ((c[i] >> (28 - j * 4)) & 0xf) * w;
920 zprintf(3, "chk=%d\n", chk);
921
922 if(chk >= 8) chk++;
923 if(chk >= 72) chk++;
924 int C_left = chk / 9;
925 int C_right = chk % 9;
926
927 if(dir == REV) {
928 SWAP(C_left, C_right);
929 SWAP(c[0], c[2]);
930 SWAP(c[1], c[3]);
931 SWAP(v[0], v[2]);
932 SWAP(v[1], v[3]);
933 }
934
935 zprintf(3, " encode start guard:");
936 encode_junk(dir);
937 encode(0x1, FWD);
938
939 zprintf(3, "encode char[0]=%d", v[3]);
940 encode(c[0], REV);
941
942 zprintf(3, "encode left finder=%d", C_left);
943 encode(databar_finders[C_left], REV);
944
945 zprintf(3, "encode char[1]=%d", v[2]);
946 encode(c[1], FWD);
947
948 zprintf(3, "encode char[3]=%d", v[0]);
949 encode(c[3], REV);
950
951 zprintf(3, "encode right finder=%d", C_right);
952 encode(databar_finders[C_right], FWD);
953
954 zprintf(3, "encode char[2]=%d", v[1]);
955 encode(c[2], FWD);
956
957 zprintf(3, " encode end guard:");
958 encode(0x1, FWD);
959 encode_junk(!dir);
960 print_sep(3);
961 }
962
963
964 /*------------------------------------------------------------*/
965 /* EAN/UPC encoding */
966
967 static const unsigned int ean_digits[10] = {
968 0x1123, 0x1222, 0x2212, 0x1141, 0x2311,
969 0x1321, 0x4111, 0x2131, 0x3121, 0x2113,
970 };
971
972 static const unsigned int ean_guard[] = {
973 0, 0,
974 0x11, /* [2] add-on delineator */
975 0x1117, /* [3] normal guard bars */
976 0x2117, /* [4] add-on guard bars */
977 0x11111, /* [5] center guard bars */
978 0x111111 /* [6] "special" guard bars */
979 };
980
981 static const unsigned char ean_parity_encode[] = {
982 0x3f, /* AAAAAA = 0 */
983 0x34, /* AABABB = 1 */
984 0x32, /* AABBAB = 2 */
985 0x31, /* AABBBA = 3 */
986 0x2c, /* ABAABB = 4 */
987 0x26, /* ABBAAB = 5 */
988 0x23, /* ABBBAA = 6 */
989 0x2a, /* ABABAB = 7 */
990 0x29, /* ABABBA = 8 */
991 0x25, /* ABBABA = 9 */
992 };
993
994 static const unsigned char addon_parity_encode[] = {
995 0x07, /* BBAAA = 0 */
996 0x0b, /* BABAA = 1 */
997 0x0d, /* BAABA = 2 */
998 0x0e, /* BAAAB = 3 */
999 0x13, /* ABBAA = 4 */
1000 0x19, /* AABBA = 5 */
1001 0x1c, /* AAABB = 6 */
1002 0x15, /* ABABA = 7 */
1003 0x16, /* ABAAB = 8 */
1004 0x1a, /* AABAB = 9 */
1005 };
1006
calc_ean_parity(char * data,int n)1007 static void calc_ean_parity (char *data,
1008 int n)
1009 {
1010 int i, chk = 0;
1011 for(i = 0; i < n; i++) {
1012 unsigned char c = data[i] - '0';
1013 chk += ((i ^ n) & 1) ? c * 3 : c;
1014 }
1015 chk %= 10;
1016 if(chk)
1017 chk = 10 - chk;
1018 data[i++] = '0' + chk;
1019 data[i] = 0;
1020 }
1021
encode_ean13(char * data)1022 static void encode_ean13 (char *data)
1023 {
1024 int i;
1025 unsigned char par = ean_parity_encode[data[0] - '0'];
1026 assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE);
1027
1028 print_sep(3);
1029 zprintf(2, "EAN-13: %s (%02x)\n", data, par);
1030 zprintf(3, " encode start guard:");
1031 encode(ean_guard[3], FWD);
1032 for(i = 1; i < 7; i++, par <<= 1) {
1033 zprintf(3, " encode %x%c:", (par >> 5) & 1, data[i]);
1034 encode(ean_digits[data[i] - '0'], (par >> 5) & 1);
1035 }
1036 zprintf(3, " encode center guard:");
1037 encode(ean_guard[5], FWD);
1038 for(; i < 13; i++) {
1039 zprintf(3, " encode %x%c:", 0, data[i]);
1040 encode(ean_digits[data[i] - '0'], FWD);
1041 }
1042 zprintf(3, " encode end guard:");
1043 encode(ean_guard[3], REV);
1044 print_sep(3);
1045 }
1046
encode_ean8(char * data)1047 static void encode_ean8 (char *data)
1048 {
1049 int i;
1050 assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE);
1051 print_sep(3);
1052 zprintf(2, "EAN-8: %s\n", data);
1053 zprintf(3, " encode start guard:");
1054 encode(ean_guard[3], FWD);
1055 for(i = 0; i < 4; i++) {
1056 zprintf(3, " encode %c:", data[i]);
1057 encode(ean_digits[data[i] - '0'], FWD);
1058 }
1059 zprintf(3, " encode center guard:");
1060 encode(ean_guard[5], FWD);
1061 for(; i < 8; i++) {
1062 zprintf(3, " encode %c:", data[i]);
1063 encode(ean_digits[data[i] - '0'], FWD);
1064 }
1065 zprintf(3, " encode end guard:");
1066 encode(ean_guard[3], REV);
1067 print_sep(3);
1068 }
1069
encode_addon(char * data,unsigned par,int n)1070 static void encode_addon (char *data,
1071 unsigned par,
1072 int n)
1073 {
1074 int i;
1075 assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE);
1076
1077 print_sep(3);
1078 zprintf(2, "EAN-%d: %s (par=%02x)\n", n, data, par);
1079 zprintf(3, " encode start guard:");
1080 encode(ean_guard[4], FWD);
1081 for(i = 0; i < n; i++, par <<= 1) {
1082 zprintf(3, " encode %x%c:", (par >> (n - 1)) & 1, data[i]);
1083 encode(ean_digits[data[i] - '0'], (par >> (n - 1)) & 1);
1084 if(i < n - 1) {
1085 zprintf(3, " encode delineator:");
1086 encode(ean_guard[2], FWD);
1087 }
1088 }
1089 zprintf(3, " encode trailing qz:");
1090 encode(0x7, FWD);
1091 print_sep(3);
1092 }
1093
encode_ean5(char * data)1094 static void encode_ean5 (char *data)
1095 {
1096 unsigned chk = ((data[0] - '0' + data[2] - '0' + data[4] - '0') * 3 +
1097 (data[1] - '0' + data[3] - '0') * 9) % 10;
1098 encode_addon(data, addon_parity_encode[chk], 5);
1099 }
1100
encode_ean2(char * data)1101 static void encode_ean2 (char *data)
1102 {
1103 unsigned par = (~(10 * (data[0] - '0') + data[1] - '0')) & 3;
1104 encode_addon(data, par, 2);
1105 }
1106
1107
1108 /*------------------------------------------------------------*/
1109 /* main test flow */
1110
test_databar_F_1()1111 int test_databar_F_1 ()
1112 {
1113 expect(ZBAR_DATABAR, "0124012345678905");
1114 assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE);
1115 encode(0x11, 0);
1116 encode(0x31111333, 0);
1117 encode(0x13911, 0);
1118 encode(0x31131231, 0);
1119 encode(0x11214222, 0);
1120 encode(0x11553, 0);
1121 encode(0x21231313, 0);
1122 encode(0x1, 0);
1123 encode_junk(rnd_size);
1124 return(0);
1125 }
1126
test_databar_F_3()1127 int test_databar_F_3 ()
1128 {
1129 expect(ZBAR_DATABAR_EXP, "1012A");
1130 assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE);
1131 encode(0x11, 0);
1132 encode(0x11521151, 0);
1133 encode(0x18411, 0);
1134 encode(0x13171121, 0);
1135 encode(0x11521232, 0);
1136 encode(0x11481, 0);
1137 encode(0x23171111, 0);
1138 encode(0x1, 0);
1139 encode_junk(rnd_size);
1140 return(0);
1141 }
1142
test_orange()1143 int test_orange ()
1144 {
1145 char data[32] = "0100845963000052";
1146 expect(ZBAR_DATABAR, data);
1147 assert(zbar_decoder_get_color(decoder) == ZBAR_SPACE);
1148 encode(0x1, 0);
1149 encode(0x23212321, 0); // data[0]
1150 encode(0x31911, 0); // finder[?] = 3
1151 encode(0x21121215, 1); // data[1]
1152 encode(0x41111133, 0); // data[3]
1153 encode(0x23811, 1); // finder[?] = 6
1154 encode(0x11215141, 1); // data[2]
1155 encode(0x11, 0);
1156 encode_junk(rnd_size);
1157
1158 expect(ZBAR_DATABAR, data);
1159 data[1] = '0';
1160 encode_databar(data + 1, FWD);
1161 encode_junk(rnd_size);
1162 return(0);
1163 }
1164
test_numeric(char * data)1165 int test_numeric (char *data)
1166 {
1167 char tmp[32] = "01";
1168 strncpy(tmp + 2, data + 1, 13);
1169 tmp[15]='\0';
1170 calc_ean_parity(tmp + 2, 13);
1171 expect(ZBAR_DATABAR, tmp);
1172
1173 tmp[1] = data[0] & '1';
1174 encode_databar(tmp + 1, (rand() >> 8) & 1);
1175
1176 encode_junk(rnd_size);
1177
1178 data[strlen(data) & ~1] = 0;
1179 expect(ZBAR_CODE128, data);
1180 encode_code128c(data);
1181
1182 encode_junk(rnd_size);
1183
1184 expect(ZBAR_I25, data);
1185 encode_i25(data, FWD);
1186
1187 encode_junk(rnd_size);
1188 #if 0 /* FIXME encoding broken */
1189 encode_i25(data, REV);
1190
1191 encode_junk(rnd_size);
1192 #endif
1193
1194 char *cdb = convert_codabar(data);
1195 expect(ZBAR_CODABAR, cdb);
1196 encode_codabar(cdb, FWD);
1197 encode_junk(rnd_size);
1198
1199 expect(ZBAR_CODABAR, cdb);
1200 encode_codabar(cdb, REV);
1201 encode_junk(rnd_size);
1202 free(cdb);
1203
1204 calc_ean_parity(data + 2, 12);
1205 expect(ZBAR_EAN13, data + 2);
1206 encode_ean13(data + 2);
1207 encode_junk(rnd_size);
1208
1209 calc_ean_parity(data + 7, 7);
1210 expect(ZBAR_EAN8, data + 7);
1211 encode_ean8(data + 7);
1212
1213 encode_junk(rnd_size);
1214
1215 data[5] = 0;
1216 expect(ZBAR_EAN5, data);
1217 encode_ean5(data);
1218
1219 encode_junk(rnd_size);
1220
1221 data[2] = 0;
1222 expect(ZBAR_EAN2, data);
1223 encode_ean2(data);
1224 encode_junk(rnd_size);
1225
1226 expect(ZBAR_NONE, NULL);
1227 return(0);
1228 }
1229
test_alpha(char * data)1230 int test_alpha (char *data)
1231 {
1232 expect(ZBAR_CODE128, data);
1233 encode_code128b(data);
1234
1235 encode_junk(rnd_size);
1236
1237 expect(ZBAR_CODE93, data);
1238 encode_code93(data, FWD);
1239
1240 encode_junk(rnd_size);
1241
1242 expect(ZBAR_CODE93, data);
1243 encode_code93(data, REV);
1244
1245 encode_junk(rnd_size);
1246
1247 char *cdb = convert_codabar(data);
1248 expect(ZBAR_CODABAR, cdb);
1249 encode_codabar(cdb, FWD);
1250 encode_junk(rnd_size);
1251
1252 expect(ZBAR_CODABAR, cdb);
1253 encode_codabar(cdb, REV);
1254 encode_junk(rnd_size);
1255 free(cdb);
1256
1257 convert_code39(data);
1258 expect(ZBAR_CODE39, data);
1259 encode_code39(data);
1260
1261 encode_junk(rnd_size);
1262
1263 #if 0 /* FIXME decoder unfinished */
1264 encode_pdf417(data);
1265
1266 encode_junk(rnd_size);
1267 #endif
1268
1269 expect(ZBAR_NONE, NULL);
1270 return(0);
1271 }
1272
test1()1273 int test1 ()
1274 {
1275 print_sep(2);
1276 if(!seed)
1277 seed = 0xbabeface;
1278 zprintf(1, "[%d] SEED=%d\n", iter, seed);
1279 srand(seed);
1280
1281 int i;
1282 char data[32];
1283 for(i = 0; i < 14; i++) {
1284 data[i] = (rand() % 10) + '0';
1285 }
1286 data[i] = 0;
1287
1288 zprintf(1, "testing data: %s\n", data);
1289
1290 test_numeric(data);
1291
1292 for(i = 0; i < 10; i++)
1293 data[i] = (rand() % 0x5f) + 0x20;
1294 data[i] = 0;
1295
1296 zprintf(1, "testing alpha: %s\n", data);
1297
1298 test_alpha(data);
1299 return(0);
1300 }
1301
1302 /* FIXME TBD:
1303 * - random module width (!= 1.0)
1304 * - simulate scan speed variance
1305 * - simulate dark "swelling" and light "blooming"
1306 * - inject parity errors
1307 */
1308
percent(int count,int iter)1309 float percent(int count, int iter)
1310 {
1311 if (iter <= 1) {
1312 if (count)
1313 return 100.0;
1314 else
1315 return 0.0;
1316 }
1317 return (count * 100.0) / iter;
1318 }
1319
main(int argc,char * argv[])1320 int main (int argc, char *argv[])
1321 {
1322 if (argp_parse(&argp, argc, argv, ARGP_NO_HELP | ARGP_NO_EXIT, 0, 0)) {
1323 argp_help(&argp, stderr, ARGP_HELP_SHORT_USAGE, PROGRAM_NAME);
1324 return -1;
1325 }
1326
1327 if (rand_seed) {
1328 seed = time(NULL);
1329 srand(seed);
1330 seed = (rand() << 8) ^ rand();
1331 zprintf(0, "Random SEED=%d\n", seed);
1332 }
1333
1334 decoder = zbar_decoder_create();
1335 /* allow empty CODE39 symbologies */
1336 zbar_decoder_set_config(decoder, ZBAR_CODE39, ZBAR_CFG_MIN_LEN, 0);
1337 /* enable addons */
1338 zbar_decoder_set_config(decoder, ZBAR_EAN2, ZBAR_CFG_ENABLE, 1);
1339 zbar_decoder_set_config(decoder, ZBAR_EAN5, ZBAR_CFG_ENABLE, 1);
1340 zbar_decoder_set_handler(decoder, symbol_handler);
1341
1342 encode_junk(rnd_size + 1);
1343
1344 if (num_iter) {
1345 for (iter == 0; iter < num_iter; iter++) {
1346 test1();
1347 seed = (rand() << 8) ^ rand();
1348 }
1349 } else {
1350 test_databar_F_1();
1351 test_databar_F_3();
1352 test_orange();
1353 test1();
1354 }
1355
1356 zbar_decoder_destroy(decoder);
1357
1358 if (!wrong &&
1359 percent(spurious, num_iter) <= 0.01 &&
1360 percent(missing, num_iter) <= 0.01) {
1361 if (spurious || missing)
1362 printf("decoder PASSED with %d spurious (%02.4f%%) and %d missing(%02.4f%%).\n",
1363 spurious, percent(spurious, num_iter),
1364 missing, percent(missing, num_iter));
1365 else
1366 printf("decoder PASSED.\n");
1367 } else {
1368 printf("decoder FAILED with %d wrong decoding(%02.4f%%), %d spurious (%02.4f%%) and %d missing(%02.4f%%).\n",
1369 wrong, percent(wrong, num_iter),
1370 spurious, percent(spurious, num_iter),
1371 missing, percent(missing, num_iter));
1372 return 1;
1373 }
1374 return(0);
1375 }
1376