diff --git a/backend/code128.c b/backend/code128.c index efc63651..d71e7182 100644 --- a/backend/code128.c +++ b/backend/code128.c @@ -596,8 +596,11 @@ int ean_128(struct zint_symbol *symbol, unsigned char source[]) symbol->rows += 1; } - error_number = gs1_verify(symbol, source, reduced); - if(error_number != 0) { return error_number; } + if(symbol->input_mode != GS1_MODE) { + /* GS1 data has not been checked yet */ + error_number = gs1_verify(symbol, source, reduced); + if(error_number != 0) { return error_number; } + } /* Decide on mode using same system as PDF417 and rules of ISO 15417 Annex E */ indexliste = 0; diff --git a/backend/library.c b/backend/library.c index ca75a811..1e817f9a 100644 --- a/backend/library.c +++ b/backend/library.c @@ -22,6 +22,7 @@ #include #include #include "common.h" +#include "gs1.h" struct zint_symbol *ZBarcode_Create() { @@ -46,6 +47,7 @@ struct zint_symbol *ZBarcode_Create() symbol->option_1 = -1; symbol->option_2 = 0; symbol->option_3 = 928; // PDF_MAX + symbol->input_mode = DATA_MODE; strcpy(symbol->primary, ""); for(i = 0; i < 178; i++) { for(j = 0; j < 1000; j++) { @@ -138,17 +140,93 @@ void error_tag(char error_string[], int error_number) } } -int ZBarcode_Encode(struct zint_symbol *symbol, unsigned char *unicode) +int eci_process(struct zint_symbol *symbol, unsigned char source[], unsigned char preprocessed[]) +{ + int j, i, next, input_length; + + input_length = ustrlen(source); + + /* Supports UTF-8 input by converting it to Latin-1 Extended ASCII */ + /* Currently only supports Latin-1 characters but expect this to be expanded + to the full ECI spectrum */ + j = 0; + i = 0; + do { + next = -1; + if(source[i] < 128) { + preprocessed[j] = source[i]; + j++; + next = i + 1; + } else { + if(source[i] == 0xC2) { + preprocessed[j] = source[i + 1]; + j++; + next = i + 2; + } + if(source[i] == 0xC3) { + preprocessed[j] = source[i + 1] + 64; + j++; + next = i + 2; + } + } + if(next == -1) { + strcpy(symbol->errtxt, "error: Invalid character in input string (only Latin-1 characters supported)"); + return ERROR_INVALID_DATA; + } + i = next; + } while(i < input_length); + preprocessed[j] = '\0'; + + return 0; +} + +int gs1_compliant(int symbology) +{ + /* Returns 1 if symbology supports GS1 data */ + + int result = 0; + + switch(symbology) { + case BARCODE_EAN128: + case BARCODE_RSS_EXP: + case BARCODE_RSS_EXPSTACK: + case BARCODE_EANX_CC: + case BARCODE_EAN128_CC: + case BARCODE_RSS14_CC: + case BARCODE_RSS_LTD_CC: + case BARCODE_RSS_EXP_CC: + case BARCODE_UPCA_CC: + case BARCODE_UPCE_CC: + case BARCODE_RSS14STACK_CC: + case BARCODE_RSS14_OMNI_CC: + case BARCODE_RSS_EXPSTACK_CC: + result = 1; + break; + } + + return result; +} + +void ustrcpy(unsigned char dest[], unsigned char source[]) { + int i; + + i = 0; + do { + dest[i] = source[i]; + i++; + } while (source[i - 1] != '\0'); +} + +int ZBarcode_Encode(struct zint_symbol *symbol, unsigned char *source) { int error_number, error_buffer; error_number = 0; int input_length; - int i, j, next; - input_length = ustrlen(unicode); - unsigned char latin1[input_length]; + input_length = ustrlen(source); + unsigned char preprocessed[input_length]; - if(ustrlen(unicode) == 0) { + if(ustrlen(source) == 0) { strcpy(symbol->errtxt, "No input data [Z00]"); error_tag(symbol->errtxt, ERROR_INVALID_DATA); return ERROR_INVALID_DATA; @@ -194,36 +272,29 @@ int ZBarcode_Encode(struct zint_symbol *symbol, unsigned char *unicode) error_buffer = error_number; } - /* Supports UTF-8 input by converting it to Latin-1 Extended ASCII */ - /* At the moment all symbologies need this but in future versions this will - be adapted to allow automatic ECI switching for more extended character support */ - j = 0; - i = 0; - do { - next = -1; - if(unicode[i] < 128) { - latin1[j] = unicode[i]; - j++; - next = i + 1; - } else { - if(unicode[i] == 0xC2) { - latin1[j] = unicode[i + 1]; - j++; - next = i + 2; + if((symbol->input_mode < 0) || (symbol->input_mode > 3)) { symbol->input_mode = DATA_MODE; } + switch(symbol->input_mode) { + case DATA_MODE: + ustrcpy(preprocessed, source); break; + case UNICODE_MODE: + error_number = eci_process(symbol, source, preprocessed); + if(error_number != 0) { return error_number; } + break; + case GS1_MODE: + if(gs1_compliant(symbol->symbology) == 1) { + ustrcpy(preprocessed, source); + } else { + strcpy(symbol->errtxt, "Selected symbology does not support GS1 mode"); + return ERROR_INVALID_OPTION; } - if(unicode[i] == 0xC3) { - latin1[j] = unicode[i + 1] + 64; - j++; - next = i + 2; + break; + case KANJI_MODE: + if(symbol->symbology != BARCODE_QRCODE) { + strcpy(symbol->errtxt, "Selected symbology does not support Kanji mode"); + return ERROR_INVALID_OPTION; } - } - if(next == -1) { - strcpy(symbol->errtxt, "error: Invalid character in input string (only Latin-1 characters supported)"); - return ERROR_INVALID_DATA; - } - i = next; - } while(i < input_length); - latin1[j] = '\0'; + ustrcpy(preprocessed, source); break; + } if(symbol->symbology == BARCODE_CODE16K) { symbol->whitespace_width = 16; @@ -238,77 +309,77 @@ int ZBarcode_Encode(struct zint_symbol *symbol, unsigned char *unicode) } switch(symbol->symbology) { - case BARCODE_C25MATRIX: error_number = matrix_two_of_five(symbol, latin1); break; - case BARCODE_C25IND: error_number = industrial_two_of_five(symbol, latin1); break; - case BARCODE_C25INTER: error_number = interleaved_two_of_five(symbol, latin1); break; - case BARCODE_C25IATA: error_number = iata_two_of_five(symbol, latin1); break; - case BARCODE_C25LOGIC: error_number = logic_two_of_five(symbol, latin1); break; - case BARCODE_DPLEIT: error_number = dpleit(symbol, latin1); break; - case BARCODE_DPIDENT: error_number = dpident(symbol, latin1); break; - case BARCODE_UPCA: error_number = eanx(symbol, latin1); break; - case BARCODE_UPCE: error_number = eanx(symbol, latin1); break; - case BARCODE_EANX: error_number = eanx(symbol, latin1); break; - case BARCODE_EAN128: error_number = ean_128(symbol, latin1); break; - case BARCODE_CODE39: error_number = c39(symbol, latin1); break; - case BARCODE_PZN: error_number = pharmazentral(symbol, latin1); break; - case BARCODE_EXCODE39: error_number = ec39(symbol, latin1); break; - case BARCODE_CODABAR: error_number = codabar(symbol, latin1); break; - case BARCODE_CODE93: error_number = c93(symbol, latin1); break; - case BARCODE_LOGMARS: error_number = c39(symbol, latin1); break; - case BARCODE_CODE128: error_number = code_128(symbol, latin1); break; - case BARCODE_CODE128B: error_number = code_128(symbol, latin1); break; - case BARCODE_NVE18: error_number = nve_18(symbol, latin1); break; - case BARCODE_CODE11: error_number = code_11(symbol, latin1); break; - case BARCODE_MSI_PLESSEY: error_number = msi_handle(symbol, latin1); break; - case BARCODE_TELEPEN: error_number = telepen(symbol, latin1); break; - case BARCODE_TELEPEN_NUM: error_number = telepen_num(symbol, latin1); break; - case BARCODE_PHARMA: error_number = pharma_one(symbol, latin1); break; - case BARCODE_PLESSEY: error_number = plessey(symbol, latin1); break; - case BARCODE_ITF14: error_number = itf14(symbol, latin1); break; - case BARCODE_FLAT: error_number = flattermarken(symbol, latin1); break; - case BARCODE_FIM: error_number = fim(symbol, latin1); break; - case BARCODE_POSTNET: error_number = post_plot(symbol, latin1); break; - case BARCODE_PLANET: error_number = planet_plot(symbol, latin1); break; - case BARCODE_RM4SCC: error_number = royal_plot(symbol, latin1); break; - case BARCODE_AUSPOST: error_number = australia_post(symbol, latin1); break; - case BARCODE_AUSREPLY: error_number = australia_post(symbol, latin1); break; - case BARCODE_AUSROUTE: error_number = australia_post(symbol, latin1); break; - case BARCODE_AUSREDIRECT: error_number = australia_post(symbol, latin1); break; - case BARCODE_CODE16K: error_number = code16k(symbol, latin1); break; - case BARCODE_PHARMA_TWO: error_number = pharma_two(symbol, latin1); break; - case BARCODE_ONECODE: error_number = imail(symbol, latin1); break; - case BARCODE_DATAMATRIX: error_number = dmatrix(symbol, latin1); break; - case BARCODE_PDF417: error_number = pdf417enc(symbol, latin1); break; - case BARCODE_PDF417TRUNC: error_number = pdf417enc(symbol, latin1); break; - case BARCODE_QRCODE: error_number = qr_code(symbol, latin1); break; - case BARCODE_MICROPDF417: error_number = micro_pdf417(symbol, latin1); break; - case BARCODE_ISBNX: error_number = eanx(symbol, latin1); break; - case BARCODE_MAXICODE: error_number = maxicode(symbol, latin1); break; - case BARCODE_RSS14: error_number = rss14(symbol, latin1); break; - case BARCODE_RSS14STACK: error_number = rss14(symbol, latin1); break; - case BARCODE_RSS14STACK_OMNI: error_number = rss14(symbol, latin1); break; - case BARCODE_RSS_LTD: error_number = rsslimited(symbol, latin1); break; - case BARCODE_RSS_EXP: error_number = rssexpanded(symbol, latin1); break; - case BARCODE_RSS_EXPSTACK: error_number = rssexpanded(symbol, latin1); break; - case BARCODE_EANX_CC: error_number = composite(symbol, latin1); break; - case BARCODE_EAN128_CC: error_number = composite(symbol, latin1); break; - case BARCODE_RSS14_CC: error_number = composite(symbol, latin1); break; - case BARCODE_RSS_LTD_CC: error_number = composite(symbol, latin1); break; - case BARCODE_RSS_EXP_CC: error_number = composite(symbol, latin1); break; - case BARCODE_UPCA_CC: error_number = composite(symbol, latin1); break; - case BARCODE_UPCE_CC: error_number = composite(symbol, latin1); break; - case BARCODE_RSS14STACK_CC: error_number = composite(symbol, latin1); break; - case BARCODE_RSS14_OMNI_CC: error_number = composite(symbol, latin1); break; - case BARCODE_RSS_EXPSTACK_CC: error_number = composite(symbol, latin1); break; - case BARCODE_AZTEC: error_number = aztec(symbol, latin1); break; - case BARCODE_KIX: error_number = kix_code(symbol, latin1); break; - case BARCODE_CODE32: error_number = code32(symbol, latin1); break; - case BARCODE_CODABLOCKF: error_number = codablock(symbol, latin1); break; - case BARCODE_DAFT: error_number = daft_code(symbol, latin1); break; - case BARCODE_EAN14: error_number = ean_14(symbol, latin1); break; - case BARCODE_MICROQR: error_number = microqr(symbol, latin1); break; - case BARCODE_AZRUNE: error_number = aztec_runes(symbol, latin1); break; - case BARCODE_KOREAPOST: error_number = korea_post(symbol, latin1); break; + case BARCODE_C25MATRIX: error_number = matrix_two_of_five(symbol, preprocessed); break; + case BARCODE_C25IND: error_number = industrial_two_of_five(symbol, preprocessed); break; + case BARCODE_C25INTER: error_number = interleaved_two_of_five(symbol, preprocessed); break; + case BARCODE_C25IATA: error_number = iata_two_of_five(symbol, preprocessed); break; + case BARCODE_C25LOGIC: error_number = logic_two_of_five(symbol, preprocessed); break; + case BARCODE_DPLEIT: error_number = dpleit(symbol, preprocessed); break; + case BARCODE_DPIDENT: error_number = dpident(symbol, preprocessed); break; + case BARCODE_UPCA: error_number = eanx(symbol, preprocessed); break; + case BARCODE_UPCE: error_number = eanx(symbol, preprocessed); break; + case BARCODE_EANX: error_number = eanx(symbol, preprocessed); break; + case BARCODE_EAN128: error_number = ean_128(symbol, preprocessed); break; + case BARCODE_CODE39: error_number = c39(symbol, preprocessed); break; + case BARCODE_PZN: error_number = pharmazentral(symbol, preprocessed); break; + case BARCODE_EXCODE39: error_number = ec39(symbol, preprocessed); break; + case BARCODE_CODABAR: error_number = codabar(symbol, preprocessed); break; + case BARCODE_CODE93: error_number = c93(symbol, preprocessed); break; + case BARCODE_LOGMARS: error_number = c39(symbol, preprocessed); break; + case BARCODE_CODE128: error_number = code_128(symbol, preprocessed); break; + case BARCODE_CODE128B: error_number = code_128(symbol, preprocessed); break; + case BARCODE_NVE18: error_number = nve_18(symbol, preprocessed); break; + case BARCODE_CODE11: error_number = code_11(symbol, preprocessed); break; + case BARCODE_MSI_PLESSEY: error_number = msi_handle(symbol, preprocessed); break; + case BARCODE_TELEPEN: error_number = telepen(symbol, preprocessed); break; + case BARCODE_TELEPEN_NUM: error_number = telepen_num(symbol, preprocessed); break; + case BARCODE_PHARMA: error_number = pharma_one(symbol, preprocessed); break; + case BARCODE_PLESSEY: error_number = plessey(symbol, preprocessed); break; + case BARCODE_ITF14: error_number = itf14(symbol, preprocessed); break; + case BARCODE_FLAT: error_number = flattermarken(symbol, preprocessed); break; + case BARCODE_FIM: error_number = fim(symbol, preprocessed); break; + case BARCODE_POSTNET: error_number = post_plot(symbol, preprocessed); break; + case BARCODE_PLANET: error_number = planet_plot(symbol, preprocessed); break; + case BARCODE_RM4SCC: error_number = royal_plot(symbol, preprocessed); break; + case BARCODE_AUSPOST: error_number = australia_post(symbol, preprocessed); break; + case BARCODE_AUSREPLY: error_number = australia_post(symbol, preprocessed); break; + case BARCODE_AUSROUTE: error_number = australia_post(symbol, preprocessed); break; + case BARCODE_AUSREDIRECT: error_number = australia_post(symbol, preprocessed); break; + case BARCODE_CODE16K: error_number = code16k(symbol, preprocessed); break; + case BARCODE_PHARMA_TWO: error_number = pharma_two(symbol, preprocessed); break; + case BARCODE_ONECODE: error_number = imail(symbol, preprocessed); break; + case BARCODE_DATAMATRIX: error_number = dmatrix(symbol, preprocessed); break; + case BARCODE_PDF417: error_number = pdf417enc(symbol, preprocessed); break; + case BARCODE_PDF417TRUNC: error_number = pdf417enc(symbol, preprocessed); break; + case BARCODE_QRCODE: error_number = qr_code(symbol, preprocessed); break; + case BARCODE_MICROPDF417: error_number = micro_pdf417(symbol, preprocessed); break; + case BARCODE_ISBNX: error_number = eanx(symbol, preprocessed); break; + case BARCODE_MAXICODE: error_number = maxicode(symbol, preprocessed); break; + case BARCODE_RSS14: error_number = rss14(symbol, preprocessed); break; + case BARCODE_RSS14STACK: error_number = rss14(symbol, preprocessed); break; + case BARCODE_RSS14STACK_OMNI: error_number = rss14(symbol, preprocessed); break; + case BARCODE_RSS_LTD: error_number = rsslimited(symbol, preprocessed); break; + case BARCODE_RSS_EXP: error_number = rssexpanded(symbol, preprocessed); break; + case BARCODE_RSS_EXPSTACK: error_number = rssexpanded(symbol, preprocessed); break; + case BARCODE_EANX_CC: error_number = composite(symbol, preprocessed); break; + case BARCODE_EAN128_CC: error_number = composite(symbol, preprocessed); break; + case BARCODE_RSS14_CC: error_number = composite(symbol, preprocessed); break; + case BARCODE_RSS_LTD_CC: error_number = composite(symbol, preprocessed); break; + case BARCODE_RSS_EXP_CC: error_number = composite(symbol, preprocessed); break; + case BARCODE_UPCA_CC: error_number = composite(symbol, preprocessed); break; + case BARCODE_UPCE_CC: error_number = composite(symbol, preprocessed); break; + case BARCODE_RSS14STACK_CC: error_number = composite(symbol, preprocessed); break; + case BARCODE_RSS14_OMNI_CC: error_number = composite(symbol, preprocessed); break; + case BARCODE_RSS_EXPSTACK_CC: error_number = composite(symbol, preprocessed); break; + case BARCODE_AZTEC: error_number = aztec(symbol, preprocessed); break; + case BARCODE_KIX: error_number = kix_code(symbol, preprocessed); break; + case BARCODE_CODE32: error_number = code32(symbol, preprocessed); break; + case BARCODE_CODABLOCKF: error_number = codablock(symbol, preprocessed); break; + case BARCODE_DAFT: error_number = daft_code(symbol, preprocessed); break; + case BARCODE_EAN14: error_number = ean_14(symbol, preprocessed); break; + case BARCODE_MICROQR: error_number = microqr(symbol, preprocessed); break; + case BARCODE_AZRUNE: error_number = aztec_runes(symbol, preprocessed); break; + case BARCODE_KOREAPOST: error_number = korea_post(symbol, preprocessed); break; } if(error_number == 0) { error_number = error_buffer; diff --git a/backend/qr.c b/backend/qr.c index d0a298b0..d1ff17da 100644 --- a/backend/qr.c +++ b/backend/qr.c @@ -26,17 +26,13 @@ #ifndef NO_QR #include -static int kanji = 0; - -QRcode *encode(int security, int size, const unsigned char *intext) +QRcode *encode(int security, int size, const unsigned char *intext, int kanji) { int version; QRecLevel level; QRencodeMode hint; QRcode *code; - level=QR_ECLEVEL_L; - if(kanji) { hint = QR_MODE_KANJI; } else { @@ -70,8 +66,11 @@ int qr_code(struct zint_symbol *symbol, unsigned char source[]) QRcode *code; int errno = 0; int i, j; + int kanji; - code = encode(symbol->option_1, symbol->option_2, source); + if(symbol->input_mode == KANJI_MODE) { kanji = 1; } else { kanji = 0; } + + code = encode(symbol->option_1, symbol->option_2, source, kanji); if(code == NULL) { strcpy(symbol->errtxt, "libqrencode failed to encode the input data [581]"); return ERROR_ENCODING_PROBLEM; diff --git a/backend/rss.c b/backend/rss.c index f923daaa..973cee56 100644 --- a/backend/rss.c +++ b/backend/rss.c @@ -1845,8 +1845,11 @@ int rssexpanded(struct zint_symbol *symbol, unsigned char source[]) separator_row = 0; reader=0; - i = gs1_verify(symbol, source, reduced); - if(i != 0) { return i; } + if(symbol->input_mode != GS1_MODE) { + /* GS1 data has not been verified yet */ + i = gs1_verify(symbol, source, reduced); + if(i != 0) { return i; } + } if((symbol->symbology == BARCODE_RSS_EXP_CC) || (symbol->symbology == BARCODE_RSS_EXPSTACK_CC)) { /* make space for a composite separator pattern */ diff --git a/backend/zint.h b/backend/zint.h index 54f0ece0..8afcf6f1 100644 --- a/backend/zint.h +++ b/backend/zint.h @@ -39,6 +39,7 @@ struct zint_symbol { int option_1; int option_2; int option_3; + int input_mode; char text[100]; int rows; int width; @@ -132,6 +133,11 @@ struct zint_symbol { #define BARCODE_BOX 4 #define BARCODE_STDOUT 8 +#define DATA_MODE 0 +#define UNICODE_MODE 1 +#define GS1_MODE 2 +#define KANJI_MODE 3 + #define WARN_INVALID_OPTION 2 #define ERROR_TOO_LONG 5 #define ERROR_INVALID_DATA 6