/* code.c - Handles Code 11, 39, 39+ and 93 */ /* libzint - the open source barcode library Copyright (C) 2008 Robin Stuart This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* In version 0.5 this file was 1,553 lines long! */ #include #include #include #include "common.h" #define NASET "0123456789-" static char *C11Table[11] = {"111121", "211121", "121121", "221111", "112121", "212111", "122111", "111221", "211211", "211111", "112111"}; /* Code 39 tables checked against ISO/IEC 16388:2007 */ #define TCSET "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd" /* Incorporates Table A1 */ static char *C39Table[43] = { "1112212111", "2112111121", "1122111121", "2122111111", "1112211121", "2112211111", "1122211111", "1112112121", "2112112111", "1122112111", "2111121121", "1121121121", "2121121111", "1111221121", "2111221111", "1121221111", "1111122121", "2111122111", "1121122111", "1111222111", "2111111221", "1121111221", "2121111211", "1111211221", "2111211211", "1121211211", "1111112221", "2111112211", "1121112211", "1111212211", "2211111121", "1221111121", "2221111111", "1211211121", "2211211111", "1221211111", "1211112121", "2211112111", "1221112111", "1212121111", "1212111211", "1211121211", "1112121211"}; /* Code 39 character assignments (Table 1) */ static char *EC39Ctrl[128] = {"%U", "$A", "$B", "$C", "$D", "$E", "$F", "$G", "$H", "$I", "$J", "$K", "$L", "$M", "$N", "$O", "$P", "$Q", "$R", "$S", "$T", "$U", "$V", "$W", "$X", "$Y", "$Z", "%A", "%B", "%C", "%D", "%E", " ", "/A", "/B", "/C", "/D", "/E", "/F", "/G", "/H", "/I", "/J", "/K", "/L", "-", ".", "/O", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "/Z", "%F", "%G", "%H", "%I", "%J", "%V", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "%K", "%L", "%M", "%N", "%O", "%W", "+A", "+B", "+C", "+D", "+E", "+F", "+G", "+H", "+I", "+J", "+K", "+L", "+M", "+N", "+O", "+P", "+Q", "+R", "+S", "+T", "+U", "+V", "+W", "+X", "+Y", "+Z", "%P", "%Q", "%R", "%S", "%T"}; /* Encoding the full ASCII character set in Code 39 (Table A2) */ static char *C93Ctrl[128] = {"bU", "aA", "aB", "aC", "aD", "aE", "aF", "aG", "aH", "aI", "aJ", "aK", "aL", "aM", "aN", "aO", "aP", "aQ", "aR", "aS", "aT", "aU", "aV", "aW", "aX", "aY", "aZ", "bA", "bB", "bC", "bD", "bE", " ", "cA", "cB", "cC", "cD", "cE", "cF", "cG", "cH", "cI", "cJ", "cK", "cL", "cM", "cN", "cO", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "cZ", "bF", "bG", "bH", "bI", "bJ", "bV", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bK", "bL", "bM", "bN", "bO", "bW", "dA", "dB", "dC", "dD", "dE", "dF", "dG", "dH", "dI", "dJ", "dK", "dL", "dM", "dN", "dO", "dP", "dQ", "dR", "dS", "dT", "dU", "dV", "dW", "dX", "dY", "dZ", "bP", "bQ", "bR", "bS", "bT"}; static char *C93Table[47] = {"131112", "111213", "111312", "111411", "121113", "121212", "121311", "111114", "131211", "141111", "211113", "211212", "211311", "221112", "221211", "231111", "112113", "112212", "112311", "122112", "132111", "111123", "111222", "111321", "121122", "131121", "212112", "212211", "211122", "211221", "221121", "222111", "112122", "112221", "122121", "123111", "121131", "311112", "311211", "321111", "112131", "113121", "211131", "121221", "312111", "311121", "122211"}; /* *********************** CODE 11 ******************** */ int code_11(struct zint_symbol *symbol, unsigned char source[]) { /* Code 11 */ unsigned int i; int h, c_digit, c_weight, c_count, k_digit, k_weight, k_count; int weight[1000], error_number; char dest[1000]; char checkstr[3]; error_number = 0; strcpy(dest, ""); if(ustrlen(source) > 80) { strcpy(symbol->errtxt, "Input too long [011]"); return ERROR_TOO_LONG; } error_number = is_sane(NASET, source); if(error_number == ERROR_INVALID_DATA) { strcpy(symbol->errtxt, "Invalid characters in data [012]"); return error_number; } c_weight = 1; c_count = 0; k_weight = 1; k_count = 0; /* start character */ concat (dest, "112211"); /* Draw main body of barcode */ for(i = 0; i < ustrlen(source); i++) { lookup(NASET, C11Table, source[i], dest); weight[i] = ctoi(source[i]); } /* Calculate C checksum */ for(h = (ustrlen(source) - 1); h >= 0; h--) { c_count += (c_weight * weight[h]); c_weight++; if(c_weight > 10) { c_weight = 1; } } c_digit = c_count%11; weight[ustrlen(source)] = c_digit; /* Calculate K checksum */ for(h = ustrlen(source); h >= 0; h--) { k_count += (k_weight * weight[h]); k_weight++; if(k_weight > 9) { k_weight = 1; } } k_digit = k_count%11; checkstr[0] = itoc(c_digit); checkstr[1] = itoc(k_digit); if(checkstr[0] == 'A') { checkstr[0] = '-'; } if(checkstr[1] == 'A') { checkstr[1] = '-'; } checkstr[2] = '\0'; lookup(NASET, C11Table, checkstr[0], dest); lookup(NASET, C11Table, checkstr[1], dest); /* Stop character */ concat (dest, "11221"); expand(symbol, dest); ustrcpy(symbol->text, source); uconcat(symbol->text, (unsigned char*)checkstr); return error_number; } int c39(struct zint_symbol *symbol, unsigned char source[]) { /* Code 39 */ unsigned int i; unsigned int counter; char check_digit; int h, error_number; char dest[1000]; error_number = 0; counter = 0; strcpy(dest, ""); if((symbol->option_2 < 0) || (symbol->option_2 > 1)) { symbol->option_2 = 0; } to_upper(source); if(ustrlen(source) > 45) { strcpy(symbol->errtxt, "Input too long [081]"); return ERROR_TOO_LONG; } error_number = is_sane(TCSET , source); if(error_number == ERROR_INVALID_DATA) { strcpy(symbol->errtxt, "Invalid characters in data [082]"); return error_number; } /* Start character */ concat(dest, "1211212111"); for(i = 0; i < ustrlen(source); i++) { lookup(TCSET, C39Table, source[i], dest); counter += posn(TCSET, source[i]); } if((symbol->symbology == BARCODE_LOGMARS) || (symbol->option_2 == 1)) { counter = counter % 43; if(counter < 10) { check_digit = itoc(counter); } else { if(counter < 36) { check_digit = (counter - 10) + 'A'; } else { switch(counter) { case 36: check_digit = '-'; break; case 37: check_digit = '.'; break; case 38: check_digit = ' '; break; case 39: check_digit = '$'; break; case 40: check_digit = '/'; break; case 41: check_digit = '+'; break; case 42: check_digit = 37; break; default: check_digit = ' '; break; /* Keep compiler happy */ } } } lookup(TCSET, C39Table, check_digit, dest); /* Display a space check digit as _, otherwise it looks like an error */ if(check_digit == ' ') { check_digit = '_'; } h = ustrlen(source); source[h] = check_digit; source[h + 1] = '\0'; } /* Stop character */ concat (dest, "121121211"); if((symbol->symbology == BARCODE_LOGMARS) || (symbol->symbology == BARCODE_HIBC_39)) { /* LOGMARS uses wider 'wide' bars than normal Code 39 */ for(i = 0; i < strlen(dest); i++) { if(dest[i] == '2') { dest[i] = '3'; } } } expand(symbol, dest); if(symbol->symbology == BARCODE_CODE39) { ustrcpy(symbol->text, (unsigned char*)"*"); uconcat(symbol->text, source); uconcat(symbol->text, (unsigned char*)"*"); } else { ustrcpy(symbol->text, source); } return error_number; } int pharmazentral(struct zint_symbol *symbol, unsigned char source[]) { /* Pharmazentral Nummer (PZN) */ int i, error_number; unsigned int h, count, check_digit; char localstr[8], checkstr[3]; int zeroes; error_number = 0; count = 0; h = ustrlen(source); if(h > 6) { strcpy(symbol->errtxt, "Input wrong length [521]"); return ERROR_TOO_LONG; } error_number = is_sane(NESET, source); if(error_number == ERROR_INVALID_DATA) { strcpy(symbol->errtxt, "Invalid characters in data [522]"); return error_number; } strcpy(localstr, "-"); zeroes = 6 - h; for(i = 0; i < zeroes; i++) concat(localstr, "0"); concat(localstr, (char *)source); for (i = 1; i < 7; i++) { count += (i + 1) * ctoi(localstr[i]); } check_digit = count%11; if (check_digit == 11) { check_digit = 0; } checkstr[0] = itoc(check_digit); checkstr[1] = '\0'; if(checkstr[0] == 'A') { strcpy(symbol->errtxt, "Invalid PZN Data"); return ERROR_INVALID_DATA; } concat(localstr, checkstr); error_number = c39(symbol, (unsigned char *)localstr); ustrcpy(symbol->text, (unsigned char *)"PZN"); uconcat(symbol->text, (unsigned char *)localstr); return error_number; } /* ************** EXTENDED CODE 39 *************** */ int ec39(struct zint_symbol *symbol, unsigned char source[]) { /* Extended Code 39 - ISO/IEC 16388:2007 Annex A */ unsigned char buffer[100]; unsigned int i; int ascii_value; int error_number; memset(buffer,0,100); error_number = 0; if(ustrlen(source) > 45) { /* only stops strings which are far too long - actual length of the barcode depends on the type of data being encoded - if it's too long it's picked up by c39() */ strcpy(symbol->errtxt, "Input too long [091]"); return ERROR_TOO_LONG; } for(i = 0; i < ustrlen(source); i++) { if(source[i] > 127) { /* Cannot encode extended ASCII */ strcpy(symbol->errtxt, "Invalid characters in input data [092]"); return ERROR_INVALID_DATA; } } /* Creates a buffer string and places control characters into it */ for(i = 0; i < ustrlen(source); i++) { ascii_value = source[i]; if(ascii_value == symbol->nullchar) { concat((char*)buffer, EC39Ctrl[0]); } else { concat((char*)buffer, EC39Ctrl[ascii_value]); } } /* Then sends the buffer to the C39 function */ error_number = c39(symbol, buffer); ustrcpy(symbol->text, source); for(i = 0; i < ustrlen(symbol->text); i++) { if(symbol->text[i] == symbol->nullchar) { symbol->text[i] = ' '; } } return error_number; } /* ******************** CODE 93 ******************* */ int c93(struct zint_symbol *symbol, unsigned char source[]) { /* Code 93 is an advancement on Code 39 and the definition is a lot tighter */ /* TCSET includes the extra characters a, b, c and d to represent Code 93 specific shift characters 1, 2, 3 and 4 respectively. These characters are never used by c39() and ec39() */ unsigned int i; int h, weight, c, k, values[100], error_number; char buffer[100], temp[2]; char set_copy[] = TCSET; strcpy(buffer, ""); int ascii_value; char dest[1000]; error_number = 0; strcpy(dest, ""); if(ustrlen(source) > 45) { /* This stops rediculously long input - the actual length of the barcode depends on the type of data */ strcpy(symbol->errtxt, "Input too long [251]"); return ERROR_TOO_LONG; } for(i = 0; i < ustrlen(source); i++) { if(source[i] > 127) { /* Cannot encode extended ASCII */ strcpy(symbol->errtxt, "Invalid characters in input data [252]"); return ERROR_INVALID_DATA; } } /* Start character */ concat(dest, "111141"); /* Message Content */ for(i = 0; i < ustrlen(source); i++) { ascii_value = source[i]; if(ascii_value == symbol->nullchar) { concat(buffer, C93Ctrl[0]); } else { concat(buffer, C93Ctrl[ascii_value]); } } /* Now we can check the true length of the barcode */ if(strlen(buffer) > 45) { strcpy(symbol->errtxt, "Input too long [253]"); return ERROR_TOO_LONG; } for(i = 0; i < strlen(buffer); i++) { values[i] = posn(TCSET, buffer[i]); } /* Putting the data into dest[] is not done until after check digits are calculated */ /* Check digit C */ c = 0; weight = 1; for(h = strlen(buffer) - 1; h >= 0; h--) { c += values[h] * weight; weight ++; if(weight == 21) { weight = 1; } } c = c % 47; /* Because concat() requires a string as its second argument the check digit is converted to a character which is then put in temp[] before being added to buffer[] - its a bit long winded but avoids putting yet another function into common.c */ values[strlen(buffer)] = c; temp[0] = set_copy[c]; temp[1] = '\0'; concat(buffer, temp); /* Check digit K */ k = 0; weight = 1; for(h = strlen(buffer) - 1; h >= 0; h--) { k += values[h] * weight; weight ++; if(weight == 16) { weight = 1; } } k = k % 47; temp[0] = set_copy[k]; temp[1] = '\0'; concat(buffer, temp); for(i = 0; i < strlen(buffer); i++) { lookup(TCSET, C93Table, buffer[i], dest); } /* Stop character */ concat(dest, "1111411"); h = ustrlen(source); source[h] = set_copy[c]; source[h + 1] = set_copy[k]; source[h + 2] = '\0'; expand(symbol, dest); ustrcpy(symbol->text, source); for(i = 0; i < ustrlen(symbol->text); i++) { if(symbol->text[i] == symbol->nullchar) { symbol->text[i] = ' '; } } return error_number; }