qr: every version, 1 to 40

PSOGM mode will put the kernel log on screen as QR codes, a page per
symbol, and version 6 held 134 bytes. Version 40 at level L holds 2,953.

What grew: blocks of two lengths and the interleave that steps around
them, the alignment-pattern grid, the version-information blocks from
version 7, the 16-bit character count from version 10. The per-version
table is down to the two columns that are genuinely transcription (EC
codewords per block, block count); total codewords come from the
geometry.

Checked against segno module for module at every version (exact-fill
payloads), and 120 symbols across all 40 versions decode with zbar.
OpenCV's detector cannot find symbols above about version 24 at all,
segno's included, so qrcheck reports those as the detector's limit.

The crash card stays a version-6 symbol (QR_CARD_BYTES), so a phone still
reads it from across the desk.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
Nexoniarz 2026-10-25 00:43:36 +02:00
commit d8e8ae604f
5 changed files with 147 additions and 83 deletions

View file

@ -155,25 +155,26 @@ check(int ok, const char *what)
}
// The version table is the one part of qr.c that is transcription rather than
// reasoning, so check what can be checked: block sizes must divide evenly, and
// the symbol must have room for exactly the codewords claimed.
// reasoning, so check what can be checked: the data left over is positive and
// the blocks are no more than one codeword apart, and the symbol has room for
// exactly the codewords the geometry formula claims.
static void
check_tables(void)
{
printf("version table\n");
for (int v = 1; v <= QR_MAX_VERSION; v++) {
int total = vinfo[v].total;
int data = total - vinfo[v].ecc * vinfo[v].blocks;
int total = total_codewords(v);
int data = data_codewords(v);
char msg[128];
snprintf(msg, sizeof msg, "v%d: %d data codewords divide into %d blocks",
v, data, vinfo[v].blocks);
check(data > 0 && data % vinfo[v].blocks == 0, msg);
snprintf(msg, sizeof msg, "v%d: %d data codewords in %d blocks",
v, data, ecc_blocks[v]);
check(data > 0 && data / ecc_blocks[v] > 0, msg);
// Count the modules a symbol of this version actually leaves for data,
// by building one and asking. If the table's codeword count disagrees
// by building one and asking. If the formula's codeword count disagrees
// with the geometry, one of the two is wrong.
struct qr q;
static struct qr q;
memset(&q, 0, sizeof q);
q.size = 17 + 4 * v;
draw_function_patterns(&q);
@ -219,7 +220,7 @@ static void
check_encode(void)
{
printf("encode\n");
struct qr q;
static struct qr q;
check(qr_encode(&q, (const unsigned char *)"HELLO", 5) == 0, "short payload encodes");
check(q.size == 21, "and picks version 1");
@ -227,7 +228,9 @@ check_encode(void)
unsigned char big[QR_MAX_BYTES];
memset(big, 'A', sizeof big);
check(qr_encode(&q, big, QR_MAX_BYTES) == 0, "maximum payload encodes");
check(q.size == 41, "and picks version 6");
check(q.size == QR_MAX_SIZE, "and picks version 40");
check(qr_capacity(40) == 2953 && qr_capacity(10) == 271 && qr_capacity(9) == 230,
"capacities match the standard at v9, v10 and v40");
check(qr_encode(&q, big, QR_MAX_BYTES + 1) == -1, "one byte over is refused");
// Every function module must still be a function module after masking --
@ -270,7 +273,7 @@ main(int argc, char **argv)
// codeword two encoders disagree about is the difference between a bug you
// can see and one you can only stare at.
if (argc > 2 && strcmp(argv[1], "-f") == 0) {
struct qr q;
static struct qr q;
int n = (int)strlen(argv[2]);
if (n > QR_MAX_BYTES || qr_encode(&q, (const unsigned char *)argv[2], n) != 0)
return 1;
@ -283,7 +286,7 @@ main(int argc, char **argv)
}
if (argc > 2 && strcmp(argv[1], "-m") == 0) {
struct qr q;
static struct qr q;
int n = (int)strlen(argv[2]);
if (n > QR_MAX_BYTES || qr_encode(&q, (const unsigned char *)argv[2], n) != 0)
return 1;
@ -308,7 +311,7 @@ main(int argc, char **argv)
check_rs();
check_encode();
struct qr q;
static struct qr q;
int len = (int)strlen(text);
if (len > QR_MAX_BYTES) {
fprintf(stderr, "qrtest: payload is %d bytes, max %d\n", len, QR_MAX_BYTES);