int cc_binary_string()

in Sharing/Src/External/zint-2.4.3/src/backend/composite.c [721:1704]


int cc_binary_string(struct zint_symbol *symbol, const char source[], char binary_string[], int cc_mode, int *cc_width, int *ecc, int lin_width)
{ /* Handles all data encodation from section 5 of ISO/IEC 24723 */
	int encoding_method, read_posn, d1, d2, value, alpha_pad;
	int i, j, mask, ai_crop,fnc1_latch;
	long int group_val;
	int ai90_mode, latch, remainder, binary_length;
	char date_str[4];
#ifndef _MSC_VER
	char general_field[strlen(source) + 1], general_field_type[strlen(source) + 1];
#else
        char* general_field = (char*)_alloca(strlen(source) + 1);
        char* general_field_type = (char*)_alloca(strlen(source) + 1);
#endif
	int target_bitsize;

	encoding_method = 1;
	read_posn = 0;
	ai_crop = 0;
	fnc1_latch = 0;
	alpha_pad = 0;
	ai90_mode = 0;
	*ecc = 0;
	value = 0;
	target_bitsize = 0;

	if((source[0] == '1') && ((source[1] == '0') || (source[1] == '1') || (source[1] == '7')) && (strlen(source) > 8)) {
		/* Source starts (10), (11) or (17) */
		encoding_method = 2;
	}

	if((source[0] == '9') && (source[1] == '0')) {
		/* Source starts (90) */
		encoding_method = 3;
	}

	if(encoding_method == 1) {
		concat(binary_string, "0");
	}

	if(encoding_method == 2) {
		/* Encoding Method field "10" - date and lot number */

		concat(binary_string, "10");

		if(source[1] == '0') {
			/* No date data */
			concat(binary_string, "11");
			read_posn = 2;
		} else {
			/* Production Date (11) or Expiration Date (17) */
			date_str[0] = source[2];
			date_str[1] = source[3];
			date_str[2] = '\0';
			group_val = atoi(date_str) * 384;

			date_str[0] = source[4];
			date_str[1] = source[5];
			group_val += (atoi(date_str) - 1) * 32;

			date_str[0] = source[6];
			date_str[1] = source[7];
			group_val += atoi(date_str);

			mask = 0x8000;
			for(j = 0; j < 16; j++) {
				if((group_val & mask) == 0x00) {
					concat(binary_string, "0");
				} else {
					concat(binary_string, "1");
				}
				mask = mask >> 1;
			}

			if(source[1] == '1') {
				/* Production Date AI 11 */
				concat(binary_string, "0");
			} else {
				/* Expiration Date AI 17 */
				concat(binary_string, "1");
			}
			read_posn = 8;
		}

		if((source[read_posn] == '1') && (source[read_posn + 1] == '0')) {
			/* Followed by AI 10 - strip this from general field */
			read_posn += 2;
		} else {
			/* An FNC1 character needs to be inserted in the general field */
			fnc1_latch = 1;
		}
	}

	if (encoding_method == 3) {
		/* Encodation Method field of "11" - AI 90 */
#ifndef _MSC_VER		
                char ninety[strlen(source) + 1];
#else
                char* ninety = (char*)_alloca(strlen(source) + 1);
#endif
                char numeric_part[4];
		int alpha, alphanum, numeric, test1, test2, test3, next_ai_posn;
		int numeric_value, table3_letter, mask;

		/* "This encodation method may be used if an element string with an AI
		90 occurs at the start of the data message, and if the data field
		following the two-digit AI 90 starts with an alphanumeric string which
		complies with a specific format." (para 5.2.2) */

		i = 0;
		do {
			ninety[i] = source[i + 2];
			i++;
		} while ((strlen(source) > i + 2) && ('[' != source[i + 2]));
		ninety[i] = '\0';

		/* Find out if the AI 90 data is alphabetic or numeric or both */

		alpha = 0;
		alphanum = 0;
		numeric = 0;

		for(i = 0; i < strlen(ninety); i++) {

			if ((ninety[i] >= 'A') && (ninety[i] <= 'Z')) {
				/* Character is alphabetic */
				alpha += 1;
			}

			if ((ninety[i] >= '0') && (ninety[i] <= '9')) {
				/* Character is numeric */
				numeric += 1;
			}

			switch(ninety[i]) {
				case '*':
				case ',':
				case '-':
				case '.':
				case '/': alphanum += 1; break;
			}

			if (!(((ninety[i] >= '0') && (ninety[i] <= '9')) || ((ninety[i] >= 'A') && (ninety[i] <= 'Z')))) {
				if((ninety[i] != '*') && (ninety[i] != ',') && (ninety[i] != '-') && (ninety[i] != '.') && (ninety[i] != '/')) {
					/* An Invalid AI 90 character */
					strcpy(symbol->errtxt, "Invalid AI 90 data");
					return ZINT_ERROR_INVALID_DATA;
				}
			}
		}

		/* must start with 0, 1, 2 or 3 digits followed by an uppercase character */
		test1 = -1;
		for(i = 3; i >= 0; i--) {
			if ((ninety[i] >= 'A') && (ninety[i] <= 'Z')) {
				test1 = i;
			}
		}

		test2 = 0;
		for(i = 0; i < test1; i++) {
			if (!((ninety[i] >= '0') && (ninety[i] <= '9'))) {
				test2 = 1;
			}
		}

		/* leading zeros are not permitted */
		test3 = 0;
		if((test1 >= 1) && (ninety[0] == '0')) { test3 = 1; }

		if((test1 != -1) && (test2 != 1) && (test3 == 0)) {
			/* Encodation method "11" can be used */
			concat(binary_string, "11");

			numeric -= test1;
			alpha --;

			/* Decide on numeric, alpha or alphanumeric mode */
			/* Alpha mode is a special mode for AI 90 */

			if(alphanum > 0) {
				/* Alphanumeric mode */
				concat(binary_string, "0");
				ai90_mode = 1;
			} else {
				if(alpha > numeric) {
					/* Alphabetic mode */
					concat(binary_string, "11");
					ai90_mode = 2;
				} else {
					/* Numeric mode */
					concat(binary_string, "10");
					ai90_mode = 3;
				}
			}

			next_ai_posn = 2 + strlen(ninety);

			if(source[next_ai_posn] == '[') {
				/* There are more AIs afterwords */
				if((source[next_ai_posn + 1] == '2') && (source[next_ai_posn + 2] == '1')) {
					/* AI 21 follows */
					ai_crop = 1;
				}

				if((source[next_ai_posn + 1] == '8') && (source[next_ai_posn + 2] == '0') && (source[next_ai_posn + 3] == '0') && (source[next_ai_posn + 4] == '4')) {
					/* AI 8004 follows */
					ai_crop = 2;
				}
			}

			switch(ai_crop) {
				case 0: concat(binary_string, "0"); break;
				case 1: concat(binary_string, "10"); break;
				case 2: concat(binary_string, "11"); break;
			}

			if(test1 == 0) {
				strcpy(numeric_part, "0");
			} else {
				for(i = 0; i < test1; i++) {
					numeric_part[i] = ninety[i];
				}
				numeric_part[i] = '\0';
			}

			numeric_value = atoi(numeric_part);

			table3_letter = -1;
			if(numeric_value < 31) {
				switch(ninety[test1]) {
					case 'B': table3_letter = 0; break;
					case 'D': table3_letter = 1; break;
					case 'H': table3_letter = 2; break;
					case 'I': table3_letter = 3; break;
					case 'J': table3_letter = 4; break;
					case 'K': table3_letter = 5; break;
					case 'L': table3_letter = 6; break;
					case 'N': table3_letter = 7; break;
					case 'P': table3_letter = 8; break;
					case 'Q': table3_letter = 9; break;
					case 'R': table3_letter = 10; break;
					case 'S': table3_letter = 11; break;
					case 'T': table3_letter = 12; break;
					case 'V': table3_letter = 13; break;
					case 'W': table3_letter = 14; break;
					case 'Z': table3_letter = 15; break;
				}
			}

			if(table3_letter != -1) {
				/* Encoding can be done according to 5.2.2 c) 2) */
				/* five bit binary string representing value before letter */
				mask = 0x10;
				for(j = 0; j < 5; j++) {
					if((numeric_value & mask) == 0x00) {
						concat(binary_string, "0");
					} else {
						concat(binary_string, "1");
					}
					mask = mask >> 1;
				}

				/* followed by four bit representation of letter from Table 3 */
				mask = 0x08;
				for(j = 0; j < 4; j++) {
					if((table3_letter & mask) == 0x00) {
						concat(binary_string, "0");
					} else {
						concat(binary_string, "1");
					}
					mask = mask >> 1;
				}
			} else {
				/* Encoding is done according to 5.2.2 c) 3) */
				concat(binary_string, "11111");
				/* ten bit representation of number */
				mask = 0x200;
				for(j = 0; j < 10; j++) {
					if((numeric_value & mask) == 0x00) {
						concat(binary_string, "0");
					} else {
						concat(binary_string, "1");
					}
					mask = mask >> 1;
				}

				/* five bit representation of ASCII character */
				mask = 0x10;
				for(j = 0; j < 5; j++) {
					if(((ninety[test1] - 65) & mask) == 0x00) {
						concat(binary_string, "0");
					} else {
						concat(binary_string, "1");
					}
					mask = mask >> 1;
				}
			}

			read_posn = test1 + 3;
		} else {
			/* Use general field encodation instead */
			concat(binary_string, "0");
			read_posn = 0;
		}
	}

	/* Now encode the rest of the AI 90 data field */
	if(ai90_mode == 2) {
		/* Alpha encodation (section 5.2.3) */
		do {
			if((source[read_posn] >= '0') && (source[read_posn] <= '9')) {
				mask = 0x10;
				for(j = 0; j < 5; j++) {
					if(((source[read_posn] + 4) & mask) == 0x00) {
						concat(binary_string, "0");
					} else {
						concat(binary_string, "1");
					}
					mask = mask >> 1;
				}
			}

			if((source[read_posn] >= 'A') && (source[read_posn] <= 'Z')) {
				mask = 0x20;
				for(j = 0; j < 6; j++) {
					if(((source[read_posn] - 65) & mask) == 0x00) {
						concat(binary_string, "0");
					} else {
						concat(binary_string, "1");
					}
					mask = mask >> 1;
				}
			}

			if(source[read_posn] == '[') {
				concat(binary_string, "11111");
			}

			read_posn++;
		} while ((source[read_posn - 1] != '[') && (source[read_posn - 1] != '\0'));
		alpha_pad = 1; /* This is overwritten if a general field is encoded */
	}

	if(ai90_mode == 1) {
		/* Alphanumeric mode */
		do {
			if((source[read_posn] >= '0') && (source[read_posn] <= '9')) {
				mask = 0x10;
				for(j = 0; j < 5; j++) {
					if(((source[read_posn] - 43) & mask) == 0x00) {
						concat(binary_string, "0");
					} else {
						concat(binary_string, "1");
					}
					mask = mask >> 1;
				}
			}

			if((source[read_posn] >= 'A') && (source[read_posn] <= 'Z')) {
				mask = 0x20;
				for(j = 0; j < 6; j++) {
					if(((source[read_posn] - 33) & mask) == 0x00) {
						concat(binary_string, "0");
					} else {
						concat(binary_string, "1");
					}
					mask = mask >> 1;
				}
			}

			switch(source[read_posn]) {
				case '[': concat(binary_string, "01111"); break;
				case '*': concat(binary_string, "111010"); break;
				case ',': concat(binary_string, "111011"); break;
				case '-': concat(binary_string, "111100"); break;
				case '.': concat(binary_string, "111101"); break;
				case '/': concat(binary_string, "111110"); break;
			}

			read_posn++;
		} while ((source[read_posn - 1] != '[') && (source[read_posn - 1] != '\0'));
	}

	read_posn += (2 * ai_crop);

	/* The compressed data field has been processed if appropriate - the
	rest of the data (if any) goes into a general-purpose data compaction field */

	j = 0;
	if(fnc1_latch == 1) {
		/* Encodation method "10" has been used but it is not followed by
		   AI 10, so a FNC1 character needs to be added */
		general_field[j] = '[';
		j++;
	}

	for(i = read_posn; i < strlen(source); i++) {
		general_field[j] = source[i];
		j++;
	}
	general_field[j] = '\0';

	if(strlen(general_field) != 0) { alpha_pad = 0; }

	latch = 0;
	for(i = 0; i < strlen(general_field); i++) {
		/* Table 13 - ISO/IEC 646 encodation */
		if((general_field[i] < ' ') || (general_field[i] > 'z')) {
			general_field_type[i] = INVALID_CHAR; latch = 1;
		} else {
			general_field_type[i] = ISOIEC;
		}

		if(general_field[i] == '#') {
			general_field_type[i] = INVALID_CHAR; latch = 1;
		}
		if(general_field[i] == '$') {
			general_field_type[i] = INVALID_CHAR; latch = 1;
		}
		if(general_field[i] == '@') {
			general_field_type[i] = INVALID_CHAR; latch = 1;
		}
		if(general_field[i] == 92) {
			general_field_type[i] = INVALID_CHAR; latch = 1;
		}
		if(general_field[i] == '^') {
			general_field_type[i] = INVALID_CHAR; latch = 1;
		}
		if(general_field[i] == 96) {
			general_field_type[i] = INVALID_CHAR; latch = 1;
		}

		/* Table 12 - Alphanumeric encodation */
		if((general_field[i] >= 'A') && (general_field[i] <= 'Z')) {
			general_field_type[i] = ALPHA_OR_ISO;
		}
		if(general_field[i] == '*') {
			general_field_type[i] = ALPHA_OR_ISO;
		}
		if(general_field[i] == ',') {
			general_field_type[i] = ALPHA_OR_ISO;
		}
		if(general_field[i] == '-') {
			general_field_type[i] = ALPHA_OR_ISO;
		}
		if(general_field[i] == '.') {
			general_field_type[i] = ALPHA_OR_ISO;
		}
		if(general_field[i] == '/') {
			general_field_type[i] = ALPHA_OR_ISO;
		}

		/* Numeric encodation */
		if((general_field[i] >= '0') && (general_field[i] <= '9')) {
			general_field_type[i] = ANY_ENC;
		}
		if(general_field[i] == '[') {
			/* FNC1 can be encoded in any system */
			general_field_type[i] = ANY_ENC;
		}

	}

	general_field_type[strlen(general_field)] = '\0';

	if(latch == 1) {
		/* Invalid characters in input data */
		strcpy(symbol->errtxt, "Invalid characters in input data");
		return ZINT_ERROR_INVALID_DATA;
	}

	for(i = 0; i < strlen(general_field); i++) {
		if((general_field_type[i] == ISOIEC) && (general_field[i + 1] == '[')) {
			general_field_type[i + 1] = ISOIEC;
		}
	}

	for(i = 0; i < strlen(general_field); i++) {
		if((general_field_type[i] == ALPHA_OR_ISO) && (general_field[i + 1] == '[')) {
			general_field_type[i + 1] = ALPHA_OR_ISO;
		}
	}

	latch = general_rules(general_field, general_field_type);

	i = 0;
	do {
		switch(general_field_type[i]) {
			case NUMERIC:

				if(i != 0) {
					if((general_field_type[i - 1] != NUMERIC) && (general_field[i - 1] != '[')) {
						concat(binary_string, "000"); /* Numeric latch */
					}
				}

				if(general_field[i] != '[') {
					d1 = ctoi(general_field[i]);
				} else {
					d1 = 10;
				}

				if(general_field[i + 1] != '[') {
					d2 = ctoi(general_field[i + 1]);
				} else {
					d2 = 10;
				}

				value = (11 * d1) + d2 + 8;

				mask = 0x40;
				for(j = 0; j < 7; j++) {
					if((value & mask) == 0x00) {
						concat(binary_string, "0");
					} else {
						concat(binary_string, "1");
					}
					mask = mask >> 1;
				}

				i += 2;
				break;

			case ALPHA:

				if(i != 0) {
					if((general_field_type[i - 1] == NUMERIC) || (general_field[i - 1] == '[')) {
						concat(binary_string, "0000"); /* Alphanumeric latch */
					}
					if(general_field_type[i - 1] == ISOIEC) {
						concat(binary_string, "00100"); /* ISO/IEC 646 latch */
					}
				}

				if((general_field[i] >= '0') && (general_field[i] <= '9')) {

					value = general_field[i] - 43;

					mask = 0x10;
					for(j = 0; j < 5; j++) {
						if((value & mask) == 0x00) {
							concat(binary_string, "0");
						} else {
							concat(binary_string, "1");
						}
						mask = mask >> 1;
					}
				}

				if((general_field[i] >= 'A') && (general_field[i] <= 'Z')) {

					value = general_field[i] - 33;

					mask = 0x20;
					for(j = 0; j < 6; j++) {
						if((value & mask) == 0x00) {
							concat(binary_string, "0");
						} else {
							concat(binary_string, "1");
						}
						mask = mask >> 1;
					}
				}

				if(general_field[i] == '[') concat(binary_string, "01111"); /* FNC1/Numeric latch */
				if(general_field[i] == '*') concat(binary_string, "111010"); /* asterisk */
				if(general_field[i] == ',') concat(binary_string, "111011"); /* comma */
				if(general_field[i] == '-') concat(binary_string, "111100"); /* minus or hyphen */
				if(general_field[i] == '.') concat(binary_string, "111101"); /* period or full stop */
				if(general_field[i] == '/') concat(binary_string, "111110"); /* slash or solidus */

				i++;
				break;

			case ISOIEC:

				if(i != 0) {
					if((general_field_type[i - 1] == NUMERIC) || (general_field[i - 1] == '[')) {
						concat(binary_string, "0000"); /* Alphanumeric latch */
						concat(binary_string, "00100"); /* ISO/IEC 646 latch */
					}
					if(general_field_type[i - 1] == ALPHA) {
						concat(binary_string, "00100"); /* ISO/IEC 646 latch */
					}
				}

				if((general_field[i] >= '0') && (general_field[i] <= '9')) {

					value = general_field[i] - 43;

					mask = 0x10;
					for(j = 0; j < 5; j++) {
						if((value & mask) == 0x00) {
							concat(binary_string, "0");
						} else {
							concat(binary_string, "1");
						}
						mask = mask >> 1;
					}
				}

				if((general_field[i] >= 'A') && (general_field[i] <= 'Z')) {

					value = general_field[i] - 1;

					mask = 0x40;
					for(j = 0; j < 7; j++) {
						if((value & mask) == 0x00) {
							concat(binary_string, "0");
						} else {
							concat(binary_string, "1");
						}
						mask = mask >> 1;
					}
				}

				if((general_field[i] >= 'a') && (general_field[i] <= 'z')) {

					value = general_field[i] - 7;

					mask = 0x40;
					for(j = 0; j < 7; j++) {
						if((value & mask) == 0x00) {
							concat(binary_string, "0");
						} else {
							concat(binary_string, "1");
						}
						mask = mask >> 1;
					}
				}

				if(general_field[i] == '[') concat(binary_string, "01111"); /* FNC1/Numeric latch */
				if(general_field[i] == '!') concat(binary_string, "11101000"); /* exclamation mark */
				if(general_field[i] == 34) concat(binary_string, "11101001"); /* quotation mark */
				if(general_field[i] == 37) concat(binary_string, "11101010"); /* percent sign */
				if(general_field[i] == '&') concat(binary_string, "11101011"); /* ampersand */
				if(general_field[i] == 39) concat(binary_string, "11101100"); /* apostrophe */
				if(general_field[i] == '(') concat(binary_string, "11101101"); /* left parenthesis */
				if(general_field[i] == ')') concat(binary_string, "11101110"); /* right parenthesis */
				if(general_field[i] == '*') concat(binary_string, "11101111"); /* asterisk */
				if(general_field[i] == '+') concat(binary_string, "11110000"); /* plus sign */
				if(general_field[i] == ',') concat(binary_string, "11110001"); /* comma */
				if(general_field[i] == '-') concat(binary_string, "11110010"); /* minus or hyphen */
				if(general_field[i] == '.') concat(binary_string, "11110011"); /* period or full stop */
				if(general_field[i] == '/') concat(binary_string, "11110100"); /* slash or solidus */
				if(general_field[i] == ':') concat(binary_string, "11110101"); /* colon */
				if(general_field[i] == ';') concat(binary_string, "11110110"); /* semicolon */
				if(general_field[i] == '<') concat(binary_string, "11110111"); /* less-than sign */
				if(general_field[i] == '=') concat(binary_string, "11111000"); /* equals sign */
				if(general_field[i] == '>') concat(binary_string, "11111001"); /* greater-than sign */
				if(general_field[i] == '?') concat(binary_string, "11111010"); /* question mark */
				if(general_field[i] == '_') concat(binary_string, "11111011"); /* underline or low line */
				if(general_field[i] == ' ') concat(binary_string, "11111100"); /* space */

				i++;
				break;
		}
	} while (i + latch < strlen(general_field));

	binary_length = strlen(binary_string);
	if(cc_mode == 1) {
		/* CC-A 2D component - calculate remaining space */
		switch(*(cc_width)) {
			case 2:
				if(binary_length > 167) { return ZINT_ERROR_TOO_LONG; }
				if(binary_length <= 167) { target_bitsize = 167; }
				if(binary_length <= 138) { target_bitsize = 138; }
				if(binary_length <= 118) { target_bitsize = 118; }
				if(binary_length <= 108) { target_bitsize = 108; }
				if(binary_length <= 88) { target_bitsize = 88; }
				if(binary_length <= 78) { target_bitsize = 78; }
				if(binary_length <= 59) { target_bitsize = 59; }
				break;
			case 3:
				if(binary_length > 167) { return ZINT_ERROR_TOO_LONG; }
				if(binary_length <= 167) { target_bitsize = 167; }
				if(binary_length <= 138) { target_bitsize = 138; }
				if(binary_length <= 118) { target_bitsize = 118; }
				if(binary_length <= 98) { target_bitsize = 98; }
				if(binary_length <= 78) { target_bitsize = 78; }
				break;
			case 4:
				if(binary_length > 197) { return ZINT_ERROR_TOO_LONG; }
				if(binary_length <= 197) { target_bitsize = 197; }
				if(binary_length <= 167) { target_bitsize = 167; }
				if(binary_length <= 138) { target_bitsize = 138; }
				if(binary_length <= 108) { target_bitsize = 108; }
				if(binary_length <= 78) { target_bitsize = 78; }
				break;
		}
	}

	if(cc_mode == 2) {
		/* CC-B 2D component - calculated from ISO/IEC 24728 Table 1  */
		switch(*(cc_width)) {
			case 2:
				if(binary_length > 336) { return ZINT_ERROR_TOO_LONG; }
				if(binary_length <= 336) { target_bitsize = 336; }
				if(binary_length <= 296) { target_bitsize = 296; }
				if(binary_length <= 256) { target_bitsize = 256; }
				if(binary_length <= 208) { target_bitsize = 208; }
				if(binary_length <= 160) { target_bitsize = 160; }
				if(binary_length <= 104) { target_bitsize = 104; }
				if(binary_length <= 56) { target_bitsize = 56; }
				break;
			case 3:
				if(binary_length > 768) { return ZINT_ERROR_TOO_LONG; }
				if(binary_length <= 768) { target_bitsize = 768; }
				if(binary_length <= 648) { target_bitsize = 648; }
				if(binary_length <= 536) { target_bitsize = 536; }
				if(binary_length <= 416) { target_bitsize = 416; }
				if(binary_length <= 304) { target_bitsize = 304; }
				if(binary_length <= 208) { target_bitsize = 208; }
				if(binary_length <= 152) { target_bitsize = 152; }
				if(binary_length <= 112) { target_bitsize = 112; }
				if(binary_length <= 72) { target_bitsize = 72; }
				if(binary_length <= 32) { target_bitsize = 32; }
				break;
			case 4:
				if(binary_length > 1184) { return ZINT_ERROR_TOO_LONG; }
				if(binary_length <= 1184) { target_bitsize = 1184; }
				if(binary_length <= 1016) { target_bitsize = 1016; }
				if(binary_length <= 840) { target_bitsize = 840; }
				if(binary_length <= 672) { target_bitsize = 672; }
				if(binary_length <= 496) { target_bitsize = 496; }
				if(binary_length <= 352) { target_bitsize = 352; }
				if(binary_length <= 264) { target_bitsize = 264; }
				if(binary_length <= 208) { target_bitsize = 208; }
				if(binary_length <= 152) { target_bitsize = 152; }
				if(binary_length <= 96) { target_bitsize = 96; }
				if(binary_length <= 56) { target_bitsize = 56; }
				break;
		}
	}

	if (cc_mode == 3) {
		/* CC-C 2D Component is a bit more complex! */
		int byte_length, codewords_used, ecc_level, ecc_codewords, rows;
		int codewords_total, target_codewords, target_bytesize;

		byte_length = binary_length / 8;
		if(binary_length % 8 != 0) { byte_length++; }

		codewords_used = (byte_length / 6) * 5;
		codewords_used += byte_length % 6;

		ecc_level = 7;
		if(codewords_used <= 1280) { ecc_level = 6; }
		if(codewords_used <= 640) { ecc_level = 5; }
		if(codewords_used <= 320) { ecc_level = 4; }
		if(codewords_used <= 160) { ecc_level = 3; }
		if(codewords_used <= 40) { ecc_level = 2; }
		*(ecc) = ecc_level;
		ecc_codewords = 1;
		for(i = 1; i <= (ecc_level + 1); i++){
			ecc_codewords *= 2;
		}

		codewords_used += ecc_codewords;
		codewords_used += 3;

		if(codewords_used > symbol->option_3) {
			return ZINT_ERROR_TOO_LONG;
		}
		/* *(cc_width) = 0.5 + sqrt((codewords_used) / 3); */
		*(cc_width) = (lin_width - 62) / 17;
		if((codewords_used / *(cc_width)) > 90) {
			/* stop the symbol from becoming too high */
			*(cc_width) = *(cc_width) + 1;
		}

		rows = codewords_used / *(cc_width);
		if(codewords_used % *(cc_width) != 0) {
			rows++;
		}

		codewords_total = *(cc_width) * rows;

		target_codewords = codewords_total - ecc_codewords;
		target_codewords -= 3;

		target_bytesize = 6 * (target_codewords / 5);
		target_bytesize += target_codewords % 5;

		target_bitsize = 8 * target_bytesize;
	}

	remainder = binary_length - target_bitsize;

	if(latch == 1) {
		i = 0;
		/* There is still one more numeric digit to encode */

		if((remainder >= 4) && (remainder <= 6)) {
			d1 = ctoi(general_field[i]);
			d1++;

			mask = 0x08;
			for(j = 0; j < 4; j++) {
				if((value & mask) == 0x00) {
					concat(binary_string, "0");
				} else {
					concat(binary_string, "1");
				}
				mask = mask >> 1;
			}
		} else {
			d1 = ctoi(general_field[i]);
			d2 = 10;

			value = (11 * d1) + d2 + 8;

			mask = 0x40;
			for(j = 0; j < 7; j++) {
				if((value & mask) == 0x00) {
					concat(binary_string, "0");
				} else {
					concat(binary_string, "1");
				}
				mask = mask >> 1;
			}
			/* This may push the symbol up to the next size */
		}
	}

	if(strlen(binary_string) > 11805) { /* (2361 * 5) */
		strcpy(symbol->errtxt, "Input too long");
		return ZINT_ERROR_TOO_LONG;
	}

	/* all the code below is repeated from above - it needs to be calculated again because the
	   size of the symbol may have changed when adding data in the above sequence */

	binary_length = strlen(binary_string);
	if(cc_mode == 1) {
		/* CC-A 2D component - calculate padding required */
		switch(*(cc_width)) {
			case 2:
				if(binary_length > 167) { return ZINT_ERROR_TOO_LONG; }
				if(binary_length <= 167) { target_bitsize = 167; }
				if(binary_length <= 138) { target_bitsize = 138; }
				if(binary_length <= 118) { target_bitsize = 118; }
				if(binary_length <= 108) { target_bitsize = 108; }
				if(binary_length <= 88) { target_bitsize = 88; }
				if(binary_length <= 78) { target_bitsize = 78; }
				if(binary_length <= 59) { target_bitsize = 59; }
				break;
			case 3:
				if(binary_length > 167) { return ZINT_ERROR_TOO_LONG; }
				if(binary_length <= 167) { target_bitsize = 167; }
				if(binary_length <= 138) { target_bitsize = 138; }
				if(binary_length <= 118) { target_bitsize = 118; }
				if(binary_length <= 98) { target_bitsize = 98; }
				if(binary_length <= 78) { target_bitsize = 78; }
				break;
			case 4:
				if(binary_length > 197) { return ZINT_ERROR_TOO_LONG; }
				if(binary_length <= 197) { target_bitsize = 197; }
				if(binary_length <= 167) { target_bitsize = 167; }
				if(binary_length <= 138) { target_bitsize = 138; }
				if(binary_length <= 108) { target_bitsize = 108; }
				if(binary_length <= 78) { target_bitsize = 78; }
				break;
		}
	}

	if(cc_mode == 2) {
		/* CC-B 2D component */
		switch(*(cc_width)) {
			case 2:
				if(binary_length > 336) { return ZINT_ERROR_TOO_LONG; }
				if(binary_length <= 336) { target_bitsize = 336; }
				if(binary_length <= 296) { target_bitsize = 296; }
				if(binary_length <= 256) { target_bitsize = 256; }
				if(binary_length <= 208) { target_bitsize = 208; }
				if(binary_length <= 160) { target_bitsize = 160; }
				if(binary_length <= 104) { target_bitsize = 104; }
				if(binary_length <= 56) { target_bitsize = 56; }
				break;
			case 3:
				if(binary_length > 768) { return ZINT_ERROR_TOO_LONG; }
				if(binary_length <= 768) { target_bitsize = 768; }
				if(binary_length <= 648) { target_bitsize = 648; }
				if(binary_length <= 536) { target_bitsize = 536; }
				if(binary_length <= 416) { target_bitsize = 416; }
				if(binary_length <= 304) { target_bitsize = 304; }
				if(binary_length <= 208) { target_bitsize = 208; }
				if(binary_length <= 152) { target_bitsize = 152; }
				if(binary_length <= 112) { target_bitsize = 112; }
				if(binary_length <= 72) { target_bitsize = 72; }
				if(binary_length <= 32) { target_bitsize = 32; }
				break;
			case 4:
				if(binary_length > 1184) { return ZINT_ERROR_TOO_LONG; }
				if(binary_length <= 1184) { target_bitsize = 1184; }
				if(binary_length <= 1016) { target_bitsize = 1016; }
				if(binary_length <= 840) { target_bitsize = 840; }
				if(binary_length <= 672) { target_bitsize = 672; }
				if(binary_length <= 496) { target_bitsize = 496; }
				if(binary_length <= 352) { target_bitsize = 352; }
				if(binary_length <= 264) { target_bitsize = 264; }
				if(binary_length <= 208) { target_bitsize = 208; }
				if(binary_length <= 152) { target_bitsize = 152; }
				if(binary_length <= 96) { target_bitsize = 96; }
				if(binary_length <= 56) { target_bitsize = 56; }
				break;
		}
	}

	if (cc_mode == 3) {
		/* CC-C 2D Component is a bit more complex! */
		int byte_length, codewords_used, ecc_level, ecc_codewords, rows;
		int codewords_total, target_codewords, target_bytesize;

		byte_length = binary_length / 8;
		if(binary_length % 8 != 0) { byte_length++; }

		codewords_used = (byte_length / 6) * 5;
		codewords_used += byte_length % 6;

		ecc_level = 7;
		if(codewords_used <= 1280) { ecc_level = 6; }
		if(codewords_used <= 640) { ecc_level = 5; }
		if(codewords_used <= 320) { ecc_level = 4; }
		if(codewords_used <= 160) { ecc_level = 3; }
		if(codewords_used <= 40) { ecc_level = 2; }
		*(ecc) = ecc_level;
		ecc_codewords = 1;
		for(i = 1; i <= (ecc_level + 1); i++){
			ecc_codewords *= 2;
		}

		codewords_used += ecc_codewords;
		codewords_used += 3;

		if(codewords_used > symbol->option_3) {
			return ZINT_ERROR_TOO_LONG;
		}
		/* *(cc_width) = 0.5 + sqrt((codewords_used) / 3); */
		*(cc_width) = (lin_width - 62) / 17;
		if((codewords_used / *(cc_width)) > 90) {
			/* stop the symbol from becoming too high */
			*(cc_width) = *(cc_width) + 1;
		}

		rows = codewords_used / *(cc_width);
		if(codewords_used % *(cc_width) != 0) {
			rows++;
		}

		codewords_total = *(cc_width) * rows;

		target_codewords = codewords_total - ecc_codewords;
		target_codewords -= 3;

		target_bytesize = 6 * (target_codewords / 5);
		target_bytesize += target_codewords % 5;

		target_bitsize = 8 * target_bytesize;
	}

	if(binary_length < target_bitsize) {
		/* Now add padding to binary string */
		if (alpha_pad == 1) {
			concat(binary_string, "11111");
			alpha_pad = 0;
			/* Extra FNC1 character required after Alpha encodation (section 5.2.3) */
		}

		if ((strlen(general_field) != 0) && (general_field_type[strlen(general_field) - 1] == NUMERIC)) {
			concat(binary_string, "0000");
		}

		while (strlen(binary_string) < target_bitsize) {
			concat(binary_string, "00100");
		}

		if(strlen(binary_string) > target_bitsize) {
			binary_string[target_bitsize] = '\0';
		}
	}

	return 0;
}