diff --git a/backend/common.c b/backend/common.c index 1627b212..c3b9d0c2 100644 --- a/backend/common.c +++ b/backend/common.c @@ -86,7 +86,7 @@ INTERNAL void to_upper(unsigned char source[]) { for (i = 0; i < src_len; i++) { if ((source[i] >= 'a') && (source[i] <= 'z')) { - source [i] = (source[i] - 'a') + 'A'; + source[i] = (source[i] - 'a') + 'A'; } } } diff --git a/backend/library.c b/backend/library.c index 472ff988..1d0bc961 100644 --- a/backend/library.c +++ b/backend/library.c @@ -235,7 +235,7 @@ static int dump_plot(struct zint_symbol *symbol) { space++; byt = 0; } - if (space == 2) { + if (space == 2 && i + 1 < symbol->width) { fputc(' ', f); space = 0; } diff --git a/backend/svg.c b/backend/svg.c index 17b8fc42..27355725 100644 --- a/backend/svg.c +++ b/backend/svg.c @@ -183,7 +183,7 @@ INTERNAL int svg_plot(struct zint_symbol *symbol) { fsvg = fopen(symbol->outfile, "w"); } if (fsvg == NULL) { - strcpy(symbol->errtxt, "660: Could not open output file"); + strcpy(symbol->errtxt, "680: Could not open output file"); return ZINT_ERROR_FILE_ACCESS; } diff --git a/backend/tests/CMakeLists.txt b/backend/tests/CMakeLists.txt index 492bc8a9..edc16155 100644 --- a/backend/tests/CMakeLists.txt +++ b/backend/tests/CMakeLists.txt @@ -13,7 +13,7 @@ set(ZINT_DEBUG FALSE CACHE BOOL "Set debug compile flag") set(ZINT_SANITIZE FALSE CACHE BOOL "Set sanitize compile/link flags") set(ZINT_TEST FALSE CACHE BOOL "Set test compile flag") -find_package(LibZint 2.7.1 REQUIRED) +find_package(LibZint REQUIRED) find_package(PNG) if(PNG_FOUND) diff --git a/docs/manual.txt b/docs/manual.txt index 93fadcd4..68d150f7 100644 --- a/docs/manual.txt +++ b/docs/manual.txt @@ -184,9 +184,7 @@ zint -d "This Text" This will encode the text "This Text". Zint will use the default symbology, Code 128, and output to the default file out.png in the current directory. Alternatively, if libpng was not present when Zint was built, the default -output file will be out.gif. The -d switch and the input data should always -be the last entry on the command line input. Any options given after this -will be ignored. +output file will be out.gif. The data input to Zint is assumed to be encoded in Unicode (UTF-8) format. If you are encoding characters beyond the 7-bit ASCII set using a scheme other than @@ -222,8 +220,7 @@ Escape Character | ASCII Equivalent | Interpretation Input data can be read directly from file using the -i switch as shown below. The input file is assumed to be Unicode (UTF-8) formatted unless an alternative -mode is selected. This command replaces the use of the -d switch and should -similarly be the last option given. +mode is selected. This command replaces the use of the -d switch. zint -i ./somefile.txt @@ -2007,7 +2004,6 @@ Input | Symbol Size 48 | 26 x 64 --------------------- - DMRE symbol sizes may be activated in automatic size mode using the option --dmre or by the API option_3 = DM_DMRE diff --git a/frontend/main.c b/frontend/main.c index 4592af4e..48ab3ad2 100644 --- a/frontend/main.c +++ b/frontend/main.c @@ -27,13 +27,15 @@ #include #include #else +#include #include "getopt.h" #include "zint.h" #endif + #define NESET "0123456789" -#ifdef _MSC_VER -#include +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #endif /* Print list of supported symbologies */ @@ -112,14 +114,14 @@ static void usage(void) { " --notext Remove human readable text\n" " -o, --output=FILE Send output to FILE. Default is out.png\n" " --primary=STRING Set structured primary message (Maxicode/Composite)\n" + " -r, --reverse Reverse colours (white on black)\n" + " --rotate=NUMBER Rotate symbol by NUMBER degrees (BMP/GIF/PCX/PNG/TIF)\n" + " --rows=NUMBER Set number of rows (Codablock-F)\n" " --scale=NUMBER Adjust size of X-dimension\n" " --secure=NUMBER Set error correction level (ECC)\n" " --separator=NUMBER Set height of row separator bars (stacked symbologies)\n" " --small Use small text\n" " --square Force Data Matrix symbols to be square\n" - " -r, --reverse Reverse colours (white on black)\n" - " --rotate=NUMBER Rotate symbol by NUMBER degrees (BMP/GIF/PCX/PNG/TIF)\n" - " --rows=NUMBER Set number of rows (Codablock-F)\n" " -t, --types Display table of barcode types\n" " --vers=NUMBER Set symbol version (size, check digits, other options)\n" " -w, --whitesp=NUMBER Set width of whitespace in multiples of X-dimension\n" @@ -186,43 +188,93 @@ static char itoc(int source) { } } -/* Concatinates dest[] with the contents of source[], copying /0 as well */ -static void concat(char dest[], char source[]) { - unsigned int i, j, n; +/* Converts upper case characters to lower case in a string source[] */ +static void to_lower(char source[]) { + int i, src_len = strlen(source); - j = strlen(dest); - n = strlen(source); - for (i = 0; i <= n; i++) { - dest[i + j] = source[i]; + for (i = 0; i < src_len; i++) { + if ((source[i] >= 'A') && (source[i] <= 'Z')) { + source[i] = (source[i] - 'A') + 'a'; + } } } +static char *filetypes[] = { + "bmp", "emf", "eps", "gif", "pcx", "png", "svg", "tif", "txt", // TODO: Determine if PNG available +}; + +/* Whether `filetype` supported by Zint */ +static int supported_filetype(char *filetype) { + char lc_filetype[4] = {0}; + int i; + + strncpy(lc_filetype, filetype, 3); + to_lower(lc_filetype); + + for (i = 0; i < (int) ARRAY_SIZE(filetypes); i++) { + if (strcmp(lc_filetype, filetypes[i]) == 0) { + return 1; + } + } + return 0; +} + +/* Get file extension, excluding those of 4 or more letters */ +static char *get_extension(char *file) { + char *dot; + + dot = strrchr(file, '.'); + if (dot && strlen(file) - (dot - file) <= 4) { /* Only recognize up to 3 letter extensions */ + return dot + 1; + } + return NULL; +} + +/* Set extension of `file` to `filetype`, replacing existing extension if any. + * Does nothing if file already has `filetype` extension */ +static void set_extension(char *file, char *filetype) { + char lc_filetype[4] = {0}; + char *extension; + char lc_extension[4]; + + strncpy(lc_filetype, filetype, 3); + to_lower(lc_filetype); + + extension = get_extension(file); + if (extension) { + strcpy(lc_extension, extension); + to_lower(lc_extension); + if (strcmp(lc_filetype, lc_extension) == 0) { + return; + } + *(extension - 1) = '\0'; /* Cut off at dot */ + } + if (strlen(file) > 251) { + file[251] = '\0'; + } + strcat(file, "."); + strcat(file, filetype); +} + static int batch_process(struct zint_symbol *symbol, char *filename, int mirror_mode, char *filetype, int rotate_angle) { FILE *file; - unsigned char buffer[7100]; + unsigned char buffer[7828] = {0}; // 7828 maximum HanXin input unsigned char character = 0; int posn = 0, error_number = 0, line_count = 1; char output_file[256]; char number[12], reverse_number[12]; int inpos, local_line_count; - char format_string[127], reversed_string[127], format_char; + char format_string[256], reversed_string[256], format_char; int format_len, i, o; - char adjusted[2]; + char adjusted[2] = {0}; - memset(buffer, 0, sizeof (unsigned char) * 7100); - memset(format_string, 0, sizeof (unsigned char) * 127); if (symbol->outfile[0] == '\0') { strcpy(format_string, "~~~~~."); strcat(format_string, filetype); } else { - if (strlen(format_string) < 127) { - strcpy(format_string, symbol->outfile); - } else { - strcpy(symbol->errtxt, "101: Format string too long"); - return ZINT_ERROR_INVALID_DATA; - } + strcpy(format_string, symbol->outfile); + set_extension(format_string, filetype); } - memset(adjusted, 0, sizeof (char) * 2); if (!strcmp(filename, "-")) { file = stdin; @@ -242,7 +294,7 @@ static int batch_process(struct zint_symbol *symbol, char *filename, int mirror_ } character = (unsigned char) intChar; if (character == '\n') { - if (buffer[posn - 1] == '\r') { + if (posn > 0 && buffer[posn - 1] == '\r') { /* CR+LF - assume Windows formatting and remove CR */ posn--; buffer[posn] = '\0'; @@ -251,10 +303,10 @@ static int batch_process(struct zint_symbol *symbol, char *filename, int mirror_ if (mirror_mode == 0) { inpos = 0; local_line_count = line_count; - memset(number, 0, sizeof (char) * 12); - memset(reverse_number, 0, sizeof (char) * 12); - memset(reversed_string, 0, sizeof (char) * 127); - memset(output_file, 0, sizeof (char) * 127); + memset(number, 0, sizeof(number)); + memset(reverse_number, 0, sizeof(reverse_number)); + memset(reversed_string, 0, sizeof(reversed_string)); + memset(output_file, 0, sizeof(output_file)); do { number[inpos] = itoc(local_line_count % 10); local_line_count /= 10; @@ -299,7 +351,7 @@ static int batch_process(struct zint_symbol *symbol, char *filename, int mirror_ adjusted[0] = format_string[i - 1]; break; } - concat(reversed_string, adjusted); + strcat(reversed_string, adjusted); } for (i = 0; i < format_len; i++) { @@ -310,7 +362,6 @@ static int batch_process(struct zint_symbol *symbol, char *filename, int mirror_ i = 0; o = 0; do { - //for (i = 0; (i < posn && i < 250); i++) { if (buffer[i] < 0x20) { output_file[o] = '_'; } else { @@ -330,6 +381,7 @@ static int batch_process(struct zint_symbol *symbol, char *filename, int mirror_ break; default: output_file[o] = buffer[i]; + break; } } @@ -342,7 +394,7 @@ static int batch_process(struct zint_symbol *symbol, char *filename, int mirror_ } i++; o++; - } while (i < posn && o < 250); + } while (i < posn && o < 251); /* Add file extension */ output_file[o] = '.'; @@ -358,14 +410,14 @@ static int batch_process(struct zint_symbol *symbol, char *filename, int mirror_ fflush(stderr); } ZBarcode_Clear(symbol); - memset(buffer, 0, sizeof (unsigned char) * 7100); + memset(buffer, 0, sizeof(buffer)); posn = 0; line_count++; } else { buffer[posn] = character; posn++; } - if (posn > 7090) { + if (posn >= (int) sizeof(buffer)) { fprintf(stderr, "On line %d: Error 103: Input data too long\n", line_count); fflush(stderr); do { @@ -443,33 +495,33 @@ static int is_extendable(const int symbology) { return 0; } +typedef struct { char *arg; int opt; } arg_opt; + int main(int argc, char **argv) { struct zint_symbol *my_symbol; - int error_number; - int rotate_angle; - int generated; - int batch_mode; - int mirror_mode; - int fullmultibyte; - int separator; - int addon_gap; - char filetype[4]; + int error_number = 0; + int rotate_angle = 0; + int help = 0; + int data_cnt = 0; + int input_cnt = 0; + int batch_mode = 0; + int mirror_mode = 0; + int fullmultibyte = 0; + int separator = 0; + int addon_gap = 0; + char filetype[4] = {0}; int i; + int ret; + char *outfile_extension; + int data_arg_num = 0; +#ifndef _MSC_VER + arg_opt arg_opts[(argc + 1) / 2]; +#else + arg_opt *arg_opts = (arg_opt *) _alloca(((argc + 1) / 2) * sizeof(arg_opt)); +#endif - error_number = 0; - rotate_angle = 0; - generated = 0; my_symbol = ZBarcode_Create(); my_symbol->input_mode = UNICODE_MODE; - batch_mode = 0; - mirror_mode = 0; - fullmultibyte = 0; - separator = 0; - addon_gap = 0; - - for (i = 0; i < 4; i++) { - filetype[i] = '\0'; - } if (argc == 1) { usage(); @@ -479,57 +531,57 @@ int main(int argc, char **argv) { while (1) { int option_index = 0; static struct option long_options[] = { - {"help", 0, 0, 'h'}, - {"types", 0, 0, 't'}, - {"ecinos", 0, 0, 'e'}, - {"bind", 0, 0, 0}, - {"box", 0, 0, 0}, - {"direct", 0, 0, 0}, - {"dump", 0, 0, 0}, + {"addongap", 1, 0, 0}, {"barcode", 1, 0, 'b'}, - {"height", 1, 0, 0}, - {"whitesp", 1, 0, 'w'}, - {"border", 1, 0, 0}, - {"data", 1, 0, 'd'}, - {"output", 1, 0, 'o'}, - {"input", 1, 0, 'i'}, - {"fg", 1, 0, 0}, + {"batch", 0, 0, 0}, + {"binary", 0, 0, 0}, {"bg", 1, 0, 0}, + {"bind", 0, 0, 0}, + {"bold", 0, 0, 0}, + {"border", 1, 0, 0}, + {"box", 0, 0, 0}, + {"cmyk", 0, 0, 0}, {"cols", 1, 0, 0}, - {"rows", 1, 0, 0}, - {"vers", 1, 0, 0}, - {"rotate", 1, 0, 0}, - {"secure", 1, 0, 0}, - {"reverse", 1, 0, 'r'}, - {"mode", 1, 0, 0}, - {"primary", 1, 0, 0}, - {"scale", 1, 0, 0}, - {"separator", 1, 0, 0}, + {"data", 1, 0, 'd'}, + {"direct", 0, 0, 0}, + {"dmre", 0, 0, 0}, + {"dotsize", 1, 0, 0}, + {"dotty", 0, 0, 0}, + {"dump", 0, 0, 0}, + {"eci", 1, 0, 0}, + {"ecinos", 0, 0, 'e'}, + {"esc", 0, 0, 0}, + {"fg", 1, 0, 0}, + {"filetype", 1, 0, 0}, + {"fontsize", 1, 0, 0}, + {"fullmultibyte", 0, 0, 0}, {"gs1", 0, 0, 0}, {"gssep", 0, 0, 0}, - {"binary", 0, 0, 0}, - {"fullmultibyte", 0, 0, 0}, + {"height", 1, 0, 0}, + {"help", 0, 0, 'h'}, + {"init", 0, 0, 0}, + {"input", 1, 0, 'i'}, + {"mirror", 0, 0, 0}, + {"mode", 1, 0, 0}, {"nobackground", 0, 0, 0}, {"notext", 0, 0, 0}, - {"square", 0, 0, 0}, - {"dmre", 0, 0, 0}, - {"init", 0, 0, 0}, + {"output", 1, 0, 'o'}, + {"primary", 1, 0, 0}, + {"reverse", 0, 0, 'r'}, + {"rotate", 1, 0, 0}, + {"rows", 1, 0, 0}, + {"scale", 1, 0, 0}, + {"secure", 1, 0, 0}, + {"separator", 1, 0, 0}, {"small", 0, 0, 0}, - {"bold", 0, 0, 0}, - {"cmyk", 0, 0, 0}, - {"addongap", 1, 0, 0}, - {"batch", 0, 0, 0}, - {"mirror", 0, 0, 0}, - {"dotty", 0, 0, 0}, - {"dotsize", 1, 0, 0}, - {"eci", 1, 0, 0}, - {"filetype", 1, 0, 0}, - {"esc", 0, 0, 0}, - {"fontsize", 1, 0, 0}, + {"square", 0, 0, 0}, + {"types", 0, 0, 't'}, {"verbose", 0, 0, 0}, // Currently undocumented, output some debug info + {"vers", 1, 0, 0}, + {"whitesp", 1, 0, 'w'}, {0, 0, 0, 0} }; - int c = getopt_long(argc, argv, "htb:w:d:o:i:rcmpe", long_options, &option_index); + int c = getopt_long(argc, argv, "b:d:ehi:o:rtw:", long_options, &option_index); if (c == -1) break; switch (c) { @@ -563,17 +615,13 @@ int main(int argc, char **argv) { } if (!strcmp(long_options[option_index].name, "dump")) { my_symbol->output_options += BARCODE_STDOUT; - strncpy(my_symbol->outfile, "dummy.txt", 10); + strcpy(my_symbol->outfile, "dummy.txt"); } if (!strcmp(long_options[option_index].name, "gs1")) { - my_symbol->input_mode = GS1_MODE; + my_symbol->input_mode = (my_symbol->input_mode & ~0x07) | GS1_MODE; } if (!strcmp(long_options[option_index].name, "binary")) { - if (my_symbol->input_mode & ESCAPE_MODE) { - my_symbol->input_mode = DATA_MODE + ESCAPE_MODE; - } else { - my_symbol->input_mode = DATA_MODE; - } + my_symbol->input_mode = (my_symbol->input_mode & ~0x07) | DATA_MODE; } if (!strcmp(long_options[option_index].name, "fg")) { strncpy(my_symbol->fgcolour, optarg, 9); @@ -666,7 +714,6 @@ int main(int argc, char **argv) { fflush(stderr); } } - if (!strcmp(long_options[option_index].name, "cols")) { error_number = validator(NESET, optarg); if (error_number == ZINT_ERROR_INVALID_DATA) { @@ -763,8 +810,13 @@ int main(int argc, char **argv) { } } if (!strcmp(long_options[option_index].name, "batch")) { - /* Switch to batch processing mode */ - batch_mode = 1; + if (data_cnt == 0) { + /* Switch to batch processing mode */ + batch_mode = 1; + } else { + fprintf(stderr, "Warning 141: Can't use batch mode if data given, ignoring\n"); + fflush(stderr); + } } if (!strcmp(long_options[option_index].name, "mirror")) { /* Use filenames which reflect content */ @@ -772,7 +824,12 @@ int main(int argc, char **argv) { } if (!strcmp(long_options[option_index].name, "filetype")) { /* Select the type of output file */ - strncpy(filetype, optarg, (size_t) 3); + if (!supported_filetype(optarg)) { + fprintf(stderr, "Warning 142: File type '%s' not supported, ignoring\n", optarg); + fflush(stderr); + } else { + strncpy(filetype, optarg, (size_t) 3); + } } if (!strcmp(long_options[option_index].name, "eci")) { error_number = validator(NESET, optarg); @@ -788,9 +845,7 @@ int main(int argc, char **argv) { } } if (!strcmp(long_options[option_index].name, "esc")) { - if (!(my_symbol->input_mode & ESCAPE_MODE)) { - my_symbol->input_mode += ESCAPE_MODE; - } + my_symbol->input_mode |= ESCAPE_MODE; } if (!strcmp(long_options[option_index].name, "verbose")) { my_symbol->debug = 1; @@ -815,20 +870,23 @@ int main(int argc, char **argv) { case 'h': usage(); + help = 1; break; case 't': types(); + help = 1; break; case 'e': show_eci(); + help = 1; break; case 'b': error_number = validator(NESET, optarg); if (error_number == ZINT_ERROR_INVALID_DATA) { - fprintf(stderr, "Error 119: Invalid barcode type\n"); + fprintf(stderr, "Error 119: Invalid barcode type '%s'\n", optarg); exit(1); } my_symbol->symbology = atoi(optarg); @@ -837,7 +895,7 @@ int main(int argc, char **argv) { case 'w': error_number = validator(NESET, optarg); if (error_number == ZINT_ERROR_INVALID_DATA) { - fprintf(stderr, "Error 120: Invalid whitespace value\n"); + fprintf(stderr, "Error 120: Invalid whitespace value '%s'\n", optarg); exit(1); } if ((atoi(optarg) >= 0) && (atoi(optarg) <= 1000)) { @@ -850,80 +908,30 @@ int main(int argc, char **argv) { case 'd': /* we have some data! */ if (batch_mode == 0) { - if (filetype[0] != '\0') { - strcat(my_symbol->outfile, "."); - strcat(my_symbol->outfile, filetype); - } - if (fullmultibyte && is_fullmultibyte(my_symbol)) { - my_symbol->option_3 = ZINT_FULL_MULTIBYTE; - } else if (separator && is_stackable(my_symbol->symbology)) { - my_symbol->option_3 = separator; - } - if (addon_gap && is_extendable(my_symbol->symbology)) { - my_symbol->option_2 = addon_gap; - } - error_number = ZBarcode_Encode(my_symbol, (unsigned char*) optarg, strlen(optarg)); - generated = 1; - if (error_number != 0) { - fprintf(stderr, "%s\n", my_symbol->errtxt); - fflush(stderr); - } - if (error_number < 5) { - error_number = ZBarcode_Print(my_symbol, rotate_angle); - - if (error_number != 0) { - fprintf(stderr, "%s\n", my_symbol->errtxt); - fflush(stderr); - ZBarcode_Delete(my_symbol); - return 1; - } - } + arg_opts[data_arg_num].arg = optarg; + arg_opts[data_arg_num].opt = c; + data_arg_num++; + data_cnt++; } else { - fprintf(stderr, "Warning 122: Can't define data in batch mode\n"); + fprintf(stderr, "Warning 122: Can't define data in batch mode, ignoring '%s'\n", optarg); fflush(stderr); } break; case 'i': /* Take data from file */ - if (fullmultibyte && is_fullmultibyte(my_symbol)) { - my_symbol->option_3 = ZINT_FULL_MULTIBYTE; - } else if (separator && is_stackable(my_symbol->symbology)) { - my_symbol->option_3 = separator; - } - if (batch_mode == 0) { - error_number = ZBarcode_Encode_File(my_symbol, optarg); - generated = 1; - if (error_number != 0) { - fprintf(stderr, "%s\n", my_symbol->errtxt); - fflush(stderr); - } - if (error_number < 5) { - error_number = ZBarcode_Print(my_symbol, rotate_angle); - if (error_number != 0) { - fprintf(stderr, "%s\n", my_symbol->errtxt); - fflush(stderr); - ZBarcode_Delete(my_symbol); - return 1; - } - } + if (batch_mode == 0 || input_cnt == 0) { + arg_opts[data_arg_num].arg = optarg; + arg_opts[data_arg_num].opt = c; + data_arg_num++; + input_cnt++; } else { - /* Take each line of text as a separate data set */ - if (filetype[0] == '\0') { - strcpy(filetype, "png"); - } - error_number = batch_process(my_symbol, optarg, mirror_mode, filetype, rotate_angle); - generated = 1; - if (error_number != 0) { - fprintf(stderr, "%s\n", my_symbol->errtxt); - fflush(stderr); - ZBarcode_Delete(my_symbol); - return 1; - } + fprintf(stderr, "Warning 143: Can only define one input file in batch mode, ignoring '%s'\n", optarg); + fflush(stderr); } break; case 'o': - strncpy(my_symbol->outfile, optarg, 250); + strncpy(my_symbol->outfile, optarg, 255); break; case 'r': @@ -937,6 +945,7 @@ int main(int argc, char **argv) { default: fprintf(stderr, "Error 123: ?? getopt error 0%o\n", c); fflush(stderr); + break; } } @@ -948,7 +957,60 @@ int main(int argc, char **argv) { fflush(stderr); } - if (generated == 0) { + if (data_arg_num) { + if (fullmultibyte && is_fullmultibyte(my_symbol)) { + my_symbol->option_3 = ZINT_FULL_MULTIBYTE; + } else if (separator && is_stackable(my_symbol->symbology)) { + my_symbol->option_3 = separator; + } + if (addon_gap && is_extendable(my_symbol->symbology)) { + my_symbol->option_2 = addon_gap; + } + + if (batch_mode) { + /* Take each line of text as a separate data set */ + if (data_arg_num > 1) { + fprintf(stderr, "Warning 144: Processing first input file '%s' only\n", arg_opts[0].arg); + fflush(stderr); + } + if (filetype[0] == '\0') { + outfile_extension = get_extension(my_symbol->outfile); + // TODO: Determine if PNG available + strcpy(filetype, outfile_extension && supported_filetype(outfile_extension) ? outfile_extension : "png"); + } + error_number = batch_process(my_symbol, arg_opts[0].arg, mirror_mode, filetype, rotate_angle); + if (error_number != 0) { + fprintf(stderr, "%s\n", my_symbol->errtxt); + fflush(stderr); + } + } else { + if (*filetype != '\0') { + set_extension(my_symbol->outfile, filetype); + } + for (i = 0; i < data_arg_num; i++) { + if (arg_opts[i].opt == 'd') { + ret = ZBarcode_Encode(my_symbol, (unsigned char *) arg_opts[i].arg, strlen(arg_opts[i].arg)); + } else { + ret = ZBarcode_Encode_File(my_symbol, arg_opts[i].arg); + } + if (ret != 0) { + fprintf(stderr, "%s\n", my_symbol->errtxt); + fflush(stderr); + if (error_number < 5) { + error_number = ret; + } + } + } + if (error_number < 5) { + error_number = ZBarcode_Print(my_symbol, rotate_angle); + + if (error_number != 0) { + fprintf(stderr, "%s\n", my_symbol->errtxt); + fflush(stderr); + } + } + } + } else if (help == 0) { fprintf(stderr, "Warning 124: No data received, no symbol generated\n"); fflush(stderr); } diff --git a/frontend/tests/CMakeLists.txt b/frontend/tests/CMakeLists.txt new file mode 100644 index 00000000..66bc0dcf --- /dev/null +++ b/frontend/tests/CMakeLists.txt @@ -0,0 +1,40 @@ +# Copyright (C) 2020 Robin Stuart +# Adapted from qrencode/tests/CMakeLists.txt +# Copyright (C) 2006-2017 Kentaro Fukuchi +# vim: set ts=4 sw=4 et : + +cmake_minimum_required(VERSION 3.9) + +enable_testing() + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") + +set(ZINT_DEBUG FALSE CACHE BOOL "Set debug compile flag") +set(ZINT_SANITIZE FALSE CACHE BOOL "Set sanitize compile/link flags") + +find_package(LibZint REQUIRED) +find_package(PNG REQUIRED) + +if(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU") + if(ZINT_DEBUG) + add_compile_options("-g") + endif() + if(ZINT_SANITIZE) + add_compile_options("-fsanitize=undefined") + add_compile_options("-fsanitize=address") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=undefined -fsanitize=address") + endif() +endif() + +include_directories(../../backend/tests) +add_library(testcommon STATIC IMPORTED GLOBAL) +set_target_properties(testcommon PROPERTIES IMPORTED_LOCATION "../../../backend/tests/build/libtestcommon.a") + +macro(zint_add_test test_name test_command) + set(ADDITIONAL_LIBS "${ARGN}" ${LIBRARY_FLAGS}) + add_executable(${test_command} ${test_command}.c) + target_link_libraries(${test_command} testcommon ZINT::ZINT ${PNG_LIBRARIES} ${ADDITIONAL_LIBS}) + add_test(${test_name} ${test_command}) +endmacro() + +zint_add_test(args, test_args) diff --git a/frontend/tests/README b/frontend/tests/README new file mode 100644 index 00000000..11293c47 --- /dev/null +++ b/frontend/tests/README @@ -0,0 +1,32 @@ +Zint frontend test suite +------------------------ + +See /backend/tests/README first to build the backend test suite, as +its library /backend/tests/build/libtestcommon.a is used here. Then + + cd + cd frontend/tests + mkdir build + cd build + cmake .. + make + +If the backend test suite was made with -DZINT_SANITIZE:BOOL=1 then instead + + cd + cd frontend/tests + mkdir build + cd build + cmake -DZINT_SANITIZE:BOOL=1 .. + make + +-DZINT_DEBUG:BOOL=1 can also be used. + +------------------------------------------------------------------------------ + +Only a single test is defined: + +./test_args + +As with the backend tests, individual test functions and single dataset items +can be run using '-f ' and '-i ' etc. diff --git a/frontend/tests/test_args.c b/frontend/tests/test_args.c new file mode 100644 index 00000000..a9c07469 --- /dev/null +++ b/frontend/tests/test_args.c @@ -0,0 +1,576 @@ +/* + libzint - the open source barcode library + Copyright (C) 2020 Robin Stuart + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + */ +/* vim: set ts=4 sw=4 et : */ + +#include +#include "testcommon.h" + +static char *exec(const char *cmd, char *buf, int buf_size, int debug, int index) { + FILE *fp; + int cnt; + + if (debug & ZINT_DEBUG_TEST_PRINT) printf("%d: %s\n", index, cmd); + + *buf = '\0'; + + fp = popen(cmd, "r"); + if (!fp) { + fprintf(stderr, "exec: failed to run '%s'\n", cmd); + return NULL; + } + cnt = fread(buf, 1, buf_size, fp); + if (fgetc(fp) != EOF) { + fprintf(stderr, "exec: failed to read full stream (%s)\n", cmd); + pclose(fp); + return NULL; + } + pclose(fp); + + if (cnt) { + if (buf[cnt - 1] == '\r' || buf[cnt - 1] == '\n') { + buf[cnt - 1] = '\0'; + if (buf[cnt - 2] == '\r' || buf[cnt - 2] == '\n') { + buf[cnt - 2] = '\0'; + } + } + } + + return buf; +} + +static void arg_int(char *cmd, const char *opt, int val) { + if (val != -1) { + sprintf(cmd + (int) strlen(cmd), "%s%s%d", strlen(cmd) ? " " : "", opt, val); + } +} + +static void arg_bool(char *cmd, const char *opt, int val) { + if (val == 1) { + sprintf(cmd + (int) strlen(cmd), "%s%s", strlen(cmd) ? " " : "", opt); + } +} + +static void arg_double(char *cmd, const char *opt, double val) { + if (val != -1) { + sprintf(cmd + (int) strlen(cmd), "%s%s%g", strlen(cmd) ? " " : "", opt, val); + } +} + +static void arg_data(char *cmd, const char *opt, const char *data) { + if (data != NULL) { + sprintf(cmd + (int) strlen(cmd), "%s%s'%s'", strlen(cmd) ? " " : "", opt, data); + } +} + +static int arg_input(char *cmd, const char *filename, const char *input) { + FILE *fp; + int cnt; + if (input != NULL) { + fp = fopen(filename, "wb"); + if (!fp) { + fprintf(stderr, "arg_input: failed to open '%s' for writing\n", filename); + return 0; + } + cnt = fwrite(input, 1, strlen(input), fp); + if (cnt != (int) strlen(input)) { + fprintf(stderr, "arg_input: failed to write %d bytes, cnt %d written (%s)\n", (int) strlen(input), cnt, filename); + fclose(fp); + return 0; + } + fclose(fp); + sprintf(cmd + (int) strlen(cmd), "%s-i '%s'", strlen(cmd) ? " " : "", filename); + return 1; + } + return 0; +} + +static void arg_input_mode(char *cmd, int input_mode) { + if (input_mode != -1) { + if ((input_mode & 0x07) == DATA_MODE) { + sprintf(cmd + (int) strlen(cmd), "%s--binary", strlen(cmd) ? " " : ""); + } else if ((input_mode & 0x07) == GS1_MODE) { + sprintf(cmd + (int) strlen(cmd), "%s--gs1", strlen(cmd) ? " " : ""); + } + if (input_mode & ESCAPE_MODE) { + sprintf(cmd + (int) strlen(cmd), "%s--esc", strlen(cmd) ? " " : ""); + } + } +} + +static void arg_output_options(char *cmd, int output_options) { + if (output_options != -1) { + if (output_options & BARCODE_BIND) { + sprintf(cmd + (int) strlen(cmd), "%s--bind", strlen(cmd) ? " " : ""); + } + if (output_options & BARCODE_BOX) { + sprintf(cmd + (int) strlen(cmd), "%s--box", strlen(cmd) ? " " : ""); + } + if (output_options & BARCODE_STDOUT) { + sprintf(cmd + (int) strlen(cmd), "%s--direct", strlen(cmd) ? " " : ""); + } + if (output_options & READER_INIT) { + sprintf(cmd + (int) strlen(cmd), "%s--init", strlen(cmd) ? " " : ""); + } + if (output_options & SMALL_TEXT) { + sprintf(cmd + (int) strlen(cmd), "%s--small", strlen(cmd) ? " " : ""); + } + if (output_options & BOLD_TEXT) { + sprintf(cmd + (int) strlen(cmd), "%s--bold", strlen(cmd) ? " " : ""); + } + if (output_options & CMYK_COLOUR) { + sprintf(cmd + (int) strlen(cmd), "%s--cmyk", strlen(cmd) ? " " : ""); + } + if (output_options & BARCODE_DOTTY_MODE) { + sprintf(cmd + (int) strlen(cmd), "%s--dotty", strlen(cmd) ? " " : ""); + } + if (output_options & GS1_GS_SEPARATOR) { + sprintf(cmd + (int) strlen(cmd), "%s--gssep", strlen(cmd) ? " " : ""); + } + } +} + +// Tests args that can be detected with `--dump` +static void test_dump_args(int index, int debug) { + + testStart(""); + + int ret; + struct item { + int b; + char *data; + char *data2; + char *input; + char *input2; + int input_mode; + int output_options; + int batch; + int cols; + int dmre; + int eci; + int fullmultibyte; + int mode; + char *primary; + int rows; + int secure; + int square; + int vers; + + char *expected; + }; + // s/\/\*[ 0-9]*\*\//\=printf("\/*%3d*\/", line(".") - line("'<")) + struct item data[] = { + /* 0*/ { -1, "123", NULL, NULL, NULL, -1, -1, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "D2 13 9B 39 65 C8 C9 8E B" }, + /* 1*/ { BARCODE_CODE128, "123", NULL, NULL, NULL, -1, -1, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "D2 13 9B 39 65 C8 C9 8E B" }, + /* 2*/ { BARCODE_CODE128, "123", "456", NULL, NULL, -1, -1, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "D2 13 9B 39 65 C8 C9 8E B\nD2 19 3B 72 67 4E 4D 8E B" }, + /* 3*/ { BARCODE_CODE128, "123", NULL, NULL, NULL, -1, -1, 1, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "Warning 141: Can't use batch mode if data given, ignoring\nD2 13 9B 39 65 C8 C9 8E B" }, + /* 4*/ { BARCODE_CODE128, NULL, NULL, "123\n45\n", NULL, -1, -1, 1, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "D2 13 9B 39 65 C8 C9 8E B\nD3 97 62 3B 63 AC" }, + /* 5*/ { BARCODE_CODE128, NULL, NULL, "123\n45\n", "7\n",-1, -1, 1, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "Warning 144: Processing first input file 'test_dump_args1.txt' only\nD2 13 9B 39 65 C8 C9 8E B\nD3 97 62 3B 63 AC" }, + /* 6*/ { BARCODE_CODE128, "\t", NULL, NULL, NULL, -1, -1, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "D0 90 D2 1A 63 AC" }, + /* 7*/ { BARCODE_CODE128, "\\t", NULL, NULL, NULL, ESCAPE_MODE, -1, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "D0 90 D2 1A 63 AC" }, + /* 8*/ { BARCODE_CODE128, "123", NULL, NULL, NULL, -1, BARCODE_BIND | BARCODE_BOX | SMALL_TEXT | BOLD_TEXT | CMYK_COLOUR, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "D2 13 9B 39 65 C8 C9 8E B" }, + /* 9*/ { BARCODE_CODE128, "123", NULL, NULL, NULL, -1, BARCODE_DOTTY_MODE, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "Error 224: Selected symbology cannot be rendered as dots" }, + /* 10*/ { BARCODE_CODABLOCKF, "ABCDEF", NULL, NULL, NULL, -1, -1, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "D0 97 BA 86 51 88 B1 11 AC 46 D8 C7 58\nD0 97 BB 12 46 88 C5 1A 3C 55 CC C7 58" }, + /* 11*/ { BARCODE_CODABLOCKF, "ABCDEF", NULL, NULL, NULL, -1, -1, 0, 10, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "D0 97 BA 86 51 88 B1 11 AC 44 68 BC 98 EB\nD0 97 BB 12 46 2B BD 7B A3 47 8A 8D 18 EB" }, + /* 12*/ { BARCODE_CODABLOCKF, "ABCDEF", NULL, NULL, NULL, -1, -1, 0, -1, 0, -1, 0, -1, NULL, 3, -1, 0, -1, "D0 97 BA 58 51 88 B1 11 AC 46 36 C7 58\nD0 97 BB 12 46 88 C5 77 AF 74 62 C7 58\nD0 97 BA CE 5D EB DD 1A 3C 56 88 C7 58" }, + /* 13*/ { BARCODE_CODE11, NULL, NULL, "123", NULL, -1, -1, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "B2 D6 96 CA B5 6D 64" }, + /* 14*/ { BARCODE_CODE11, NULL, NULL, "123", NULL, -1, -1, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, 1, "B2 D6 96 CA B5 64" }, + /* 15*/ { BARCODE_CODE11, "123", NULL, "456", NULL, -1, -1, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, 2, "B2 D6 96 CA B2\nB2 B6 DA 9A B2" }, + /* 16*/ { BARCODE_CODE11, "123", "456", "789", "012", -1, -1, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, 2, "B2 D6 96 CA B2\nB2 B6 DA 9A B2\nB2 A6 D2 D5 64\nB2 AD AD 2D 64" }, + /* 17*/ { BARCODE_PDF417, "123", NULL, NULL, NULL, -1, -1, 0, -1, 0, -1, 0, -1, NULL, 1, 0, 0, -1, "FF 54 7A BC 3D 4F 1D 5C 0F E8 A4\nFF 54 7A 90 2F D3 1F AB 8F E8 A4\nFF 54 6A F8 3A BF 15 3C 0F E8 A4\nFF 54 57 9E 24 E7 1A F7 CF E8 A4\nFF 54 7A E7 3D 0D 9D 73 0F E8 A4\nFF 54 7D 70 B9 CB DF 5E CF E8 A4" }, + /* 18*/ { BARCODE_DATAMATRIX, "ABC", NULL, NULL, NULL, -1, -1, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "AA 8\nB3 4\n8F 0\nB2 C\nA6 0\nBA C\nD6 0\nEB 4\nE2 8\nFF C" }, + /* 19*/ { BARCODE_DATAMATRIX, "ABC", NULL, NULL, NULL, -1, READER_INIT, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "AA A\nAC 7\n8A 4\nA0 3\nC2 2\nB5 1\n82 2\nBA 7\n8C C\nA0 5\n86 A\nFF F" }, + /* 20*/ { BARCODE_DATAMATRIX, "ABCDEFGHIJK", NULL, NULL, NULL, -1, -1, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "AA AA AA AA\nA6 C7 FA F9\nB2 AA C7 BA\n98 BF F4 0F\nE8 DA 90 C8\nC7 D5 B6 DF\nC5 50 B0 2C\nFF FF FF FF" }, + /* 21*/ { BARCODE_DATAMATRIX, "ABCDEFGHIJK", NULL, NULL, NULL, -1, -1, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 1, -1, "AA AA\nA6 D3\nB2 DA\n99 19\nA8 A6\n84 F7\nC0 8C\nF9 87\nFC 4C\nD8 A5\n83 E6\n99 75\nF7 82\nAE 65\n8D 6A\nFF FF" }, + /* 22*/ { BARCODE_DATAMATRIX, "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF", NULL, NULL, NULL, -1, -1, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "AA AA A8\nA6 94 BC\nB2 AD F0\n99 08 F4\nA9 E1 B8\n86 81 CC\nC2 F5 88\nF5 D5 3C\nF2 68 30\nDA 7A BC\nB7 FE 70\nA8 E7 34\n91 40 88\nD6 33 DC\nD2 89 20\nD1 6A 94\nE2 71 A8\nE4 3E EC\nF2 9D 70\nE5 8D FC\nB9 56 50\nFF FF FC" }, + /* 23*/ { BARCODE_DATAMATRIX, "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF", NULL, NULL, NULL, -1, -1, 0, -1, 1, -1, 0, -1, NULL, -1, -1, 0, -1, "AA AA AA AA AA AA AA AA\nA6 D9 C8 0B FC 57 F3 17\nB2 BA A7 CA C9 18 87 BE\n99 2F EF 2B F1 A1 B9 DF\nA8 84 99 CA CF 4A BF 14\n86 D5 D9 87 A4 EF F4 9F\n85 44 BF 22 E7 58 C6 8A\nFF FF FF FF FF FF FF FF" }, + /* 24*/ { BARCODE_DATAMATRIX, "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEF", NULL, NULL, NULL, -1, -1, 0, -1, 1, -1, 0, -1, NULL, -1, -1, 1, -1, "AA AA A8\nA6 94 BC\nB2 AD F0\n99 08 F4\nA9 E1 B8\n86 81 CC\nC2 F5 88\nF5 D5 3C\nF2 68 30\nDA 7A BC\nB7 FE 70\nA8 E7 34\n91 40 88\nD6 33 DC\nD2 89 20\nD1 6A 94\nE2 71 A8\nE4 3E EC\nF2 9D 70\nE5 8D FC\nB9 56 50\nFF FF FC" }, + /* 25*/ { BARCODE_DATAMATRIX, "[91]12[92]34", NULL, NULL, NULL, GS1_MODE, -1, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "AA A8\nFA 9C\nBC 00\nD7 84\nED E0\nA4 E4\nA7 40\n9D 3C\nBF 50\nFA 24\nB1 68\nE5 04\n92 70\nFF FC" }, + /* 26*/ { BARCODE_DATAMATRIX, "[91]12[92]34", NULL, NULL, NULL, GS1_MODE, GS1_GS_SEPARATOR, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "AA A8\nF9 DC\nBF 20\nD6 C4\nED 10\nA0 0C\nA7 C0\n96 5C\nBA 70\nBB A4\nE2 18\nDD 14\n9C 40\nFF FC" }, + /* 27*/ { BARCODE_DATAMATRIX, "[9\\x31]12[92]34", NULL, NULL, NULL, GS1_MODE | ESCAPE_MODE, GS1_GS_SEPARATOR, 0, -1, 0, -1, 0, -1, NULL, -1, -1, 0, -1, "AA A8\nF9 DC\nBF 20\nD6 C4\nED 10\nA0 0C\nA7 C0\n96 5C\nBA 70\nBB A4\nE2 18\nDD 14\n9C 40\nFF FC" }, + /* 28*/ { BARCODE_EANX_CC, "[91]12", NULL, NULL, NULL, -1, -1, 0, -1, 0, -1, 0, -1, "12345678+12", -1, -1, 0, -1, "DB BC D3 9C 44 E9 D2 2C 19 E7 A2 D8 A0 00 00 00\nDB 31 1C 9C C7 29 92 47 D9 E9 40 C8 A0 00 00 00\nDA 3B EB 10 AF 09 9A 18 9D 7D 82 E8 A0 00 00 00\n10 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00\n20 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00\n10 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00\n14 68 D1 A6 49 BD 55 C9 D4 22 48 B9 40 59 94 98" }, + /* 29*/ { BARCODE_EANX_CC, "[91]12", NULL, NULL, NULL, -1, -1, 0, -1, 0, -1, 0, 2, "12345678+12", -1, -1, 0, -1, "D3 A3 E9 DB F5 C9 DB 43 D9 CB 98 D2 20 00 00 00\nD3 25 0F 11 E4 49 D3 51 F1 AC FC D6 20 00 00 00\nD1 33 48 19 39 E9 93 18 49 D8 98 D7 20 00 00 00\nD1 A6 FC DA 1C 49 9B C5 05 E2 84 D7 A0 00 00 00\n10 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00\n20 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00\n10 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00\n14 68 D1 A6 49 BD 55 C9 D4 22 48 B9 40 59 94 98" }, + /* 30*/ { BARCODE_QRCODE, "点", NULL, NULL, NULL, -1, -1, 0, -1, 0, -1, 0, -1, NULL, -1, 1, 0, -1, "FE 4B F8\n82 92 08\nBA 42 E8\nBA 92 E8\nBA 3A E8\n82 EA 08\nFE AB F8\n00 38 00\nFB CD 50\nA5 89 18\n0B 74 B8\nFC 81 A0\n92 34 B8\n00 DE 48\nFE AB 10\n82 5E 50\nBA C9 20\nBA C9 20\nBA F4 E0\n82 81 A0\nFE B4 E8" }, + /* 31*/ { BARCODE_QRCODE, "点", NULL, NULL, NULL, -1, -1, 0, -1, 0, 26, 0, -1, NULL, -1, 1, 0, -1, "FE 5B F8\n82 72 08\nBA DA E8\nBA 52 E8\nBA 2A E8\n82 0A 08\nFE AB F8\n00 D8 00\nEF F6 20\nB5 C2 28\n36 28 88\nFD 42 10\n62 2A C8\n00 95 70\nFE B7 38\n82 FD D8\nBA 97 00\nBA 43 60\nBA C8 C8\n82 C3 68\nFE EA F8" }, + /* 32*/ { BARCODE_QRCODE, "\223\137", NULL, NULL, NULL, DATA_MODE, -1, 0, -1, 0, -1, 0, -1, NULL, -1, 1, 0, -1, "FE 2B F8\n82 0A 08\nBA A2 E8\nBA 0A E8\nBA 5A E8\n82 72 08\nFE AB F8\n00 A0 00\nEF AE 20\n75 B5 20\n82 F7 58\nF4 9D C8\n5E 17 28\n00 C2 20\nFE 88 80\n82 82 38\nBA EA A8\nBA 55 50\nBA D7 68\n82 BD D0\nFE B7 78" }, + /* 33*/ { BARCODE_QRCODE, "\223\137", NULL, NULL, NULL, DATA_MODE, -1, 0, -1, 0, -1, 1, -1, NULL, -1, 1, 0, -1, "FE 4B F8\n82 92 08\nBA 42 E8\nBA 92 E8\nBA 3A E8\n82 EA 08\nFE AB F8\n00 38 00\nFB CD 50\nA5 89 18\n0B 74 B8\nFC 81 A0\n92 34 B8\n00 DE 48\nFE AB 10\n82 5E 50\nBA C9 20\nBA C9 20\nBA F4 E0\n82 81 A0\nFE B4 E8" }, + /* 34*/ { BARCODE_QRCODE, "\\x93\\x5F", NULL, NULL, NULL, DATA_MODE | ESCAPE_MODE, -1, 0, -1, 0, -1, 1, -1, NULL, -1, 1, 0, -1, "FE 4B F8\n82 92 08\nBA 42 E8\nBA 92 E8\nBA 3A E8\n82 EA 08\nFE AB F8\n00 38 00\nFB CD 50\nA5 89 18\n0B 74 B8\nFC 81 A0\n92 34 B8\n00 DE 48\nFE AB 10\n82 5E 50\nBA C9 20\nBA C9 20\nBA F4 E0\n82 81 A0\nFE B4 E8" }, + }; + int data_size = ARRAY_SIZE(data); + + char cmd[4096]; + char buf[4096]; + + char *input1_filename = "test_dump_args1.txt"; + char *input2_filename = "test_dump_args2.txt"; + int have_input1; + int have_input2; + + for (int i = 0; i < data_size; i++) { + + if (index != -1 && i != index) continue; + + strcpy(cmd, "zint --dump"); + if (debug & ZINT_DEBUG_PRINT) { + strcat(cmd, " --verbose"); + } + + arg_int(cmd, "-b ", data[i].b); + arg_data(cmd, "-d ", data[i].data); + arg_data(cmd, "-d ", data[i].data2); + have_input1 = arg_input(cmd, input1_filename, data[i].input); + have_input2 = arg_input(cmd, input2_filename, data[i].input2); + arg_input_mode(cmd, data[i].input_mode); + arg_output_options(cmd, data[i].output_options); + arg_bool(cmd, "--batch", data[i].batch); + arg_int(cmd, "--cols=", data[i].cols); + arg_bool(cmd, "--dmre", data[i].dmre); + arg_int(cmd, "--eci=", data[i].eci); + arg_bool(cmd, "--fullmultibyte", data[i].fullmultibyte); + arg_int(cmd, "--mode=", data[i].mode); + arg_data(cmd, "--primary=", data[i].primary); + arg_int(cmd, "--rows=", data[i].rows); + arg_int(cmd, "--secure=", data[i].secure); + arg_bool(cmd, "--square", data[i].square); + arg_int(cmd, "--vers=", data[i].vers); + + strcat(cmd, " 2>&1"); + + assert_nonnull(exec(cmd, buf, sizeof(buf) - 1, debug, i), "i:%d exec(%s) NULL\n", i, cmd); + assert_zero(strcmp(buf, data[i].expected), "i:%d buf (%s) != expected (%s)\n", i, buf, data[i].expected); + + if (have_input1) { + assert_zero(remove(input1_filename), "i:%d remove(%s) != 0 (%d)\n", i, input1_filename, errno); + } + if (have_input2) { + assert_zero(remove(input2_filename), "i:%d remove(%s) != 0\n", i, input2_filename); + } + } + + testFinish(); +} + +static void test_input(int index, int debug) { + + testStart(""); + + int ret; + struct item { + int b; + int batch; + int mirror; + char *filetype; + char *input; + char *outfile; + + int num_expected; + char *expected; + }; + // s/\/\*[ 0-9]*\*\//\=printf("\/*%3d*\/", line(".") - line("'<")) + struct item data[] = { + /* 0*/ { BARCODE_CODE128, 1, 0, NULL, "123\n456\n", "test_batch~.png", 2, "test_batch1.png\000test_batch2.png" }, + /* 1*/ { BARCODE_CODE128, 1, 1, NULL, "123\n456\n7890123456789\n", NULL, 3, "123.png\000456.png\0007890123456789.png" }, + /* 2*/ { BARCODE_CODE128, 1, 1, "svg", "123\n456\n7890123456789\n", NULL, 3, "123.svg\000456.svg\0007890123456789.svg" }, + /* 3*/ { BARCODE_CODE128, 1, 0, NULL, "\n", "test_batch.png", 0, NULL }, + /* 4*/ { BARCODE_CODE128, 1, 0, NULL, "123\n456\n", "test_67890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890~.png", 2, "test_678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901.png\000test_678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678902.png" }, + /* 5*/ { BARCODE_CODE128, 0, 0, "svg", "123", "test_678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901.png", 1, "test_678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901.svg" }, + /* 6*/ { BARCODE_CODE128, 1, 0, "svg", "123\n", "test_678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901.png", 1, "test_678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901.svg" }, + /* 7*/ { BARCODE_CODE128, 1, 0, NULL, "123\n", "test_batch.jpeg", 1, "test_batch.jpeg.png" }, + /* 8*/ { BARCODE_CODE128, 1, 0, NULL, "123\n", "test_batch.jpg", 1, "test_batch.png" }, + /* 9*/ { BARCODE_CODE128, 1, 0, "emf", "123\n", "test_batch.jpeg", 1, "test_batch.jpeg.emf" }, + /* 10*/ { BARCODE_CODE128, 1, 0, "emf", "123\n", "test_batch.jpg", 1, "test_batch.emf" }, + /* 11*/ { BARCODE_CODE128, 1, 0, "eps", "123\n", "test_batch.ps", 1, "test_batch.eps" }, + }; + int data_size = ARRAY_SIZE(data); + + char cmd[4096]; + char buf[4096]; + + char *input_filename = "test_input.txt"; + char *outfile; + + for (int i = 0; i < data_size; i++) { + + if (index != -1 && i != index) continue; + + strcpy(cmd, "zint"); + if (debug & ZINT_DEBUG_PRINT) { + strcat(cmd, " --verbose"); + } + + arg_int(cmd, "-b ", data[i].b); + arg_bool(cmd, "--batch", data[i].batch); + arg_bool(cmd, "--mirror", data[i].mirror); + arg_data(cmd, "--filetype=", data[i].filetype); + arg_input(cmd, input_filename, data[i].input); + arg_data(cmd, "-o ", data[i].outfile); + + assert_nonnull(exec(cmd, buf, sizeof(buf) - 1, debug, i), "i:%d exec(%s) NULL\n", i, cmd); + + outfile = data[i].expected; + for (int j = 0; j < data[i].num_expected; j++) { + assert_nonzero(testUtilExists(outfile), "i:%d j:%d testUtilExists(%s) != 1\n", i, j, outfile); + assert_zero(remove(outfile), "i:%d j:%d remove(%s) != 0 (%d)\n", i, j, outfile, errno); + outfile += strlen(outfile) + 1; + } + + assert_zero(remove(input_filename), "i:%d remove(%s) != 0 (%d)\n", i, input_filename, errno); + } + + testFinish(); +} + +// Note ordering of `--batch` before/after data/input args affects error messages +static void test_batch_input(int index, int debug) { + + testStart(""); + + int ret; + struct item { + int b; + char *data; + char *input; + char *input2; + + char *expected; + }; + // s/\/\*[ 0-9]*\*\//\=printf("\/*%3d*\/", line(".") - line("'<")) + struct item data[] = { + /* 0*/ { BARCODE_CODE128, "123", NULL, NULL, "Warning 122: Can't define data in batch mode, ignoring '123'\nWarning 124: No data received, no symbol generated" }, + /* 1*/ { BARCODE_CODE128, "123", "123\n456\n", NULL, "Warning 122: Can't define data in batch mode, ignoring '123'\nD2 13 9B 39 65 C8 C9 8E B\nD2 19 3B 72 67 4E 4D 8E B" }, + /* 3*/ { BARCODE_CODE128, NULL, "123\n456\n", "789\n", "Warning 143: Can only define one input file in batch mode, ignoring 'test_batch_input2.txt'\nD2 13 9B 39 65 C8 C9 8E B\nD2 19 3B 72 67 4E 4D 8E B" }, + }; + int data_size = ARRAY_SIZE(data); + + char cmd[4096]; + char buf[4096]; + + char *input1_filename = "test_batch_input1.txt"; + char *input2_filename = "test_batch_input2.txt"; + int have_input1; + int have_input2; + + for (int i = 0; i < data_size; i++) { + + if (index != -1 && i != index) continue; + + strcpy(cmd, "zint --dump --batch"); + if (debug & ZINT_DEBUG_PRINT) { + strcat(cmd, " --verbose"); + } + + arg_int(cmd, "-b ", data[i].b); + arg_data(cmd, "-d ", data[i].data); + have_input1 = arg_input(cmd, input1_filename, data[i].input); + have_input2 = arg_input(cmd, input2_filename, data[i].input2); + + strcat(cmd, " 2>&1"); + + assert_nonnull(exec(cmd, buf, sizeof(buf) - 1, debug, i), "i:%d exec(%s) NULL\n", i, cmd); + assert_zero(strcmp(buf, data[i].expected), "i:%d buf (%s) != expected (%s)\n", i, buf, data[i].expected); + + if (have_input1) { + assert_zero(remove(input1_filename), "i:%d remove(%s) != 0 (%d)\n", i, input1_filename, errno); + } + if (have_input2) { + assert_zero(remove(input2_filename), "i:%d remove(%s) != 0\n", i, input2_filename); + } + } + + testFinish(); +} + +static void test_batch_large(int index, int debug) { + + testStart(""); + + int ret; + struct item { + int b; + int mirror; + char *pattern; + int length; + + char *expected; + }; + // s/\/\*[ 0-9]*\*\//\=printf("\/*%3d*\/", line(".") - line("'<")) + struct item data[] = { + /* 0*/ { BARCODE_HANXIN, 0, "1", 7827, "out.png" }, + /* 1*/ { BARCODE_HANXIN, 1, "1", 7827, "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111.png" }, + /* 2*/ { BARCODE_HANXIN, 0, "1", 7828, NULL }, + }; + int data_size = ARRAY_SIZE(data); + + char cmd[16384]; + char data_buf[8192]; + char buf[16384]; + + char *input_filename = "test_batch_large.txt"; + int have_input; + + for (int i = 0; i < data_size; i++) { + + if (index != -1 && i != index) continue; + + strcpy(cmd, "zint --batch"); + if (debug & ZINT_DEBUG_PRINT) { + strcat(cmd, " --verbose"); + } + + arg_int(cmd, "-b ", data[i].b); + arg_bool(cmd, "--mirror", data[i].mirror); + + testUtilStrCpyRepeat(data_buf, data[i].pattern, data[i].length); + strcat(data_buf, "\n"); + have_input = arg_input(cmd, input_filename, data_buf); + + assert_nonnull(exec(cmd, buf, sizeof(buf) - 1, debug, i), "i:%d exec(%s) NULL\n", i, cmd); + if (data[i].expected) { + assert_zero(remove(data[i].expected), "i:%d remove(%s) != 0 (%d)\n", i, data[i].expected, errno); + } else { + assert_zero(testUtilExists("out.png"), "i:%d testUtilExists(out.png) != 0 (%d)\n", i, errno); + } + + if (have_input) { + assert_zero(remove(input_filename), "i:%d remove(%s) != 0 (%d)\n", i, input_filename, errno); + } + } + + testFinish(); +} + +static void test_checks(int index, int debug) { + + testStart(""); + + int ret; + struct item { + int addongap; + int border; + int cols; + double dotsize; + int eci; + char *filetype; + int height; + int mode; + int rotate; + int rows; + double scale; + int secure; + int separator; + int vers; + int w; + + char *expected; + }; + // s/\/\*[ 0-9]*\*\//\=printf("\/*%3d*\/", line(".") - line("'<")) + struct item data[] = { + /* 0*/ { -2, -1, -1, -1, -1, NULL, -1, -1, -1, -1, -1, -1, -1, -1, -1, "Error 139: Invalid add-on gap value" }, + /* 1*/ { 6, -1, -1, -1, -1, NULL, -1, -1, -1, -1, -1, -1, -1, -1, -1, "Warning 140: Invalid add-on gap value\nD2 13 9B 39 63 AC" }, + /* 2*/ { -1, -2, -1, -1, -1, NULL, -1, -1, -1, -1, -1, -1, -1, -1, -1, "Error 107: Invalid border width value" }, + /* 3*/ { -1, 1001, -1, -1, -1, NULL, -1, -1, -1, -1, -1, -1, -1, -1, -1, "Warning 108: Border width out of range\nD2 13 9B 39 63 AC" }, + /* 4*/ { -1, -1, -1, 0.009, -1, NULL, -1, -1, -1, -1, -1, -1, -1, -1, -1, "Warning 106: Invalid dot radius value\nD2 13 9B 39 63 AC" }, + /* 5*/ { -1, -1, -2, -1, -1, NULL, -1, -1, -1, -1, -1, -1, -1, -1, -1, "Error 131: Invalid columns value" }, + /* 6*/ { -1, -1, 68, -1, -1, NULL, -1, -1, -1, -1, -1, -1, -1, -1, -1, "Warning 111: Number of columns out of range\nD2 13 9B 39 63 AC" }, + /* 7*/ { -1, -1, -1, -1, -2, NULL, -1, -1, -1, -1, -1, -1, -1, -1, -1, "Error 138: Invalid ECI value" }, + /* 8*/ { -1, -1, -1, -1, 1000000, NULL, -1, -1, -1, -1, -1, -1, -1, -1, -1, "Warning 118: Invalid ECI code\nD2 13 9B 39 63 AC" }, + /* 9*/ { -1, -1, -1, -1, -1, "jpg", -1, -1, -1, -1, -1, -1, -1, -1, -1, "Warning 142: File type 'jpg' not supported, ignoring\nD2 13 9B 39 63 AC" }, + /* 10*/ { -1, -1, -1, -1, -1, NULL, -2, -1, -1, -1, -1, -1, -1, -1, -1, "Error 109: Invalid symbol height value" }, + /* 11*/ { -1, -1, -1, -1, -1, NULL, 0, -1, -1, -1, -1, -1, -1, -1, -1, "Warning 110: Symbol height out of range\nD2 13 9B 39 63 AC" }, + /* 12*/ { -1, -1, -1, -1, -1, NULL, -1, -2, -1, -1, -1, -1, -1, -1, -1, "Error 136: Invalid mode value" }, + /* 13*/ { -1, -1, -1, -1, -1, NULL, -1, 7, -1, -1, -1, -1, -1, -1, -1, "Warning 116: Invalid mode\nD2 13 9B 39 63 AC" }, + /* 14*/ { -1, -1, -1, -1, -1, NULL, -1, -1, -2, -1, -1, -1, -1, -1, -1, "Error 117: Invalid rotation value" }, + /* 15*/ { -1, -1, -1, -1, -1, NULL, -1, -1, 45, -1, -1, -1, -1, -1, -1, "Warning 137: Invalid rotation parameter\nD2 13 9B 39 63 AC" }, + /* 16*/ { -1, -1, -1, -1, -1, NULL, -1, -1, -1, -2, -1, -1, -1, -1, -1, "Error 132: Invalid rows value" }, + /* 17*/ { -1, -1, -1, -1, -1, NULL, -1, -1, -1, 45, -1, -1, -1, -1, -1, "Warning 112: Number of rows out of range\nD2 13 9B 39 63 AC" }, + /* 18*/ { -1, -1, -1, -1, -1, NULL, -1, -1, -1, -1, -2, -1, -1, -1, -1, "Warning 105: Invalid scale value\nD2 13 9B 39 63 AC" }, + /* 19*/ { -1, -1, -1, -1, -1, NULL, -1, -1, -1, -1, -1, -2, -1, -1, -1, "Error 134: Invalid ECC value" }, + /* 20*/ { -1, -1, -1, -1, -1, NULL, -1, -1, -1, -1, -1, 9, -1, -1, -1, "Warning 114: ECC level out of range\nD2 13 9B 39 63 AC" }, + /* 21*/ { -1, -1, -1, -1, -1, NULL, -1, -1, -1, -1, -1, -1, -2, -1, -1, "Error 128: Invalid separator value" }, + /* 22*/ { -1, -1, -1, -1, -1, NULL, -1, -1, -1, -1, -1, -1, 5, -1, -1, "Warning 127: Invalid separator value\nD2 13 9B 39 63 AC" }, + /* 23*/ { -1, -1, -1, -1, -1, NULL, -1, -1, -1, -1, -1, -1, -1, -2, -1, "Error 133: Invalid version value" }, + /* 24*/ { -1, -1, -1, -1, -1, NULL, -1, -1, -1, -1, -1, -1, -1, 85, -1, "Warning 113: Invalid version\nD2 13 9B 39 63 AC" }, + /* 25*/ { -1, -1, -1, -1, -1, NULL, -1, -1, -1, -1, -1, -1, -1, -1, -2, "Error 120: Invalid whitespace value '-2'" }, + /* 26*/ { -1, -1, -1, -1, -1, NULL, -1, -1, -1, -1, -1, -1, -1, -1, 1001, "Warning 121: Whitespace value out of range\nD2 13 9B 39 63 AC" }, + }; + int data_size = ARRAY_SIZE(data); + + char cmd[4096]; + char buf[4096]; + + for (int i = 0; i < data_size; i++) { + + if (index != -1 && i != index) continue; + + strcpy(cmd, "zint --dump -d '1'"); + if (debug & ZINT_DEBUG_PRINT) { + strcat(cmd, " --verbose"); + } + + arg_int(cmd, "--addongap=", data[i].addongap); + arg_int(cmd, "--border=", data[i].border); + arg_int(cmd, "--cols=", data[i].cols); + arg_double(cmd, "--dotsize=", data[i].dotsize); + arg_int(cmd, "--eci=", data[i].eci); + arg_data(cmd, "--filetype=", data[i].filetype); + arg_int(cmd, "--height=", data[i].height); + arg_int(cmd, "--mode=", data[i].mode); + arg_int(cmd, "--rotate=", data[i].rotate); + arg_int(cmd, "--rows=", data[i].rows); + arg_double(cmd, "--scale=", data[i].scale); + arg_int(cmd, "--secure=", data[i].secure); + arg_int(cmd, "--separator=", data[i].separator); + arg_int(cmd, "--vers=", data[i].vers); + arg_int(cmd, "-w ", data[i].w); + + strcat(cmd, " 2>&1"); + + assert_nonnull(exec(cmd, buf, sizeof(buf) - 1, debug, i), "i:%d exec(%s) NULL\n", i, cmd); + assert_zero(strcmp(buf, data[i].expected), "i:%d buf (%s) != expected (%s)\n", i, buf, data[i].expected); + } + + testFinish(); +} + +int main(int argc, char *argv[]) { + + testFunction funcs[] = { /* name, func, has_index, has_generate, has_debug */ + { "test_dump_args", test_dump_args, 1, 0, 1 }, + { "test_input", test_input, 1, 0, 1 }, + { "test_batch_input", test_batch_input, 1, 0, 1 }, + { "test_batch_large", test_batch_large, 1, 0, 1 }, + { "test_checks", test_checks, 1, 0, 1 }, + }; + + testRun(argc, argv, funcs, ARRAY_SIZE(funcs)); + + testReport(); + + return 0; +}