#include <assert.h>
#include <stdio.h>
#include "common.h"
#include "general_field.h"
#include "gs1.h"
#include "rss.h"
static int dbar_combins(const int n, const int r) {
int i;
int maxDenom, minDenom;
int val = 1, j = 1;
if (n - r > r) {
minDenom = r;
maxDenom = n - r;
} else {
minDenom = n - r;
maxDenom = r;
}
for (i = n; i > maxDenom; i--) {
val *= i;
if (j <= minDenom) {
val /= j;
j++;
}
}
for (; j <= minDenom; j++) {
val /= j;
}
return val;
}
static void dbar_getWidths(int widths[], int val, int n, const int elements, const int maxWidth, const int noNarrow) {
int bar;
int elmWidth;
int mxwElement;
int subVal, lessVal;
int narrowMask = 0;
for (bar = 0; bar < elements - 1; bar++) {
for (elmWidth = 1, narrowMask |= (1 << bar); ; elmWidth++, narrowMask &= ~(1 << bar)) {
subVal = dbar_combins(n - elmWidth - 1, elements - bar - 2);
if (noNarrow && !narrowMask && n - elmWidth - (elements - bar - 1) >= elements - bar - 1) {
subVal -= dbar_combins(n - elmWidth - (elements - bar), elements - bar - 2);
}
if (elements - bar - 1 > 1) {
lessVal = 0;
for (mxwElement = n - elmWidth - (elements - bar - 2); mxwElement > maxWidth; mxwElement--) {
lessVal += dbar_combins(n - elmWidth - mxwElement - 1, elements - bar - 3);
}
subVal -= lessVal * (elements - 1 - bar);
} else if (n - elmWidth > maxWidth) {
subVal--;
}
val -= subVal;
if (val < 0) break;
}
val += subVal;
n -= elmWidth;
widths[bar] = elmWidth;
}
widths[bar] = n;
}
static void dbar_widths(int *ret_widths, int v_odd, int v_even, int n_odd, int n_even, const int elements,
const int maxWidth, const int noNarrow) {
int widths[2][7];
int i;
assert(elements <= 7);
dbar_getWidths(widths[0], v_odd, n_odd, elements, maxWidth, noNarrow);
dbar_getWidths(widths[1], v_even, n_even, elements, 9 - maxWidth, !noNarrow);
for (i = 0; i < elements; i++) {
ret_widths[i << 1] = widths[0][i];
ret_widths[(i << 1) + 1] = widths[1][i];
}
}
static uint64_t dbar_to_uint64(const unsigned char source[], const int length) {
uint64_t val = 0;
int i;
for (i = 0; i < length; i++) {
val *= 10;
val += source[i] - '0';
}
return val;
}
static unsigned char *dbar_gtin14(const unsigned char *source, const int length, unsigned char buf[14]) {
const int zeroes = 13 - length;
assert(zeroes >= 0);
memset(buf, '0', zeroes);
memcpy(buf + zeroes, source, length);
buf[zeroes + length] = zint_gs1_check_digit(buf, 13);
return buf;
}
static void dbar_set_gtin14_hrt(struct zint_symbol *symbol, const unsigned char *source, const int length) {
unsigned char buf[14];
z_hrt_cpy_nochk(symbol, ZCUCP("(01)"), 4);
z_hrt_cat_nochk(symbol, dbar_gtin14(source, length, buf), 14);
}
static int dbar_expand(struct zint_symbol *symbol, int writer, int latch, const int *const widths, const int start,
const int end) {
int i, j;
for (i = start; i < end; i++) {
const int width = widths[i];
if (latch) {
for (j = 0; j < width; j++) {
z_set_module(symbol, symbol->rows, writer);
writer++;
}
} else {
for (j = 0; j < width; j++) {
z_unset_module(symbol, symbol->rows, writer);
writer++;
}
}
latch = !latch;
}
return writer;
}
static void dbar_omn_finder_adjust(struct zint_symbol *symbol, const int separator_row, const int above_below,
const int finder_start) {
int i, finder_end;
int module_row = separator_row + above_below;
int latch;
latch = 1;
for (i = finder_start, finder_end = finder_start + 13; i < finder_end; i++) {
if (!z_module_is_set(symbol, module_row, i)) {
if (latch) {
z_set_module(symbol, separator_row, i);
latch = 0;
} else {
z_unset_module(symbol, separator_row, i);
latch = 1;
}
} else {
z_unset_module(symbol, separator_row, i);
latch = 1;
}
}
}
static void dbar_omn_separator(struct zint_symbol *symbol, int width, const int separator_row, const int above_below,
const int finder_start, const int finder2_start, const int bottom_finder_value_3) {
int i, finder_end, finder_value_3_set;
int module_row = separator_row + above_below;
for (i = 4, width -= 4; i < width; i++) {
if (!z_module_is_set(symbol, module_row, i)) {
z_set_module(symbol, separator_row, i);
}
}
if (bottom_finder_value_3) {
finder_value_3_set = finder_start + 10;
for (i = finder_start, finder_end = finder_start + 13; i < finder_end; i++) {
if (i == finder_value_3_set) {
z_set_module(symbol, separator_row, i);
} else {
z_unset_module(symbol, separator_row, i);
}
}
} else {
if (finder_start) {
dbar_omn_finder_adjust(symbol, separator_row, above_below, finder_start);
}
if (finder2_start) {
dbar_omn_finder_adjust(symbol, separator_row, above_below, finder2_start);
}
}
}
INTERNAL int zint_dbar_omnstk_set_height(struct zint_symbol *symbol, const int first_row) {
float fixed_height = 0.0f;
const int second_row = first_row + 2;
int i;
assert(first_row >= 0);
for (i = 0; i < symbol->rows; i++) {
if (i != first_row && i != second_row) {
fixed_height += symbol->row_height[i];
}
}
if (symbol->height) {
symbol->row_height[first_row] = z_stripf((symbol->height - fixed_height) * symbol->row_height[first_row] /
(symbol->row_height[first_row] + symbol->row_height[second_row]));
if (symbol->row_height[first_row] < 0.5f) {
symbol->row_height[first_row] = 0.5f;
symbol->row_height[second_row] = 0.7f;
} else {
symbol->row_height[second_row] = z_stripf(symbol->height - fixed_height - symbol->row_height[first_row]);
if (symbol->row_height[second_row] < 0.7f) {
symbol->row_height[second_row] = 0.7f;
}
}
}
symbol->height = z_stripf(z_stripf(symbol->row_height[first_row] + symbol->row_height[second_row])
+ fixed_height);
if (symbol->output_options & COMPLIANT_HEIGHT) {
if (symbol->row_height[first_row] < 5.0f || symbol->row_height[second_row] < 7.0f) {
return z_errtxt(ZINT_WARN_NONCOMPLIANT, symbol, 379, "Height not compliant with standards");
}
}
return 0;
}
static int dbar_omn_group(const int val, const int outside) {
const int end = 8 >> outside;
int i;
for (i = outside ? 0 : 5; i < end; i++) {
if (val < dbar_omn_g_sum[i + 1]) {
return i;
}
}
return i;
}
INTERNAL int zint_dbar_omn_cc(struct zint_symbol *symbol, unsigned char source[], int length, const int cc_rows) {
int error_number = 0, i, j;
uint64_t val;
int left_pair, right_pair;
int data_character[4];
int data_widths[4][8], checksum, c_left, c_right, total_widths[46], writer;
int separator_row = 0;
const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS;
if ((length == 17 || length == 18) && (memcmp(source, "[01]", 4) == 0 || memcmp(source, "(01)", 4) == 0)) {
source += 4;
length -= 4;
} else if ((length == 15 || length == 16) && source[0] == '0' && source[1] == '1') {
source += 2;
length -= 2;
}
if (length > 14) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 380, "Input length %d too long (maximum 14)", length);
}
if ((i = z_not_sane(NEON_F, source, length))) {
return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 381,
"Invalid character at position %d in input (digits only)", i);
}
if (length == 14) {
if (zint_gs1_check_digit(source, 13) != source[13]) {
return ZEXT z_errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 388,
"Invalid check digit '%1$c', expecting '%2$c'",
source[13], zint_gs1_check_digit(source, 13));
}
length--;
}
if (symbol->symbology != BARCODE_DBAR_OMN) {
symbol->rows = 0;
}
switch (symbol->symbology) {
case BARCODE_DBAR_OMN_CC:
case BARCODE_DBAR_STK_CC:
case BARCODE_DBAR_OMNSTK_CC:
separator_row = symbol->rows++;
symbol->row_height[separator_row] = 1;
break;
}
val = dbar_to_uint64(source, length);
if (cc_rows) {
val += 10000000000000;
}
left_pair = (int) (val / 4537077);
right_pair = (int) (val % 4537077);
data_character[0] = left_pair / 1597;
data_character[1] = left_pair % 1597;
data_character[2] = right_pair / 1597;
data_character[3] = right_pair % 1597;
for (i = 0; i < 4; i++) {
const int group = dbar_omn_group(data_character[i], !(i & 1) );
const int v = data_character[i] - dbar_omn_g_sum[group];
const int v_div = v / dbar_omn_t_even_odd[group];
const int v_mod = v % dbar_omn_t_even_odd[group];
dbar_widths(data_widths[i], !(i & 1) ? v_div : v_mod, i & 1 ? v_div : v_mod, dbar_omn_modules[group],
dbar_omn_modules[group + 9], 4 , dbar_omn_widest[group], i & 1 );
}
checksum = 0;
for (i = 0; i < 4; i++) {
for (j = 0; j < 8; j++) {
checksum += dbar_omn_checksum_weight[i][j] * data_widths[i][j];
}
}
checksum %= 79;
if (checksum >= 8) {
checksum++;
}
if (checksum >= 72) {
checksum++;
}
c_left = checksum / 9;
c_right = checksum % 9;
if (symbol->debug & ZINT_DEBUG_PRINT) {
printf("checksum %d, c_left: %d, c_right: %d\n", checksum, c_left, c_right);
}
total_widths[0] = 1;
total_widths[1] = 1;
total_widths[44] = 1;
total_widths[45] = 1;
for (i = 0; i < 8; i++) {
total_widths[i + 2] = data_widths[0][i];
total_widths[i + 15] = data_widths[1][7 - i];
total_widths[i + 23] = data_widths[3][i];
total_widths[i + 36] = data_widths[2][7 - i];
}
for (i = 0; i < 5; i++) {
total_widths[i + 10] = dbar_omn_finder_pattern[c_left][i];
total_widths[i + 31] = dbar_omn_finder_pattern[c_right][4 - i];
}
if (symbol->symbology == BARCODE_DBAR_OMN || symbol->symbology == BARCODE_DBAR_OMN_CC) {
writer = dbar_expand(symbol, 0 , 0 , total_widths, 0 , 46 );
if (symbol->width < writer) {
symbol->width = writer;
}
if (symbol->symbology == BARCODE_DBAR_OMN_CC) {
dbar_omn_separator(symbol, 96, separator_row, 1 , 18, 63, 0 );
}
symbol->rows++;
dbar_set_gtin14_hrt(symbol, source, length);
if (symbol->output_options & COMPLIANT_HEIGHT) {
if (symbol->symbology == BARCODE_DBAR_OMN_CC) {
symbol->height = symbol->height ? 13.0f : 33.0f;
} else {
error_number = z_set_height(symbol, 13.0f, 33.0f, 0.0f, 0 );
}
} else {
if (symbol->symbology == BARCODE_DBAR_OMN_CC) {
symbol->height = 14.0f;
} else {
(void) z_set_height(symbol, 0.0f, 50.0f, 0.0f, 1 );
}
}
} else if (symbol->symbology == BARCODE_DBAR_STK || symbol->symbology == BARCODE_DBAR_STK_CC) {
writer = dbar_expand(symbol, 0 , 0 , total_widths, 0 , 23 );
z_set_module(symbol, symbol->rows, writer);
z_unset_module(symbol, symbol->rows, writer + 1);
symbol->row_height[symbol->rows] = 5.0f;
symbol->rows += 2;
z_set_module(symbol, symbol->rows, 0);
z_unset_module(symbol, symbol->rows, 1);
(void) dbar_expand(symbol, 2 , 1 , total_widths, 23 , 46 );
symbol->row_height[symbol->rows] = 7.0f;
for (i = 1; i < 46; i++) {
if (z_module_is_set(symbol, symbol->rows - 2, i) == z_module_is_set(symbol, symbol->rows, i)) {
if (!(z_module_is_set(symbol, symbol->rows - 2, i))) {
z_set_module(symbol, symbol->rows - 1, i);
}
} else {
if (!(z_module_is_set(symbol, symbol->rows - 1, i - 1))) {
z_set_module(symbol, symbol->rows - 1, i);
}
}
}
z_unset_module(symbol, symbol->rows - 1, 1);
z_unset_module(symbol, symbol->rows - 1, 2);
z_unset_module(symbol, symbol->rows - 1, 3);
symbol->row_height[symbol->rows - 1] = 1;
if (symbol->symbology == BARCODE_DBAR_STK_CC) {
dbar_omn_separator(symbol, 50, separator_row, 1 , 18, 0, 0 );
}
symbol->rows++;
if (symbol->width < 50) {
symbol->width = 50;
}
if (symbol->symbology != BARCODE_DBAR_STK_CC) {
error_number = zint_dbar_omnstk_set_height(symbol, 0 );
}
} else if (symbol->symbology == BARCODE_DBAR_OMNSTK || symbol->symbology == BARCODE_DBAR_OMNSTK_CC) {
writer = dbar_expand(symbol, 0 , 0 , total_widths, 0 , 23 );
z_set_module(symbol, symbol->rows, writer);
z_unset_module(symbol, symbol->rows, writer + 1);
symbol->rows += 4;
z_set_module(symbol, symbol->rows, 0);
z_unset_module(symbol, symbol->rows, 1);
(void) dbar_expand(symbol, 2 , 1 , total_widths, 23 , 46 );
for (i = 5; i < 46; i += 2) {
z_set_module(symbol, symbol->rows - 2, i);
}
symbol->row_height[symbol->rows - 2] = 1;
dbar_omn_separator(symbol, 50, symbol->rows - 3, -1 , 18, 0, 0 );
symbol->row_height[symbol->rows - 3] = 1;
dbar_omn_separator(symbol, 50, symbol->rows - 1, 1 , 17 + 2, 0, c_right == 3);
symbol->row_height[symbol->rows - 1] = 1;
if (symbol->width < 50) {
symbol->width = 50;
}
if (symbol->symbology == BARCODE_DBAR_OMNSTK_CC) {
dbar_omn_separator(symbol, 50, separator_row, 1 , 18, 0, 0 );
}
symbol->rows++;
if (symbol->symbology == BARCODE_DBAR_OMNSTK_CC) {
symbol->height = symbol->height ? 33.0f : 66.0f;
} else {
if (symbol->output_options & COMPLIANT_HEIGHT) {
error_number = z_set_height(symbol, 33.0f, 66.0f, 0.0f, 0 );
} else {
(void) z_set_height(symbol, 0.0f, 66.0f, 0.0f, 1 );
}
}
}
if (content_segs) {
unsigned char buf[14];
if (z_ct_cpy_cat(symbol, ZCUCP("01"), 2, '\xFF' , dbar_gtin14(source, length, buf), 14)) {
return ZINT_ERROR_MEMORY;
}
}
return error_number;
}
INTERNAL int zint_dbar_omn(struct zint_symbol *symbol, unsigned char source[], int length) {
return zint_dbar_omn_cc(symbol, source, length, 0 );
}
static int dbar_ltd_group(int *p_val) {
static int g_sum[7] = {
0, 183064, 820064, 1000776, 1491021, 1979845, 1996939
};
int i;
for (i = 6; i > 0; i--) {
if (*p_val >= g_sum[i]) {
*p_val -= g_sum[i];
return i;
}
}
return 0;
}
INTERNAL int zint_dbar_ltd_cc(struct zint_symbol *symbol, unsigned char source[], int length, const int cc_rows) {
int error_number = 0, i;
uint64_t val;
int pair_vals[2];
int pair_widths[2][14];
int checksum, total_widths[47], writer;
const char *checksum_finder_pattern;
int separator_row = 0;
const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS;
if ((length == 17 || length == 18) && (memcmp(source, "[01]", 4) == 0 || memcmp(source, "(01)", 4) == 0)) {
source += 4;
length -= 4;
} else if ((length == 15 || length == 16) && source[0] == '0' && source[1] == '1') {
source += 2;
length -= 2;
}
if (length > 14) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 382, "Input length %d too long (maximum 14)", length);
}
if ((i = z_not_sane(NEON_F, source, length))) {
return z_errtxtf(ZINT_ERROR_INVALID_DATA, symbol, 383,
"Invalid character at position %d in input (digits only)", i);
}
if (length == 14) {
if (zint_gs1_check_digit(source, 13) != source[13]) {
return ZEXT z_errtxtf(ZINT_ERROR_INVALID_CHECK, symbol, 389,
"Invalid check digit '%1$c', expecting '%2$c'",
source[13], zint_gs1_check_digit(source, 13));
}
length--;
}
if (length == 13) {
if (source[0] != '0' && source[0] != '1') {
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 384, "Input value out of range (0 to 1999999999999)");
}
}
if (symbol->symbology == BARCODE_DBAR_LTD_CC) {
separator_row = symbol->rows++;
symbol->row_height[separator_row] = 1;
}
val = dbar_to_uint64(source, length);
if (cc_rows) {
val += 2015133531096;
}
pair_vals[0] = (int) (val / 2013571);
pair_vals[1] = (int) (val % 2013571);
for (i = 0; i < 2; i++) {
const int group = dbar_ltd_group(&pair_vals[i]);
const int odd = pair_vals[i] / dbar_ltd_t_even[group];
const int even = pair_vals[i] % dbar_ltd_t_even[group];
dbar_widths(pair_widths[i], odd, even, dbar_ltd_modules[group], 26 - dbar_ltd_modules[group], 7 ,
dbar_ltd_widest[group], 0 );
}
checksum = 0;
for (i = 0; i < 14; i++) {
#if defined(_MSC_VER) && _MSC_VER == 1900 && defined(_WIN64)
checksum %= 89;
#endif
checksum += dbar_ltd_checksum_weight[0][i] * pair_widths[0][i];
checksum += dbar_ltd_checksum_weight[1][i] * pair_widths[1][i];
}
checksum %= 89;
checksum_finder_pattern = dbar_ltd_finder_pattern[checksum];
total_widths[0] = 1;
total_widths[1] = 1;
total_widths[44] = 1;
total_widths[45] = 1;
total_widths[46] = 5;
for (i = 0; i < 14; i++) {
total_widths[i + 2] = pair_widths[0][i];
total_widths[i + 16] = checksum_finder_pattern[i];
total_widths[i + 30] = pair_widths[1][i];
}
writer = dbar_expand(symbol, 0 , 0 , total_widths, 0 , 47 );
if (symbol->width < writer) {
symbol->width = writer;
}
symbol->rows++;
if (symbol->symbology == BARCODE_DBAR_LTD_CC) {
for (i = 4; i < 70; i++) {
if (!z_module_is_set(symbol, separator_row + 1, i)) {
z_set_module(symbol, separator_row, i);
}
}
}
dbar_set_gtin14_hrt(symbol, source, length);
if (content_segs) {
unsigned char buf[14];
if (z_ct_cpy_cat(symbol, ZCUCP("01"), 2, '\xFF' , dbar_gtin14(source, length, buf), 14)) {
return ZINT_ERROR_MEMORY;
}
}
if (symbol->symbology == BARCODE_DBAR_LTD_CC) {
symbol->height = 10.0f;
} else {
if (symbol->output_options & COMPLIANT_HEIGHT) {
error_number = z_set_height(symbol, 10.0f, 10.0f, 0.0f, 0 );
} else {
(void) z_set_height(symbol, 0.0f, 50.0f, 0.0f, 1 );
}
}
return error_number;
}
INTERNAL int zint_dbar_ltd(struct zint_symbol *symbol, unsigned char source[], int length) {
return zint_dbar_ltd_cc(symbol, source, length, 0 );
}
INTERNAL int zint_dbar_exp_date(const unsigned char source[], const int length, const int position) {
int yy, mm, dd;
if (position + 4 + 2 > length) {
return -1;
}
yy = z_to_int(source + position, 2);
mm = z_to_int(source + position + 2, 2);
dd = z_to_int(source + position + 4, 2);
if (yy < 0 || mm <= 0 || mm > 12 || dd < 0 || dd > 31) {
return -1;
}
return yy * 384 + (mm - 1) * 32 + dd;
}
static int dbar_exp_binary_string(struct zint_symbol *symbol, const unsigned char source[], const int length,
char binary_string[], int *p_cols_per_row, const int max_rows, int *p_bp) {
int encoding_method, i, j, read_posn, mode = GF_NUMERIC;
char last_digit = '\0';
int symbol_characters, characters_per_row = *p_cols_per_row * 2;
int min_cols_per_row = 0;
char *general_field = (char *) z_alloca(length + 1);
int bp = *p_bp;
int remainder;
int cdf_bp_start;
const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
if (length > 77) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 378, "Processed input length %d too long (maximum 77)", length);
}
if (length >= 16 && source[0] == '0' && source[1] == '1') {
encoding_method = 1;
if (debug_print) fputs("Choosing Method 1\n", stdout);
} else {
encoding_method = 2;
if (debug_print) fputs("Choosing Method 2\n", stdout);
}
if (length >= 20 && encoding_method == 1 && source[2] == '9' && source[16] == '3') {
if (debug_print) fputs("Checking for other methods\n", stdout);
if (length >= 26 && source[17] == '1' && source[18] == '0') {
int weight = z_to_int(source + 20, 6);
if (weight >= 0 && weight <= 99999) {
if (length == 26) {
if (source[19] == '3' && weight <= 32767) {
encoding_method = 3;
} else {
encoding_method = 7;
}
} else if (length == 34 && source[26] == '1'
&& (source[27] == '1' || source[27] == '3' || source[27] == '5' || source[27] == '7')
&& zint_dbar_exp_date(source, length, 28) >= 0) {
encoding_method = 6 + (source[27] - '0');
}
}
} else if (length >= 26 && source[17] == '2' && source[18] == '0') {
int weight = z_to_int(source + 20, 6);
if (weight >= 0 && weight <= 99999) {
if (length == 26) {
if ((source[19] == '2' && weight <= 9999) || (source[19] == '3' && weight <= 22767)) {
encoding_method = 4;
} else {
encoding_method = 8;
}
} else if (length == 34 && source[26] == '1'
&& (source[27] == '1' || source[27] == '3' || source[27] == '5' || source[27] == '7')
&& zint_dbar_exp_date(source, length, 28) >= 0) {
encoding_method = 7 + (source[27] - '0');
}
}
} else if (source[17] == '9' && (source[19] >= '0' && source[19] <= '3')) {
if (source[18] == '2') {
encoding_method = 5;
} else if (source[18] == '3' && z_to_int(source + 20, 3) >= 0) {
encoding_method = 6;
}
}
if (debug_print && encoding_method != 1) printf("Now using method %d\n", encoding_method);
}
switch (encoding_method) {
case 1:
bp = z_bin_append_posn(4, 3, binary_string, bp);
read_posn = 16;
break;
case 2:
bp = z_bin_append_posn(0, 4, binary_string, bp);
read_posn = 0;
break;
case 3:
case 4:
bp = z_bin_append_posn(4 + (encoding_method - 3), 4, binary_string, bp);
read_posn = 26;
break;
case 5:
bp = z_bin_append_posn(0x30, 7, binary_string, bp);
read_posn = 20;
break;
case 6:
bp = z_bin_append_posn(0x34, 7, binary_string, bp);
read_posn = 23;
break;
default:
bp = z_bin_append_posn(56 + (encoding_method - 7), 7, binary_string, bp);
read_posn = length;
break;
}
if (debug_print) printf("Setting binary = %.*s\n", bp, binary_string);
for (i = 0; i < read_posn; i++) {
if (!z_isdigit(source[i]) && source[i] != '\x1D') {
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 385,
"Invalid character in Compressed Field data (digits only)");
}
}
if (debug_print) fputs("Proceeding to encode data\n", stdout);
cdf_bp_start = bp;
if (encoding_method == 1) {
bp = z_bin_append_posn(z_ctoi(source[2]), 4, binary_string, bp);
for (i = 3; i < 15; i += 3) {
bp = z_bin_append_posn(z_to_int(source + i, 3), 10, binary_string, bp);
}
} else if (encoding_method == 3 || encoding_method == 4) {
for (i = 3; i < 15; i += 3) {
bp = z_bin_append_posn(z_to_int(source + i, 3), 10, binary_string, bp);
}
if (encoding_method == 4 && source[19] == '3') {
bp = z_bin_append_posn(z_to_int(source + 20, 6) + 10000, 15, binary_string, bp);
} else {
bp = z_bin_append_posn(z_to_int(source + 20, 6), 15, binary_string, bp);
}
} else if (encoding_method == 5 || encoding_method == 6) {
for (i = 3; i < 15; i += 3) {
bp = z_bin_append_posn(z_to_int(source + i, 3), 10, binary_string, bp);
}
bp = z_bin_append_posn(source[19] - '0', 2, binary_string, bp);
if (encoding_method == 6) {
bp = z_bin_append_posn(z_to_int(source + 20, 3), 10, binary_string, bp);
}
} else if (encoding_method >= 7 && encoding_method <= 14) {
int group_val;
unsigned char weight_str[7];
for (i = 3; i < 15; i += 3) {
bp = z_bin_append_posn(z_to_int(source + i, 3), 10, binary_string, bp);
}
weight_str[0] = source[19];
for (i = 1; i < 6; i++) {
weight_str[i] = source[20 + i];
}
weight_str[6] = '\0';
bp = z_bin_append_posn(z_to_int(weight_str, 6), 20, binary_string, bp);
if (length == 34) {
group_val = zint_dbar_exp_date(source, length, 28);
} else {
group_val = 38400;
}
bp = z_bin_append_posn((int) group_val, 16, binary_string, bp);
}
if (debug_print && bp > cdf_bp_start) {
printf("Compressed data field (%d) = %.*s\n", bp - cdf_bp_start, bp - cdf_bp_start,
binary_string + cdf_bp_start);
}
j = 0;
for (i = read_posn; i < length; i++) {
general_field[j++] = source[i];
}
if (debug_print) printf("General field data (%d): %.*s\n", j, j, general_field);
if (j != 0) {
general_field[j] = '\0';
if (!zint_general_field_encode(general_field, j, &mode, &last_digit, binary_string, &bp)) {
return z_errtxt(ZINT_ERROR_INVALID_DATA, symbol, 386, "Invalid character in General Field data");
}
}
if (debug_print) printf("Resultant binary (%d): %.*s\n", bp, bp, binary_string);
remainder = 12 - (bp % 12);
if (remainder == 12) {
remainder = 0;
}
symbol_characters = ((bp + remainder) / 12) + 1;
if (max_rows) {
min_cols_per_row = ((symbol_characters + 1) / 2 + max_rows - 1) / max_rows;
if (min_cols_per_row > *p_cols_per_row) {
characters_per_row = min_cols_per_row * 2;
}
}
if (characters_per_row && (symbol_characters % characters_per_row) == 1) {
symbol_characters++;
}
if (symbol_characters < 4) {
symbol_characters = 4;
}
remainder = (12 * (symbol_characters - 1)) - bp;
if (last_digit) {
if (debug_print) fputs("Adding extra (odd) numeric digit\n", stdout);
if (remainder >= 4 && remainder <= 6) {
bp = z_bin_append_posn(z_ctoi(last_digit) + 1, 4, binary_string, bp);
} else {
bp = z_bin_append_posn(z_ctoi(last_digit) * 11 + 10 + 8, 7, binary_string, bp);
}
remainder = 12 - (bp % 12);
if (remainder == 12) {
remainder = 0;
}
symbol_characters = ((bp + remainder) / 12) + 1;
if (max_rows) {
min_cols_per_row = ((symbol_characters + 1) / 2 + max_rows - 1) / max_rows;
if (min_cols_per_row > *p_cols_per_row) {
characters_per_row = min_cols_per_row * 2;
}
}
if (characters_per_row && (symbol_characters % characters_per_row) == 1) {
symbol_characters++;
}
if (symbol_characters < 4) {
symbol_characters = 4;
}
remainder = (12 * (symbol_characters - 1)) - bp;
if (debug_print) printf(" Expanded binary (%d): %.*s\n", bp, bp, binary_string);
}
if (bp > 252) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 387,
"Input too long, requires %d symbol characters (maximum 21)", (bp + 11) / 12);
}
if (min_cols_per_row && min_cols_per_row > *p_cols_per_row) {
*p_cols_per_row = min_cols_per_row;
}
i = remainder;
if (mode == GF_NUMERIC) {
bp = z_bin_append_posn(0, 4, binary_string, bp);
i -= 4;
}
for (; i > 0; i -= 5) {
bp = z_bin_append_posn(4, 5, binary_string, bp);
}
if (encoding_method == 1 || encoding_method == 2 || encoding_method == 5 || encoding_method == 6) {
const char variable_bit1 = symbol_characters & 1 ? '1' : '0';
const char variable_bit2 = symbol_characters > 14 ? '1' : '0';
if (encoding_method == 1) {
binary_string[2] = variable_bit1;
binary_string[3] = variable_bit2;
} else if (encoding_method == 2) {
binary_string[3] = variable_bit1;
binary_string[4] = variable_bit2;
} else {
binary_string[6] = variable_bit1;
binary_string[7] = variable_bit2;
}
}
if (debug_print) {
printf(" Final binary (%d): %.*s\n Symbol chars: %d, Remainder: %d\n",
bp, bp, binary_string, symbol_characters, remainder);
}
*p_bp = bp;
return 0;
}
static void dbar_exp_separator(struct zint_symbol *symbol, int width, const int cols, const int separator_row,
const int above_below, const int special_case_row, const int left_to_right, const int odd_last_row,
int *p_v2_latch) {
int i, i_start, i_end, j, k;
int module_row = separator_row + above_below;
int v2_latch = p_v2_latch ? *p_v2_latch : 0;
int space_latch = 0;
for (j = 4 + special_case_row, width -= 4; j < width; j++) {
if (z_module_is_set(symbol, module_row, j)) {
z_unset_module(symbol, separator_row, j);
} else {
z_set_module(symbol, separator_row, j);
}
}
for (j = 0; j < cols; j++) {
k = (49 * j) + 19 + special_case_row;
if (left_to_right) {
i_start = v2_latch ? 2 : 0;
i_end = v2_latch ? 15 : 13;
for (i = i_start; i < i_end; i++) {
if (z_module_is_set(symbol, module_row, i + k)) {
z_unset_module(symbol, separator_row, i + k);
space_latch = 0;
} else {
if (space_latch) {
z_unset_module(symbol, separator_row, i + k);
} else {
z_set_module(symbol, separator_row, i + k);
}
space_latch = !space_latch;
}
}
} else {
if (odd_last_row) {
k -= 17;
}
i_start = v2_latch ? 14 : 12;
i_end = v2_latch ? 2 : 0;
for (i = i_start; i >= i_end; i--) {
if (z_module_is_set(symbol, module_row, i + k)) {
z_unset_module(symbol, separator_row, i + k);
space_latch = 0;
} else {
if (space_latch) {
z_unset_module(symbol, separator_row, i + k);
} else {
z_set_module(symbol, separator_row, i + k);
}
space_latch = !space_latch;
}
}
}
v2_latch = !v2_latch;
}
if (p_v2_latch && above_below == -1) {
*p_v2_latch = v2_latch;
}
}
static void dbar_exp_hrt(struct zint_symbol *symbol, unsigned char source[], const int length) {
if (symbol->input_mode & GS1PARENS_MODE) {
z_hrt_cpy_nochk(symbol, source, length);
} else {
z_hrt_conv_gs1_brackets_nochk(symbol, source, length);
}
}
static int dbar_exp_group(const int val) {
int i;
for (i = 0; i < ARRAY_SIZE(dbar_exp_g_sum) - 1; i++) {
if (val < dbar_exp_g_sum[i + 1]) {
return i;
}
}
return i;
}
INTERNAL int zint_dbar_exp_cc(struct zint_symbol *symbol, unsigned char source[], int length, const int cc_rows) {
int error_number, warn_number;
int i, j, p, codeblocks, data_chars, symbol_chars, group;
int char_widths[21][8], checksum, check_widths[8];
int check_char, odd, even, elements[235], pattern_width, reader, writer;
int separator_row = 0;
int bp = 0;
int cols_per_row = 0;
int max_rows = 0;
int stack_rows = 1;
unsigned char *reduced = (unsigned char *) z_alloca(length + 1);
int reduced_length;
char *binary_string = (char *) z_alloca(13 * length + 200 + 1);
const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS;
const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
error_number = zint_gs1_verify(symbol, source, length, reduced, &reduced_length);
if (error_number >= ZINT_ERROR) {
return error_number;
}
warn_number = error_number;
if (debug_print) {
printf("Reduced (%d): %s\n", reduced_length, reduced);
}
if (symbol->symbology != BARCODE_DBAR_EXP) {
symbol->rows = 0;
}
if (symbol->symbology == BARCODE_DBAR_EXP_CC || symbol->symbology == BARCODE_DBAR_EXPSTK_CC) {
separator_row = symbol->rows++;
symbol->row_height[separator_row] = 1;
}
if (cc_rows) {
binary_string[bp++] = '1';
} else {
binary_string[bp++] = '0';
}
if (symbol->symbology == BARCODE_DBAR_EXPSTK || symbol->symbology == BARCODE_DBAR_EXPSTK_CC) {
cols_per_row = 2;
if (symbol->option_2 >= 1 && symbol->option_2 <= 11) {
cols_per_row = symbol->option_2;
if (cc_rows && cols_per_row == 1) {
cols_per_row = 2;
}
} else if (symbol->option_3 >= 2 && symbol->option_3 <= 11) {
max_rows = symbol->option_3;
}
}
error_number = dbar_exp_binary_string(symbol, reduced, reduced_length, binary_string, &cols_per_row, max_rows,
&bp);
if (error_number != 0) {
return error_number;
}
if (symbol->symbology == BARCODE_DBAR_EXPSTK || symbol->symbology == BARCODE_DBAR_EXPSTK_CC) {
symbol->option_2 = cols_per_row;
symbol->option_3 = max_rows;
}
data_chars = bp / 12;
symbol_chars = data_chars + 1;
if (debug_print) fputs("Data:", stdout);
for (i = 0; i < data_chars; i++) {
const int k = i * 12;
int vs = 0;
for (j = 0; j < 12; j++) {
if (binary_string[k + j] == '1') {
vs |= (0x800 >> j);
}
}
if (debug_print) printf("%s%d", i == 0 || (i & 1) ? " " : ",", vs);
group = dbar_exp_group(vs);
odd = (vs - dbar_exp_g_sum[group]) / dbar_exp_t_even[group];
even = (vs - dbar_exp_g_sum[group]) % dbar_exp_t_even[group];
dbar_widths(char_widths[i], odd, even, dbar_exp_modules[group], 17 - dbar_exp_modules[group], 4 ,
dbar_exp_widest[group], 1 );
}
if (debug_print) fputc('\n', stdout);
checksum = 0;
for (i = 0; i < data_chars; i++) {
const int row = dbar_exp_weight_rows[(data_chars - 2) / 2][i];
for (j = 0; j < 8; j++) {
checksum += char_widths[i][j] * dbar_exp_checksum_weight[row][j];
}
}
check_char = 211 * (symbol_chars - 4) + checksum % 211;
if (debug_print) {
printf("Data chars: %d, Check char: %d\n", data_chars, check_char);
}
group = dbar_exp_group(check_char);
odd = (check_char - dbar_exp_g_sum[group]) / dbar_exp_t_even[group];
even = (check_char - dbar_exp_g_sum[group]) % dbar_exp_t_even[group];
dbar_widths(check_widths, odd, even, dbar_exp_modules[group], 17 - dbar_exp_modules[group], 4 ,
dbar_exp_widest[group], 1 );
codeblocks = (symbol_chars + 1) / 2;
pattern_width = codeblocks * 5 + symbol_chars * 8 + 4;
memset(elements, 0, sizeof(int) * pattern_width);
p = (symbol_chars - 1) / 2 - 1;
for (i = 0; i < codeblocks; i++) {
const int k = dbar_exp_finder_sequence[p][i] - 1;
for (j = 0; j < 5; j++) {
elements[(21 * i) + j + 10] = dbar_exp_finder_pattern[k][j];
}
}
for (i = 0; i < 8; i++) {
elements[i + 2] = check_widths[i];
}
for (i = 1; i < data_chars; i += 2) {
const int k = ((i - 1) / 2) * 21 + 23;
for (j = 0; j < 8; j++) {
elements[k + j] = char_widths[i][j];
}
}
for (i = 0; i < data_chars; i += 2) {
const int k = (i / 2) * 21 + 15;
for (j = 0; j < 8; j++) {
elements[k + j] = char_widths[i][7 - j];
}
}
if (symbol->symbology == BARCODE_DBAR_EXP || symbol->symbology == BARCODE_DBAR_EXP_CC) {
elements[0] = 1;
elements[1] = 1;
elements[pattern_width - 2] = 1;
elements[pattern_width - 1] = 1;
writer = dbar_expand(symbol, 0 , 0 , elements, 0 , pattern_width );
if (symbol->width < writer) {
symbol->width = writer;
}
symbol->rows++;
dbar_exp_hrt(symbol, source, length);
if (content_segs && z_ct_cpy(symbol, reduced, reduced_length)) {
return ZINT_ERROR_MEMORY;
}
} else {
int current_row, current_block, left_to_right;
int v2_latch = 0;
stack_rows = codeblocks / cols_per_row;
if (codeblocks % cols_per_row > 0) {
stack_rows++;
}
current_block = 0;
for (current_row = 1; current_row <= stack_rows; current_row++) {
int elements_in_sub = 2;
int sub_elements[235] = {0};
int special_case_row = 0;
int num_columns;
int latch;
num_columns = current_row * cols_per_row > codeblocks ? codeblocks - current_block : cols_per_row;
sub_elements[0] = 1;
sub_elements[1] = 1;
if (current_row == stack_rows && num_columns != cols_per_row && !(current_row & 1)
&& !(cols_per_row & 1) && (num_columns & 1)) {
special_case_row = 1;
sub_elements[0] = 2;
}
left_to_right = (cols_per_row & 1) || (current_row & 1) || special_case_row;
if (debug_print) {
if (current_row == stack_rows) {
printf("Last row: number of columns: %d / %d, left to right: %d, special case: %d\n",
num_columns, cols_per_row, left_to_right, special_case_row);
}
}
reader = 0;
do {
i = 2 + (current_block * 21);
for (j = 0; j < 21; j++) {
if (i + j < pattern_width) {
if (left_to_right) {
sub_elements[j + (reader * 21) + 2] = elements[i + j];
} else {
sub_elements[(20 - j) + (num_columns - 1 - reader) * 21 + 2] = elements[i + j];
}
}
elements_in_sub++;
}
reader++;
current_block++;
} while (reader < cols_per_row && current_block < codeblocks);
sub_elements[elements_in_sub++] = 1;
sub_elements[elements_in_sub++] = 1;
latch = !((current_row & 1) || special_case_row);
writer = dbar_expand(symbol, 0 , latch, sub_elements, 0 , elements_in_sub );
if (symbol->width < writer) {
symbol->width = writer;
}
if (current_row != 1) {
int odd_last_row = (current_row == stack_rows) && (data_chars % 2 == 0);
for (j = 5; j < (49 * cols_per_row); j += 2) {
z_set_module(symbol, symbol->rows - 2, j);
}
symbol->row_height[symbol->rows - 2] = 1;
dbar_exp_separator(symbol, writer, reader, symbol->rows - 1, 1 , special_case_row,
left_to_right, odd_last_row, &v2_latch);
symbol->row_height[symbol->rows - 1] = 1;
}
if (current_row != stack_rows) {
dbar_exp_separator(symbol, writer, reader, symbol->rows + 1, -1 , 0 ,
left_to_right, 0 , &v2_latch);
symbol->row_height[symbol->rows + 1] = 1;
}
symbol->rows += 4;
}
symbol->rows -= 3;
if (content_segs && z_ct_cpy(symbol, reduced, reduced_length)) {
return ZINT_ERROR_MEMORY;
}
}
if (symbol->symbology == BARCODE_DBAR_EXP_CC || symbol->symbology == BARCODE_DBAR_EXPSTK_CC) {
dbar_exp_separator(symbol, symbol->width, 4, separator_row, 1 , 0 ,
1 , 0 , NULL);
}
if (symbol->symbology == BARCODE_DBAR_EXP_CC || symbol->symbology == BARCODE_DBAR_EXPSTK_CC) {
symbol->height = symbol->height ? 34.0f : 34.0f * stack_rows;
} else {
if (symbol->output_options & COMPLIANT_HEIGHT) {
if (warn_number == 0) {
warn_number = z_set_height(symbol, 34.0f, 34.0f * stack_rows, 0.0f, 0 );
} else {
(void) z_set_height(symbol, 34.0f, 34.0f * stack_rows, 0.0f, 1 );
}
} else {
(void) z_set_height(symbol, 0.0f, 34.0f * stack_rows, 0.0f, 1 );
}
}
return warn_number;
}
INTERNAL int zint_dbar_exp(struct zint_symbol *symbol, unsigned char source[], int length) {
return zint_dbar_exp_cc(symbol, source, length, 0 );
}