use crate::{
block_read::{read_exact, BlockRead},
error::{Error, Result},
vbr::Geometry,
};
pub(crate) struct Upcase {
mapping: [u16; 128],
}
impl Upcase {
pub(crate) fn ascii() -> Self {
let mut mapping = [0u16; 128];
for (i, slot) in mapping.iter_mut().enumerate() {
let c = i as u16;
*slot = if (0x61..=0x7a).contains(&c) {
c - 0x20
} else {
c
};
}
Self { mapping }
}
pub(crate) fn load<R: BlockRead>(
&mut self,
reader: &mut R,
geo: &Geometry,
first_cluster: u32,
) -> Result<()> {
let base = geo
.cluster_byte(first_cluster)
.ok_or(Error::BadUpcaseTable)?;
let mut b = [0u8; 256];
read_exact(reader, base, &mut b, "io_upcase")?;
for (i, slot) in self.mapping.iter_mut().enumerate() {
*slot = u16::from_le_bytes([b[i * 2], b[i * 2 + 1]]);
}
Ok(())
}
pub(crate) fn up(&self, c: u16) -> u16 {
match self.mapping.get(usize::from(c)) {
Some(&m) => m,
None => c,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ascii_table_upcases_lowercase_only() {
let up = Upcase::ascii();
assert_eq!(up.up(u16::from(b'a')), u16::from(b'A'));
assert_eq!(up.up(u16::from(b'z')), u16::from(b'Z'));
assert_eq!(up.up(u16::from(b'A')), u16::from(b'A')); assert_eq!(up.up(u16::from(b'5')), u16::from(b'5')); assert_eq!(up.up(u16::from(b'_')), u16::from(b'_')); }
#[test]
fn codepoints_outside_the_table_map_to_themselves() {
let up = Upcase::ascii();
assert_eq!(up.up(200), 200); assert_eq!(up.up(0x00E9), 0x00E9); assert_eq!(up.up(0xFFFF), 0xFFFF);
}
}