An x86-64 operating system built from xv6, now largely rewritten: SMP, a copy-on-write root filesystem (SchFS), PCI/USB/virtio drivers, a TTF rasteriser, and a Linux-numbered syscall ABI. No history before this point -- the tree was never under version control. This commit exists so the rename that follows has something to undo to.
456 lines
14 KiB
C
456 lines
14 KiB
C
// QR encoder. See include/qr.h for why it exists and why it is this small.
|
|
//
|
|
// Freestanding on purpose: no allocation, no floating point, no libc beyond
|
|
// memset/memmove. It has to run in panic context, where the heap may be exactly
|
|
// what is broken. Every buffer here is either on the caller's struct or a
|
|
// bounded local.
|
|
//
|
|
// The structure follows ISO/IEC 18004 in the order the standard describes it,
|
|
// which is also the only order in which any of it can be checked:
|
|
//
|
|
// 1. encode the payload into data codewords
|
|
// 2. append Reed-Solomon error correction, per block
|
|
// 3. interleave the blocks
|
|
// 4. draw the function patterns (finders, timing, alignment, format area)
|
|
// 5. lay the codeword bits into the remaining modules in a zigzag
|
|
// 6. try all 8 masks, score each, keep the best
|
|
//
|
|
// Verified by scanning the output with a phone, which is the only test that
|
|
// matters and is also literally the feature.
|
|
|
|
#ifdef QR_HOST
|
|
#include <string.h>
|
|
#else
|
|
#include "types.h"
|
|
#include "defs.h"
|
|
#endif
|
|
|
|
#include "qr.h"
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Version table
|
|
// ---------------------------------------------------------------------------
|
|
//
|
|
// Per version, at error correction level L: total codewords, error correction
|
|
// codewords per block, and number of blocks. These are from the standard's
|
|
// tables and cannot be derived, so they are the one part of this file that has
|
|
// to be right by transcription rather than by reasoning.
|
|
//
|
|
// A useful check on them: total - ecc*blocks must be divisible by blocks for
|
|
// every row below, because levels 1..6 at L happen to have equally sized
|
|
// blocks. qr_encode() asserts exactly that at runtime, which is what turns a
|
|
// mistyped number here into a visible failure instead of an unscannable symbol.
|
|
static const struct {
|
|
short total; // total codewords in the symbol
|
|
unsigned char ecc; // EC codewords per block
|
|
unsigned char blocks; // number of RS blocks
|
|
} vinfo[QR_MAX_VERSION + 1] = {
|
|
{ 0, 0, 0 }, // version 0 does not exist; keeps indexing natural
|
|
{ 26, 7, 1 },
|
|
{ 44, 10, 1 },
|
|
{ 70, 15, 1 },
|
|
{ 100, 20, 1 },
|
|
{ 134, 26, 1 },
|
|
{ 172, 18, 2 },
|
|
};
|
|
|
|
int
|
|
qr_capacity(int version)
|
|
{
|
|
if (version < 1 || version > QR_MAX_VERSION)
|
|
return 0;
|
|
// Data codewords, less the two bytes of framing: a 4-bit mode indicator, an
|
|
// 8-bit character count (versions 1-9), and a 4-bit terminator come to
|
|
// exactly two codewords' worth of overhead.
|
|
int data = vinfo[version].total - vinfo[version].ecc * vinfo[version].blocks;
|
|
return data - 2;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// GF(256) and Reed-Solomon
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// Multiply in GF(256) modulo x^8 + x^4 + x^3 + x^2 + 1 (0x11D).
|
|
//
|
|
// Done by shift-and-add rather than log/exp tables. Two 256-byte tables plus
|
|
// their initialisation is more code than this loop, and this needs no init step
|
|
// at all -- which matters when the caller is a panic handler that cannot assume
|
|
// any particular earlier function ran.
|
|
static unsigned char
|
|
gmul(unsigned char x, unsigned char y)
|
|
{
|
|
unsigned char z = 0;
|
|
for (int i = 7; i >= 0; i--) {
|
|
z = (unsigned char)((z << 1) ^ ((z >> 7) * 0x1D));
|
|
z ^= (unsigned char)(((y >> i) & 1) * x);
|
|
}
|
|
return z;
|
|
}
|
|
|
|
// Coefficients of the degree-`degree` generator polynomial, highest power
|
|
// first, with the leading 1 left implicit.
|
|
static void
|
|
rs_divisor(int degree, unsigned char *result)
|
|
{
|
|
memset(result, 0, degree);
|
|
result[degree - 1] = 1; // start at the monomial x^0
|
|
|
|
// Multiply by (x - r) for r = 1, a, a^2, ... Each pass shifts the polynomial
|
|
// up one degree and folds in the new root.
|
|
unsigned char root = 1;
|
|
for (int i = 0; i < degree; i++) {
|
|
for (int j = 0; j < degree; j++) {
|
|
result[j] = gmul(result[j], root);
|
|
if (j + 1 < degree)
|
|
result[j] ^= result[j + 1];
|
|
}
|
|
root = gmul(root, 0x02);
|
|
}
|
|
}
|
|
|
|
// The remainder of data[] divided by the generator: the EC codewords.
|
|
static void
|
|
rs_remainder(const unsigned char *data, int len,
|
|
const unsigned char *gen, int degree, unsigned char *result)
|
|
{
|
|
memset(result, 0, degree);
|
|
for (int i = 0; i < len; i++) {
|
|
unsigned char factor = data[i] ^ result[0];
|
|
memmove(&result[0], &result[1], degree - 1);
|
|
result[degree - 1] = 0;
|
|
for (int j = 0; j < degree; j++)
|
|
result[j] ^= gmul(gen[j], factor);
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Module access
|
|
// ---------------------------------------------------------------------------
|
|
|
|
static void
|
|
set_fn(struct qr *q, int x, int y, int dark)
|
|
{
|
|
if (x < 0 || y < 0 || x >= q->size || y >= q->size)
|
|
return;
|
|
q->mod[y][x] = (unsigned char)(dark != 0);
|
|
q->fn[y][x] = 1;
|
|
}
|
|
|
|
static int
|
|
absi(int v)
|
|
{
|
|
return v < 0 ? -v : v;
|
|
}
|
|
|
|
static int
|
|
cheb(int dx, int dy)
|
|
{
|
|
int ax = absi(dx), ay = absi(dy);
|
|
return ax > ay ? ax : ay;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Function patterns
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// A finder plus its separator, as one 9x9 stamp centred on (cx, cy).
|
|
//
|
|
// Writing it by Chebyshev distance rather than as a literal bitmap is not
|
|
// cleverness for its own sake: the concentric rings *are* the definition -- dark
|
|
// 3x3 core, light ring, dark ring, light separator -- and the edge stamps run
|
|
// off the symbol, which set_fn() clips.
|
|
static void
|
|
draw_finder(struct qr *q, int cx, int cy)
|
|
{
|
|
for (int dy = -4; dy <= 4; dy++)
|
|
for (int dx = -4; dx <= 4; dx++) {
|
|
int d = cheb(dx, dy);
|
|
set_fn(q, cx + dx, cy + dy, d != 2 && d != 4);
|
|
}
|
|
}
|
|
|
|
// The 5x5 alignment pattern: dark 3x3 outline with a light ring inside.
|
|
static void
|
|
draw_alignment(struct qr *q, int cx, int cy)
|
|
{
|
|
for (int dy = -2; dy <= 2; dy++)
|
|
for (int dx = -2; dx <= 2; dx++)
|
|
set_fn(q, cx + dx, cy + dy, cheb(dx, dy) != 1);
|
|
}
|
|
|
|
// The 15-bit format information, twice, plus the always-dark module.
|
|
//
|
|
// Called once with the real mask at the end, and once early with mask 0 purely
|
|
// to *reserve* these modules -- the zigzag below skips anything marked as a
|
|
// function pattern, so the reservation has to exist before data is placed.
|
|
static void
|
|
draw_format(struct qr *q, int mask)
|
|
{
|
|
// 0b01 is error correction level L. Five data bits, then a BCH(15,5) check
|
|
// computed with generator 0x537, then XOR 0x5412 so an all-zero format never
|
|
// produces an all-zero pattern.
|
|
int data = (1 << 3) | mask;
|
|
int rem = data;
|
|
for (int i = 0; i < 10; i++)
|
|
rem = (rem << 1) ^ ((rem >> 9) * 0x537);
|
|
int bits = ((data << 10) | rem) ^ 0x5412;
|
|
|
|
int n = q->size;
|
|
|
|
// First copy: down the left of the top-right finder, then left along the top
|
|
// of the bottom-left one. The 6/7 and 7/8 jogs skip the timing pattern.
|
|
for (int i = 0; i <= 5; i++)
|
|
set_fn(q, 8, i, (bits >> i) & 1);
|
|
set_fn(q, 8, 7, (bits >> 6) & 1);
|
|
set_fn(q, 8, 8, (bits >> 7) & 1);
|
|
set_fn(q, 7, 8, (bits >> 8) & 1);
|
|
for (int i = 9; i < 15; i++)
|
|
set_fn(q, 14 - i, 8, (bits >> i) & 1);
|
|
|
|
// Second copy, so the format survives damage to either corner.
|
|
for (int i = 0; i < 8; i++)
|
|
set_fn(q, n - 1 - i, 8, (bits >> i) & 1);
|
|
for (int i = 8; i < 15; i++)
|
|
set_fn(q, 8, n - 15 + i, (bits >> i) & 1);
|
|
|
|
set_fn(q, 8, n - 8, 1); // the dark module, always set, always here
|
|
}
|
|
|
|
static void
|
|
draw_function_patterns(struct qr *q)
|
|
{
|
|
int n = q->size;
|
|
|
|
// Timing patterns first: the finders overwrite their ends, which is correct.
|
|
for (int i = 0; i < n; i++) {
|
|
set_fn(q, 6, i, i % 2 == 0);
|
|
set_fn(q, i, 6, i % 2 == 0);
|
|
}
|
|
|
|
draw_finder(q, 3, 3);
|
|
draw_finder(q, n - 4, 3);
|
|
draw_finder(q, 3, n - 4);
|
|
|
|
// For versions 2-6 the alignment centres are {6, n-7}, and three of those
|
|
// four combinations collide with a finder. Only the bottom-right survives,
|
|
// which is why there is no position table here. Version 7 would need one.
|
|
if (q->size > 21)
|
|
draw_alignment(q, n - 7, n - 7);
|
|
|
|
draw_format(q, 0); // reserve; overwritten once a mask is chosen
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Masking
|
|
// ---------------------------------------------------------------------------
|
|
|
|
static int
|
|
mask_bit(int mask, int x, int y)
|
|
{
|
|
switch (mask) {
|
|
case 0: return (x + y) % 2 == 0;
|
|
case 1: return y % 2 == 0;
|
|
case 2: return x % 3 == 0;
|
|
case 3: return (x + y) % 3 == 0;
|
|
case 4: return (x / 3 + y / 2) % 2 == 0;
|
|
case 5: return x * y % 2 + x * y % 3 == 0;
|
|
case 6: return (x * y % 2 + x * y % 3) % 2 == 0;
|
|
case 7: return ((x + y) % 2 + x * y % 3) % 2 == 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
apply_mask(struct qr *q, int mask)
|
|
{
|
|
for (int y = 0; y < q->size; y++)
|
|
for (int x = 0; x < q->size; x++)
|
|
if (!q->fn[y][x])
|
|
q->mod[y][x] ^= (unsigned char)mask_bit(mask, x, y);
|
|
}
|
|
|
|
// The standard's four penalty rules. Lower is better.
|
|
//
|
|
// A decoder will read any legal mask, so this is not correctness -- it is scan
|
|
// reliability, which is the whole point when the reader is a handheld camera
|
|
// pointed at a screen. Rule 3 in particular exists to stop the data accidentally
|
|
// containing something that looks like a finder pattern.
|
|
static int
|
|
penalty(const struct qr *q)
|
|
{
|
|
int n = q->size, score = 0, dark = 0;
|
|
|
|
for (int y = 0; y < n; y++) {
|
|
for (int x = 0; x < n; x++)
|
|
dark += q->mod[y][x];
|
|
|
|
// Rule 1, both directions: runs of five or more identical modules.
|
|
for (int dir = 0; dir < 2; dir++) {
|
|
int run = 1;
|
|
int prev = dir ? q->mod[0][y] : q->mod[y][0];
|
|
for (int i = 1; i < n; i++) {
|
|
int cur = dir ? q->mod[i][y] : q->mod[y][i];
|
|
if (cur == prev) {
|
|
run++;
|
|
} else {
|
|
if (run >= 5) score += 3 + (run - 5);
|
|
run = 1;
|
|
prev = cur;
|
|
}
|
|
}
|
|
if (run >= 5) score += 3 + (run - 5);
|
|
}
|
|
}
|
|
|
|
// Rule 2: every 2x2 block of one colour.
|
|
for (int y = 0; y + 1 < n; y++)
|
|
for (int x = 0; x + 1 < n; x++) {
|
|
int c = q->mod[y][x];
|
|
if (c == q->mod[y][x + 1] && c == q->mod[y + 1][x] && c == q->mod[y + 1][x + 1])
|
|
score += 3;
|
|
}
|
|
|
|
// Rule 3: the finder-lookalike 1011101 with four light modules on either
|
|
// side, in either direction.
|
|
for (int dir = 0; dir < 2; dir++)
|
|
for (int a = 0; a < n; a++) {
|
|
unsigned bits = 0;
|
|
for (int b = 0; b < n; b++) {
|
|
int m = dir ? q->mod[b][a] : q->mod[a][b];
|
|
bits = ((bits << 1) | (unsigned)m) & 0x7FF;
|
|
if (b >= 10 && (bits == 0x05D || bits == 0x5D0))
|
|
score += 40;
|
|
}
|
|
}
|
|
|
|
// Rule 4: deviation from an even split of dark and light, in 5% steps.
|
|
int total = n * n;
|
|
int k = (absi(dark * 20 - total * 10) + total - 1) / total;
|
|
score += k * 10;
|
|
|
|
return score;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Encode
|
|
// ---------------------------------------------------------------------------
|
|
|
|
static void
|
|
put_bits(unsigned char *buf, int *pos, unsigned val, int n)
|
|
{
|
|
for (int i = n - 1; i >= 0; i--) {
|
|
buf[*pos >> 3] |= (unsigned char)(((val >> i) & 1) << (7 - (*pos & 7)));
|
|
(*pos)++;
|
|
}
|
|
}
|
|
|
|
int
|
|
qr_encode(struct qr *q, const unsigned char *data, int len)
|
|
{
|
|
int v;
|
|
|
|
if (len < 0)
|
|
return -1;
|
|
for (v = 1; v <= QR_MAX_VERSION; v++)
|
|
if (len <= qr_capacity(v))
|
|
break;
|
|
if (v > QR_MAX_VERSION)
|
|
return -1;
|
|
|
|
int total = vinfo[v].total;
|
|
int ecclen = vinfo[v].ecc;
|
|
int blocks = vinfo[v].blocks;
|
|
int datacw = total - ecclen * blocks;
|
|
|
|
// The table claims equal-sized blocks for every version this file supports.
|
|
// If that is ever untrue the interleave below is silently wrong, so check it
|
|
// rather than trust it.
|
|
if (datacw % blocks != 0)
|
|
return -1;
|
|
int blocklen = datacw / blocks;
|
|
|
|
// --- 1. payload -> data codewords ---------------------------------------
|
|
unsigned char cw[172]; // >= max total codewords
|
|
memset(cw, 0, sizeof(cw));
|
|
|
|
int pos = 0;
|
|
put_bits(cw, &pos, 0x4, 4); // byte mode
|
|
put_bits(cw, &pos, (unsigned)len, 8);
|
|
for (int i = 0; i < len; i++)
|
|
put_bits(cw, &pos, data[i], 8);
|
|
|
|
// Terminator, up to four zero bits, then round up to a whole codeword.
|
|
int spare = datacw * 8 - pos;
|
|
put_bits(cw, &pos, 0, spare < 4 ? spare : 4);
|
|
if (pos & 7)
|
|
put_bits(cw, &pos, 0, 8 - (pos & 7));
|
|
|
|
// Fill the rest with the standard alternating pad bytes. They are specified
|
|
// values, not arbitrary filler: a decoder uses the character count to know
|
|
// where the data ends, but the pad pattern keeps the symbol from having large
|
|
// uniform regions that mask selection would then have to fight.
|
|
for (int i = pos / 8; i < datacw; i++)
|
|
cw[i] = (i - pos / 8) % 2 == 0 ? 0xEC : 0x11;
|
|
|
|
// --- 2 and 3. error correction, then interleave -------------------------
|
|
unsigned char gen[30];
|
|
unsigned char ec[4][30];
|
|
rs_divisor(ecclen, gen);
|
|
for (int b = 0; b < blocks; b++)
|
|
rs_remainder(&cw[b * blocklen], blocklen, gen, ecclen, ec[b]);
|
|
|
|
unsigned char out[172];
|
|
int o = 0;
|
|
for (int i = 0; i < blocklen; i++)
|
|
for (int b = 0; b < blocks; b++)
|
|
out[o++] = cw[b * blocklen + i];
|
|
for (int i = 0; i < ecclen; i++)
|
|
for (int b = 0; b < blocks; b++)
|
|
out[o++] = ec[b][i];
|
|
|
|
// --- 4. function patterns ------------------------------------------------
|
|
memset(q, 0, sizeof(*q));
|
|
q->size = 17 + 4 * v;
|
|
draw_function_patterns(q);
|
|
|
|
// --- 5. zigzag placement -------------------------------------------------
|
|
//
|
|
// Two-module-wide columns walked from the right edge leftwards, alternating
|
|
// upward and downward. Column 6 is skipped entirely because it is the vertical
|
|
// timing pattern -- without that step every subsequent column lands one place
|
|
// out and the symbol is quietly unreadable.
|
|
int bit = 0;
|
|
int nbits = o * 8;
|
|
for (int right = q->size - 1; right >= 1; right -= 2) {
|
|
if (right == 6)
|
|
right = 5;
|
|
for (int vert = 0; vert < q->size; vert++) {
|
|
for (int j = 0; j < 2; j++) {
|
|
int x = right - j;
|
|
int upward = ((right + 1) & 2) == 0;
|
|
int y = upward ? q->size - 1 - vert : vert;
|
|
if (!q->fn[y][x] && bit < nbits) {
|
|
q->mod[y][x] = (unsigned char)((out[bit >> 3] >> (7 - (bit & 7))) & 1);
|
|
bit++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- 6. pick a mask ------------------------------------------------------
|
|
int best = 0, bestscore = 0;
|
|
for (int m = 0; m < 8; m++) {
|
|
apply_mask(q, m);
|
|
draw_format(q, m);
|
|
int s = penalty(q);
|
|
if (m == 0 || s < bestscore) {
|
|
bestscore = s;
|
|
best = m;
|
|
}
|
|
apply_mask(q, m); // XOR again to undo; masking is involutive
|
|
}
|
|
apply_mask(q, best);
|
|
draw_format(q, best);
|
|
|
|
return 0;
|
|
}
|