#include #include #include #include #include "code-common.h" #include "code-layout.h" #include "data-common.h" #include "rs.h" #define MIN(a, b) ((b) < (a) ? (b) : (a)) #include static void x_dump(struct bitstream * bits) { size_t i, n; bitstream_seek(bits, 0); n = bitstream_size(bits); for (i = 0; i < n; ++i) { printf("%d", bitstream_read(bits, 1)); if (i % 8 == 7) printf(" "); if ((i+1) % (7 * 8) == 0) printf("\n"); } printf("\n"); } static void setpx(struct qr_code * code, int x, int y) { size_t off = y * code->modules->stride + x / CHAR_BIT; unsigned char bit = 1 << (x % CHAR_BIT); code->modules->bits[off] |= bit; } static void draw_locator(struct qr_code * code, int x, int y) { int i; for (i = 0; i < 6; ++i) { setpx(code, x + i, y + 0); setpx(code, x + 6, y + i); setpx(code, x + i + 1, y + 6); setpx(code, x, y + i + 1); } for (i = 0; i < 9; ++i) setpx(code, x + 2 + i % 3, y + 2 + i / 3); } static void draw_fixed_bits(struct qr_code * code) { int dim = code_side_length(code->format); int i; /* Locator pattern */ draw_locator(code, 0, 0); draw_locator(code, 0, dim - 7); draw_locator(code, dim - 7, 0); /* Timing pattern */ for (i = 8; i < dim - 8; i += 2) { setpx(code, i, 6); setpx(code, 6, i); } /* XXX: alignment pattern */ } static int pad_data(struct bitstream * bits, size_t limit) { /* This function is not very nice. Sorry. */ size_t count, n; assert(bitstream_size(bits) <= limit); if (bitstream_resize(bits, limit) != 0) return -1; n = bitstream_size(bits); 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); 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) { bitstream_write(bits, 0xEC11, 16); count -= 16; } if (count > 0) { assert(count == 8); bitstream_write(bits, 0xEC, 8); } return 0; } static struct bitstream * make_data(int format, enum qr_ec_level ec, struct bitstream * data) { const size_t total_bits = code_total_capacity(format); const size_t total_words = total_bits / 8; size_t block_count, data_words, rs_words; size_t i; struct bitstream * dcopy = 0; struct bitstream * out = 0; struct bitstream ** blocks = 0; /* Set up the output stream */ out = bitstream_create(); if (!out) return 0; if (bitstream_resize(out, total_bits) != 0) goto fail; /** * XXX: For our test case (1-M) there is only one RS block. * This is not the case for most other formats, so we'll * have to deal with this eventually. */ block_count = 1; data_words = 16; rs_words = 10; assert(data_words + rs_words == total_words); /* Make a copy of the data and pad it */ dcopy = bitstream_copy(data); if (!dcopy) goto fail; if (pad_data(dcopy, data_words * 8) != 0) goto fail; puts("Pad data:"); x_dump(dcopy); /* Make space for the RS blocks */ blocks = calloc(block_count, sizeof(*blocks)); if (!blocks) goto fail; /* Generate RS codewords */ bitstream_seek(dcopy, 0); puts("Generate RS blocks:"); for (i = 0; i < block_count; ++i) { /* XXX: some blocks may be longer */ blocks[i] = rs_generate_words(dcopy, data_words, rs_words); if (!blocks[i]) { while (i--) bitstream_destroy(blocks[i]); free(blocks); blocks = 0; goto fail; } x_dump(blocks[i]); } /* Finally, write everything out in the correct order */ /* XXX: need to handle multiple blocks */ bitstream_cat(out, dcopy); bitstream_cat(out, blocks[0]); bitstream_write(out, 0, total_bits - total_words * 8); puts("Final bitstream:"); x_dump(out); exit: if (blocks) { while (block_count--) bitstream_destroy(blocks[block_count]); free(blocks); } if (dcopy) bitstream_destroy(dcopy); return out; fail: bitstream_destroy(out); out = 0; goto exit; } struct qr_code * qr_code_create(enum qr_ec_level ec, const struct qr_data * data) { struct qr_code * code; struct bitstream * bits = 0; struct qr_iterator * layout; size_t dim; code = malloc(sizeof(*code)); if (!code) return 0; dim = code_side_length(data->format); code->format = data->format; code->modules = qr_bitmap_create(dim, dim, 0); if (!code->modules) goto fail; draw_fixed_bits(code); bits = make_data(data->format, ec, data->bits); if (!bits) goto fail; layout = qr_layout_begin(code); if (!layout) goto fail; bitstream_seek(bits, 0); while (bitstream_remaining(bits) >= 8) qr_layout_write(layout, bitstream_read(bits, 8)); qr_layout_end(layout); exit: if (bits) bitstream_destroy(bits); return code; fail: qr_code_destroy(code); code = 0; goto exit; }