aboutsummaryrefslogtreecommitdiff
path: root/lpg/libqr
diff options
context:
space:
mode:
Diffstat (limited to 'lpg/libqr')
-rw-r--r--lpg/libqr/.gitignore6
-rw-r--r--lpg/libqr/COPYING15
-rw-r--r--lpg/libqr/Makefile33
-rw-r--r--lpg/libqr/TODO11
-rw-r--r--lpg/libqr/bitmap.c216
-rw-r--r--lpg/libqr/bitstream.c243
-rw-r--r--lpg/libqr/code-common.c109
-rw-r--r--lpg/libqr/code-create.c565
-rw-r--r--lpg/libqr/code-layout.c188
-rw-r--r--lpg/libqr/code-parse.c348
-rw-r--r--lpg/libqr/constants.c151
-rw-r--r--lpg/libqr/constants.h29
-rw-r--r--lpg/libqr/data-common.c38
-rw-r--r--lpg/libqr/data-create.c273
-rw-r--r--lpg/libqr/data-parse.c240
-rw-r--r--lpg/libqr/galois.c125
-rw-r--r--lpg/libqr/galois.h11
-rw-r--r--lpg/libqr/qr/bitmap.h37
-rw-r--r--lpg/libqr/qr/bitstream.h57
-rw-r--r--lpg/libqr/qr/code.h25
-rw-r--r--lpg/libqr/qr/common.h32
-rw-r--r--lpg/libqr/qr/data.h41
-rw-r--r--lpg/libqr/qr/layout.h22
-rw-r--r--lpg/libqr/qr/parse.h24
-rw-r--r--lpg/libqr/qr/types.h34
-rw-r--r--lpg/libqr/qr/version.h18
-rw-r--r--lpg/libqr/qrgen.c402
-rw-r--r--lpg/libqr/qrparse.c59
-rw-r--r--lpg/libqr/testqr.xbm19
29 files changed, 3371 insertions, 0 deletions
diff --git a/lpg/libqr/.gitignore b/lpg/libqr/.gitignore
new file mode 100644
index 0000000..33bcf18
--- /dev/null
+++ b/lpg/libqr/.gitignore
@@ -0,0 +1,6 @@
+*~
+*.o
+*.a
+*.so
+qrgen
+qrparse
diff --git a/lpg/libqr/COPYING b/lpg/libqr/COPYING
new file mode 100644
index 0000000..ff2f585
--- /dev/null
+++ b/lpg/libqr/COPYING
@@ -0,0 +1,15 @@
+I, the author, hereby release this work into the public domain.
+
+Where the above is not possible, I release this work as "Copyright
+Free", or (at your option) under the terms of the Creative Commons CC0
+license:
+
+ http://creativecommons.org/publicdomain/zero/1.0/
+
+The author waives all rights concerning the modification, reproduction
+and/or distribution of this work, or derivatives thereof, in whole or
+in part, and in any form. Attribution is not required.
+
+
+Leo Howell, September 2009
+
diff --git a/lpg/libqr/Makefile b/lpg/libqr/Makefile
new file mode 100644
index 0000000..176c30c
--- /dev/null
+++ b/lpg/libqr/Makefile
@@ -0,0 +1,33 @@
+# XXX: This Makefile only works single-threaded, -j1 is required.
+OBJECTS := bitmap.o \
+ bitstream.o \
+ constants.o \
+ code-common.o \
+ code-create.o \
+ code-layout.o \
+ code-parse.o \
+ data-common.o \
+ data-create.o \
+ data-parse.o \
+ galois.o
+
+CFLAGS := -std=c89 -pedantic -I. -Wall
+CFLAGS += -g
+#CFLAGS += -O3 -DNDEBUG
+
+all : libqr qrgen qrparse
+
+$(OBJECTS) : $(wildcard *.h qr/*.h)
+
+libqr : libqr.a($(OBJECTS))
+
+qrgen : libqr qrgen.c
+ $(CC) $(CFLAGS) -o qrgen qrgen.c libqr.a $(shell pkg-config libpng --cflags --libs)
+
+qrparse : libqr qrparse.c
+ $(CC) $(CFLAGS) -o qrparse qrparse.c libqr.a
+
+.PHONY : clean
+clean:
+ $(RM) qr/*~ *~ *.o *.a *.so qrgen
+
diff --git a/lpg/libqr/TODO b/lpg/libqr/TODO
new file mode 100644
index 0000000..1b9671b
--- /dev/null
+++ b/lpg/libqr/TODO
@@ -0,0 +1,11 @@
+* Parsing
+
+* Detection
+
+* Test suite
+* No-malloc
+* Optimize
+* Documentation
+
+* Other data types
+
diff --git a/lpg/libqr/bitmap.c b/lpg/libqr/bitmap.c
new file mode 100644
index 0000000..246b9bd
--- /dev/null
+++ b/lpg/libqr/bitmap.c
@@ -0,0 +1,216 @@
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <qr/bitmap.h>
+
+struct qr_bitmap * qr_bitmap_create(size_t width, size_t height, int masked)
+{
+ struct qr_bitmap * out;
+ size_t size;
+
+ out = malloc(sizeof(*out));
+ if (!out)
+ goto fail;
+
+ out->width = width;
+ out->height = height;
+ out->stride = (width / CHAR_BIT) + (width % CHAR_BIT ? 1 : 0);
+
+ size = out->stride * height;
+
+ out->mask = 0;
+ out->bits = malloc(size);
+ if (!out->bits)
+ goto fail;
+ memset(out->bits, 0, size);
+
+ if (masked) {
+ out->mask = malloc(out->stride * width);
+ if (!out->mask)
+ goto fail;
+ memset(out->mask, 0xFF, size);
+ }
+
+ return out;
+
+fail:
+ qr_bitmap_destroy(out);
+ return 0;
+}
+
+void qr_bitmap_destroy(struct qr_bitmap * bmp)
+{
+ if (bmp) {
+ free(bmp->bits);
+ free(bmp->mask);
+ free(bmp);
+ }
+}
+
+int qr_bitmap_add_mask(struct qr_bitmap * bmp)
+{
+ size_t size = bmp->stride * bmp->width;
+ bmp->mask = malloc(size);
+ if (!bmp->mask)
+ return -1;
+ memset(bmp->mask, 0xFF, size);
+ return 0;
+}
+
+struct qr_bitmap * qr_bitmap_clone(const struct qr_bitmap * src)
+{
+ struct qr_bitmap * bmp;
+ size_t size;
+
+ bmp = qr_bitmap_create(src->width, src->height, !!src->mask);
+ if (!bmp)
+ return 0;
+
+ assert(bmp->stride == src->stride);
+
+ size = bmp->width * bmp->stride;
+ memcpy(bmp->bits, src->bits, size);
+ if (bmp->mask)
+ memcpy(bmp->mask, src->mask, size);
+
+ return bmp;
+}
+
+void qr_bitmap_merge(struct qr_bitmap * dest, const struct qr_bitmap * src)
+{
+ unsigned char * d, * s, * m;
+ size_t n;
+
+ assert(dest->stride == src->stride);
+ assert(dest->height == src->height);
+ assert(src->mask);
+
+ n = dest->stride * dest->height;
+ d = dest->bits;
+ s = src->bits;
+ m = src->mask;
+
+ while (n--) {
+ *d &= ~*m;
+ *d++ |= *s++ & *m++;
+ }
+}
+
+/* CHAR_BIT | mod_bits (multi-byte) */
+static void render_line_1(unsigned char * out,
+ const unsigned char * in,
+ size_t mod_bits,
+ size_t dim,
+ unsigned long mark,
+ unsigned long space)
+{
+ unsigned char in_mask;
+ size_t n, b;
+
+ in_mask = 1;
+ n = dim;
+
+ while (n-- > 0) {
+ unsigned long v = (*in & in_mask) ? mark : space;
+
+ if ((in_mask <<= 1) == 0) {
+ in_mask = 1;
+ ++in;
+ }
+
+ b = mod_bits / CHAR_BIT;
+ while (b-- > 0) {
+ *out++ = (unsigned char) v;
+ v >>= CHAR_BIT;
+ }
+ }
+}
+
+/* mod_bits | CHAR_BIT (packed) */
+static void render_line_2(unsigned char * out,
+ const unsigned char * in,
+ size_t mod_bits,
+ size_t dim,
+ unsigned long mark,
+ unsigned long space)
+{
+ unsigned char in_mask;
+ size_t n, b, step;
+
+ in_mask = 1;
+ step = CHAR_BIT / mod_bits;
+ n = dim;
+
+ while (n > 0) {
+ unsigned char tmp = 0;
+
+ b = step;
+ while (b-- > 0) {
+ unsigned long v = (*in & in_mask) ? mark : space;
+
+ if ((in_mask <<= 1) == 0) {
+ in_mask = 1;
+ ++in;
+ }
+
+ tmp |= v << (b * mod_bits);
+ if (--n == 0)
+ break;
+ };
+
+ *out++ = tmp;
+ }
+}
+
+void qr_bitmap_render(const struct qr_bitmap * bmp,
+ void * buffer,
+ int mod_bits,
+ long line_stride,
+ int line_repeat,
+ unsigned long mark,
+ unsigned long space)
+{
+ unsigned char * out;
+ const unsigned char * in;
+ size_t n, dim;
+ int pack;
+
+ pack = (mod_bits < CHAR_BIT);
+ assert(!pack || (CHAR_BIT % mod_bits == 0));
+ assert( pack || (mod_bits % CHAR_BIT == 0));
+
+ in = bmp->bits;
+ out = buffer;
+ dim = bmp->width;
+
+ if (pack) {
+ mark &= (1 << mod_bits) - 1;
+ space &= (1 << mod_bits) - 1;
+ }
+
+ n = dim;
+ while (n-- > 0) {
+ size_t rpt;
+ unsigned char * next;
+
+ if (pack)
+ render_line_2(out, in, mod_bits, dim, mark, space);
+ else
+ render_line_1(out, in, mod_bits, dim, mark, space);
+
+ rpt = line_repeat;
+ next = out + line_stride;
+ while (--rpt > 0) {
+ size_t bits = dim * mod_bits;
+ size_t bytes = bits / CHAR_BIT + !!(bits % CHAR_BIT);
+ memcpy(next, out, bytes);
+ next += line_stride;
+ }
+
+ in += bmp->stride;
+ out = next;
+ }
+}
+
diff --git a/lpg/libqr/bitstream.c b/lpg/libqr/bitstream.c
new file mode 100644
index 0000000..cc8a1ae
--- /dev/null
+++ b/lpg/libqr/bitstream.c
@@ -0,0 +1,243 @@
+/**
+ * It would perhaps be more sensible just to store the bits
+ * as an array of char or similar, but this way is more fun.
+ * This is a pretty inefficient implementation, althought I
+ * suspect that won't be a problem.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <assert.h>
+
+#include <qr/bitstream.h>
+
+#define MAX(a, b) ((a) < (b) ? (b) : (a))
+#define MIN(a, b) ((a) > (b) ? (b) : (a))
+
+struct qr_bitstream {
+ size_t pos; /* bits */
+ size_t count; /* bits */
+ size_t bufsiz; /* bytes */
+ unsigned char * buffer;
+};
+
+static size_t bits_to_bytes(size_t bits)
+{
+ return (bits / CHAR_BIT) + (bits % CHAR_BIT != 0);
+}
+
+static int ensure_available(struct qr_bitstream * stream, size_t bits)
+{
+ size_t need_bits = stream->pos + bits;
+ size_t newsize;
+
+ if (stream->bufsiz * CHAR_BIT >= need_bits)
+ return 0;
+
+ newsize = MAX(stream->bufsiz, 100) * CHAR_BIT;
+ while (newsize < need_bits)
+ newsize *= 2;
+
+ return qr_bitstream_resize(stream, newsize);
+}
+
+struct qr_bitstream * qr_bitstream_create(void)
+{
+ struct qr_bitstream * obj;
+
+ obj = malloc(sizeof(*obj));
+
+ if (obj) {
+ obj->pos = 0;
+ obj->count = 0;
+ obj->bufsiz = 0;
+ obj->buffer = 0;
+ }
+
+ return obj;
+}
+
+int qr_bitstream_resize(struct qr_bitstream * stream, size_t bits)
+{
+ size_t newsize;
+ void * newbuf;
+
+ newsize = bits_to_bytes(bits);
+ newbuf = realloc(stream->buffer, newsize);
+
+ if (newbuf) {
+ stream->bufsiz = newsize;
+ stream->buffer = newbuf;
+ }
+
+ return newbuf ? 0 : -1;
+}
+
+void qr_bitstream_destroy(struct qr_bitstream * stream)
+{
+ free(stream->buffer);
+ free(stream);
+}
+
+struct qr_bitstream * qr_bitstream_dup(const struct qr_bitstream * src)
+{
+ struct qr_bitstream * ret;
+
+ ret = qr_bitstream_create();
+ if (!ret)
+ return 0;
+
+ if (qr_bitstream_resize(ret, src->count) != 0) {
+ free(ret);
+ return 0;
+ }
+
+ ret->pos = src->pos;
+ ret->count = src->count;
+ memcpy(ret->buffer, src->buffer, src->bufsiz);
+
+ return ret;
+}
+
+void qr_bitstream_seek(struct qr_bitstream * stream, size_t pos)
+{
+ assert(pos <= stream->count);
+ stream->pos = pos;
+}
+
+size_t qr_bitstream_tell(const struct qr_bitstream * stream)
+{
+ return stream->pos;
+}
+
+size_t qr_bitstream_remaining(const struct qr_bitstream * stream)
+{
+ return stream->count - stream->pos;
+}
+
+size_t qr_bitstream_size(const struct qr_bitstream * stream)
+{
+ return stream->count;
+}
+
+unsigned long qr_bitstream_read(struct qr_bitstream * stream, int bits)
+{
+ unsigned long result = 0;
+ unsigned char * byte;
+ size_t bitnum;
+
+ assert(qr_bitstream_remaining(stream) >= (size_t) bits);
+
+ byte = stream->buffer + (stream->pos / CHAR_BIT);
+ bitnum = stream->pos % CHAR_BIT;
+
+ stream->pos += bits;
+
+ while (bits-- > 0) {
+ int bit = (*byte >> bitnum++) & 0x1;
+ result = (result << 1) | bit;
+ if (bitnum == CHAR_BIT) {
+ bitnum = 0;
+ ++byte;
+ }
+ }
+
+ return result;
+}
+
+void qr_bitstream_unpack(struct qr_bitstream * stream,
+ unsigned int * result,
+ size_t count,
+ int bitsize)
+{
+ assert(qr_bitstream_remaining(stream) >= (count * bitsize));
+
+ while (count--)
+ *(result++) = qr_bitstream_read(stream, bitsize);
+}
+
+int qr_bitstream_write(struct qr_bitstream * stream,
+ unsigned long value,
+ int bits)
+{
+ unsigned char * byte;
+ size_t bitnum;
+
+ if (ensure_available(stream, bits) != 0)
+ return -1;
+
+ byte = stream->buffer + (stream->pos / CHAR_BIT);
+ bitnum = stream->pos % CHAR_BIT;
+
+ stream->pos += bits;
+ stream->count = stream->pos; /* truncate */
+
+ while (bits-- > 0) {
+ int bit = (value >> bits) & 0x1;
+ unsigned char mask = 1 << bitnum++;
+ *byte = (*byte & ~mask) | (bit ? mask : 0);
+ if (bitnum == CHAR_BIT) {
+ bitnum = 0;
+ ++byte;
+ }
+ }
+
+ return 0;
+}
+
+int qr_bitstream_pack(struct qr_bitstream * stream,
+ const unsigned int * values,
+ size_t count,
+ int bitsize)
+{
+ if (ensure_available(stream, count * bitsize) != 0)
+ return -1;
+
+ while (count--)
+ qr_bitstream_write(stream, *(values++), bitsize);
+
+ return 0;
+}
+
+int qr_bitstream_cat(struct qr_bitstream * dest, const struct qr_bitstream * src)
+{
+ size_t count = qr_bitstream_size(src);
+ size_t srcpos;
+
+ if (ensure_available(dest, count) != 0)
+ return -1;
+
+ srcpos = qr_bitstream_tell(src);
+ qr_bitstream_seek((struct qr_bitstream *)src, 0);
+ qr_bitstream_copy(dest, (struct qr_bitstream *)src, count);
+ qr_bitstream_seek((struct qr_bitstream *)src, srcpos);
+
+ return 0;
+}
+
+int qr_bitstream_copy(struct qr_bitstream * dest,
+ struct qr_bitstream * src,
+ size_t count)
+{
+ if (qr_bitstream_remaining(src) < count)
+ return -1;
+ if (ensure_available(dest, count) != 0)
+ return -1;
+
+ /* uint must be at least 16 bits */
+ for (; count >= 16; count -= 16)
+ qr_bitstream_write(
+ dest,
+ qr_bitstream_read((struct qr_bitstream *)src, 16),
+ 16);
+
+ if (count > 0)
+ qr_bitstream_write(
+ dest,
+ qr_bitstream_read((struct qr_bitstream *)src, count),
+ count);
+
+ return 0;
+}
+
diff --git a/lpg/libqr/code-common.c b/lpg/libqr/code-common.c
new file mode 100644
index 0000000..babaf86
--- /dev/null
+++ b/lpg/libqr/code-common.c
@@ -0,0 +1,109 @@
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include <qr/bitmap.h>
+#include <qr/bitstream.h>
+#include <qr/code.h>
+#include <qr/common.h>
+#include "constants.h"
+
+void qr_code_destroy(struct qr_code * code)
+{
+ if (code) {
+ qr_bitmap_destroy(code->modules);
+ free(code);
+ }
+}
+
+int qr_code_width(const struct qr_code * code)
+{
+ return code->version * 4 + 17;
+}
+
+size_t qr_code_total_capacity(int version)
+{
+ int side = version * 4 + 17;
+
+ int alignment_side = version > 1 ? (version / 7) + 2 : 0;
+
+ int alignment_count = alignment_side >= 2 ?
+ alignment_side * alignment_side - 3 : 0;
+
+ int locator_bits = 8*8*3;
+
+ int format_bits = 8*4 - 1 + (version >= 7 ? 6*3*2 : 0);
+
+ int timing_bits = 2 * (side - 8*2 -
+ (alignment_side > 2 ? (alignment_side - 2) * 5 : 0));
+
+ int function_bits = timing_bits + format_bits + locator_bits
+ + alignment_count * 5*5;
+
+ return side * side - function_bits;
+}
+
+void qr_get_rs_block_sizes(int version,
+ enum qr_ec_level ec,
+ int block_count[2],
+ int data_length[2],
+ int ec_length[2])
+{
+ /* FIXME: rather than using a big static table, better to
+ * calculate these values.
+ */
+ int total_words = qr_code_total_capacity(version) / 8;
+ int data_words = QR_DATA_WORD_COUNT[version - 1][ec ^ 0x1];
+ int ec_words = total_words - data_words;
+ int total_blocks;
+
+ block_count[0] = QR_RS_BLOCK_COUNT[version - 1][ec ^ 0x1][0];
+ block_count[1] = QR_RS_BLOCK_COUNT[version - 1][ec ^ 0x1][1];
+ total_blocks = block_count[0] + block_count[1];
+
+ data_length[0] = data_words / total_blocks;
+ data_length[1] = data_length[0] + 1;
+
+ assert(data_length[0] * block_count[0] +
+ data_length[1] * block_count[1] == data_words);
+
+ ec_length[0] = ec_length[1] = ec_words / total_blocks;
+
+ assert(ec_length[0] * block_count[0] +
+ ec_length[1] * block_count[1] == ec_words);
+ assert(data_words + ec_words == total_words);
+}
+
+void qr_mask_apply(struct qr_bitmap * bmp, int mask)
+{
+ size_t i, j;
+
+ assert((mask & 0x7) == mask);
+ mask &= 0x7;
+
+ /* Slow version for now; we can optimize later */
+
+ for (i = 0; i < bmp->height; ++i) {
+ unsigned char * p = bmp->bits + i * bmp->stride;
+
+ for (j = 0; j < bmp->width; ++j) {
+ int bit = j % CHAR_BIT;
+ size_t off = j / CHAR_BIT;
+ int t;
+
+ switch (mask) {
+ case 0: t = (i + j) % 2; break;
+ case 1: t = i % 2; break;
+ case 2: t = j % 3; break;
+ case 3: t = (i + j) % 3; break;
+ case 4: t = (i/2 + j/3) % 2; break;
+ case 5: t = ((i*j) % 2) + ((i*j) % 3); break;
+ case 6: t = (((i*j) % 2) + ((i*j) % 3)) % 2; break;
+ case 7: t = (((i*j) % 3) + ((i+j) % 2)) % 2; break;
+ }
+
+ p[off] ^= (t == 0) << bit;
+ }
+ }
+}
+
diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c
new file mode 100644
index 0000000..f64e42d
--- /dev/null
+++ b/lpg/libqr/code-create.c
@@ -0,0 +1,565 @@
+#include <stdlib.h>
+#include <limits.h>
+#include <assert.h>
+
+#include <qr/bitmap.h>
+#include <qr/bitstream.h>
+#include <qr/code.h>
+#include <qr/common.h>
+#include <qr/data.h>
+#include <qr/layout.h>
+#include "constants.h"
+#include "galois.h"
+
+#define MIN(a, b) ((b) < (a) ? (b) : (a))
+
+static int mask_data(struct qr_code * code);
+static int score_mask(const struct qr_bitmap * bmp);
+static int score_runs(const struct qr_bitmap * bmp, int base);
+static int count_2blocks(const struct qr_bitmap * bmp);
+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 unsigned int calc_format_bits(enum qr_ec_level ec, int mask);
+static unsigned long calc_version_bits(int version);
+
+static void setpx(struct qr_bitmap * bmp, int x, int y)
+{
+ size_t off = y * bmp->stride + x / CHAR_BIT;
+ unsigned char bit = 1 << (x % CHAR_BIT);
+
+ bmp->bits[off] |= bit;
+}
+
+static void draw_locator(struct qr_bitmap * bmp, int x, int y)
+{
+ int i;
+ for (i = 0; i < 6; ++i) {
+ setpx(bmp, x + i, y + 0);
+ setpx(bmp, x + 6, y + i);
+ setpx(bmp, x + i + 1, y + 6);
+ setpx(bmp, x, y + i + 1);
+ }
+ for (i = 0; i < 9; ++i)
+ setpx(bmp, x + 2 + i % 3, y + 2 + i / 3);
+}
+
+static int draw_functional(struct qr_code * code,
+ enum qr_ec_level ec,
+ unsigned int mask)
+{
+ struct qr_bitmap * bmp;
+ int dim = qr_code_width(code);
+ int i;
+ int x, y;
+ int am_side;
+
+ bmp = qr_bitmap_create(dim, dim, 0);
+ if (!bmp)
+ return -1;
+
+ /* Locator pattern */
+ draw_locator(bmp, 0, 0);
+ draw_locator(bmp, 0, dim - 7);
+ draw_locator(bmp, dim - 7, 0);
+
+ /* Timing pattern */
+ for (i = 8; i < dim - 8; i += 2) {
+ setpx(bmp, i, 6);
+ setpx(bmp, 6, i);
+ }
+
+ /* Alignment pattern */
+ am_side = code->version > 1 ? (code->version / 7) + 2 : 0;
+ for (y = 0; y < am_side; ++y) {
+ const int * am_pos = QR_ALIGNMENT_LOCATION[code->version - 1];
+
+ for (x = 0; x < am_side; ++x) {
+ if ((x == 0 && y == 0) ||
+ (x == 0 && y == am_side - 1) ||
+ (x == am_side - 1 && y == 0))
+ continue;
+
+ for (i = -2; i < 2; ++i) {
+ setpx(bmp, am_pos[x] + i, am_pos[y] - 2);
+ setpx(bmp, am_pos[x] + 2, am_pos[y] + i);
+ setpx(bmp, am_pos[x] - i, am_pos[y] + 2);
+ setpx(bmp, am_pos[x] - 2, am_pos[y] - i);
+ }
+ setpx(bmp, am_pos[x], am_pos[y]);
+ }
+ }
+
+ /* 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;
+
+ return 0;
+}
+
+static int pad_data(struct qr_bitstream * bits, size_t limit)
+{
+ /* This function is not very nice. Sorry. */
+
+ size_t count, n;
+
+ assert(qr_bitstream_size(bits) <= limit);
+
+ if (qr_bitstream_resize(bits, limit) != 0)
+ return -1;
+
+ n = qr_bitstream_size(bits);
+ qr_bitstream_seek(bits, n);
+ count = limit - n;
+
+ /* First append the terminator (0000) if possible,
+ * and pad with zeros up to an 8-bit boundary
+ */
+ n = (n + 4) % 8;
+ if (n != 0)
+ n = 8 - n;
+ n = MIN(count, n + 4);
+ qr_bitstream_write(bits, 0, n);
+ count -= n;
+
+ assert(count % 8 == 0); /* since data codewords are 8 bits */
+
+ /* Finally pad with the repeating sequence 11101100 00010001 */
+ while (count >= 16) {
+ qr_bitstream_write(bits, 0xEC11, 16);
+ count -= 16;
+ }
+ if (count > 0) {
+ assert(count == 8);
+ qr_bitstream_write(bits, 0xEC, 8);
+ }
+
+ return 0;
+}
+
+static struct qr_bitstream * make_data(int version,
+ enum qr_ec_level ec,
+ struct qr_bitstream * data)
+{
+ const size_t total_bits = qr_code_total_capacity(version);
+ const size_t total_data = QR_DATA_WORD_COUNT[version - 1][ec ^ 0x1];
+ int block_count[2], data_length[2], ec_length[2];
+ int total_blocks;
+ int i, w;
+ struct qr_bitstream * dcopy = 0;
+ struct qr_bitstream * out = 0;
+ struct qr_bitstream ** blocks = 0;
+
+ /* Set up the output stream */
+ out = qr_bitstream_create();
+ if (!out)
+ return 0;
+
+ if (qr_bitstream_resize(out, total_bits) != 0)
+ goto fail;
+
+ qr_get_rs_block_sizes(version, ec, block_count, data_length, ec_length);
+ total_blocks = block_count[0] + block_count[1];
+
+ /* Make a copy of the data and pad it */
+ dcopy = qr_bitstream_dup(data);
+ if (!dcopy)
+ goto fail;
+
+ if (pad_data(dcopy, total_data * QR_WORD_BITS) != 0)
+ goto fail;
+
+ /* Make space for the RS blocks */
+ blocks = malloc(total_blocks * sizeof(*blocks));
+ if (!blocks)
+ goto fail;
+ for (i = 0; i < total_blocks; ++i)
+ blocks[i] = NULL;
+
+ /* Generate RS codewords */
+ qr_bitstream_seek(dcopy, 0);
+ for (i = 0; i < total_blocks; ++i) {
+ int type = (i >= block_count[0]);
+ blocks[i] = rs_generate_words(dcopy,
+ data_length[type],
+ ec_length[type]);
+ if (!blocks[i]) {
+ while (i--)
+ qr_bitstream_destroy(blocks[i]);
+ free(blocks);
+ blocks = 0;
+ goto fail;
+ }
+ }
+
+ /* Finally, write everything out in the correct order */
+ assert(block_count[1] == 0 || data_length[1] >= data_length[0]);
+ for (w = 0; w < data_length[block_count[1] ? 1 : 0]; ++w) {
+ for (i = (w >= data_length[0] ? block_count[0] : 0); i < total_blocks; ++i) {
+ long di = w + i * data_length[0]
+ + (i > block_count[0] ?
+ (i - block_count[0]) * (data_length[1] - data_length[0])
+ : 0);
+
+ qr_bitstream_seek(dcopy, di * QR_WORD_BITS);
+ qr_bitstream_copy(out, dcopy, QR_WORD_BITS);
+ }
+ }
+ for (i = 0; i < total_blocks; ++i)
+ qr_bitstream_seek(blocks[i], 0);
+ assert(block_count[1] == 0 || ec_length[1] == ec_length[0]);
+ for (w = 0; w < ec_length[0]; ++w)
+ for (i = 0; i < total_blocks; ++i)
+ qr_bitstream_copy(out, blocks[i], QR_WORD_BITS);
+
+ qr_bitstream_write(out, 0, total_bits % QR_WORD_BITS);
+
+exit:
+ if (blocks) {
+ while (total_blocks--)
+ qr_bitstream_destroy(blocks[total_blocks]);
+ free(blocks);
+ }
+ if (dcopy)
+ qr_bitstream_destroy(dcopy);
+
+ return out;
+
+fail:
+ qr_bitstream_destroy(out);
+ out = 0;
+ goto exit;
+}
+
+struct qr_code * qr_code_create(const struct qr_data * data)
+{
+ struct qr_code * code;
+ struct qr_bitstream * bits = 0;
+ struct qr_iterator * layout;
+ int mask;
+ size_t dim;
+
+ code = malloc(sizeof(*code));
+ if (!code)
+ return 0;
+
+ code->version = data->version;
+ dim = qr_code_width(code);
+ code->modules = qr_bitmap_create(dim, dim, 1);
+
+ if (!code->modules)
+ goto fail;
+
+ bits = make_data(data->version, data->ec, data->bits);
+ if (!bits)
+ goto fail;
+
+ qr_layout_init_mask(code);
+
+ layout = qr_layout_begin(code);
+ if (!layout)
+ goto fail;
+
+ qr_bitstream_seek(bits, 0);
+ while (qr_bitstream_remaining(bits) >= (size_t) QR_WORD_BITS)
+ qr_layout_write(layout, qr_bitstream_read(bits, QR_WORD_BITS));
+ qr_layout_end(layout);
+
+ mask = mask_data(code);
+ if (mask < 0)
+ goto fail;
+
+ if (draw_functional(code, data->ec, mask) != 0)
+ goto fail;
+
+exit:
+ if (bits)
+ qr_bitstream_destroy(bits);
+
+ return code;
+
+fail:
+ qr_code_destroy(code);
+ code = 0;
+ goto exit;
+}
+
+static int mask_data(struct qr_code * code)
+{
+ struct qr_bitmap * mask, * test;
+ int selected, score;
+ int i, best;
+
+ mask = 0;
+
+ /* Generate bitmap for each mask and evaluate */
+ for (i = 0; i < 8; ++i) {
+ test = qr_bitmap_clone(code->modules);
+ if (!test) {
+ qr_bitmap_destroy(mask);
+ return -1;
+ }
+ qr_mask_apply(test, i);
+ score = score_mask(test);
+ if (!mask || score < best) {
+ best = score;
+ selected = i;
+ qr_bitmap_destroy(mask);
+ mask = test;
+ } else {
+ qr_bitmap_destroy(test);
+ }
+ }
+
+ qr_bitmap_destroy(code->modules);
+ code->modules = mask;
+
+ return selected;
+}
+
+static int score_mask(const struct qr_bitmap * bmp)
+{
+ const int N[4] = { 3, 3, 40, 10 };
+ int score = 0;
+
+ score += score_runs(bmp, N[0]);
+ score += N[1] * count_2blocks(bmp);
+ score += N[2] * count_locators(bmp);
+ score += N[3] * ((abs(calc_bw_balance(bmp) - 50) + 4) / 5);
+
+ return score;
+}
+
+static int score_runs(const struct qr_bitmap * bmp, int base)
+{
+ /* Runs of 5+n bits -> N[0] + i */
+ size_t x, y;
+ int flip;
+ int score = 0;
+ int count, last;
+
+ for (flip = 0; flip <= 1; ++flip) {
+ for (y = 0; y < bmp->height; ++y) {
+ count = 0;
+ for (x = 0; x < bmp->width; ++x) {
+ int mask, bit;
+ if (flip) {
+ mask = get_mask(bmp, y, x);
+ bit = get_mask(bmp, y, x);
+ } else {
+ mask = get_mask(bmp, x, y);
+ bit = get_px(bmp, x, y);
+ }
+
+ if (mask &&
+ (count == 0 || !!bit == !!last)) {
+ ++count;
+ last = bit;
+ } else {
+ if (count >= 5)
+ score += base + count - 5;
+ count = 0;
+ }
+ }
+ }
+ }
+
+ return score;
+}
+
+static int count_2blocks(const struct qr_bitmap * bmp)
+{
+ /* Count the number of 2x2 blocks (on or off) */
+ size_t x, y;
+ int count = 0;
+
+ /* Slow and stupid */
+ for (y = 0; y < bmp->height - 1; ++y) {
+ for (x = 0; x < bmp->width - 1; ++x) {
+ if (get_mask(bmp, x, y) &&
+ get_mask(bmp, x+1, y) &&
+ get_mask(bmp, x, y+1) &&
+ get_mask(bmp, x+1, y+1)) {
+ int v[4];
+ v[0] = get_px(bmp, x, y);
+ v[1] = get_px(bmp, x+1, y);
+ v[2] = get_px(bmp, x, y+1);
+ v[3] = get_px(bmp, x+1, y+1);
+ if (!(v[0] || v[1] || v[2] || v[3]) ||
+ (v[0] && v[1] && v[2] && v[3])) {
+ ++count;
+ }
+ }
+ }
+ }
+
+ return count;
+}
+
+static int count_locators(const struct qr_bitmap * bmp)
+{
+ /* 1:1:3:1:1 patterns -> N[2] */
+ size_t x, y;
+ int flip;
+ int count = 0;
+
+ for (flip = 0; flip <= 1; ++flip) {
+ for (y = 0; y < bmp->height - 7; ++y) {
+ for (x = 0; x < bmp->width - 7; ++x) {
+ int bits[7];
+ int i;
+
+ for (i = 0; i < 7; ++i)
+ if (!(flip ? get_mask(bmp, y, x+i) : get_mask(bmp, x+i, y)))
+ continue;
+
+ for (i = 0; i < 7; ++i)
+ bits[i] = flip ? get_px(bmp, y, x+i) : get_px(bmp, x+i, y);
+
+ if (!bits[0])
+ for (i = 0; i < 7; ++i)
+ bits[i] = !bits[i];
+
+ if ( bits[0] && !bits[1] && bits[2] &&
+ bits[3] && bits[4] && !bits[5] &&
+ bits[6])
+ ++count;
+ }
+ }
+ }
+
+ return count;
+}
+
+static int calc_bw_balance(const struct qr_bitmap * bmp)
+{
+ /* Calculate the proportion (in percent) of "on" bits */
+ size_t x, y;
+ unsigned char bit;
+ long on, total;
+
+ assert(bmp->mask); /* we only need this case */
+
+ on = total = 0;
+ for (y = 0; y < bmp->height; ++y) {
+ size_t off = y * bmp->stride;
+ unsigned char * bits = bmp->bits + off;
+ unsigned char * mask = bmp->mask + off;
+
+ for (x = 0; x < bmp->width / CHAR_BIT; ++x, ++bits, ++mask) {
+ for (bit = 1; bit; bit <<= 1) {
+ int m = *mask & bit;
+
+ total += !!m;
+ on += !!(*bits & m);
+ }
+ }
+ }
+
+ return (on * 100) / total;
+}
+
+static int get_px(const struct qr_bitmap * bmp, int x, int y)
+{
+ size_t off = y * bmp->stride + x / CHAR_BIT;
+ unsigned char bit = 1 << (x % CHAR_BIT);
+
+ return bmp->bits[off] & bit;
+}
+
+static int get_mask(const struct qr_bitmap * bmp, int x, int y)
+{
+ size_t off = y * bmp->stride + x / CHAR_BIT;
+ unsigned char bit = 1 << (x % CHAR_BIT);
+
+ 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 + (i > 5));
+ 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;
+ }
+
+ if (code->version >= 7) {
+ bits = calc_version_bits(code->version);
+
+ for (i = 0; i < 18; ++i) {
+ if (bits & 0x1) {
+ int a = i % 3, b = i / 3;
+ setpx(bmp, dim - 11 + a, b);
+ setpx(bmp, b, dim - 11 + a);
+ }
+ bits >>= 1;
+ }
+ }
+
+ return 0;
+}
+
+static unsigned int calc_format_bits(enum qr_ec_level ec, int mask)
+{
+ unsigned int bits;
+
+ bits = (ec & 0x3) << 3 | (mask & 0x7);
+
+ /* Compute (15, 5) BCH code */
+
+ bits <<= 15 - 5;
+ bits |= (unsigned int)gf_residue(bits, QR_FORMAT_POLY);
+
+ bits ^= QR_FORMAT_MASK;
+
+ return bits;
+}
+
+static unsigned long calc_version_bits(int version)
+{
+ unsigned long bits;
+
+ bits = version & 0x3F;
+
+ /* (18, 6) BCH code */
+
+ bits <<= 18 - 6;
+ bits |= gf_residue(bits, QR_VERSION_POLY);
+
+ return bits;
+}
+
diff --git a/lpg/libqr/code-layout.c b/lpg/libqr/code-layout.c
new file mode 100644
index 0000000..fe8caa7
--- /dev/null
+++ b/lpg/libqr/code-layout.c
@@ -0,0 +1,188 @@
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <qr/bitmap.h>
+#include <qr/code.h>
+#include <qr/common.h>
+#include <qr/layout.h>
+#include "constants.h"
+
+struct qr_iterator {
+ struct qr_code * code;
+ int dim;
+ int column;
+ int row;
+ int up;
+ int mask;
+ unsigned char * p;
+};
+
+void qr_layout_init_mask(struct qr_code * code)
+{
+ size_t x, y;
+ size_t dim = qr_code_width(code);
+ struct qr_bitmap * bmp = code->modules;
+ const int * am_pos = QR_ALIGNMENT_LOCATION[code->version - 1];
+ size_t am_side;
+
+ if (!bmp->mask)
+ qr_bitmap_add_mask(bmp);
+
+ assert(bmp->mask);
+
+ memset(bmp->mask, 0, bmp->height * bmp->stride);
+
+ /* slow and stupid, but I'm sleepy */
+ for (y = 0; y < bmp->height; ++y) {
+ unsigned char * row = bmp->mask + y * bmp->stride;
+ for (x = 0; x < bmp->width; ++x) {
+ unsigned char bit = 1 << (x % CHAR_BIT);
+ int off = x / CHAR_BIT;
+
+ if (x == 6 || y == 6) /* timing */
+ continue;
+
+ if (x < 9 && y < 9) /* top-left */
+ continue;
+
+ if (x >= dim - 8 && y < 9) /* top-right */
+ continue;
+
+ if (x < 9 && y >= dim - 8) /* bottom-left */
+ continue;
+
+ /* version info */
+ if (code->version >= 7) {
+ if (y < 6 && x >= dim - 11)
+ continue;
+ if (x < 6 && y >= dim - 11)
+ continue;
+ }
+
+ row[off] |= bit;
+ }
+ }
+
+ /* Alignment pattern */
+ am_side = code->version > 1 ? (code->version / 7) + 2 : 0;
+ for (y = 0; y < am_side; ++y) {
+ for (x = 0; x < am_side; ++x) {
+ int i, j;
+
+ if ((x == 0 && y == 0) ||
+ (x == 0 && y == am_side - 1) ||
+ (x == am_side - 1 && y == 0))
+ continue;
+
+ for (j = -2; j <= 2; ++j) {
+ unsigned char * row = bmp->mask + (am_pos[y]+j) * bmp->stride;
+ for (i = -2; i <= 2; ++i) {
+ unsigned char bit = 1 << ((am_pos[x]+i) % CHAR_BIT);
+ int off = (am_pos[x]+i) / CHAR_BIT;
+
+ row[off] &= ~bit;
+ }
+ }
+ }
+ }
+}
+
+static int is_data_bit(const struct qr_iterator * i)
+{
+ unsigned char bit = 1 << (i->column % CHAR_BIT);
+ int off = (i->row * i->code->modules->stride) + (i->column / CHAR_BIT);
+
+ return i->code->modules->mask[off] & bit;
+}
+
+static void set_pointer(struct qr_iterator * i)
+{
+ i->mask = 1 << (i->column % CHAR_BIT);
+ i->p = i->code->modules->bits
+ + i->code->modules->stride * i->row
+ + i->column / CHAR_BIT;
+}
+
+static void advance(struct qr_iterator * i)
+{
+ do {
+ /* This XOR is to account for the vertical strip of
+ * timing bits in column 6 which displaces everything.
+ */
+ if ((i->column < 6) ^ !(i->column % 2)) {
+ /* Right-hand part or at left edge */
+ i->column -= 1;
+ } else {
+ /* Left-hand part */
+ i->column += 1;
+
+ if (( i->up && i->row == 0) ||
+ (!i->up && i->row == i->dim - 1)) {
+ /* Hit the top / bottom */
+ i->column -= 2;
+ i->up = !i->up;
+ } else {
+ i->row += i->up ? -1 : 1;
+ }
+ }
+
+ if (i->column < 0)
+ continue; /* don't go off left edge */
+
+ /* Check for one-past-end */
+ if (i->column == 0 && i->row >= i->dim - 8)
+ break;
+
+ } while (!is_data_bit(i));
+
+ set_pointer(i);
+}
+
+struct qr_iterator * qr_layout_begin(struct qr_code * code)
+{
+ struct qr_iterator * i;
+
+ i = malloc(sizeof(*i));
+ if (i) {
+ i->dim = qr_code_width(code);
+ i->code = code;
+ i->column = i->dim - 1;
+ i->row = i->dim - 1;
+ i->up = 1;
+ set_pointer(i);
+ }
+
+ return i;
+}
+
+void qr_layout_end(struct qr_iterator * i)
+{
+ free(i);
+}
+
+unsigned int qr_layout_read(struct qr_iterator * i)
+{
+ unsigned int x = 0;
+ int b;
+
+ for (b = 0; b < QR_WORD_BITS; ++b) {
+ x = (x << 1) | ((*i->p & i->mask) ? 1 : 0);
+ advance(i);
+ }
+
+ return x;
+}
+
+void qr_layout_write(struct qr_iterator * i, unsigned int x)
+{
+ int b;
+
+ for (b = 0; b < QR_WORD_BITS; ++b) {
+ *i->p |= (x & 0x80) ? i->mask : 0;
+ advance(i);
+ x <<= 1;
+ }
+}
+
diff --git a/lpg/libqr/code-parse.c b/lpg/libqr/code-parse.c
new file mode 100644
index 0000000..a84df72
--- /dev/null
+++ b/lpg/libqr/code-parse.c
@@ -0,0 +1,348 @@
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <qr/bitmap.h>
+#include <qr/bitstream.h>
+#include <qr/code.h>
+#include <qr/common.h>
+#include <qr/layout.h>
+#include <qr/parse.h>
+
+#include "constants.h"
+#include "galois.h"
+
+/* XXX: duplicated */
+static int get_px(const struct qr_bitmap * bmp, int x, int y)
+{
+ size_t off = y * bmp->stride + x / CHAR_BIT;
+ unsigned char bit = 1 << (x % CHAR_BIT);
+
+ return bmp->bits[off] & bit;
+}
+
+static int unpack_bits(int version,
+ enum qr_ec_level ec,
+ struct qr_bitstream * raw_bits,
+ struct qr_bitstream * bits_out)
+{
+ /* FIXME: more comments to explain the algorithm */
+
+ int total_words = qr_code_total_capacity(version) / QR_WORD_BITS;
+ int block_count[2], data_length[2], ec_length[2];
+ int total_blocks;
+ int i, w, block;
+ struct qr_bitstream ** blocks = 0;
+ int status = -1;
+
+ qr_get_rs_block_sizes(version, ec, block_count, data_length, ec_length);
+ total_blocks = block_count[0] + block_count[1];
+
+ status = qr_bitstream_resize(bits_out,
+ (block_count[0] * data_length[0] +
+ block_count[1] * data_length[1]) * QR_WORD_BITS);
+ if (status != 0)
+ goto cleanup;
+
+ blocks = malloc(total_blocks * sizeof(*blocks));
+ if (blocks == NULL)
+ goto cleanup;
+
+ for (i = 0; i < total_blocks; ++i)
+ blocks[i] = NULL;
+
+ /* Allocate temporary space for the blocks */
+ for (i = 0; i < total_blocks; ++i) {
+ int type = (i >= block_count[0]);
+ blocks[i] = qr_bitstream_create();
+ if (blocks[i] == NULL)
+ goto cleanup;
+ status = qr_bitstream_resize(blocks[i],
+ (data_length[type] + ec_length[type]) * QR_WORD_BITS);
+ if (status != 0)
+ goto cleanup;
+ }
+
+ /* Read in the data & EC (see spec table 19) */
+
+ qr_bitstream_seek(raw_bits, 0);
+
+ fprintf(stderr, "block counts %d and %d\n", block_count[0], block_count[1]);
+ fprintf(stderr, "row lengths %d and %d\n", data_length[0], data_length[1]);
+
+ block = 0;
+ for (w = 0; w < total_words; ++w) {
+ if (block == 0 && w / total_blocks >= data_length[0] && block_count[1] != 0) {
+ /* Skip the short blocks, if there are any */
+ block += block_count[0];
+ }
+ qr_bitstream_copy(blocks[block], raw_bits, QR_WORD_BITS);
+ block = (block + 1) % total_blocks;
+ }
+
+ /* XXX: apply ec */
+
+ for (block = 0; block < total_blocks; ++block) {
+ int type = (block >= block_count[0]);
+ struct qr_bitstream * stream = blocks[block];
+ qr_bitstream_seek(stream, 0);
+ qr_bitstream_copy(bits_out, stream, data_length[type] * QR_WORD_BITS);
+ }
+ status = 0;
+
+cleanup:
+ if (blocks != NULL) {
+ for (block = 0; block < total_blocks; ++block)
+ if (blocks[block] != NULL)
+ qr_bitstream_destroy(blocks[block]);
+ free(blocks);
+ }
+
+ return status;
+}
+
+static int read_bits(const struct qr_code * code,
+ enum qr_ec_level ec,
+ struct qr_bitstream * data_bits)
+{
+ const size_t total_bits = qr_code_total_capacity(code->version);
+ const size_t total_words = total_bits / QR_WORD_BITS;
+ struct qr_bitstream * raw_bits;
+ struct qr_iterator * layout;
+ size_t w;
+ int ret = -1;
+
+ raw_bits = qr_bitstream_create();
+ if (raw_bits == NULL)
+ goto cleanup;
+
+ ret = qr_bitstream_resize(raw_bits, total_words * QR_WORD_BITS);
+ if (ret != 0)
+ goto cleanup;
+
+ layout = qr_layout_begin((struct qr_code *) code); /* dropping const! */
+ if (layout == NULL)
+ goto cleanup;
+ for (w = 0; w < total_words; ++w)
+ qr_bitstream_write(raw_bits, qr_layout_read(layout), QR_WORD_BITS);
+ qr_layout_end(layout);
+
+ ret = unpack_bits(code->version, ec, raw_bits, data_bits);
+
+cleanup:
+ if (raw_bits != NULL)
+ qr_bitstream_destroy(raw_bits);
+
+ return ret;
+}
+
+static int read_format(const struct qr_bitmap * bmp, enum qr_ec_level * ec, int * mask)
+{
+ int dim;
+ int i;
+ unsigned bits1, bits2;
+ enum qr_ec_level ec1, ec2;
+ int mask1, mask2;
+ int err1, err2;
+
+ dim = bmp->width;
+ bits1 = bits2 = 0;
+
+ for (i = 14; i >= 8; --i) {
+ bits1 = (bits1 << 1) | !!get_px(bmp, 14 - i + (i <= 8), 8);
+ bits2 = (bits2 << 1) | !!get_px(bmp, 8, dim - 1 - (14 - i));
+ }
+
+ for (; i >= 0; --i) {
+ bits1 = (bits1 << 1) | !!get_px(bmp, 8, i + (i >= 6));
+ bits2 = (bits2 << 1) | !!get_px(bmp, dim - 1 - i, 8);
+ }
+
+ fprintf(stderr, "read format bits %x / %x\n", bits1, bits2);
+
+ err1 = qr_decode_format(bits1, &ec1, &mask1);
+ err2 = qr_decode_format(bits2, &ec2, &mask2);
+
+ if (err1 < 0 && err2 < 0)
+ return -1;
+
+ if (err1 < err2)
+ *ec = ec1, *mask = mask1;
+ else
+ *ec = ec2, *mask = mask2;
+
+ return 0;
+}
+
+static int read_version(const struct qr_bitmap * bmp)
+{
+ int dim;
+ int i;
+ unsigned long bits1, bits2;
+ int ver1, ver2;
+ int err1, err2;
+
+ dim = bmp->width;
+ bits1 = bits2 = 0;
+
+ for (i = 17; i >= 0; --i) {
+ bits1 = (bits1 << 1) | !!get_px(bmp, i / 3, dim - 11 + (i % 3));
+ bits2 = (bits2 << 1) | !!get_px(bmp, dim - 11 + (i % 3), i / 3);
+ }
+
+ fprintf(stderr, "read version bits %lx / %lx\n", bits1, bits2);
+
+ err1 = qr_decode_version(bits1, &ver1);
+ err2 = qr_decode_version(bits2, &ver2);
+
+ fprintf(stderr, "got versions %d[%d] / %d[%d]\n", ver1, err1, ver2, err2);
+
+ if (err1 < 0 && err2 < 0)
+ return -1;
+
+ return err1 < err2 ? ver1 : ver2;
+}
+
+int qr_code_parse(const void * buffer,
+ size_t line_bits,
+ size_t line_stride,
+ size_t line_count,
+ struct qr_data ** data)
+{
+ /* TODO: more informative return values for errors */
+ struct qr_bitmap src_bmp;
+ struct qr_code code;
+ enum qr_ec_level ec;
+ int mask;
+ struct qr_bitstream * data_bits = NULL;
+ int status;
+
+ fprintf(stderr, "parsing code bitmap %lux%lu\n", (unsigned long) line_bits, (unsigned long) line_count);
+
+ if (line_bits != line_count
+ || line_bits < 21
+ || (line_bits - 17) % 4 != 0) {
+ /* Invalid size */
+ fprintf(stderr, "Invalid size\n");
+ return -1;
+ }
+
+ code.version = (line_bits - 17) / 4;
+ fprintf(stderr, "assuming version %d\n", code.version);
+
+ src_bmp.bits = (unsigned char *) buffer; /* dropping const! */
+ src_bmp.mask = NULL;
+ src_bmp.stride = line_stride;
+ src_bmp.width = line_bits;
+ src_bmp.height = line_count;
+
+ if (code.version >= 7 && read_version(&src_bmp) != code.version) {
+ fprintf(stderr, "Invalid version info\n");
+ return -1;
+ }
+
+ if (read_format(&src_bmp, &ec, &mask) != 0) {
+ fprintf(stderr, "Failed to read format\n");
+ return -1;
+ }
+
+ fprintf(stderr, "detected ec type %d; mask %d\n", ec, mask);
+
+ code.modules = qr_bitmap_clone(&src_bmp);
+ if (code.modules == NULL) {
+ status = -1;
+ goto cleanup;
+ }
+ qr_mask_apply(code.modules, mask);
+
+ qr_layout_init_mask(&code);
+
+ data_bits = qr_bitstream_create();
+ if (data_bits == NULL) {
+ status = -1;
+ goto cleanup;
+ }
+
+ status = read_bits(&code, ec, data_bits);
+ if (status != 0)
+ goto cleanup;
+
+ *data = malloc(sizeof(**data));
+ if (*data == NULL) {
+ status = -1;
+ goto cleanup;
+ }
+
+ (*data)->version = code.version;
+ (*data)->ec = ec;
+ (*data)->bits = data_bits;
+ (*data)->offset = 0;
+
+ data_bits = 0;
+ status = 0;
+
+cleanup:
+ if (data_bits)
+ qr_bitstream_destroy(data_bits);
+ if (code.modules)
+ qr_bitmap_destroy(code.modules);
+
+ return status;
+}
+
+int qr_decode_format(unsigned long bits, enum qr_ec_level * ec, int * mask)
+{
+ bits ^= QR_FORMAT_MASK;
+
+ /* TODO: check and fix errors */
+
+ bits >>= 10;
+ *mask = bits & 7;
+ *ec = bits >> 3;
+
+ return 0;
+}
+
+int qr_decode_version(unsigned long bits, int * version)
+{
+ int v, errors;
+ unsigned long version_bits;
+ int best_err, best_version;
+
+ if (bits != (bits & 0x3FFFF))
+ fprintf(stderr, "WARNING: excess version bits");
+
+ best_err = 18;
+
+ for (v = 7; v <= 40; ++v) {
+ /* FIXME: cache these values */
+ /* see calc_version_bits() */
+ version_bits = v;
+ version_bits <<= 12;
+ version_bits |= gf_residue(version_bits, QR_VERSION_POLY);
+
+ /* count errors */
+ errors = 0;
+ version_bits ^= bits;
+ while (version_bits != 0) {
+ if ((version_bits & 1) == 1)
+ ++errors;
+ version_bits >>= 1;
+ }
+
+ if (errors < best_err) {
+ best_version = v;
+ best_err = errors;
+ }
+
+ if (errors == 0) /* can we do better than this? */
+ break;
+ }
+
+ *version = best_version;
+
+ return best_err;
+}
+
diff --git a/lpg/libqr/constants.c b/lpg/libqr/constants.c
new file mode 100644
index 0000000..18c37e6
--- /dev/null
+++ b/lpg/libqr/constants.c
@@ -0,0 +1,151 @@
+#include "constants.h"
+
+/* FIXME: don't like big tables of data */
+
+const int QR_ALIGNMENT_LOCATION[40][7] = {
+ { 0, 0, 0, 0, 0, 0, 0 }, /* 1 */
+ { 6, 18, 0, 0, 0, 0, 0 }, /* 2 */
+ { 6, 22, 0, 0, 0, 0, 0 }, /* 3 */
+ { 6, 26, 0, 0, 0, 0, 0 }, /* 4 */
+ { 6, 30, 0, 0, 0, 0, 0 }, /* 5 */
+ { 6, 34, 0, 0, 0, 0, 0 }, /* 6 */
+ { 6, 22, 38, 0, 0, 0, 0 }, /* 7 */
+ { 6, 24, 42, 0, 0, 0, 0 }, /* 8 */
+ { 6, 26, 46, 0, 0, 0, 0 }, /* 9 */
+ { 6, 28, 50, 0, 0, 0, 0 }, /* 10 */
+ { 6, 30, 54, 0, 0, 0, 0 }, /* 11 */
+ { 6, 32, 58, 0, 0, 0, 0 }, /* 12 */
+ { 6, 34, 62, 0, 0, 0, 0 }, /* 13 */
+ { 6, 26, 46, 66, 0, 0, 0 }, /* 14 */
+ { 6, 26, 48, 70, 0, 0, 0 }, /* 15 */
+ { 6, 26, 50, 74, 0, 0, 0 }, /* 16 */
+ { 6, 30, 54, 78, 0, 0, 0 }, /* 17 */
+ { 6, 30, 56, 82, 0, 0, 0 }, /* 18 */
+ { 6, 30, 58, 86, 0, 0, 0 }, /* 19 */
+ { 6, 34, 62, 90, 0, 0, 0 }, /* 20 */
+ { 6, 28, 50, 72, 94, 0, 0 }, /* 21 */
+ { 6, 26, 50, 74, 98, 0, 0 }, /* 22 */
+ { 6, 30, 54, 78,102, 0, 0 }, /* 23 */
+ { 6, 28, 54, 80,106, 0, 0 }, /* 24 */
+ { 6, 32, 58, 84,110, 0, 0 }, /* 25 */
+ { 6, 30, 58, 86,114, 0, 0 }, /* 26 */
+ { 6, 34, 62, 90,118, 0, 0 }, /* 27 */
+ { 6, 26, 50, 74, 98,122, 0 }, /* 28 */
+ { 6, 30, 54, 78,102,126, 0 }, /* 29 */
+ { 6, 26, 52, 78,104,130, 0 }, /* 30 */
+ { 6, 30, 56, 82,108,134, 0 }, /* 31 */
+ { 6, 34, 60, 86,112,138, 0 }, /* 32 */
+ { 6, 30, 58, 86,114,142, 0 }, /* 33 */
+ { 6, 34, 62, 90,118,146, 0 }, /* 34 */
+ { 6, 30, 54, 78,102,126,150 }, /* 35 */
+ { 6, 24, 50, 76,102,128,154 }, /* 36 */
+ { 6, 28, 54, 80,106,132,158 }, /* 37 */
+ { 6, 32, 58, 84,110,136,162 }, /* 38 */
+ { 6, 26, 54, 82,110,138,166 }, /* 39 */
+ { 6, 30, 58, 86,114,142,170 }, /* 40 */
+};
+
+const int QR_DATA_WORD_COUNT[40][4] = {
+ { 19, 16, 13, 9 },
+ { 34, 28, 22, 16 },
+ { 55, 44, 34, 26 },
+ { 80, 64, 48, 36 },
+ { 108, 86, 62, 46 },
+ { 136, 108, 76, 60 },
+ { 156, 124, 88, 66 },
+ { 194, 154, 110, 86 },
+ { 232, 182, 132, 100 },
+ { 274, 216, 154, 122 },
+ { 324, 254, 180, 140 },
+ { 370, 290, 206, 158 },
+ { 428, 334, 244, 180 },
+ { 461, 365, 261, 197 },
+ { 523, 415, 295, 223 },
+ { 589, 453, 325, 253 },
+ { 647, 507, 367, 283 },
+ { 721, 563, 397, 313 },
+ { 795, 627, 445, 341 },
+ { 861, 669, 485, 385 },
+ { 932, 714, 512, 406 },
+ { 1006, 782, 568, 442 },
+ { 1094, 860, 614, 464 },
+ { 1174, 914, 664, 514 },
+ { 1276, 1000, 718, 538 },
+ { 1370, 1062, 754, 596 },
+ { 1468, 1128, 808, 628 },
+ { 1531, 1193, 871, 661 },
+ { 1631, 1267, 911, 701 },
+ { 1735, 1373, 985, 745 },
+ { 1845, 1455, 1033, 793 },
+ { 1955, 1541, 1115, 845 },
+ { 2071, 1631, 1171, 901 },
+ { 2191, 1725, 1231, 961 },
+ { 2306, 1812, 1286, 986 },
+ { 2434, 1914, 1351, 1054 },
+ { 2566, 1992, 1426, 1096 },
+ { 2812, 2216, 1582, 1222 },
+ { 2956, 2334, 1666, 1276 }
+};
+
+const int QR_RS_BLOCK_COUNT[40][4][2] = {
+ { { 1, 0 }, { 1, 0 }, { 1, 0 }, { 1, 0 } }, /* 1 */
+ { { 1, 0 }, { 1, 0 }, { 1, 0 }, { 1, 0 } }, /* 2 */
+ { { 1, 0 }, { 1, 0 }, { 2, 0 }, { 2, 0 } }, /* 3 */
+ { { 1, 0 }, { 2, 0 }, { 2, 0 }, { 4, 0 } }, /* 4 */
+ { { 1, 0 }, { 2, 0 }, { 2, 2 }, { 2, 2 } }, /* 5 */
+ { { 2, 0 }, { 4, 0 }, { 4, 0 }, { 4, 0 } }, /* 6 */
+ { { 2, 0 }, { 4, 0 }, { 2, 4 }, { 4, 1 } }, /* 7 */
+ { { 2, 0 }, { 2, 2 }, { 4, 2 }, { 4, 2 } }, /* 8 */
+ { { 2, 0 }, { 3, 2 }, { 4, 4 }, { 4, 4 } }, /* 9 */
+ { { 2, 2 }, { 4, 1 }, { 6, 2 }, { 6, 2 } }, /* 10 */
+ { { 4, 0 }, { 1, 4 }, { 4, 4 }, { 3, 8 } }, /* 11 */
+ { { 2, 2 }, { 6, 2 }, { 4, 6 }, { 7, 4 } }, /* 12 */
+ { { 4, 0 }, { 8, 1 }, { 8, 4 }, { 12, 4 } }, /* 13 */
+ { { 3, 1 }, { 4, 5 }, { 11, 5 }, { 11, 5 } }, /* 14 */
+ { { 5, 1 }, { 5, 5 }, { 5, 7 }, { 11, 7 } }, /* 15 */
+ { { 5, 1 }, { 7, 3 }, { 15, 2 }, { 3, 13 } }, /* 16 */
+ { { 1, 5 }, { 10, 1 }, { 1, 15 }, { 2, 17 } }, /* 17 */
+ { { 5, 1 }, { 9, 4 }, { 17, 1 }, { 2, 19 } }, /* 18 */
+ { { 3, 4 }, { 3, 11 }, { 17, 4 }, { 9, 16 } }, /* 19 */
+ { { 3, 5 }, { 3, 13 }, { 15, 5 }, { 15, 10 } }, /* 20 */
+ { { 4, 4 }, { 17, 0 }, { 17, 6 }, { 19, 6 } }, /* 21 */
+ { { 2, 7 }, { 17, 0 }, { 7, 16 }, { 34, 0 } }, /* 22 */
+ { { 4, 5 }, { 4, 14 }, { 11, 14 }, { 16, 14 } }, /* 23 */
+ { { 6, 4 }, { 6, 14 }, { 11, 16 }, { 30, 2 } }, /* 24 */
+ { { 8, 4 }, { 8, 13 }, { 7, 22 }, { 22, 13 } }, /* 25 */
+ { { 10, 2 }, { 19, 4 }, { 28, 6 }, { 33, 4 } }, /* 26 */
+ { { 8, 4 }, { 22, 3 }, { 8, 26 }, { 12, 28 } }, /* 27 */
+ { { 3, 10 }, { 3, 23 }, { 4, 31 }, { 11, 31 } }, /* 28 */
+ { { 7, 7 }, { 21, 7 }, { 1, 37 }, { 19, 26 } }, /* 29 */
+ { { 5, 10 }, { 19, 10 }, { 15, 25 }, { 23, 25 } }, /* 30 */
+ { { 13, 3 }, { 2, 29 }, { 42, 1 }, { 23, 28 } }, /* 31 */
+ { { 17, 0 }, { 10, 23 }, { 10, 35 }, { 19, 35 } }, /* 32 */
+ { { 17, 1 }, { 14, 21 }, { 29, 19 }, { 11, 46 } }, /* 33 */
+ { { 13, 6 }, { 14, 23 }, { 44, 7 }, { 59, 1 } }, /* 34 */
+ { { 12, 7 }, { 12, 26 }, { 39, 14 }, { 22, 41 } }, /* 35 */
+ { { 6, 14 }, { 6, 34 }, { 46, 10 }, { 2, 64 } }, /* 36 */
+ { { 17, 4 }, { 29, 14 }, { 49, 10 }, { 24, 46 } }, /* 37 */
+ { { 4, 18 }, { 13, 32 }, { 48, 14 }, { 42, 32 } }, /* 38 */
+ { { 20, 4 }, { 40, 7 }, { 43, 22 }, { 10, 67 } }, /* 39 */
+ { { 19, 6 }, { 18, 31 }, { 34, 34 }, { 20, 61 } } /* 40 */
+};
+
+const enum qr_data_type QR_TYPE_CODES[16] = {
+ QR_DATA_INVALID, /* 0000 */
+ QR_DATA_NUMERIC, /* 0001 */
+ QR_DATA_ALPHA, /* 0010 */
+ QR_DATA_MIXED, /* 0011 */
+ QR_DATA_8BIT, /* 0100 */
+ QR_DATA_FNC1, /* 0101 */
+ QR_DATA_INVALID, /* 0110 */
+ QR_DATA_ECI, /* 0111 */
+ QR_DATA_KANJI, /* 1000 */
+ QR_DATA_FNC1, /* 1001 */
+ QR_DATA_INVALID, /* 1010 */
+ QR_DATA_INVALID, /* 1011 */
+ QR_DATA_INVALID, /* 1100 */
+ QR_DATA_INVALID, /* 1101 */
+ QR_DATA_INVALID, /* 1110 */
+ QR_DATA_INVALID, /* 1111 */
+};
+
diff --git a/lpg/libqr/constants.h b/lpg/libqr/constants.h
new file mode 100644
index 0000000..b1f7493
--- /dev/null
+++ b/lpg/libqr/constants.h
@@ -0,0 +1,29 @@
+#ifndef QR_CONSTANTS_H
+#define QR_CONSTANTS_H
+
+#include <qr/types.h>
+
+/* XOR mask for format data: 101 0100 0001 0010 */
+static const unsigned int QR_FORMAT_MASK = 0x5412;
+
+/* Format info EC polynomial
+ * G(x) = x^10 + x^8 + x^5 + x^4 + x^2 + x + 1
+ */
+static const unsigned int QR_FORMAT_POLY = 0x537;
+
+/* Version info EC polynomial
+ * G(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1
+ */
+static const unsigned int QR_VERSION_POLY = 0x1F25;
+
+/* A QR-code word is always 8 bits, but CHAR_BIT might not be */
+static const int QR_WORD_BITS = 8;
+
+extern const int QR_ALIGNMENT_LOCATION[40][7];
+extern const int QR_DATA_WORD_COUNT[40][4];
+/* See qr_get_rs_block_sizes() */
+extern const int QR_RS_BLOCK_COUNT[40][4][2];
+extern const enum qr_data_type QR_TYPE_CODES[16];
+
+#endif
+
diff --git a/lpg/libqr/data-common.c b/lpg/libqr/data-common.c
new file mode 100644
index 0000000..af3a766
--- /dev/null
+++ b/lpg/libqr/data-common.c
@@ -0,0 +1,38 @@
+#include <stdlib.h>
+
+#include <qr/bitstream.h>
+#include <qr/data.h>
+
+void qr_data_destroy(struct qr_data * data)
+{
+ qr_bitstream_destroy(data->bits);
+ free(data);
+}
+
+size_t qr_data_size_field_length(int version, enum qr_data_type type)
+{
+ static const size_t QR_SIZE_LENGTHS[3][4] = {
+ { 10, 9, 8, 8 },
+ { 12, 11, 16, 10 },
+ { 14, 13, 16, 12 }
+ };
+ int row, col;
+
+ switch (type) {
+ case QR_DATA_NUMERIC: col = 0; break;
+ case QR_DATA_ALPHA: col = 1; break;
+ case QR_DATA_8BIT: col = 2; break;
+ case QR_DATA_KANJI: col = 3; break;
+ default: return 0;
+ }
+
+ if (version < 10)
+ row = 0;
+ else if (version < 27)
+ row = 1;
+ else
+ row = 2;
+
+ return QR_SIZE_LENGTHS[row][col];
+}
+
diff --git a/lpg/libqr/data-create.c b/lpg/libqr/data-create.c
new file mode 100644
index 0000000..09d6653
--- /dev/null
+++ b/lpg/libqr/data-create.c
@@ -0,0 +1,273 @@
+/**
+ * Not "pure" C - only works with ASCII
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+
+#include <qr/bitstream.h>
+#include <qr/data.h>
+#include "constants.h"
+
+static void write_type_and_length(struct qr_data * data,
+ enum qr_data_type type,
+ size_t length)
+{
+ (void)qr_bitstream_write(data->bits, QR_TYPE_CODES[type], 4);
+ (void)qr_bitstream_write(data->bits, length,
+ qr_data_size_field_length(data->version, type));
+}
+
+static struct qr_data * encode_numeric(struct qr_data * data,
+ const unsigned char * input,
+ size_t length)
+{
+ struct qr_bitstream * stream = data->bits;
+ size_t bits;
+
+ bits = 4 + qr_data_size_field_length(data->version, QR_DATA_NUMERIC)
+ + qr_data_dpart_length(QR_DATA_NUMERIC, length);
+
+ stream = data->bits;
+ if (qr_bitstream_resize(stream,
+ qr_bitstream_size(stream) + bits) != 0)
+ return 0;
+
+ write_type_and_length(data, QR_DATA_NUMERIC, length);
+
+ for (; length >= 3; length -= 3) {
+ unsigned int x;
+
+ if (!isdigit(input[0]) ||
+ !isdigit(input[1]) ||
+ !isdigit(input[2]))
+ return 0;
+
+ x = (input[0] - '0') * 100
+ + (input[1] - '0') * 10
+ + (input[2] - '0');
+ qr_bitstream_write(stream, x, 10);
+ input += 3;
+ }
+
+ if (length > 0) {
+ unsigned int x;
+
+ if (!isdigit(*input))
+ return 0;
+
+ x = *input++ - '0';
+
+ if (length == 2) {
+ if (!isdigit(*input))
+ return 0;
+ x = x * 10 + (*input - '0');
+ }
+
+ qr_bitstream_write(stream, x, length == 2 ? 7 : 4);
+ }
+
+ return data;
+}
+
+static int get_alpha_code(char c)
+{
+ if (isdigit(c))
+ return c - '0';
+ else if (isalpha(c))
+ return toupper(c) - 'A' + 10;
+
+ switch (c) {
+ case ' ': return 36;
+ case '$': return 37;
+ case '%': return 38;
+ case '*': return 39;
+ case '+': return 40;
+ case '-': return 41;
+ case '.': return 42;
+ case '/': return 43;
+ case ':': return 44;
+ default: return -1;
+ }
+}
+
+static struct qr_data * encode_alpha(struct qr_data * data,
+ const unsigned char * input,
+ size_t length)
+{
+ struct qr_bitstream * stream = data->bits;
+ size_t bits;
+
+ bits = 4 + qr_data_size_field_length(data->version, QR_DATA_ALPHA)
+ + qr_data_dpart_length(QR_DATA_ALPHA, length);
+
+ stream = data->bits;
+ if (qr_bitstream_resize(stream,
+ qr_bitstream_size(stream) + bits) != 0)
+ return 0;
+
+ write_type_and_length(data, QR_DATA_ALPHA, length);
+
+ for (; length >= 2; length -= 2) {
+ unsigned int x;
+ int c1, c2;
+
+ c1 = get_alpha_code(*input++);
+ c2 = get_alpha_code(*input++);
+
+ if (c1 < 0 || c2 < 0)
+ return 0;
+
+ x = c1 * 45 + c2;
+ qr_bitstream_write(stream, x, 11);
+ }
+
+ if (length > 0) {
+ int c = get_alpha_code(*input);
+
+ if (c < 0)
+ return 0;
+
+ qr_bitstream_write(stream, c, 6);
+ }
+
+ return data;
+}
+
+static struct qr_data * encode_8bit(struct qr_data * data,
+ const unsigned char * input,
+ size_t length)
+{
+ struct qr_bitstream * stream = data->bits;
+ size_t bits;
+
+ bits = 4 + qr_data_size_field_length(data->version, QR_DATA_8BIT)
+ + qr_data_dpart_length(QR_DATA_8BIT, length);
+
+ stream = data->bits;
+ if (qr_bitstream_resize(stream,
+ qr_bitstream_size(stream) + bits) != 0)
+ return 0;
+
+ write_type_and_length(data, QR_DATA_8BIT, length);
+
+ while (length--)
+ qr_bitstream_write(stream, *input++, 8);
+
+ return data;
+}
+
+static struct qr_data * encode_kanji(struct qr_data * data,
+ const unsigned char * input,
+ size_t length)
+{
+ return 0;
+}
+
+static int calc_min_version(enum qr_data_type type,
+ enum qr_ec_level ec,
+ size_t length)
+{
+ size_t dbits;
+ int version;
+
+ dbits = qr_data_dpart_length(type, length);
+
+ for (version = 1; version <= 40; ++version) {
+ if (4 + dbits + qr_data_size_field_length(version, type)
+ < 8 * (size_t) QR_DATA_WORD_COUNT[version - 1][ec ^ 0x1])
+ return version;
+ }
+
+ return -1;
+}
+
+struct qr_data * qr_data_create(int version,
+ enum qr_ec_level ec,
+ enum qr_data_type type,
+ const char * input,
+ size_t length)
+{
+ struct qr_data * data;
+ int minver;
+
+ minver = calc_min_version(type, ec, length);
+
+ if (version == 0)
+ version = minver;
+
+ if (minver < 0 || version < minver)
+ return 0;
+
+ data = malloc(sizeof(*data));
+ if (!data)
+ return 0;
+
+ data->version = version;
+ data->ec = ec;
+ data->bits = qr_bitstream_create();
+ data->offset = 0;
+
+ if (data->bits) {
+ struct qr_data * ret;
+
+ switch (type) {
+ case QR_DATA_NUMERIC:
+ ret = encode_numeric(data, (const unsigned char *) input, length);
+ break;
+ case QR_DATA_ALPHA:
+ ret = encode_alpha(data, (const unsigned char *) input, length);
+ break;
+ case QR_DATA_8BIT:
+ ret = encode_8bit(data, (const unsigned char *) input, length);
+ break;
+ case QR_DATA_KANJI:
+ ret = encode_kanji(data, (const unsigned char *) input, length);
+ break;
+ default:
+ /* unsupported / invalid */
+ ret = 0;
+ break;
+ }
+
+ if (!ret) {
+ qr_bitstream_destroy(data->bits);
+ free(data);
+ }
+
+ return ret;
+ } else {
+ free(data);
+ return 0;
+ }
+}
+
+size_t qr_data_dpart_length(enum qr_data_type type, size_t length)
+{
+ size_t bits;
+
+ switch (type) {
+ case QR_DATA_NUMERIC:
+ bits = 10 * (length / 3);
+ if (length % 3 == 1)
+ bits += 4;
+ else if (length % 3 == 2)
+ bits += 7;
+ break;
+ case QR_DATA_ALPHA:
+ bits = 11 * (length / 2)
+ + 6 * (length % 2);
+ break;
+ case QR_DATA_8BIT:
+ bits = 8 * length;
+ break;
+ case QR_DATA_KANJI:
+ /* unsupported */
+ default:
+ /* unsupported; will be ignored */
+ bits = 0;
+ }
+
+ return bits;
+}
+
diff --git a/lpg/libqr/data-parse.c b/lpg/libqr/data-parse.c
new file mode 100644
index 0000000..d641c47
--- /dev/null
+++ b/lpg/libqr/data-parse.c
@@ -0,0 +1,240 @@
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <qr/bitstream.h>
+#include <qr/data.h>
+#include "constants.h"
+
+static enum qr_data_type read_data_type(struct qr_bitstream * stream)
+{
+ const size_t length = 4;
+ unsigned int type;
+
+ if (qr_bitstream_remaining(stream) < length)
+ return QR_DATA_INVALID;
+
+ type = qr_bitstream_read(stream, length);
+ assert(type < 16);
+
+ return QR_TYPE_CODES[type];
+}
+
+static enum qr_data_type parse_numeric(const struct qr_data * data,
+ char ** output,
+ size_t * length)
+{
+ struct qr_bitstream * stream;
+ size_t field_len, bits;
+ unsigned int digits;
+ unsigned int chunk;
+ char * p, * buffer;
+
+ stream = data->bits;
+ buffer = 0;
+
+ field_len = qr_data_size_field_length(data->version, QR_DATA_NUMERIC);
+ if (qr_bitstream_remaining(stream) < field_len)
+ goto invalid;
+
+ digits = qr_bitstream_read(stream, field_len);
+
+ bits = (digits / 3) * 10;
+ if (digits % 3 == 1)
+ bits += 4;
+ else if (digits % 3 == 2)
+ bits += 7;
+
+ if (qr_bitstream_remaining(stream) < bits)
+ goto invalid;
+
+ buffer = malloc(digits + 1);
+ if (!buffer)
+ goto invalid;
+
+ p = buffer;
+
+ for (; bits >= 10; bits -= 10) {
+ chunk = qr_bitstream_read(stream, 10);
+ if (chunk >= 1000)
+ goto invalid;
+ sprintf(p, "%03u", chunk);
+ p += 3;
+ }
+
+ if (bits > 0) {
+ chunk = qr_bitstream_read(stream, bits);
+ if (chunk >= (bits >= 7 ? 100 : 10))
+ goto invalid;
+ sprintf(p, "%0*u", bits >= 7 ? 2 : 1, chunk);
+ }
+
+ *output = buffer;
+ *length = digits;
+
+ return QR_DATA_NUMERIC;
+invalid:
+ free(buffer);
+ return QR_DATA_INVALID;
+}
+
+static enum qr_data_type parse_alpha(const struct qr_data * data,
+ char ** output,
+ size_t * length)
+{
+ static const char charset[45] =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
+ struct qr_bitstream * stream;
+ size_t field_len, bits;
+ unsigned int chars;
+ unsigned int chunk;
+ char * p, * buffer;
+
+ stream = data->bits;
+ buffer = 0;
+
+ field_len = qr_data_size_field_length(data->version, QR_DATA_ALPHA);
+ if (qr_bitstream_remaining(stream) < field_len)
+ goto invalid;
+
+ chars = qr_bitstream_read(stream, field_len);
+
+ bits = (chars / 2) * 11;
+ if (chars % 2 == 1)
+ bits += 6;
+
+ if (qr_bitstream_remaining(stream) < bits)
+ goto invalid;
+
+ buffer = malloc(chars + 1);
+ if (!buffer)
+ goto invalid;
+
+ p = buffer;
+
+ for (; bits >= 11; bits -= 11) {
+ unsigned int c1, c2;
+ chunk = qr_bitstream_read(stream, 11);
+ c1 = chunk / 45;
+ c2 = chunk % 45;
+ if (c1 >= 45)
+ goto invalid;
+ *p++ = charset[c1];
+ *p++ = charset[c2];
+ }
+
+ if (bits > 0) {
+ chunk = qr_bitstream_read(stream, bits);
+ if (chunk >= 45)
+ goto invalid;
+ *p = charset[chunk];
+ }
+
+ *output = buffer;
+ *length = chars;
+
+ return QR_DATA_ALPHA;
+invalid:
+ free(buffer);
+ return QR_DATA_INVALID;
+}
+
+static enum qr_data_type parse_8bit(const struct qr_data * data,
+ char ** output,
+ size_t * length)
+{
+ struct qr_bitstream * stream;
+ size_t field_len;
+ unsigned int bytes;
+ char * p;
+
+ stream = data->bits;
+
+ field_len = qr_data_size_field_length(data->version, QR_DATA_8BIT);
+ if (qr_bitstream_remaining(stream) < field_len)
+ return QR_DATA_INVALID;
+
+ bytes = qr_bitstream_read(stream, field_len);
+
+ if (qr_bitstream_remaining(stream) < bytes * 8)
+ return QR_DATA_INVALID;
+
+ *output = malloc(bytes + 1);
+ if (!*output)
+ return QR_DATA_INVALID;
+
+ p = *output;
+ *length = bytes;
+
+ while (bytes-- > 0)
+ *p++ = qr_bitstream_read(stream, 8);
+
+ *p = '\0';
+
+ return QR_DATA_8BIT;
+}
+
+static enum qr_data_type parse_kanji(const struct qr_data * data,
+ char ** output,
+ size_t * length)
+{
+ return QR_DATA_INVALID;
+}
+
+enum qr_data_type qr_data_type(const struct qr_data * data)
+{
+ qr_bitstream_seek(data->bits, data->offset);
+ return read_data_type(data->bits);
+}
+
+int qr_get_data_length(const struct qr_data * data)
+{
+ size_t field_len;
+ enum qr_data_type type;
+
+ qr_bitstream_seek(data->bits, data->offset);
+
+ type = read_data_type(data->bits);
+
+ switch (type) {
+ case QR_DATA_NUMERIC:
+ case QR_DATA_ALPHA:
+ case QR_DATA_8BIT:
+ case QR_DATA_KANJI:
+ field_len = qr_data_size_field_length(data->version, type);
+ break;
+ default:
+ /* unsupported / invalid */
+ return -1;
+ }
+
+ if (qr_bitstream_remaining(data->bits) < field_len)
+ return -1;
+
+ return (int) qr_bitstream_read(data->bits, field_len);
+}
+
+enum qr_data_type qr_parse_data(const struct qr_data * input,
+ char ** output,
+ size_t * length)
+{
+ qr_bitstream_seek(input->bits, input->offset);
+
+ *output = NULL;
+ *length = 0;
+
+ switch (read_data_type(input->bits)) {
+ case QR_DATA_NUMERIC:
+ return parse_numeric(input, output, length);
+ case QR_DATA_ALPHA:
+ return parse_alpha(input, output, length);
+ case QR_DATA_8BIT:
+ return parse_8bit(input, output, length);
+ case QR_DATA_KANJI:
+ return parse_kanji(input, output, length);
+ default:
+ /* unsupported / invalid */
+ return QR_DATA_INVALID;
+ }
+}
+
diff --git a/lpg/libqr/galois.c b/lpg/libqr/galois.c
new file mode 100644
index 0000000..decefb0
--- /dev/null
+++ b/lpg/libqr/galois.c
@@ -0,0 +1,125 @@
+#include <assert.h>
+#include <stdlib.h>
+
+#include <qr/bitstream.h>
+#include "galois.h"
+
+/* Calculate the residue of a modulo m */
+unsigned long gf_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;
+}
+
+static unsigned int gf_mult(unsigned int a, unsigned int b)
+{
+ /* Reduce modulo x^8 + x^4 + x^3 + x^2 + 1
+ * using the peasant's algorithm
+ */
+ const unsigned int m = 0x11D;
+ unsigned int x = 0;
+ int i;
+
+ for (i = 0; i < 8; ++i) {
+ x ^= (b & 0x1) ? a : 0;
+ a = (a << 1) ^ ((a & 0x80) ? m : 0);
+ b >>= 1;
+ }
+
+ return x & 0xFF;
+}
+
+static unsigned int * make_generator(int k)
+{
+ unsigned int * g;
+ unsigned int a;
+ int i, j;
+
+ g = calloc(k, sizeof(*g));
+ if (!g)
+ return 0;
+
+ g[0] = 1; /* Start with g(x) = 1 */
+ a = 1; /* 2^0 = 1 */
+
+ for (i = 0; i < k; ++i) {
+ /* Multiply our poly g(x) by (x + 2^i) */
+ for (j = k - 1; j > 0; --j)
+ g[j] = gf_mult(g[j], a) ^ g[j-1];
+ g[0] = gf_mult(g[0], a);
+
+ a = gf_mult(a, 2);
+ }
+
+ return g;
+}
+
+struct qr_bitstream * rs_generate_words(struct qr_bitstream * data,
+ size_t data_words,
+ size_t rs_words)
+{
+ struct qr_bitstream * ec = 0;
+ unsigned int * b = 0;
+ unsigned int * g;
+ size_t n = rs_words;
+ size_t i, r;
+
+ assert(qr_bitstream_remaining(data) >= data_words * 8);
+
+ ec = qr_bitstream_create();
+ if (!ec)
+ return 0;
+
+ if (qr_bitstream_resize(ec, n * 8) != 0)
+ goto fail;
+
+ b = calloc(n, sizeof(*b));
+ if (!b)
+ goto fail;
+
+ g = make_generator(n);
+ if (!g)
+ goto fail;
+
+ /* First, prepare the registers (b) with data bits */
+ for (i = 0; i < data_words; ++i) {
+ unsigned int x = b[n-1] ^ qr_bitstream_read(data, 8);
+ for (r = n-1; r > 0; --r)
+ b[r] = b[r-1] ^ gf_mult(g[r], x);
+ b[0] = gf_mult(g[0], x);
+ }
+
+ /* Read off the registers */
+ for (r = 0; r < n; ++r)
+ qr_bitstream_write(ec, b[(n-1)-r], 8);
+
+ free(g);
+ free(b);
+ return ec;
+fail:
+ free(b);
+ qr_bitstream_destroy(ec);
+ return 0;
+}
+
diff --git a/lpg/libqr/galois.h b/lpg/libqr/galois.h
new file mode 100644
index 0000000..4ca0c93
--- /dev/null
+++ b/lpg/libqr/galois.h
@@ -0,0 +1,11 @@
+#ifndef QR_GALOIS_H
+#define QR_GALOIS_H
+
+unsigned long gf_residue(unsigned long a, unsigned long m);
+
+struct qr_bitstream * rs_generate_words(struct qr_bitstream * data,
+ size_t data_words,
+ size_t rs_words);
+
+#endif
+
diff --git a/lpg/libqr/qr/bitmap.h b/lpg/libqr/qr/bitmap.h
new file mode 100644
index 0000000..098d9c3
--- /dev/null
+++ b/lpg/libqr/qr/bitmap.h
@@ -0,0 +1,37 @@
+#ifndef QR_BITMAP_H
+#define QR_BITMAP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct qr_bitmap {
+ unsigned char * bits;
+ unsigned char * mask;
+ size_t stride;
+ size_t width, height;
+};
+
+struct qr_bitmap * qr_bitmap_create(size_t width, size_t height, int masked);
+void qr_bitmap_destroy(struct qr_bitmap *);
+
+int qr_bitmap_add_mask(struct qr_bitmap *);
+
+struct qr_bitmap * qr_bitmap_clone(const struct qr_bitmap *);
+
+void qr_bitmap_merge(struct qr_bitmap * dest, const struct qr_bitmap * src);
+
+void qr_bitmap_render(const struct qr_bitmap * bmp,
+ void * buffer,
+ int mod_bits,
+ long line_stride,
+ int line_repeat,
+ unsigned long mark,
+ unsigned long space);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/lpg/libqr/qr/bitstream.h b/lpg/libqr/qr/bitstream.h
new file mode 100644
index 0000000..aa431e8
--- /dev/null
+++ b/lpg/libqr/qr/bitstream.h
@@ -0,0 +1,57 @@
+#ifndef QR_BITSTREAM_H
+#define QR_BITSTREAM_H
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Note: when writing / reading multiple bits, the
+ * _most_ significant bits come first in the stream.
+ * (That is, the order you would naturally write the
+ * number in binary)
+ */
+
+struct qr_bitstream;
+
+struct qr_bitstream * qr_bitstream_create(void);
+int qr_bitstream_resize(struct qr_bitstream *, size_t bits);
+void qr_bitstream_destroy(struct qr_bitstream *);
+struct qr_bitstream * qr_bitstream_dup(const struct qr_bitstream *);
+
+void qr_bitstream_seek(struct qr_bitstream *, size_t pos);
+size_t qr_bitstream_tell(const struct qr_bitstream *);
+size_t qr_bitstream_remaining(const struct qr_bitstream *);
+size_t qr_bitstream_size(const struct qr_bitstream *);
+
+unsigned long qr_bitstream_read(struct qr_bitstream *, int bits);
+
+void qr_bitstream_unpack(struct qr_bitstream *,
+ unsigned int * result,
+ size_t count,
+ int bitsize);
+
+int qr_bitstream_write(struct qr_bitstream *,
+ unsigned long value,
+ int bits);
+
+int qr_bitstream_pack(struct qr_bitstream *,
+ const unsigned int * values,
+ size_t count,
+ int bitsize);
+
+int qr_bitstream_cat(struct qr_bitstream *,
+ const struct qr_bitstream * src);
+
+int qr_bitstream_copy(struct qr_bitstream * dest,
+ struct qr_bitstream * src,
+ size_t count);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/lpg/libqr/qr/code.h b/lpg/libqr/qr/code.h
new file mode 100644
index 0000000..0f5d49c
--- /dev/null
+++ b/lpg/libqr/qr/code.h
@@ -0,0 +1,25 @@
+#ifndef QR_CODE_H
+#define QR_CODE_H
+
+#include <stddef.h>
+#include "types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct qr_code {
+ int version;
+ struct qr_bitmap * modules;
+};
+
+struct qr_code * qr_code_create(const struct qr_data * data);
+
+void qr_code_destroy(struct qr_code *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/lpg/libqr/qr/common.h b/lpg/libqr/qr/common.h
new file mode 100644
index 0000000..b7052ad
--- /dev/null
+++ b/lpg/libqr/qr/common.h
@@ -0,0 +1,32 @@
+#ifndef QR_COMMON_H
+#define QR_COMMON_H
+
+#include <qr/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void qr_mask_apply(struct qr_bitmap * bmp, int mask);
+
+size_t qr_code_total_capacity(int version);
+
+int qr_code_width(const struct qr_code *);
+
+/* See table 19 of the spec for the layout of EC data. There are at
+ * most two different block lengths, so the total number of data+ec
+ * blocks is the sum of block_count[]. The total number of 8-bit
+ * words in each kind of block is data_length + ec_length.
+ */
+void qr_get_rs_block_sizes(int version,
+ enum qr_ec_level ec,
+ int block_count[2],
+ int data_length[2],
+ int ec_length[2]);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/lpg/libqr/qr/data.h b/lpg/libqr/qr/data.h
new file mode 100644
index 0000000..06600ab
--- /dev/null
+++ b/lpg/libqr/qr/data.h
@@ -0,0 +1,41 @@
+#ifndef QR_DATA_H
+#define QR_DATA_H
+
+#include <stddef.h>
+#include "types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct qr_data {
+ int version; /* 1 ~ 40 */
+ enum qr_ec_level ec;
+ struct qr_bitstream * bits;
+ size_t offset;
+};
+
+struct qr_data * qr_data_create(int format, /* 1 ~ 40; 0=auto */
+ enum qr_ec_level ec,
+ enum qr_data_type type,
+ const char * input,
+ size_t length);
+
+void qr_data_destroy(struct qr_data *);
+
+enum qr_data_type qr_data_type(const struct qr_data *);
+
+size_t qr_data_length(const struct qr_data *);
+size_t qr_data_size_field_length(int version, enum qr_data_type);
+size_t qr_data_dpart_length(enum qr_data_type type, size_t nchars);
+
+enum qr_data_type qr_parse_data(const struct qr_data * input,
+ char ** output,
+ size_t * length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/lpg/libqr/qr/layout.h b/lpg/libqr/qr/layout.h
new file mode 100644
index 0000000..e691bdb
--- /dev/null
+++ b/lpg/libqr/qr/layout.h
@@ -0,0 +1,22 @@
+#ifndef QR_CODE_LAYOUT_H
+#define QR_CODE_LAYOUT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct qr_iterator;
+
+void qr_layout_init_mask(struct qr_code *);
+
+struct qr_iterator * qr_layout_begin(struct qr_code * code);
+unsigned int qr_layout_read(struct qr_iterator *);
+void qr_layout_write(struct qr_iterator *, unsigned int);
+void qr_layout_end(struct qr_iterator *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/lpg/libqr/qr/parse.h b/lpg/libqr/qr/parse.h
new file mode 100644
index 0000000..0e08354
--- /dev/null
+++ b/lpg/libqr/qr/parse.h
@@ -0,0 +1,24 @@
+#ifndef QR_PARSE_H
+#define QR_PARSE_H
+
+#include "data.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int qr_code_parse(const void * buffer,
+ size_t line_bits,
+ size_t line_stride,
+ size_t line_count,
+ struct qr_data ** data);
+
+int qr_decode_format(unsigned long bits, enum qr_ec_level * ec, int * mask);
+int qr_decode_version(unsigned long bits, int * version);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/lpg/libqr/qr/types.h b/lpg/libqr/qr/types.h
new file mode 100644
index 0000000..ae760ab
--- /dev/null
+++ b/lpg/libqr/qr/types.h
@@ -0,0 +1,34 @@
+#ifndef QR_TYPES_H
+#define QR_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct qr_data;
+struct qr_code;
+
+enum qr_data_type {
+ QR_DATA_INVALID = -1,
+ QR_DATA_ECI = 7,
+ QR_DATA_NUMERIC = 1,
+ QR_DATA_ALPHA = 2,
+ QR_DATA_8BIT = 4,
+ QR_DATA_KANJI = 8, /* JIS X 0208 */
+ QR_DATA_MIXED = 3,
+ QR_DATA_FNC1 = 9
+};
+
+enum qr_ec_level {
+ QR_EC_LEVEL_L = 0x1,
+ QR_EC_LEVEL_M = 0x0,
+ QR_EC_LEVEL_Q = 0x3,
+ QR_EC_LEVEL_H = 0x2
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/lpg/libqr/qr/version.h b/lpg/libqr/qr/version.h
new file mode 100644
index 0000000..ce540f4
--- /dev/null
+++ b/lpg/libqr/qr/version.h
@@ -0,0 +1,18 @@
+#ifndef QR_VERSION_H
+#define QR_VERSION_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define QR_VERSION_MAJOR 0
+#define QR_VERSION_MINOR 3
+
+#define QR_VERSION "0.3"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/lpg/libqr/qrgen.c b/lpg/libqr/qrgen.c
new file mode 100644
index 0000000..cf518e5
--- /dev/null
+++ b/lpg/libqr/qrgen.c
@@ -0,0 +1,402 @@
+#include <assert.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <limits.h>
+#include <png.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <qr/bitmap.h>
+#include <qr/bitstream.h>
+#include <qr/code.h>
+#include <qr/data.h>
+#include <qr/version.h>
+
+struct config {
+ int version;
+ enum qr_ec_level ec;
+ enum qr_data_type dtype;
+ enum {
+ FORMAT_ANSI,
+ FORMAT_PBM,
+ FORMAT_PNG
+ } format;
+ const char * file;
+ const char * outfile;
+ const char * input;
+};
+
+struct qr_code * create(int version,
+ enum qr_ec_level ec,
+ enum qr_data_type dtype,
+ const char * input,
+ size_t len)
+{
+ struct qr_data * data;
+ struct qr_code * code;
+
+ data = qr_data_create(version, ec, dtype, input, len);
+
+ if (!data) {
+ /* BUG: this could also indicate OOM or
+ * some other error.
+ */
+ fprintf(stderr, "Invalid data\n");
+ exit(1);
+ }
+
+ code = qr_code_create(data);
+ qr_data_destroy(data);
+
+ if (!code) {
+ perror("Failed to create code");
+ exit(2);
+ }
+
+ return code;
+}
+
+void output_pbm(FILE * file, const struct qr_bitmap * bmp, const char * comment)
+{
+ unsigned char * row;
+ int x, y;
+
+ fputs("P1\n", file);
+
+ if (comment)
+ fprintf(file, "# %s\n", comment);
+
+ fprintf(file, "%u %u\n",
+ (unsigned)bmp->width + 8,
+ (unsigned)bmp->height + 8);
+
+ row = bmp->bits;
+
+ for (y = -4; y < (int)bmp->height + 4; ++y) {
+
+ if (y < 0 || y >= (int)bmp->height) {
+ for (x = 0; x < (int)bmp->width + 8; ++x)
+ fputs("0 ", file);
+ fputc('\n', file);
+ continue;
+ }
+
+ fputs("0 0 0 0 ", file);
+
+ for (x = 0; x < (int)bmp->width; ++x) {
+
+ int mask = 1 << x % CHAR_BIT;
+ int byte = row[x / CHAR_BIT];
+
+ fprintf(file, "%c ", (byte & mask) ? '1' : '0');
+ }
+
+ fputs("0 0 0 0\n", file);
+ row += bmp->stride;
+ }
+}
+
+void output_ansi(FILE * file, const struct qr_bitmap * bmp)
+{
+ const char * out[2] = {
+ " ",
+ "\033[7m \033[0m",
+ };
+
+ unsigned char * line;
+ size_t x, y;
+
+ line = bmp->bits;
+
+ for (y = 0; y < bmp->height; ++y) {
+
+ for (x = 0; x < bmp->width; ++x) {
+
+ int mask = 1 << (x % CHAR_BIT);
+ int byte = line[x / CHAR_BIT];
+
+ fprintf(file, "%s", out[!!(byte & mask)]);
+ }
+
+ fputc('\n', file);
+
+ line += bmp->stride;
+ }
+}
+
+void output_png(FILE * file, const struct qr_bitmap * bmp, const char * comment)
+{
+ const int px_size = 4;
+ png_structp png_ptr;
+ png_infop info_ptr;
+ png_text text;
+ int x, y, p;
+ unsigned char * row;
+
+ png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if (!png_ptr)
+ goto err;
+
+ info_ptr = png_create_info_struct(png_ptr);
+ if (!info_ptr)
+ goto err;
+
+ if (setjmp(png_jmpbuf(png_ptr)))
+ goto err;
+
+ png_init_io(png_ptr, file);
+ png_set_IHDR(png_ptr, info_ptr,
+ (bmp->width + 8) * px_size,
+ (bmp->height + 8) * px_size,
+ 1,
+ PNG_COLOR_TYPE_GRAY,
+ PNG_INTERLACE_NONE,
+ PNG_COMPRESSION_TYPE_DEFAULT,
+ PNG_FILTER_TYPE_DEFAULT);
+
+ text.compression = PNG_TEXT_COMPRESSION_NONE;
+ text.key = "Software";
+ text.text = (char *) comment;
+ text.text_length = strlen(comment);
+ png_set_text(png_ptr, info_ptr, &text, 1);
+
+ png_write_info(png_ptr, info_ptr);
+ png_set_packing(png_ptr);
+
+ row = malloc((bmp->width + 8) * px_size);
+ memset(row, 1, (bmp->width + 8) * px_size);
+ for (y = 0; y < 4; ++y)
+ for (p = 0; p < px_size; ++p)
+ png_write_row(png_ptr, row);
+
+ for (y = 0; y < bmp->height; ++y) {
+ const unsigned char * bmp_row = bmp->bits + y * bmp->stride;
+ unsigned char * out = row + 4 * px_size;
+ for (x = 0; x < bmp->width; ++x) {
+ int px = bmp_row[x / CHAR_BIT] & (1 << (x % CHAR_BIT));
+ for (p = 0; p < px_size; ++p)
+ *out++ = !px;
+ }
+ for (p = 0; p < px_size; ++p)
+ png_write_row(png_ptr, row);
+ }
+
+ memset(row, 1, (bmp->width + 8) * px_size);
+ for (y = 0; y < 4; ++y)
+ for (p = 0; p < px_size; ++p)
+ png_write_row(png_ptr, row);
+
+ free(row);
+ png_write_end(png_ptr, info_ptr);
+ png_destroy_write_struct(&png_ptr, NULL);
+ return;
+
+err:
+ fprintf(stderr, "error writing PNG\n");
+ exit(2);
+}
+
+void show_help() {
+ fprintf(stderr,
+ "Usage:\n\t%s [options] <data>\n\n"
+ "\t-h Display this help message\n"
+ "\t-f <file> File containing data to encode (- for stdin)\n"
+ "\t-v <n> Specify QR version (size) 1 <= n <= 40\n"
+ "\t-e <type> Specify EC type: L, M, Q, H\n"
+ "\t-a Output as ANSI graphics (default)\n"
+ "\t-p Output as PBM\n"
+ "\t-g Output as PNG\n"
+ "\t-o <file> File to write (- for stdout)\n\n",
+ "qrgen");
+}
+
+void set_default_config(struct config * conf)
+{
+ conf->version = 0;
+ conf->ec = QR_EC_LEVEL_M;
+ conf->dtype = QR_DATA_8BIT;
+ conf->format = FORMAT_ANSI;
+ conf->file = NULL;
+ conf->outfile = NULL;
+ conf->input = NULL;
+}
+
+void parse_options(int argc, char ** argv, struct config * conf)
+{
+ int c;
+
+ for (;;) {
+ c = getopt(argc, argv, ":hf:v:e:t:apgo:");
+
+ if (c == -1) /* no more options */
+ break;
+
+ switch (c) {
+ case 'h': /* help */
+ show_help();
+ exit(0);
+ break;
+ case 'f': /* file */
+ conf->file = optarg;
+ break;
+ case 'v': /* version */
+ conf->version = atoi(optarg);
+ if (conf->version < 1 || conf->version > 40) {
+ fprintf(stderr,
+ "Version must be between 1 and 40\n");
+ exit(1);
+ }
+ break;
+ case 'e': /* ec */
+ switch (tolower(optarg[0])) {
+ case 'l': conf->ec = QR_EC_LEVEL_L; break;
+ case 'm': conf->ec = QR_EC_LEVEL_M; break;
+ case 'q': conf->ec = QR_EC_LEVEL_Q; break;
+ case 'h': conf->ec = QR_EC_LEVEL_H; break;
+ default:
+ fprintf(stderr,
+ "Invalid EC type (%c). Choose from"
+ " L, M, Q or H.\n", optarg[0]);
+ }
+ break;
+ case 't': /* type */
+ fprintf(stderr, "XXX: ignored \"type\"\n");
+ break;
+ case 'a': /* ansi */
+ conf->format = FORMAT_ANSI; break;
+ case 'p': /* pnm */
+ conf->format = FORMAT_PBM; break;
+ case 'g': /* png */
+ conf->format = FORMAT_PNG; break;
+ case 'o': /* output file */
+ conf->outfile = optarg; break;
+ case ':':
+ fprintf(stderr,
+ "Argument \"%s\" missing parameter\n",
+ argv[optind-1]);
+ exit(1);
+ break;
+ case '?': default:
+ fprintf(stderr,
+ "Invalid argument: \"%s\"\n"
+ "Try -h for help\n",
+ argv[optind-1]);
+ exit(1);
+ break;
+ }
+ }
+
+
+ if (optind < argc)
+ conf->input = argv[optind++];
+
+ if (!conf->file && !conf->input) {
+ fprintf(stderr, "No data (try -h for help)\n");
+ exit(1);
+ }
+}
+
+void slurp_file(const char * path, char ** data, size_t * len)
+{
+ const size_t chunk_size = 65536;
+ FILE * file;
+ char * tmpbuf;
+ size_t count;
+
+ if (strcmp(path, "-") == 0)
+ file = stdin;
+ else
+ file = fopen(path, "rb");
+
+ if (!file) {
+ fprintf(stderr, "Failed to open %s\n", path);
+ exit(2);
+ }
+
+ *data = NULL;
+ *len = 0;
+
+ do {
+ tmpbuf = realloc(*data, *len + chunk_size);
+ if (!tmpbuf) {
+ perror("realloc");
+ exit(2);
+ }
+ *data = tmpbuf;
+ count = fread(*data + *len, 1, chunk_size, file);
+ if (count == 0 && !feof(file)) {
+ perror("fread");
+ exit(2);
+ }
+ *len += count;
+ } while (*len == chunk_size);
+
+ fclose(file);
+}
+
+int main(int argc, char ** argv) {
+
+ struct config conf;
+ struct qr_code * code;
+ char * file_data;
+ size_t len;
+ FILE * outfile;
+
+ set_default_config(&conf);
+ parse_options(argc, argv, &conf);
+
+ if (conf.file)
+ slurp_file(conf.file, &file_data, &len);
+ else
+ len = strlen(conf.input);
+
+ if (!conf.outfile) {
+ switch (conf.format) {
+ case FORMAT_ANSI:
+ conf.outfile = "-"; break;
+ case FORMAT_PBM:
+ conf.outfile = "qr.pbm"; break;
+ case FORMAT_PNG:
+ conf.outfile = "qr.png"; break;
+ }
+ }
+
+ if (strcmp(conf.outfile, "-") == 0) {
+ outfile = stdout;
+ } else {
+ outfile = fopen(conf.outfile, "wb");
+ if (!outfile) {
+ perror("fopen");
+ exit(2);
+ }
+ }
+
+ code = create(conf.version,
+ conf.ec,
+ conf.dtype,
+ conf.file ? file_data : conf.input,
+ len);
+
+ if (conf.file)
+ free(file_data);
+
+ switch (conf.format) {
+ case FORMAT_ANSI:
+ output_ansi(outfile, code->modules);
+ break;
+ case FORMAT_PBM:
+ output_pbm(outfile, code->modules, "libqr v" QR_VERSION);
+ break;
+ case FORMAT_PNG:
+ output_png(outfile, code->modules, "libqr v" QR_VERSION);
+ break;
+ }
+
+ fclose(outfile);
+ qr_code_destroy(code);
+
+ return 0;
+}
+
diff --git a/lpg/libqr/qrparse.c b/lpg/libqr/qrparse.c
new file mode 100644
index 0000000..1b5c80e
--- /dev/null
+++ b/lpg/libqr/qrparse.c
@@ -0,0 +1,59 @@
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <qr/code.h>
+#include <qr/data.h>
+#include <qr/parse.h>
+
+#include "testqr.xbm"
+
+int main(int argc, char ** argv)
+{
+ struct qr_data * data;
+ int ret;
+
+ ret = qr_code_parse(testqr_bits,
+ testqr_width,
+ (testqr_width + CHAR_BIT - 1) / CHAR_BIT,
+ testqr_height,
+ &data);
+
+ fprintf(stderr, "qr_code_parse returned %d\n", ret);
+
+ if (ret == 0) {
+ const char * ec_str, * type_str;
+ char * data_str;
+ size_t data_len;
+ enum qr_data_type data_type;
+
+ fprintf(stderr, "version = %d\n", data->version);
+ switch (data->ec) {
+ case QR_EC_LEVEL_L: ec_str = "L"; break;
+ case QR_EC_LEVEL_M: ec_str = "M"; break;
+ case QR_EC_LEVEL_Q: ec_str = "Q"; break;
+ case QR_EC_LEVEL_H: ec_str = "H"; break;
+ default: ec_str = "(unknown)"; break;
+ }
+ fprintf(stderr, "EC level %s\n", ec_str);
+
+ data_type = qr_parse_data(data, &data_str, &data_len);
+ switch (data_type) {
+ case QR_DATA_INVALID: type_str = "(invalid)"; break;
+ case QR_DATA_ECI: type_str = "ECI"; break;
+ case QR_DATA_NUMERIC: type_str = "numeric"; break;
+ case QR_DATA_ALPHA: type_str = "alpha"; break;
+ case QR_DATA_8BIT: type_str = "8-bit"; break;
+ case QR_DATA_KANJI: type_str = "kanji"; break;
+ case QR_DATA_MIXED: type_str = "mixed"; break;
+ case QR_DATA_FNC1: type_str = "FNC1"; break;
+ default: type_str = "(unknown)"; break;
+ }
+ fprintf(stderr, "Data type: %s; %lu bytes\nContent: %s\n", type_str, (unsigned long) data_len, data_str);
+ free(data_str);
+ qr_data_destroy(data);
+ }
+
+ return 0;
+}
+
diff --git a/lpg/libqr/testqr.xbm b/lpg/libqr/testqr.xbm
new file mode 100644
index 0000000..ca2966f
--- /dev/null
+++ b/lpg/libqr/testqr.xbm
@@ -0,0 +1,19 @@
+#define testqr_width 37
+#define testqr_height 37
+static unsigned char testqr_bits[] = {
+ 0x7F, 0x63, 0xFB, 0xDA, 0x1F, 0x41, 0xD7, 0xAD, 0x55, 0x10, 0x5D, 0x3D,
+ 0xE9, 0x5E, 0x17, 0x5D, 0xC6, 0xB5, 0x43, 0x17, 0x5D, 0x41, 0x61, 0x52,
+ 0x17, 0x41, 0x76, 0xC9, 0x46, 0x10, 0x7F, 0x55, 0x55, 0xD5, 0x1F, 0x00,
+ 0x98, 0x47, 0x05, 0x00, 0xF9, 0x99, 0xE0, 0x36, 0x1D, 0x24, 0x01, 0x07,
+ 0xC7, 0x0A, 0x60, 0xBC, 0xB9, 0x44, 0x16, 0x81, 0x21, 0x9D, 0x8D, 0x1B,
+ 0xCF, 0x8E, 0x83, 0x51, 0x16, 0xA2, 0x1B, 0xFD, 0x3A, 0x1B, 0xEB, 0x3B,
+ 0x1D, 0x5B, 0x17, 0xA9, 0xF6, 0x70, 0xF8, 0x1F, 0xC1, 0x68, 0x66, 0xFD,
+ 0x1D, 0xB3, 0x07, 0xC2, 0x54, 0x04, 0xD8, 0x0C, 0x4F, 0x4D, 0x15, 0x11,
+ 0xA1, 0x99, 0xA2, 0x11, 0x60, 0x65, 0xCC, 0x49, 0x05, 0x1D, 0x1F, 0xC3,
+ 0x8E, 0x15, 0x64, 0xED, 0xB9, 0x9A, 0x02, 0x90, 0x03, 0x1D, 0xAA, 0x0D,
+ 0x45, 0xD8, 0x72, 0x92, 0x01, 0x83, 0x53, 0x6E, 0x55, 0x06, 0xC7, 0xC4,
+ 0x02, 0xB4, 0x1B, 0x19, 0x24, 0x0F, 0x8D, 0x12, 0xE5, 0xAA, 0xAA, 0xF3,
+ 0x03, 0x00, 0x5F, 0x66, 0x11, 0x11, 0x7F, 0x73, 0x8F, 0x57, 0x1B, 0x41,
+ 0x8D, 0x39, 0x1B, 0x19, 0x5D, 0x3B, 0x3D, 0xFB, 0x13, 0x5D, 0x03, 0x70,
+ 0x62, 0x1C, 0x5D, 0x6A, 0x46, 0x37, 0x19, 0x41, 0xDA, 0x62, 0xF8, 0x1D,
+ 0x7F, 0x7B, 0x3E, 0x58, 0x14, };