/* code49.c - Handles Code 49 */ /* libzint - the open source barcode library Copyright (C) 2009 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. */ #include #include #include #include "common.h" #include "code49.h" #define INSET "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%!&*" /* "!" represents Shift 1 and "&" represents Shift 2, "*" represents FNC1 */ int code_49(struct zint_symbol *symbol, unsigned char source[]) { int i, j, rows, M, x_count, y_count, z_count, posn_val, local_value; char intermediate[170]; int codewords[170], codeword_count; int c_grid[8][8]; /* Refers to table 3 */ int w_grid[8][4]; /* Refets to table 2 */ int pad_count = 0; char pattern[40]; int gs1; if(ustrlen(source) > 81) { strcpy(symbol->errtxt, "Input too long"); return ERROR_TOO_LONG; } if(symbol->input_mode == GS1_MODE) { gs1 = 1; } else { gs1 = 0; } strcpy(intermediate, ""); for(i = 0; i < ustrlen(source); i++) { if(source[i] > 127) { strcpy(symbol->errtxt, "Invalid characters in input data"); return ERROR_INVALID_DATA; } if(gs1 && (i = 0)) { concat(intermediate, "*"); /* FNC1 */ } if(source[i] == symbol->nullchar) { concat(intermediate, c49_table7[0]); } else { if(gs1 && (source[i] == '[')) { concat(intermediate, "*"); /* FNC1 */ } else { concat(intermediate, c49_table7[source[i]]); } } } codeword_count = 0; i = 0; do { if((intermediate[i] >= '0') && (intermediate[i] <= '9')) { /* Numeric data */ for(j = 0; (intermediate[i + j] >= '0') && (intermediate[i + j] <= '9'); j++); if(j >= 5) { /* Use Numeric Encodation Method */ int block_count, c; int block_remain; int block_value; codewords[codeword_count] = 48; /* Numeric Shift */ codeword_count++; block_count = j / 5; block_remain = j % 5; for(c = 0; c < block_count; c++) { if((c == block_count - 1) && (block_remain == 2)) { /* Rule (d) */ block_value = 100000; block_value += ctoi(intermediate[i]) * 1000; block_value += ctoi(intermediate[i + 1]) * 100; block_value += ctoi(intermediate[i + 2]) * 10; block_value += ctoi(intermediate[i + 3]); codewords[codeword_count] = block_value / (48 * 48); block_value = block_value - (48 * 48) * codewords[codeword_count]; codeword_count++; codewords[codeword_count] = block_value / 48; block_value = block_value - 48 * codewords[codeword_count]; codeword_count++; codewords[codeword_count] = block_value; codeword_count++; i += 4; block_value = ctoi(intermediate[i]) * 100; block_value += ctoi(intermediate[i + 1]) * 10; block_value += ctoi(intermediate[i + 2]); codewords[codeword_count] = block_value / 48; block_value = block_value - 48 * codewords[codeword_count]; codeword_count++; codewords[codeword_count] = block_value; codeword_count++; i += 3; } else { block_value = ctoi(intermediate[i]) * 10000; block_value += ctoi(intermediate[i + 1]) * 1000; block_value += ctoi(intermediate[i + 2]) * 100; block_value += ctoi(intermediate[i + 3]) * 10; block_value += ctoi(intermediate[i + 4]); codewords[codeword_count] = block_value / (48 * 48); block_value = block_value - (48 * 48) * codewords[codeword_count]; codeword_count++; codewords[codeword_count] = block_value / 48; block_value = block_value - 48 * codewords[codeword_count]; codeword_count++; codewords[codeword_count] = block_value; codeword_count++; i += 5; } } switch(block_remain) { case 1: /* Rule (a) */ codewords[codeword_count] = posn(INSET, intermediate[i]); codeword_count++; i++; break; case 3: /* Rule (b) */ block_value = ctoi(intermediate[i]) * 100; block_value += ctoi(intermediate[i + 1]) * 10; block_value += ctoi(intermediate[i + 2]); codewords[codeword_count] = block_value / 48; block_value = block_value - 48 * codewords[codeword_count]; codeword_count++; codewords[codeword_count] = block_value; codeword_count++; i += 3; break; case 4: /* Rule (c) */ block_value = 100000; block_value += ctoi(intermediate[i]) * 1000; block_value += ctoi(intermediate[i + 1]) * 100; block_value += ctoi(intermediate[i + 2]) * 10; block_value += ctoi(intermediate[i + 3]); codewords[codeword_count] = block_value / (48 * 48); block_value = block_value - (48 * 48) * codewords[codeword_count]; codeword_count++; codewords[codeword_count] = block_value / 48; block_value = block_value - 48 * codewords[codeword_count]; codeword_count++; codewords[codeword_count] = block_value; codeword_count++; i += 4; break; } if(i < strlen(intermediate)) { /* There is more to add */ codewords[codeword_count] = 48; /* Numeric Shift */ codeword_count++; } } else { codewords[codeword_count] = posn(INSET, intermediate[i]); codeword_count++; i++; } } else { codewords[codeword_count] = posn(INSET, intermediate[i]); codeword_count++; i++; } } while(i < strlen(intermediate)); switch(codewords[0]) { /* Set starting mode value */ case 48: M = 2; case 43: M = 4; case 44: M = 5; default: M = 0; } if(M != 0) { for(i = 0; i < codeword_count; i++) { codewords[i] = codewords[i + 1]; } codeword_count--; } if(codeword_count > 49) { strcpy(symbol->errtxt, "Input too long"); return ERROR_TOO_LONG; } /* Place codewords in code character array (c grid) */ rows = 0; do{ for(i = 0; i < 7; i++) { if(((rows * 7) + i) < codeword_count) { c_grid[rows][i] = codewords[(rows * 7) + i]; } else { c_grid[rows][i] = 48; /* Pad */ pad_count++; } } rows++; } while ((rows * 7) < codeword_count); if((((rows <= 6) && (pad_count < 5))) || (rows > 6) || (rows == 1)) { /* Add a row */ for(i = 0; i < 7; i++) { c_grid[rows][i] = 48; /* Pad */ } rows++; } /* Add row count and mode character */ c_grid[rows - 1][6] = (7 * (rows - 2)) + M; /* Add row check character */ for(i = 0; i < rows - 1; i++) { int row_sum = 0; for(j = 0; j < 7; j++) { row_sum += c_grid[i][j]; } c_grid[i][7] = row_sum % 49; } /* Calculate Symbol Check Characters */ posn_val = 0; x_count = c_grid[rows - 1][6] * 20; y_count = c_grid[rows - 1][6] * 16; z_count = c_grid[rows - 1][6] * 38; for(i = 0; i < rows - 1; i++) { for(j = 0; j < 4; j++) { local_value = (c_grid[i][2 * j] * 49) + c_grid[i][(2 * j) + 1]; x_count += c49_x_weight[posn_val] * local_value; y_count += c49_y_weight[posn_val] * local_value; z_count += c49_z_weight[posn_val] * local_value; posn_val++; } } if(rows > 6) { /* Add Z Symbol Check */ c_grid[rows - 1][0] = (z_count % 2401) / 49; c_grid[rows - 1][1] = (z_count % 2401) % 49; } local_value = (c_grid[rows - 1][0] * 49) + c_grid[rows - 1][1]; x_count += c49_x_weight[posn_val] * local_value; y_count += c49_y_weight[posn_val] * local_value; posn_val++; /* Add Y Symbol Check */ c_grid[rows - 1][2] = (y_count % 2401) / 49; c_grid[rows - 1][3] = (y_count % 2401) % 49; local_value = (c_grid[rows - 1][2] * 49) + c_grid[rows - 1][3]; x_count += c49_x_weight[posn_val] * local_value; /* Add X Symbol Check */ c_grid[rows - 1][4] = (x_count % 2401) / 49; c_grid[rows - 1][5] = (x_count % 2401) % 49; /* Add last row check character */ j = 0; for(i = 0; i < 7; i++) { j += c_grid[rows - 1][i]; } c_grid[rows - 1][7] = j % 49; /* Transfer data to symbol character array (w grid) */ for(i = 0; i < rows; i++) { for(j = 0; j < 4; j ++) { w_grid[i][j] = (c_grid[i][2 * j] * 49) + c_grid[i][(2 * j) + 1]; } } for(i = 0; i < rows; i++) { strcpy(pattern, "11"); /* Start character */ for(j = 0; j < 4; j++) { if(i != (rows - 1)) { if(c49_table4[i][j] == 'E') { /* Even Parity */ concat(pattern, c49_appxe_even[w_grid[i][j]]); } else { /* Odd Parity */ concat(pattern, c49_appxe_odd[w_grid[i][j]]); } } else { /* Last row uses all even parity */ concat(pattern, c49_appxe_even[w_grid[i][j]]); } } concat(pattern, "4"); /* Stop character */ /* Expand into symbol */ symbol->row_height[i] = 10; expand(symbol, pattern); } symbol->whitespace_width = 10; symbol->output_options = BARCODE_BIND; symbol->border_width = 2; return 0; }