zint/backend/dm200.c

912 lines
25 KiB
C
Raw Normal View History

2008-07-14 09:15:55 +12:00
/**
*
* IEC16022 bar code generation
* Adrian Kennard, Andrews & Arnold Ltd
* with help from Cliff Hones on the RS coding
*
* (c) 2004 Adrian Kennard, Andrews & Arnold Ltd
* (c) 2006 Stefan Schmidt <stefan@datenfreihafen.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "reedsol.h"
2008-10-09 06:06:16 +13:00
#include "common.h"
2008-07-14 09:15:55 +12:00
#include "dm200.h"
static struct ecc200matrix_s {
int H, W;
int FH, FW;
int bytes;
int datablock, rsblock;
} ecc200matrix[] = {
2008-10-07 08:17:07 +13:00
{10, 10, 10, 10, 3, 3, 5},
{12, 12, 12, 12, 5, 5, 7},
{8, 18, 8, 18, 5, 5, 7},
{14, 14, 14, 14, 8, 8, 10},
{8, 32, 8, 16, 10, 10, 11},
{16, 16, 16, 16, 12, 12, 12},
{12, 26, 12, 26, 16, 16, 14},
{18, 18, 18, 18, 18, 18, 14},
{20, 20, 20, 20, 22, 22, 18},
{12, 36, 12, 18, 22, 22, 18},
{22, 22, 22, 22, 30, 30, 20},
{16, 36, 16, 18, 32, 32, 24},
{24, 24, 24, 24, 36, 36, 24},
{26, 26, 26, 26, 44, 44, 28},
{16, 48, 16, 24, 49, 49, 28},
{32, 32, 16, 16, 62, 62, 36},
{36, 36, 18, 18, 86, 86, 42},
{40, 40, 20, 20, 114, 114, 48},
{44, 44, 22, 22, 144, 144, 56},
{48, 48, 24, 24, 174, 174, 68},
{52, 52, 26, 26, 204, 102, 42},
{64, 64, 16, 16, 280, 140, 56},
{72, 72, 18, 18, 368, 92, 36},
{80, 80, 20, 20, 456, 114, 48},
{88, 88, 22, 22, 576, 144, 56},
{96, 96, 24, 24, 696, 174, 68},
{104, 104, 26, 26, 816, 136, 56},
{120, 120, 20, 20, 1050, 175, 68},
{132, 132, 22, 22, 1304, 163, 62},
{144, 144, 24, 24, 1558, 156, 62}, /* 156*4+155*2 */
{0}
2008-07-14 09:15:55 +12:00
};
// simple checked response malloc
static void *safemalloc(int n)
{
void *p = malloc(n);
if (!p) {
fprintf(stderr, "Malloc(%d) failed\n", n);
exit(1);
}
return p;
}
// Annex M placement alorithm low level
2008-10-05 18:51:58 +13:00
static void ecc200placementbit(int *array, int NR, int NC, int r, int c, int p, char b)
2008-07-14 09:15:55 +12:00
{
if (r < 0) {
r += NR;
c += 4 - ((NR + 4) % 8);
}
if (c < 0) {
c += NC;
r += 4 - ((NC + 4) % 8);
}
array[r * NC + c] = (p << 3) + b;
}
static void ecc200placementblock(int *array, int NR, int NC, int r,
int c, int p)
{
ecc200placementbit(array, NR, NC, r - 2, c - 2, p, 7);
ecc200placementbit(array, NR, NC, r - 2, c - 1, p, 6);
ecc200placementbit(array, NR, NC, r - 1, c - 2, p, 5);
ecc200placementbit(array, NR, NC, r - 1, c - 1, p, 4);
ecc200placementbit(array, NR, NC, r - 1, c - 0, p, 3);
ecc200placementbit(array, NR, NC, r - 0, c - 2, p, 2);
ecc200placementbit(array, NR, NC, r - 0, c - 1, p, 1);
ecc200placementbit(array, NR, NC, r - 0, c - 0, p, 0);
}
static void ecc200placementcornerA(int *array, int NR, int NC, int p)
{
ecc200placementbit(array, NR, NC, NR - 1, 0, p, 7);
ecc200placementbit(array, NR, NC, NR - 1, 1, p, 6);
ecc200placementbit(array, NR, NC, NR - 1, 2, p, 5);
ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4);
ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3);
ecc200placementbit(array, NR, NC, 1, NC - 1, p, 2);
ecc200placementbit(array, NR, NC, 2, NC - 1, p, 1);
ecc200placementbit(array, NR, NC, 3, NC - 1, p, 0);
}
static void ecc200placementcornerB(int *array, int NR, int NC, int p)
{
ecc200placementbit(array, NR, NC, NR - 3, 0, p, 7);
ecc200placementbit(array, NR, NC, NR - 2, 0, p, 6);
ecc200placementbit(array, NR, NC, NR - 1, 0, p, 5);
ecc200placementbit(array, NR, NC, 0, NC - 4, p, 4);
ecc200placementbit(array, NR, NC, 0, NC - 3, p, 3);
ecc200placementbit(array, NR, NC, 0, NC - 2, p, 2);
ecc200placementbit(array, NR, NC, 0, NC - 1, p, 1);
ecc200placementbit(array, NR, NC, 1, NC - 1, p, 0);
}
static void ecc200placementcornerC(int *array, int NR, int NC, int p)
{
ecc200placementbit(array, NR, NC, NR - 3, 0, p, 7);
ecc200placementbit(array, NR, NC, NR - 2, 0, p, 6);
ecc200placementbit(array, NR, NC, NR - 1, 0, p, 5);
ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4);
ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3);
ecc200placementbit(array, NR, NC, 1, NC - 1, p, 2);
ecc200placementbit(array, NR, NC, 2, NC - 1, p, 1);
ecc200placementbit(array, NR, NC, 3, NC - 1, p, 0);
}
static void ecc200placementcornerD(int *array, int NR, int NC, int p)
{
ecc200placementbit(array, NR, NC, NR - 1, 0, p, 7);
ecc200placementbit(array, NR, NC, NR - 1, NC - 1, p, 6);
ecc200placementbit(array, NR, NC, 0, NC - 3, p, 5);
ecc200placementbit(array, NR, NC, 0, NC - 2, p, 4);
ecc200placementbit(array, NR, NC, 0, NC - 1, p, 3);
ecc200placementbit(array, NR, NC, 1, NC - 3, p, 2);
ecc200placementbit(array, NR, NC, 1, NC - 2, p, 1);
ecc200placementbit(array, NR, NC, 1, NC - 1, p, 0);
}
// Annex M placement alorithm main function
static void ecc200placement(int *array, int NR, int NC)
{
int r, c, p;
// invalidate
for (r = 0; r < NR; r++)
for (c = 0; c < NC; c++)
array[r * NC + c] = 0;
// start
p = 1;
r = 4;
c = 0;
do {
// check corner
if (r == NR && !c)
ecc200placementcornerA(array, NR, NC, p++);
if (r == NR - 2 && !c && NC % 4)
ecc200placementcornerB(array, NR, NC, p++);
if (r == NR - 2 && !c && (NC % 8) == 4)
ecc200placementcornerC(array, NR, NC, p++);
if (r == NR + 4 && c == 2 && !(NC % 8))
ecc200placementcornerD(array, NR, NC, p++);
// up/right
do {
if (r < NR && c >= 0 && !array[r * NC + c])
ecc200placementblock(array, NR, NC, r, c, p++);
r -= 2;
c += 2;
}
while (r >= 0 && c < NC);
r++;
c += 3;
// down/left
do {
if (r >= 0 && c < NC && !array[r * NC + c])
ecc200placementblock(array, NR, NC, r, c, p++);
r += 2;
c -= 2;
}
while (r < NR && c >= 0);
r += 3;
c++;
}
while (r < NR || c < NC);
// unfilled corner
if (!array[NR * NC - 1])
array[NR * NC - 1] = array[NR * NC - NC - 2] = 1;
}
// calculate and append ecc code, and if necessary interleave
static void ecc200(unsigned char *binary, int bytes, int datablock, int rsblock)
{
int blocks = (bytes + 2) / datablock, b;
rs_init_gf(0x12d);
rs_init_code(rsblock, 1);
for (b = 0; b < blocks; b++) {
unsigned char buf[256], ecc[256];
int n, p = 0;
for (n = b; n < bytes; n += blocks)
buf[p++] = binary[n];
rs_encode(p, buf, ecc);
p = rsblock - 1; // comes back reversed
for (n = b; n < rsblock * blocks; n += blocks)
binary[bytes + n] = ecc[p--];
}
2008-10-13 07:52:54 +13:00
rs_free();
2008-07-14 09:15:55 +12:00
}
/*
* perform encoding for ecc200, source s len sl, to target t len tl, using
* optional encoding control string e return 1 if OK, 0 if failed. Does all
* necessary padding to tl
*/
2008-10-05 18:51:58 +13:00
char ecc200encode(unsigned char *t, int tl, unsigned char *s, int sl, char *encoding, int *lenp)
2008-07-14 09:15:55 +12:00
{
char enc = 'a'; // start in ASCII encoding mode
int tp = 0, sp = 0;
if (strlen(encoding) < sl) {
fprintf(stderr, "Encoding string too short\n");
return 0;
}
2008-10-13 07:52:54 +13:00
2008-07-14 09:15:55 +12:00
// do the encoding
while (sp < sl && tp < tl) {
char newenc = enc; // suggest new encoding
2008-10-07 07:50:36 +13:00
if ((tl - tp <= 1 && (enc == 'c' || enc == 't')) || (tl - tp <= 2 && enc == 'x'))
2008-07-14 09:15:55 +12:00
enc = 'a'; // auto revert to ASCII
newenc = tolower(encoding[sp]);
switch (newenc) { // encode character
case 'c': // C40
case 't': // Text
case 'x': // X12
{
2008-10-03 22:49:03 +13:00
char out[6];
int p = 0;
const char *e=0,
2008-07-14 09:15:55 +12:00
*s2 = "!\"#$%&'()*+,-./:;<=>?@[\\]_",
*s3 = 0;
if (newenc == 'c') {
e = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
s3 = "`abcdefghijklmnopqrstuvwxyz{|}~\177";
}
if (newenc == 't') {
e = " 0123456789abcdefghijklmnopqrstuvwxyz";
s3 = "`ABCDEFGHIJKLMNOPQRSTUVWXYZ{|}~\177";
}
if (newenc == 'x')
e = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ\r*>";
2008-10-03 22:49:03 +13:00
if (!e)
break;
2008-07-14 09:15:55 +12:00
do {
unsigned char c = s[sp++];
char *w;
if (c & 0x80) {
if (newenc == 'x') {
2008-10-05 18:51:58 +13:00
fprintf(stderr, "Cannot encode char 0x%02X in X12\n", c);
2008-07-14 09:15:55 +12:00
return 0;
}
c &= 0x7f;
2008-10-05 18:51:58 +13:00
out[(int)p++] = 1;
out[(int)p++] = 30;
2008-07-14 09:15:55 +12:00
}
w = strchr(e, c);
if (w)
2008-10-05 18:51:58 +13:00
out[(int)p++] = ((w - e) + 3) % 40;
2008-07-14 09:15:55 +12:00
else {
if (newenc == 'x') {
2008-10-05 18:51:58 +13:00
fprintf(stderr, "Cannot encode char 0x%02X in X12\n", c);
2008-07-14 09:15:55 +12:00
return 0;
}
if (c < 32) { // shift 1
2008-10-05 18:51:58 +13:00
out[(int)p++] = 0;
out[(int)p++] = c;
2008-07-14 09:15:55 +12:00
} else {
w = strchr(s2, c);
if (w) { // shift 2
2008-10-05 18:51:58 +13:00
out[(int)p++] = 1;
out[(int)p++] = (w - s2);
2008-07-14 09:15:55 +12:00
} else {
2008-10-05 18:51:58 +13:00
w = strchr(s3, c);
2008-07-14 09:15:55 +12:00
if (w) {
2008-10-05 18:51:58 +13:00
out[(int)p++] = 2;
out[(int)p++] = (w - s3);
2008-07-14 09:15:55 +12:00
} else {
2008-10-05 18:51:58 +13:00
fprintf (stderr, "Could not encode 0x%02X, should not happen\n", c);
return 0;
2008-07-14 09:15:55 +12:00
}
}
}
}
2008-09-03 07:39:07 +12:00
if (p == 2 && tp + 2 <= tl && sp == sl)
2008-10-05 18:51:58 +13:00
out[(int)p++] = 0; // shift 1 pad at end
2008-07-14 09:15:55 +12:00
while (p >= 3) {
int v =
out[0] * 1600 +
out[1] * 40 + out[2] + 1;
if (enc != newenc) {
2008-10-05 18:51:58 +13:00
if (enc == 'c' || enc == 't' || enc == 'x')
2008-07-14 09:15:55 +12:00
t[tp++] = 254; // escape C40/text/X12
else if (enc == 'x')
t[tp++] = 0x7C; // escape EDIFACT
if (newenc == 'c')
t[tp++] = 230;
if (newenc == 't')
t[tp++] = 239;
if (newenc == 'x')
t[tp++] = 238;
enc = newenc;
}
2009-01-03 10:09:16 +13:00
t[tp++] = (int)(v / 256);
t[tp++] = v % 256;
2008-07-14 09:15:55 +12:00
p -= 3;
out[0] = out[3];
out[1] = out[4];
out[2] = out[5];
}
}
while (p && sp < sl);
}
break;
case 'e': // EDIFACT
{
unsigned char out[4], p = 0;
if (enc != newenc) { // can only be from C40/Text/X12
t[tp++] = 254;
enc = 'a';
}
2008-10-05 18:51:58 +13:00
while (sp < sl && tolower(encoding[sp]) == 'e' && p < 4)
2008-07-14 09:15:55 +12:00
out[p++] = s[sp++];
if (p < 4) {
out[p++] = 0x1F;
enc = 'a';
} // termination
t[tp] = ((s[0] & 0x3F) << 2);
t[tp++] |= ((s[1] & 0x30) >> 4);
t[tp] = ((s[1] & 0x0F) << 4);
if (p == 2)
tp++;
else {
t[tp++] |= ((s[2] & 0x3C) >> 2);
t[tp] = ((s[2] & 0x03) << 6);
t[tp++] |= (s[3] & 0x3F);
}
}
break;
case 'a': // ASCII
if (enc != newenc) {
if (enc == 'c' || enc == 't' || enc == 'x')
t[tp++] = 254; // escape C40/text/X12
else
t[tp++] = 0x7C; // escape EDIFACT
}
enc = 'a';
2008-10-05 18:51:58 +13:00
if (sl - sp >= 2 && isdigit(s[sp]) && isdigit(s[sp + 1])) {
t[tp++] = (s[sp] - '0') * 10 + s[sp + 1] - '0' + 130;
2008-07-14 09:15:55 +12:00
sp += 2;
} else if (s[sp] > 127) {
t[tp++] = 235;
t[tp++] = s[sp++] - 127;
} else
t[tp++] = s[sp++] + 1;
break;
case 'b': // Binary
{
int l = 0; // how much to encode
if (encoding) {
int p;
2008-10-05 18:51:58 +13:00
for (p = sp; p < sl && tolower(encoding[p]) == 'b'; p++)
2008-07-14 09:15:55 +12:00
l++;
}
t[tp++] = 231; // base256
if (l < 250)
t[tp++] = l;
else {
t[tp++] = 249 + (l / 250);
t[tp++] = (l % 250);
}
while (l-- && tp < tl) {
t[tp] = s[sp++] + (((tp + 1) * 149) % 255) + 1; // see annex H
tp++;
}
enc = 'a'; // reverse to ASCII at end
}
break;
default:
fprintf(stderr, "Unknown encoding %c\n", newenc);
return 0; // failed
}
}
if (lenp)
*lenp = tp;
if (tp < tl && enc != 'a') {
if (enc == 'c' || enc == 'x' || enc == 't')
t[tp++] = 254; // escape X12/C40/Text
else
t[tp++] = 0x7C; // escape EDIFACT
}
if (tp < tl)
t[tp++] = 129; // pad
while (tp < tl) { // more padding
int v = 129 + (((tp + 1) * 149) % 253) + 1; // see Annex H
if (v > 254)
v -= 254;
t[tp++] = v;
}
if (tp > tl || sp < sl)
return 0; // did not fit
/*
* for (tp = 0; tp < tl; tp++) fprintf (stderr, "%02X ", t[tp]); \
* fprintf (stderr, "\n");
*/
return 1; // OK
}
// Auto encoding format functions
static char encchr[] = "ACTXEB";
enum {
E_ASCII,
E_C40,
E_TEXT,
E_X12,
E_EDIFACT,
E_BINARY,
E_MAX
};
unsigned char switchcost[E_MAX][E_MAX] = {
2008-10-07 08:17:07 +13:00
{0, 1, 1, 1, 1, 2}, // From E_ASCII
{1, 0, 2, 2, 2, 3}, // From E_C40
{1, 2, 0, 2, 2, 3}, // From E_TEXT
{1, 2, 2, 0, 2, 3}, // From E_X12
{1, 2, 2, 2, 0, 3}, // From E_EDIFACT
{0, 1, 1, 1, 1, 0}, // From E_BINARY
2008-07-14 09:15:55 +12:00
};
/*
* Creates a encoding list (malloc)
* returns encoding string
* if lenp not null, target len stored
* if error, null returned
* if exact specified, then assumes shortcuts applicable for exact fit
* in target
* 1. No unlatch to return to ASCII for last encoded byte after C40 or
* Text or X12
* 2. No unlatch to return to ASCII for last 1 or 2 encoded bytes after
* EDIFACT
* 3. Final C40 or text encoding exactly in last 2 bytes can have a shift
* 0 to pad to make a tripple
* Only use the encoding from an exact request if the len matches the target,
* otherwise free the result and try again with exact=0
*/
static char *encmake(int l, unsigned char *s, int *lenp, char exact)
{
char *encoding = 0;
int p = l;
2008-10-03 22:49:03 +13:00
int e;
2008-07-14 09:15:55 +12:00
struct {
// number of bytes of source that can be encoded in a row at this point
// using this encoding mode
short s;
// number of bytes of target generated encoding from this point to end if
// already in this encoding mode
short t;
} enc[MAXBARCODE][E_MAX];
memset(&enc, 0, sizeof(enc));
if (!l)
return ""; // no length
if (l > MAXBARCODE)
return 0; // not valid
while (p--) {
2008-10-03 22:49:03 +13:00
char sub;
int b = 0, sl, tl, bl, t;
2008-07-14 09:15:55 +12:00
// consider each encoding from this point
// ASCII
sl = tl = 1;
if (isdigit(s[p]) && p + 1 < l && isdigit(s[p + 1]))
sl = 2; // double digit
else if (s[p] & 0x80)
tl = 2; // high shifted
bl = 0;
if (p + sl < l)
for (e = 0; e < E_MAX; e++)
2008-10-05 18:51:58 +13:00
if (enc[p + sl][(int)e].t && ((t = enc[p + sl][(int)e].t + switchcost[E_ASCII][(int)e]) < bl || !bl)) {
2008-07-14 09:15:55 +12:00
bl = t;
b = e;
}
enc[p][E_ASCII].t = tl + bl;
enc[p][E_ASCII].s = sl;
if (bl && b == E_ASCII)
2008-10-05 18:51:58 +13:00
enc[p][(int)b].s += enc[p + sl][(int)b].s;
2008-07-14 09:15:55 +12:00
// C40
sub = tl = sl = 0;
do {
unsigned char c = s[p + sl++];
if (c & 0x80) { // shift + upper
sub += 2;
c &= 0x7F;
}
if (c != ' ' && !isdigit(c) && !isupper(c))
sub++; // shift
sub++;
while (sub >= 3) {
sub -= 3;
tl += 2;
}
} while (sub && p + sl < l);
if (exact && sub == 2 && p + sl == l) {
// special case, can encode last block with shift 0 at end (Is this
// valid when not end of target buffer?)
sub = 0;
tl += 2;
}
if (!sub) { // can encode C40
bl = 0;
if (p + sl < l)
for (e = 0; e < E_MAX; e++)
2008-10-05 18:51:58 +13:00
if (enc[p + sl][(int)e].t && ((t = enc[p + sl][(int)e].t + switchcost[E_C40][(int)e]) < bl || !bl)) {
2008-07-14 09:15:55 +12:00
bl = t;
b = e;
}
if (exact && enc[p + sl][E_ASCII].t == 1 && 1 < bl) {
// special case, switch to ASCII for last bytes
bl = 1;
b = E_ASCII;
}
enc[p][E_C40].t = tl + bl;
enc[p][E_C40].s = sl;
if (bl && b == E_C40)
2008-10-05 18:51:58 +13:00
enc[p][(int)b].s += enc[p + sl][(int)b].s;
2008-07-14 09:15:55 +12:00
}
// Text
sub = tl = sl = 0;
do {
unsigned char c = s[p + sl++];
if (c & 0x80) { // shift + upper
sub += 2;
c &= 0x7F;
}
if (c != ' ' && !isdigit(c) && !islower(c))
sub++; // shift
sub++;
while (sub >= 3) {
sub -= 3;
tl += 2;
}
} while (sub && p + sl < l);
if (exact && sub == 2 && p + sl == l) {
// special case, can encode last block with shift 0 at end (Is this
// valid when not end of target buffer?)
sub = 0;
tl += 2;
}
if (!sub && sl) { // can encode Text
bl = 0;
if (p + sl < l)
for (e = 0; e < E_MAX; e++)
2008-10-05 18:51:58 +13:00
if (enc[p + sl][(int)e].t && ((t = enc[p + sl][(int)e].t + switchcost[E_TEXT][(int)e]) < bl || !bl)) {
2008-07-14 09:15:55 +12:00
bl = t;
b = e;
}
if (exact && enc[p + sl][E_ASCII].t == 1 && 1 < bl) { // special case, switch to ASCII for last bytes
bl = 1;
b = E_ASCII;
}
enc[p][E_TEXT].t = tl + bl;
enc[p][E_TEXT].s = sl;
if (bl && b == E_TEXT)
2008-10-05 18:51:58 +13:00
enc[p][(int)b].s += enc[p + sl][(int)b].s;
2008-07-14 09:15:55 +12:00
}
// X12
sub = tl = sl = 0;
do {
unsigned char c = s[p + sl++];
2008-10-05 18:51:58 +13:00
if (c != 13 && c != '*' && c != '>' && c != ' ' && !isdigit(c) && !isupper(c)) {
2008-07-14 09:15:55 +12:00
sl = 0;
break;
}
sub++;
while (sub >= 3) {
sub -= 3;
tl += 2;
}
} while (sub && p + sl < l);
if (!sub && sl) { // can encode X12
bl = 0;
if (p + sl < l)
for (e = 0; e < E_MAX; e++)
2008-10-05 18:51:58 +13:00
if (enc[p + sl][(int)e].t && ((t = enc[p + sl][(int)e].t + switchcost[E_X12][(int)e]) < bl || !bl)) {
2008-07-14 09:15:55 +12:00
bl = t;
b = e;
}
if (exact && enc[p + sl][E_ASCII].t == 1 && 1 < bl) {
// special case, switch to ASCII for last bytes
bl = 1;
b = E_ASCII;
}
enc[p][E_X12].t = tl + bl;
enc[p][E_X12].s = sl;
if (bl && b == E_X12)
2008-10-05 18:51:58 +13:00
enc[p][(int)b].s += enc[p + sl][(int)b].s;
2008-07-14 09:15:55 +12:00
}
// EDIFACT
sl = bl = 0;
if (s[p + 0] >= 32 && s[p + 0] <= 94) { // can encode 1
char bs = 0;
if (p + 1 == l && (!bl || bl < 2)) {
bl = 2;
bs = 1;
} else
for (e = 0; e < E_MAX; e++)
2008-10-05 18:51:58 +13:00
if (e != E_EDIFACT && enc[p + 1][(int)e].t && ((t = 2 + enc[p + 1][(int)e].t + switchcost[E_ASCII][(int)e]) < bl || !bl))
// E_ASCII as allowed for unlatch
2008-07-14 09:15:55 +12:00
{
bs = 1;
bl = t;
b = e;
}
if (p + 1 < l && s[p + 1] >= 32 && s[p + 1] <= 94) { // can encode 2
if (p + 2 == l && (!bl || bl < 2)) {
bl = 3;
bs = 2;
} else
for (e = 0; e < E_MAX; e++)
2008-10-05 18:51:58 +13:00
if (e != E_EDIFACT && enc[p + 2][(int)e].t && ((t = 3 + enc[p + 2][(int)e].t + switchcost[E_ASCII][(int)e]) < bl || !bl))
// E_ASCII as allowed for unlatch
2008-07-14 09:15:55 +12:00
{
bs = 2;
bl = t;
b = e;
}
if (p + 2 < l && s[p + 2] >= 32 && s[p + 2] <= 94) { // can encode 3
if (p + 3 == l && (!bl || bl < 3)) {
bl = 3;
bs = 3;
} else
for (e = 0; e < E_MAX; e++)
2008-10-05 18:51:58 +13:00
if (e != E_EDIFACT && enc[p + 3][(int)e].t && ((t = 3 + enc[p + 3][(int)e].t + switchcost [E_ASCII][(int)e]) < bl || !bl))
// E_ASCII as allowed for unlatch
2008-07-14 09:15:55 +12:00
{
bs = 3;
bl = t;
b = e;
}
if (p + 4 < l && s[p + 3] >= 32 && s[p + 3] <= 94) { // can encode 4
2008-10-05 18:51:58 +13:00
if (p + 4 == l && (!bl || bl < 3)) {
2008-07-14 09:15:55 +12:00
bl = 3;
bs = 4;
} else {
2008-10-05 18:51:58 +13:00
for (e = 0; e < E_MAX; e++)
if (enc[p + 4][(int)e].t && ((t = 3 + enc[p + 4][(int)e].t + switchcost [E_EDIFACT][(int)e]) < bl || !bl)) {
2008-07-14 09:15:55 +12:00
bs = 4;
bl = t;
b = e;
}
2008-10-05 18:51:58 +13:00
if (exact && enc[p + 4][E_ASCII].t && enc[p + 4][E_ASCII].t <= 2 && (t = 3 + enc[p + 4][E_ASCII].t) < bl) {
2008-07-14 09:15:55 +12:00
// special case, switch to ASCII for last 1 ot two bytes
bs = 4;
bl = t;
b = E_ASCII;
}
}
}
}
}
enc[p][E_EDIFACT].t = bl;
enc[p][E_EDIFACT].s = bs;
if (bl && b == E_EDIFACT)
2008-10-05 18:51:58 +13:00
enc[p][(int)b].s += enc[p + bs][(int)b].s;
2008-07-14 09:15:55 +12:00
}
// Binary
bl = 0;
for (e = 0; e < E_MAX; e++)
2008-10-05 18:51:58 +13:00
if (enc[p + 1][(int)e].t && ((t = enc[p + 1][(int)e].t + switchcost[E_BINARY][(int)e] + ((e == E_BINARY && enc[p + 1][(int)e].t == 249) ? 1 : 0)) < bl || !bl)) {
2008-07-14 09:15:55 +12:00
bl = t;
b = e;
}
enc[p][E_BINARY].t = 1 + bl;
enc[p][E_BINARY].s = 1;
if (bl && b == E_BINARY)
2008-10-05 18:51:58 +13:00
enc[p][(int)b].s += enc[p + 1][(int)b].s;
2008-07-14 09:15:55 +12:00
/*
2009-01-03 10:09:16 +13:00
fprintf (stderr, "%d:", p); for (e = 0; e < E_MAX; e++) fprintf \
(stderr, " %c*%d/%d", encchr[e], enc[p][e].s, enc[p][e].t); \
fprintf (stderr, "\n");
*/
2008-07-14 09:15:55 +12:00
}
encoding = safemalloc(l + 1);
p = 0;
{
2008-10-03 22:49:03 +13:00
int cur = E_ASCII; // starts ASCII
2008-07-14 09:15:55 +12:00
while (p < l) {
2008-10-03 22:49:03 +13:00
int t, m = 0, b = 0;
2008-07-14 09:15:55 +12:00
for (e = 0; e < E_MAX; e++)
2008-10-07 07:50:36 +13:00
if (enc[p][(int)e].t && (((t = enc[p][(int)e].t + switchcost[(int)cur][(int)e]) < m) || ((t == m && e == cur) || !m))) {
2008-07-14 09:15:55 +12:00
b = e;
m = t;
}
cur = b;
2008-10-05 18:51:58 +13:00
m = enc[p][(int)b].s;
2008-07-14 09:15:55 +12:00
if (!p && lenp)
2008-10-05 18:51:58 +13:00
*lenp = enc[p][(int)b].t;
2008-07-14 09:15:55 +12:00
while (p < l && m--)
2008-10-05 18:51:58 +13:00
encoding[p++] = encchr[(int)b];
2008-07-14 09:15:55 +12:00
}
}
encoding[p] = 0;
return encoding;
}
/*
* Main encoding function
* Returns the grid (malloced) containing the matrix. L corner at 0,0.
* Takes suggested size in *Wptr, *Hptr, or 0,0. Fills in actual size.
* Takes barcodelen and barcode to be encoded
* Note, if *encodingptr is null, then fills with auto picked (malloced)
* encoding
* If lenp not null, then the length of encoded data before any final
* unlatch or pad is stored
* If maxp not null, then the max storage of this size code is stored
* If eccp not null, then the number of ecc bytes used in this size is
* stored
* Returns 0 on error (writes to stderr with details).
*/
2008-10-09 06:06:16 +13:00
int iec16022ecc200(unsigned char *barcode, int barcodelen, struct zint_symbol *symbol)
2008-07-14 09:15:55 +12:00
{
unsigned char binary[3000]; // encoded raw data and ecc to place in barcode
int W = 0, H = 0;
char *encoding = 0;
unsigned char *grid = 0;
2008-10-09 06:06:16 +13:00
int lend, *lenp;
2008-07-14 09:15:55 +12:00
struct ecc200matrix_s *matrix;
memset(binary, 0, sizeof(binary));
2009-01-03 10:09:16 +13:00
unsigned char adjusted[barcodelen];
int i;
2008-07-14 09:15:55 +12:00
2008-10-09 06:06:16 +13:00
lend = 0;
lenp = &lend;
2008-12-31 22:55:58 +13:00
switch(symbol->option_2) {
case 1: W = 10; H = 10; break;
case 2: W = 12; H = 12; break;
case 3: W = 14; H = 14; break;
case 4: W = 16; H = 16; break;
case 5: W = 18; H = 18; break;
case 6: W = 20; H = 20; break;
case 7: W = 22; H = 22; break;
case 8: W = 24; H = 24; break;
case 9: W = 26; H = 26; break;
case 10: W = 32; H = 32; break;
case 11: W = 36; H = 36; break;
case 12: W = 40; H = 40; break;
case 13: W = 44; H = 44; break;
case 14: W = 48; H = 48; break;
case 15: W = 52; H = 52; break;
case 16: W = 64; H = 64; break;
case 17: W = 72; H = 72; break;
case 18: W = 80; H = 80; break;
case 19: W = 88; H = 88; break;
case 20: W = 96; H = 96; break;
case 21: W = 104; H = 104; break;
case 22: W = 120; H = 120; break;
case 23: W = 132; H = 132; break;
case 24: W = 144; H = 144; break;
case 25: W = 18; H = 8; break;
case 26: W = 32; H = 8; break;
case 27: W = 26; H = 12; break;
case 28: W = 36; H = 12; break;
case 29: W = 36; H = 16; break;
case 30: W = 48; H = 16; break;
default: W = 0; H = 0; break;
}
2009-01-03 10:09:16 +13:00
/* Adjust for NULL characters */
for(i = 0; i < barcodelen; i++) {
if(barcode[i] == symbol->nullchar) {
adjusted[i] = 0x00;
} else {
adjusted[i] = barcode[i];
}
}
2008-12-31 22:55:58 +13:00
2008-07-14 09:15:55 +12:00
// encoding
if (W) { // known size
2008-10-05 18:51:58 +13:00
for (matrix = ecc200matrix; matrix->W && (matrix->W != W || matrix->H != H); matrix++) ;
2008-07-14 09:15:55 +12:00
if (!matrix->W) {
2008-10-09 06:06:16 +13:00
strcpy(symbol->errtxt, "Invalid size");
return ERROR_INVALID_OPTION;
2008-07-14 09:15:55 +12:00
}
if (!encoding) {
int len;
2009-01-03 10:09:16 +13:00
char *e = encmake(barcodelen, adjusted, &len, 1);
2008-07-14 09:15:55 +12:00
if (e && len != matrix->bytes) { // try not an exact fit
free(e);
2009-01-03 10:09:16 +13:00
e = encmake(barcodelen, adjusted, &len, 0);
2008-07-14 09:15:55 +12:00
if (len > matrix->bytes) {
2008-10-09 06:06:16 +13:00
strcpy(symbol->errtxt, "Cannot make barcode fit");
if (e) free (e);
return ERROR_INVALID_OPTION;
2008-07-14 09:15:55 +12:00
}
}
encoding = e;
}
} else {
// find a suitable encoding
if (encoding == NULL)
2009-01-03 10:09:16 +13:00
encoding = encmake(barcodelen, adjusted, NULL, 1);
2008-07-14 09:15:55 +12:00
if (encoding) { // find one that fits chosen encoding
for (matrix = ecc200matrix; matrix->W; matrix++)
2009-01-03 10:09:16 +13:00
if (ecc200encode(binary, matrix->bytes, adjusted, barcodelen, encoding, 0)) {
2008-07-14 09:15:55 +12:00
break;
2009-01-03 10:09:16 +13:00
}
2008-07-14 09:15:55 +12:00
} else {
int len;
char *e;
2009-01-03 10:09:16 +13:00
e = encmake(barcodelen, adjusted, &len, 1);
2008-07-14 09:15:55 +12:00
for (matrix = ecc200matrix;
matrix->W && matrix->bytes != len; matrix++) ;
if (e && !matrix->W) { // try for non exact fit
free(e);
2009-01-03 10:09:16 +13:00
e = encmake(barcodelen, adjusted, &len, 0);
2008-10-05 18:51:58 +13:00
for (matrix = ecc200matrix; matrix->W && matrix->bytes < len; matrix++) ;
2008-07-14 09:15:55 +12:00
}
encoding = e;
}
if (!matrix->W) {
2008-10-09 06:06:16 +13:00
strcpy(symbol->errtxt, "Cannot find suitable size, barcode too long");
return ERROR_INVALID_OPTION;
2008-07-14 09:15:55 +12:00
}
W = matrix->W;
H = matrix->H;
}
2009-01-03 10:09:16 +13:00
if (!ecc200encode(binary, matrix->bytes, adjusted, barcodelen, encoding, lenp)) {
2008-10-09 06:06:16 +13:00
strcpy(symbol->errtxt, "Barcode too long");
2008-10-07 21:38:08 +13:00
free(encoding);
2008-10-09 06:06:16 +13:00
return ERROR_INVALID_OPTION;
2008-07-14 09:15:55 +12:00
}
2009-01-03 10:09:16 +13:00
2008-07-14 09:15:55 +12:00
// ecc code
ecc200(binary, matrix->bytes, matrix->datablock, matrix->rsblock);
{ // placement
int x, y, NC, NR, *places;
NC = W - 2 * (W / matrix->FW);
NR = H - 2 * (H / matrix->FH);
places = safemalloc(NC * NR * sizeof(int));
ecc200placement(places, NR, NC);
grid = safemalloc(W * H);
memset(grid, 0, W * H);
for (y = 0; y < H; y += matrix->FH) {
for (x = 0; x < W; x++)
grid[y * W + x] = 1;
for (x = 0; x < W; x += 2)
grid[(y + matrix->FH - 1) * W + x] = 1;
}
for (x = 0; x < W; x += matrix->FW) {
for (y = 0; y < H; y++)
grid[y * W + x] = 1;
for (y = 0; y < H; y += 2)
grid[y * W + x + matrix->FW - 1] = 1;
}
for (y = 0; y < NR; y++) {
for (x = 0; x < NC; x++) {
int v = places[(NR - y - 1) * NC + x];
//fprintf (stderr, "%4d", v);
2008-10-07 07:50:36 +13:00
if (v == 1 || (v > 7 && (binary[(v >> 3) - 1] & (1 << (v & 7)))))
2008-10-05 18:51:58 +13:00
grid[(1 + y + 2 * (y / (matrix->FH - 2))) * W + 1 + x + 2 * (x / (matrix->FW - 2))] = 1;
2008-07-14 09:15:55 +12:00
}
//fprintf (stderr, "\n");
}
2008-10-09 06:06:16 +13:00
for(y = H - 1; y >= 0; y--) {
int x;
for(x = 0; x < W; x++) {
if(grid[W * y + x]) {
symbol->encoded_data[(H - y) - 1][x] = '1'; }
else {
symbol->encoded_data[(H - y) - 1][x] = '0'; }
}
symbol->row_height[(H - y) - 1] = 1;
}
2008-10-07 21:38:08 +13:00
free(grid);
2008-07-14 09:15:55 +12:00
free(places);
}
2008-10-09 06:06:16 +13:00
symbol->rows = H;
symbol->width = W;
2008-10-07 21:38:08 +13:00
free(encoding);
2008-10-09 06:06:16 +13:00
return 0;
2008-07-14 09:15:55 +12:00
}