use anyhow::bail;
use quick_xml::events::Event;
use std::io::Read;
use crate::{
excel::XmlReader,
helper::{extract_val_attribute, string_to_bool, string_to_float, string_to_unsignedint},
};
use super::color::XlsxColor;
pub type XlsxFonts = Vec<XlsxFont>;
pub(crate) fn load_fonts(reader: &mut XmlReader<impl Read>) -> anyhow::Result<XlsxFonts> {
let mut buf = Vec::new();
let mut fonts: Vec<XlsxFont> = vec![];
loop {
buf.clear();
match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"font" => {
let font = XlsxFont::load(reader)?;
fonts.push(font);
}
Ok(Event::End(ref e)) if e.local_name().as_ref() == b"fonts" => break,
Ok(Event::Eof) => bail!("unexpected end of file."),
Err(e) => bail!(e.to_string()),
_ => (),
}
}
Ok(fonts)
}
#[derive(Debug, Clone, PartialEq)]
pub struct XlsxFont {
pub bold: Option<bool>,
pub charset: Option<String>,
pub color: Option<XlsxColor>,
pub condense: Option<bool>,
pub extend: Option<bool>,
pub family: Option<u64>,
pub italic: Option<bool>,
pub name: Option<String>,
pub outline: Option<bool>,
pub scheme: Option<String>,
pub shadow: Option<bool>,
pub strike: Option<bool>,
pub size: Option<f64>,
pub underline: Option<String>,
pub vert_align: Option<String>,
}
impl XlsxFont {
pub(crate) fn load(reader: &mut XmlReader<impl Read>) -> anyhow::Result<Self> {
let mut buf = Vec::new();
let mut font = Self {
bold: None,
charset: None,
color: None,
condense: None,
extend: None,
family: None,
italic: None,
name: None,
outline: None,
scheme: None,
shadow: None,
strike: None,
size: None,
underline: None,
vert_align: None,
};
loop {
buf.clear();
match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"b" => {
let val_string = extract_val_attribute(e)?.unwrap_or("1".to_owned());
font.bold = string_to_bool(&val_string);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"charset" => {
font.charset = extract_val_attribute(e)?;
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"color" => {
font.color = Some(XlsxColor::load(e)?);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"condense" => {
let val_string = extract_val_attribute(e)?.unwrap_or("1".to_owned());
font.condense = string_to_bool(&val_string);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"extend" => {
let val_string = extract_val_attribute(e)?.unwrap_or("1".to_owned());
font.extend = string_to_bool(&val_string);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"family" => {
let Some(val_string) = extract_val_attribute(e)? else {
continue;
};
font.family = string_to_unsignedint(&val_string);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"i" => {
let val_string = extract_val_attribute(e)?.unwrap_or("1".to_owned());
font.italic = string_to_bool(&val_string);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"name" => {
font.name = extract_val_attribute(e)?;
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"outline" => {
let val_string = extract_val_attribute(e)?.unwrap_or("1".to_owned());
font.outline = string_to_bool(&val_string);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"scheme" => {
font.scheme = extract_val_attribute(e)?;
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"shadow" => {
let val_string = extract_val_attribute(e)?.unwrap_or("1".to_owned());
font.shadow = string_to_bool(&val_string);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"strike" => {
let val_string = extract_val_attribute(e)?.unwrap_or("1".to_owned());
font.strike = string_to_bool(&val_string);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"sz" => {
let Some(val_string) = extract_val_attribute(e)? else {
continue;
};
font.size = string_to_float(&val_string);
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"u" => {
font.underline = extract_val_attribute(e)?;
}
Ok(Event::Start(ref e)) if e.local_name().as_ref() == b"vertAlign" => {
font.vert_align = extract_val_attribute(e)?;
}
Ok(Event::End(ref e)) if e.local_name().as_ref() == b"font" => break,
Ok(Event::Eof) => bail!("unexpected end of file."),
Err(e) => bail!(e.to_string()),
_ => (),
}
}
Ok(font)
}
}