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