From: Ian Jackson Date: Mon, 2 May 2022 09:56:57 +0000 (+0100) Subject: svg size handling: Introduce new size parser X-Git-Tag: otter-1.1.0~318 X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=commitdiff_plain;h=f80342862917f9b366a958debd0f8ea22c479c7e;p=otter.git svg size handling: Introduce new size parser We want to get the size out of the svg on load, to make the library spec size attribute optional (and to make things less confusing). So start by add code to parse size out of an SVG. But in fact it turns out we have one of these in bundle processing already. The need to be combined. But for now, commit what we have. Signed-off-by: Ian Jackson --- diff --git a/src/shapelib.rs b/src/shapelib.rs index 5a0c4711..9d555418 100644 --- a/src/shapelib.rs +++ b/src/shapelib.rs @@ -520,6 +520,15 @@ impl ItemSpec { } } +#[derive(Error,Clone,Serialize,Deserialize,Debug)] +pub enum SVGSizeError { + #[error("parse error: {0}")] ParseError(String), + #[error("attribute {0} repeated")] AttributeRepeated(String), + #[error("attribute {0} unparseable")] AttributeUnparseable(String), + #[error("specifies only one of width and height")] OneOfWidthHeight, +} +use SVGSizeError as SvSE; + impl Contents { #[throws(SpecError)] fn load_svg(&self, item_name: &SvgBaseName, @@ -538,6 +547,47 @@ impl Contents { SpE::InternalError(m.to_string()) })?; + #[throws(SVGSizeError)] + fn get_width_height(xml: &str) -> Option> { + use xmlparser::Token as Tk; + let mut in_svg_element = false; + let mut wh = [None; 2]; + for token in xmlparser::Tokenizer::from(xml) { + match token.map_err(|e| SvSE::ParseError(e.to_string()))? { + Tk::ElementStart{ local, .. } => { + in_svg_element = local.eq_ignore_ascii_case("svg"); + }, + Tk::ElementEnd{..} => { + if in_svg_element { return None } + }, + Tk::Attribute { local, value, .. } if in_svg_element => { + let i = + if local.eq_ignore_ascii_case("width" ) { 0 } else + if local.eq_ignore_ascii_case("height") { 1 } else { continue }; + if wh[i].is_some() { + throw!(SvSE::AttributeRepeated(local.to_string())) + } + let v: f64 = value.parse().map_err( + |_| SvSE::AttributeUnparseable(local.to_string()) + )?; + wh[i] = Some(v); + if wh.iter().all(Option::is_some) { break } + }, + _ => { }, + } + } + Some(PosC::try_from_iter_2( + wh.into_iter().map(|v| v.ok_or_else(|| SvSE::OneOfWidthHeight)) + )?) + } + + let _ = get_width_height(&svg_data).map_err(|error| SpE::SVGError { + error, + item_name: item_name.as_str().into(), + item_for_lib: lib_name_for.into(), + item_for_item: item_for.into(), + })?; + Html::from_html_string(svg_data) } diff --git a/src/spec.rs b/src/spec.rs index 73df6f59..f79f8efd 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -92,6 +92,12 @@ pub enum SpecError { CurrencyQtyNotMultipleOfUnit, #[error("coordinate overflow")] CoordinateOverflow(#[from] CoordinateOverflow), + #[error("SVG handling error: {item_name} for {item_for_lib} {item_for_item} {error}")] SVGError { + item_name: String, + item_for_lib: String, + item_for_item: String, + error: crate::shapelib::SVGSizeError, // TODO it needs to move + }, #[error("image for supposedly-occultable piece \ is not itself occultable but has multiple faces")] UnoccultableButRichImageForOccultation,