mirror of
https://github.com/zint/zint
synced 2024-11-16 20:57:25 +13:00
1072 lines
30 KiB
C
Executable File
1072 lines
30 KiB
C
Executable File
/* dmatrix.c Handles Data Matrix ECC 200 symbols */
|
|
|
|
/*
|
|
libzint - the open source barcode library
|
|
Copyright (C) 2009 Robin Stuart <robin@zint.org.uk>
|
|
|
|
developed from and including some functions from:
|
|
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>
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions
|
|
are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
3. Neither the name of the project nor the names of its contributors
|
|
may be used to endorse or promote products derived from this software
|
|
without specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
SUCH DAMAGE.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#ifdef _MSC_VER
|
|
#include <malloc.h>
|
|
#endif
|
|
#include "reedsol.h"
|
|
#include "common.h"
|
|
#include "dmatrix.h"
|
|
|
|
// Annex M placement alorithm low level
|
|
static void ecc200placementbit(int *array, int NR, int NC, int r, int c, int p, char b)
|
|
{
|
|
if (r < 0) {
|
|
r += NR;
|
|
c += 4 - ((NR + 4) % 8);
|
|
}
|
|
if (c < 0) {
|
|
c += NC;
|
|
r += 4 - ((NC + 4) % 8);
|
|
}
|
|
// Necessary for 26x32,26x40,26x48,36x120,36x144,72x120,72x144
|
|
if (r >= NR) {
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"r >= NR:%i,%i at r=%i->",p,b,r);
|
|
#endif
|
|
r -= NR;
|
|
#ifdef DEBUG
|
|
fprintf(stderr,"%i,c=%i\n",r,c);
|
|
#endif
|
|
}
|
|
#ifdef DEBUG
|
|
if(0 != array[r * NC + c] ){
|
|
int a = array[r * NC + c];
|
|
fprintf(stderr,"Double:%i,%i->%i,%i at r=%i,c=%i\n",a >> 3, a & 7, p,b,r,c);
|
|
return;
|
|
}
|
|
#endif
|
|
// Check index limits
|
|
assert( r < NR );
|
|
assert( c < NC );
|
|
// Check double-assignment
|
|
assert( 0 == array[r * NC + c] );
|
|
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 skew)
|
|
{
|
|
int blocks = (bytes + 2) / datablock, b;
|
|
int n, p;
|
|
rs_init_gf(0x12d);
|
|
rs_init_code(rsblock, 1);
|
|
for (b = 0; b < blocks; b++) {
|
|
unsigned char buf[256], ecc[256];
|
|
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) {
|
|
if (skew) {
|
|
/* Rotate ecc data to make 144x144 size symbols acceptable */
|
|
/* See http://groups.google.com/group/postscriptbarcode/msg/5ae8fda7757477da */
|
|
if(b < 8) {
|
|
binary[bytes + n + 2] = ecc[p--];
|
|
} else {
|
|
binary[bytes + n - 8] = ecc[p--];
|
|
}
|
|
} else {
|
|
binary[bytes + n] = ecc[p--];
|
|
}
|
|
}
|
|
}
|
|
rs_free();
|
|
}
|
|
|
|
int isx12(unsigned char source)
|
|
{
|
|
if(source == 13) { return 1; }
|
|
if(source == 42) { return 1; }
|
|
if(source == 62) { return 1; }
|
|
if(source == 32) { return 1; }
|
|
if((source >= '0') && (source <= '9')) { return 1; }
|
|
if((source >= 'A') && (source <= 'Z')) { return 1; }
|
|
|
|
return 0;
|
|
}
|
|
|
|
void dminsert(char binary_string[], int posn, char newbit)
|
|
{ /* Insert a character into the middle of a string at position posn */
|
|
int i, end;
|
|
|
|
end = strlen(binary_string);
|
|
for(i = end; i > posn; i--) {
|
|
binary_string[i] = binary_string[i - 1];
|
|
}
|
|
binary_string[posn] = newbit;
|
|
}
|
|
|
|
void insert_value(unsigned char binary_stream[], int posn, int streamlen, char newbit)
|
|
{
|
|
int i;
|
|
|
|
for(i = streamlen; i > posn; i--) {
|
|
binary_stream[i] = binary_stream[i - 1];
|
|
}
|
|
binary_stream[posn] = newbit;
|
|
}
|
|
|
|
int look_ahead_test(unsigned char source[], int sourcelen, int position, int current_mode, int gs1)
|
|
{
|
|
/* A custom version of the 'look ahead test' from Annex P */
|
|
/* This version is deliberately very reluctant to end a data stream with EDIFACT encoding */
|
|
|
|
float ascii_count, c40_count, text_count, x12_count, edf_count, b256_count, best_count;
|
|
int sp, done, best_scheme;
|
|
|
|
/* step (j) */
|
|
if(current_mode == DM_ASCII) {
|
|
ascii_count = 0.0;
|
|
c40_count = 1.0;
|
|
text_count = 1.0;
|
|
x12_count = 1.0;
|
|
edf_count = 1.0;
|
|
b256_count = 1.25;
|
|
} else {
|
|
ascii_count = 1.0;
|
|
c40_count = 2.0;
|
|
text_count = 2.0;
|
|
x12_count = 2.0;
|
|
edf_count = 2.0;
|
|
b256_count = 2.25;
|
|
}
|
|
|
|
switch(current_mode) {
|
|
case DM_C40: c40_count = 0.0; break;
|
|
case DM_TEXT: text_count = 0.0; break;
|
|
case DM_X12: x12_count = 0.0; break;
|
|
case DM_EDIFACT: edf_count = 0.0; break;
|
|
case DM_BASE256: b256_count = 0.0; break;
|
|
}
|
|
|
|
for(sp = position; (sp < sourcelen) && (sp <= (position + 8)); sp++) {
|
|
|
|
//if(source[sp] <= 127) { reduced_char = source[sp]; } else { reduced_char = source[sp] - 127; }
|
|
|
|
/* ascii */
|
|
if((source[sp] >= '0') && (source[sp] <= '9')) { ascii_count += 0.5; } else { ascii_count += 1.0; }
|
|
if(source[sp] > 127) { ascii_count += 2.0; }
|
|
|
|
/* c40 */
|
|
done = 0;
|
|
if(source[sp] == ' ') { c40_count += (2.0 / 3.0); done = 1; }
|
|
if((source[sp] >= '0') && (source[sp] <= '9')) { c40_count += (2.0 / 3.0); done = 1; }
|
|
if((source[sp] >= 'A') && (source[sp] <= 'Z')) { c40_count += (2.0 / 3.0); done = 1; }
|
|
if(source[sp] > 127) { c40_count += (8.0 / 3.0); }
|
|
if(done == 0) { c40_count += (4.0 / 3.0); }
|
|
|
|
/* text */
|
|
done = 0;
|
|
if(source[sp] == ' ') { text_count += (2.0 / 3.0); done = 1; }
|
|
if((source[sp] >= '0') && (source[sp] <= '9')) { text_count += (2.0 / 3.0); done = 1; }
|
|
if((source[sp] >= 'a') && (source[sp] <= 'z')) { text_count += (2.0 / 3.0); done = 1; }
|
|
if(source[sp] > 127) { text_count += (8.0 / 3.0); }
|
|
if(done == 0) { text_count += (4.0 / 3.0); }
|
|
|
|
/* x12 */
|
|
done = 0;
|
|
if(isx12(source[sp])) { x12_count += (2.0 / 3.0); done = 1; }
|
|
if(source[sp] > 127) { x12_count += (13.0f / 3.0f); done = 1; }
|
|
if(done == 0) x12_count += (10.0f / 3.0f);
|
|
|
|
/* step (p) */
|
|
/* edifact */
|
|
done = 0;
|
|
if((source[sp] >= ' ') && (source[sp] <= '^')) { edf_count += (3.0f / 4.0f); done = 1; }
|
|
if(source[sp] > 127) { edf_count += (17.0f / 4.0f); done = 1; }
|
|
if(done == 0) edf_count += (13.0f / 4.0f);
|
|
|
|
/* step (q) */
|
|
/* b256 */
|
|
if(gs1 && (source[sp] == '[')) { b256_count += 4.0; } else { b256_count += 1.0; }
|
|
|
|
/* printf("%c lat a%.2f c%.2f t%.2f x%.2f e%.2f b%.2f\n", source[sp], ascii_count, c40_count, text_count, x12_count, edf_count, b256_count); */
|
|
|
|
}
|
|
|
|
best_count = ascii_count;
|
|
best_scheme = DM_ASCII;
|
|
|
|
if(b256_count <= best_count) {
|
|
best_count = b256_count;
|
|
best_scheme = DM_BASE256;
|
|
}
|
|
|
|
if(edf_count <= best_count) {
|
|
best_count = edf_count;
|
|
best_scheme = DM_EDIFACT;
|
|
}
|
|
|
|
if(text_count <= best_count) {
|
|
best_count = text_count;
|
|
best_scheme = DM_TEXT;
|
|
}
|
|
|
|
if(x12_count <= best_count) {
|
|
best_count = x12_count;
|
|
best_scheme = DM_X12;
|
|
}
|
|
|
|
if(c40_count <= best_count) {
|
|
best_count = c40_count;
|
|
best_scheme = DM_C40;
|
|
}
|
|
|
|
return best_scheme;
|
|
}
|
|
|
|
int dm200encode(struct zint_symbol *symbol, unsigned char source[], unsigned char target[], int *last_mode, int *length_p, int process_buffer[], int *process_p)
|
|
{
|
|
/* Encodes data using ASCII, C40, Text, X12, EDIFACT or Base 256 modes as appropriate */
|
|
/* Supports encoding FNC1 in supporting systems */
|
|
|
|
int sp, tp, i, gs1;
|
|
int current_mode, next_mode;
|
|
int inputlen = *length_p;
|
|
int debug = 0;
|
|
#ifndef _MSC_VER
|
|
char binary[2 * inputlen];
|
|
#else
|
|
char* binary = (char*)_alloca(2 * inputlen);
|
|
#endif
|
|
|
|
sp = 0;
|
|
tp = 0;
|
|
memset(process_buffer, 0, 8);
|
|
*process_p = 0;
|
|
strcpy(binary, "");
|
|
|
|
/* step (a) */
|
|
current_mode = DM_ASCII;
|
|
next_mode = DM_ASCII;
|
|
|
|
if(symbol->input_mode == GS1_MODE) { gs1 = 1; } else { gs1 = 0; }
|
|
|
|
if(gs1) {
|
|
target[tp] = 232; tp++;
|
|
concat(binary, " ");
|
|
if(debug) printf("FN1 ");
|
|
} /* FNC1 */
|
|
|
|
if(symbol->output_options & READER_INIT) {
|
|
if(gs1) {
|
|
strcpy(symbol->errtxt, "Cannot encode in GS1 mode and Reader Initialisation at the same time");
|
|
return ERROR_INVALID_OPTION;
|
|
} else {
|
|
target[tp] = 234; tp++; /* Reader Programming */
|
|
concat(binary, " ");
|
|
if(debug) printf("RP ");
|
|
}
|
|
}
|
|
|
|
/* Check for Macro05/Macro06 */
|
|
/* "[)>[RS]05[GS]...[RS][EOT]" -> CW 236 */
|
|
/* "[)>[RS]06[GS]...[RS][EOT]" -> CW 237 */
|
|
if (tp == 0 && sp == 0 && inputlen >= 9
|
|
&& source[0] == '[' && source[1] == ')' && source[2] == '>'
|
|
&& source[3] == '\x1e' && source[4] == '0'
|
|
&& (source[5] == '5' || source[5] == '6')
|
|
&& source[6] == '\x1d'
|
|
&& source[inputlen-2] == '\x1e' && source[inputlen-1] == '\x04' )
|
|
{
|
|
/* Output macro Codeword */
|
|
if (source[5] == '5') {
|
|
target[tp] = 236;
|
|
if(debug) printf("Macro05 ");
|
|
} else {
|
|
target[tp] = 237;
|
|
if(debug) printf("Macro06 ");
|
|
}
|
|
tp++;
|
|
concat(binary, " ");
|
|
/* Remove macro characters from input string */
|
|
sp = 7;
|
|
inputlen -= 2;
|
|
*length_p -= 2;
|
|
}
|
|
|
|
|
|
while (sp < inputlen) {
|
|
|
|
current_mode = next_mode;
|
|
|
|
/* step (b) - ASCII encodation */
|
|
if(current_mode == DM_ASCII) {
|
|
next_mode = DM_ASCII;
|
|
|
|
if(istwodigits(source, sp) && ((sp + 1) != inputlen)) {
|
|
target[tp] = (10 * ctoi(source[sp])) + ctoi(source[sp + 1]) + 130;
|
|
if(debug) printf("N%d ", target[tp] - 130);
|
|
tp++; concat(binary, " ");
|
|
sp += 2;
|
|
} else {
|
|
next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1);
|
|
|
|
if(next_mode != DM_ASCII) {
|
|
switch(next_mode) {
|
|
case DM_C40: target[tp] = 230; tp++; concat(binary, " ");
|
|
if(debug) printf("C40 "); break;
|
|
case DM_TEXT: target[tp] = 239; tp++; concat(binary, " ");
|
|
if(debug) printf("TEX "); break;
|
|
case DM_X12: target[tp] = 238; tp++; concat(binary, " ");
|
|
if(debug) printf("X12 "); break;
|
|
case DM_EDIFACT: target[tp] = 240; tp++; concat(binary, " ");
|
|
if(debug) printf("EDI "); break;
|
|
case DM_BASE256: target[tp] = 231; tp++; concat(binary, " ");
|
|
if(debug) printf("BAS "); break;
|
|
}
|
|
} else {
|
|
if(source[sp] > 127) {
|
|
target[tp] = 235; /* FNC4 */
|
|
if(debug) printf("FN4 ");
|
|
tp++;
|
|
target[tp] = (source[sp] - 128) + 1;
|
|
if(debug) printf("A%02X ", target[tp] - 1);
|
|
tp++; concat(binary, " ");
|
|
} else {
|
|
if(gs1 && (source[sp] == '[')) {
|
|
target[tp] = 232; /* FNC1 */
|
|
if(debug) printf("FN1 ");
|
|
} else {
|
|
target[tp] = source[sp] + 1;
|
|
if(debug) printf("A%02X ", target[tp] - 1);
|
|
}
|
|
tp++;
|
|
concat(binary, " ");
|
|
}
|
|
sp++;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* step (c) C40 encodation */
|
|
if(current_mode == DM_C40) {
|
|
int shift_set, value;
|
|
|
|
next_mode = DM_C40;
|
|
if(*process_p == 0) {
|
|
next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1);
|
|
}
|
|
|
|
if(next_mode != DM_C40) {
|
|
target[tp] = 254; tp++; concat(binary, " "); /* Unlatch */
|
|
next_mode = DM_ASCII;
|
|
if (debug) printf("ASC ");
|
|
} else {
|
|
if(source[sp] > 127) {
|
|
process_buffer[*process_p] = 1; (*process_p)++;
|
|
process_buffer[*process_p] = 30; (*process_p)++; /* Upper Shift */
|
|
shift_set = c40_shift[source[sp] - 128];
|
|
value = c40_value[source[sp] - 128];
|
|
} else {
|
|
shift_set = c40_shift[source[sp]];
|
|
value = c40_value[source[sp]];
|
|
}
|
|
|
|
if(gs1 && (source[sp] == '[')) {
|
|
shift_set = 2;
|
|
value = 27; /* FNC1 */
|
|
}
|
|
|
|
if(shift_set != 0) {
|
|
process_buffer[*process_p] = shift_set - 1; (*process_p)++;
|
|
}
|
|
process_buffer[*process_p] = value; (*process_p)++;
|
|
|
|
if(*process_p >= 3) {
|
|
int iv;
|
|
|
|
iv = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + (process_buffer[2]) + 1;
|
|
target[tp] = iv / 256; tp++;
|
|
target[tp] = iv % 256; tp++;
|
|
concat(binary, " ");
|
|
if (debug) printf("[%d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2]);
|
|
|
|
process_buffer[0] = process_buffer[3];
|
|
process_buffer[1] = process_buffer[4];
|
|
process_buffer[2] = process_buffer[5];
|
|
process_buffer[3] = 0;
|
|
process_buffer[4] = 0;
|
|
process_buffer[5] = 0;
|
|
*process_p -= 3;
|
|
}
|
|
sp++;
|
|
}
|
|
}
|
|
|
|
/* step (d) Text encodation */
|
|
if(current_mode == DM_TEXT) {
|
|
int shift_set, value;
|
|
|
|
next_mode = DM_TEXT;
|
|
if(*process_p == 0) {
|
|
next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1);
|
|
}
|
|
|
|
if(next_mode != DM_TEXT) {
|
|
target[tp] = 254; tp++; concat(binary, " ");/* Unlatch */
|
|
next_mode = DM_ASCII;
|
|
if (debug) printf("ASC ");
|
|
} else {
|
|
if(source[sp] > 127) {
|
|
process_buffer[*process_p] = 1; (*process_p)++;
|
|
process_buffer[*process_p] = 30; (*process_p)++; /* Upper Shift */
|
|
shift_set = text_shift[source[sp] - 128];
|
|
value = text_value[source[sp] - 128];
|
|
} else {
|
|
shift_set = text_shift[source[sp]];
|
|
value = text_value[source[sp]];
|
|
}
|
|
|
|
if(gs1 && (source[sp] == '[')) {
|
|
shift_set = 2;
|
|
value = 27; /* FNC1 */
|
|
}
|
|
|
|
if(shift_set != 0) {
|
|
process_buffer[*process_p] = shift_set - 1; (*process_p)++;
|
|
}
|
|
process_buffer[*process_p] = value; (*process_p)++;
|
|
|
|
if(*process_p >= 3) {
|
|
int iv;
|
|
|
|
iv = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + (process_buffer[2]) + 1;
|
|
target[tp] = iv / 256; tp++;
|
|
target[tp] = iv % 256; tp++;
|
|
concat(binary, " ");
|
|
if (debug) printf("[%d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2]);
|
|
|
|
process_buffer[0] = process_buffer[3];
|
|
process_buffer[1] = process_buffer[4];
|
|
process_buffer[2] = process_buffer[5];
|
|
process_buffer[3] = 0;
|
|
process_buffer[4] = 0;
|
|
process_buffer[5] = 0;
|
|
*process_p -= 3;
|
|
}
|
|
sp++;
|
|
}
|
|
}
|
|
|
|
/* step (e) X12 encodation */
|
|
if(current_mode == DM_X12) {
|
|
int value = 0;
|
|
|
|
next_mode = DM_X12;
|
|
if(*process_p == 0) {
|
|
next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1);
|
|
}
|
|
|
|
if(next_mode != DM_X12) {
|
|
target[tp] = 254; tp++; concat(binary, " ");/* Unlatch */
|
|
next_mode = DM_ASCII;
|
|
if (debug) printf("ASC ");
|
|
} else {
|
|
if(source[sp] == 13) { value = 0; }
|
|
if(source[sp] == '*') { value = 1; }
|
|
if(source[sp] == '>') { value = 2; }
|
|
if(source[sp] == ' ') { value = 3; }
|
|
if((source[sp] >= '0') && (source[sp] <= '9')) { value = (source[sp] - '0') + 4; }
|
|
if((source[sp] >= 'A') && (source[sp] <= 'Z')) { value = (source[sp] - 'A') + 14; }
|
|
|
|
process_buffer[*process_p] = value; (*process_p)++;
|
|
|
|
if(*process_p >= 3) {
|
|
int iv;
|
|
|
|
iv = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + (process_buffer[2]) + 1;
|
|
target[tp] = iv / 256; tp++;
|
|
target[tp] = iv % 256; tp++;
|
|
concat(binary, " ");
|
|
if (debug) printf("[%d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2]);
|
|
|
|
process_buffer[0] = process_buffer[3];
|
|
process_buffer[1] = process_buffer[4];
|
|
process_buffer[2] = process_buffer[5];
|
|
process_buffer[3] = 0;
|
|
process_buffer[4] = 0;
|
|
process_buffer[5] = 0;
|
|
*process_p -= 3;
|
|
}
|
|
sp++;
|
|
}
|
|
}
|
|
|
|
/* step (f) EDIFACT encodation */
|
|
if(current_mode == DM_EDIFACT) {
|
|
int value = 0;
|
|
|
|
next_mode = DM_EDIFACT;
|
|
if(*process_p == 3) {
|
|
next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1);
|
|
}
|
|
|
|
if(next_mode != DM_EDIFACT) {
|
|
process_buffer[*process_p] = 31; (*process_p)++;
|
|
next_mode = DM_ASCII;
|
|
} else {
|
|
if((source[sp] >= '@') && (source[sp] <= '^')) { value = source[sp] - '@'; }
|
|
if((source[sp] >= ' ') && (source[sp] <= '?')) { value = source[sp]; }
|
|
/* possibility put an assertion here for invalid character (none of the ifs trigger) */
|
|
|
|
process_buffer[*process_p] = value; (*process_p)++;
|
|
sp++;
|
|
}
|
|
|
|
if(*process_p >= 4) {
|
|
target[tp] = (process_buffer[0] << 2) + ((process_buffer[1] & 0x30) >> 4); tp++;
|
|
target[tp] = ((process_buffer[1] & 0x0f) << 4) + ((process_buffer[2] & 0x3c) >> 2); tp++;
|
|
target[tp] = ((process_buffer[2] & 0x03) << 6) + process_buffer[3]; tp++;
|
|
concat(binary, " ");
|
|
if (debug) printf("[%d %d %d %d] ", process_buffer[0], process_buffer[1], process_buffer[2], process_buffer[3]);
|
|
|
|
process_buffer[0] = process_buffer[4];
|
|
process_buffer[1] = process_buffer[5];
|
|
process_buffer[2] = process_buffer[6];
|
|
process_buffer[3] = process_buffer[7];
|
|
process_buffer[4] = 0;
|
|
process_buffer[5] = 0;
|
|
process_buffer[6] = 0;
|
|
process_buffer[7] = 0;
|
|
*process_p -= 4;
|
|
}
|
|
}
|
|
|
|
/* step (g) Base 256 encodation */
|
|
if(current_mode == DM_BASE256) {
|
|
next_mode = look_ahead_test(source, inputlen, sp, current_mode, gs1);
|
|
|
|
if(next_mode == DM_BASE256) {
|
|
target[tp] = source[sp];
|
|
if(debug) printf("B%02X ", target[tp]);
|
|
tp++;
|
|
sp++;
|
|
concat(binary, "b");
|
|
} else {
|
|
next_mode = DM_ASCII;
|
|
if(debug) printf("ASC ");
|
|
}
|
|
}
|
|
|
|
if(tp > 1558) {
|
|
return 0;
|
|
}
|
|
|
|
} /* while */
|
|
|
|
/* Add length and randomising algorithm to b256 */
|
|
i = 0;
|
|
while (i < tp) {
|
|
if(binary[i] == 'b') {
|
|
if((i == 0) || ((i != 0) && (binary[i - 1] != 'b'))) {
|
|
/* start of binary data */
|
|
int binary_count; /* length of b256 data */
|
|
|
|
for(binary_count = 0; binary[binary_count + i] == 'b'; binary_count++);
|
|
|
|
if(binary_count <= 249) {
|
|
dminsert(binary, i, 'b');
|
|
insert_value(target, i, tp, binary_count); tp++;
|
|
} else {
|
|
dminsert(binary, i, 'b');
|
|
dminsert(binary, i + 1, 'b');
|
|
insert_value(target, i, tp, (binary_count / 250) + 249); tp++;
|
|
insert_value(target, i + 1, tp, binary_count % 250); tp++;
|
|
}
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
|
|
for(i = 0; i < tp; i++) {
|
|
if(binary[i] == 'b') {
|
|
int prn, temp;
|
|
|
|
prn = ((149 * (i + 1)) % 255) + 1;
|
|
temp = target[i] + prn;
|
|
if (temp <= 255) { target[i] = temp; } else { target[i] = temp - 256; }
|
|
}
|
|
}
|
|
|
|
*(last_mode) = current_mode;
|
|
return tp;
|
|
}
|
|
|
|
int dm200encode_remainder(unsigned char target[], int target_length, unsigned char source[], int inputlen, int last_mode, int process_buffer[], int process_p, int symbols_left)
|
|
{
|
|
int debug = 0;
|
|
|
|
switch (last_mode)
|
|
{
|
|
case DM_C40:
|
|
case DM_TEXT:
|
|
if (symbols_left == process_p) // No unlatch required!
|
|
{
|
|
if (process_p == 1) // 1 data character left to encode.
|
|
{
|
|
target[target_length] = source[inputlen - 1] + 1; target_length++;
|
|
}
|
|
|
|
if (process_p == 2) // 2 data characters left to encode.
|
|
{
|
|
// Pad with shift 1 value (0) and encode as double.
|
|
int intValue = (1600 * process_buffer[0]) + (40 * process_buffer[1]) + 1; // ie (0 + 1).
|
|
target[target_length] = (unsigned char)(intValue / 256); target_length++;
|
|
target[target_length] = (unsigned char)(intValue % 256); target_length++;
|
|
}
|
|
}
|
|
|
|
if (symbols_left > process_p)
|
|
{
|
|
target[target_length] = (254); target_length++; // Unlatch and encode remaining data in ascii.
|
|
if (process_p == 1 || (process_p == 2 && process_buffer[0] < 3)) // Check for a shift value.
|
|
{
|
|
target[target_length] = source[inputlen - 1] + 1; target_length++;
|
|
}
|
|
|
|
else if (process_p == 2)
|
|
{
|
|
target[target_length] = source[inputlen - 2] + 1; target_length++;
|
|
target[target_length] = source[inputlen - 1] + 1; target_length++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DM_X12:
|
|
if (symbols_left == process_p) // Unlatch not required!
|
|
{
|
|
if (process_p == 1) // 1 data character left to encode.
|
|
{
|
|
target[target_length] = source[inputlen - 1] + 1; target_length++;
|
|
}
|
|
|
|
if (process_p == 2)
|
|
{
|
|
// Encode last 2 bytes as ascii.
|
|
target[target_length] = source[inputlen - 2] + 1; target_length++;
|
|
target[target_length] = source[inputlen - 1] + 1; target_length++;
|
|
}
|
|
}
|
|
|
|
if (symbols_left > process_p) // Unlatch and encode remaining data in ascii.
|
|
{
|
|
target[target_length] = (254); target_length++; // Unlatch.
|
|
if (process_p == 1)
|
|
{
|
|
target[target_length] = source[inputlen - 1] + 1; target_length++;
|
|
}
|
|
|
|
if (process_p == 2)
|
|
{
|
|
target[target_length] = source[inputlen - 2] + 1; target_length++;
|
|
target[target_length] = source[inputlen - 1] + 1; target_length++;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DM_EDIFACT:
|
|
if (symbols_left == process_p) // Unlatch not required!
|
|
{
|
|
if (process_p == 1)
|
|
{
|
|
target[target_length] = source[inputlen - 1] + 1; target_length++;
|
|
}
|
|
|
|
if (process_p == 2)
|
|
{
|
|
target[target_length] = source[inputlen - 2] + 1; target_length++;
|
|
target[target_length] = source[inputlen - 1] + 1; target_length++;
|
|
}
|
|
|
|
if (process_p == 3) // Append edifact unlatch value (31) and encode as triple.
|
|
{
|
|
target[target_length] = (unsigned char)((process_buffer[0] << 2) + ((process_buffer[1] & 0x30) >> 4)); target_length++;
|
|
target[target_length] = (unsigned char)(((process_buffer[1] & 0x0f) << 4) + ((process_buffer[2] & 0x3c) >> 2)); target_length++;
|
|
target[target_length] = (unsigned char)(((process_buffer[2] & 0x03) << 6) + 31); target_length++;
|
|
}
|
|
}
|
|
|
|
if (symbols_left > process_p) // Unlatch and encode remaining data in ascii.
|
|
{
|
|
// Edifact unlatch.
|
|
if (symbols_left < 3)
|
|
{
|
|
target[target_length] = 31; target_length++;
|
|
}
|
|
|
|
else
|
|
target[target_length] = (31 << 2); target_length++;
|
|
|
|
if (process_p == 1)
|
|
{
|
|
target[target_length] = source[inputlen - 1] + 1; target_length++;
|
|
}
|
|
|
|
if (process_p == 2)
|
|
{
|
|
target[target_length] = source[inputlen - 2] + 1; target_length++;
|
|
target[target_length] = source[inputlen - 1] + 1; target_length++;
|
|
}
|
|
|
|
if (process_p == 3)
|
|
{
|
|
target[target_length] = source[inputlen - 3] + 1; target_length++;
|
|
target[target_length] = source[inputlen - 2] + 1; target_length++;
|
|
target[target_length] = source[inputlen - 1] + 1; target_length++;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if(debug)
|
|
{
|
|
int i;
|
|
printf("\n\n");
|
|
for(i = 0; i < target_length; i++)
|
|
printf("%03d ", target[i]);
|
|
|
|
printf("\n");
|
|
}
|
|
|
|
return target_length;
|
|
}
|
|
|
|
void add_tail(unsigned char target[], int tp, int tail_length)
|
|
{
|
|
/* add pad bits */
|
|
int i, prn, temp;
|
|
|
|
for(i = tail_length; i > 0; i--) {
|
|
if(i == tail_length) {
|
|
target[tp] = 129; tp++; /* Pad */
|
|
} else {
|
|
prn = ((149 * (tp + 1)) % 253) + 1;
|
|
temp = 129 + prn;
|
|
if(temp <= 254) {
|
|
target[tp] = temp; tp++;
|
|
} else {
|
|
target[tp] = temp - 254; tp++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int data_matrix_200(struct zint_symbol *symbol, unsigned char source[], int length)
|
|
{
|
|
int inputlen, i, skew = 0;
|
|
unsigned char binary[2200];
|
|
int binlen;
|
|
int process_buffer[8]; /* holds remaining data to finalised */
|
|
int process_p; /* number of characters left to finalise */
|
|
int symbolsize, optionsize, calcsize;
|
|
int taillength, error_number = 0;
|
|
int H, W, FH, FW, datablock, bytes, rsblock;
|
|
int last_mode;
|
|
unsigned char *grid = 0;
|
|
int symbols_left;
|
|
inputlen = length;
|
|
|
|
/* inputlen may be decremented by 2 if macro character is used */
|
|
binlen = dm200encode(symbol, source, binary, &last_mode, &inputlen, process_buffer, &process_p);
|
|
|
|
if(binlen == 0) {
|
|
strcpy(symbol->errtxt, "Data too long to fit in symbol");
|
|
return ERROR_TOO_LONG;
|
|
}
|
|
|
|
if((symbol->option_2 >= 1) && (symbol->option_2 <= DMSIZESCOUNT)) {
|
|
optionsize = intsymbol[symbol->option_2 - 1];
|
|
} else {
|
|
optionsize = -1;
|
|
}
|
|
|
|
calcsize = DMSIZESCOUNT-1;
|
|
for(i = DMSIZESCOUNT-1; i > -1; i--) {
|
|
if(matrixbytes[i] >= (binlen + process_p)) // Allow for the remaining data characters.
|
|
{
|
|
calcsize = i;
|
|
}
|
|
}
|
|
|
|
/* Skip rectangular symbols in square only mode */
|
|
while(symbol->option_3 == DM_SQUARE && matrixH[calcsize] != matrixW[calcsize]) {
|
|
calcsize++;
|
|
}
|
|
|
|
symbolsize = optionsize;
|
|
if(calcsize > optionsize) {
|
|
symbolsize = calcsize;
|
|
if(optionsize != -1) {
|
|
/* flag an error */
|
|
error_number = WARN_INVALID_OPTION;
|
|
strcpy(symbol->errtxt, "Data does not fit in selected symbol size");
|
|
}
|
|
}
|
|
|
|
// Now we know the symbol size we can handle the remaining data in the process buffer.
|
|
symbols_left = matrixbytes[symbolsize] - binlen;
|
|
binlen = dm200encode_remainder(binary, binlen, source, inputlen, last_mode, process_buffer, process_p, symbols_left);
|
|
|
|
H = matrixH[symbolsize];
|
|
W = matrixW[symbolsize];
|
|
FH = matrixFH[symbolsize];
|
|
FW = matrixFW[symbolsize];
|
|
bytes = matrixbytes[symbolsize];
|
|
datablock = matrixdatablock[symbolsize];
|
|
rsblock = matrixrsblock[symbolsize];
|
|
|
|
taillength = bytes - binlen;
|
|
|
|
if(taillength != 0) {
|
|
add_tail(binary, binlen, taillength);
|
|
}
|
|
|
|
// ecc code
|
|
if(symbolsize == INTSYMBOL144) { skew = 1; }
|
|
ecc200(binary, bytes, datablock, rsblock, skew);
|
|
// Print Codewords
|
|
#ifdef DEBUG
|
|
{
|
|
int CWCount;
|
|
if (skew)
|
|
CWCount = 1558+620;
|
|
else
|
|
CWCount = bytes + rsblock * (bytes / datablock);
|
|
printf("Codewords (%i):",CWCount);
|
|
for (int posCur = 0;posCur < CWCount;posCur++)
|
|
printf(" %3i",binary[posCur]);
|
|
puts("\n");
|
|
}
|
|
#endif
|
|
{ // placement
|
|
int x, y, NC, NR, *places;
|
|
NC = W - 2 * (W / FW);
|
|
NR = H - 2 * (H / FH);
|
|
places = (int*)malloc(NC * NR * sizeof(int));
|
|
ecc200placement(places, NR, NC);
|
|
grid = (unsigned char*)malloc(W * H);
|
|
memset(grid, 0, W * H);
|
|
for (y = 0; y < H; y += FH) {
|
|
for (x = 0; x < W; x++)
|
|
grid[y * W + x] = 1;
|
|
for (x = 0; x < W; x += 2)
|
|
grid[(y + FH - 1) * W + x] = 1;
|
|
}
|
|
for (x = 0; x < W; x += FW) {
|
|
for (y = 0; y < H; y++)
|
|
grid[y * W + x] = 1;
|
|
for (y = 0; y < H; y += 2)
|
|
grid[y * W + x + FW - 1] = 1;
|
|
}
|
|
#ifdef DEBUG
|
|
// Print position matrix as in standard
|
|
for (y = NR-1; y >= 0; y--) {
|
|
for (x = 0; x < NC; x++) {
|
|
if (x != 0)
|
|
fprintf (stderr, "|");
|
|
int v = places[(NR - y - 1) * NC + x];
|
|
fprintf(stderr,"%3d.%2d",(v>>3),8-(v&7));
|
|
}
|
|
fprintf (stderr, "\n");
|
|
}
|
|
#endif
|
|
for (y = 0; y < NR; y++) {
|
|
for (x = 0; x < NC; x++) {
|
|
int v = places[(NR - y - 1) * NC + x];
|
|
//fprintf (stderr, "%4d", v);
|
|
if (v == 1 || (v > 7 && (binary[(v >> 3) - 1] & (1 << (v & 7)))))
|
|
grid[(1 + y + 2 * (y / (FH - 2))) * W + 1 + x + 2 * (x / (FW - 2))] = 1;
|
|
}
|
|
//fprintf (stderr, "\n");
|
|
}
|
|
for(y = H - 1; y >= 0; y--) {
|
|
int x;
|
|
for(x = 0; x < W; x++) {
|
|
if(grid[W * y + x]) {
|
|
set_module(symbol, (H - y) - 1, x);
|
|
}
|
|
}
|
|
symbol->row_height[(H - y) - 1] = 1;
|
|
}
|
|
free(grid);
|
|
free(places);
|
|
}
|
|
|
|
symbol->rows = H;
|
|
symbol->width = W;
|
|
|
|
return error_number;
|
|
}
|
|
|
|
int dmatrix(struct zint_symbol *symbol, unsigned char source[], int length)
|
|
{
|
|
int error_number;
|
|
|
|
if(symbol->option_1 <= 1) {
|
|
/* ECC 200 */
|
|
error_number = data_matrix_200(symbol, source, length);
|
|
} else {
|
|
/* ECC 000 - 140 */
|
|
strcpy(symbol->errtxt, "Older Data Matrix standards are no longer supported");
|
|
error_number = ERROR_INVALID_OPTION;
|
|
}
|
|
|
|
return error_number;
|
|
}
|