# 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 }