summaryrefslogtreecommitdiffstats
path: root/zbar/qrcode/bch15_5.c
diff options
context:
space:
mode:
Diffstat (limited to 'zbar/qrcode/bch15_5.c')
-rw-r--r--zbar/qrcode/bch15_5.c207
1 files changed, 207 insertions, 0 deletions
diff --git a/zbar/qrcode/bch15_5.c b/zbar/qrcode/bch15_5.c
new file mode 100644
index 0000000..2295ad9
--- /dev/null
+++ b/zbar/qrcode/bch15_5.c
@@ -0,0 +1,207 @@
+/*Copyright (C) 2008-2009 Timothy B. Terriberry (tterribe@xiph.org)
+ You can redistribute this library 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 (at your option) any later
+ version.*/
+#include "bch15_5.h"
+
+/*A cycle in GF(2**4) generated by alpha=(x**4+x+1).
+ It is extended an extra 16 entries to avoid some expensive mod operations.*/
+static const unsigned char gf16_exp[31] = { 1, 2, 4, 8, 3, 6, 12, 11,
+ 5, 10, 7, 14, 15, 13, 9, 1,
+ 2, 4, 8, 3, 6, 12, 11, 5,
+ 10, 7, 14, 15, 13, 9, 1 };
+
+/*The location of each integer 1...16 in the cycle.*/
+static const signed char gf16_log[16] = { -1, 0, 1, 4, 2, 8, 5, 10,
+ 3, 14, 9, 7, 6, 13, 11, 12 };
+
+/*Multiplication in GF(2**4) using logarithms.*/
+static unsigned gf16_mul(unsigned _a, unsigned _b)
+{
+ return _a == 0 || _b == 0 ? 0 : gf16_exp[gf16_log[_a] + gf16_log[_b]];
+}
+
+/*Division in GF(2**4) using logarithms.
+ The result when dividing by zero is undefined.*/
+static unsigned gf16_div(unsigned _a, unsigned _b)
+{
+ return _a == 0 ? 0 : gf16_exp[gf16_log[_a] + 15 - gf16_log[_b]];
+}
+
+/*Multiplication in GF(2**4) when the second argument is known to be non-zero
+ (proven by representing it by its logarithm).*/
+static unsigned gf16_hmul(unsigned _a, unsigned _logb)
+{
+ return _a == 0 ? 0 : gf16_exp[gf16_log[_a] + _logb];
+}
+
+/*The syndrome normally has five values, S_1 ... S_5.
+ We only calculate and store the odd ones in _s, since S_2=S_1**2 and
+ S_4=S_2**2.
+ Returns zero iff all the syndrome values are zero.*/
+static int bch15_5_calc_syndrome(unsigned _s[3], unsigned _y)
+{
+ unsigned p;
+ int i;
+ int j;
+ p = 0;
+ for (i = 0; i < 15; i++)
+ if (_y & 1 << i)
+ p ^= gf16_exp[i];
+ _s[0] = p;
+ p = 0;
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 5; j++)
+ if (_y & 1 << 5 * i + j)
+ p ^= gf16_exp[j * 3];
+ _s[1] = p;
+ p = 0;
+ for (i = 0; i < 5; i++)
+ for (j = 0; j < 3; j++)
+ if (_y & 1 << 3 * i + j)
+ p ^= gf16_exp[j * 5];
+ _s[2] = p;
+ return _s[0] != 0 || _s[1] != 0 || _s[2] != 0;
+}
+
+/*Compute the coefficients of the error-locator polynomial.
+ Returns the number of errors (the degree of the polynomial).*/
+static int bch15_5_calc_omega(unsigned _o[3], unsigned _s[3])
+{
+ unsigned s02;
+ unsigned tt;
+ unsigned dd;
+ int d;
+ _o[0] = _s[0];
+ s02 = gf16_mul(_s[0], _s[0]);
+ dd = _s[1] ^ gf16_mul(_s[0], s02);
+ tt = _s[2] ^ gf16_mul(s02, _s[1]);
+ _o[1] = dd ? gf16_div(tt, dd) : 0;
+ _o[2] = dd ^ gf16_mul(_s[0], _o[1]);
+ for (d = 3; d > 0 && !_o[d - 1]; d--)
+ ;
+ return d;
+}
+
+/*Find the roots of the error polynomial.
+ Returns the number of roots found, or a negative value if the polynomial did
+ not have enough roots, indicating a decoding error.*/
+static int bch15_5_calc_epos(unsigned _epos[3], unsigned _s[3])
+{
+ unsigned o[3];
+ int nerrors;
+ int d;
+ int i;
+ d = bch15_5_calc_omega(o, _s);
+ nerrors = 0;
+ if (d == 1)
+ _epos[nerrors++] = gf16_log[o[0]];
+ else if (d > 0) {
+ for (i = 0; i < 15; i++) {
+ int i2;
+ i2 = gf16_log[gf16_exp[i << 1]];
+ if (!(gf16_exp[i + i2] ^ gf16_hmul(o[0], i2) ^ gf16_hmul(o[1], i) ^
+ o[2])) {
+ _epos[nerrors++] = i;
+ }
+ }
+ if (nerrors < d)
+ return -1;
+ }
+ return nerrors;
+}
+
+int bch15_5_correct(unsigned *_y)
+{
+ unsigned s[3];
+ unsigned epos[3];
+ unsigned y;
+ int nerrors;
+ int i;
+ y = *_y;
+ if (!bch15_5_calc_syndrome(s, y))
+ return 0;
+ nerrors = bch15_5_calc_epos(epos, s);
+ if (nerrors > 0) {
+ /*If we had a non-zero syndrome value, we should always find at least one
+ error location, or we've got a decoding error.*/
+ for (i = 0; i < nerrors; i++)
+ y ^= 1 << epos[i];
+ /*If there were too many errors, we may not find enough roots to reduce the
+ syndrome to zero.
+ We could recompute it to check, but it's much faster just to check that
+ we have a valid codeword.*/
+ if (bch15_5_encode(y >> 10) == y) {
+ /*Decoding succeeded.*/
+ *_y = y;
+ return nerrors;
+ }
+ }
+ /*Decoding failed due to too many bit errors.*/
+ return -1;
+}
+
+unsigned bch15_5_encode(unsigned _x)
+{
+ return (-(_x & 1) & 0x0537) ^ (-(_x >> 1 & 1) & 0x0A6E) ^
+ (-(_x >> 2 & 1) & 0x11EB) ^ (-(_x >> 3 & 1) & 0x23D6) ^
+ (-(_x >> 4 & 1) & 0x429B);
+}
+
+#if 0
+#include <stdio.h>
+
+static unsigned codes[32];
+
+static int hamming(int _a,int _b){
+ int d;
+ int n;
+ d=_a^_b;
+ for(n=0;d;n++)d&=d-1;
+ return n;
+}
+
+static int closest(int _y){
+ int min_i;
+ int min_d;
+ int i;
+ int d;
+ min_i=0;
+ min_d=hamming(_y,codes[0]);
+ for(i=1;i<32;i++){
+ d=hamming(_y,codes[i]);
+ if(d<min_d){
+ min_d=d;
+ min_i=i;
+ }
+ }
+ return codes[min_i];
+}
+
+int main(void){
+ int i;
+ /*Print a list of the valid (uncorrupt) codewords.*/
+ for(i=0;i<32;i++)codes[i]=bch15_5_encode(i);
+ for(i=0;i<32;i++)printf("0x%04X%s",codes[i],i+1<32?" ":"\n");
+ /*Try to decode all receivable (possibly corrupt) codewords.*/
+ for(i=0;i<0x8000;i++){
+ unsigned y;
+ unsigned z;
+ int nerrors;
+ int j;
+ y=i;
+ nerrors=bch15_5_correct(&y);
+ z=closest(i);
+ if(nerrors<0){
+ printf("0x%04X->Failed\n",i);
+ if(hamming(i,z)<=3)printf("Error: 0x%04X should map to 0x%04X\n",i,z);
+ }
+ else{
+ printf("0x%04X->0x%04X\n",i,y);
+ if(z!=y)printf("Error: 0x%04X should map to 0x%04X\n",i,z);
+ }
+ }
+ return 0;
+}
+#endif