Skip to main content

honzo_chunks/data/
css.rs

1use cssparser::{
2    AtRuleParser, ParseError, Parser, ParserInput, QualifiedRuleParser, StyleSheetParser,
3};
4use honzo_core::HonzoError;
5
6pub const CSS_TAG: [u8; 4] = *b"CSS_";
7
8pub fn is_css_tag(tag: &[u8; 4]) -> bool {
9    *tag == CSS_TAG
10}
11
12struct CssValidator;
13
14fn parse_entirely<'i, 't>(input: &mut Parser<'i, 't>) -> Result<(), ParseError<'i, ()>> {
15    while !input.is_exhausted() {
16        input.next()?;
17    }
18    Ok(())
19}
20
21impl<'i> QualifiedRuleParser<'i> for CssValidator {
22    type Prelude = ();
23    type QualifiedRule = ();
24    type Error = ();
25
26    fn parse_prelude<'t>(
27        &mut self,
28        input: &mut Parser<'i, 't>,
29    ) -> Result<Self::Prelude, ParseError<'i, Self::Error>> {
30        input.parse_entirely(parse_entirely)
31    }
32
33    fn parse_block<'t>(
34        &mut self,
35        _prelude: Self::Prelude,
36        _start: &cssparser::ParserState,
37        input: &mut Parser<'i, 't>,
38    ) -> Result<Self::QualifiedRule, ParseError<'i, Self::Error>> {
39        input.parse_entirely(parse_entirely)
40    }
41}
42
43impl<'i> AtRuleParser<'i> for CssValidator {
44    type Prelude = ();
45    type AtRule = ();
46    type Error = ();
47
48    fn parse_prelude<'t>(
49        &mut self,
50        _name: cssparser::CowRcStr<'i>,
51        input: &mut Parser<'i, 't>,
52    ) -> Result<Self::Prelude, ParseError<'i, Self::Error>> {
53        input.parse_entirely(parse_entirely)
54    }
55
56    fn parse_block<'t>(
57        &mut self,
58        _prelude: Self::Prelude,
59        _start: &cssparser::ParserState,
60        input: &mut Parser<'i, 't>,
61    ) -> Result<Self::AtRule, ParseError<'i, Self::Error>> {
62        input.parse_entirely(parse_entirely)
63    }
64
65    fn rule_without_block<'t>(
66        &mut self,
67        _prelude: Self::Prelude,
68        _start: &cssparser::ParserState,
69    ) -> Result<Self::AtRule, ()> {
70        Ok(())
71    }
72}
73
74/// Validate CSS bytes by parsing as a stylesheet with cssparser.
75/// Returns the CSS as a string slice if valid.
76pub fn validate_css(bytes: &[u8]) -> Result<&str, HonzoError> {
77    let s = core::str::from_utf8(bytes).map_err(|_| HonzoError::Truncated)?;
78    let mut input = ParserInput::new(s);
79    let mut parser = Parser::new(&mut input);
80    let mut validator = CssValidator;
81    let mut list_parser = StyleSheetParser::new(&mut parser, &mut validator);
82    loop {
83        match list_parser.next() {
84            Some(Ok(..)) => continue,
85            Some(Err((ParseError { .. }, _))) => return Err(HonzoError::InvalidCss),
86            None => break,
87        }
88    }
89    Ok(s)
90}
91
92pub fn validate_css_bytes(bytes: &[u8]) -> Result<(), u8> {
93    match validate_css(bytes) {
94        Ok(..) => Ok(()),
95        Err(HonzoError::Truncated) => Err(7),
96        Err(HonzoError::InvalidCss) => Err(8),
97        Err(..) => Err(255),
98    }
99}
100
101pub fn chunk_name() -> &'static str {
102    "stylesheet"
103}