/* blockf.c - Codablock F */ /* 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. */ #include #include #include #include #include "common.h" #define TRUE 1 #define FALSE 0 #define SHIFTA 90 #define LATCHA 91 #define SHIFTB 92 #define LATCHB 93 #define SHIFTC 94 #define LATCHC 95 #define AORB 96 #define ABORC 97 #define CANDB 98 #define CANDBB 99 #define MODEA 98 #define MODEB 100 #define MODEC 99 /* Annex A Table A.1 */ static char *C128Table[107] = {"212222", "222122", "222221", "121223", "121322", "131222", "122213", "122312", "132212", "221213", "221312", "231212", "112232", "122132", "122231", "113222", "123122", "123221", "223211", "221132", "221231", "213212", "223112", "312131", "311222", "321122", "321221", "312212", "322112", "322211", "212123", "212321", "232121", "111323", "131123", "131321", "112313", "132113", "132311", "211313", "231113", "231311", "112133", "112331", "132131", "113123", "113321", "133121", "313121", "211331", "231131", "213113", "213311", "213131", "311123", "311321", "331121", "312113", "312311", "332111", "314111", "221411", "431111", "111224", "111422", "121124", "121421", "141122", "141221", "112214", "112412", "122114", "122411", "142112", "142211", "241211", "221114", "413111", "241112", "134111", "111242", "121142", "121241", "114212", "124112", "124211", "411212", "421112", "421211", "212141", "214121", "412121", "111143", "111341", "131141", "114113", "114311", "411113", "411311", "113141", "114131", "311141", "411131", "211412", "211214", "211232", "2331112"}; int parunmodd(unsigned char llyth); void grwp(int *indexliste); void dxsmooth(int *indexliste); int a3_convert(unsigned char source) { /* Annex A section 3 */ if(source < 32) { return source + 64; } if((source >= 32) && (source <= 127)) { return source - 32; } if((source >= 128) && (source <= 159)) { return (source - 128) + 64; } /* if source >= 160 */ return (source - 128) - 32; } int character_subset_select(unsigned char source[], int input_position) { /* Section 4.5.2 - Determining the Character Subset Selector in a Row */ if((source[input_position] >= '0') && (source[input_position + 1] <= '9')) { /* Rule 1 */ return MODEC; } if((source[input_position] >= 128) && (source[input_position] <= 160)) { /* Rule 2 (i) */ return MODEA; } if((source[input_position] >= 0) && (source[input_position] <= 31)) { /* Rule 3 */ return MODEA; } /* Rule 4 */ return MODEB; } int data_encode_blockf(unsigned char source[], int subset_selector[], int blockmatrix[][62], int *columns_needed, int *rows_needed, int *final_mode) { int i, input_position, input_length, current_mode, current_row, error_number; int column_position, c, done, exit_status; error_number = 0; exit_status = 0; current_row = 0; current_mode = MODEA; input_length = ustrlen(source); column_position = 0; input_position = 0; done = 0; c = 0; do { done = 0; /* 'done' ensures that the instructions are followed in the correct order for each input character */ if(column_position == 0) { /* The Beginning of a row */ c = (*columns_needed); current_mode = character_subset_select(source, input_position); subset_selector[current_row] = current_mode; } if(c <= 2) { /* Annex B section 1 rule 1 */ /* Ensure that there is sufficient encodation capacity to continue (using the rules of Annex B.2). */ switch(current_mode) { case MODEA: /* Table B1 applies */ if(parunmodd(source[input_position]) == ABORC) { blockmatrix[current_row][column_position] = a3_convert(source[input_position]); column_position++; c--; input_position++; done = 1; } if((parunmodd(source[input_position]) == SHIFTB) && (c == 1)) { /* Needs two symbols */ blockmatrix[current_row][column_position] = 100; /* Code B */ column_position++; c--; done = 1; } if((source[input_position] >= 244) && (done == 0)) { /* Needs three symbols */ blockmatrix[current_row][column_position] = 100; /* Code B */ column_position++; c--; if(c == 1) { blockmatrix[current_row][column_position] = 101; /* Code A */ column_position++; c--; } done = 1; } if((source[input_position] >= 128) && (done == 0)) { /* Needs two symbols */ if(c == 1) { blockmatrix[current_row][column_position] = 100; /* Code B */ column_position++; c--; done = 1; } } break; case MODEB: /* Table B2 applies */ if(parunmodd(source[input_position]) == ABORC) { blockmatrix[current_row][column_position] = a3_convert(source[input_position]); column_position++; c--; input_position++; done = 1; } if((parunmodd(source[input_position]) == SHIFTA) && (c == 1)) { /* Needs two symbols */ blockmatrix[current_row][column_position] = 101; /* Code A */ column_position++; c--; done = 1; } if(((source[input_position] >= 128) && (source[input_position] <= 159)) && (done == 0)) { /* Needs three symbols */ blockmatrix[current_row][column_position] = 101; /* Code A */ column_position++; c--; if(c == 1) { blockmatrix[current_row][column_position] = 100; /* Code B */ column_position++; c--; } done = 1; } if((source[input_position] >= 160) && (done == 0)) { /* Needs two symbols */ if(c == 1) { blockmatrix[current_row][column_position] = 101; /* Code A */ column_position++; c--; done = 1; } } break; case MODEC: /* Table B3 applies */ if((parunmodd(source[input_position]) != ABORC) && (c == 1)) { /* Needs two symbols */ blockmatrix[current_row][column_position] = 101; /* Code A */ column_position++; c--; done = 1; } if(((parunmodd(source[input_position]) == ABORC) && (parunmodd(source[input_position + 1]) != ABORC)) && (c == 1)) { /* Needs two symbols */ blockmatrix[current_row][column_position] = 101; /* Code A */ column_position++; c--; done = 1; } if(source[input_position] >= 128) { /* Needs three symbols */ blockmatrix[current_row][column_position] = 101; /* Code A */ column_position++; c--; if(c == 1) { blockmatrix[current_row][column_position] = 100; /* Code B */ column_position++; c--; } } break; } } if(done == 0) { if(((parunmodd(source[input_position]) == AORB) || (parunmodd(source[input_position]) == SHIFTA)) && (current_mode == MODEA)) { /* Annex B section 1 rule 2 */ /* If in Code Subset A and the next data character can be encoded in Subset A encode the next character. */ if(source[input_position] >= 128) { /* Extended ASCII character */ blockmatrix[current_row][column_position] = 101; /* FNC4 */ column_position++; c--; } blockmatrix[current_row][column_position] = a3_convert(source[input_position]); column_position++; c--; input_position++; done = 1; } } if(done == 0) { if(((parunmodd(source[input_position]) == AORB) || (parunmodd(source[input_position]) == SHIFTB)) && (current_mode == MODEB)) { /* Annex B section 1 rule 3 */ /* If in Code Subset B and the next data character can be encoded in subset B, encode the next character. */ if(source[input_position] >= 128) { /* Extended ASCII character */ blockmatrix[current_row][column_position] = 100; /* FNC4 */ column_position++; c--; } blockmatrix[current_row][column_position] = a3_convert(source[input_position]); column_position++; c--; input_position++; done = 1; } } if(done == 0) { if(((parunmodd(source[input_position]) == ABORC) && (parunmodd(source[input_position + 1]) == ABORC)) && (current_mode == MODEC)) { /* Annex B section 1 rule 4 */ /* If in Code Subset C and the next data are 2 digits, encode them. */ blockmatrix[current_row][column_position] = (ctoi(source[input_position]) * 10) + ctoi(source[input_position + 1]); column_position++; c--; input_position += 2; done = 1; } } if(done == 0) { if(((current_mode == MODEA) || (current_mode == MODEB)) && (parunmodd(source[input_position]) == ABORC)) { /* Count the number of numeric digits */ /* If 4 or more numeric data characters occur together when in subsets A or B: a. If there is an even number of numeric data characters, insert a Code C character before the first numeric digit to change to subset C. b. If there is an odd number of numeric data characters, insert a Code Set C character immedi- ately after the first numeric digit to change to subset C. */ i = 0; do { i++; } while(parunmodd(source[input_position + i]) == ABORC); i--; if(i >= 4) { /* Annex B section 1 rule 5 */ if((i % 2) == 1) { /* Annex B section 1 rule 5a */ blockmatrix[current_row][column_position] = 99; /* Code C */ column_position++; c--; blockmatrix[current_row][column_position] = (ctoi(source[input_position]) * 10) + ctoi(source[input_position + 1]); column_position++; c--; input_position += 2; current_mode = MODEC; } else { /* Annex B section 1 rule 5b */ blockmatrix[current_row][column_position] = a3_convert(source[input_position]); column_position++; c--; input_position++; } done = 1; } else { blockmatrix[current_row][column_position] = a3_convert(source[input_position]); column_position++; c--; input_position++; done = 1; } } } if(done == 0) { if((current_mode == MODEB) && (parunmodd(source[input_position]) == SHIFTA)) { /* Annex B section 1 rule 6 */ /* When in subset B and an ASCII control character occurs in the data: a. If there is a lower case character immediately following the control character, insert a Shift character before the control character. b. Otherwise, insert a Code A character before the control character to change to subset A. */ if((source[input_position + 1] >= 96) && (source[input_position + 1] <= 127)) { /* Annex B section 1 rule 6a */ blockmatrix[current_row][column_position] = 98; /* Shift */ column_position++; c--; if(source[input_position] >= 128) { /* Extended ASCII character */ blockmatrix[current_row][column_position] = 100; /* FNC4 */ column_position++; c--; } blockmatrix[current_row][column_position] = a3_convert(source[input_position]); column_position++; c--; input_position++; } else { /* Annex B section 1 rule 6b */ blockmatrix[current_row][column_position] = 101; /* Code A */ column_position++; c--; if(source[input_position] >= 128) { /* Extended ASCII character */ blockmatrix[current_row][column_position] = 100; /* FNC4 */ column_position++; c--; } blockmatrix[current_row][column_position] = a3_convert(source[input_position]); column_position++; c--; input_position++; current_mode = MODEA; } done = 1; } } if(done == 0) { if((current_mode == MODEA) && (parunmodd(source[input_position]) == SHIFTB)) { /* Annex B section 1 rule 7 */ /* When in subset A and a lower case character occurs in the data: a. If following that character, a control character occurs in the data before the occurrence of another lower case character, insert a Shift character before the lower case character. b. Otherwise, insert a Code B character before the lower case character to change to subset B. */ if((parunmodd(source[input_position + 1]) == SHIFTA) && (parunmodd(source[input_position + 2]) == SHIFTB)) { /* Annex B section 1 rule 7a */ blockmatrix[current_row][column_position] = 98; /* Shift */ column_position++; c--; if(source[input_position] >= 128) { /* Extended ASCII character */ blockmatrix[current_row][column_position] = 101; /* FNC4 */ column_position++; c--; } blockmatrix[current_row][column_position] = a3_convert(source[input_position]); column_position++; c--; input_position++; } else { /* Annex B section 1 rule 7b */ blockmatrix[current_row][column_position] = 100; /* Code B */ column_position++; c--; if(source[input_position] >= 128) { /* Extended ASCII character */ blockmatrix[current_row][column_position] = 101; /* FNC4 */ column_position++; c--; } blockmatrix[current_row][column_position] = a3_convert(source[input_position]); column_position++; c--; input_position++; current_mode = MODEB; } done = 1; } } if(done == 0) { if((current_mode == MODEC) && ((parunmodd(source[input_position]) != ABORC) || (parunmodd(source[input_position + 1]) != ABORC))) { /* Annex B section 1 rule 8 */ /* When in subset C and a non-numeric character (or a single digit) occurs in the data, insert a Code A or Code B character before that character, following rules 8a and 8b to determine between code subsets A and B. a. If an ASCII control character (eg NUL) occurs in the data before any lower case character, use Code A. b. Otherwise use Code B. */ if(parunmodd(source[input_position]) == SHIFTA) { /* Annex B section 1 rule 8a */ blockmatrix[current_row][column_position] = 101; /* Code A */ column_position++; c--; if(source[input_position] >= 128) { /* Extended ASCII character */ blockmatrix[current_row][column_position] = 101; /* FNC4 */ column_position++; c--; } blockmatrix[current_row][column_position] = a3_convert(source[input_position]); column_position++; c--; input_position++; current_mode = MODEA; } else { /* Annex B section 1 rule 8b */ blockmatrix[current_row][column_position] = 100; /* Code B */ column_position++; c--; if(source[input_position] >= 128) { /* Extended ASCII character */ blockmatrix[current_row][column_position] = 100; /* FNC4 */ column_position++; c--; } blockmatrix[current_row][column_position] = a3_convert(source[input_position]); column_position++; c--; input_position++; current_mode = MODEB; } done = 1; } } if(input_position == input_length) { /* End of data - Annex B rule 5a */ if (c == 1) { if(current_mode == MODEA) { blockmatrix[current_row][column_position] = 100; /* Code B */ current_mode = MODEB; } else { blockmatrix[current_row][column_position] = 101; /* Code A */ current_mode = MODEA; } column_position++; c--; } if (c == 0) { /* Another row is needed */ column_position = 0; c = (*columns_needed); current_row++; subset_selector[current_row] = MODEA; current_mode = MODEA; } if (c > 2) { /* Fill up the last row */ do { if(current_mode == MODEA) { blockmatrix[current_row][column_position] = 100; /* Code B */ current_mode = MODEB; } else { blockmatrix[current_row][column_position] = 101; /* Code A */ current_mode = MODEA; } column_position++; c--; } while (c > 2); } /* If (c == 2) { do nothing } */ exit_status = 1; *(final_mode) = current_mode; } else { if(c <= 0) { /* Start new row - Annex B rule 5b */ column_position = 0; current_row++; if(current_row > 43) { return ERROR_TOO_LONG; } } } } while (exit_status == 0); *(rows_needed) = current_row + 1; return error_number; } int codablock(struct zint_symbol *symbol, unsigned char source[]) { int error_number, input_length, i, j, k; int rows_needed, columns_needed; int min_module_height; int last_mode, this_mode, final_mode; float estimate_codelength; int blockmatrix[44][62]; char row_pattern[750]; int subset_selector[44], row_indicator[44], row_check[44]; long int k1_sum, k2_sum; int k1_check, k2_check; error_number = 0; input_length = ustrlen(source); final_mode = MODEA; if(input_length > 5450) { strcpy(symbol->errtxt, "Input data too long"); return ERROR_TOO_LONG; } /* Make a guess at how many characters will be needed to encode the data */ estimate_codelength = 0.0; last_mode = AORB; /* Codablock always starts with Code A */ for(i = 0; i < input_length; i++) { this_mode = parunmodd(source[i]); if(this_mode != last_mode) { estimate_codelength += 1.0; } if(this_mode != ABORC) { estimate_codelength += 1.0; } else { estimate_codelength += 0.5; } if(source[i] > 127) { estimate_codelength += 1.0; } last_mode = this_mode; } /* Decide symbol size based on the above guess */ rows_needed = 0.5 + sqrt((estimate_codelength + 2) / 1.45); if(rows_needed < 2) { rows_needed = 2; } if(rows_needed > 44) { rows_needed = 44; } columns_needed = (estimate_codelength + 2) / rows_needed; if(columns_needed < 4) { columns_needed = 4; } if(columns_needed > 62) { strcpy(symbol->errtxt, "Input data too long"); return ERROR_TOO_LONG; } /* Encode the data */ error_number = data_encode_blockf(source, subset_selector, blockmatrix, &columns_needed, &rows_needed, &final_mode); if(error_number > 0) { if(error_number == ERROR_TOO_LONG) { strcpy(symbol->errtxt, "Input data too long"); } return error_number; } /* Add check digits - Annex F */ k1_sum = 0; k2_sum = 0; for(i = 0; i < input_length; i++) { k1_sum += (i + 1) * source[i]; k2_sum += i * source[i]; } k1_check = k1_sum % 86; k2_check = k2_sum % 86; if((final_mode == MODEA) || (final_mode == MODEB)) { k1_check = k1_check + 64; if(k1_check > 95) { k1_check -= 96; } k2_check = k2_check + 64; if(k2_check > 95) { k2_check -= 96; } } blockmatrix[rows_needed - 1][columns_needed - 2] = k1_check; blockmatrix[rows_needed - 1][columns_needed - 1] = k2_check; /* Calculate row height (4.6.1.a) */ min_module_height = (0.55 * (columns_needed + 3)) + 3; if(min_module_height < 8) { min_module_height = 8; } /* Encode the Row Indicator in the First Row of the Symbol - Table D2 */ if(subset_selector[0] == 99) { /* Code C */ row_indicator[0] = rows_needed - 2; } else { /* Code A or B */ row_indicator[0] = rows_needed + 62; if(row_indicator[0] > 95) { row_indicator[0] -= 95; } } /* Encode the Row Indicator in the Second and Subsequent Rows of the Symbol - Table D3 */ for(i = 1; i < rows_needed; i++) { /* Note that the second row is row number 1 because counting starts from 0 */ if(subset_selector[i] == 99) { /* Code C */ row_indicator[i] = i + 42; } else { /* Code A or B */ row_indicator[i] = i + 10; } } /* Calculate row check digits - Annex E */ for(i = 0; i < rows_needed; i++) { k = 103; k += subset_selector[i]; k += 2 * row_indicator[i]; for(j = 0; j < columns_needed; j++) { k+= (j + 3) * blockmatrix[i][j]; } row_check[i] = k % 103; } /* Resolve the data into patterns and place in symbol structure */ for(i = 0; i < rows_needed; i++) { int writer, flip_flop; strcpy(row_pattern, ""); /* Start character */ concat(row_pattern, C128Table[103]); /* Always Start A */ concat(row_pattern, C128Table[subset_selector[i]]); concat(row_pattern, C128Table[row_indicator[i]]); /*printf("103 %d %d ", subset_selector[i], row_indicator[i]);*/ for(j = 0; j < columns_needed; j++) { concat(row_pattern, C128Table[blockmatrix[i][j]]); /*printf("%d ",blockmatrix[i][j]);*/ } concat(row_pattern, C128Table[row_check[i]]); /* Stop character */ concat(row_pattern, C128Table[106]); /*printf("%d 106\n", row_check[i]);*/ /* Write the information into the symbol */ writer = 0; flip_flop = 1; for (j = 0; j < strlen(row_pattern); j++) { for(k = 0; k < ctoi(row_pattern[j]); k++) { if(flip_flop == 1) { symbol->encoded_data[i][writer] = '1'; writer++; } else { symbol->encoded_data[i][writer] = '0'; writer++; } } if(flip_flop == 0) { flip_flop = 1; } else { flip_flop = 0; } } symbol->row_height[i] = min_module_height + 2; } symbol->border_width = 2; symbol->output_options = BARCODE_BIND; symbol->rows = rows_needed; symbol->width = (11 * (columns_needed + 5)) + 2; return error_number; }