Move escape character processing into library

And expand to include all 8-bit values.
This commit is contained in:
Robin Stuart 2017-10-21 12:45:50 +01:00
parent 1fb99fff8c
commit 0314ca65a8
5 changed files with 142 additions and 89 deletions

View File

@ -43,7 +43,11 @@ size_t ustrlen(const unsigned char data[]) {
int ctoi(const char source) { int ctoi(const char source) {
if ((source >= '0') && (source <= '9')) if ((source >= '0') && (source <= '9'))
return (source - '0'); return (source - '0');
if ((source >= 'A') && (source <= 'F'))
return (source - 'A' + 10); return (source - 'A' + 10);
if ((source >= 'a') && (source <= 'f'))
return (source - 'a' + 10);
return -1;
} }

View File

@ -57,7 +57,7 @@ struct zint_symbol *ZBarcode_Create() {
symbol->width = 0; symbol->width = 0;
strcpy(symbol->fgcolour, "000000"); strcpy(symbol->fgcolour, "000000");
strcpy(symbol->bgcolour, "ffffff"); strcpy(symbol->bgcolour, "ffffff");
strcpy(symbol->outfile, ""); strcpy(symbol->outfile, "out.png");
symbol->scale = 1.0; symbol->scale = 1.0;
symbol->option_1 = -1; symbol->option_1 = -1;
symbol->option_2 = 0; 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; int error_number, error_buffer, i;
#ifdef _MSC_VER #ifdef _MSC_VER
unsigned char* local_source; 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; error_number = ZINT_ERROR_INVALID_OPTION;
} }
if ((symbol->input_mode < 0) || (symbol->input_mode > 2)) { /* Start acting on input mode */
symbol->input_mode = DATA_MODE;
}
if ((symbol->eci != 3) && (symbol->eci != 26)) {
symbol->input_mode = DATA_MODE;
}
if (symbol->input_mode == GS1_MODE) { if (symbol->input_mode == GS1_MODE) {
for (i = 0; i < in_length; i++) { for (i = 0; i < in_length; i++) {
if (source[i] == '\0') { 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'; 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) { if (symbol->input_mode == UNICODE_MODE) {
strip_bom(local_source, &in_length); strip_bom(local_source, &in_length);
} }

View File

@ -220,6 +220,7 @@ extern "C" {
#define GS1_MODE 2 #define GS1_MODE 2
#define KANJI_MODE 3 #define KANJI_MODE 3
#define SJIS_MODE 4 #define SJIS_MODE 4
#define ESCAPE_MODE 8
// Data Matrix specific options // Data Matrix specific options
#define DM_SQUARE 100 #define DM_SQUARE 100

View File

@ -179,12 +179,12 @@ Unicode then you will need to set the appropriate input options as shown in
section 4.11 below. section 4.11 below.
Non-printing characters can be entered on the command line using the backslash Non-printing characters can be entered on the command line using the backslash
(\) as an escape character. Permissible characters are shown in the table (\) as an escape character in combination with the --esc switch. Permissible
below. Note that this only applies on the command line. characters are shown in the table below.
------------------------------------------------------------- --------------------------------------------------------------------
Escape Character | ASCII Equivalent | Interpretation Escape Character | ASCII Equivalent | Interpretation
------------------------------------------------------------- --------------------------------------------------------------------
\0 | 0x00 | Null \0 | 0x00 | Null
\E | 0x04 | End of Transmission \E | 0x04 | End of Transmission
\a | 0x07 | Bell \a | 0x07 | Bell
@ -197,7 +197,9 @@ Escape Character | ASCII Equivalent | Interpretation
\e | 0x1B | Escape \e | 0x1B | Escape
\G | 0x1D | Group Selector \G | 0x1D | Group Selector
\R | 0x1E | Record 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. 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 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. DATA_MODE | Uses full ASCII range interpreted as Latin-1 or binary data.
UNICODE_MODE | Uses pre-formatted UTF-8 input. UNICODE_MODE | Uses pre-formatted UTF-8 input.
GS1_MODE | Encodes GS1 data using FNC1 characters. 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 5.10 Verifying Symbology Availability
------------------------------------- -------------------------------------
An additional function available in the API is defined as: An additional function available in the API is defined as:

View File

@ -92,6 +92,7 @@ void usage(void) {
" --dump Dump hexadecimal representation to stdout\n" " --dump Dump hexadecimal representation to stdout\n"
" -e, --ecinos Display table of ECI character encodings\n" " -e, --ecinos Display table of ECI character encodings\n"
" --eci=NUMBER Set the ECI mode for raw data\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" " --filetype=TYPE Set output file type (PNG/EPS/SVG/PNG/EPS/GIF/TXT)\n"
" --fg=COLOUR Specify a foreground colour (in hex)\n" " --fg=COLOUR Specify a foreground colour (in hex)\n"
" --gs1 Treat input as GS1 compatible data\n" " --gs1 Treat input as GS1 compatible data\n"
@ -168,78 +169,6 @@ int validator(char test_string[], char source[]) {
return 0; 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 */ /* Converts an integer value to its hexadecimal character */
static char itoc(int source) { static char itoc(int source) {
if ((source >= 0) && (source <= 9)) { if ((source >= 0) && (source <= 9)) {
@ -500,6 +429,7 @@ int main(int argc, char **argv) {
{"dotsize", 1, 0, 0}, {"dotsize", 1, 0, 0},
{"eci", 1, 0, 0}, {"eci", 1, 0, 0},
{"filetype", 1, 0, 0}, {"filetype", 1, 0, 0},
{"esc", 0, 0, 0},
{"verbose", 0, 0, 0}, // Currently undocumented, output some debug info {"verbose", 0, 0, 0}, // Currently undocumented, output some debug info
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
@ -696,6 +626,11 @@ int main(int argc, char **argv) {
fflush(stderr); 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")) { if (!strcmp(long_options[option_index].name, "verbose")) {
my_symbol->debug = 1; my_symbol->debug = 1;
} }
@ -742,7 +677,7 @@ int main(int argc, char **argv) {
strcat(my_symbol->outfile, "."); strcat(my_symbol->outfile, ".");
strcat(my_symbol->outfile, filetype); 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 < 5) {
if (error_number != 0) { if (error_number != 0) {
fprintf(stderr, "%s\n", my_symbol->errtxt); fprintf(stderr, "%s\n", my_symbol->errtxt);