use crate::{DecodeError, Decoder, EncodeError, Encoder};
pub const KOI8R_NAME: &str = "KOI8-R";
pub struct KOI8REncoder;
impl Encoder for KOI8REncoder {
fn name(&self) -> &'static str {
KOI8R_NAME
}
fn encode(
&mut self,
src: &str,
dst: &mut [u8],
finish: bool,
) -> Result<(usize, usize), EncodeError> {
if src.is_empty() {
return if finish {
Ok((0, 0))
} else {
Err(EncodeError::InputIsEmpty)
};
}
if dst.len() < 2 {
return Err(EncodeError::OutputTooShort);
}
let (mut read, mut write) = (0, 0);
for c in src.chars() {
if c.is_ascii() {
read += 1;
dst[write] = c as u8;
write += 1;
} else {
read += c.len_utf8();
if let Ok(pos) = UCS_TO_KOI8R.binary_search_by_key(&(c as u32), |v| v.0 as u32) {
dst[write] = UCS_TO_KOI8R[pos].1;
write += 1;
} else {
return Err(EncodeError::Unmappable { read, write, c });
}
}
if dst.len() == write {
break;
}
}
Ok((read, write))
}
}
pub struct KOI8RDecoder;
impl Decoder for KOI8RDecoder {
fn name(&self) -> &'static str {
KOI8R_NAME
}
fn decode(
&mut self,
src: &[u8],
dst: &mut String,
finish: bool,
) -> Result<(usize, usize), DecodeError> {
if src.is_empty() {
return if finish {
Ok((0, 0))
} else {
Err(DecodeError::InputIsEmpty)
};
}
let mut len = dst.capacity() - dst.len();
if len < 4 {
return Err(DecodeError::OutputTooShort);
}
let (mut read, mut write) = (0, 0);
while read < src.len() && len > 0 {
read += 1;
let b = src[read];
if b < 0x80 {
dst.push(b as char);
write += 1;
len -= 1;
} else {
let b = b - 0x80;
let ucs_code = KOI8R_TO_UCS[b as usize];
let ucs = unsafe {
char::from_u32_unchecked(ucs_code as u32)
};
if len < ucs.len_utf8() {
read -= 1;
break;
}
len -= ucs.len_utf8();
write += ucs.len_utf8();
dst.push(ucs);
}
}
Ok((read, write))
}
}
const KOI8R_TO_UCS: [u16; 128] = [
0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, 0x252C, 0x2534, 0x253C, 0x2580,
0x2584, 0x2588, 0x258C, 0x2590, 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248,
0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, 0x2550, 0x2551, 0x2552, 0x0451,
0x2553, 0x2554, 0x2555, 0x2556, 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E,
0x255F, 0x2560, 0x2561, 0x0401, 0x2562, 0x2563, 0x2564, 0x2565, 0x2566, 0x2567, 0x2568, 0x2569,
0x256A, 0x256B, 0x256C, 0x00A9, 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433,
0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x044F, 0x0440, 0x0441,
0x0442, 0x0443, 0x0436, 0x0432, 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A,
0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, 0x0425, 0x0418, 0x0419, 0x041A,
0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412,
0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A,
];
const UCS_TO_KOI8R: [(u16, u8); 128] = [
(0x00A0, 0x9A),
(0x00A9, 0xBF),
(0x00B0, 0x9C),
(0x00B2, 0x9D),
(0x00B7, 0x9E),
(0x00F7, 0x9F),
(0x0401, 0xB3),
(0x0410, 0xE1),
(0x0411, 0xE2),
(0x0412, 0xF7),
(0x0413, 0xE7),
(0x0414, 0xE4),
(0x0415, 0xE5),
(0x0416, 0xF6),
(0x0417, 0xFA),
(0x0418, 0xE9),
(0x0419, 0xEA),
(0x041A, 0xEB),
(0x041B, 0xEC),
(0x041C, 0xED),
(0x041D, 0xEE),
(0x041E, 0xEF),
(0x041F, 0xF0),
(0x0420, 0xF2),
(0x0421, 0xF3),
(0x0422, 0xF4),
(0x0423, 0xF5),
(0x0424, 0xE6),
(0x0425, 0xE8),
(0x0426, 0xE3),
(0x0427, 0xFE),
(0x0428, 0xFB),
(0x0429, 0xFD),
(0x042A, 0xFF),
(0x042B, 0xF9),
(0x042C, 0xF8),
(0x042D, 0xFC),
(0x042E, 0xE0),
(0x042F, 0xF1),
(0x0430, 0xC1),
(0x0431, 0xC2),
(0x0432, 0xD7),
(0x0433, 0xC7),
(0x0434, 0xC4),
(0x0435, 0xC5),
(0x0436, 0xD6),
(0x0437, 0xDA),
(0x0438, 0xC9),
(0x0439, 0xCA),
(0x043A, 0xCB),
(0x043B, 0xCC),
(0x043C, 0xCD),
(0x043D, 0xCE),
(0x043E, 0xCF),
(0x043F, 0xD0),
(0x0440, 0xD2),
(0x0441, 0xD3),
(0x0442, 0xD4),
(0x0443, 0xD5),
(0x0444, 0xC6),
(0x0445, 0xC8),
(0x0446, 0xC3),
(0x0447, 0xDE),
(0x0448, 0xDB),
(0x0449, 0xDD),
(0x044A, 0xDF),
(0x044B, 0xD9),
(0x044C, 0xD8),
(0x044D, 0xDC),
(0x044E, 0xC0),
(0x044F, 0xD1),
(0x0451, 0xA3),
(0x2219, 0x95),
(0x221A, 0x96),
(0x2248, 0x97),
(0x2264, 0x98),
(0x2265, 0x99),
(0x2320, 0x93),
(0x2321, 0x9B),
(0x2500, 0x80),
(0x2502, 0x81),
(0x250C, 0x82),
(0x2510, 0x83),
(0x2514, 0x84),
(0x2518, 0x85),
(0x251C, 0x86),
(0x2524, 0x87),
(0x252C, 0x88),
(0x2534, 0x89),
(0x253C, 0x8A),
(0x2550, 0xA0),
(0x2551, 0xA1),
(0x2552, 0xA2),
(0x2553, 0xA4),
(0x2554, 0xA5),
(0x2555, 0xA6),
(0x2556, 0xA7),
(0x2557, 0xA8),
(0x2558, 0xA9),
(0x2559, 0xAA),
(0x255A, 0xAB),
(0x255B, 0xAC),
(0x255C, 0xAD),
(0x255D, 0xAE),
(0x255E, 0xAF),
(0x255F, 0xB0),
(0x2560, 0xB1),
(0x2561, 0xB2),
(0x2562, 0xB4),
(0x2563, 0xB5),
(0x2564, 0xB6),
(0x2565, 0xB7),
(0x2566, 0xB8),
(0x2567, 0xB9),
(0x2568, 0xBA),
(0x2569, 0xBB),
(0x256A, 0xBC),
(0x256B, 0xBD),
(0x256C, 0xBE),
(0x2580, 0x8B),
(0x2584, 0x8C),
(0x2588, 0x8D),
(0x258C, 0x8E),
(0x2590, 0x8F),
(0x2591, 0x90),
(0x2592, 0x91),
(0x2593, 0x92),
(0x25A0, 0x94),
];