|
|
|
@ -1,34 +1,81 @@
|
|
|
|
|
/// 5 bits
|
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
|
struct ZChar(u8);
|
|
|
|
|
struct ZsciiChar(u8);
|
|
|
|
|
|
|
|
|
|
struct ZsciiString(Vec<ZsciiChar>);
|
|
|
|
|
/// technically 10 bits, but top two unused so they are dropped
|
|
|
|
|
#[derive(PartialEq, Clone, Copy)]
|
|
|
|
|
pub struct ZsciiChar(u8);
|
|
|
|
|
|
|
|
|
|
pub type ZsciiString = Vec<ZsciiChar>;
|
|
|
|
|
|
|
|
|
|
/// Returns:
|
|
|
|
|
/// - a result that wraps a ZsciiString, erroring if the slice terminates before the string ends
|
|
|
|
|
/// - a usize indicating how many bytes were consumed
|
|
|
|
|
|
|
|
|
|
pub fn decode_zchars(zchars: &[u8]) -> Option<(ZsciiString, usize)> {
|
|
|
|
|
pub fn decode_zchars(
|
|
|
|
|
zchars: &[u8],
|
|
|
|
|
alphabet_table: Option<&[u8]>,
|
|
|
|
|
abbreviations_table: &[u8],
|
|
|
|
|
) -> Option<(ZsciiString, usize)> {
|
|
|
|
|
fn cut_string(zchars: &[u8]) -> Option<Vec<u16>> {
|
|
|
|
|
for (i, word) in zchars.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).enumerate() {
|
|
|
|
|
let mut out = Vec::new();
|
|
|
|
|
for word in zchars.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])) {
|
|
|
|
|
out.push(word);
|
|
|
|
|
if 0x8000 & word != 0 {
|
|
|
|
|
return Some(out);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// requires: alphabet_num < 3, 5 < char_idx < 32, !(alphabet_num = 2 AND char_idx = 6)
|
|
|
|
|
fn index_alphabet(
|
|
|
|
|
alphabet_table: Option<&[u8]>,
|
|
|
|
|
alphabet_number: usize,
|
|
|
|
|
ZChar(char_idx): ZChar,
|
|
|
|
|
zchars: &mut impl Iterator<Item = ZChar>,
|
|
|
|
|
) -> Option<ZsciiChar> {
|
|
|
|
|
let default_alphabet: [[ZsciiChar; 26]; 3] = [
|
|
|
|
|
b"abcdefghijklmnopqrstuvwxyz".map(ZsciiChar),
|
|
|
|
|
b"ABCDEFGHIJKLMNOPQRSTUVWXYZ".map(ZsciiChar),
|
|
|
|
|
br#" 0123456789.,!?_#'"/\-:()"#.map(ZsciiChar)
|
|
|
|
|
];
|
|
|
|
|
if alphabet_number == 2 && char_idx == 7 {
|
|
|
|
|
Some(ZsciiChar(13))
|
|
|
|
|
} else if alphabet_number == 2 && char_idx == 6 {
|
|
|
|
|
todo!()
|
|
|
|
|
} else if let Some(alphabet_table) = alphabet_table {
|
|
|
|
|
todo!()
|
|
|
|
|
} else {
|
|
|
|
|
Some(default_alphabet[alphabet_number][char_idx as usize - 6])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let zwords = cut_string(zchars)?;
|
|
|
|
|
let consumed_length = zwords.len() * 2;
|
|
|
|
|
let mut zchars = zwords.iter()
|
|
|
|
|
.flat_map(|word| [
|
|
|
|
|
(word >> 10) & 0x1f,
|
|
|
|
|
(word >> 5) & 0x1f,
|
|
|
|
|
word & 0x1f
|
|
|
|
|
])
|
|
|
|
|
.map(|word| ZChar(word as u8))
|
|
|
|
|
.peekable();
|
|
|
|
|
|
|
|
|
|
let mut out = Vec::new();
|
|
|
|
|
let mut current_alphabet = 0;
|
|
|
|
|
while let Some(char) = zchars.next() {
|
|
|
|
|
match char {
|
|
|
|
|
ZChar(0) => out.push(ZsciiChar(32)),
|
|
|
|
|
ZChar(1..=3) => todo!("abbreviations"),
|
|
|
|
|
ZChar(4..=5) => if zchars.peek().is_some_and(|&ZChar(n)| n > 5) {
|
|
|
|
|
if let Some(zc) = index_alphabet(alphabet_table, char.0 as usize - 3, zchars.next().unwrap(), &mut zchars) { out.push(zc) }
|
|
|
|
|
},
|
|
|
|
|
ZChar(_) => if let Some(zc) = index_alphabet(alphabet_table, 0, char, &mut zchars) {
|
|
|
|
|
out.push(zc)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
let zchars = slice_string(zchars);
|
|
|
|
|
// let mut index: usize = 0;
|
|
|
|
|
// let mut out = Vec::new();
|
|
|
|
|
// loop {
|
|
|
|
|
// let word = u16::from_be_bytes([zchars[index], zchars[index + 1]]);
|
|
|
|
|
// let end_bit_set = word & 0x8000 != 0;
|
|
|
|
|
// let chars = [
|
|
|
|
|
// (word & (0b11111 << 10)) >> 10,
|
|
|
|
|
// (word & (0b11111 << 5)) >> 5,
|
|
|
|
|
// (word & (0b11111 << 0)) >> 0,
|
|
|
|
|
// ].map(|c| ZChar(c as u8));
|
|
|
|
|
// out.extend(chars);
|
|
|
|
|
// index += 2;
|
|
|
|
|
// if index >= zchars.len() - 1 { break (Err(out), index); }
|
|
|
|
|
// if end_bit_set { break (Ok(out), index); }
|
|
|
|
|
// // TODO: finish
|
|
|
|
|
// }
|
|
|
|
|
Some((out, consumed_length))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|