1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
# Whether a message's bytes are one JSON text (RFC 8259), read once from the start with a stack of the arrays and
# objects open. Input that is not UTF-8 fails as encoding: it is no JSON text either.
state valid = false
input check = message { data: bytes }
fn space(b) = b == 0x20 || b == 0x09 || b == 0x0a || b == 0x0d
fn digit(b) = b >= 0x30 && b <= 0x39
fn hex(b) = digit(b) || (b >= 0x61 && b <= 0x66) || (b >= 0x41 && b <= 0x46)
on check {
let t = text(check.data)
let d = bytes(t)
let n, i, mode, ok = d.bytes, 0, 0, true # mode 0: a value, 1: after one, 2: a key, 3: a key or }, 4: a value or ]
let open: list of i64
while ok {
while i < n && space(d[i]) { i = i + 1 }
if i == n {
ok = mode == 1 && open.count == 0
break
}
let b = d[i]
if mode == 1 {
if open.count == 0 { ok = false }
else if b == 0x2c { mode = if open.last == 0x5b { 0 } else { 2 } }
else if b == open.last + 2 { open.remove(open.count - 1) }
else { ok = false }
i = i + 1
} else if mode == 3 && b == 0x7d || mode == 4 && b == 0x5d {
open.remove(open.count - 1)
mode = 1
i = i + 1
} else if mode == 2 || mode == 3 {
if b != 0x22 { ok = false }
mode = 5 # the key, then ':'
} else if b == 0x5b || b == 0x7b {
open.append(b)
mode = if b == 0x5b { 4 } else { 3 }
i = i + 1
} else if b == 0x22 || mode == 5 {
i = i + 1 # a string: no control bytes, escapes as RFC 8259 writes them
while i < n && d[i] != 0x22 && ok {
if d[i] < 0x20 { ok = false }
else if d[i] == 0x5c && i + 1 < n && d[i + 1] == 0x75 {
ok = i + 5 < n && hex(d[i + 2]) && hex(d[i + 3]) && hex(d[i + 4]) && hex(d[i + 5])
i = i + 6
} else if d[i] == 0x5c {
ok = i + 1 < n && (d[i + 1] == 0x22 || d[i + 1] == 0x5c || d[i + 1] == 0x2f || d[i + 1] == 0x62 ||
d[i + 1] == 0x66 || d[i + 1] == 0x6e || d[i + 1] == 0x72 || d[i + 1] == 0x74)
i = i + 2
} else { i = i + 1 }
}
ok = ok && i < n
i = i + 1
if mode == 5 {
while i < n && space(d[i]) { i = i + 1 }
ok = ok && i < n && d[i] == 0x3a
i = i + 1
mode = 0
} else { mode = 1 }
} else if b == 0x2d || digit(b) { # -?(0|[1-9]\d*)(\.\d+)?([eE][+-]?\d+)?
if b == 0x2d { i = i + 1 }
ok = i < n && digit(d[i])
if ok && d[i] == 0x30 { i = i + 1 } else { while i < n && digit(d[i]) { i = i + 1 } }
if ok && i < n && d[i] == 0x2e {
i = i + 1
ok = i < n && digit(d[i])
while i < n && digit(d[i]) { i = i + 1 }
}
if ok && i < n && (d[i] == 0x65 || d[i] == 0x45) {
i = i + 1
if i < n && (d[i] == 0x2b || d[i] == 0x2d) { i = i + 1 }
ok = i < n && digit(d[i])
while i < n && digit(d[i]) { i = i + 1 }
}
mode = 1
} else {
let word = if b == 0x74 { "true" } else if b == 0x66 { "false" } else { "null" }
ok = i + word.bytes <= n && t[i .. i + word.bytes] == word
i = i + word.bytes
mode = 1
}
}
valid = ok
}
|