From 0314ca65a8c5e5eb3caed5098b47e65c11b7ecac Mon Sep 17 00:00:00 2001 From: Robin Stuart Date: Sat, 21 Oct 2017 12:45:50 +0100 Subject: [PATCH] Move escape character processing into library And expand to include all 8-bit values. --- backend/common.c | 6 ++- backend/library.c | 118 ++++++++++++++++++++++++++++++++++++++++++---- backend/zint.h | 1 + docs/manual.txt | 25 ++++++++-- frontend/main.c | 81 ++++--------------------------- 5 files changed, 142 insertions(+), 89 deletions(-) diff --git a/backend/common.c b/backend/common.c index 4edaab2f..b0d32728 100644 --- a/backend/common.c +++ b/backend/common.c @@ -43,7 +43,11 @@ size_t ustrlen(const unsigned char data[]) { int ctoi(const char source) { if ((source >= '0') && (source <= '9')) return (source - '0'); - return (source - 'A' + 10); + if ((source >= 'A') && (source <= 'F')) + return (source - 'A' + 10); + if ((source >= 'a') && (source <= 'f')) + return (source - 'a' + 10); + return -1; } diff --git a/backend/library.c b/backend/library.c index a0967dad..9db839e8 100644 --- a/backend/library.c +++ b/backend/library.c @@ -57,7 +57,7 @@ struct zint_symbol *ZBarcode_Create() { symbol->width = 0; strcpy(symbol->fgcolour, "000000"); strcpy(symbol->bgcolour, "ffffff"); - strcpy(symbol->outfile, ""); + strcpy(symbol->outfile, "out.png"); symbol->scale = 1.0; symbol->option_1 = -1; symbol->option_2 = 0; @@ -792,7 +792,96 @@ void strip_bom(unsigned char *source, int *input_length) { } } -int ZBarcode_Encode(struct zint_symbol *symbol, const unsigned char *source,int in_length) { +int escape_char_process(struct zint_symbol *symbol, unsigned char *input_string, int *length) { + int error_number; + int in_posn, out_posn; + int hex1, hex2; + +#ifndef _MSC_VER + unsigned char escaped_string[*length + 1]; +#else + unsigned char* escaped_string = (unsigned char*) _alloca(length + 1); +#endif + + in_posn = 0; + out_posn = 0; + + do { + if (input_string[in_posn] == '\\') { + switch (input_string[in_posn + 1]) { + case '0': escaped_string[out_posn] = 0x00; /* Null */ + in_posn += 2; + break; + case 'E': escaped_string[out_posn] = 0x04; /* End of Transmission */ + in_posn += 2; + break; + case 'a': escaped_string[out_posn] = 0x07; /* Bell */ + in_posn += 2; + break; + case 'b': escaped_string[out_posn] = 0x08; /* Backspace */ + in_posn += 2; + break; + case 't': escaped_string[out_posn] = 0x09; /* Horizontal tab */ + in_posn += 2; + break; + case 'n': escaped_string[out_posn] = 0x0a; /* Line feed */ + in_posn += 2; + break; + case 'v': escaped_string[out_posn] = 0x0b; /* Vertical tab */ + in_posn += 2; + break; + case 'f': escaped_string[out_posn] = 0x0c; /* Form feed */ + in_posn += 2; + break; + case 'r': escaped_string[out_posn] = 0x0d; /* Carriage return */ + in_posn += 2; + break; + case 'e': escaped_string[out_posn] = 0x1b; /* Escape */ + in_posn += 2; + break; + case 'G': escaped_string[out_posn] = 0x1d; /* Group Separator */ + in_posn += 2; + break; + case 'R': escaped_string[out_posn] = 0x1e; /* Record Separator */ + in_posn += 2; + break; + case 'x': if (in_posn + 4 > *length) { + strcpy(symbol->errtxt, "232: Incomplete escape character in input data"); + return ZINT_ERROR_INVALID_DATA; + } + hex1 = ctoi(input_string[in_posn + 2]); + hex2 = ctoi(input_string[in_posn + 3]); + if ((hex1 >= 0) && (hex2 >= 0)) { + escaped_string[out_posn] += (hex1 << 4) + hex2; + in_posn += 4; + } else { + strcpy(symbol->errtxt, "233: Corrupt escape character in input data"); + return ZINT_ERROR_INVALID_DATA; + } + break; + case '\\': escaped_string[out_posn] = '\\'; + in_posn += 2; + break; + default: strcpy(symbol->errtxt, "234: Unrecognised escape character in input data"); + return ZINT_ERROR_INVALID_DATA; + break; + } + } else { + escaped_string[out_posn] = input_string[in_posn]; + in_posn++; + } + out_posn++; + } while (in_posn < *length); + + memcpy(input_string, escaped_string, out_posn); + *length = out_posn; + + error_number = 0; + + return error_number; +} + +int ZBarcode_Encode(struct zint_symbol *symbol, const unsigned char *source, int in_length) { int error_number, error_buffer, i; #ifdef _MSC_VER unsigned char* local_source; @@ -967,14 +1056,7 @@ int ZBarcode_Encode(struct zint_symbol *symbol, const unsigned char *source,int error_number = ZINT_ERROR_INVALID_OPTION; } - if ((symbol->input_mode < 0) || (symbol->input_mode > 2)) { - symbol->input_mode = DATA_MODE; - } - - if ((symbol->eci != 3) && (symbol->eci != 26)) { - symbol->input_mode = DATA_MODE; - } - + /* Start acting on input mode */ if (symbol->input_mode == GS1_MODE) { for (i = 0; i < in_length; i++) { if (source[i] == '\0') { @@ -997,6 +1079,22 @@ int ZBarcode_Encode(struct zint_symbol *symbol, const unsigned char *source,int local_source[in_length] = '\0'; } + if (symbol->input_mode &= ESCAPE_MODE) { + error_number = escape_char_process(symbol, local_source, &in_length); + if (error_number != 0) { + return error_number; + } + symbol->input_mode -= ESCAPE_MODE; + } + + if ((symbol->input_mode < 0) || (symbol->input_mode > 2)) { + symbol->input_mode = DATA_MODE; + } + + if ((symbol->eci != 3) && (symbol->eci != 26)) { + symbol->input_mode = DATA_MODE; + } + if (symbol->input_mode == UNICODE_MODE) { strip_bom(local_source, &in_length); } diff --git a/backend/zint.h b/backend/zint.h index 4f46c5af..50336151 100644 --- a/backend/zint.h +++ b/backend/zint.h @@ -220,6 +220,7 @@ extern "C" { #define GS1_MODE 2 #define KANJI_MODE 3 #define SJIS_MODE 4 +#define ESCAPE_MODE 8 // Data Matrix specific options #define DM_SQUARE 100 diff --git a/docs/manual.txt b/docs/manual.txt index 140f290c..b4b21715 100644 --- a/docs/manual.txt +++ b/docs/manual.txt @@ -179,12 +179,12 @@ Unicode then you will need to set the appropriate input options as shown in section 4.11 below. Non-printing characters can be entered on the command line using the backslash -(\) as an escape character. Permissible characters are shown in the table -below. Note that this only applies on the command line. +(\) as an escape character in combination with the --esc switch. Permissible +characters are shown in the table below. -------------------------------------------------------------- +-------------------------------------------------------------------- Escape Character | ASCII Equivalent | Interpretation -------------------------------------------------------------- +-------------------------------------------------------------------- \0 | 0x00 | Null \E | 0x04 | End of Transmission \a | 0x07 | Bell @@ -197,7 +197,9 @@ Escape Character | ASCII Equivalent | Interpretation \e | 0x1B | Escape \G | 0x1D | Group Selector \R | 0x1E | Record Selector -------------------------------------------------------------- +\xNN | 0xNN | Any other 8-bit character + | | where NN is hexadecimal +-------------------------------------------------------------------- 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 @@ -1042,8 +1044,21 @@ Value | Effect DATA_MODE | Uses full ASCII range interpreted as Latin-1 or binary data. UNICODE_MODE | Uses pre-formatted UTF-8 input. GS1_MODE | Encodes GS1 data using FNC1 characters. +ESCAPE_MODE | Process input data for escape sequences ----------------------------------------------------------------------------- +DATA_MODE, UNICODE_MODE and GS1_MODE are mutually exclusive, whereas +ESCAPE_MODE is optional. So, for example, you can set + +my_symbol->input_mode = UNICODE_MODE + ESCAPE_MODE; + +whereas + +my_symbol->input_mode = DATA_MODE + GS1_MODE; + +is not valid. Permissable escape sequences are listed in section 4.1. + + 5.10 Verifying Symbology Availability ------------------------------------- An additional function available in the API is defined as: diff --git a/frontend/main.c b/frontend/main.c index c148ef24..d71bcd13 100644 --- a/frontend/main.c +++ b/frontend/main.c @@ -92,6 +92,7 @@ void usage(void) { " --dump Dump hexadecimal representation to stdout\n" " -e, --ecinos Display table of ECI character encodings\n" " --eci=NUMBER Set the ECI mode for raw data\n" + " --esc Process escape characters in input data\n" " --filetype=TYPE Set output file type (PNG/EPS/SVG/PNG/EPS/GIF/TXT)\n" " --fg=COLOUR Specify a foreground colour (in hex)\n" " --gs1 Treat input as GS1 compatible data\n" @@ -168,78 +169,6 @@ int validator(char test_string[], char source[]) { return 0; } -int escape_char_process(struct zint_symbol *my_symbol, unsigned char input_string[], int length) { - int error_number; - int i, j; - -#ifndef _MSC_VER - unsigned char escaped_string[length + 1]; -#else - unsigned char* escaped_string = (unsigned char*) _alloca(length + 1); -#endif - - i = 0; - j = 0; - - do { - if (input_string[i] == '\\') { - switch (input_string[i + 1]) { - case '0': escaped_string[j] = 0x00; /* Null */ - i += 2; - break; - case 'E': escaped_string[j] = 0x04; /* End of Transmission */ - i += 2; - break; - case 'a': escaped_string[j] = 0x07; /* Bell */ - i += 2; - break; - case 'b': escaped_string[j] = 0x08; /* Backspace */ - i += 2; - break; - case 't': escaped_string[j] = 0x09; /* Horizontal tab */ - i += 2; - break; - case 'n': escaped_string[j] = 0x0a; /* Line feed */ - i += 2; - break; - case 'v': escaped_string[j] = 0x0b; /* Vertical tab */ - i += 2; - break; - case 'f': escaped_string[j] = 0x0c; /* Form feed */ - i += 2; - break; - case 'r': escaped_string[j] = 0x0d; /* Carriage return */ - i += 2; - break; - case 'e': escaped_string[j] = 0x1b; /* Escape */ - i += 2; - break; - case 'G': escaped_string[j] = 0x1d; /* Group Separator */ - i += 2; - break; - case 'R': escaped_string[j] = 0x1e; /* Record Separator */ - i += 2; - break; - case '\\': escaped_string[j] = '\\'; - i += 2; - break; - default: escaped_string[j] = input_string[i]; - i++; - break; - } - } else { - escaped_string[j] = input_string[i]; - i++; - } - j++; - } while (i < length); - escaped_string[j] = '\0'; - - error_number = ZBarcode_Encode(my_symbol, escaped_string, j); - - return error_number; -} - /* Converts an integer value to its hexadecimal character */ static char itoc(int source) { if ((source >= 0) && (source <= 9)) { @@ -500,6 +429,7 @@ int main(int argc, char **argv) { {"dotsize", 1, 0, 0}, {"eci", 1, 0, 0}, {"filetype", 1, 0, 0}, + {"esc", 0, 0, 0}, {"verbose", 0, 0, 0}, // Currently undocumented, output some debug info {0, 0, 0, 0} }; @@ -696,6 +626,11 @@ int main(int argc, char **argv) { fflush(stderr); } } + if (!strcmp(long_options[option_index].name, "esc")) { + if (!(my_symbol->input_mode &= ESCAPE_MODE)) { + my_symbol->input_mode += ESCAPE_MODE; + } + } if (!strcmp(long_options[option_index].name, "verbose")) { my_symbol->debug = 1; } @@ -742,7 +677,7 @@ int main(int argc, char **argv) { strcat(my_symbol->outfile, "."); strcat(my_symbol->outfile, filetype); } - error_number = escape_char_process(my_symbol, (unsigned char*) optarg, strlen(optarg)); + error_number = ZBarcode_Encode(my_symbol, (unsigned char*) optarg, strlen(optarg)); if (error_number < 5) { if (error_number != 0) { fprintf(stderr, "%s\n", my_symbol->errtxt);