#include <assert.h>
#include <limits.h>
#include <math.h>
#include <stdio.h>
#include "common.h"
#include "pdf417.h"
#include "pdf417_tabs.h"
#define PDF_ALP 1
#define PDF_LOW 2
#define PDF_MIX 3
#define PDF_PNC 4
#define PDF_TEX 4
#define PDF_BYT 5
#define PDF_NUM 6
#define PDF_NUM_MODES 6
static const char pdf_smodes[] = { '?', 'A', 'L', 'M', 'P', 'B', 'N' };
static const char *pdf_mode_str(const int mode) {
static const char modes[3][7] = { "Text", "Byte", "Number" };
return mode >= PDF_TEX && mode <= PDF_NUM ? modes[mode - PDF_TEX] : "ERROR";
}
#define PDF_REAL_MODE(m) ((m) <= PDF_TEX ? PDF_TEX : (m))
#define T_ALPHA 1
#define T_LOWER 2
#define T_MIXED 4
#define T_PUNCT 8
#define T_ALWMX (T_ALPHA | T_LOWER | T_MIXED)
#define T_MXPNC (T_MIXED | T_PUNCT)
#define PDF_TABLE_TO_MODE(t) (((t) >> 1) + !!((t) & 0x07))
static const char pdf_asciix[256] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, T_MXPNC, T_PUNCT, 0, 0, T_MXPNC, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
T_ALWMX, T_PUNCT, T_PUNCT, T_MIXED, T_MXPNC, T_MIXED, T_MIXED, T_PUNCT,
T_PUNCT, T_PUNCT, T_MXPNC, T_MIXED, T_MXPNC, T_MXPNC, T_MXPNC, T_MXPNC,
T_MIXED, T_MIXED, T_MIXED, T_MIXED, T_MIXED, T_MIXED, T_MIXED, T_MIXED,
T_MIXED, T_MIXED, T_MXPNC, T_PUNCT, T_PUNCT, T_MIXED, T_PUNCT, T_PUNCT,
T_PUNCT, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA,
T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA,
T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA, T_ALPHA,
T_ALPHA, T_ALPHA, T_ALPHA, T_PUNCT, T_PUNCT, T_PUNCT, T_MIXED, T_PUNCT,
T_PUNCT, T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER,
T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER,
T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER, T_LOWER,
T_LOWER, T_LOWER, T_LOWER, T_PUNCT, T_PUNCT, T_PUNCT, T_PUNCT, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
static const char pdf_asciiy[127] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 12, 15, 0, 0, 11, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
26, 10, 20, 15, 18, 21, 10, 28,
23, 24, 22, 20, 13, 16, 17, 19,
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 14, 0, 1, 23, 2, 25,
3, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 4, 5, 6, 24, 7,
8, 0, 1, 2, 3, 4, 5, 6,
7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22,
23, 24, 25, 26, 21, 27, 9
};
static const char pdf_MicroAutosize[56] = {
4, 6, 7, 8, 10, 12, 13, 14, 16, 18, 19, 20, 24, 29, 30, 33, 34, 37, 39, 46, 54, 58, 70, 72, 82, 90, 108, 126,
1, 14, 2, 7, 3, 25, 8, 16, 5, 17, 9, 6, 10, 11, 28, 12, 19, 13, 29, 20, 30, 21, 22, 31, 23, 32, 33, 34
};
#define PDF_MAX_LEN 2710
#define PDF_MAX_LEN_S "2710"
#define PDF_MAX_STREAM_LEN (PDF_MAX_LEN * 3)
#define MICRO_PDF_MAX_LEN 366
#define MICRO_PDF_MAX_LEN_S "366"
static int pdf_quelmode(const unsigned char codeascii) {
if (z_isdigit(codeascii)) {
return PDF_NUM;
}
if (pdf_asciix[codeascii]) {
return PDF_TEX;
}
return PDF_BYT;
}
static int pdf_textprocess_switch(const int curtable, const int newtable, unsigned char chainet[PDF_MAX_STREAM_LEN],
int wnet) {
switch (curtable) {
case T_ALPHA:
switch (newtable) {
case T_LOWER:
chainet[wnet++] = 27;
break;
case T_MIXED:
chainet[wnet++] = 28;
break;
case T_PUNCT:
chainet[wnet++] = 28;
chainet[wnet++] = 25;
break;
}
break;
case T_LOWER:
switch (newtable) {
case T_ALPHA:
chainet[wnet++] = 28;
chainet[wnet++] = 28;
break;
case T_MIXED:
chainet[wnet++] = 28;
break;
case T_PUNCT:
chainet[wnet++] = 28;
chainet[wnet++] = 25;
break;
}
break;
case T_MIXED:
switch (newtable) {
case T_ALPHA:
chainet[wnet++] = 28;
break;
case T_LOWER:
chainet[wnet++] = 27;
break;
case T_PUNCT:
chainet[wnet++] = 25;
break;
}
break;
case T_PUNCT:
switch (newtable) {
case T_ALPHA:
chainet[wnet++] = 29;
break;
case T_LOWER:
chainet[wnet++] = 29;
chainet[wnet++] = 27;
break;
case T_MIXED:
chainet[wnet++] = 29;
chainet[wnet++] = 28;
break;
}
break;
}
return wnet;
}
static int pdf_text_num_length(short liste[3][PDF_MAX_LEN], const int indexliste, const int start) {
int i, len = 0;
for (i = start; i < indexliste; i++) {
if (liste[1][i] == PDF_BYT)
break;
len += liste[0][i];
if (len >= 5)
break;
}
return len;
}
static int pdf_text_submode_length(const unsigned char chaine[], const int start, const int length, int *p_curtable) {
int j, indexlistet, curtable = *p_curtable, listet[PDF_MAX_LEN], wnet = 0;
unsigned char chainet[PDF_MAX_STREAM_LEN];
for (indexlistet = 0; indexlistet < length; indexlistet++) {
assert(pdf_asciix[chaine[start + indexlistet]]);
listet[indexlistet] = pdf_asciix[chaine[start + indexlistet]];
}
for (j = 0; j < length; j++) {
if (listet[j] & curtable) {
wnet++;
} else {
int newtable;
if (j == length - 1 || !(listet[j] & listet[j + 1])) {
if ((listet[j] & T_ALPHA) && curtable == T_LOWER) {
wnet += 2;
continue;
}
if (listet[j] & T_PUNCT) {
wnet += 2;
continue;
}
newtable = listet[j];
} else {
newtable = listet[j] & listet[j + 1];
}
if (newtable == T_ALWMX) {
newtable = T_ALPHA;
} else if (newtable == T_MXPNC) {
newtable = T_MIXED;
}
wnet = pdf_textprocess_switch(curtable, newtable, chainet, wnet);
curtable = newtable;
wnet++;
}
}
*p_curtable = curtable;
return wnet;
}
static int pdf_num_stay(const unsigned char *chaine, const int indexliste, short liste[3][PDF_MAX_LEN], const int i) {
int curtable, not_tex, last_len, last_ml, next_len, num_cws, tex_cws;
if (liste[0][i] >= 13 || (indexliste == 1 && liste[0][i] > 5)) {
return 1;
}
if (liste[0][i] < 11) {
return 0;
}
curtable = T_ALPHA;
not_tex = i == 0 || liste[1][i - 1] == PDF_BYT;
last_len = not_tex ? 0 : pdf_text_submode_length(chaine, liste[2][i - 1], liste[0][i - 1], &curtable);
last_ml = curtable == T_MIXED;
curtable = T_ALPHA;
not_tex = i == indexliste - 1 || liste[1][i + 1] == PDF_BYT;
next_len = not_tex ? 0 : pdf_text_submode_length(chaine, liste[2][i + 1], liste[0][i + 1], &curtable);
num_cws = ((last_len + 1) >> 1) + 1 + 4 + (liste[0][i] > 11) + 1 + ((next_len + 1) >> 1);
curtable = T_MIXED;
next_len = not_tex ? 0 : pdf_text_submode_length(chaine, liste[2][i + 1], liste[0][i + 1], &curtable);
tex_cws = (last_len + !last_ml + liste[0][i] + next_len + 1) >> 1;
if (num_cws > tex_cws) {
return 0;
}
return 1;
}
static void pdf_appendix_d_encode(const unsigned char *chaine, short liste[3][PDF_MAX_LEN], int *p_indexliste) {
const int indexliste = *p_indexliste;
int i = 0, next, last = 0, stayintext = 0;
while (i < indexliste) {
if (liste[1][i] == PDF_NUM && pdf_num_stay(chaine, indexliste, liste, i)) {
liste[0][last] = liste[0][i];
liste[1][last] = PDF_NUM;
liste[2][last] = liste[2][i];
stayintext = 0;
last++;
} else if ((liste[1][i] == PDF_TEX || liste[1][i] == PDF_NUM)
&& (stayintext || i == indexliste - 1 || liste[0][i] >= 5
|| pdf_text_num_length(liste, indexliste, i) >= 5)) {
liste[0][last] = liste[0][i];
liste[1][last] = PDF_TEX;
liste[2][last] = liste[2][i];
stayintext = 0;
next = i + 1;
while (next < indexliste) {
if (liste[1][next] == PDF_NUM && pdf_num_stay(chaine, indexliste, liste, next)) {
break;
} else if (liste[1][next] == PDF_BYT) {
break;
}
liste[0][last] += liste[0][next];
next++;
}
last++;
i = next;
continue;
} else {
liste[0][last] = liste[0][i];
liste[1][last] = PDF_BYT;
liste[2][last] = liste[2][i];
stayintext = 0;
next = i + 1;
while (next < indexliste) {
if (liste[1][next] != PDF_BYT) {
if (liste[0][last] == 1 && last > 0 && liste[1][last - 1] == PDF_TEX) {
stayintext = 1;
break;
}
if (liste[0][next] >= 5 || pdf_text_num_length(liste, indexliste, next) >= 5) {
break;
}
}
liste[0][last] += liste[0][next];
next++;
}
last++;
i = next;
continue;
}
i++;
}
*p_indexliste = last;
}
static void pdf_textprocess_end(short *chainemc, int *p_mclength, const int is_last_seg,
unsigned char chainet[PDF_MAX_STREAM_LEN], int wnet, int *p_curtable, int *p_tex_padded) {
int i;
*p_tex_padded = wnet & 1;
if (*p_tex_padded) {
if (is_last_seg) {
chainet[wnet++] = 29;
} else {
chainet[wnet++] = 28 + (*p_curtable == T_PUNCT);
*p_curtable = *p_curtable == T_ALPHA || *p_curtable == T_LOWER ? T_MIXED : T_ALPHA;
}
}
for (i = 0; i < wnet; i += 2) {
chainemc[(*p_mclength)++] = (30 * chainet[i]) + chainet[i + 1];
}
}
static void pdf_textprocess(short *chainemc, int *p_mclength, const unsigned char chaine[], const int start,
const int length, const int lastmode, const int is_last_seg, int *p_curtable, int *p_tex_padded) {
const int real_lastmode = PDF_REAL_MODE(lastmode);
int j, indexlistet;
int curtable = real_lastmode == PDF_TEX ? *p_curtable : T_ALPHA;
int listet[2][PDF_MAX_LEN] = {{0}};
unsigned char chainet[PDF_MAX_STREAM_LEN];
int wnet = 0;
if (real_lastmode != PDF_TEX) {
chainemc[(*p_mclength)++] = 900;
}
for (indexlistet = 0; indexlistet < length; indexlistet++) {
const int codeascii = chaine[start + indexlistet];
listet[0][indexlistet] = pdf_asciix[codeascii];
listet[1][indexlistet] = pdf_asciiy[codeascii];
}
for (j = 0; j < length; j++) {
if (listet[0][j] & curtable) {
chainet[wnet++] = listet[1][j];
} else {
int newtable;
if (j == length - 1 || !(listet[0][j] & listet[0][j + 1])) {
if ((listet[0][j] & T_ALPHA) && curtable == T_LOWER) {
chainet[wnet++] = 27;
chainet[wnet++] = listet[1][j];
continue;
}
if (listet[0][j] & T_PUNCT) {
chainet[wnet++] = 29;
chainet[wnet++] = listet[1][j];
continue;
}
newtable = listet[0][j];
} else {
newtable = listet[0][j] & listet[0][j + 1];
}
if (newtable == T_ALWMX) {
newtable = T_ALPHA;
} else if (newtable == T_MXPNC) {
newtable = T_MIXED;
}
wnet = pdf_textprocess_switch(curtable, newtable, chainet, wnet);
curtable = newtable;
chainet[wnet++] = listet[1][j];
}
}
*p_curtable = curtable;
pdf_textprocess_end(chainemc, p_mclength, is_last_seg, chainet, wnet, p_curtable, p_tex_padded);
}
static void pdf_textprocess_minimal(short *chainemc, int *p_mclength, const unsigned char chaine[],
short liste[3][PDF_MAX_LEN], const int indexliste, const int lastmode, const int is_last_seg,
int *p_curtable, int *p_tex_padded, int *p_i) {
const int real_lastmode = PDF_REAL_MODE(lastmode);
int i, j, k;
int curtable = real_lastmode == PDF_TEX ? *p_curtable : T_ALPHA;
unsigned char chainet[PDF_MAX_STREAM_LEN];
int wnet = 0;
if (real_lastmode != PDF_TEX) {
chainemc[(*p_mclength)++] = 900;
}
for (i = *p_i; i < indexliste && PDF_REAL_MODE(liste[1][i]) == PDF_TEX; i++) {
static const unsigned char newtables[5] = { 0, T_ALPHA, T_LOWER, T_MIXED, T_PUNCT };
const int newtable = newtables[liste[1][i]];
const int from = liste[2][i];
for (j = 0; j < liste[0][i]; j++) {
const int c = chaine[from + j];
const int t_table = pdf_asciix[c];
if (!t_table) {
if (wnet & 1) {
chainet[wnet++] = 29;
if (curtable == T_PUNCT) {
curtable = T_ALPHA;
}
}
for (k = 0; k < wnet; k += 2) {
chainemc[(*p_mclength)++] = (30 * chainet[k]) + chainet[k + 1];
}
chainemc[(*p_mclength)++] = 913;
chainemc[(*p_mclength)++] = c;
wnet = 0;
continue;
}
if (newtable != curtable) {
wnet = pdf_textprocess_switch(curtable, newtable, chainet, wnet);
curtable = newtable;
}
if (curtable == T_LOWER && t_table == T_ALPHA) {
chainet[wnet++] = 27;
} else if (curtable != T_PUNCT && (t_table & T_PUNCT) && (curtable != T_MIXED || !(t_table & T_MIXED))) {
chainet[wnet++] = 29;
}
chainet[wnet++] = pdf_asciiy[c];
}
}
*p_i = i ? i - 1 : 0;
*p_curtable = curtable;
pdf_textprocess_end(chainemc, p_mclength, is_last_seg, chainet, wnet, p_curtable, p_tex_padded);
}
INTERNAL void zint_pdf_byteprocess(short *chainemc, int *p_mclength, const unsigned char chaine[], int start,
const int length, const int lastmode) {
const int real_lastmode = PDF_REAL_MODE(lastmode);
if (length == 1) {
chainemc[(*p_mclength)++] = real_lastmode == PDF_TEX ? 913 : 901;
chainemc[(*p_mclength)++] = chaine[start];
} else {
int len;
if (length % 6 == 0) {
chainemc[(*p_mclength)++] = 924;
} else {
chainemc[(*p_mclength)++] = 901;
}
len = 0;
while (len < length) {
uint64_t total;
unsigned int chunkLen = length - len;
if (6 <= chunkLen) {
chunkLen = 6;
len += chunkLen;
total = 0;
while (chunkLen--) {
const uint64_t mantisa = chaine[start++];
total |= mantisa << (chunkLen * 8);
}
chunkLen = 5;
while (chunkLen--) {
chainemc[*p_mclength + chunkLen] = (int) (total % 900);
total /= 900;
}
*p_mclength += 5;
} else {
len += chunkLen;
while (chunkLen--) {
chainemc[(*p_mclength)++] = chaine[start++];
}
}
}
}
}
static void pdf_numbprocess(short *chainemc, int *p_mclength, const unsigned char chaine[], const int start,
const int length) {
int j;
chainemc[(*p_mclength)++] = 902;
j = 0;
while (j < length) {
int dumlength = 0;
int p, len, loop, nombre, dummy[50];
char chainemod[45];
int longueur = length - j;
if (longueur > 44) {
longueur = 44;
}
len = longueur + 1;
chainemod[0] = 1;
for (loop = 1; loop < len; loop++) {
chainemod[loop] = z_ctoi(chaine[start + loop + j - 1]);
}
do {
p = 0;
nombre = 0;
for (loop = 0; loop < len; loop++) {
nombre *= 10;
nombre += chainemod[loop];
if (nombre < 900) {
if (p) {
chainemod[p++] = 0;
}
} else {
chainemod[p] = (nombre / 900);
nombre -= chainemod[p++] * 900;
}
}
dummy[dumlength++] = nombre;
len = p;
} while (p);
for (loop = dumlength - 1; loop >= 0; loop--) {
chainemc[(*p_mclength)++] = dummy[loop];
}
j += longueur;
}
}
#ifdef ZINT_TEST
INTERNAL void zint_test_pdf_numbprocess(short *chainemc, int *p_mclength, const unsigned char chaine[],
const int start, const int length) {
pdf_numbprocess(chainemc, p_mclength, chaine, start, length);
}
#endif
static int pdf_table_length(const unsigned char source[], const int length, const int position, const int t_table) {
int i;
for (i = position; i < length && (pdf_asciix[source[i]] & t_table); i++);
return i - position;
}
struct pdf_edge {
unsigned char mode;
unsigned short from;
unsigned short len;
unsigned short units;
unsigned short unit_size;
unsigned short size;
unsigned short previous;
};
#define PDF_PREVIOUS(edges, edge) \
((edge)->previous ? (edges) + (edge)->previous : NULL)
#if 0#else
#define PDF_TRACE_Edges(px, s, l, p, v)
#define PDF_TRACE_AddEdge(s, l, es, p, v, t, e) do { (void)(s); (void)(l); } while (0)
#define PDF_TRACE_NotAddEdge(s, l, es, p, v, t, e) do { (void)(s); (void)(l); } while (0)
#endif
static int pdf_new_Edge(struct pdf_edge *edges, const int mode, const int from, const int len, const int t_table,
const int lastmode, struct pdf_edge *previous, struct pdf_edge *edge) {
const int real_mode = PDF_REAL_MODE(mode);
int previousMode, real_previousMode;
int units;
int unit_size = 0;
int dv, md;
edge->mode = mode;
edge->from = from;
edge->len = len;
if (previous) {
assert(previous->mode && previous->len && (previous->unit_size + previous->size));
previousMode = previous->mode;
real_previousMode = PDF_REAL_MODE(previousMode);
edge->previous = previous - edges;
if (real_mode != real_previousMode) {
edge->size = previous->size + previous->unit_size + 1;
units = 0;
} else {
edge->size = previous->size;
units = previous->units;
}
} else {
previousMode = lastmode;
real_previousMode = PDF_REAL_MODE(previousMode);
edge->previous = 0;
edge->size = real_mode != real_previousMode || real_previousMode != PDF_TEX ? 1 : 0;
units = 0;
}
switch (mode) {
case PDF_ALP:
assert(!t_table || (t_table & (T_ALPHA | T_PUNCT)));
if (t_table) {
if (previousMode != mode && real_previousMode == PDF_TEX) {
units += 1 + (previousMode == PDF_LOW);
}
units += (1 + !(t_table & T_ALPHA)) * len;
} else {
assert(len == 1);
if (units & 1) {
units++;
}
if (previousMode != mode && real_previousMode == PDF_TEX) {
units += 1 + (previousMode == PDF_LOW);
}
units += 4;
}
unit_size = (units + 1) >> 1;
break;
case PDF_LOW:
assert(!t_table || (t_table & (T_LOWER | T_PUNCT | T_ALPHA)));
if (t_table) {
if (previousMode != mode) {
units += 1 + (previousMode == PDF_PNC);
}
units += (1 + !(t_table & T_LOWER)) * len;
} else {
assert(len == 1);
if (units & 1) {
units++;
}
if (previousMode != mode) {
units += 1 + (previousMode == PDF_PNC);
}
units += 4;
}
unit_size = (units + 1) >> 1;
break;
case PDF_MIX:
assert(!t_table || (t_table & (T_MIXED | T_PUNCT)));
if (t_table) {
if (previousMode != mode) {
units += 1 + (previousMode == PDF_PNC);
}
units += (1 + !(t_table & T_MIXED)) * len;
} else {
assert(len == 1);
if (units & 1) {
units++;
}
if (previousMode != mode) {
units += 1 + (previousMode == PDF_PNC);
}
units += 4;
}
unit_size = (units + 1) >> 1;
break;
case PDF_PNC:
assert(!t_table || (t_table & T_PUNCT));
if (t_table) {
if (previousMode != mode) {
units += 1 + (previousMode != PDF_MIX);
}
units += len;
} else {
assert(len == 1);
if (units & 1) {
units += 3;
} else if (previousMode != mode) {
units += 1 + (previousMode != PDF_MIX);
}
units += 4;
}
unit_size = (units + 1) >> 1;
break;
case PDF_BYT:
units += len;
dv = units / 6;
unit_size = dv * 5 + (units - dv * 6);
break;
case PDF_NUM:
units += len;
dv = units / 44;
md = units - dv * 44;
unit_size = dv * 15 + (md ? md / 3 + 1 : 0);
break;
}
edge->units = units;
edge->unit_size = unit_size;
return edge->size + edge->unit_size;
}
static int pdf_new_units_better(const int mode, const int existing_units, const int new_units) {
if (PDF_REAL_MODE(mode) == PDF_TEX) {
if ((new_units & 1) != (existing_units & 1)) {
return (existing_units & 1);
}
} else if (mode == PDF_BYT) {
const int existing_md = existing_units % 6;
if (new_units % 6 != existing_md) {
return existing_md;
}
}
return new_units < existing_units;
}
static void pdf_addEdge(const unsigned char *source, const int length, struct pdf_edge *edges, const int mode,
const int from, const int len, const int t_table, const int lastmode, struct pdf_edge *previous) {
struct pdf_edge edge;
const int new_size = pdf_new_Edge(edges, mode, from, len, t_table, lastmode, previous, &edge);
const int vertexIndex = from + len;
const int v_ij = vertexIndex * PDF_NUM_MODES + mode - 1;
const int v_size = edges[v_ij].size + edges[v_ij].unit_size;
if (edges[v_ij].mode == 0 || v_size > new_size
|| (v_size == new_size && pdf_new_units_better(mode, edge.units, edges[v_ij].units))) {
PDF_TRACE_AddEdge(source, length, edges, previous, vertexIndex, t_table, &edge);
edges[v_ij] = edge;
} else {
PDF_TRACE_NotAddEdge(source, length, edges, previous, vertexIndex, t_table, &edge);
}
}
static void pdf_addEdges(const unsigned char source[], const int length, const int lastmode, struct pdf_edge *edges,
const int from, struct pdf_edge *previous) {
const unsigned char c = source[from];
const int t_table = pdf_asciix[c];
if (t_table & T_ALPHA) {
const int len = pdf_table_length(source, length, from, T_ALPHA);
pdf_addEdge(source, length, edges, PDF_ALP, from, len, T_ALPHA, lastmode, previous);
}
if (!t_table || (t_table & T_PUNCT)) {
pdf_addEdge(source, length, edges, PDF_ALP, from, 1 , t_table & ~T_ALPHA, lastmode, previous);
}
if (t_table & T_LOWER) {
const int len = pdf_table_length(source, length, from, T_LOWER);
pdf_addEdge(source, length, edges, PDF_LOW, from, len, T_LOWER, lastmode, previous);
}
if (!t_table || (t_table & (T_PUNCT | T_ALPHA))) {
pdf_addEdge(source, length, edges, PDF_LOW, from, 1 , t_table & ~T_LOWER, lastmode, previous);
}
if (t_table & T_MIXED) {
const int len = pdf_table_length(source, length, from, T_MIXED);
pdf_addEdge(source, length, edges, PDF_MIX, from, len, T_MIXED, lastmode, previous);
if (len > 1 && z_isdigit(source[from + 1])) {
pdf_addEdge(source, length, edges, PDF_MIX, from, 1 , T_MIXED, lastmode, previous);
}
}
if (!t_table || (t_table & T_PUNCT)) {
pdf_addEdge(source, length, edges, PDF_MIX, from, 1 , t_table & ~T_MIXED, lastmode, previous);
}
if (t_table & T_PUNCT) {
const int len = pdf_table_length(source, length, from, T_PUNCT);
pdf_addEdge(source, length, edges, PDF_PNC, from, len, T_PUNCT, lastmode, previous);
}
if (!t_table) {
pdf_addEdge(source, length, edges, PDF_PNC, from, 1 , t_table, lastmode, previous);
}
if (z_isdigit(c)) {
const int len = z_cnt_digits(source, length, from, -1 );
pdf_addEdge(source, length, edges, PDF_NUM, from, len, 0 , lastmode, previous);
}
pdf_addEdge(source, length, edges, PDF_BYT, from, 1 , 0 , lastmode, previous);
}
static int pdf_define_modes(short liste[3][PDF_MAX_LEN], int *p_indexliste, const unsigned char source[],
const int length, const int lastmode, const int debug_print) {
int i, j, v_i;
int minimalJ, minimalSize;
struct pdf_edge *edge;
int mode_start, mode_len;
struct pdf_edge *edges = (struct pdf_edge *) calloc((length + 1) * PDF_NUM_MODES, sizeof(struct pdf_edge));
if (!edges) {
return 0;
}
pdf_addEdges(source, length, lastmode, edges, 0, NULL);
PDF_TRACE_Edges("DEBUG Initial situation\n", source, length, edges, 0);
for (i = 1; i < length; i++) {
v_i = i * PDF_NUM_MODES;
for (j = 0; j < PDF_NUM_MODES; j++) {
if (edges[v_i + j].mode) {
pdf_addEdges(source, length, lastmode, edges, i, edges + v_i + j);
}
}
PDF_TRACE_Edges("DEBUG situation after adding edges to vertices at position %d\n", source, length, edges, i);
}
PDF_TRACE_Edges("DEBUG Final situation\n", source, length, edges, length);
v_i = length * PDF_NUM_MODES;
minimalJ = -1;
minimalSize = INT_MAX;
for (j = 0; j < PDF_NUM_MODES; j++) {
edge = edges + v_i + j;
if (edge->mode) {
const int edge_size = edge->size + edge->unit_size;
if (debug_print) {
printf("edges[%d][%d][0] size %d(%d,%d)\n", length, j, edge_size, edge->unit_size, edge->size);
}
if (edge_size < minimalSize) {
minimalSize = edge_size;
minimalJ = j;
if (debug_print) printf(" set minimalJ %d\n", minimalJ);
}
} else {
if (debug_print) printf("edges[%d][%d][0] NULL\n", length, j);
}
}
assert(minimalJ >= 0);
edge = edges + v_i + minimalJ;
mode_len = 0;
mode_start = length;
while (edge) {
const int current_mode = edge->mode;
const int current_from = edge->from;
mode_len += edge->len;
edge = PDF_PREVIOUS(edges, edge);
if (!edge || edge->mode != current_mode) {
mode_start--;
liste[0][mode_start] = mode_len;
liste[1][mode_start] = current_mode;
liste[2][mode_start] = current_from;
mode_len = 0;
}
}
*p_indexliste = length - mode_start;
if (mode_start) {
memmove(liste[0], liste[0] + mode_start, sizeof(short) * (*p_indexliste));
memmove(liste[1], liste[1] + mode_start, sizeof(short) * (*p_indexliste));
memmove(liste[2], liste[2] + mode_start, sizeof(short) * (*p_indexliste));
}
if (debug_print) {
printf("modes (%d):", *p_indexliste);
for (i = 0; i < *p_indexliste; i++) printf(" %c(%d,%d)", pdf_smodes[liste[1][i]], liste[2][i], liste[0][i]);
fputc('\n', stdout);
}
free(edges);
return 1;
}
static int pdf_initial(struct zint_symbol *symbol, const unsigned char chaine[], const int length, const int eci,
const int is_micro, const int is_last_seg, int *p_lastmode, int *p_curtable, int *p_tex_padded,
short chainemc[PDF_MAX_STREAM_LEN], int *p_mclength) {
int i, indexchaine = 0, indexliste = 0;
short liste[3][PDF_MAX_LEN] = {{0}};
int mclength;
const int fast_encode = symbol->input_mode & FAST_MODE;
const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
if (fast_encode) {
int mode = pdf_quelmode(chaine[0]);
do {
liste[1][indexliste] = mode;
liste[2][indexliste] = indexchaine;
while (liste[1][indexliste] == mode && indexchaine < length) {
liste[0][indexliste]++;
indexchaine++;
mode = pdf_quelmode(chaine[indexchaine]);
}
indexliste++;
} while (indexchaine < length);
if (debug_print) {
fputs("\nInitial block pattern:\n", stdout);
for (i = 0; i < indexliste; i++) {
int j;
for (j = 0; j < liste[0][i]; j++) fputc(pdf_mode_str(liste[1][i])[0], stdout);
}
fputc('\n', stdout);
}
pdf_appendix_d_encode(chaine, liste, &indexliste);
} else {
if (!pdf_define_modes(liste, &indexliste, chaine, length, *p_lastmode, debug_print)) {
return z_errtxt(ZINT_ERROR_MEMORY, symbol, 749, "Insufficient memory for mode buffers");
}
}
if (debug_print) {
fputs("\nCompacted block pattern:\n", stdout);
for (i = 0; i < indexliste; i++) {
int j;
for (j = 0; j < liste[0][i]; j++) fputc(pdf_mode_str(PDF_REAL_MODE(liste[1][i]))[0], stdout);
}
fputc('\n', stdout);
}
indexchaine = 0;
mclength = *p_mclength;
if (mclength == 0 && !is_micro) {
mclength++;
}
if (*p_mclength == 0 && (symbol->output_options & READER_INIT)) {
chainemc[mclength++] = 921;
}
if (eci != 0) {
if (eci > 811799) {
return z_errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 472, "ECI code '%d' out of range (0 to 811799)",
symbol->eci);
}
if (eci <= 899) {
chainemc[mclength++] = 927;
chainemc[mclength++] = eci;
} else if (eci <= 810899) {
chainemc[mclength++] = 926;
chainemc[mclength++] = (eci / 900) - 1;
chainemc[mclength++] = eci % 900;
} else {
chainemc[mclength++] = 925;
chainemc[mclength++] = eci - 810900;
}
}
for (i = 0; i < indexliste; i++) {
const int real_mode = PDF_REAL_MODE(liste[1][i]);
switch (real_mode) {
case PDF_TEX:
if (fast_encode) {
pdf_textprocess(chainemc, &mclength, chaine, indexchaine, liste[0][i], *p_lastmode, is_last_seg,
p_curtable, p_tex_padded);
indexchaine += liste[0][i];
*p_lastmode = PDF_ALP;
} else {
pdf_textprocess_minimal(chainemc, &mclength, chaine, liste, indexliste, *p_lastmode, is_last_seg,
p_curtable, p_tex_padded, &i);
indexchaine = i + 1 < indexliste ? liste[2][i + 1] : length;
*p_lastmode = PDF_TABLE_TO_MODE(*p_curtable);
}
break;
case PDF_BYT:
zint_pdf_byteprocess(chainemc, &mclength, chaine, indexchaine, liste[0][i], *p_lastmode);
if (PDF_REAL_MODE(*p_lastmode) != PDF_TEX || liste[0][i] != 1) {
*p_lastmode = PDF_BYT;
} else if (*p_curtable == T_PUNCT && *p_tex_padded) {
*p_curtable = T_ALPHA;
}
indexchaine += liste[0][i];
break;
case PDF_NUM:
pdf_numbprocess(chainemc, &mclength, chaine, indexchaine, liste[0][i]);
*p_lastmode = PDF_NUM;
indexchaine += liste[0][i];
break;
}
}
*p_mclength = mclength;
return 0;
}
static int pdf_initial_segs(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count,
const int is_micro, short chainemc[PDF_MAX_STREAM_LEN], int *p_mclength, int structapp_cws[18],
int *p_structapp_cp) {
int i;
int error_number = 0;
int structapp_cp = 0;
int lastmode;
int curtable;
int tex_padded;
const int content_segs = symbol->output_options & BARCODE_CONTENT_SEGS;
*p_mclength = 0;
if (symbol->structapp.count) {
int id_cnt = 0, ids[10];
if (symbol->structapp.count < 2 || symbol->structapp.count > 99999) {
return z_errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 740,
"Structured Append count '%d' out of range (2 to 99999)", symbol->structapp.count);
}
if (symbol->structapp.index < 1 || symbol->structapp.index > symbol->structapp.count) {
return ZEXT z_errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 741,
"Structured Append index '%1$d' out of range (1 to count %2$d)",
symbol->structapp.index, symbol->structapp.count);
}
if (symbol->structapp.id[0]) {
int id_len;
for (id_len = 1; id_len < 31 && symbol->structapp.id[id_len]; id_len++);
if (id_len > 30) {
return z_errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 742,
"Structured Append ID length %d too long (30 digit maximum)", id_len);
}
for (i = 0; i < id_len; i += 3, id_cnt++) {
const int triplet_len = i + 3 < id_len ? 3 : id_len - i;
ids[id_cnt] = z_to_int(ZCUCP(symbol->structapp.id + i), triplet_len);
if (ids[id_cnt] == -1) {
return z_errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 743,
"Invalid Structured Append ID (digits only)");
}
if (ids[id_cnt] > 899) {
return ZEXT z_errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 744,
"Structured Append ID triplet %1$d value '%2$03d' out of range (000 to 899)",
id_cnt + 1, ids[id_cnt]);
}
}
}
structapp_cws[structapp_cp++] = 928;
structapp_cws[structapp_cp++] = (100000 + symbol->structapp.index - 1) / 900;
structapp_cws[structapp_cp++] = (100000 + symbol->structapp.index - 1) % 900;
for (i = 0; i < id_cnt; i++) {
structapp_cws[structapp_cp++] = ids[i];
}
structapp_cws[structapp_cp++] = 923;
structapp_cws[structapp_cp++] = 1;
structapp_cws[structapp_cp++] = (100000 + symbol->structapp.count) / 900;
structapp_cws[structapp_cp++] = (100000 + symbol->structapp.count) % 900;
if (symbol->structapp.index == symbol->structapp.count) {
structapp_cws[structapp_cp++] = 922;
}
}
*p_structapp_cp = structapp_cp;
lastmode = is_micro ? PDF_BYT : PDF_ALP;
curtable = T_ALPHA;
for (i = 0; i < seg_count; i++) {
if ((error_number = pdf_initial(symbol, segs[i].source, segs[i].length, segs[i].eci, is_micro,
i + 1 == seg_count, &lastmode, &curtable, &tex_padded, chainemc, p_mclength))) {
assert(error_number >= ZINT_ERROR);
return error_number;
}
if (content_segs && segs[i].eci) {
z_ct_set_seg_eci(symbol, i, segs[i].eci);
}
}
return error_number;
}
static int pdf_enc(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
int i, j, longueur, loop, mccorrection[520] = {0}, offset;
int total, mclength, c1, c2, c3, dummy[35];
short chainemc[PDF_MAX_STREAM_LEN];
int rows, cols, ecc, ecc_cws, padding;
char pattern[580];
int bp = 0;
int structapp_cws[18] = {0};
int structapp_cp = 0;
int error_number;
const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
if ((i = z_segs_length(segs, seg_count)) > PDF_MAX_LEN) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 463, "Input length %d too long (maximum " PDF_MAX_LEN_S ")", i);
}
if ((error_number = pdf_initial_segs(symbol, segs, seg_count, 0 , chainemc, &mclength, structapp_cws,
&structapp_cp))) {
assert(error_number >= ZINT_ERROR);
return error_number;
}
if (debug_print) {
printf("\nCompressed data stream (%d):\n", mclength - 1);
for (i = 1; i < mclength; i++) {
printf("%d ", chainemc[i]);
}
fputs("\n\n", stdout);
}
assert(mclength > 0);
ecc = symbol->option_1;
if (ecc < 0) {
const int data_cws = mclength - 1 + structapp_cp;
if (data_cws <= 40) {
ecc = 2;
} else if (data_cws <= 160) {
ecc = 3;
} else if (data_cws <= 320) {
ecc = 4;
} else if (data_cws <= 863) {
ecc = 5;
} else {
ecc = 6;
}
}
ecc_cws = 2 << ecc;
longueur = mclength + structapp_cp + ecc_cws;
if (debug_print) printf("Total No. of Codewords: %d, ECC %d, No. of ECC Codewords: %d\n", longueur, ecc, ecc_cws);
if (longueur > 928) {
return z_errtxt(ZINT_ERROR_TOO_LONG, symbol, 464,
"Input too long, requires too many codewords (maximum 928)");
}
cols = symbol->option_2;
rows = symbol->option_3;
if (rows) {
if (cols < 1) {
cols = (longueur + rows - 1) / rows;
if (cols <= 1) {
cols = 1;
} else {
for (; cols > 30 && rows < 90; rows++, cols = (longueur + rows - 1) / rows);
assert(cols <= 30);
for (; cols >= 1 && rows < 90 && rows * cols > 928; rows++, cols = (longueur + rows - 1) / rows);
if (rows * cols > 928) {
return z_errtxt(ZINT_ERROR_TOO_LONG, symbol, 465,
"Input too long, requires too many codewords (maximum 928)");
}
}
} else {
for (; rows <= 90 && rows * cols < longueur; rows++);
if (rows > 90 || rows * cols > 928) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 745, "Input too long for number of columns '%d'", cols);
}
}
if (rows != symbol->option_3) {
error_number = ZEXT z_errtxtf(ZINT_WARN_INVALID_OPTION, symbol, 746,
"Number of rows increased from %1$d to %2$d", symbol->option_3, rows);
}
} else {
if (cols < 1) {
cols = (int) round(sqrt((longueur - 1) / 3.0));
}
rows = (longueur + cols - 1) / cols;
if (rows <= 3) {
rows = 3;
} else {
for (; rows > 90 && cols < 30; cols++, rows = (longueur + cols - 1) / cols);
assert(rows <= 90);
for (; rows >= 3 && cols < 30 && rows * cols > 928; cols++, rows = (longueur + cols - 1) / cols);
if (rows * cols > 928) {
return z_errtxt(ZINT_ERROR_TOO_LONG, symbol, 747,
"Input too long, requires too many codewords (maximum 928)");
}
if (symbol->option_2 && cols != symbol->option_2) {
error_number = ZEXT z_errtxtf(ZINT_WARN_INVALID_OPTION, symbol, 748,
"Number of columns increased from %1$d to %2$d", symbol->option_2, cols);
}
}
}
assert(rows * cols >= longueur);
symbol->option_1 = ecc;
symbol->option_2 = cols;
symbol->option_3 = rows;
padding = rows * cols - longueur;
for (i = 0; i < padding; i++) {
chainemc[mclength++] = 900;
}
if (debug_print) printf("Padding: %d\n", padding);
if (structapp_cp) {
for (i = 0; i < structapp_cp; i++) {
chainemc[mclength++] = structapp_cws[i];
}
}
chainemc[0] = mclength;
switch (ecc) {
case 1: offset = 2; break;
case 2: offset = 6; break;
case 3: offset = 14; break;
case 4: offset = 30; break;
case 5: offset = 62; break;
case 6: offset = 126; break;
case 7: offset = 254; break;
case 8: offset = 510; break;
default: offset = 0; break;
}
for (i = 0; i < mclength; i++) {
total = (chainemc[i] + mccorrection[ecc_cws - 1]) % 929;
for (j = ecc_cws - 1; j > 0; j--) {
mccorrection[j] = (mccorrection[j - 1] + 929 - (total * zint_pdf_coefrs[offset + j]) % 929) % 929;
}
mccorrection[0] = (929 - (total * zint_pdf_coefrs[offset]) % 929) % 929;
}
for (i = ecc_cws - 1; i >= 0; i--) {
chainemc[mclength++] = mccorrection[i] ? 929 - mccorrection[i] : 0;
}
if (debug_print) {
printf("Complete CW string (%d):\n", mclength);
for (i = 0; i < mclength; i++) {
printf("%d ", chainemc[i]);
}
fputc('\n', stdout);
}
#ifdef ZINT_TEST
if (symbol->debug & ZINT_DEBUG_TEST) {
z_debug_test_codeword_dump_short(symbol, chainemc, mclength);
}
#endif
if (debug_print) printf("\nSymbol size:\n%d columns x %d rows\n", cols, rows);
assert(cols > 0);
c1 = (rows - 1) / 3;
c2 = ecc * 3 + (rows - 1) % 3;
c3 = cols - 1;
assert(rows * cols <= mclength);
for (i = 0; i < rows; i++) {
const int k = (i / 3) * 30;
bp = 0;
for (j = 0; j < cols; j++) {
dummy[j + 1] = chainemc[i * cols + j];
}
switch (i % 3) {
case 0:
dummy[0] = k + c1;
dummy[cols + 1] = k + c3;
offset = 0;
break;
case 1:
dummy[0] = k + c2;
dummy[cols + 1] = k + c1;
offset = 929;
break;
case 2:
dummy[0] = k + c3;
dummy[cols + 1] = k + c2;
offset = 1858;
break;
}
bp = z_bin_append_posn(0x1FEA8, 17, pattern, bp);
for (j = 0; j <= cols; j++) {
bp = z_bin_append_posn(zint_pdf_bitpattern[offset + dummy[j]], 16, pattern, bp);
pattern[bp++] = '0';
}
if (symbol->symbology != BARCODE_PDF417COMP) {
bp = z_bin_append_posn(zint_pdf_bitpattern[offset + dummy[j]], 16, pattern, bp);
pattern[bp++] = '0';
bp = z_bin_append_posn(0x3FA29, 18, pattern, bp);
} else {
pattern[bp++] = '1';
}
for (loop = 0; loop < bp; loop++) {
if (pattern[loop] == '1') {
z_set_module(symbol, i, loop);
}
}
}
symbol->width = bp;
symbol->rows = rows;
if (error_number) {
(void) z_set_height(symbol, 3.0f, 0.0f, 0.0f, 1 );
} else {
error_number = z_set_height(symbol, 3.0f, 0.0f, 0.0f, 0 );
}
return error_number;
}
INTERNAL int zint_pdf417(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
int codeerr, error_number;
error_number = 0;
if (symbol->option_1 < -1 || symbol->option_1 > 8) {
z_errtxtf(0, symbol, 460, "Error correction level '%d' out of range (0 to 8)", symbol->option_1);
if (symbol->warn_level == WARN_FAIL_ALL) {
return ZINT_ERROR_INVALID_OPTION;
}
error_number = z_errtxt_adj(ZINT_WARN_INVALID_OPTION, symbol, "%1$s%2$s", ", ignoring");
symbol->option_1 = -1;
}
if (symbol->option_2 < 0 || symbol->option_2 > 30) {
z_errtxtf(0, symbol, 461, "Number of columns '%d' out of range (1 to 30)", symbol->option_2);
if (symbol->warn_level == WARN_FAIL_ALL) {
return ZINT_ERROR_INVALID_OPTION;
}
error_number = z_errtxt_adj(ZINT_WARN_INVALID_OPTION, symbol, "%1$s%2$s", ", ignoring");
symbol->option_2 = 0;
}
if (symbol->option_3 && (symbol->option_3 < 3 || symbol->option_3 > 90)) {
return z_errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 466, "Number of rows '%d' out of range (3 to 90)",
symbol->option_3);
}
if (symbol->option_2 && symbol->option_3 && symbol->option_2 * symbol->option_3 > 928) {
return z_errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 475, "Columns x rows value '%d' out of range (1 to 928)",
symbol->option_2 * symbol->option_3);
}
codeerr = pdf_enc(symbol, segs, seg_count);
if (codeerr != 0) {
error_number = codeerr;
}
return error_number;
}
INTERNAL int zint_micropdf417(struct zint_symbol *symbol, struct zint_seg segs[], const int seg_count) {
int i, k, j, longueur, mccorrection[50] = {0}, offset;
int ecc_cwds;
int total, mclength, error_number = 0;
short chainemc[PDF_MAX_STREAM_LEN];
char pattern[580];
int bp = 0;
int structapp_cws[18] = {0};
int structapp_cp = 0;
int variant;
int LeftRAP, CentreRAP, RightRAP, Cluster, loop;
const int debug_print = symbol->debug & ZINT_DEBUG_PRINT;
static char col_max_codewords[5] = { 0, 20, 37, 82, 126 };
if ((i = z_segs_length(segs, seg_count)) > MICRO_PDF_MAX_LEN) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 474,
"Input length %d too long (maximum " MICRO_PDF_MAX_LEN_S ")", i);
}
if (symbol->option_3) {
return z_errtxt(ZINT_ERROR_INVALID_OPTION, symbol, 476, "Cannot specify rows for MicroPDF417");
}
if ((error_number = pdf_initial_segs(symbol, segs, seg_count, 1 , chainemc, &mclength, structapp_cws,
&structapp_cp))) {
assert(error_number >= ZINT_ERROR);
return error_number;
}
if (mclength + structapp_cp > 126) {
return z_errtxtf(ZINT_ERROR_TOO_LONG, symbol, 467, "Input too long, requires %d codewords (maximum 126)",
mclength + structapp_cp);
}
if (symbol->option_2 > 4) {
if (symbol->warn_level == WARN_FAIL_ALL) {
return z_errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 471, "Number of columns '%d' out of range (1 to 4)",
symbol->option_2);
}
error_number = z_errtxtf(ZINT_WARN_INVALID_OPTION, symbol, 468,
"Number of columns '%d' out of range (1 to 4), ignoring", symbol->option_2);
symbol->option_2 = 0;
}
if (debug_print) {
printf("\nEncoded Data Stream (%d):\n", mclength);
for (i = 0; i < mclength; i++) {
printf("%3d ", chainemc[i]);
}
fputc('\n', stdout);
}
variant = 0;
if (symbol->option_2 >= 1 && mclength + structapp_cp > col_max_codewords[symbol->option_2]) {
if (symbol->warn_level == WARN_FAIL_ALL) {
return ZEXT z_errtxtf(ZINT_ERROR_INVALID_OPTION, symbol, 469,
"Input too long for number of columns '%1$d', requires %2$d codewords (maximum %3$d)",
symbol->option_2, mclength + structapp_cp, col_max_codewords[symbol->option_2]);
}
error_number = z_errtxtf(ZINT_WARN_INVALID_OPTION, symbol, 470,
"Input too long for number of columns '%d', ignoring", symbol->option_2);
symbol->option_2 = 0;
}
if (symbol->option_2 == 1) {
if (mclength + structapp_cp <= 4) {
variant = 1;
} else if (mclength + structapp_cp <= 7) {
variant = 2;
} else if (mclength + structapp_cp <= 10) {
variant = 3;
} else if (mclength + structapp_cp <= 12) {
variant = 4;
} else if (mclength + structapp_cp <= 16) {
variant = 5;
} else {
variant = 6;
}
} else if (symbol->option_2 == 2) {
if (mclength + structapp_cp <= 8) {
variant = 7;
} else if (mclength + structapp_cp <= 13) {
variant = 8;
} else if (mclength + structapp_cp <= 19) {
variant = 9;
} else if (mclength + structapp_cp <= 24) {
variant = 10;
} else if (mclength + structapp_cp <= 29) {
variant = 11;
} else if (mclength + structapp_cp <= 33) {
variant = 12;
} else {
variant = 13;
}
} else if (symbol->option_2 == 3) {
if (mclength + structapp_cp <= 6) {
variant = 14;
} else if (mclength + structapp_cp <= 10) {
variant = 15;
} else if (mclength + structapp_cp <= 14) {
variant = 16;
} else if (mclength + structapp_cp <= 18) {
variant = 17;
} else if (mclength + structapp_cp <= 24) {
variant = 18;
} else if (mclength + structapp_cp <= 34) {
variant = 19;
} else if (mclength + structapp_cp <= 46) {
variant = 20;
} else if (mclength + structapp_cp <= 58) {
variant = 21;
} else if (mclength + structapp_cp <= 70) {
variant = 22;
} else {
variant = 23;
}
} else if (symbol->option_2 == 4) {
if (mclength + structapp_cp <= 8) {
variant = 24;
} else if (mclength + structapp_cp <= 12) {
variant = 25;
} else if (mclength + structapp_cp <= 18) {
variant = 26;
} else if (mclength + structapp_cp <= 24) {
variant = 27;
} else if (mclength + structapp_cp <= 30) {
variant = 28;
} else if (mclength + structapp_cp <= 39) {
variant = 29;
} else if (mclength + structapp_cp <= 54) {
variant = 30;
} else if (mclength + structapp_cp <= 72) {
variant = 31;
} else if (mclength + structapp_cp <= 90) {
variant = 32;
} else if (mclength + structapp_cp <= 108) {
variant = 33;
} else {
variant = 34;
}
} else {
for (i = 27; i >= 0; i--) {
if (pdf_MicroAutosize[i] >= mclength + structapp_cp) {
variant = pdf_MicroAutosize[i + 28];
} else {
break;
}
}
}
assert(variant > 0);
variant--;
symbol->option_2 = zint_pdf_MicroVariants[variant];
symbol->rows = zint_pdf_MicroVariants[variant + 34];
ecc_cwds = zint_pdf_MicroVariants[variant + 68];
longueur = (symbol->option_2 * symbol->rows) - ecc_cwds;
i = longueur - (mclength + structapp_cp);
offset = zint_pdf_MicroVariants[variant + 102];
symbol->option_1 = ((int) z_stripf(roundf(z_stripf(ecc_cwds * 100.0f / (longueur + ecc_cwds))))) << 8;
if (debug_print) {
fputs("\nChoose symbol size:\n", stdout);
printf("%d columns x %d rows, variant %d\n", symbol->option_2, symbol->rows, variant + 1);
printf("%d data codewords (including %d pads), %d ecc codewords\n", longueur, i, ecc_cwds);
fputc('\n', stdout);
}
while (i-- > 0) {
chainemc[mclength++] = 900;
}
if (structapp_cp) {
for (i = 0; i < structapp_cp; i++) {
chainemc[mclength++] = structapp_cws[i];
}
}
longueur = mclength;
for (i = 0; i < longueur; i++) {
total = (chainemc[i] + mccorrection[ecc_cwds - 1]) % 929;
for (j = ecc_cwds - 1; j >= 0; j--) {
if (j == 0) {
mccorrection[j] = (929 - (total * zint_pdf_Microcoeffs[offset + j]) % 929) % 929;
} else {
mccorrection[j] = (mccorrection[j - 1] + 929 - (total * zint_pdf_Microcoeffs[offset + j]) % 929)
% 929;
}
}
}
for (j = 0; j < ecc_cwds; j++) {
if (mccorrection[j] != 0) {
mccorrection[j] = 929 - mccorrection[j];
}
}
for (i = ecc_cwds - 1; i >= 0; i--) {
chainemc[mclength++] = mccorrection[i];
}
if (debug_print) {
printf("Encoded Data Stream with ECC (%d):\n", mclength);
for (i = 0; i < mclength; i++) {
printf("%3d ", chainemc[i]);
}
fputc('\n', stdout);
}
#ifdef ZINT_TEST
if (symbol->debug & ZINT_DEBUG_TEST) {
z_debug_test_codeword_dump_short(symbol, chainemc, mclength);
}
#endif
LeftRAP = zint_pdf_RAPTable[variant];
CentreRAP = zint_pdf_RAPTable[variant + 34];
RightRAP = zint_pdf_RAPTable[variant + 68];
Cluster = zint_pdf_RAPTable[variant + 102] / 3;
if (debug_print) fputs("\nInternal row representation:\n", stdout);
for (i = 0; i < symbol->rows; i++) {
if (debug_print) printf("row %d: ", i);
bp = 0;
offset = 929 * Cluster;
k = i * symbol->option_2;
bp = z_bin_append_posn(zint_pdf_rap_side[LeftRAP - 1], 10, pattern, bp);
bp = z_bin_append_posn(zint_pdf_bitpattern[offset + chainemc[k]], 16, pattern, bp);
pattern[bp++] = '0';
if (symbol->option_2 >= 2) {
if (symbol->option_2 == 3) {
bp = z_bin_append_posn(zint_pdf_rap_centre[CentreRAP - 1], 10, pattern, bp);
}
bp = z_bin_append_posn(zint_pdf_bitpattern[offset + chainemc[k + 1]], 16, pattern, bp);
pattern[bp++] = '0';
if (symbol->option_2 >= 3) {
if (symbol->option_2 == 4) {
bp = z_bin_append_posn(zint_pdf_rap_centre[CentreRAP - 1], 10, pattern, bp);
}
bp = z_bin_append_posn(zint_pdf_bitpattern[offset + chainemc[k + 2]], 16, pattern, bp);
pattern[bp++] = '0';
if (symbol->option_2 == 4) {
bp = z_bin_append_posn(zint_pdf_bitpattern[offset + chainemc[k + 3]], 16, pattern, bp);
pattern[bp++] = '0';
}
}
}
bp = z_bin_append_posn(zint_pdf_rap_side[RightRAP - 1], 10, pattern, bp);
pattern[bp++] = '1';
if (debug_print) printf("%.*s\n", bp, pattern);
for (loop = 0; loop < bp; loop++) {
if (pattern[loop] == '1') {
z_set_module(symbol, i, loop);
}
}
LeftRAP++;
CentreRAP++;
RightRAP++;
Cluster++;
if (LeftRAP == 53) {
LeftRAP = 1;
}
if (CentreRAP == 53) {
CentreRAP = 1;
}
if (RightRAP == 53) {
RightRAP = 1;
}
if (Cluster == 3) {
Cluster = 0;
}
}
symbol->width = bp;
if (error_number) {
(void) z_set_height(symbol, 2.0f, 0.0f, 0.0f, 1 );
} else {
error_number = z_set_height(symbol, 2.0f, 0.0f, 0.0f, 0 );
}
return error_number;
}
#undef T_ALPHA
#undef T_LOWER
#undef T_MIXED
#undef T_PUNCT
#undef T_ALWMX
#undef T_MXPNC