mirror of
https://github.com/zint/zint
synced 2024-11-16 20:57:25 +13:00
Ultracode: Add error correction
This commit is contained in:
parent
7216202f06
commit
77c8e76bfa
177
backend/ultra.c
177
backend/ultra.c
@ -44,6 +44,8 @@
|
|||||||
|
|
||||||
#define PREDICT_WINDOW 12
|
#define PREDICT_WINDOW 12
|
||||||
|
|
||||||
|
#define GFMUL(i, j) ((((i) == 0)||((j) == 0)) ? 0 : gfPwr[(gfLog[i] + gfLog[j])])
|
||||||
|
|
||||||
static const char fragment[27][14] = {"http://", "https://", "http://www.", "https://www.",
|
static const char fragment[27][14] = {"http://", "https://", "http://www.", "https://www.",
|
||||||
"ftp://", "www.", ".com", ".edu", ".gov", ".int", ".mil", ".net", ".org",
|
"ftp://", "www.", ".com", ".edu", ".gov", ".int", ".mil", ".net", ".org",
|
||||||
".mobi", ".coop", ".biz", ".info", "mailto:", "tel:", ".cgi", ".asp",
|
".mobi", ".coop", ".biz", ".info", "mailto:", "tel:", ".cgi", ".asp",
|
||||||
@ -54,6 +56,86 @@ static const char ultra_c43_set2[] = "abcdefghijklmnopqrstuvwxyz:/?#[]@=_~!.,-";
|
|||||||
static const char ultra_c43_set3[] = "{}`()\"+'<>|$;&\\^*";
|
static const char ultra_c43_set3[] = "{}`()\"+'<>|$;&\\^*";
|
||||||
static const char ultra_digit[] = "0123456789,/";
|
static const char ultra_digit[] = "0123456789,/";
|
||||||
|
|
||||||
|
/* The following adapted from ECC283.C "RSEC codeword generator"
|
||||||
|
* from Annex B of Ultracode draft
|
||||||
|
* originally written by Ted Williams of Symbol Vision Corp.
|
||||||
|
* Dated 2001-03-09
|
||||||
|
* Corrected thanks to input from Terry Burton */
|
||||||
|
|
||||||
|
/* Generate divisor polynomial gQ(x) for GF283() given the required ECC size, 3 to 101 */
|
||||||
|
void ultra_genPoly(short EccSize, unsigned short gPoly[], unsigned short gfPwr[], unsigned short gfLog[]) {
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
gPoly[0] = 1;
|
||||||
|
for (i = 1; i < (EccSize + 1); i++) gPoly[i] = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < EccSize; i++) {
|
||||||
|
for (j = i; j >= 0; j--)
|
||||||
|
gPoly[j + 1] = (gPoly[j] + GFMUL(gPoly[j + 1], gfPwr[i + 1])) % 283;
|
||||||
|
gPoly[0] = GFMUL(gPoly[0], gfPwr[i + 1]);
|
||||||
|
}
|
||||||
|
for (i = EccSize - 1; i >= 0; i -= 2) gPoly[i] = 283 - gPoly[i];
|
||||||
|
|
||||||
|
/* gPoly[i] is > 0 so modulo operation not needed */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Generate the log and antilog tables for GF283() multiplication & division */
|
||||||
|
void ultra_initLogTables(unsigned short gfPwr[], unsigned short gfLog[]) {
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
for (j = 0; j < 283; j++) gfLog[j] = 0;
|
||||||
|
i = 1;
|
||||||
|
for (j = 0; j < 282; j++) {
|
||||||
|
/* j + 282 indicies save doing the modulo operation in GFMUL */
|
||||||
|
gfPwr[j + 282] = gfPwr[j] = (short) i;
|
||||||
|
gfLog[i] = (short) j;
|
||||||
|
i = (i * 3) % 283;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ultra_gf283(short DataSize, short EccSize, int Message[]) {
|
||||||
|
/* Input is complete message codewords in array Message[282]
|
||||||
|
* DataSize is number of message codewords
|
||||||
|
* EccSize is number of Reed-Solomon GF(283) check codewords to generate
|
||||||
|
*
|
||||||
|
* Upon exit, Message[282] contains complete 282 codeword Symbol Message
|
||||||
|
* including leading zeroes corresponding to each truncated codeword */
|
||||||
|
|
||||||
|
unsigned short gPoly[283], gfPwr[(282 * 2)], gfLog[283];
|
||||||
|
int i, j, n;
|
||||||
|
unsigned short t;
|
||||||
|
|
||||||
|
/* first build the log & antilog tables used in multiplication & division */
|
||||||
|
ultra_initLogTables(gfPwr, gfLog);
|
||||||
|
|
||||||
|
/* then generate the division polynomial of length EccSize */
|
||||||
|
ultra_genPoly(EccSize, gPoly, gfPwr, gfLog);
|
||||||
|
|
||||||
|
/* zero all EccSize codeword values */
|
||||||
|
for (j = 281; (j > (281 - EccSize)); j--) Message[j] = 0;
|
||||||
|
|
||||||
|
/* shift message codewords to the right, leave space for ECC checkwords */
|
||||||
|
for (i = DataSize - 1; (i >= 0); j--, i--) Message[j] = Message[i];
|
||||||
|
|
||||||
|
/* add zeroes to pad left end Message[] for truncated codewords */
|
||||||
|
j++;
|
||||||
|
for (i = 0; i < j; i++) Message[i] = 0;
|
||||||
|
|
||||||
|
/* generate (EccSize) Reed-Solomon checkwords */
|
||||||
|
for (n = j; n < (j + DataSize); n++) {
|
||||||
|
t = (Message[j + DataSize] + Message[n]) % 283;
|
||||||
|
for (i = 0; i < (EccSize - 1); i++) {
|
||||||
|
Message[j + DataSize + i] = (Message[j + DataSize + i + 1] + 283
|
||||||
|
- GFMUL(t, gPoly[EccSize - 1 - i])) % 283;
|
||||||
|
}
|
||||||
|
Message[j + DataSize + EccSize - 1] = (283 - GFMUL(t, gPoly[0])) % 283;
|
||||||
|
}
|
||||||
|
for (i = j + DataSize; i < (j + DataSize + EccSize); i++)
|
||||||
|
Message[i] = (283 - Message[i]) % 283;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* End of Ted Williams code */
|
||||||
|
|
||||||
int ultra_find_fragment(unsigned char source[], int source_length, int position) {
|
int ultra_find_fragment(unsigned char source[], int source_length, int position) {
|
||||||
int retval = -1;
|
int retval = -1;
|
||||||
int j, k, latch;
|
int j, k, latch;
|
||||||
@ -543,8 +625,8 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou
|
|||||||
}
|
}
|
||||||
codeword_count++;
|
codeword_count++;
|
||||||
|
|
||||||
for (i = input_posn + 7; i < (in_length - 2); i++) {
|
for (i = 7; i < (in_length - 2); i++) {
|
||||||
crop_source[i - input_posn] = source[i];
|
crop_source[i - 7] = source[i];
|
||||||
}
|
}
|
||||||
crop_length = in_length - 9;
|
crop_length = in_length - 9;
|
||||||
crop_source[crop_length] = '\0';
|
crop_source[crop_length] = '\0';
|
||||||
@ -639,24 +721,36 @@ int ultra_generate_codewords(struct zint_symbol *symbol, const unsigned char sou
|
|||||||
|
|
||||||
int ultracode(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length) {
|
int ultracode(struct zint_symbol *symbol, const unsigned char source[], const size_t in_length) {
|
||||||
int data_cw_count = 0;
|
int data_cw_count = 0;
|
||||||
int ecc_cw;
|
int ecc_cw; // = Q in section 7.7.1
|
||||||
int ecc_level; // = Q in section 7.7.1
|
int ecc_level;
|
||||||
int misdecode_cw; // = P in section 7.7.1
|
int misdecode_cw; // = P in section 7.7.1
|
||||||
|
int rows, columns;
|
||||||
|
int total_cws;
|
||||||
|
int pads;
|
||||||
|
int cw_memalloc;
|
||||||
|
int codeword[283];
|
||||||
|
int i, posn;
|
||||||
|
int acc;
|
||||||
|
|
||||||
|
cw_memalloc = in_length * 2;
|
||||||
|
if (cw_memalloc < 283) {
|
||||||
|
cw_memalloc = 283;
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef _MSC_VER
|
#ifndef _MSC_VER
|
||||||
int data_codewords[in_length * 2];
|
int data_codewords[cw_memalloc];
|
||||||
#else
|
#else
|
||||||
int* data_codewords = (int *) _alloca(in_length * 2 * sizeof (int));
|
int* data_codewords = (int *) _alloca(cw_memalloc * sizeof (int));
|
||||||
#endif /* _MSC_VER */
|
#endif /* _MSC_VER */
|
||||||
|
|
||||||
data_cw_count = ultra_generate_codewords(symbol, source, in_length, data_codewords);
|
data_cw_count = ultra_generate_codewords(symbol, source, in_length, data_codewords);
|
||||||
|
|
||||||
printf("Codewords returned = %d\n", data_cw_count);
|
//printf("Codewords returned = %d\n", data_cw_count);
|
||||||
|
|
||||||
for (int i = 0; i < data_cw_count; i++) {
|
//for (int i = 0; i < data_cw_count; i++) {
|
||||||
printf("%d ", data_codewords[i]);
|
// printf("%d ", data_codewords[i]);
|
||||||
}
|
//}
|
||||||
printf("\n");
|
//printf("\n");
|
||||||
|
|
||||||
/* Default ECC level is EC2 */
|
/* Default ECC level is EC2 */
|
||||||
if ((symbol->option_1 <= 0) || (symbol->option_1 > 6)) {
|
if ((symbol->option_1 <= 0) || (symbol->option_1 > 6)) {
|
||||||
@ -678,7 +772,7 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si
|
|||||||
ecc_cw = (ecc_level * ((data_cw_count / 25) + 1)) + misdecode_cw + 2;
|
ecc_cw = (ecc_level * ((data_cw_count / 25) + 1)) + misdecode_cw + 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("ECC codewords: %d\n", ecc_cw);
|
//printf("ECC codewords: %d\n", ecc_cw);
|
||||||
|
|
||||||
/* Maximum capacity is 282 codewords */
|
/* Maximum capacity is 282 codewords */
|
||||||
if (data_cw_count + ecc_cw > 282) {
|
if (data_cw_count + ecc_cw > 282) {
|
||||||
@ -686,6 +780,65 @@ int ultracode(struct zint_symbol *symbol, const unsigned char source[], const si
|
|||||||
return ZINT_ERROR_TOO_LONG;
|
return ZINT_ERROR_TOO_LONG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
total_cws = data_cw_count + ecc_cw;
|
||||||
|
|
||||||
|
rows = 5;
|
||||||
|
if (total_cws < 164) {
|
||||||
|
rows = 4;
|
||||||
|
}
|
||||||
|
if (total_cws < 84) {
|
||||||
|
rows = 3;
|
||||||
|
}
|
||||||
|
if (total_cws < 40) {
|
||||||
|
rows = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((total_cws % rows) == 0) {
|
||||||
|
pads = 0;
|
||||||
|
columns = total_cws / rows;
|
||||||
|
} else {
|
||||||
|
pads = rows - (total_cws % rows);
|
||||||
|
columns = (total_cws + pads) / rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Calculated size is %d rows by %d columns\n", rows, columns);
|
||||||
|
|
||||||
|
acc = ecc_cw - misdecode_cw; // ACC = (Q-P) - section 6.11.6
|
||||||
|
|
||||||
|
/* Insert MCC and ACC into data codewords */
|
||||||
|
for (i = 282; i > 2; i--) {
|
||||||
|
data_codewords[i] = data_codewords[i - 2];
|
||||||
|
}
|
||||||
|
data_codewords[1] = data_cw_count += 2; // MCC
|
||||||
|
data_codewords[2] = acc; // ACC
|
||||||
|
|
||||||
|
/* Calculate error correction codewords (RSEC) */
|
||||||
|
ultra_gf283((short) data_cw_count, (short) ecc_cw, data_codewords);
|
||||||
|
|
||||||
|
/* Rearrange to make final codeword sequence */
|
||||||
|
posn = 0;
|
||||||
|
codeword[posn++] = data_codewords[282 - (data_cw_count + ecc_cw)]; // Start Character
|
||||||
|
codeword[posn++] = data_cw_count; // MCC
|
||||||
|
for (i = 0; i < ecc_cw; i++) {
|
||||||
|
codeword[posn++] = data_codewords[(282 - ecc_cw) + i]; // RSEC Region
|
||||||
|
}
|
||||||
|
codeword[posn++] = data_cw_count + ecc_cw; // TCC = C + Q - section 6.11.4
|
||||||
|
codeword[posn++] = 283; // Separator
|
||||||
|
codeword[posn++] = acc; // ACC
|
||||||
|
for (i = 0; i < (data_cw_count - 3); i++) {
|
||||||
|
codeword[posn++] = data_codewords[(282 - ((data_cw_count - 3) + ecc_cw)) + i]; // Data Region
|
||||||
|
}
|
||||||
|
for (i = 0; i < pads; i++) {
|
||||||
|
codeword[posn++] = 284; // Pad pattern
|
||||||
|
}
|
||||||
|
codeword[posn++] = ecc_cw; // QCC
|
||||||
|
|
||||||
|
printf("Rearranged codewords with ECC:\n");
|
||||||
|
for (i = 0; i < posn; i++) {
|
||||||
|
printf("%d ", codeword[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
strcpy(symbol->errtxt, "1000: Ultracode has not been implemented - yet!");
|
strcpy(symbol->errtxt, "1000: Ultracode has not been implemented - yet!");
|
||||||
return ZINT_ERROR_INVALID_OPTION;
|
return ZINT_ERROR_INVALID_OPTION;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user