Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38c89b1a9a | ||
|
|
d8e8ae604f |
9 changed files with 204 additions and 83 deletions
|
|
@ -457,6 +457,8 @@ extern uint64 boot_epoch;
|
|||
int cpunum(void);
|
||||
extern volatile uint* lapic;
|
||||
void lapiceoi(void);
|
||||
extern volatile int panic_stop; // kernel/core/panic.c
|
||||
void lapic_nmi_others(void);
|
||||
void lapicinit(void);
|
||||
void lapicstartap(uchar, uint);
|
||||
void microdelay(int);
|
||||
|
|
|
|||
|
|
@ -8,25 +8,26 @@
|
|||
// no second machine on the desk. A phone camera is a working out-of-band
|
||||
// channel that needs no drivers on our side at all. See docs/architecture/graphics.md.
|
||||
//
|
||||
// Deliberately small, in three ways:
|
||||
// Deliberately small, in two ways:
|
||||
//
|
||||
// - Byte mode only. The report is arbitrary bytes; alphanumeric mode would
|
||||
// pack tighter but only for a restricted character set.
|
||||
// - Error correction level L only. The screen is a clean, evenly lit,
|
||||
// high-contrast source -- the failure mode QR's stronger levels protect
|
||||
// against (dirt, print damage, curved packaging) does not apply.
|
||||
// - Versions 1 to 6 only. Version 7 is where QR starts requiring an extra
|
||||
// 18-bit version-information block in two more places on the symbol, and
|
||||
// version 10 is where the character count field grows and the alignment
|
||||
// pattern grid becomes 2-dimensional. Stopping at 6 avoids both, and
|
||||
// 134 bytes is a large crash report.
|
||||
//
|
||||
// If a payload ever needs more than 134 bytes, the honest fix is to shorten the
|
||||
// report -- not to reach for version 10 and its two extra tables.
|
||||
// Every version, 1 to 40. It stopped at 6 -- 134 bytes, enough for the crash
|
||||
// card -- until PSOGM mode wanted the log itself off the machine, a page of it
|
||||
// per symbol: version 40 at level L carries 2,953 bytes. A struct qr is
|
||||
// therefore about 62 KB; keep one static, never on a stack.
|
||||
|
||||
#define QR_MAX_VERSION 6
|
||||
#define QR_MAX_SIZE (17 + 4 * QR_MAX_VERSION) // 41 modules per side
|
||||
#define QR_MAX_BYTES 134
|
||||
#define QR_MAX_VERSION 40
|
||||
#define QR_MAX_SIZE (17 + 4 * QR_MAX_VERSION) // 177 modules per side
|
||||
#define QR_MAX_BYTES 2953
|
||||
|
||||
// The crash card on the PSOGM stays small, so a phone reads it from across a
|
||||
// desk: a version-6 symbol at most.
|
||||
#define QR_CARD_BYTES 134
|
||||
|
||||
struct qr {
|
||||
int size; // modules per side; 0 if unencoded
|
||||
|
|
|
|||
|
|
@ -56,6 +56,14 @@ struct tssblk {
|
|||
|
||||
static struct tssblk tssblk[NCPU];
|
||||
|
||||
// The stack an NMI arrives on: IST slot 1, one per CPU. Without it an NMI runs
|
||||
// on whatever stack was live, and for a few instructions at the top of
|
||||
// syscall_entry that is the user's -- at ring 0, so the CPU would push the
|
||||
// trap frame there, and a fault on that push is a double fault on the same
|
||||
// stack. Panic stops the other processors with an NMI; it must not be the
|
||||
// thing that resets the machine instead of the report.
|
||||
static uint8 nmistack[NCPU][4096] __attribute__((aligned(16)));
|
||||
|
||||
// What each CPU currently has open. Kept per CPU rather than read back from the
|
||||
// process, because switching *away* has to close what was opened and the
|
||||
// process that opened it may be part-way through exit() by then.
|
||||
|
|
@ -89,6 +97,7 @@ ioperm_tss(int cpu, uint64 *limit)
|
|||
memset(b->map, 0xFF, sizeof(b->map));
|
||||
b->tail = 0xFF;
|
||||
b->ts.iomb = (uint16)__builtin_offsetof(struct tssblk, map);
|
||||
b->ts.ist[0] = (uint64)(nmistack[cpu] + sizeof(nmistack[cpu]));
|
||||
installed[cpu].n = 0;
|
||||
|
||||
// The limit is the offset of the last valid byte, and it has to include the
|
||||
|
|
|
|||
|
|
@ -402,6 +402,21 @@ cpunum(void)
|
|||
panic("unknown apicid\n");
|
||||
}
|
||||
|
||||
// An NMI to every processor but this one: how a panic stops the others. An
|
||||
// NMI is delivered with interrupts off too, so it reaches a processor spinning
|
||||
// on a lock with cli as surely as one running a program; trap() halts any that
|
||||
// takes one while panic_stop is set. Bounded, because the caller is dying.
|
||||
void
|
||||
lapic_nmi_others(void)
|
||||
{
|
||||
if (!lapic)
|
||||
return;
|
||||
lapicw(ICRHI, 0);
|
||||
lapicw(ICRLO, 0x000C0000 | 0x00000400 | ASSERT); // all but self, NMI
|
||||
for (int i = 0; i < 100000 && (lapic[ICRLO] & DELIVS); i++)
|
||||
microdelay(1);
|
||||
}
|
||||
|
||||
// Acknowledge interrupt.
|
||||
void
|
||||
lapiceoi(void)
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ void tvinit(void)
|
|||
for (n = 0; n < 256; n++)
|
||||
mkgate(idt, n, vectors[n], 0);
|
||||
mkgate(idt, T_SYSCALL, vectors[T_SYSCALL], 3);
|
||||
// NMI on its own stack, IST slot 1; see nmistack in ioperm.c.
|
||||
idt[T_NMI * 4 + 1] |= 1;
|
||||
}
|
||||
|
||||
uint
|
||||
|
|
@ -81,6 +83,17 @@ trapsig(uint64 trapno)
|
|||
void
|
||||
trap(struct trapframe *tf)
|
||||
{
|
||||
// Another processor has panicked and wants this one stopped: a processor
|
||||
// left running carries on with a kernel that is already dead, and on a
|
||||
// laptop that showed as the report flashing up and being drawn over, and
|
||||
// as fans that stayed loud until somebody held the power button. First, and
|
||||
// before the canary check, because this stack may be what is broken.
|
||||
if(tf->trapno == T_NMI && panic_stop)
|
||||
for(;;){
|
||||
cli();
|
||||
hlt();
|
||||
}
|
||||
|
||||
kstack_check_canary("trap entry");
|
||||
switch(tf->trapno){
|
||||
case T_IRQ0 + IRQ_TIMER:
|
||||
|
|
|
|||
|
|
@ -326,7 +326,7 @@ text_at(int x, int y, const char *s, uint32 color)
|
|||
static int
|
||||
draw_qr_panel(int sw, int sh, int ch, char *reason, addr_t *pcs, int npcs)
|
||||
{
|
||||
char payload[QR_MAX_BYTES];
|
||||
char payload[QR_CARD_BYTES];
|
||||
int n = build_qr_payload(payload, sizeof(payload), reason, pcs, npcs);
|
||||
|
||||
if (n <= 0 || qr_encode(&panic_qr, (unsigned char *)payload, n) != 0)
|
||||
|
|
@ -559,6 +559,9 @@ report_serial(char *reason, addr_t *pcs, int npcs)
|
|||
|
||||
static void panic_blink(void) __attribute__((noreturn));
|
||||
|
||||
volatile int panic_stop;
|
||||
static volatile int panic_owner = -1;
|
||||
|
||||
__attribute__((noreturn))
|
||||
void
|
||||
panic(char *s)
|
||||
|
|
@ -566,6 +569,21 @@ panic(char *s)
|
|||
addr_t pcs[10];
|
||||
|
||||
cli();
|
||||
|
||||
// One processor reports; any other that panics meanwhile -- the same broken
|
||||
// state tends to reach several at once -- stops where it is. The owner may
|
||||
// panic again while drawing, and that nested report is let through.
|
||||
int me = cpunum();
|
||||
int owner = __sync_val_compare_and_swap(&panic_owner, -1, me);
|
||||
if (owner != -1 && owner != me)
|
||||
for (;;) {
|
||||
cli();
|
||||
hlt();
|
||||
}
|
||||
// And the rest are stopped outright, see trap().
|
||||
panic_stop = 1;
|
||||
lapic_nmi_others();
|
||||
|
||||
// Stop every other path from writing to the console. consputc checks this
|
||||
// and spins, which is what keeps another CPU from painting over the report
|
||||
// while it is being drawn.
|
||||
|
|
|
|||
158
kernel/core/qr.c
158
kernel/core/qr.c
|
|
@ -2,8 +2,8 @@
|
|||
//
|
||||
// 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.
|
||||
// what is broken. Every buffer here is on the caller's struct, a bounded
|
||||
// local, or static.
|
||||
//
|
||||
// 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:
|
||||
|
|
@ -40,42 +40,66 @@
|
|||
// 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 },
|
||||
// Error correction level L, every version. Two numbers per version are
|
||||
// transcribed from ISO/IEC 18004 table 9 -- EC codewords per block, and how
|
||||
// many blocks -- and everything else is computed: the symbol's total codeword
|
||||
// count from its geometry, and the block lengths from the total. Above
|
||||
// version 5 the blocks are not all one length; the first ones are a codeword
|
||||
// shorter, and interleaving has to step around the gap.
|
||||
static const unsigned char ecc_per_block[QR_MAX_VERSION + 1] = {
|
||||
0, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28,
|
||||
28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
|
||||
30,
|
||||
};
|
||||
static const unsigned char ecc_blocks[QR_MAX_VERSION + 1] = {
|
||||
0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7,
|
||||
8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24,
|
||||
25,
|
||||
};
|
||||
|
||||
// Modules left for data once every function pattern is drawn: the whole
|
||||
// square, less finders and separators (192), timing (2 * (n - 16)), format
|
||||
// (31), alignment patterns and, from version 7, the two version blocks (36).
|
||||
static int
|
||||
raw_modules(int v)
|
||||
{
|
||||
int r = (16 * v + 128) * v + 64;
|
||||
if (v >= 2) {
|
||||
int na = v / 7 + 2;
|
||||
r -= (25 * na - 10) * na - 55;
|
||||
if (v >= 7)
|
||||
r -= 36;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int
|
||||
total_codewords(int v)
|
||||
{
|
||||
return raw_modules(v) / 8;
|
||||
}
|
||||
|
||||
static int
|
||||
data_codewords(int v)
|
||||
{
|
||||
return total_codewords(v) - ecc_per_block[v] * ecc_blocks[v];
|
||||
}
|
||||
|
||||
// Byte mode's character count is 8 bits up to version 9 and 16 from 10.
|
||||
static int
|
||||
count_bits(int v)
|
||||
{
|
||||
return v <= 9 ? 8 : 16;
|
||||
}
|
||||
|
||||
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;
|
||||
return (data_codewords(version) * 8 - 4 - count_bits(version)) / 8;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 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)
|
||||
{
|
||||
|
|
@ -231,11 +255,37 @@ draw_function_patterns(struct qr *q)
|
|||
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);
|
||||
// Alignment patterns on a grid: the same list of centres on both axes,
|
||||
// every combination drawn except the three that would sit on a finder. The
|
||||
// list starts at 6, ends at n-7, and steps evenly (in even numbers) between,
|
||||
// except version 32, which the standard spaces by hand.
|
||||
int v = (n - 17) / 4;
|
||||
if (v >= 2) {
|
||||
int na = v / 7 + 2, pos[7];
|
||||
int step = v == 32 ? 26 : (v * 4 + na * 2 + 1) / (na * 2 - 2) * 2;
|
||||
pos[0] = 6;
|
||||
for (int i = na - 1, p = n - 7; i >= 1; i--, p -= step)
|
||||
pos[i] = p;
|
||||
for (int i = 0; i < na; i++)
|
||||
for (int j = 0; j < na; j++)
|
||||
if (!((i == 0 && j == 0) || (i == 0 && j == na - 1) ||
|
||||
(i == na - 1 && j == 0)))
|
||||
draw_alignment(q, pos[i], pos[j]);
|
||||
}
|
||||
|
||||
// From version 7 the version number is written out too, 6 bits and a
|
||||
// BCH(18,6) check, in a 3x6 block beside each of the two far finders.
|
||||
if (v >= 7) {
|
||||
int rem = v;
|
||||
for (int i = 0; i < 12; i++)
|
||||
rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
|
||||
long bits = ((long)v << 12) | rem;
|
||||
for (int i = 0; i < 18; i++) {
|
||||
int bit = (bits >> i) & 1, a = n - 11 + i % 3, b = i / 3;
|
||||
set_fn(q, a, b, bit);
|
||||
set_fn(q, b, a, bit);
|
||||
}
|
||||
}
|
||||
|
||||
draw_format(q, 0); // reserve; overwritten once a mask is chosen
|
||||
}
|
||||
|
|
@ -357,25 +407,24 @@ qr_encode(struct qr *q, const unsigned char *data, int len)
|
|||
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;
|
||||
int blocks = ecc_blocks[v];
|
||||
int ecclen = ecc_per_block[v];
|
||||
int total = total_codewords(v);
|
||||
int datacw = data_codewords(v);
|
||||
int nshort = blocks - total % blocks; // blocks one data codeword short
|
||||
int shortlen = total / blocks - ecclen; // their data length
|
||||
|
||||
// --- 1. payload -> data codewords ---------------------------------------
|
||||
unsigned char cw[172]; // >= max total codewords
|
||||
//
|
||||
// Static, not on the stack: version 40 is 3,706 codewords, and this runs on
|
||||
// whatever stack a panic left. Not reentrant, which nothing here needs.
|
||||
static unsigned char cw[3706], out[3706];
|
||||
static unsigned char ec[25][30];
|
||||
memset(cw, 0, sizeof(cw));
|
||||
|
||||
int pos = 0;
|
||||
put_bits(cw, &pos, 0x4, 4); // byte mode
|
||||
put_bits(cw, &pos, (unsigned)len, 8);
|
||||
put_bits(cw, &pos, (unsigned)len, count_bits(v));
|
||||
for (int i = 0; i < len; i++)
|
||||
put_bits(cw, &pos, data[i], 8);
|
||||
|
||||
|
|
@ -393,20 +442,25 @@ qr_encode(struct qr *q, const unsigned char *data, int len)
|
|||
cw[i] = (i - pos / 8) % 2 == 0 ? 0xEC : 0x11;
|
||||
|
||||
// --- 2 and 3. error correction, then interleave -------------------------
|
||||
//
|
||||
// Block b starts at start(b): the short blocks first, then the long ones.
|
||||
unsigned char gen[30];
|
||||
unsigned char ec[4][30];
|
||||
rs_divisor(ecclen, gen);
|
||||
#define BSTART(b) ((b) * shortlen + ((b) > nshort ? (b) - nshort : 0))
|
||||
#define BLEN(b) (shortlen + ((b) >= nshort))
|
||||
for (int b = 0; b < blocks; b++)
|
||||
rs_remainder(&cw[b * blocklen], blocklen, gen, ecclen, ec[b]);
|
||||
rs_remainder(&cw[BSTART(b)], BLEN(b), gen, ecclen, ec[b]);
|
||||
|
||||
unsigned char out[172];
|
||||
int o = 0;
|
||||
for (int i = 0; i < blocklen; i++)
|
||||
for (int i = 0; i <= shortlen; i++)
|
||||
for (int b = 0; b < blocks; b++)
|
||||
out[o++] = cw[b * blocklen + i];
|
||||
if (i < BLEN(b))
|
||||
out[o++] = cw[BSTART(b) + i];
|
||||
for (int i = 0; i < ecclen; i++)
|
||||
for (int b = 0; b < blocks; b++)
|
||||
out[o++] = ec[b][i];
|
||||
#undef BSTART
|
||||
#undef BLEN
|
||||
|
||||
// --- 4. function patterns ------------------------------------------------
|
||||
memset(q, 0, sizeof(*q));
|
||||
|
|
|
|||
|
|
@ -117,10 +117,15 @@ def decode(m):
|
|||
return ""
|
||||
|
||||
|
||||
# Byte capacity per version: total - ecc*blocks - 2. Mirrors the table in qr.c;
|
||||
# the exact-fill cases below are built from it, and a disagreement would show up
|
||||
# Byte-mode capacity per version at level L, from ISO/IEC 18004 table 7 --
|
||||
# written out rather than computed, so it checks qr.c instead of agreeing with
|
||||
# it. The exact-fill cases below are built from it, and a disagreement shows up
|
||||
# as a version mismatch rather than passing quietly.
|
||||
CAPACITY = {1: 17, 2: 32, 3: 53, 4: 78, 5: 106, 6: 134}
|
||||
CAPACITY = dict(enumerate([
|
||||
17, 32, 53, 78, 106, 134, 154, 192, 230, 271, 321, 367, 425, 458, 520,
|
||||
586, 644, 718, 792, 858, 929, 1003, 1091, 1171, 1273, 1367, 1465, 1528,
|
||||
1628, 1732, 1840, 1952, 2068, 2188, 2303, 2431, 2563, 2699, 2809, 2953,
|
||||
], start=1))
|
||||
|
||||
alpha = lambda n: "".join(chr(65 + i % 26) for i in range(n))
|
||||
|
||||
|
|
@ -133,8 +138,9 @@ CASES = [
|
|||
bytes(range(1, 40)).decode("latin-1"), # non-printable payload
|
||||
]
|
||||
# One payload that exactly fills each version, and one just under, so both the
|
||||
# padded and unpadded paths are covered at every version -- including 6, which
|
||||
# is the only one with more than one Reed-Solomon block.
|
||||
# padded and unpadded paths are covered at every version: several Reed-Solomon
|
||||
# blocks from 6, blocks of two lengths from 6 too, the version information
|
||||
# from 7, the 16-bit character count from 10.
|
||||
for v, cap in CAPACITY.items():
|
||||
CASES.append(alpha(cap))
|
||||
CASES.append(alpha(cap - 1))
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue