/**
* qrencode - QR-code encoder
*
* Copyright (C) 2006 Kentaro Fukuchi
*
* 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
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "qrencode.h"
#include "qrspec.h"
#include "bitstream.h"
#include "datastream.h"
#include "rscode.h"
/******************************************************************************
* Raw code
*****************************************************************************/
typedef struct {
int dataLength;
unsigned char *data;
int eccLength;
unsigned char *ecc;
} RSblock;
typedef struct {
unsigned char *datacode;
int blocks;
RSblock *rsblock;
int count;
int dataLength;
int eccLength;
int b1;
int b2;
} QRRawCode;
static void RSblock_init(RSblock *block, int dl, unsigned char *data, int el)
{
RS *rs;
block->dataLength = dl;
block->data = data;
block->eccLength = el;
block->ecc = (unsigned char *)malloc(el);
rs = init_rs(8, 0x11d, 0, 1, el, 255 - dl - el);
encode_rs_char(rs, data, block->ecc);
}
QRRawCode *QRraw_new(QRenc_DataStream *stream)
{
QRRawCode *raw;
int *spec;
int i;
RSblock *rsblock;
unsigned char *p;
raw = (QRRawCode *)malloc(sizeof(QRRawCode));
raw->datacode = QRenc_getByteStream(stream);
spec = QRspec_getEccSpec(stream->version, stream->level);
raw->blocks = QRspec_rsBlockNum(spec);
raw->rsblock = (RSblock *)malloc(sizeof(RSblock) * raw->blocks);
rsblock = raw->rsblock;
p = raw->datacode;
for(i=0; i<QRspec_rsBlockNum1(spec); i++) {
RSblock_init(rsblock, QRspec_rsDataCodes1(spec), p,
QRspec_rsEccCodes1(spec));
p += QRspec_rsDataCodes1(spec);
rsblock++;
}
for(i=0; i<QRspec_rsBlockNum2(spec); i++) {
RSblock_init(rsblock, QRspec_rsDataCodes2(spec), p,
QRspec_rsEccCodes2(spec));
p += QRspec_rsDataCodes2(spec);
rsblock++;
}
raw->b1 = QRspec_rsBlockNum1(spec);
raw->b2 = QRspec_rsBlockNum2(spec);
raw->dataLength = QRspec_rsBlockNum1(spec) * QRspec_rsDataCodes1(spec)
+ QRspec_rsBlockNum2(spec) * QRspec_rsDataCodes2(spec);
raw->eccLength = QRspec_rsBlockNum(spec) * QRspec_rsEccCodes1(spec);
raw->count = 0;
free(spec);
return raw;
}
/**
* Return a code (byte).
* This function can be called iteratively.
* @param raw raw code.
* @return code
*/
unsigned char QRraw_getCode(QRRawCode *raw)
{
int col, row;
unsigned char ret;
if(raw->count < raw->dataLength) {
row = raw->count % raw->blocks;
col = raw->count / raw->blocks;
if(col >= raw->rsblock[row].dataLength) {
row += raw->b1;
}
ret = raw->rsblock[row].data[col];
} else if(raw->count < raw->dataLength + raw->eccLength) {
row = (raw->count - raw->dataLength) % raw->blocks;
col = (raw->count - raw->dataLength) / raw->blocks;
ret = raw->rsblock[row].ecc[col];
} else {
return 0;
}
raw->count++;
return ret;
}
void QRraw_free(QRRawCode *raw)
{
int i;
free(raw->datacode);
for(i=0; i<raw->blocks; i++) {
free(raw->rsblock[i].ecc);
}
free(raw->rsblock);
free(raw);
}
/******************************************************************************
* Frame filling
*****************************************************************************/
typedef struct {
int width;
unsigned char *frame;
int x, y;
int dir;
int bit;
} FrameFiller;
static FrameFiller *FrameFiller_new(int width, unsigned char *frame)
{
FrameFiller *filler;
filler = (FrameFiller *)malloc(sizeof(FrameFiller));
filler->width = width;
filler->frame = frame;
filler->x = width - 1;
filler->y = width - 1;
filler->dir = -1;
filler->bit = -1;
return filler;
}
static unsigned char *FrameFiller_next(FrameFiller *filler)
{
unsigned char *p;
int x, y, w;
if(filler->bit == -1) {
filler->bit = 0;
return filler->frame + filler->y * filler->width + filler->x;
}
x = filler->x;
y = filler->y;
p = filler->frame;
w = filler->width;
if(filler->bit == 0) {
x--;
filler->bit++;
} else {
x++;
y += filler->dir;
filler->bit--;
}
if(filler->dir < 0) {
if(y < 0) {
y = 0;
x -= 2;
filler->dir = 1;
if(x == 6) {
x--;
y = 9;
}
}
} else {
if(y == w) {
y = w - 1;
x -= 2;
filler->dir = -1;
if(x == 6) {
x--;
y -= 8;
}
}
}
if(x < 0 || y < 0) return NULL;
filler->x = x;
filler->y = y;
if(p[y * w + x] & 0x80) {
// This tail recursion could be optimized.
return FrameFiller_next(filler);
}
return &p[y * w + x];
}
unsigned char *QRenc_fillerTest(int version)
{
int width, length;
unsigned char *frame, *p;
FrameFiller *filler;
int i, j;
unsigned char cl = 1;
unsigned char ch = 0;
width = QRspec_getWidth(version);
frame = QRspec_newFrame(version);
filler = FrameFiller_new(width, frame);
length = QRspec_getDataLength(version, QR_EC_LEVEL_L)
+ QRspec_getECCLength(version, QR_EC_LEVEL_L);
for(i=0; i<length; i++) {
for(j=0; j<8; j++) {
p = FrameFiller_next(filler);
*p = ch | cl;
cl++;
if(cl == 9) {
cl = 1;
ch += 0x10;
}
}
}
length = QRspec_getRemainder(version);
for(i=0; i<length; i++) {
p = FrameFiller_next(filler);
*p = 0xa0;
}
p = FrameFiller_next(filler);
free(filler);
if(p != NULL) {
return NULL;
}
return frame;
}
/******************************************************************************
* Mask
*****************************************************************************/
#define MASKMAKER(__exp__) \
int x, y;\
\
for(y=0; y<width; y++) {\
for(x=0; x<width; x++) {\
if(*s & 0x20) {\
*d = *s ^ ((__exp__) == 0);\
} else {\
*d = *s;\
}\
s++; d++;\
}\
}
static void QRenc_mask0(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER((x+y)&1)
}
static void QRenc_mask1(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER(y&1)
}
static void QRenc_mask2(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER(x%3)
}
static void QRenc_mask3(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER((x+y)%3)
}
static void QRenc_mask4(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER(((y/2)+(x/3))&1)
}
static void QRenc_mask5(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER(((x*y)&1)+(x*y)%3)
}
static void QRenc_mask6(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER((((x*y)&1)+(x*y)%3)&1)
}
static void QRenc_mask7(int width, const unsigned char *s, unsigned char *d)
{
MASKMAKER((((x*y)%3)+((x+y)&1))&1)
}
typedef void MaskMaker(int, const unsigned char *, unsigned char *);
static MaskMaker *maskMakers[] = {
QRenc_mask0, QRenc_mask1, QRenc_mask2, QRenc_mask3,
QRenc_mask4, QRenc_mask5, QRenc_mask6, QRenc_mask7
};
unsigned char *QRenc_mask(int width, unsigned char *frame, int mask)
{
unsigned char *masked;
masked = (unsigned char *)malloc(width * width);
maskMakers[mask](width, frame, masked);
return masked;
}
/******************************************************************************
* QR-code encoding
*****************************************************************************/
unsigned char *QRenc_encode(QRenc_DataStream *stream)
{
int version;
int width;
QRRawCode *raw;
unsigned char *frame, *p, code, mask;
FrameFiller *filler;
int i, j;
version = QRenc_getVersion(stream);
width = QRspec_getWidth(version);
raw = QRraw_new(stream);
frame = QRspec_newFrame(version);
filler = FrameFiller_new(width, frame);
/* inteleaved data and ecc codes */
for(i=0; i<raw->dataLength; i++) {
code = QRraw_getCode(raw);
mask = 0x80;
for(j=0; j<8; j++) {
p = FrameFiller_next(filler);
*p = 0xa0 | ((mask & code) != 0);
mask = mask >> 1;
}
}
/* remainder bits */
j = QRspec_getRemainder(version);
for(i=0; i<j; i++) {
p = FrameFiller_next(filler);
*p = 0xa0;
}
free(filler);
/* masking */
/* put format information */
return frame;
}