diff options
Diffstat (limited to 'circuitpython/lib/quirc/tests')
-rw-r--r-- | circuitpython/lib/quirc/tests/dbgutil.c | 307 | ||||
-rw-r--r-- | circuitpython/lib/quirc/tests/dbgutil.h | 48 | ||||
-rw-r--r-- | circuitpython/lib/quirc/tests/inspect.c | 264 | ||||
-rw-r--r-- | circuitpython/lib/quirc/tests/qrtest.c | 309 |
4 files changed, 928 insertions, 0 deletions
diff --git a/circuitpython/lib/quirc/tests/dbgutil.c b/circuitpython/lib/quirc/tests/dbgutil.c new file mode 100644 index 0000000..c023d91 --- /dev/null +++ b/circuitpython/lib/quirc/tests/dbgutil.c @@ -0,0 +1,307 @@ +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <jpeglib.h> +#include <png.h> + +#include <quirc.h> + +#include "dbgutil.h" + +static const char *data_type_str(int dt) +{ + switch (dt) { + case QUIRC_DATA_TYPE_NUMERIC: return "NUMERIC"; + case QUIRC_DATA_TYPE_ALPHA: return "ALPHA"; + case QUIRC_DATA_TYPE_BYTE: return "BYTE"; + case QUIRC_DATA_TYPE_KANJI: return "KANJI"; + } + + return "unknown"; +} + +void dump_data(const struct quirc_data *data) +{ + printf(" Version: %d\n", data->version); + printf(" ECC level: %c\n", "MLHQ"[data->ecc_level]); + printf(" Mask: %d\n", data->mask); + printf(" Data type: %d (%s)\n", + data->data_type, data_type_str(data->data_type)); + printf(" Length: %d\n", data->payload_len); + printf(" Payload: %s\n", data->payload); + + if (data->eci) + printf(" ECI: %d\n", data->eci); +} + +void dump_cells(const struct quirc_code *code) +{ + int u, v; + + printf(" %d cells, corners:", code->size); + for (u = 0; u < 4; u++) + printf(" (%d,%d)", code->corners[u].x, + code->corners[u].y); + printf("\n"); + + for (v = 0; v < code->size; v++) { + printf(" "); + for (u = 0; u < code->size; u++) { + int p = v * code->size + u; + + if (code->cell_bitmap[p >> 3] & (1 << (p & 7))) + printf("[]"); + else + printf(" "); + } + printf("\n"); + } +} + +struct my_jpeg_error { + struct jpeg_error_mgr base; + jmp_buf env; +}; + +static void my_output_message(struct jpeg_common_struct *com) +{ + struct my_jpeg_error *err = (struct my_jpeg_error *)com->err; + char buf[JMSG_LENGTH_MAX]; + + err->base.format_message(com, buf); + fprintf(stderr, "JPEG error: %s\n", buf); +} + +static void my_error_exit(struct jpeg_common_struct *com) +{ + struct my_jpeg_error *err = (struct my_jpeg_error *)com->err; + + my_output_message(com); + longjmp(err->env, 0); +} + +static struct jpeg_error_mgr *my_error_mgr(struct my_jpeg_error *err) +{ + jpeg_std_error(&err->base); + + err->base.error_exit = my_error_exit; + err->base.output_message = my_output_message; + + return &err->base; +} + +int load_jpeg(struct quirc *q, const char *filename) +{ + FILE *infile = fopen(filename, "rb"); + struct jpeg_decompress_struct dinfo; + struct my_jpeg_error err; + uint8_t *image; + int y; + + if (!infile) { + perror("can't open input file"); + return -1; + } + + memset(&dinfo, 0, sizeof(dinfo)); + dinfo.err = my_error_mgr(&err); + + if (setjmp(err.env)) + goto fail; + + jpeg_create_decompress(&dinfo); + jpeg_stdio_src(&dinfo, infile); + + jpeg_read_header(&dinfo, TRUE); + dinfo.output_components = 1; + dinfo.out_color_space = JCS_GRAYSCALE; + jpeg_start_decompress(&dinfo); + + if (dinfo.output_components != 1) { + fprintf(stderr, "Unexpected number of output components: %d", + dinfo.output_components); + goto fail; + } + + if (quirc_resize(q, dinfo.output_width, dinfo.output_height) < 0) + goto fail; + + image = quirc_begin(q, NULL, NULL); + + for (y = 0; y < dinfo.output_height; y++) { + JSAMPROW row_pointer = image + y * dinfo.output_width; + + jpeg_read_scanlines(&dinfo, &row_pointer, 1); + } + + jpeg_finish_decompress(&dinfo); + fclose(infile); + jpeg_destroy_decompress(&dinfo); + return 0; + +fail: + fclose(infile); + jpeg_destroy_decompress(&dinfo); + return -1; +} + +/* hacked from https://dev.w3.org/Amaya/libpng/example.c + * + * Check if a file is a PNG image using png_sig_cmp(). Returns 1 if the given + * file is a PNG and 0 otherwise. + */ +#define PNG_BYTES_TO_CHECK 4 +int check_if_png(const char *filename) +{ + int ret = 0; + FILE *infile = NULL; + unsigned char buf[PNG_BYTES_TO_CHECK]; + + /* Open the prospective PNG file. */ + if ((infile = fopen(filename, "rb")) == NULL) + goto out; + + /* Read in some of the signature bytes */ + if (fread(buf, 1, PNG_BYTES_TO_CHECK, infile) != PNG_BYTES_TO_CHECK) + goto out; + + /* + * Compare the first PNG_BYTES_TO_CHECK bytes of the signature. + * png_sig_cmp() returns zero if the image is a PNG and nonzero if it + * isn't a PNG. + */ + if (png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK) == 0) + ret = 1; + + /* FALLTHROUGH */ +out: + if (infile) + fclose(infile); + return (ret); +} + +int load_png(struct quirc *q, const char *filename) +{ + int width, height, rowbytes, interlace_type, number_passes = 1; + png_uint_32 trns; + png_byte color_type, bit_depth; + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + FILE *infile = NULL; + uint8_t *image; + int ret = -1; + int pass; + + if ((infile = fopen(filename, "rb")) == NULL) + goto out; + + png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + goto out; + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + goto out; + + if (setjmp(png_jmpbuf(png_ptr))) + goto out; + + png_init_io(png_ptr, infile); + + png_read_info(png_ptr, info_ptr); + + color_type = png_get_color_type(png_ptr, info_ptr); + bit_depth = png_get_bit_depth(png_ptr, info_ptr); + interlace_type = png_get_interlace_type(png_ptr, info_ptr); + + // Read any color_type into 8bit depth, Grayscale format. + // See http://www.libpng.org/pub/png/libpng-manual.txt + + // PNG_COLOR_TYPE_GRAY_ALPHA is always 8 or 16bit depth. + if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) + png_set_expand_gray_1_2_4_to_8(png_ptr); + + if ((trns = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) + png_set_tRNS_to_alpha(png_ptr); + + if (bit_depth == 16) +#if PNG_LIBPNG_VER >= 10504 + png_set_scale_16(png_ptr); +#else + png_set_strip_16(png_ptr); +#endif + + if ((trns) || color_type & PNG_COLOR_MASK_ALPHA) + png_set_strip_alpha(png_ptr); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb(png_ptr); + + if (color_type == PNG_COLOR_TYPE_PALETTE || + color_type == PNG_COLOR_TYPE_RGB || + color_type == PNG_COLOR_TYPE_RGB_ALPHA) { + png_set_rgb_to_gray_fixed(png_ptr, 1, -1, -1); + } + + if (interlace_type != PNG_INTERLACE_NONE) + number_passes = png_set_interlace_handling(png_ptr); + + png_read_update_info(png_ptr, info_ptr); + + width = png_get_image_width(png_ptr, info_ptr); + height = png_get_image_height(png_ptr, info_ptr); + rowbytes = png_get_rowbytes(png_ptr, info_ptr); + if (rowbytes != width) { + fprintf(stderr, + "load_png: expected rowbytes to be %u but got %u\n", + width, rowbytes); + goto out; + } + + if (quirc_resize(q, width, height) < 0) + goto out; + + image = quirc_begin(q, NULL, NULL); + + for (pass = 0; pass < number_passes; pass++) { + int y; + + for (y = 0; y < height; y++) { + png_bytep row_pointer = image + y * width; + png_read_rows(png_ptr, &row_pointer, NULL, 1); + } + } + + png_read_end(png_ptr, info_ptr); + + ret = 0; + /* FALLTHROUGH */ +out: + /* cleanup */ + if (png_ptr) { + if (info_ptr) + png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)NULL); + else + png_destroy_read_struct(&png_ptr, (png_infopp)NULL, (png_infopp)NULL); + } + if (infile) + fclose(infile); + return (ret); +} diff --git a/circuitpython/lib/quirc/tests/dbgutil.h b/circuitpython/lib/quirc/tests/dbgutil.h new file mode 100644 index 0000000..7a5cc6a --- /dev/null +++ b/circuitpython/lib/quirc/tests/dbgutil.h @@ -0,0 +1,48 @@ +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef DBGUTIL_H_ +#define DBGUTIL_H_ + +#include "quirc.h" + +/* Dump decoded information on stdout. */ +void dump_data(const struct quirc_data *data); + +/* Dump a grid cell map on stdout. */ +void dump_cells(const struct quirc_code *code); + +/* Read a JPEG image into the decoder. + * + * Note that you must call quirc_end() if the function returns + * successfully (0). + */ +int load_jpeg(struct quirc *q, const char *filename); + +/* Check if a file is a PNG image. + * + * returns 1 if the given file is a PNG and 0 otherwise. + */ +int check_if_png(const char *filename); + +/* Read a PNG image into the decoder. + * + * Note that you must call quirc_end() if the function returns + * successfully (0). + */ +int load_png(struct quirc *q, const char *filename); + +#endif diff --git a/circuitpython/lib/quirc/tests/inspect.c b/circuitpython/lib/quirc/tests/inspect.c new file mode 100644 index 0000000..ce5357a --- /dev/null +++ b/circuitpython/lib/quirc/tests/inspect.c @@ -0,0 +1,264 @@ +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> +#include <SDL.h> +#include <SDL_gfxPrimitives.h> +#include "quirc_internal.h" +#include "dbgutil.h" + +static void dump_info(struct quirc *q) +{ + int count = quirc_count(q); + int i; + + printf("%d QR-codes found:\n\n", count); + for (i = 0; i < count; i++) { + struct quirc_code code; + struct quirc_data data; + quirc_decode_error_t err; + + quirc_extract(q, i, &code); + err = quirc_decode(&code, &data); + if (err == QUIRC_ERROR_DATA_ECC) { + quirc_flip(&code); + err = quirc_decode(&code, &data); + } + + dump_cells(&code); + printf("\n"); + + if (err) { + printf(" Decoding FAILED: %s\n", quirc_strerror(err)); + } else { + printf(" Decoding successful:\n"); + dump_data(&data); + } + + printf("\n"); + } +} + +static void draw_frame(SDL_Surface *screen, struct quirc *q) +{ + uint8_t *pix; + uint8_t *raw = q->image; + int x, y; + + SDL_LockSurface(screen); + pix = screen->pixels; + for (y = 0; y < q->h; y++) { + uint32_t *row = (uint32_t *)pix; + + for (x = 0; x < q->w; x++) { + uint8_t v = *(raw++); + uint32_t color = (v << 16) | (v << 8) | v; + struct quirc_region *reg = &q->regions[v]; + + switch (v) { + case QUIRC_PIXEL_WHITE: + color = 0x00ffffff; + break; + + case QUIRC_PIXEL_BLACK: + color = 0x00000000; + break; + + default: + if (reg->capstone >= 0) + color = 0x00008000; + else + color = 0x00808080; + break; + } + + *(row++) = color; + } + + pix += screen->pitch; + } + SDL_UnlockSurface(screen); +} + +static void draw_blob(SDL_Surface *screen, int x, int y) +{ + int i, j; + + for (i = -2; i <= 2; i++) + for (j = -2; j <= 2; j++) + pixelColor(screen, x + i, y + j, 0x0000ffff); +} + +static void draw_mark(SDL_Surface *screen, int x, int y) +{ + pixelColor(screen, x, y, 0xff0000ff); + pixelColor(screen, x + 1, y, 0xff0000ff); + pixelColor(screen, x - 1, y, 0xff0000ff); + pixelColor(screen, x, y + 1, 0xff0000ff); + pixelColor(screen, x, y - 1, 0xff0000ff); +} + +static void draw_capstone(SDL_Surface *screen, struct quirc *q, int index) +{ + struct quirc_capstone *cap = &q->capstones[index]; + int j; + char buf[8]; + + for (j = 0; j < 4; j++) { + struct quirc_point *p0 = &cap->corners[j]; + struct quirc_point *p1 = &cap->corners[(j + 1) % 4]; + + lineColor(screen, p0->x, p0->y, p1->x, p1->y, + 0x800080ff); + } + + draw_blob(screen, cap->corners[0].x, cap->corners[0].y); + + if (cap->qr_grid < 0) { + snprintf(buf, sizeof(buf), "?%d", index); + stringColor(screen, cap->center.x, cap->center.y, buf, + 0x000000ff); + } +} + +static void perspective_map(const double *c, + double u, double v, struct quirc_point *ret) +{ + double den = c[6]*u + c[7]*v + 1.0; + double x = (c[0]*u + c[1]*v + c[2]) / den; + double y = (c[3]*u + c[4]*v + c[5]) / den; + + ret->x = rint(x); + ret->y = rint(y); +} + +static void draw_grid(SDL_Surface *screen, struct quirc *q, int index) +{ + struct quirc_grid *qr = &q->grids[index]; + int x, y; + int i; + + for (i = 0; i < 3; i++) { + struct quirc_capstone *cap = &q->capstones[qr->caps[i]]; + char buf[16]; + + snprintf(buf, sizeof(buf), "%d.%c", index, "ABC"[i]); + stringColor(screen, cap->center.x, cap->center.y, buf, + 0x000000ff); + } + + lineColor(screen, qr->tpep[0].x, qr->tpep[0].y, + qr->tpep[1].x, qr->tpep[1].y, 0xff00ffff); + lineColor(screen, qr->tpep[1].x, qr->tpep[1].y, + qr->tpep[2].x, qr->tpep[2].y, 0xff00ffff); + + if (qr->align_region >= 0) + draw_blob(screen, qr->align.x, qr->align.y); + + for (y = 0; y < qr->grid_size; y++) { + for (x = 0; x < qr->grid_size; x++) { + double u = x + 0.5; + double v = y + 0.5; + struct quirc_point p; + + perspective_map(qr->c, u, v, &p); + draw_mark(screen, p.x, p.y); + } + } +} + +static int sdl_examine(struct quirc *q) +{ + SDL_Surface *screen; + SDL_Event ev; + + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + fprintf(stderr, "couldn't init SDL: %s\n", SDL_GetError()); + return -1; + } + + screen = SDL_SetVideoMode(q->w, q->h, 32, SDL_SWSURFACE); + if (!screen) { + fprintf(stderr, "couldn't init video mode: %s\n", + SDL_GetError()); + return -1; + } + + while (SDL_WaitEvent(&ev) >= 0) { + int i; + + if (ev.type == SDL_QUIT) + break; + + if (ev.type == SDL_KEYDOWN && + ev.key.keysym.sym == 'q') + break; + + draw_frame(screen, q); + for (i = 0; i < q->num_capstones; i++) + draw_capstone(screen, q, i); + for (i = 0; i < q->num_grids; i++) + draw_grid(screen, q, i); + SDL_Flip(screen); + } + + SDL_Quit(); + return 0; +} + +int main(int argc, char **argv) +{ + struct quirc *q; + + printf("quirc inspection program\n"); + printf("Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com>\n"); + printf("Library version: %s\n", quirc_version()); + printf("\n"); + + if (argc < 2) { + fprintf(stderr, "Usage: %s <testfile.jpg|testfile.png>\n", argv[0]); + return -1; + } + + q = quirc_new(); + if (!q) { + perror("can't create quirc object"); + return -1; + } + + int status = -1; + if (check_if_png(argv[1])) { + status = load_png(q, argv[1]); + } else { + status = load_jpeg(q, argv[1]); + } + if (status < 0) { + quirc_destroy(q); + return -1; + } + + quirc_end(q); + dump_info(q); + + if (sdl_examine(q) < 0) { + quirc_destroy(q); + return -1; + } + + quirc_destroy(q); + return 0; +} diff --git a/circuitpython/lib/quirc/tests/qrtest.c b/circuitpython/lib/quirc/tests/qrtest.c new file mode 100644 index 0000000..1bb178e --- /dev/null +++ b/circuitpython/lib/quirc/tests/qrtest.c @@ -0,0 +1,309 @@ +/* quirc -- QR-code recognition library + * Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <dirent.h> +#include <ctype.h> +#include <quirc.h> +#include <jpeglib.h> +#include <setjmp.h> +#include <time.h> +#include "dbgutil.h" + +static int want_verbose = 0; +static int want_cell_dump = 0; + +#define MS(ts) (unsigned int)((ts.tv_sec * 1000) + (ts.tv_nsec / 1000000)) + +static struct quirc *decoder; + +struct result_info { + int file_count; + int id_count; + int decode_count; + + unsigned int load_time; + unsigned int identify_time; + unsigned int total_time; +}; + +static void print_result(const char *name, struct result_info *info) +{ + puts("----------------------------------------" + "---------------------------------------"); + printf("%s: %d files, %d codes, %d decoded (%d failures)", + name, info->file_count, info->id_count, info->decode_count, + (info->id_count - info->decode_count)); + if (info->id_count) + printf(", %d%% success rate", + (info->decode_count * 100 + info->id_count / 2) / + info->id_count); + printf("\n"); + printf("Total time [load: %u, identify: %u, total: %u]\n", + info->load_time, + info->identify_time, + info->total_time); + if (info->file_count) + printf("Average time [load: %u, identify: %u, total: %u]\n", + info->load_time / info->file_count, + info->identify_time / info->file_count, + info->total_time / info->file_count); +} + +static void add_result(struct result_info *sum, struct result_info *inf) +{ + sum->file_count += inf->file_count; + sum->id_count += inf->id_count; + sum->decode_count += inf->decode_count; + + sum->load_time += inf->load_time; + sum->identify_time += inf->identify_time; + sum->total_time += inf->total_time; +} + +static int scan_file(const char *path, const char *filename, + struct result_info *info) +{ + int (*loader)(struct quirc *, const char *); + int len = strlen(filename); + const char *ext; + struct timespec tp; + unsigned int start; + unsigned int total_start; + int ret; + int i; + + while (len >= 0 && filename[len] != '.') + len--; + ext = filename + len + 1; + if (strcasecmp(ext, "jpg") == 0 || strcasecmp(ext, "jpeg") == 0) + loader = load_jpeg; + else if (strcasecmp(ext, "png") == 0) + loader = load_png; + else + return 0; + + (void)clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp); + total_start = start = MS(tp); + ret = loader(decoder, path); + (void)clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp); + info->load_time = MS(tp) - start; + + if (ret < 0) { + fprintf(stderr, "%s: load failed\n", filename); + return -1; + } + + (void)clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp); + start = MS(tp); + quirc_end(decoder); + (void)clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp); + info->identify_time = MS(tp) - start; + + info->id_count = quirc_count(decoder); + for (i = 0; i < info->id_count; i++) { + struct quirc_code code; + struct quirc_data data; + + quirc_extract(decoder, i, &code); + + quirc_decode_error_t err = quirc_decode(&code, &data); + if (err == QUIRC_ERROR_DATA_ECC) { + quirc_flip(&code); + err = quirc_decode(&code, &data); + } + + if (!err) { + info->decode_count++; + } + } + + (void)clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &tp); + info->total_time += MS(tp) - total_start; + + printf(" %-30s: %5u %5u %5u %5d %5d\n", filename, + info->load_time, + info->identify_time, + info->total_time, + info->id_count, info->decode_count); + + if (want_cell_dump || want_verbose) { + for (i = 0; i < info->id_count; i++) { + struct quirc_code code; + + quirc_extract(decoder, i, &code); + if (want_cell_dump) { + dump_cells(&code); + printf("\n"); + } + + if (want_verbose) { + struct quirc_data data; + quirc_decode_error_t err = quirc_decode(&code, &data); + if (err == QUIRC_ERROR_DATA_ECC) { + quirc_flip(&code); + err = quirc_decode(&code, &data); + } + + if (err) { + printf(" ERROR: %s\n\n", quirc_strerror(err)); + } else { + printf(" Decode successful:\n"); + dump_data(&data); + printf("\n"); + } + } + } + } + + info->file_count = 1; + return 1; +} + +static int test_scan(const char *path, struct result_info *info); + +static int scan_dir(const char *path, const char *filename, + struct result_info *info) +{ + DIR *d = opendir(path); + struct dirent *ent; + int count = 0; + + if (!d) { + fprintf(stderr, "%s: opendir: %s\n", path, strerror(errno)); + return -1; + } + + printf("%s:\n", path); + + while ((ent = readdir(d))) { + if (ent->d_name[0] != '.') { + char fullpath[1024]; + struct result_info sub; + + snprintf(fullpath, sizeof(fullpath), "%s/%s", + path, ent->d_name); + if (test_scan(fullpath, &sub) > 0) { + add_result(info, &sub); + count++; + } + } + } + + closedir(d); + + if (count > 1) { + print_result(filename, info); + puts(""); + } + + return count > 0; +} + +static int test_scan(const char *path, struct result_info *info) +{ + int len = strlen(path); + struct stat st; + const char *filename; + + memset(info, 0, sizeof(*info)); + + while (len >= 0 && path[len] != '/') + len--; + filename = path + len + 1; + + if (lstat(path, &st) < 0) { + fprintf(stderr, "%s: lstat: %s\n", path, strerror(errno)); + return -1; + } + + if (S_ISREG(st.st_mode)) + return scan_file(path, filename, info); + + if (S_ISDIR(st.st_mode)) + return scan_dir(path, filename, info); + + return 0; +} + +static int run_tests(int argc, char **argv) +{ + struct result_info sum; + int count = 0; + int i; + + decoder = quirc_new(); + if (!decoder) { + perror("quirc_new"); + return -1; + } + + printf(" %-30s %17s %11s\n", "", "Time (ms)", "Count"); + printf(" %-30s %5s %5s %5s %5s %5s\n", + "Filename", "Load", "ID", "Total", "ID", "Dec"); + puts("----------------------------------------" + "---------------------------------------"); + + memset(&sum, 0, sizeof(sum)); + for (i = 0; i < argc; i++) { + struct result_info info; + + if (test_scan(argv[i], &info) > 0) { + add_result(&sum, &info); + count++; + } + } + + if (count > 1) + print_result("TOTAL", &sum); + + quirc_destroy(decoder); + return 0; +} + +int main(int argc, char **argv) +{ + int opt; + + printf("quirc test program\n"); + printf("Copyright (C) 2010-2012 Daniel Beer <dlbeer@gmail.com>\n"); + printf("Library version: %s\n", quirc_version()); + printf("\n"); + + while ((opt = getopt(argc, argv, "vd")) >= 0) + switch (opt) { + case 'v': + want_verbose = 1; + break; + + case 'd': + want_cell_dump = 1; + break; + + case '?': + return -1; + } + + argv += optind; + argc -= optind; + + return run_tests(argc, argv);; +} |