use std::{
collections::HashMap,
fmt::{Debug, Display, Write},
+ io::Read,
iter::{once, repeat},
ops::{Index, IndexMut, Not, Range, RangeInclusive},
- str::{from_utf8, FromStr},
+ str::{from_utf8, FromStr, Utf8Error},
sync::{Arc, OnceLock, Weak},
};
+use binrw::Error as BinError;
use chrono::NaiveDateTime;
pub use color::ParseError as ParseColorError;
use color::{palette::css::TRANSPARENT, AlphaColor, Rgba8, Srgb};
use serde::{de::Visitor, Deserialize};
use smallstr::SmallString;
use smallvec::{smallvec, SmallVec};
+use thiserror::Error as ThisError;
+use tlo::parse_tlo;
use crate::{
dictionary::Value as DataValue,
}
}
+#[derive(ThisError, Debug)]
+pub enum ParseLookError {
+ #[error("{0}")]
+ XmlError(#[from] DeError),
+
+ #[error("{0}")]
+ Utf8Error(#[from] Utf8Error),
+
+ #[error("{0}")]
+ BinError(#[from] BinError),
+
+ #[error("{0}")]
+ IoError(#[from] std::io::Error),
+}
+
impl Look {
- fn shared_default() -> Arc<Look> {
+ pub fn shared_default() -> Arc<Look> {
static LOOK: OnceLock<Arc<Look>> = OnceLock::new();
LOOK.get_or_init(|| Arc::new(Look::default())).clone()
}
- fn from_xml(xml: &str) -> Result<Self, DeError> {
- Ok(from_str::<TableProperties>(xml)?.into())
+ pub fn from_xml(xml: &str) -> Result<Self, ParseLookError> {
+ Ok(from_str::<TableProperties>(xml)
+ .map_err(ParseLookError::from)?
+ .into())
+ }
+
+ pub fn from_binary(tlo: &[u8]) -> Result<Self, ParseLookError> {
+ parse_tlo(tlo).map_err(ParseLookError::from)
+ }
+
+ pub fn from_data(data: &[u8]) -> Result<Self, ParseLookError> {
+ if data.starts_with(b"\xff\xff\0\0") {
+ Self::from_binary(data)
+ } else {
+ Self::from_xml(from_utf8(data).map_err(ParseLookError::from)?)
+ }
+ }
+
+ pub fn from_reader<R>(mut reader: R) -> Result<Self, ParseLookError>
+ where
+ R: Read,
+ {
+ let mut buffer = Vec::new();
+ reader
+ .read_to_end(&mut buffer)
+ .map_err(ParseLookError::from)?;
+ Self::from_data(&buffer)
}
}
-use std::fmt::Debug;
+use std::{fmt::Debug, io::Cursor};
use crate::output::pivot::{
Axis2, Border, BoxBorder, FootnoteMarkerPosition, FootnoteMarkerType, HeadingRegion,
v2_styles: V2Styles,
}
+pub fn parse_tlo(input: &[u8]) -> BinResult<Look> {
+ let mut cursor = Cursor::new(input);
+ let tlo = TableLook::read(&mut cursor)?;
+ match input.len() as u64 - cursor.position() {
+ 0 => Ok(tlo.into()),
+ extra => Err(BinError::AssertFail {
+ pos: cursor.position(),
+ message: format!("unexpected {extra} bytes following TLO data"),
+ }),
+ }
+}
+
/// Points (72/inch) to pixels (96/inch).
fn pt_to_px(pt: i32) -> usize {
num::cast((pt as f64 * (96.0 / 72.0)).round()).unwrap_or_default()
#[cfg(test)]
mod test {
- use std::io::Cursor;
-
- use binrw::BinRead;
-
- use crate::output::pivot::{tlo::TableLook, Look};
+ use crate::output::pivot::tlo::parse_tlo;
#[test]
fn parse() {
- let bytes = include_bytes!("test1.tlo");
- let tlo = TableLook::read(&mut Cursor::new(bytes)).unwrap();
- println!("{tlo:#?}");
- let look = Look::from(tlo);
+ let look = parse_tlo(include_bytes!("test1.tlo"));
println!("{look:#?}");
}
}