zint/backend/qr.c

781 lines
25 KiB
C
Raw Normal View History

2009-10-07 08:03:00 +13:00
/* qr.c Handles QR Code */
2008-07-14 09:15:55 +12:00
/*
libzint - the open source barcode library
2009-10-07 08:03:00 +13:00
Copyright (C) 2009 Robin Stuart <robin@zint.org.uk>
2008-07-14 09:15:55 +12:00
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 3 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 Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <string.h>
#include "common.h"
2009-08-09 20:45:58 +12:00
#include <stdio.h>
2009-10-07 08:03:00 +13:00
#include "sjis.h"
#include "qr.h"
#include "qrrs.h"
2008-09-03 07:49:08 +12:00
2009-10-07 08:03:00 +13:00
int in_alpha(int glyph) {
/* Returns true if input glyph is in the Alphanumeric set */
int retval = 0;
char cglyph = (char) glyph;
if((cglyph >= '0') && (cglyph <= '9')) {
retval = 1;
}
if((cglyph >= 'A') && (cglyph <= 'Z')) {
retval = 1;
}
switch (cglyph) {
case ' ':
case '$':
case '%':
case '*':
case '+':
case '-':
case '.':
case '/':
case ':':
retval = 1;
break;
}
return retval;
}
2008-07-14 09:15:55 +12:00
2009-10-07 08:03:00 +13:00
void define_mode(char mode[], int jisdata[], int length)
{
/* Values placed into mode[] are: K = Kanji, B = Binary, A = Alphanumeric, N = Numeric */
int i, mlen, j;
for(i = 0; i < length; i++) {
if(jisdata[i] > 0xff) {
mode[i] = 'K';
} else {
mode[i] = 'B';
if(in_alpha(jisdata[i])) { mode[i] = 'A'; }
if((jisdata[i] >= '0') && (jisdata[i] <= '9')) { mode[i] = 'N'; }
}
}
/* If less than 6 numeric digits together then don't use numeric mode */
for(i = 0; i < length; i++) {
if(mode[i] == 'N') {
if(((i != 0) && (mode[i - 1] != 'N')) || (i == 0)) {
mlen = 0;
while (((mlen + i) < length) && (mode[mlen + i] == 'N')) {
mlen++;
};
if(mlen < 6) {
for(j = 0; j < mlen; j++) {
mode[i + j] = 'A';
}
}
}
}
}
/* If less than 4 alphanumeric characters together then don't use alphanumeric mode */
for(i = 0; i < length; i++) {
if(mode[i] == 'A') {
if(((i != 0) && (mode[i - 1] != 'A')) || (i == 0)) {
mlen = 0;
while (((mlen + i) < length) && (mode[mlen + i] == 'A')) {
mlen++;
};
if(mlen < 6) {
for(j = 0; j < mlen; j++) {
mode[i + j] = 'B';
}
}
}
}
}
}
2009-08-09 20:45:58 +12:00
2009-10-07 08:03:00 +13:00
int estimate_binary_length(char mode[], int length)
{
/* Make an estimate (worst case scenario) of how long the binary string will be */
int i, count = 0;
char current = 0;
int a_count = 0;
int n_count = 0;
switch(mode[0]) {
case 'K': count = 12 + 4; current = 'K'; break;
case 'B': count = 16 + 4; current = 'B'; break;
case 'A': count = 13 + 4; current = 'A'; break;
case 'N': count = 14 + 4; current = 'N'; break;
2009-08-09 20:45:58 +12:00
}
2009-10-07 08:03:00 +13:00
for(i = 0; i < length; i++) {
if(mode[i] != current) {
if(current == 'N') {
switch(n_count) {
case 1: count += 4; break;
case 2: count += 7; break;
}
}
switch(mode[i]) {
case 'K': count += 12 + 4; current = 'K'; break;
case 'B': count += 16 + 4; current = 'B'; break;
case 'A': count += 13 + 4; current = 'A'; break;
case 'N': count += 14 + 4; current = 'N'; break;
}
}
switch(mode[i]) {
case 'K': count += 13; break;
case 'B': count += 8; break;
case 'A': a_count++; if((a_count % 2) == 0) { count += 11; a_count = 0; } break;
case 'N': n_count++; if((n_count % 3) == 0) { count += 10; n_count = 0; } break;
}
2008-07-14 09:15:55 +12:00
}
2009-10-07 08:03:00 +13:00
return count;
}
2008-07-14 09:15:55 +12:00
2009-10-07 08:03:00 +13:00
void qr_binary(int datastream[], int version, int target_binlen, char mode[], int jisdata[], int length)
{
/* Convert input data to a binary stream and add padding */
int position = 0, debug = 1;
int short_data_block_length, i, scheme;
char data_block, padbits;
int current_binlen, current_bytes;
int toggle;
#ifndef _MSC_VER
char binary[target_binlen * 8];
#else
char binary = (char *)_alloca(target_binlen * 8);
#endif
strcpy(binary, "");
if(version <= 9) {
scheme = 1;
}
if((version >= 10) && (version <= 26)) {
scheme = 2;
}
if(version >= 27) {
scheme = 3;
}
if(debug) {
for(i = 0; i < length; i++) {
printf("%c", mode[i]);
2008-07-14 09:15:55 +12:00
}
2009-10-07 08:03:00 +13:00
printf("\n");
2008-07-14 09:15:55 +12:00
}
2009-10-07 08:03:00 +13:00
do {
data_block = mode[position];
short_data_block_length = 0;
do {
short_data_block_length++;
} while (((short_data_block_length + position) < length) && (mode[position + short_data_block_length] == data_block));
switch(data_block) {
case 'K':
/* Kanji mode */
/* Mode indicator */
concat(binary, "1000");
/* Character count indicator */
switch(scheme) {
case 3:
if(short_data_block_length & 0x800) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x400) { concat(binary, "1"); } else { concat(binary, "0"); }
case 2:
if(short_data_block_length & 0x200) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x100) { concat(binary, "1"); } else { concat(binary, "0"); }
case 1:
if(short_data_block_length & 0x80) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x40) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x20) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x10) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x08) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x04) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x02) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x01) { concat(binary, "1"); } else { concat(binary, "0"); }
break;
}
if(debug) { printf("Kanji block (length %d)\n\t", short_data_block_length); }
/* Character representation */
for(i = 0; i < short_data_block_length; i++) {
int jis = jisdata[position + i];
int msb, lsb, prod;
if(jis > 0x9fff) { jis -= 0xc140; }
msb = (jis & 0xff00) >> 4;
lsb = (jis & 0xff);
prod = (msb * 0xc0) + lsb;
if(prod & 0x1000) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x800) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x400) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x200) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x100) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x80) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x40) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x20) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x10) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x08) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x04) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x02) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x01) { concat(binary, "1"); } else { concat(binary, "0"); }
if(debug) { printf("0x%4X ", prod); }
}
if(debug) { printf("\n"); }
break;
case 'B':
/* Byte mode */
/* Mode indicator */
concat(binary, "0100");
/* Character count indicator */
switch (scheme) {
case 3:
case 2:
if(short_data_block_length & 0x8000) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x4000) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x2000) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x1000) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x800) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x400) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x200) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x100) { concat(binary, "1"); } else { concat(binary, "0"); }
case 1:
if(short_data_block_length & 0x80) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x40) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x20) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x10) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x08) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x04) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x02) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x01) { concat(binary, "1"); } else { concat(binary, "0"); }
break;
}
if(debug) { printf("Byte block (length %d)\n\t", short_data_block_length); }
/* Character representation */
for(i = 0; i < short_data_block_length; i++) {
int byte = jisdata[position + i];
if(byte & 0x80) { concat(binary, "1"); } else { concat(binary, "0"); }
if(byte & 0x40) { concat(binary, "1"); } else { concat(binary, "0"); }
if(byte & 0x20) { concat(binary, "1"); } else { concat(binary, "0"); }
if(byte & 0x10) { concat(binary, "1"); } else { concat(binary, "0"); }
if(byte & 0x08) { concat(binary, "1"); } else { concat(binary, "0"); }
if(byte & 0x04) { concat(binary, "1"); } else { concat(binary, "0"); }
if(byte & 0x02) { concat(binary, "1"); } else { concat(binary, "0"); }
if(byte & 0x01) { concat(binary, "1"); } else { concat(binary, "0"); }
if(debug) { printf("0x%4X ", byte); }
}
if(debug) { printf("\n"); }
break;
case 'A':
/* Alphanumeric mode */
/* Mode indicator */
concat(binary, "0010");
/* Character count indicator */
switch (scheme) {
case 3:
if(short_data_block_length & 0x1000) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x800) { concat(binary, "1"); } else { concat(binary, "0"); }
case 2:
if(short_data_block_length & 0x400) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x200) { concat(binary, "1"); } else { concat(binary, "0"); }
case 1:
if(short_data_block_length & 0x100) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x80) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x40) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x20) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x10) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x08) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x04) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x02) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x01) { concat(binary, "1"); } else { concat(binary, "0"); }
break;
}
if(debug) { printf("Alpha block (length %d)\n\t", short_data_block_length); }
/* Character representation */
i = 0;
while ( i < short_data_block_length ) {
int count;
int first = 0, second = 0, prod;
first = posn(RHODIUM, (char) jisdata[position + i]);
count = 1;
prod = first;
if(mode[position + i + 1] == 'A') {
second = posn(RHODIUM, (char) jisdata[position + i + 1]);
count = 2;
prod = (first * 45) + second;
}
switch(count) {
case 2:
if(prod & 0x400) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x200) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x100) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x80) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x40) { concat(binary, "1"); } else { concat(binary, "0"); }
case 1:
if(prod & 0x20) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x10) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x08) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x04) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x02) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x01) { concat(binary, "1"); } else { concat(binary, "0"); }
break;
}
if(debug) { printf("0x%4X ", prod); }
i += 2;
};
if(debug) { printf("\n"); }
break;
case 'N':
/* Numeric mode */
/* Mode indicator */
concat(binary, "0001");
/* Character count indicator */
switch (scheme) {
case 3:
if(short_data_block_length & 0x2000) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x1000) { concat(binary, "1"); } else { concat(binary, "0"); }
case 2:
if(short_data_block_length & 0x800) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x400) { concat(binary, "1"); } else { concat(binary, "0"); }
case 1:
if(short_data_block_length & 0x200) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x100) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x80) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x40) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x20) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x10) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x08) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x04) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x02) { concat(binary, "1"); } else { concat(binary, "0"); }
if(short_data_block_length & 0x01) { concat(binary, "1"); } else { concat(binary, "0"); }
break;
}
if(debug) { printf("Number block (length %d)\n\t", short_data_block_length); }
/* Character representation */
i = 0;
while ( i < short_data_block_length ) {
int count;
int first = 0, second = 0, third = 0, prod;
first = posn(NEON, (char) jisdata[position + i]);
count = 1;
prod = first;
if(mode[position + i + 1] == 'N') {
second = posn(NEON, (char) jisdata[position + i + 1]);
count = 2;
prod = (prod * 10) + second;
}
if(mode[position + i + 2] == 'N') {
third = posn(NEON, (char) jisdata[position + i + 2]);
count = 3;
prod = (prod * 10) + third;
}
switch(count) {
case 3:
if(prod & 0x200) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x100) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x80) { concat(binary, "1"); } else { concat(binary, "0"); }
case 2:
if(prod & 0x40) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x20) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x10) { concat(binary, "1"); } else { concat(binary, "0"); }
case 1:
if(prod & 0x08) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x04) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x02) { concat(binary, "1"); } else { concat(binary, "0"); }
if(prod & 0x01) { concat(binary, "1"); } else { concat(binary, "0"); }
break;
}
if(debug) { printf("0x%4X (%d)", prod, prod); }
i += 3;
};
if(debug) { printf("\n"); }
break;
}
position += short_data_block_length;
} while (position < length - 1) ;
/* Terminator */
concat(binary, "0000");
current_binlen = strlen(binary);
padbits = 8 - (current_binlen % 8);
if(padbits == 8) { padbits = 0; }
current_bytes = (current_binlen + padbits) / 8;
/* Padding bits */
for(i = 0; i < padbits; i++) {
concat(binary, "0");
2008-07-14 09:15:55 +12:00
}
2009-10-07 08:03:00 +13:00
/* Put data into 8-bit codewords */
for(i = 0; i < current_bytes; i++) {
datastream[i] = 0x00;
if(binary[i * 8] == '1') { datastream[i] += 0x80; }
if(binary[i * 8 + 1] == '1') { datastream[i] += 0x40; }
if(binary[i * 8 + 2] == '1') { datastream[i] += 0x20; }
if(binary[i * 8 + 3] == '1') { datastream[i] += 0x10; }
if(binary[i * 8 + 4] == '1') { datastream[i] += 0x08; }
if(binary[i * 8 + 5] == '1') { datastream[i] += 0x04; }
if(binary[i * 8 + 6] == '1') { datastream[i] += 0x02; }
if(binary[i * 8 + 7] == '1') { datastream[i] += 0x01; }
}
/* Add pad codewords */
toggle = 0;
for(i = current_bytes; i < target_binlen; i++) {
if(toggle == 0) {
datastream[i] = 0xec;
toggle = 1;
} else {
datastream[i] = 0x11;
toggle = 0;
}
}
2008-07-14 09:15:55 +12:00
2009-10-07 08:03:00 +13:00
if(debug) {
for(i = 0; i < target_binlen; i++) {
printf("0x%2X ", datastream[i]);
}
printf("\n");
}
2008-07-14 09:15:55 +12:00
}
2009-10-07 08:03:00 +13:00
void add_ecc(int fullstream[], int datastream[], int version, int data_cw, int blocks)
2008-07-14 09:15:55 +12:00
{
2009-10-07 08:03:00 +13:00
/* Split data into blocks, add error correction and then interleave the blocks and error correction data */
int ecc_cw = qr_total_codewords[version - 1] - data_cw;
int short_data_block_length = data_cw / blocks;
int qty_long_blocks = data_cw % blocks;
int qty_short_blocks = blocks - qty_long_blocks;
int ecc_block_length = ecc_cw / blocks;
int i, j, length_this_block, posn, debug = 1;
RS *rs;
#ifndef _MSC_VER
2009-10-07 08:03:00 +13:00
unsigned char data_block[short_data_block_length + 2];
unsigned char ecc_block[ecc_block_length + 2];
int interleaved_data[data_cw + 2];
int interleaved_ecc[ecc_cw + 2];
#else
2009-10-07 08:03:00 +13:00
unsigned char data_block = (unsigned char *)_alloca(short_data_block_length + 2);
unsigned char ecc_block = (unsigned char *)_alloca(ecc_block_length + 2);
int interleaved_data = (int *)_alloca(data_cw + 2);
int interleaved_ecc = (int *)_alloca(ecc_cw + 2);
#endif
2009-10-07 08:03:00 +13:00
posn = 0;
for(i = 0; i < blocks; i++) {
if(i < qty_short_blocks) { length_this_block = short_data_block_length; } else { length_this_block = short_data_block_length + 1; }
for(j = 0; j < ecc_block_length; j++) {
ecc_block[j] = 0;
}
for(j = 0; j < length_this_block; j++) {
data_block[j] = (unsigned char) datastream[posn + j];
}
rs = init_rs(8, 0x11d, 0, 1, ecc_block_length, 255 - length_this_block - ecc_block_length);
encode_rs_char(rs, data_block, ecc_block);
if(debug) {
printf("Block %d: ", i + 1);
for(j = 0; j < length_this_block; j++) {
printf("%2X ", data_block[j]);
}
if(i < qty_short_blocks) {
printf(" ");
}
printf(" // ");
for(j = 0; j < ecc_block_length; j++) {
printf("%2X ", ecc_block[j]);
}
printf("\n");
}
for(j = 0; j < short_data_block_length; j++) {
interleaved_data[(j * blocks) + i] = (int) data_block[j];
}
if(i >= qty_short_blocks){
interleaved_data[(short_data_block_length * blocks) + (i - qty_short_blocks)] = (int) data_block[short_data_block_length];
}
for(j = 0; j < ecc_block_length; j++) {
interleaved_ecc[(j * blocks) + i] = (int) ecc_block[j];
}
posn += length_this_block;
}
2009-10-07 08:03:00 +13:00
free_rs_cache();
2009-10-07 08:03:00 +13:00
for(j = 0; j < data_cw; j++) {
fullstream[j] = interleaved_data[j];
}
for(j = 0; j < ecc_cw; j++) {
fullstream[j + data_cw] = interleaved_ecc[j];
}
if(debug) {
printf("\nData Stream: \n");
for(j = 0; j < (data_cw + ecc_cw); j++) {
printf("%2X ", fullstream[j]);
}
printf("\n");
}
}
void place_finder(unsigned char grid[], int size, int x, int y)
{
int xp, yp;
int finder[] = {
1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0, 1,
1, 0, 1, 1, 1, 0, 1,
1, 0, 1, 1, 1, 0, 1,
1, 0, 1, 1, 1, 0, 1,
1, 0, 0, 0, 0, 0, 1,
1, 1, 1, 1, 1, 1, 1
};
for(xp = 0; xp < 7; xp++) {
for(yp = 0; yp < 7; yp++) {
if (finder[xp + (7 * yp)] == 1) {
grid[((yp + y) * size) + (xp + x)] = 0x11;
} else {
grid[((yp + y) * size) + (xp + x)] = 0x10;
}
2009-08-09 03:25:17 +12:00
}
}
2009-10-07 08:03:00 +13:00
}
void setup_grid(unsigned char* grid, int size)
{
int i, toggle = 1;
for(i = 0; i < size; i++) {
if(toggle == 1) {
grid[(6 * size) + i] = 0x11;
grid[(i * size) + 6] = 0x11;
toggle = 0;
} else {
grid[(6 * size) + i] = 0x10;
grid[(i * size) + 6] = 0x10;
toggle = 1;
}
}
place_finder(grid, size, 0, 0);
place_finder(grid, size, 0, size - 7);
place_finder(grid, size, size - 7, 0);
}
int qr_code(struct zint_symbol *symbol, unsigned char source[], int length)
{
int error_number, i, j, glyph, est_binlen;
int ecc_level, autosize, version, max_cw, target_binlen, blocks, size;
#ifndef _MSC_VER
int utfdata[length + 1];
int jisdata[length + 1];
char mode[length + 1];
#else
int utfdata = (int *)_alloca((length + 1) * sizeof(int));
int jisdata = (int *)_alloca((length + 1) * sizeof(int));
char mode = (char *)_alloca((length + 1) * sizeof(int));
#endif
switch(symbol->input_mode) {
case DATA_MODE:
for(i = 0; i < length; i++) {
2009-10-07 08:03:00 +13:00
jisdata[i] = (int)source[i];
}
break;
2009-10-07 08:03:00 +13:00
default:
/* Convert Unicode input to Shift-JIS */
error_number = utf8toutf16(symbol, source, utfdata, &length);
if(error_number != 0) { return error_number; }
2009-10-07 08:03:00 +13:00
for(i = 0; i < length; i++) {
if(utfdata[i] <= 0xff) {
jisdata[i] = utfdata[i];
} else {
j = 0;
glyph = 0;
do {
if(sjis_lookup[j * 2] == utfdata[i]) {
glyph = sjis_lookup[(j * 2) + 1];
}
j++;
} while ((j < 6843) && (glyph == 0));
if(glyph == 0) {
strcpy(symbol->errtxt, "Invalid character in input data");
return ERROR_INVALID_DATA;
}
jisdata[i] = glyph;
}
}
break;
2009-08-09 03:25:17 +12:00
}
2009-10-07 08:03:00 +13:00
define_mode(mode, jisdata, length);
est_binlen = estimate_binary_length(mode, length);
ecc_level = LEVEL_L;
max_cw = 2956;
if((symbol->option_1 >= 1) && (symbol->option_1 <= 4)) {
switch (symbol->option_1) {
case 1: ecc_level = LEVEL_L; max_cw = 2956; break;
case 2: ecc_level = LEVEL_M; max_cw = 2334; break;
case 3: ecc_level = LEVEL_Q; max_cw = 1666; break;
case 4: ecc_level = LEVEL_H; max_cw = 1276; break;
}
}
if(est_binlen > (8 * max_cw)) {
strcpy(symbol->errtxt, "Input too long for selected error correction level");
return ERROR_TOO_LONG;
}
autosize = 40;
for(i = 39; i >= 0; i--) {
switch(ecc_level) {
case LEVEL_L:
if ((8 * qr_data_codewords_L[i]) >= est_binlen) {
autosize = i + 1;
}
break;
case LEVEL_M:
if ((8 * qr_data_codewords_M[i]) >= est_binlen) {
autosize = i + 1;
}
break;
case LEVEL_Q:
if ((8 * qr_data_codewords_Q[i]) >= est_binlen) {
autosize = i + 1;
}
break;
case LEVEL_H:
if ((8 * qr_data_codewords_H[i]) >= est_binlen) {
autosize = i + 1;
}
break;
}
}
if((symbol->option_2 >= 1) && (symbol->option_2 <= 40)) {
if (symbol->option_2 > autosize) {
version = symbol->option_2;
} else {
version = autosize;
}
} else {
version = autosize;
}
target_binlen = qr_data_codewords_L[version - 1]; blocks = qr_blocks_L[version - 1];
switch(ecc_level) {
case LEVEL_M: target_binlen = qr_data_codewords_M[version - 1]; blocks = qr_blocks_M[version - 1]; break;
case LEVEL_Q: target_binlen = qr_data_codewords_Q[version - 1]; blocks = qr_blocks_Q[version - 1]; break;
case LEVEL_H: target_binlen = qr_data_codewords_H[version - 1]; blocks = qr_blocks_H[version - 1]; break;
}
#ifndef _MSC_VER
int datastream[target_binlen + 1];
int fullstream[qr_total_codewords[version - 1] + 1];
#else
int datastream = (int *)_alloca((target_binlen + 1) * sizeof(int));
int fullstream = (int *)_alloca((qr_total_codewords[version - 1] + 1) * sizeof(int));
#endif
2009-08-09 03:25:17 +12:00
2009-10-07 08:03:00 +13:00
qr_binary(datastream, version, target_binlen, mode, jisdata, length);
add_ecc(fullstream, datastream, version, target_binlen, blocks);
size = qr_sizes[version - 1];
#ifndef _MSC_VER
unsigned char grid[size * size];
#else
unsigned char grid = (unsigned char *)_alloca((size * size) * sizeof(unsigned char));
#endif
for(i = 0; i < size; i++) {
for(j = 0; j < size; j++) {
grid[(i * size) + j] = 0;
}
2008-07-14 09:15:55 +12:00
}
2009-10-07 08:03:00 +13:00
setup_grid(grid, size);
2008-07-14 09:15:55 +12:00
2009-10-07 08:03:00 +13:00
symbol->width = size;
symbol->rows = size;
for(i = 0; i < size; i++) {
for(j = 0; j < size; j++) {
if(grid[(i * size) + j] & 0x01) {
set_module(symbol, i, j);
2008-07-14 09:15:55 +12:00
}
}
symbol->row_height[i] = 1;
}
2009-10-07 08:03:00 +13:00
printf("Version %d: target %d bytes\n", version, target_binlen);
2008-07-14 09:15:55 +12:00
return 0;
2008-07-14 09:15:55 +12:00
}
2008-09-03 07:49:08 +12:00