// Static dictionary references (RFC 7932 section 8) and literal context
// modes (section 7.1).
///|
const NUM_TRANSFORMS : Int32 = 121
///|
/// The longest transformed word: a 24-byte word plus 13 added bytes.
const MAX_TRANSFORMED_WORD : Int32 = 37
///|
/// Writes word `index` of length `length` under transform `transform` into
/// `out`, and returns how many bytes it wrote.
fn transform_word(
out : FixedArray[Byte],
length : Int32,
index : Int32,
transform : Int32,
) -> Int32 {
let prefix = transform_prefixes[transform]
let kind = transform_types[transform].to_int()
let suffix = transform_suffixes[transform]
out.blit_from_bytesview(0, prefix)
let mut n = prefix.length()
let mut start = dictionary_offsets[length] + index * length
let mut word_length = length
if kind >= 1 && kind <= 9 {
word_length = (length - kind).max(0)
} else if kind >= 12 {
let skip = kind - 11
start += skip
word_length = (length - skip).max(0)
}
out.blit_from_bytesview(n, dictionary[start:start + word_length])
if kind == 10 {
ferment(out, n, word_length, 0) |> ignore
} else if kind == 11 {
for i = 0; i < word_length; {
continue i + ferment(out, n, word_length, i)
}
}
n += word_length
out.blit_from_bytesview(n, suffix)
n + suffix.length()
}
///|
/// RFC 7932's `Ferment`: uppercases the character at `pos` of the word at
/// `out[start:start + length]` and returns its length in bytes.
fn ferment(
out : FixedArray[Byte],
start : Int32,
length : Int32,
pos : Int32,
) -> Int32 {
let c = out[start + pos]
if c < 192 {
if c >= 97 && c <= 122 {
out[start + pos] = c ^ 32
}
1
} else if c < 224 {
if pos + 1 < length {
out[start + pos + 1] = out[start + pos + 1] ^ 32
}
2
} else {
if pos + 2 < length {
out[start + pos + 2] = out[start + pos + 2] ^ 5
}
3
}
}
///|
/// The literal context ID of `mode` for the last two bytes `p1` and `p2`.
fn literal_context(mode : Int32, p1 : Int32, p2 : Int32) -> Int32 {
match mode {
0 => p1 & 0x3f
1 => p1 >> 2
2 => lut0[p1].to_int() | lut1[p2].to_int()
_ => (lut2[p1].to_int() << 3) | lut2[p2].to_int()
}
}