int aztec()

in Sharing/Src/External/zint-2.4.3/src/backend/aztec.c [667:1277]


int aztec(struct zint_symbol *symbol, unsigned char source[], int length)
{
	int x, y, i, j, data_blocks, ecc_blocks, layers, total_bits;
	char binary_string[20000], bit_pattern[20045], descriptor[42];
	char adjusted_string[20000];
	unsigned char desc_data[4], desc_ecc[6];
	int err_code, ecc_level, compact, data_length, data_maxsize, codeword_size, adjusted_length;
	int remainder, padbits, count, gs1, adjustment_size;
	int debug = 0, reader = 0;
	int comp_loop = 4;

#ifndef _MSC_VER
        unsigned char local_source[length + 1];
#else
        unsigned char* local_source = (unsigned char*)_alloca(length + 1);
#endif

	memset(binary_string,0,20000);
	memset(adjusted_string,0,20000);

	if(symbol->input_mode == GS1_MODE) { gs1 = 1; } else { gs1 = 0; }
	if(symbol->output_options & READER_INIT) { reader = 1; comp_loop = 1; }
	if((gs1 == 1) && (reader == 1)) {
		strcpy(symbol->errtxt, "Cannot encode in GS1 and Reader Initialisation mode at the same time");
		return ZINT_ERROR_INVALID_OPTION;
	}

	switch(symbol->input_mode) {
		case DATA_MODE:
		case GS1_MODE:
			memcpy(local_source, source, length);
			local_source[length] = '\0';
			break;
		case UNICODE_MODE:
			err_code = latin1_process(symbol, source, local_source, &length);
			if(err_code != 0) { return err_code; }
			break;
	}
	
	/* Aztec code can't handle NULL characters */
	for(i = 0; i < length; i++) {
		if(local_source[i] == '\0') {
			strcpy(symbol->errtxt, "Invalid character (NULL) in input data");
			return ZINT_ERROR_INVALID_DATA;
		}
	}
	
	err_code = aztec_text_process(local_source, length, binary_string, gs1);


	if(err_code != 0) {
		strcpy(symbol->errtxt, "Input too long or too many extended ASCII characters");
		return err_code;
	}

	if(!((symbol->option_1 >= -1) && (symbol->option_1 <= 4))) {
		strcpy(symbol->errtxt, "Invalid error correction level - using default instead");
		err_code = WARN_INVALID_OPTION;
		symbol->option_1 = -1;
	}

	ecc_level = symbol->option_1;

	if((ecc_level == -1) || (ecc_level == 0)) {
		ecc_level = 2;
	}

	data_length = strlen(binary_string);

	layers = 0; /* Keep compiler happy! */
	data_maxsize = 0; /* Keep compiler happy! */
	adjustment_size = 0;
	if(symbol->option_2 == 0) { /* The size of the symbol can be determined by Zint */
		do {
			/* Decide what size symbol to use - the smallest that fits the data */
			compact = 0; /* 1 = Aztec Compact, 0 = Normal Aztec */
			layers = 0;

			switch(ecc_level) {
				/* For each level of error correction work out the smallest symbol which
				the data will fit in */
				case 1: for(i = 32; i > 0; i--) {
						if((data_length + adjustment_size) < Aztec10DataSizes[i - 1]) {
							layers = i;
							compact = 0;
							data_maxsize = Aztec10DataSizes[i - 1];
						}
					}
					for(i = comp_loop; i > 0; i--) {
						if((data_length + adjustment_size) < AztecCompact10DataSizes[i - 1]) {
							layers = i;
							compact = 1;
							data_maxsize = AztecCompact10DataSizes[i - 1];
						}
					}
					break;
				case 2: for(i = 32; i > 0; i--) {
						if((data_length + adjustment_size) < Aztec23DataSizes[i - 1]) {
							layers = i;
							compact = 0;
							data_maxsize = Aztec23DataSizes[i - 1];
						}
					}
					for(i = comp_loop; i > 0; i--) {
						if((data_length + adjustment_size) < AztecCompact23DataSizes[i - 1]) {
							layers = i;
							compact = 1;
							data_maxsize = AztecCompact23DataSizes[i - 1];
						}
					}
					break;
				case 3: for(i = 32; i > 0; i--) {
						if((data_length + adjustment_size) < Aztec36DataSizes[i - 1]) {
							layers = i;
							compact = 0;
							data_maxsize = Aztec36DataSizes[i - 1];
						}
					}
					for(i = comp_loop; i > 0; i--) {
						if((data_length + adjustment_size) < AztecCompact36DataSizes[i - 1]) {
							layers = i;
							compact = 1;
							data_maxsize = AztecCompact36DataSizes[i - 1];
						}
					}
					break;
				case 4: for(i = 32; i > 0; i--) {
						if((data_length + adjustment_size) < Aztec50DataSizes[i - 1]) {
							layers = i;
							compact = 0;
							data_maxsize = Aztec50DataSizes[i - 1];
						}
					}
					for(i = comp_loop; i > 0; i--) {
						if((data_length + adjustment_size) < AztecCompact50DataSizes[i - 1]) {
							layers = i;
							compact = 1;
							data_maxsize = AztecCompact50DataSizes[i - 1];
						}
					}
					break;
			}

			if(layers == 0) { /* Couldn't find a symbol which fits the data */
				strcpy(symbol->errtxt, "Input too long (too many bits for selected ECC)");
				return ZINT_ERROR_TOO_LONG;
			}

			/* Determine codeword bitlength - Table 3 */
			codeword_size = 6; /* if (layers <= 2) */
			if((layers >= 3) && (layers <= 8)) { codeword_size = 8; }
			if((layers >= 9) && (layers <= 22)) { codeword_size = 10; }
			if(layers >= 23) { codeword_size = 12; }

			j = 0; i = 0;
			do {
				if((j + 1) % codeword_size == 0) {
					/* Last bit of codeword */
					int t, done = 0;
					count = 0;

					/* Discover how many '1's in current codeword */
					for(t = 0; t < (codeword_size - 1); t++) {
						if(binary_string[(i - (codeword_size - 1)) + t] == '1') count++;
					}

					if(count == (codeword_size - 1)) {
						adjusted_string[j] = '0';
						j++;
						done = 1;
					}

					if(count == 0) {
						adjusted_string[j] = '1';
						j++;
						done = 1;
					}

					if(done == 0) {
						adjusted_string[j] = binary_string[i];
						j++;
						i++;
					}
				}
				adjusted_string[j] = binary_string[i];
				j++;
				i++;
			} while (i <= (data_length + 1));
			adjusted_string[j] = '\0';
			adjusted_length = strlen(adjusted_string);
			adjustment_size = adjusted_length - data_length;

			/* Add padding */
			remainder = adjusted_length % codeword_size;

			padbits = codeword_size - remainder;
			if(padbits == codeword_size) { padbits = 0; }
			
			for(i = 0; i < padbits; i++) {
				concat(adjusted_string, "1");
			}
			adjusted_length = strlen(adjusted_string);

			count = 0;
			for(i = (adjusted_length - codeword_size); i < adjusted_length; i++) {
				if(adjusted_string[i] == '1') { count++; }
			}
			if(count == codeword_size) { adjusted_string[adjusted_length - 1] = '0'; } 
			
			if(debug) {
				printf("Codewords:\n");
				for(i = 0; i < (adjusted_length / codeword_size); i++) {
					for(j = 0; j < codeword_size; j++) {
						printf("%c", adjusted_string[(i * codeword_size) + j]);
					}
					printf("\n");
				}
			}

		} while(adjusted_length > data_maxsize);
		/* This loop will only repeat on the rare occasions when the rule about not having all 1s or all 0s
		means that the binary string has had to be lengthened beyond the maximum number of bits that can
		be encoded in a symbol of the selected size */

	} else { /* The size of the symbol has been specified by the user */
		if((reader == 1) && ((symbol->option_2 >= 2) && (symbol->option_2 <= 4))) {
			symbol->option_2 = 5;
		}
		if((symbol->option_2 >= 1) && (symbol->option_2 <= 4)) {
			compact = 1;
			layers = symbol->option_2;
		}
		if((symbol->option_2 >= 5) && (symbol->option_2 <= 36)) {
			compact = 0;
			layers = symbol->option_2 - 4;
		}
		if((symbol->option_2 < 0) || (symbol->option_2 > 36)) {
			strcpy(symbol->errtxt, "Invalid Aztec Code size");
			return ZINT_ERROR_INVALID_OPTION;
		}

		/* Determine codeword bitlength - Table 3 */
		if((layers >= 0) && (layers <= 2)) { codeword_size = 6; }
		if((layers >= 3) && (layers <= 8)) { codeword_size = 8; }
		if((layers >= 9) && (layers <= 22)) { codeword_size = 10; }
		if(layers >= 23) { codeword_size = 12; }

		j = 0; i = 0;
		do {
			if((j + 1) % codeword_size == 0) {
				/* Last bit of codeword */
				int t, done = 0;
				count = 0;

				/* Discover how many '1's in current codeword */
				for(t = 0; t < (codeword_size - 1); t++) {
					if(binary_string[(i - (codeword_size - 1)) + t] == '1') count++;
				}

				if(count == (codeword_size - 1)) {
					adjusted_string[j] = '0';
					j++;
					done = 1;
				}

				if(count == 0) {
					adjusted_string[j] = '1';
					j++;
					done = 1;
				}

				if(done == 0) {
					adjusted_string[j] = binary_string[i];
					j++;
					i++;
				}
			}
			adjusted_string[j] = binary_string[i];
			j++;
			i++;
		} while (i <= (data_length + 1));
		adjusted_string[j] = '\0';
		adjusted_length = strlen(adjusted_string);

		remainder = adjusted_length % codeword_size;

		padbits = codeword_size - remainder;
		if(padbits == codeword_size) { padbits = 0; }
			
		for(i = 0; i < padbits; i++) {
			concat(adjusted_string, "1");
		}
		adjusted_length = strlen(adjusted_string);

		count = 0;
		for(i = (adjusted_length - codeword_size); i < adjusted_length; i++) {
			if(adjusted_string[i] == '1') { count++; }
		}
		if(count == codeword_size) { adjusted_string[adjusted_length - 1] = '0'; } 
		
		/* Check if the data actually fits into the selected symbol size */
		if (compact) {
			data_maxsize = codeword_size * (AztecCompactSizes[layers - 1] - 3);
		} else {
			data_maxsize = codeword_size * (AztecSizes[layers - 1] - 3);
		}

		if(adjusted_length > data_maxsize) {
			strcpy(symbol->errtxt, "Data too long for specified Aztec Code symbol size");
			return ZINT_ERROR_TOO_LONG;
		}

		if(debug) {
			printf("Codewords:\n");
			for(i = 0; i < (adjusted_length / codeword_size); i++) {
				for(j = 0; j < codeword_size; j++) {
					printf("%c", adjusted_string[(i * codeword_size) + j]);
				}
				printf("\n");
			}
		}

	}

	if(reader && (layers > 22)) {
		strcpy(symbol->errtxt, "Data too long for reader initialisation symbol");
		return ZINT_ERROR_TOO_LONG;
	}

	data_blocks = adjusted_length / codeword_size;

	if(compact) {
		ecc_blocks = AztecCompactSizes[layers - 1] - data_blocks;
	} else {
		ecc_blocks = AztecSizes[layers - 1] - data_blocks;
	}

	if(debug) {
		printf("Generating a ");
		if(compact) { printf("compact"); } else { printf("full-size"); }
		printf(" symbol with %d layers\n", layers);
		printf("Requires ");
		if(compact) { printf("%d", AztecCompactSizes[layers - 1]); } else { printf("%d", AztecSizes[layers - 1]); }
		printf(" codewords of %d-bits\n", codeword_size);
		printf("    (%d data words, %d ecc words)\n", data_blocks, ecc_blocks);
	}
	
#ifndef _MSC_VER
	unsigned int data_part[data_blocks + 3], ecc_part[ecc_blocks + 3];
#else
	unsigned int* data_part = (unsigned int*)_alloca((data_blocks + 3) * sizeof(unsigned int));
	unsigned int* ecc_part = (unsigned int*)_alloca((ecc_blocks + 3) * sizeof(unsigned int));
#endif
	/* Copy across data into separate integers */
	memset(data_part,0,(data_blocks + 2)*sizeof(int));
	memset(ecc_part,0,(ecc_blocks + 2)*sizeof(int));

	/* Split into codewords and calculate reed-colomon error correction codes */
	switch(codeword_size) {
		case 6:
			for(i = 0; i < data_blocks; i++) {
				if(adjusted_string[i * codeword_size] == '1') { data_part[i] += 32; }
				if(adjusted_string[(i * codeword_size) + 1] == '1') { data_part[i] += 16; }
				if(adjusted_string[(i * codeword_size) + 2] == '1') { data_part[i] += 8; }
				if(adjusted_string[(i * codeword_size) + 3] == '1') { data_part[i] += 4; }
				if(adjusted_string[(i * codeword_size) + 4] == '1') { data_part[i] += 2; }
				if(adjusted_string[(i * codeword_size) + 5] == '1') { data_part[i] += 1; }
			}
			rs_init_gf(0x43);
			rs_init_code(ecc_blocks, 1);
			rs_encode_long(data_blocks, data_part, ecc_part);
			for(i = (ecc_blocks - 1); i >= 0; i--) {
				if(ecc_part[i] & 0x20) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x10) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x08) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x04) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x02) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x01) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
			}
			rs_free();
			break;
		case 8:
			for(i = 0; i < data_blocks; i++) {
				if(adjusted_string[i * codeword_size] == '1') { data_part[i] += 128; }
				if(adjusted_string[(i * codeword_size) + 1] == '1') { data_part[i] += 64; }
				if(adjusted_string[(i * codeword_size) + 2] == '1') { data_part[i] += 32; }
				if(adjusted_string[(i * codeword_size) + 3] == '1') { data_part[i] += 16; }
				if(adjusted_string[(i * codeword_size) + 4] == '1') { data_part[i] += 8; }
				if(adjusted_string[(i * codeword_size) + 5] == '1') { data_part[i] += 4; }
				if(adjusted_string[(i * codeword_size) + 6] == '1') { data_part[i] += 2; }
				if(adjusted_string[(i * codeword_size) + 7] == '1') { data_part[i] += 1; }
			}
			rs_init_gf(0x12d);
			rs_init_code(ecc_blocks, 1);
			rs_encode_long(data_blocks, data_part, ecc_part);
			for(i = (ecc_blocks - 1); i >= 0; i--) {
				if(ecc_part[i] & 0x80) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x40) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x20) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x10) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x08) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x04) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x02) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x01) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
			}
			rs_free();
			break;
		case 10:
			for(i = 0; i < data_blocks; i++) {
				if(adjusted_string[i * codeword_size] == '1') { data_part[i] += 512; }
				if(adjusted_string[(i * codeword_size) + 1] == '1') { data_part[i] += 256; }
				if(adjusted_string[(i * codeword_size) + 2] == '1') { data_part[i] += 128; }
				if(adjusted_string[(i * codeword_size) + 3] == '1') { data_part[i] += 64; }
				if(adjusted_string[(i * codeword_size) + 4] == '1') { data_part[i] += 32; }
				if(adjusted_string[(i * codeword_size) + 5] == '1') { data_part[i] += 16; }
				if(adjusted_string[(i * codeword_size) + 6] == '1') { data_part[i] += 8; }
				if(adjusted_string[(i * codeword_size) + 7] == '1') { data_part[i] += 4; }
				if(adjusted_string[(i * codeword_size) + 8] == '1') { data_part[i] += 2; }
				if(adjusted_string[(i * codeword_size) + 9] == '1') { data_part[i] += 1; }
			}
			rs_init_gf(0x409);
			rs_init_code(ecc_blocks, 1);
			rs_encode_long(data_blocks, data_part, ecc_part);
			for(i = (ecc_blocks - 1); i >= 0; i--) {
				if(ecc_part[i] & 0x200) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x100) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x80) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x40) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x20) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x10) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x08) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x04) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x02) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x01) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
			}
			rs_free();
			break;
		case 12:
			for(i = 0; i < data_blocks; i++) {
				if(adjusted_string[i * codeword_size] == '1') { data_part[i] += 2048; }
				if(adjusted_string[(i * codeword_size) + 1] == '1') { data_part[i] += 1024; }
				if(adjusted_string[(i * codeword_size) + 2] == '1') { data_part[i] += 512; }
				if(adjusted_string[(i * codeword_size) + 3] == '1') { data_part[i] += 256; }
				if(adjusted_string[(i * codeword_size) + 4] == '1') { data_part[i] += 128; }
				if(adjusted_string[(i * codeword_size) + 5] == '1') { data_part[i] += 64; }
				if(adjusted_string[(i * codeword_size) + 6] == '1') { data_part[i] += 32; }
				if(adjusted_string[(i * codeword_size) + 7] == '1') { data_part[i] += 16; }
				if(adjusted_string[(i * codeword_size) + 8] == '1') { data_part[i] += 8; }
				if(adjusted_string[(i * codeword_size) + 9] == '1') { data_part[i] += 4; }
				if(adjusted_string[(i * codeword_size) + 10] == '1') { data_part[i] += 2; }
				if(adjusted_string[(i * codeword_size) + 11] == '1') { data_part[i] += 1; }
			}
			rs_init_gf(0x1069);
			rs_init_code(ecc_blocks, 1);
			rs_encode_long(data_blocks, data_part, ecc_part);
			for(i = (ecc_blocks - 1); i >= 0; i--) {
				if(ecc_part[i] & 0x800) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x400) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x200) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x100) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x80) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x40) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x20) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x10) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x08) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x04) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x02) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
				if(ecc_part[i] & 0x01) { concat(adjusted_string, "1"); } else { concat(adjusted_string, "0"); }
			}
			rs_free();
			break;
	}

	/* Invert the data so that actual data is on the outside and reed-solomon on the inside */
	memset(bit_pattern,'0',20045);

	total_bits = (data_blocks + ecc_blocks) * codeword_size;
	for(i = 0; i < total_bits; i++) {
		bit_pattern[i] = adjusted_string[total_bits - i - 1];
	}

	/* Now add the symbol descriptor */
	memset(desc_data,0,4);
	memset(desc_ecc,0,6);
	memset(descriptor,0,42);

	if(compact) {
		/* The first 2 bits represent the number of layers minus 1 */
		if((layers - 1) & 0x02) { descriptor[0] = '1'; } else { descriptor[0] = '0'; }
		if((layers - 1) & 0x01) { descriptor[1] = '1'; } else { descriptor[1] = '0'; }
		/* The next 6 bits represent the number of data blocks minus 1 */
		if(reader) {
			descriptor[2] = '1';
		} else {
			if((data_blocks - 1) & 0x20) { descriptor[2] = '1'; } else { descriptor[2] = '0'; }
		}
		if((data_blocks - 1) & 0x10) { descriptor[3] = '1'; } else { descriptor[3] = '0'; }
		if((data_blocks - 1) & 0x08) { descriptor[4] = '1'; } else { descriptor[4] = '0'; }
		if((data_blocks - 1) & 0x04) { descriptor[5] = '1'; } else { descriptor[5] = '0'; }
		if((data_blocks - 1) & 0x02) { descriptor[6] = '1'; } else { descriptor[6] = '0'; }
		if((data_blocks - 1) & 0x01) { descriptor[7] = '1'; } else { descriptor[7] = '0'; }
		descriptor[8] = '\0';
		if(debug) printf("Mode Message = %s\n", descriptor);
	} else {
		/* The first 5 bits represent the number of layers minus 1 */
		if((layers - 1) & 0x10) { descriptor[0] = '1'; } else { descriptor[0] = '0'; }
		if((layers - 1) & 0x08) { descriptor[1] = '1'; } else { descriptor[1] = '0'; }
		if((layers - 1) & 0x04) { descriptor[2] = '1'; } else { descriptor[2] = '0'; }
		if((layers - 1) & 0x02) { descriptor[3] = '1'; } else { descriptor[3] = '0'; }
		if((layers - 1) & 0x01) { descriptor[4] = '1'; } else { descriptor[4] = '0'; }
		/* The next 11 bits represent the number of data blocks minus 1 */
		if(reader) {
			descriptor[5] = '1';
		} else {
			if((data_blocks - 1) & 0x400) { descriptor[5] = '1'; } else { descriptor[5] = '0'; }
		}
		if((data_blocks - 1) & 0x200) { descriptor[6] = '1'; } else { descriptor[6] = '0'; }
		if((data_blocks - 1) & 0x100) { descriptor[7] = '1'; } else { descriptor[7] = '0'; }
		if((data_blocks - 1) & 0x80) { descriptor[8] = '1'; } else { descriptor[8] = '0'; }
		if((data_blocks - 1) & 0x40) { descriptor[9] = '1'; } else { descriptor[9] = '0'; }
		if((data_blocks - 1) & 0x20) { descriptor[10] = '1'; } else { descriptor[10] = '0'; }
		if((data_blocks - 1) & 0x10) { descriptor[11] = '1'; } else { descriptor[11] = '0'; }
		if((data_blocks - 1) & 0x08) { descriptor[12] = '1'; } else { descriptor[12] = '0'; }
		if((data_blocks - 1) & 0x04) { descriptor[13] = '1'; } else { descriptor[13] = '0'; }
		if((data_blocks - 1) & 0x02) { descriptor[14] = '1'; } else { descriptor[14] = '0'; }
		if((data_blocks - 1) & 0x01) { descriptor[15] = '1'; } else { descriptor[15] = '0'; }
		descriptor[16] = '\0';
		if(debug) printf("Mode Message = %s\n", descriptor);
	}

	/* Split into 4-bit codewords */
	for(i = 0; i < 4; i++) {
		if(descriptor[i * 4] == '1') { desc_data[i] += 8; }
		if(descriptor[(i * 4) + 1] == '1') { desc_data[i] += 4; }
		if(descriptor[(i * 4) + 2] == '1') { desc_data[i] += 2; }
		if(descriptor[(i * 4) + 3] == '1') { desc_data[i] += 1; }
	}
	
	/* Add reed-solomon error correction with Galois field GF(16) and prime modulus
	x^4 + x + 1 (section 7.2.3)*/

	rs_init_gf(0x13);
	if(compact) {
		rs_init_code(5, 1);
		rs_encode(2, desc_data, desc_ecc);
		for(i = 0; i < 5; i++) {
			if(desc_ecc[4 - i] & 0x08) { descriptor[(i * 4) + 8] = '1'; } else { descriptor[(i * 4) + 8] = '0'; }
			if(desc_ecc[4 - i] & 0x04) { descriptor[(i * 4) + 9] = '1'; } else { descriptor[(i * 4) + 9] = '0'; }
			if(desc_ecc[4 - i] & 0x02) { descriptor[(i * 4) + 10] = '1'; } else { descriptor[(i * 4) + 10] = '0'; }
			if(desc_ecc[4 - i] & 0x01) { descriptor[(i * 4) + 11] = '1'; } else { descriptor[(i * 4) + 11] = '0'; }
		}
	} else {
		rs_init_code(6, 1);
		rs_encode(4, desc_data, desc_ecc);
		for(i = 0; i < 6; i++) {
			if(desc_ecc[5 - i] & 0x08) { descriptor[(i * 4) + 16] = '1'; } else { descriptor[(i * 4) + 16] = '0'; }
			if(desc_ecc[5 - i] & 0x04) { descriptor[(i * 4) + 17] = '1'; } else { descriptor[(i * 4) + 17] = '0'; }
			if(desc_ecc[5 - i] & 0x02) { descriptor[(i * 4) + 18] = '1'; } else { descriptor[(i * 4) + 18] = '0'; }
			if(desc_ecc[5 - i] & 0x01) { descriptor[(i * 4) + 19] = '1'; } else { descriptor[(i * 4) + 19] = '0'; }
		}
	}
	rs_free();

	/* Merge descriptor with the rest of the symbol */
	for(i = 0; i < 40; i++) {
		if(compact) {
			bit_pattern[2000 + i - 2] = descriptor[i];
		} else {
			bit_pattern[20000 + i - 2] = descriptor[i];
		}
	}

	/* Plot all of the data into the symbol in pre-defined spiral pattern */
	if(compact) {

		for(y = AztecCompactOffset[layers - 1]; y < (27 - AztecCompactOffset[layers - 1]); y++) {
			for(x = AztecCompactOffset[layers - 1]; x < (27 - AztecCompactOffset[layers - 1]); x++) {
				if(CompactAztecMap[(y * 27) + x] == 1) {
					set_module(symbol, y - AztecCompactOffset[layers - 1], x - AztecCompactOffset[layers - 1]);
				}
				if(CompactAztecMap[(y * 27) + x] >= 2) {
					if(bit_pattern[CompactAztecMap[(y * 27) + x] - 2] == '1') {
						set_module(symbol, y - AztecCompactOffset[layers - 1], x - AztecCompactOffset[layers - 1]);
					}
				}
			}
			symbol->row_height[y - AztecCompactOffset[layers - 1]] = 1;
		}
		symbol->rows = 27 - (2 * AztecCompactOffset[layers - 1]);
		symbol->width = 27 - (2 * AztecCompactOffset[layers - 1]);
	} else {

		for(y = AztecOffset[layers - 1]; y < (151 - AztecOffset[layers - 1]); y++) {
			for(x = AztecOffset[layers - 1]; x < (151 - AztecOffset[layers - 1]); x++) {
				if(AztecMap[(y * 151) + x] == 1) {
					set_module(symbol, y - AztecOffset[layers - 1], x - AztecOffset[layers - 1]);
				}
				if(AztecMap[(y * 151) + x] >= 2) {
					if(bit_pattern[AztecMap[(y * 151) + x] - 2] == '1') {
						set_module(symbol, y - AztecOffset[layers - 1], x - AztecOffset[layers - 1]);
					}
				}
			}
			symbol->row_height[y - AztecOffset[layers - 1]] = 1;
		}
		symbol->rows = 151 - (2 * AztecOffset[layers - 1]);
		symbol->width = 151 - (2 * AztecOffset[layers - 1]);
	}

	return err_code;
}