Skip to content

Commit

Permalink
Reed-Solomon code routine has been completely rewritten.
Browse files Browse the repository at this point in the history
  • Loading branch information
fukuchi committed Aug 15, 2013
1 parent 055f441 commit f9f6034
Show file tree
Hide file tree
Showing 10 changed files with 262 additions and 82 deletions.
8 changes: 8 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
2013.08.15 Kentaro FUKUCHI <kentaro@fukuchi.org>
* rsecc.[ch], rscode.[ch], Makefile.am, qrencode.c:
- Reed-Solomon error correction code has been completely rewritten.
- Phil Karn's code has been removed (moved to tests).
* tests/test_rs.c, tests/test_qrencode.c, tests/rscode.[ch], tests/Makefile.am:
- Test codes related to ECC have been updated.
- Phil Karn's code has been moved to tests, just for test purpose.

2013.07.29 Kentaro FUKUCHI <kentaro@fukuchi.org>
[3.4]
* configure.ac, README, NEWS:
Expand Down
2 changes: 1 addition & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ libqrencode_la_SOURCES = qrencode.c qrencode_inner.h \
qrinput.c qrinput.h \
bitstream.c bitstream.h \
qrspec.c qrspec.h \
rscode.c rscode.h \
rsecc.c rsecc.h \
split.c split.h \
mask.c mask.h \
mqrspec.c mqrspec.h \
Expand Down
25 changes: 6 additions & 19 deletions qrencode.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#include "mqrspec.h"
#include "bitstream.h"
#include "qrinput.h"
#include "rscode.h"
#include "rsecc.h"
#include "split.h"
#include "mask.h"
#include "mmask.h"
Expand Down Expand Up @@ -59,34 +59,31 @@ typedef struct {
int count;
} QRRawCode;

static void RSblock_initBlock(RSblock *block, int dl, unsigned char *data, int el, unsigned char *ecc, RS *rs)
static void RSblock_initBlock(RSblock *block, int dl, unsigned char *data, int el, unsigned char *ecc)
{
block->dataLength = dl;
block->data = data;
block->eccLength = el;
block->ecc = ecc;

encode_rs_char(rs, data, ecc);
RSECC_encode(el, 255 - dl - el, data, ecc);
}

