From ad59de83b7f82cb812d23ac2bb948ac32fe0ac71 Mon Sep 17 00:00:00 2001
From: Leo Howell <leo@lwh.jp>
Date: Thu, 8 Oct 2009 12:18:31 +0900
Subject: Render ec level, mask info bits

---
 lpg/libqr/code-create.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++-
 lpg/libqr/qr/code.h     |   8 ++--
 2 files changed, 102 insertions(+), 6 deletions(-)

(limited to 'lpg/libqr')

diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c
index 5582a30..9ce46f7 100644
--- a/lpg/libqr/code-create.c
+++ b/lpg/libqr/code-create.c
@@ -19,6 +19,12 @@ static int count_locators(const struct qr_bitmap * bmp);
 static int calc_bw_balance(const struct qr_bitmap * bmp);
 static int get_px(const struct qr_bitmap * bmp, int x, int y);
 static int get_mask(const struct qr_bitmap * bmp, int x, int y);
+static int draw_format(struct qr_bitmap * bmp,
+                        struct qr_code * code,
+                        enum qr_ec_level ec,
+                        int mask);
+static int calc_format_bits(enum qr_ec_level ec, int mask);
+static unsigned long gal_residue(unsigned long a, unsigned long m);
 
 /* FIXME: the static functions should be in a better
  * order, with prototypes.
@@ -63,6 +69,7 @@ static void draw_locator(struct qr_bitmap * bmp, int x, int y)
 }
 
 static int draw_functional(struct qr_code * code,
+                           enum qr_ec_level ec,
                            unsigned int mask)
 {
         struct qr_bitmap * bmp;
@@ -85,8 +92,13 @@ static int draw_functional(struct qr_code * code,
         }
 
         /* XXX: alignment pattern */
-        /* XXX: mask, format info */
 
+        /* Format info */
+        setpx(bmp, 8, dim - 8);
+        if (draw_format(bmp, code, ec, mask) != 0)
+                return -1;
+
+        /* Merge data */
         qr_bitmap_merge(bmp, code->modules);
         qr_bitmap_destroy(code->modules);
         code->modules = bmp;
@@ -261,7 +273,7 @@ struct qr_code * qr_code_create(enum qr_ec_level       ec,
         if (mask < 0)
                 goto fail;
 
-        if (draw_functional(code, mask) != 0)
+        if (draw_functional(code, ec, mask) != 0)
                 goto fail;
 
 exit:
@@ -466,3 +478,87 @@ static int get_mask(const struct qr_bitmap * bmp, int x, int y)
         return bmp->mask[off] & bit;
 }
 
+static int draw_format(struct qr_bitmap * bmp,
+                        struct qr_code * code,
+                        enum qr_ec_level ec,
+                        int mask)
+{
+        int i;
+        size_t dim;
+        long bits;
+
+        dim = bmp->width;
+
+        bits = calc_format_bits(ec, mask);
+        if (bits < 0)
+                return -1;
+
+        for (i = 0; i < 8; ++i) {
+                if (bits & 0x1) {
+                        setpx(bmp, 8, i);
+                        setpx(bmp, dim - 1 - i, 8);
+                }
+                bits >>= 1;
+        }
+
+        for (i = 0; i < 7; ++i) {
+                if (bits & 0x1) {
+                        setpx(bmp, 8, dim - 7 + i);
+                        setpx(bmp, 6 - i + (i == 0), 8);
+                }
+                bits >>= 1;
+        }
+
+        /* XXX: size info for 7~40 */
+
+        return 0;
+}
+
+static int calc_format_bits(enum qr_ec_level ec, int mask)
+{
+        int bits;
+
+        bits = (ec & 0x3) << 3 | (mask & 0x7);
+
+        /* Compute (15, 5) BCH code with
+         *   G(x) = x^10 + x^8 + x^5 + x^4 + x^2 + x + 1
+         */
+
+        bits <<= 15 - 5;
+        bits |= (unsigned int)gal_residue(bits, 0x537);
+
+        /* XOR mask: 101 0100 0001 0010 */
+        bits ^= 0x5412;
+
+        return bits;
+}
+
+/* Calculate the residue of a modulo m */
+static unsigned long gal_residue(unsigned long a,
+                                   unsigned long m)
+{
+        unsigned long o = 1;
+        int n = 1;
+
+        /* Find one past the highest bit of the modulus */
+        while (m & ~(o - 1))
+                o <<= 1;
+
+        /* Find the highest n such that O(m * x^n) <= O(a) */
+        while (a & ~(o - 1)) {
+                o <<= 1;
+                ++n;
+        }
+
+        /* For each n, try to reduce a by (m * x^n) */
+        while (n--) {
+                o >>= 1;
+
+                /* o is the highest bit of (m * x^n) */
+                if (a & o)
+                        a ^= m << n;
+        }
+
+        return a;
+}
+
diff --git a/lpg/libqr/qr/code.h b/lpg/libqr/qr/code.h
index 56a9884..dba0040 100644
--- a/lpg/libqr/qr/code.h
+++ b/lpg/libqr/qr/code.h
@@ -5,10 +5,10 @@
 #include "types.h"
 
 enum qr_ec_level {
-        QR_EC_LEVEL_L,
-        QR_EC_LEVEL_M,
-        QR_EC_LEVEL_Q,
-        QR_EC_LEVEL_H
+        QR_EC_LEVEL_L = 0x1,
+        QR_EC_LEVEL_M = 0x0,
+        QR_EC_LEVEL_Q = 0x3,
+        QR_EC_LEVEL_H = 0x2
 };
 
 struct qr_code * qr_code_create(enum qr_ec_level       ec,
-- 
cgit v1.2.3-70-g09d2