Mercurial > hgrepos > Python2 > PyMuPDF
diff mupdf-source/thirdparty/zint/backend/aztec.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mupdf-source/thirdparty/zint/backend/aztec.c Mon Sep 15 11:43:07 2025 +0200 @@ -0,0 +1,1352 @@ +/* aztec.c - Handles Aztec 2D Symbols */ +/* + libzint - the open source barcode library + Copyright (C) 2009-2024 Robin Stuart <rstuart114@gmail.com> + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the project nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + */ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include <assert.h> +#include <stdio.h> +#include "common.h" +#include "aztec.h" +#include "reedsol.h" + +#define AZTEC_MAX_CAPACITY 19968 /* ISO/IEC 24778:2008 5.3 Table 1 Maximum Symbol Bit Capacity */ +/* Allow up to absolute minimum 3 ECC codewords, but now warn if results in less than the 5% minimum (ISO/IEC + 24778:2008 4.1.e) - previously could go down to 3 ECC codewords anyway if version given, due to bit-stuffing */ +#define AZTEC_BIN_CAPACITY 19932 /* AZTEC_MAX_CAPACITY less 3 * 12 = 36 */ +#define AZTEC_MAP_SIZE 22801 /* AztecMap Version 32 151 x 151 */ +#define AZTEC_MAP_POSN_MAX 20039 /* Maximum position index in AztecMap */ + +#define AZ_BIN_CAP_CWDS_S "1661" /* String version of (AZTEC_BIN_CAPACITY / 12) */ + +/* Count number of consecutive (. SP) or (, SP) Punct mode doubles for comparison against Digit mode encoding */ +static int az_count_doubles(const unsigned char source[], int i, const int length) { + int c = 0; + + while ((i + 1 < length) && ((source[i] == '.') || (source[i] == ',')) && (source[i + 1] == ' ')) { + c++; + i += 2; + } + + return c; +} + +/* Count number of consecutive full stops or commas (can be encoded in Punct or Digit mode) */ +static int az_count_dotcomma(const unsigned char source[], int i, const int length) { + int c = 0; + + while (i < length && ((source[i] == '.') || (source[i] == ','))) { + c++; + i++; + } + + return c; +} + +/* Count number of consecutive `chr`s */ +static int az_count_chr(const unsigned char source[], int i, const int length, const unsigned char chr) { + int c = 0; + + while (i < length && source[i] == chr) { + c++; + i++; + } + + return c; +} + +/* Return mode following current, or 'E' if none */ +static char az_get_next_mode(const char encode_mode[], const int src_len, int i) { + int current_mode = encode_mode[i]; + + do { + i++; + } while ((i < src_len) && (encode_mode[i] == current_mode)); + if (i >= src_len) { + return 'E'; + } else { + return encode_mode[i]; + } +} + +/* Same as `bin_append_posn()`, except check for buffer overflow first */ +static int az_bin_append_posn(const int arg, const int length, char *binary, const int bin_posn) { + + if (bin_posn + length > AZTEC_BIN_CAPACITY) { + return 0; /* Fail */ + } + return bin_append_posn(arg, length, binary, bin_posn); +} + +/* Determine encoding modes and encode */ +static int aztec_text_process(const unsigned char source[], int src_len, int bp, char binary_string[], const int gs1, + const int eci, char *p_current_mode, int *data_length, const int debug_print) { + + int i, j; + const char initial_mode = p_current_mode ? *p_current_mode : 'U'; + char current_mode; + int count; + char next_mode; + int reduced_length; + char *encode_mode = (char *) z_alloca(src_len + 1); + unsigned char *reduced_source = (unsigned char *) z_alloca(src_len + 1); + char *reduced_encode_mode = (char *) z_alloca(src_len + 1); + + for (i = 0; i < src_len; i++) { + if (source[i] >= 128) { + encode_mode[i] = 'B'; + } else if (gs1 && source[i] == '\x1D') { + encode_mode[i] = 'P'; /* For FLG(n) & FLG(0) = FNC1 */ + } else { + encode_mode[i] = AztecModes[source[i]]; + } + } + + /* Deal first with letter combinations which can be combined to one codeword + Combinations are (CR LF) (. SP) (, SP) (: SP) in Punct mode */ + current_mode = initial_mode; + for (i = 0; i + 1 < src_len; i++) { + /* Combination (CR LF) should always be in Punct mode */ + if ((source[i] == 13) && (source[i + 1] == 10)) { + encode_mode[i] = 'P'; + encode_mode[i + 1] = 'P'; + + /* Combination (: SP) should always be in Punct mode */ + } else if ((source[i] == ':') && (source[i + 1] == ' ')) { + encode_mode[i + 1] = 'P'; + + /* Combinations (. SP) and (, SP) sometimes use fewer bits in Digit mode */ + } else if (((source[i] == '.') || (source[i] == ',')) && (source[i + 1] == ' ') && (encode_mode[i] == 'X')) { + count = az_count_doubles(source, i, src_len); + next_mode = az_get_next_mode(encode_mode, src_len, i); + + if (current_mode == 'U') { + if ((next_mode == 'D') && (count <= 5)) { + memset(encode_mode + i, 'D', 2 * count); + } + + } else if (current_mode == 'L') { + if ((next_mode == 'D') && (count <= 4)) { + memset(encode_mode + i, 'D', 2 * count); + } + + } else if (current_mode == 'M') { + if ((next_mode == 'D') && (count == 1)) { + encode_mode[i] = 'D'; + encode_mode[i + 1] = 'D'; + } + + } else if (current_mode == 'D') { + if ((next_mode != 'D') && (count <= 4)) { + memset(encode_mode + i, 'D', 2 * count); + } else if ((next_mode == 'D') && (count <= 7)) { + memset(encode_mode + i, 'D', 2 * count); + } + } + + /* Default is Punct mode */ + if (encode_mode[i] == 'X') { + encode_mode[i] = 'P'; + encode_mode[i + 1] = 'P'; + } + } + + if ((encode_mode[i] != 'X') && (encode_mode[i] != 'B')) { + current_mode = encode_mode[i]; + } + } + + if (debug_print) { + fputs("First Pass:\n", stdout); + printf("%.*s\n", src_len, encode_mode); + } + + /* Reduce two letter combinations to one codeword marked as [abcd] in Punct mode */ + i = 0; + j = 0; + while (i < src_len) { + reduced_encode_mode[j] = encode_mode[i]; + if (i + 1 < src_len) { + if ((source[i] == 13) && (source[i + 1] == 10)) { /* CR LF */ + reduced_source[j] = 'a'; + i += 2; + } else if ((source[i] == '.') && (source[i + 1] == ' ') && (encode_mode[i] == 'P')) { + reduced_source[j] = 'b'; + i += 2; + } else if ((source[i] == ',') && (source[i + 1] == ' ') && (encode_mode[i] == 'P')) { + reduced_source[j] = 'c'; + i += 2; + } else if ((source[i] == ':') && (source[i + 1] == ' ')) { + reduced_source[j] = 'd'; + i += 2; + } else { + reduced_source[j] = source[i++]; + } + } else { + reduced_source[j] = source[i++]; + } + j++; + } + + reduced_length = j; + + current_mode = initial_mode; + for (i = 0; i < reduced_length; i++) { + /* Resolve Carriage Return (CR) which can be Punct or Mixed mode */ + if (reduced_source[i] == 13) { + count = az_count_chr(reduced_source, i, reduced_length, 13); + next_mode = az_get_next_mode(reduced_encode_mode, reduced_length, i); + + if ((current_mode == 'U') && ((next_mode == 'U') || (next_mode == 'B')) && (count == 1)) { + reduced_encode_mode[i] = 'P'; + + } else if ((current_mode == 'L') && ((next_mode == 'L') || (next_mode == 'B')) && (count == 1)) { + reduced_encode_mode[i] = 'P'; + + } else if ((current_mode == 'P') || (next_mode == 'P')) { + reduced_encode_mode[i] = 'P'; + } + + if (current_mode == 'D') { + if (((next_mode == 'E') || (next_mode == 'U') || (next_mode == 'D') || (next_mode == 'B')) + && (count <= 2)) { + memset(reduced_encode_mode + i, 'P', count); + } else if ((next_mode == 'L') && (count == 1)) { + reduced_encode_mode[i] = 'P'; + } + } + + /* Default is Mixed mode */ + if (reduced_encode_mode[i] == 'X') { + reduced_encode_mode[i] = 'M'; + } + + /* Resolve full stop and comma which can be in Punct or Digit mode */ + } else if ((reduced_source[i] == '.') || (reduced_source[i] == ',')) { + count = az_count_dotcomma(reduced_source, i, reduced_length); + next_mode = az_get_next_mode(reduced_encode_mode, reduced_length, i); + + if (current_mode == 'U') { + if (((next_mode == 'U') || (next_mode == 'L') || (next_mode == 'M') || (next_mode == 'B')) + && (count == 1)) { + reduced_encode_mode[i] = 'P'; + } + + } else if (current_mode == 'L') { + if ((next_mode == 'L') && (count <= 2)) { + memset(reduced_encode_mode + i, 'P', count); + } else if (((next_mode == 'M') || (next_mode == 'B')) && (count == 1)) { + reduced_encode_mode[i] = 'P'; + } + + } else if (current_mode == 'M') { + if (((next_mode == 'E') || (next_mode == 'U') || (next_mode == 'L') || (next_mode == 'M')) + && (count <= 4)) { + memset(reduced_encode_mode + i, 'P', count); + } else if ((next_mode == 'B') && (count <= 2)) { + memset(reduced_encode_mode + i, 'P', count); + } + + } else if ((current_mode == 'P') && (next_mode != 'D') && (count <= 9)) { + memset(reduced_encode_mode + i, 'P', count); + } + + /* Default is Digit mode */ + if (reduced_encode_mode[i] == 'X') { + reduced_encode_mode[i] = 'D'; + } + + /* Resolve Space (SP) which can be any mode except Punct */ + } else if (reduced_source[i] == ' ') { + count = az_count_chr(reduced_source, i, reduced_length, ' '); + next_mode = az_get_next_mode(reduced_encode_mode, reduced_length, i); + + if (current_mode == 'U') { + if ((next_mode == 'E') && (count <= 5)) { + memset(reduced_encode_mode + i, 'U', count); + } else if (((next_mode == 'U') || (next_mode == 'L') || (next_mode == 'M') || (next_mode == 'P') + || (next_mode == 'B')) && (count <= 9)) { + memset(reduced_encode_mode + i, 'U', count); + } + + } else if (current_mode == 'L') { + if ((next_mode == 'E') && (count <= 5)) { + memset(reduced_encode_mode + i, 'L', count); + + } else if ((next_mode == 'U') && (count == 1)) { + reduced_encode_mode[i] = 'L'; + + } else if ((next_mode == 'L') && (count <= 14)) { + memset(reduced_encode_mode + i, 'L', count); + + } else if (((next_mode == 'M') || (next_mode == 'P') || (next_mode == 'B')) && (count <= 9)) { + memset(reduced_encode_mode + i, 'L', count); + } + + } else if (current_mode == 'M') { + if (((next_mode == 'E') || (next_mode == 'U')) && (count <= 9)) { + memset(reduced_encode_mode + i, 'M', count); + + } else if (((next_mode == 'L') || (next_mode == 'B')) && (count <= 14)) { + memset(reduced_encode_mode + i, 'M', count); + + } else if (((next_mode == 'M') || (next_mode == 'P')) && (count <= 19)) { + memset(reduced_encode_mode + i, 'M', count); + } + + } else if (current_mode == 'P') { + if ((next_mode == 'E') && (count <= 5)) { + memset(reduced_encode_mode + i, 'U', count); + + } else if (((next_mode == 'U') || (next_mode == 'L') || (next_mode == 'M') || (next_mode == 'P') + || (next_mode == 'B')) && (count <= 9)) { + memset(reduced_encode_mode + i, 'U', count); + } + } + + /* Default is Digit mode */ + if (reduced_encode_mode[i] == 'X') { + reduced_encode_mode[i] = 'D'; + } + } + + if (reduced_encode_mode[i] != 'B') { + current_mode = reduced_encode_mode[i]; + } + } + + /* Decide when to use P/S instead of P/L and U/S instead of U/L */ + current_mode = initial_mode; + for (i = 0; i < reduced_length; i++) { + + if (reduced_encode_mode[i] != current_mode) { + + for (count = 0; ((i + count) < reduced_length) + && (reduced_encode_mode[i + count] == reduced_encode_mode[i]); count++); + next_mode = az_get_next_mode(reduced_encode_mode, reduced_length, i); + + if (reduced_encode_mode[i] == 'P') { + if ((current_mode == 'U') && (count <= 2)) { + memset(reduced_encode_mode + i, 'p', count); + + } else if ((current_mode == 'L') && (next_mode != 'U') && (count <= 2)) { + memset(reduced_encode_mode + i, 'p', count); + + } else if ((current_mode == 'L') && (next_mode == 'U') && (count == 1)) { + reduced_encode_mode[i] = 'p'; + + } else if ((current_mode == 'M') && (next_mode != 'M') && (count == 1)) { + reduced_encode_mode[i] = 'p'; + + } else if ((current_mode == 'M') && (next_mode == 'M') && (count <= 2)) { + memset(reduced_encode_mode + i, 'p', count); + + } else if ((current_mode == 'D') && (next_mode != 'D') && (count <= 3)) { + memset(reduced_encode_mode + i, 'p', count); + + } else if ((current_mode == 'D') && (next_mode == 'D') && (count <= 6)) { + memset(reduced_encode_mode + i, 'p', count); + } + + } else if (reduced_encode_mode[i] == 'U') { + if ((current_mode == 'L') && ((next_mode == 'L') || (next_mode == 'M')) && (count <= 2)) { + memset(reduced_encode_mode + i, 'u', count); + + } else if ((current_mode == 'L') && ((next_mode == 'E') || (next_mode == 'D') || (next_mode == 'B') + || (next_mode == 'P')) && (count == 1)) { + reduced_encode_mode[i] = 'u'; + + } else if ((current_mode == 'D') && (next_mode == 'D') && (count == 1)) { + reduced_encode_mode[i] = 'u'; + + } else if ((current_mode == 'D') && (next_mode == 'P') && (count <= 2)) { + memset(reduced_encode_mode + i, 'u', count); + } + } + } + + if ((reduced_encode_mode[i] != 'p') && (reduced_encode_mode[i] != 'u') && (reduced_encode_mode[i] != 'B')) { + current_mode = reduced_encode_mode[i]; + } + } + + if (debug_print) { + printf("%.*s\n", reduced_length, reduced_source); + printf("%.*s\n", reduced_length, reduced_encode_mode); + } + + if (bp == 0 && gs1) { + bp = bin_append_posn(0, 5, binary_string, bp); /* P/S */ + bp = bin_append_posn(0, 5, binary_string, bp); /* FLG(n) */ + bp = bin_append_posn(0, 3, binary_string, bp); /* FLG(0) */ + } + + if (eci != 0) { + bp = bin_append_posn(0, initial_mode == 'D' ? 4 : 5, binary_string, bp); /* P/S */ + bp = bin_append_posn(0, 5, binary_string, bp); /* FLG(n) */ + if (eci < 10) { + bp = bin_append_posn(1, 3, binary_string, bp); /* FLG(1) */ + bp = bin_append_posn(2 + eci, 4, binary_string, bp); + } else if (eci <= 99) { + bp = bin_append_posn(2, 3, binary_string, bp); /* FLG(2) */ + bp = bin_append_posn(2 + (eci / 10), 4, binary_string, bp); + bp = bin_append_posn(2 + (eci % 10), 4, binary_string, bp); + } else if (eci <= 999) { + bp = bin_append_posn(3, 3, binary_string, bp); /* FLG(3) */ + bp = bin_append_posn(2 + (eci / 100), 4, binary_string, bp); + bp = bin_append_posn(2 + ((eci % 100) / 10), 4, binary_string, bp); + bp = bin_append_posn(2 + (eci % 10), 4, binary_string, bp); + } else if (eci <= 9999) { + bp = bin_append_posn(4, 3, binary_string, bp); /* FLG(4) */ + bp = bin_append_posn(2 + (eci / 1000), 4, binary_string, bp); + bp = bin_append_posn(2 + ((eci % 1000) / 100), 4, binary_string, bp); + bp = bin_append_posn(2 + ((eci % 100) / 10), 4, binary_string, bp); + bp = bin_append_posn(2 + (eci % 10), 4, binary_string, bp); + } else if (eci <= 99999) { + bp = bin_append_posn(5, 3, binary_string, bp); /* FLG(5) */ + bp = bin_append_posn(2 + (eci / 10000), 4, binary_string, bp); + bp = bin_append_posn(2 + ((eci % 10000) / 1000), 4, binary_string, bp); + bp = bin_append_posn(2 + ((eci % 1000) / 100), 4, binary_string, bp); + bp = bin_append_posn(2 + ((eci % 100) / 10), 4, binary_string, bp); + bp = bin_append_posn(2 + (eci % 10), 4, binary_string, bp); + } else { + bp = bin_append_posn(6, 3, binary_string, bp); /* FLG(6) */ + bp = bin_append_posn(2 + (eci / 100000), 4, binary_string, bp); + bp = bin_append_posn(2 + ((eci % 100000) / 10000), 4, binary_string, bp); + bp = bin_append_posn(2 + ((eci % 10000) / 1000), 4, binary_string, bp); + bp = bin_append_posn(2 + ((eci % 1000) / 100), 4, binary_string, bp); + bp = bin_append_posn(2 + ((eci % 100) / 10), 4, binary_string, bp); + bp = bin_append_posn(2 + (eci % 10), 4, binary_string, bp); + } + } + + current_mode = initial_mode; + for (i = 0; i < reduced_length; i++) { + + if (reduced_encode_mode[i] != current_mode) { + /* Change mode */ + if (current_mode == 'U') { + switch (reduced_encode_mode[i]) { + case 'L': + if (!(bp = az_bin_append_posn(28, 5, binary_string, bp))) return 0; /* L/L */ + break; + case 'M': + if (!(bp = az_bin_append_posn(29, 5, binary_string, bp))) return 0; /* M/L */ + break; + case 'P': + if (!(bp = az_bin_append_posn(29, 5, binary_string, bp))) return 0; /* M/L */ + if (!(bp = az_bin_append_posn(30, 5, binary_string, bp))) return 0; /* P/L */ + break; + case 'p': + if (!(bp = az_bin_append_posn(0, 5, binary_string, bp))) return 0; /* P/S */ + break; + case 'D': + if (!(bp = az_bin_append_posn(30, 5, binary_string, bp))) return 0; /* D/L */ + break; + case 'B': + if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* B/S */ + break; + } + } else if (current_mode == 'L') { + switch (reduced_encode_mode[i]) { + case 'U': + if (!(bp = az_bin_append_posn(30, 5, binary_string, bp))) return 0; /* D/L */ + if (!(bp = az_bin_append_posn(14, 4, binary_string, bp))) return 0; /* U/L */ + break; + case 'u': + if (!(bp = az_bin_append_posn(28, 5, binary_string, bp))) return 0; /* U/S */ + break; + case 'M': + if (!(bp = az_bin_append_posn(29, 5, binary_string, bp))) return 0; /* M/L */ + break; + case 'P': + if (!(bp = az_bin_append_posn(29, 5, binary_string, bp))) return 0; /* M/L */ + if (!(bp = az_bin_append_posn(30, 5, binary_string, bp))) return 0; /* P/L */ + break; + case 'p': + if (!(bp = az_bin_append_posn(0, 5, binary_string, bp))) return 0; /* P/S */ + break; + case 'D': + if (!(bp = az_bin_append_posn(30, 5, binary_string, bp))) return 0; /* D/L */ + break; + case 'B': + if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* B/S */ + break; + } + } else if (current_mode == 'M') { + switch (reduced_encode_mode[i]) { + case 'U': + if (!(bp = az_bin_append_posn(29, 5, binary_string, bp))) return 0; /* U/L */ + break; + case 'L': + if (!(bp = az_bin_append_posn(28, 5, binary_string, bp))) return 0; /* L/L */ + break; + case 'P': + if (!(bp = az_bin_append_posn(30, 5, binary_string, bp))) return 0; /* P/L */ + break; + case 'p': + if (!(bp = az_bin_append_posn(0, 5, binary_string, bp))) return 0; /* P/S */ + break; + case 'D': + if (!(bp = az_bin_append_posn(29, 5, binary_string, bp))) return 0; /* U/L */ + if (!(bp = az_bin_append_posn(30, 5, binary_string, bp))) return 0; /* D/L */ + break; + case 'B': + if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* B/S */ + break; + } + } else if (current_mode == 'P') { + switch (reduced_encode_mode[i]) { + case 'U': + if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* U/L */ + break; + case 'L': + if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* U/L */ + if (!(bp = az_bin_append_posn(28, 5, binary_string, bp))) return 0; /* L/L */ + break; + case 'M': + if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* U/L */ + if (!(bp = az_bin_append_posn(29, 5, binary_string, bp))) return 0; /* M/L */ + break; + case 'D': + if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* U/L */ + if (!(bp = az_bin_append_posn(30, 5, binary_string, bp))) return 0; /* D/L */ + break; + case 'B': + if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* U/L */ + current_mode = 'U'; + if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* B/S */ + break; + } + } else if (current_mode == 'D') { + switch (reduced_encode_mode[i]) { + case 'U': + if (!(bp = az_bin_append_posn(14, 4, binary_string, bp))) return 0; /* U/L */ + break; + case 'u': + if (!(bp = az_bin_append_posn(15, 4, binary_string, bp))) return 0; /* U/S */ + break; + case 'L': + if (!(bp = az_bin_append_posn(14, 4, binary_string, bp))) return 0; /* U/L */ + if (!(bp = az_bin_append_posn(28, 5, binary_string, bp))) return 0; /* L/L */ + break; + case 'M': + if (!(bp = az_bin_append_posn(14, 4, binary_string, bp))) return 0; /* U/L */ + if (!(bp = az_bin_append_posn(29, 5, binary_string, bp))) return 0; /* M/L */ + break; + case 'P': + if (!(bp = az_bin_append_posn(14, 4, binary_string, bp))) return 0; /* U/L */ + if (!(bp = az_bin_append_posn(29, 5, binary_string, bp))) return 0; /* M/L */ + if (!(bp = az_bin_append_posn(30, 5, binary_string, bp))) return 0; /* P/L */ + break; + case 'p': + if (!(bp = az_bin_append_posn(0, 4, binary_string, bp))) return 0; /* P/S */ + break; + case 'B': + if (!(bp = az_bin_append_posn(14, 4, binary_string, bp))) return 0; /* U/L */ + current_mode = 'U'; + if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* B/S */ + break; + } + } + + /* Byte mode - process full block here */ + if (reduced_encode_mode[i] == 'B') { + int big_batch = 0; + for (count = 0; ((i + count) < reduced_length) && (reduced_encode_mode[i + count] == 'B'); count++); + + if (count > 2047 + 2078) { /* Can't be more than 19968 / 8 = 2496 */ + return 0; + } + + if (count > 2047) { /* Max 11-bit number */ + big_batch = count > 2078 ? 2078 : count; + /* Put 00000 followed by 11-bit number of bytes less 31 */ + if (!(bp = az_bin_append_posn(big_batch - 31, 16, binary_string, bp))) return 0; + for (j = 0; j < big_batch; j++) { + if (!(bp = az_bin_append_posn(reduced_source[i++], 8, binary_string, bp))) return 0; + } + count -= big_batch; + } + if (count) { + if (big_batch) { + if (!(bp = az_bin_append_posn(31, 5, binary_string, bp))) return 0; /* B/S */ + } + if (count > 31) { + assert(count <= 2078); + /* Put 00000 followed by 11-bit number of bytes less 31 */ + if (!(bp = az_bin_append_posn(count - 31, 16, binary_string, bp))) return 0; + } else { + /* Put 5-bit number of bytes */ + if (!(bp = az_bin_append_posn(count, 5, binary_string, bp))) return 0; + } + for (j = 0; j < count; j++) { + if (!(bp = az_bin_append_posn(reduced_source[i++], 8, binary_string, bp))) return 0; + } + } + i--; + continue; + } + + if ((reduced_encode_mode[i] != 'u') && (reduced_encode_mode[i] != 'p')) { + current_mode = reduced_encode_mode[i]; + } + } + + if ((reduced_encode_mode[i] == 'U') || (reduced_encode_mode[i] == 'u')) { + if (reduced_source[i] == ' ') { + if (!(bp = az_bin_append_posn(1, 5, binary_string, bp))) return 0; /* SP */ + } else { + if (!(bp = az_bin_append_posn(AztecSymbolChar[reduced_source[i]], 5, binary_string, bp))) return 0; + } + } else if (reduced_encode_mode[i] == 'L') { + if (reduced_source[i] == ' ') { + if (!(bp = az_bin_append_posn(1, 5, binary_string, bp))) return 0; /* SP */ + } else { + if (!(bp = az_bin_append_posn(AztecSymbolChar[reduced_source[i]], 5, binary_string, bp))) return 0; + } + } else if (reduced_encode_mode[i] == 'M') { + if (reduced_source[i] == ' ') { + if (!(bp = az_bin_append_posn(1, 5, binary_string, bp))) return 0; /* SP */ + } else if (reduced_source[i] == 13) { + if (!(bp = az_bin_append_posn(14, 5, binary_string, bp))) return 0; /* CR */ + } else { + if (!(bp = az_bin_append_posn(AztecSymbolChar[reduced_source[i]], 5, binary_string, bp))) return 0; + } + } else if ((reduced_encode_mode[i] == 'P') || (reduced_encode_mode[i] == 'p')) { + if (gs1 && reduced_source[i] == '\x1D') { + if (!(bp = az_bin_append_posn(0, 5, binary_string, bp))) return 0; /* FLG(n) */ + if (!(bp = az_bin_append_posn(0, 3, binary_string, bp))) return 0; /* FLG(0) = FNC1 */ + } else if (reduced_source[i] == 13) { + if (!(bp = az_bin_append_posn(1, 5, binary_string, bp))) return 0; /* CR */ + } else if (reduced_source[i] == 'a') { + if (!(bp = az_bin_append_posn(2, 5, binary_string, bp))) return 0; /* CR LF */ + } else if (reduced_source[i] == 'b') { + if (!(bp = az_bin_append_posn(3, 5, binary_string, bp))) return 0; /* . SP */ + } else if (reduced_source[i] == 'c') { + if (!(bp = az_bin_append_posn(4, 5, binary_string, bp))) return 0; /* , SP */ + } else if (reduced_source[i] == 'd') { + if (!(bp = az_bin_append_posn(5, 5, binary_string, bp))) return 0; /* : SP */ + } else if (reduced_source[i] == ',') { + if (!(bp = az_bin_append_posn(17, 5, binary_string, bp))) return 0; /* Comma */ + } else if (reduced_source[i] == '.') { + if (!(bp = az_bin_append_posn(19, 5, binary_string, bp))) return 0; /* Full stop */ + } else { + if (!(bp = az_bin_append_posn(AztecSymbolChar[reduced_source[i]], 5, binary_string, bp))) return 0; + } + } else if (reduced_encode_mode[i] == 'D') { + if (reduced_source[i] == ' ') { + if (!(bp = az_bin_append_posn(1, 4, binary_string, bp))) return 0; /* SP */ + } else if (reduced_source[i] == ',') { + if (!(bp = az_bin_append_posn(12, 4, binary_string, bp))) return 0; /* Comma */ + } else if (reduced_source[i] == '.') { + if (!(bp = az_bin_append_posn(13, 4, binary_string, bp))) return 0; /* Full stop */ + } else { + if (!(bp = az_bin_append_posn(AztecSymbolChar[reduced_source[i]], 4, binary_string, bp))) return 0; + } + } + } + + if (debug_print) { + printf("Binary String (%d): %.*s\n", bp, bp, binary_string); + } + + *data_length = bp; + if (p_current_mode) { + *p_current_mode = current_mode; + } + + return 1; +} + +/* Call `aztec_text_process()` for each segment */ +static int aztec_text_process_segs(struct zint_seg segs[], const int seg_count, int bp, char binary_string[], + const int gs1, int *data_length, const int debug_print) { + int i; + + char current_mode = 'U'; + + for (i = 0; i < seg_count; i++) { + if (!aztec_text_process(segs[i].source, segs[i].length, bp, binary_string, gs1, segs[i].eci, ¤t_mode, + &bp, debug_print)) { + return 0; + } + } + + *data_length = bp; + + return 1; +} + +/* Prevent data from obscuring reference grid */ +static int az_avoidReferenceGrid(int output) { + + if (output > 10) { + output += (output - 11) / 15 + 1; + } + + return output; +} + +/* Calculate the position of the bits in the grid (non-compact) */ +static void az_populate_map(short AztecMap[], const int layers) { + int layer; + int x, y; + const int offset = AztecOffset[layers - 1]; + const int endoffset = 151 - offset; + + for (layer = 0; layer < layers; layer++) { + const int start = (112 * layer) + (16 * layer * layer) + 2; + const int length = 28 + (layer * 4) + (layer + 1) * 4; + int av0, av1; + int n = start, end; + /* Top */ + x = 64 - (layer * 2); + y = 63 - (layer * 2); + av0 = az_avoidReferenceGrid(y) * 151; + av1 = az_avoidReferenceGrid(y - 1) * 151; + end = start + length; + while (n < end) { + const int avxi = az_avoidReferenceGrid(x++); + AztecMap[av0 + avxi] = n++; + AztecMap[av1 + avxi] = n++; + } + /* Right */ + x = 78 + (layer * 2); + y = 64 - (layer * 2); + av0 = az_avoidReferenceGrid(x); + av1 = az_avoidReferenceGrid(x + 1); + end += length; + while (n < end) { + const int avyi = az_avoidReferenceGrid(y++) * 151; + AztecMap[avyi + av0] = n++; + AztecMap[avyi + av1] = n++; + } + /* Bottom */ + x = 77 + (layer * 2); + y = 78 + (layer * 2); + av0 = az_avoidReferenceGrid(y) * 151; + av1 = az_avoidReferenceGrid(y + 1) * 151; + end += length; + while (n < end) { + const int avxi = az_avoidReferenceGrid(x--); + AztecMap[av0 + avxi] = n++; + AztecMap[av1 + avxi] = n++; + } + /* Left */ + x = 63 - (layer * 2); + y = 77 + (layer * 2); + av0 = az_avoidReferenceGrid(x); + av1 = az_avoidReferenceGrid(x - 1); + end += length; + while (n < end) { + const int avyi = az_avoidReferenceGrid(y--) * 151; + AztecMap[avyi + av0] = n++; + AztecMap[avyi + av1] = n++; + } + } + + /* Copy "Core Symbol" (finder, descriptor, orientation) */ + for (y = 0; y < 15; y++) { + memcpy(AztecMap + (y + 68) * 151 + 68, AztecMapCore[y], sizeof(short) * 15); + } + + /* Reference grid guide bars */ + for (y = offset <= 11 ? 11 : AztecMapGridYOffsets[(offset - 11) / 16]; y < endoffset; y += 16) { + for (x = offset; x < endoffset; x++) { + AztecMap[(x * 151) + y] = x & 1; + AztecMap[(y * 151) + x] = x & 1; + } + } +} + +/* Helper to insert dummy '0' or '1's into runs of same bits. See ISO/IEC 24778:2008 7.3.1.2 */ +static int az_bitrun_stuff(const char *binary_string, const int data_length, const int codeword_size, + const int data_maxsize, char adjusted_string[AZTEC_MAX_CAPACITY]) { + int i, j = 0, count = 0; + + for (i = 0; i < data_length; i++) { + + if ((j + 1) % codeword_size == 0) { + /* Last bit of codeword */ + /* 7.3.1.2 "whenever the first B-1 bits ... are all “0”s, then a dummy “1” is inserted..." + "Similarly a message codeword that starts with B-1 “1”s has a dummy “0” inserted..." */ + + if (count == 0 || count == (codeword_size - 1)) { + /* Codeword of B-1 '0's or B-1 '1's */ + if (j > data_maxsize) { + return 0; /* Fail */ + } + adjusted_string[j++] = count == 0 ? '1' : '0'; + count = binary_string[i] == '1' ? 1 : 0; + } else { + count = 0; + } + + } else if (binary_string[i] == '1') { /* Skip B so only counting B-1 */ + count++; + } + if (j > data_maxsize) { + return 0; /* Fail */ + } + adjusted_string[j++] = binary_string[i]; + } + + return j; +} + +/* Helper to add padding, accounting for bitrun stuffing */ +static int az_add_padding(const int padbits, const int codeword_size, char adjusted_string[AZTEC_MAX_CAPACITY], + int adjusted_length) { + int i, count = 0; + + for (i = 0; i < padbits; i++) { + adjusted_string[adjusted_length++] = '1'; + } + + for (i = (adjusted_length - codeword_size); i < adjusted_length; i++) { + count += adjusted_string[i] == '1'; + } + if (count == codeword_size) { + adjusted_string[adjusted_length - 1] = '0'; + } + + return adjusted_length; +} + +/* Determine codeword bitlength - Table 3 */ +static int az_codeword_size(const int layers) { + int codeword_size; + + if (layers <= 2) { + codeword_size = 6; + } else if (layers <= 8) { + codeword_size = 8; + } else if (layers <= 22) { + codeword_size = 10; + } else { + codeword_size = 12; + } + return codeword_size; +} + +INTERNAL int aztec(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) { + int x, y, i, p, data_blocks, ecc_blocks, layers, total_bits; + char bit_pattern[AZTEC_MAP_POSN_MAX + 1]; /* Note AZTEC_MAP_POSN_MAX > AZTEC_BIN_CAPACITY */ + /* To lessen stack usage, share binary_string buffer with bit_pattern, as accessed separately */ + char *binary_string = bit_pattern; + char descriptor[42]; + char adjusted_string[AZTEC_MAX_CAPACITY]; + short AztecMap[AZTEC_MAP_SIZE]; + unsigned char desc_data[4], desc_ecc[6]; + int error_number = 0; + int compact, data_length, data_maxsize, codeword_size, adjusted_length; + int remainder, padbits, adjustment_size; + int bp = 0; + const int gs1 = (symbol->input_mode & 0x07) == GS1_MODE; + const int reader_init = symbol->output_options & READER_INIT; + const int compact_loop_start = reader_init ? 1 : 4; /* Compact 2-4 excluded from Reader Initialisation */ + const int debug_print = symbol->debug & ZINT_DEBUG_PRINT; + rs_t rs; + rs_uint_t rs_uint; + unsigned int *data_part; + unsigned int *ecc_part; + + if (gs1 && reader_init) { + return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 501, "Cannot use Reader Initialisation in GS1 mode"); + } + + if (symbol->structapp.count) { + /* Structured Append info as string <SP> + ID + <SP> + index + count + NUL */ + unsigned char sa_src[1 + sizeof(symbol->structapp.id) + 1 + 1 + 1 + 1] = {0}; + int sa_len; + int id_len; + + if (symbol->structapp.count < 2 || symbol->structapp.count > 26) { + return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 701, + "Structured Append count '%d' out of range (2 to 26)", symbol->structapp.count); + } + if (symbol->structapp.index < 1 || symbol->structapp.index > symbol->structapp.count) { + return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 702, + "Structured Append index '%1$d' out of range (1 to count %2$d)", + symbol->structapp.index, symbol->structapp.count); + } + + for (id_len = 0; id_len < 32 && symbol->structapp.id[id_len]; id_len++); + + if (id_len && chr_cnt((const unsigned char *) symbol->structapp.id, id_len, ' ')) { + /* Note ID can contain any old chars apart from space so don't print in error message */ + return errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 703, "Structured Append ID cannot contain spaces"); + } + + bp = bin_append_posn(29, 5, binary_string, bp); /* M/L */ + bp = bin_append_posn(29, 5, binary_string, bp); /* U/L */ + + sa_len = 0; + if (id_len) { /* ID has a space on either side */ + sa_src[sa_len++] = ' '; + memcpy(sa_src + sa_len, symbol->structapp.id, id_len); + sa_len += id_len; + sa_src[sa_len++] = ' '; + } + sa_src[sa_len++] = 'A' + symbol->structapp.index - 1; + sa_src[sa_len++] = 'A' + symbol->structapp.count - 1; + if (debug_print) { + printf("Structured Append Count: %d, Index: %d, ID: %.32s, String: %s\n", + symbol->structapp.count, symbol->structapp.index, symbol->structapp.id, sa_src); + } + + (void) aztec_text_process(sa_src, sa_len, bp, binary_string, 0 /*gs1*/, 0 /*eci*/, NULL /*p_current_mode*/, + &bp, debug_print); + /* Will be in U/L due to uppercase A-Z index/count indicators at end */ + } + + if (!aztec_text_process_segs(segs, seg_count, bp, binary_string, gs1, &data_length, debug_print)) { + return errtxt(ZINT_ERROR_TOO_LONG, symbol, 502, + "Input too long, requires too many codewords (maximum " AZ_BIN_CAP_CWDS_S ")"); + } + assert(data_length > 0); /* Suppress clang-tidy warning: clang-analyzer-core.UndefinedBinaryOperatorResult */ + + if (symbol->option_1 < -1 || symbol->option_1 > 4) { + errtxtf(0, symbol, 503, "Error correction level '%d' out of range (1 to 4)", symbol->option_1); + if (symbol->warn_level == WARN_FAIL_ALL) { + return ZINT_ERROR_INVALID_OPTION; + } + error_number = errtxt_adj(ZINT_WARN_INVALID_OPTION, symbol, "%1$s%2$s", ", ignoring"); + symbol->option_1 = -1; + } + + data_maxsize = 0; /* Keep compiler happy! */ + adjustment_size = 0; + if (symbol->option_2 == 0) { /* The size of the symbol can be determined by Zint */ + int ecc_level = symbol->option_1; + + if (ecc_level <= 0) { + ecc_level = 2; + } + + do { + /* Decide what size symbol to use - the smallest that fits the data */ + compact = 0; /* 1 = Aztec Compact, 0 = Normal Aztec */ + layers = 0; + + /* For each level of error correction work out the smallest symbol which the data will fit in */ + for (i = compact_loop_start; i > 0; i--) { + if ((data_length + adjustment_size) <= AztecCompactDataSizes[ecc_level - 1][i - 1]) { + layers = i; + compact = 1; + data_maxsize = AztecCompactDataSizes[ecc_level - 1][i - 1]; + } + } + if (!compact) { + for (i = 32; i > 0; i--) { + if ((data_length + adjustment_size) <= AztecDataSizes[ecc_level - 1][i - 1]) { + layers = i; + compact = 0; + data_maxsize = AztecDataSizes[ecc_level - 1][i - 1]; + } + } + } + + if (layers == 0) { /* Couldn't find a symbol which fits the data */ + if (adjustment_size == 0) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 707, + "Input too long for ECC level %1$d, requires too many codewords (maximum %2$d)", + ecc_level, AztecDataSizes[ecc_level - 1][31] / 12); + } + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 504, + "Input too long for ECC level %1$d, requires %2$d codewords (maximum %3$d)", + ecc_level, (data_length + adjustment_size + 11) / 12, + AztecDataSizes[ecc_level - 1][31] / 12); + } + + codeword_size = az_codeword_size(layers); + + adjusted_length = az_bitrun_stuff(binary_string, data_length, codeword_size, + adjustment_size ? data_maxsize : AZTEC_BIN_CAPACITY, adjusted_string); + if (adjusted_length == 0) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 705, + "Input too long for ECC level %1$d, requires too many codewords (maximum %2$d)", + ecc_level, (adjustment_size ? data_maxsize : AZTEC_BIN_CAPACITY) / codeword_size); + } + adjustment_size = adjusted_length - data_length; + + /* Add padding */ + remainder = adjusted_length % codeword_size; + + padbits = codeword_size - remainder; + if (padbits == codeword_size) { + padbits = 0; + } + if (debug_print) printf("Remainder: %d Pad bits: %d\n", remainder, padbits); + + assert(adjusted_length <= AZTEC_BIN_CAPACITY); + + adjusted_length = az_add_padding(padbits, codeword_size, adjusted_string, adjusted_length); + + if (debug_print) printf("Adjusted Length: %d, Data Max Size %d\n", adjusted_length, data_maxsize); + + } 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 ((symbol->option_2 < 0) || (symbol->option_2 > 36)) { + return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 510, "Version '%d' out of range (1 to 36)", + symbol->option_2); + } + if (reader_init) { + /* For back-compatibility, silently ignore compact 2-4 requests but error on layers > 22 */ + if (symbol->option_2 >= 2 && symbol->option_2 <= 4) { + symbol->option_2 = 5; + } else if (symbol->option_2 > 26) { + /* Caught below anyway but catch here also for better feedback */ + return errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 709, + "Version '%d' out of range for Reader Initialisation symbols (maximum 26)", + symbol->option_2); + } + } + if (symbol->option_2 <= 4) { + compact = 1; + layers = symbol->option_2; + } else { + compact = 0; + layers = symbol->option_2 - 4; + } + + codeword_size = az_codeword_size(layers); + if (compact) { + data_maxsize = codeword_size * (AztecCompactSizes[layers - 1] - 3); + } else { + data_maxsize = codeword_size * (AztecSizes[layers - 1] - 3); + } + + adjusted_length = az_bitrun_stuff(binary_string, data_length, codeword_size, data_maxsize, adjusted_string); + if (adjusted_length == 0) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 704, + "Input too long for Version %1$d, requires too many codewords (maximum %2$d)", + symbol->option_2, data_maxsize / codeword_size); + } + + /* Add padding */ + remainder = adjusted_length % codeword_size; + + padbits = codeword_size - remainder; + if (padbits == codeword_size) { + padbits = 0; + } + if (debug_print) printf("Remainder: %d Pad bits: %d\n", remainder, padbits); + + /* Check if the data actually fits into the selected symbol size */ + + if (adjusted_length + padbits > data_maxsize) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 505, + "Input too long for Version %1$d, requires %2$d codewords (maximum %3$d)", + symbol->option_2, (adjusted_length + padbits) / codeword_size, + data_maxsize / codeword_size); + } + + adjusted_length = az_add_padding(padbits, codeword_size, adjusted_string, adjusted_length); + + if (debug_print) printf("Adjusted Length: %d\n", adjusted_length); + } + + if (debug_print) { + printf("Codewords (%d):\n", adjusted_length / codeword_size); + for (i = 0; i < (adjusted_length / codeword_size); i++) { + printf(" %.*s", codeword_size, adjusted_string + i * codeword_size); + } + fputc('\n', stdout); + } + + if (reader_init && (layers > 22)) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 506, + "Input too long for Reader Initialisation, requires %d layers (maximum 22)", layers); + } + + data_blocks = adjusted_length / codeword_size; + + if (compact) { + ecc_blocks = AztecCompactSizes[layers - 1] - data_blocks; + if (layers == 4) { /* Can use spare blocks for ECC (76 available - 64 max data blocks) */ + ecc_blocks += 12; + } + } else { + ecc_blocks = AztecSizes[layers - 1] - data_blocks; + } + if (ecc_blocks < data_blocks / 20) { + error_number = errtxtf(ZINT_WARN_NONCOMPLIANT, symbol, 708, + "Number of ECC codewords %1$d less than %2$d (5%% of data codewords %3$d)", + ecc_blocks, data_blocks / 20, data_blocks); + } + + if (debug_print) { + printf("Generating a %s symbol with %d layers\n", compact ? "compact" : "full-size", layers); + printf("Requires %d codewords of %d-bits\n", data_blocks + ecc_blocks, codeword_size); + printf(" (%d data words, %d ecc words)\n", data_blocks, ecc_blocks); + } + + data_part = (unsigned int *) z_alloca(sizeof(unsigned int) * data_blocks); + ecc_part = (unsigned int *) z_alloca(sizeof(unsigned int) * ecc_blocks); + + /* Copy across data into separate integers */ + memset(data_part, 0, sizeof(unsigned int) * data_blocks); + memset(ecc_part, 0, sizeof(unsigned int) * ecc_blocks); + + /* Split into codewords and calculate reed-solomon error correction codes */ + for (i = 0; i < data_blocks; i++) { + for (p = 0; p < codeword_size; p++) { + if (adjusted_string[i * codeword_size + p] == '1') { + data_part[i] |= 0x01 << (codeword_size - (p + 1)); + } + } + } + + switch (codeword_size) { + case 6: + rs_init_gf(&rs, 0x43); + rs_init_code(&rs, ecc_blocks, 1); + rs_encode_uint(&rs, data_blocks, data_part, ecc_part); + break; + case 8: + rs_init_gf(&rs, 0x12d); + rs_init_code(&rs, ecc_blocks, 1); + rs_encode_uint(&rs, data_blocks, data_part, ecc_part); + break; + case 10: + if (!rs_uint_init_gf(&rs_uint, 0x409, 1023)) { /* Can fail on malloc() */ + return errtxt(ZINT_ERROR_MEMORY, symbol, 500, "Insufficient memory for Reed-Solomon log tables"); + } + rs_uint_init_code(&rs_uint, ecc_blocks, 1); + rs_uint_encode(&rs_uint, data_blocks, data_part, ecc_part); + rs_uint_free(&rs_uint); + break; + case 12: + if (!rs_uint_init_gf(&rs_uint, 0x1069, 4095)) { /* Can fail on malloc() */ + /* Note using AUSPOST error nos range as out of 50x ones & 51x taken by CODEONE */ + return errtxt(ZINT_ERROR_MEMORY, symbol, 700, "Insufficient memory for Reed-Solomon log tables"); + } + rs_uint_init_code(&rs_uint, ecc_blocks, 1); + rs_uint_encode(&rs_uint, data_blocks, data_part, ecc_part); + rs_uint_free(&rs_uint); + break; + } + + for (i = 0; i < ecc_blocks; i++) { + adjusted_length = bin_append_posn(ecc_part[i], codeword_size, adjusted_string, adjusted_length); + } + + /* Invert the data so that actual data is on the outside and reed-solomon on the inside */ + memset(bit_pattern, '0', AZTEC_MAP_POSN_MAX + 1); + + 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 */ + descriptor[0] = ((layers - 1) & 0x02) ? '1' : '0'; + descriptor[1] = ((layers - 1) & 0x01) ? '1' : '0'; + + /* The next 6 bits represent the number of data blocks minus 1 */ + descriptor[2] = reader_init || ((data_blocks - 1) & 0x20) ? '1' : '0'; + for (i = 3; i < 8; i++) { + descriptor[i] = ((data_blocks - 1) & (0x10 >> (i - 3))) ? '1' : '0'; + } + if (debug_print) printf("Mode Message = %.8s\n", descriptor); + } else { + /* The first 5 bits represent the number of layers minus 1 */ + for (i = 0; i < 5; i++) { + descriptor[i] = ((layers - 1) & (0x10 >> i)) ? '1' : '0'; + } + + /* The next 11 bits represent the number of data blocks minus 1 */ + descriptor[5] = reader_init || ((data_blocks - 1) & 0x400) ? '1' : '0'; + for (i = 6; i < 16; i++) { + descriptor[i] = ((data_blocks - 1) & (0x200 >> (i - 6))) ? '1' : '0'; + } + if (debug_print) printf("Mode Message = %.16s\n", descriptor); + } + + /* Split into 4-bit codewords */ + for (i = 0; i < 4; i++) { + desc_data[i] = ((descriptor[i * 4] == '1') << 3) | ((descriptor[(i * 4) + 1] == '1') << 2) + | ((descriptor[(i * 4) + 2] == '1') << 1) | (descriptor[(i * 4) + 3] == '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(&rs, 0x13); + if (compact) { + rs_init_code(&rs, 5, 1); + rs_encode(&rs, 2, desc_data, desc_ecc); + for (i = 0; i < 5; i++) { + descriptor[(i * 4) + 8] = (desc_ecc[i] & 0x08) ? '1' : '0'; + descriptor[(i * 4) + 9] = (desc_ecc[i] & 0x04) ? '1' : '0'; + descriptor[(i * 4) + 10] = (desc_ecc[i] & 0x02) ? '1' : '0'; + descriptor[(i * 4) + 11] = (desc_ecc[i] & 0x01) ? '1' : '0'; + } + } else { + rs_init_code(&rs, 6, 1); + rs_encode(&rs, 4, desc_data, desc_ecc); + for (i = 0; i < 6; i++) { + descriptor[(i * 4) + 16] = (desc_ecc[i] & 0x08) ? '1' : '0'; + descriptor[(i * 4) + 17] = (desc_ecc[i] & 0x04) ? '1' : '0'; + descriptor[(i * 4) + 18] = (desc_ecc[i] & 0x02) ? '1' : '0'; + descriptor[(i * 4) + 19] = (desc_ecc[i] & 0x01) ? '1' : '0'; + } + } + + /* Merge descriptor with the rest of the symbol */ + if (compact) { + memcpy(bit_pattern + 2000 - 2, descriptor, 40); + } else { + memcpy(bit_pattern + 20000 - 2, descriptor, 40); + } + + /* Plot all of the data into the symbol in pre-defined spiral pattern */ + if (compact) { + const int offset = AztecCompactOffset[layers - 1]; + const int end_offset = 27 - offset; + for (y = offset; y < end_offset; y++) { + const int y_map = y * 27; + for (x = offset; x < end_offset; x++) { + const int map = AztecCompactMap[y_map + x]; + if (map == 1 || (map >= 2 && bit_pattern[map - 2] == '1')) { + set_module(symbol, y - offset, x - offset); + } + } + symbol->row_height[y - offset] = 1; + } + symbol->height = 27 - (2 * offset); + symbol->rows = 27 - (2 * offset); + symbol->width = 27 - (2 * offset); + } else { + const int offset = AztecOffset[layers - 1]; + const int end_offset = 151 - offset; + az_populate_map(AztecMap, layers); + for (y = offset; y < end_offset; y++) { + const int y_map = y * 151; + for (x = offset; x < end_offset; x++) { + const int map = AztecMap[y_map + x]; + if (map == 1 || (map >= 2 && bit_pattern[map - 2] == '1')) { + set_module(symbol, y - offset, x - offset); + } + } + symbol->row_height[y - offset] = 1; + } + symbol->height = 151 - (2 * offset); + symbol->rows = 151 - (2 * offset); + symbol->width = 151 - (2 * offset); + } + + return error_number; +} + +/* Encodes Aztec runes as specified in ISO/IEC 24778:2008 Annex A */ +INTERNAL int azrune(struct zint_symbol *symbol, unsigned char source[], int length) { + unsigned int input_value; + int i, y, x, r; + char binary_string[28]; + unsigned char data_codewords[3], ecc_codewords[6]; + int bp = 0; + const int debug_print = symbol->debug & ZINT_DEBUG_PRINT; + rs_t rs; + + input_value = 0; + if (length > 3) { + return errtxtf(ZINT_ERROR_TOO_LONG, symbol, 507, "Input length %d too long (maximum 3)", length); + } + if ((i = not_sane(NEON_F, source, length))) { + return errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 508, + "Invalid character at position %d in input (digits only)", i); + } + switch (length) { + case 3: + input_value = 100 * ctoi(source[0]) + 10 * ctoi(source[1]) + ctoi(source[2]); + break; + case 2: + input_value = 10 * ctoi(source[0]) + ctoi(source[1]); + break; + case 1: + input_value = ctoi(source[0]); + break; + } + + if (input_value > 255) { + return errtxt(ZINT_ERROR_INVALID_DATA, symbol, 509, "Input value out of range (0 to 255)"); + } + + bp = bin_append_posn(input_value, 8, binary_string, bp); + + data_codewords[0] = (unsigned char) (input_value >> 4); + data_codewords[1] = (unsigned char) (input_value & 0xF); + + rs_init_gf(&rs, 0x13); + rs_init_code(&rs, 5, 1); + rs_encode(&rs, 2, data_codewords, ecc_codewords); + + for (i = 0; i < 5; i++) { + bp = bin_append_posn(ecc_codewords[i], 4, binary_string, bp); + } + + for (i = 0; i < 28; i += 2) { + binary_string[i] = '0' + (binary_string[i] != '1'); + } + + if (debug_print) { + printf("Binary String: %.28s\n", binary_string); + } + + for (y = 8; y < 19; y++) { + r = y * 27; + for (x = 8; x < 19; x++) { + if (AztecCompactMap[r + x] == 1) { + set_module(symbol, y - 8, x - 8); + } else if (AztecCompactMap[r + x] && binary_string[AztecCompactMap[r + x] - 2000] == '1') { + set_module(symbol, y - 8, x - 8); + } + } + symbol->row_height[y - 8] = 1; + } + symbol->height = 11; + symbol->rows = 11; + symbol->width = 11; + + return 0; +} + +/* vim: set ts=4 sw=4 et : */