static int RSblock_init(RSblock *blocks, int spec[5], unsigned char *data, unsigned char *ecc)
{
int i;
RSblock *block;
unsigned char *dp, *ep;
RS *rs;
int el, dl;

dl = QRspec_rsDataCodes1(spec);
el = QRspec_rsEccCodes1(spec);
rs = init_rs(8, 0x11d, 0, 1, el, 255 - dl - el);
if(rs == NULL) return -1;

block = blocks;
dp = data;
ep = ecc;
for(i=0; i<QRspec_rsBlockNum1(spec); i++) {
RSblock_initBlock(block, dl, dp, el, ep, rs);
RSblock_initBlock(block, dl, dp, el, ep);
dp += dl;
ep += el;
block++;
Expand All @@ -96,10 +93,8 @@ static int RSblock_init(RSblock *blocks, int spec[5], unsigned char *data, unsig

dl = QRspec_rsDataCodes2(spec);
el = QRspec_rsEccCodes2(spec);
rs = init_rs(8, 0x11d, 0, 1, el, 255 - dl - el);
if(rs == NULL) return -1;
for(i=0; i<QRspec_rsBlockNum2(spec); i++) {
RSblock_initBlock(block, dl, dp, el, ep, rs);
RSblock_initBlock(block, dl, dp, el, ep);
dp += dl;
ep += el;
block++;
Expand Down Expand Up @@ -211,7 +206,6 @@ __STATIC void MQRraw_free(MQRRawCode *raw);
__STATIC MQRRawCode *MQRraw_new(QRinput *input)
{
MQRRawCode *raw;
RS *rs;

raw = (MQRRawCode *)malloc(sizeof(MQRRawCode));
if(raw == NULL) return NULL;
Expand All @@ -238,13 +232,7 @@ __STATIC MQRRawCode *MQRraw_new(QRinput *input)
return NULL;
}

rs = init_rs(8, 0x11d, 0, 1, raw->eccLength, 255 - raw->dataLength - raw->eccLength);
if(rs == NULL) {
MQRraw_free(raw);
return NULL;
}

RSblock_initBlock(raw->rsblock, raw->dataLength, raw->datacode, raw->eccLength, raw->ecccode, rs);
RSblock_initBlock(raw->rsblock, raw->dataLength, raw->datacode, raw->eccLength, raw->ecccode);

raw->count = 0;

Expand Down Expand Up @@ -925,5 +913,4 @@ void QRcode_clearCache(void)
{
QRspec_clearCache();
MQRspec_clearCache();
free_rs_cache();
}
131 changes: 131 additions & 0 deletions rsecc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/*
* qrencode - QR Code encoder
*
* Reed solomon error correction code encoder specialized for QR code.
*
* Copyright (C) 2013 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#if HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <string.h>

#include "rsecc.h"

static int initialized = 0;

#define SYMBOL_SIZE (8)
static const int proot = 0x11d; /* stands for x^8+x^4+x^3+x^2+1 (see pp.37 of JIS X0510:2004) */
#define symbols ((1 << SYMBOL_SIZE) - 1)
#define max_generatorSize (30)

#define min_length (2)
#define max_length (max_generatorSize)

static unsigned char alpha[symbols + 1];
static unsigned char aindex[symbols + 1];
static unsigned char generator[max_length - min_length + 1][max_generatorSize + 1];
static unsigned char generatorInitialized[max_length - min_length + 1];

static void RSECC_initLookupTable(void)
{
int i, b;

alpha[symbols] = 0;
aindex[0] = symbols;

b = 1;
for(i = 0; i < symbols; i++) {
alpha[i] = b;
aindex[b] = i;
b <<= 1;
if(b & (symbols + 1)) {
b ^= proot;
}
b &= symbols;
}
}

void RSECC_init(void)
{
RSECC_initLookupTable();
memset(generatorInitialized, 0, (max_length - min_length));
initialized = 1;
}

static void generator_init(int length)
{
int i, j, a;
int g[max_generatorSize + 1];

g[0] = 1;
a = 0;
for(i = 1; i <= length; i++) {
g[i] = 1;
for(j = i - 1; j > 0; j--) {
if(g[0] != 0) {
g[j] = g[j - 1] ^ alpha[(aindex[g[j]] + a) % symbols];
} else {
g[j] = g[j - 1];
}
}
g[0] = alpha[(aindex[g[0]] + a) % symbols];
a++;
}

for(i = 0; i <= length; i++) {
generator[length - min_length][i] = aindex[g[i]];
}

generatorInitialized[length - min_length] = 1;
}

int RSECC_encode(int length, int pad, const unsigned char *data, unsigned char *ecc)
{
int i, j;
unsigned char feedback;
unsigned char *gen;

if(!initialized) {
RSECC_init();
}

if(length > max_length) return -1;

memset(ecc, 0, length);
if(!generatorInitialized[length - min_length]) generator_init(length);
gen = generator[length - min_length];

for(i = 0; i < symbols - length - pad; i++) {
feedback = aindex[data[i] ^ ecc[0]];
if(feedback != symbols) {
for(j = 1; j < length; j++) {
ecc[j] ^= alpha[(feedback + gen[length - j]) % symbols];
}
}
memmove(&ecc[0], &ecc[1], length - 1);
if(feedback != symbols) {
ecc[length - 1] = alpha[(feedback + gen[0]) % symbols];
} else {
ecc[length - 1] = 0;
}
}

return 0;
}
28 changes: 28 additions & 0 deletions rsecc.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* qrencode - QR Code encoder
*
* Reed solomon error correction code encoder specialized for QR code.
*
* Copyright (C) 2006-2011 Kentaro Fukuchi <kentaro@fukuchi.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

#ifndef __RSECC_H__
#define __RSECC_H__

extern int RSECC_encode(int length, int pad, const unsigned char *data, unsigned char *ecc);

#endif /* __RSECC_H__ */
4 changes: 2 additions & 2 deletions tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ noinst_PROGRAMS = test_qrinput test_bitstream test_estimatebit \
$(sdlPROGRAMS)
noinst_LIBRARIES = libdecoder.a
DECODER_LIBS = libdecoder.a $(LIBICONV)
noinst_HEADERS = common.h
noinst_HEADERS = common.h rscode.h
if HAVE_LIBPTHREAD
noinst_PROGRAMS += pthread_qrencode
endif
Expand All @@ -33,7 +33,7 @@ test_qrspec_LDADD = ../libqrencode.la $(DECODER_LIBS)
test_mqrspec_SOURCES = test_mqrspec.c
test_mqrspec_LDADD = ../libqrencode.la $(DECODER_LIBS)

test_rs_SOURCES = test_rs.c
test_rs_SOURCES = test_rs.c rscode.c
test_rs_LDADD = ../libqrencode.la

test_qrencode_SOURCES = test_qrencode.c
Expand Down
55 changes: 1 addition & 54 deletions rscode.c → tests/rscode.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,6 @@
#endif
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_LIBPTHREAD
# include <pthread.h>
#endif

#include "rscode.h"

Expand All @@ -56,14 +53,8 @@ struct _RS {
int iprim; /* prim-th root of 1, index form */
int pad; /* Padding bytes in shortened block */
int gfpoly;
struct _RS *next;
};

static RS *rslist = NULL;
#ifdef HAVE_LIBPTHREAD
static pthread_mutex_t rslist_mutex = PTHREAD_MUTEX_INITIALIZER;
#endif

static inline int modnn(RS *rs, int x){
while (x >= rs->nn) {
x -= rs->nn;
Expand Down Expand Up @@ -211,32 +202,7 @@ static RS *init_rs_char(int symsize, int gfpoly, int fcr, int prim, int nroots,

RS *init_rs(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad)
{
RS *rs;

#ifdef HAVE_LIBPTHREAD
pthread_mutex_lock(&rslist_mutex);
#endif
for(rs = rslist; rs != NULL; rs = rs->next) {
if(rs->pad != pad) continue;
if(rs->nroots != nroots) continue;
if(rs->mm != symsize) continue;
if(rs->gfpoly != gfpoly) continue;
if(rs->fcr != fcr) continue;
if(rs->prim != prim) continue;

goto DONE;
}

rs = init_rs_char(symsize, gfpoly, fcr, prim, nroots, pad);
if(rs == NULL) goto DONE;
rs->next = rslist;
rslist = rs;

DONE:
#ifdef HAVE_LIBPTHREAD
pthread_mutex_unlock(&rslist_mutex);
#endif
return rs;
return init_rs_char(symsize, gfpoly, fcr, prim, nroots, pad);
}


Expand All @@ -248,25 +214,6 @@ void free_rs_char(RS *rs)
free(rs);
}

void free_rs_cache(void)
{
RS *rs, *next;

#ifdef HAVE_LIBPTHREAD
pthread_mutex_lock(&rslist_mutex);
#endif
rs = rslist;
while(rs != NULL) {
next = rs->next;
free_rs_char(rs);
rs = next;
}
rslist = NULL;
#ifdef HAVE_LIBPTHREAD
pthread_mutex_unlock(&rslist_mutex);
#endif
}

/* The guts of the Reed-Solomon encoder, meant to be #included
* into a function body with the following typedefs, macros and variables supplied
* according to the code parameters:
Expand Down
1 change: 0 additions & 1 deletion rscode.h → tests/rscode.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,5 @@ typedef struct _RS RS;
extern RS *init_rs(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad);
extern void encode_rs_char(RS *rs, const unsigned char *data, unsigned char *parity);
extern void free_rs_char(RS *rs);
extern void free_rs_cache(void);

#endif /* __RSCODE_H__ */
2 changes: 1 addition & 1 deletion tests/test_qrencode.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include "../mqrspec.h"
#include "../qrinput.h"
#include "../mask.h"
#include "../rscode.h"
#include "../rsecc.h"
#include "../split.h"
#include "decoder.h"

Expand Down
Loading

0 comments on commit f9f6034

Please sign in to comment.