Skip to main content

html_escape/encode/element/
style.rs

1use alloc::{borrow::Cow, string::String, vec::Vec};
2use core::str::from_utf8_unchecked;
3#[cfg(feature = "std")]
4use std::io::{self, Write};
5
6macro_rules! parse_style_comment {
7    (@eof $step:ident, $b:block) => {
8        // An unfinished `</style` at the end can still end the element with the text after it.
9        if $step == 7 {
10            $b
11        }
12    };
13    ($e:expr, $step:ident, $b:block, $bc:block) => {
14        match $step {
15            0 => match $e {
16                b'<' => $step = 1,
17                _ => (),
18            },
19            1 => match $e {
20                b'/' => $step = 2,
21                b'!' => $step = 10,
22                b'<' => $step = 1,
23                _ => $step = 0,
24            },
25            2 => match $e {
26                b's' | b'S' => $step = 3,
27                b'<' => $step = 1,
28                _ => $step = 0,
29            },
30            3 => match $e {
31                b't' | b'T' => $step = 4,
32                b'<' => $step = 1,
33                _ => $step = 0,
34            },
35            4 => match $e {
36                b'y' | b'Y' => $step = 5,
37                b'<' => $step = 1,
38                _ => $step = 0,
39            },
40            5 => match $e {
41                b'l' | b'L' => $step = 6,
42                b'<' => $step = 1,
43                _ => $step = 0,
44            },
45            6 => match $e {
46                b'e' | b'E' => $step = 7,
47                b'<' => $step = 1,
48                _ => $step = 0,
49            },
50            7 => match $e {
51                b'/' | b'>' | 9..=13 | 28..=32 => {
52                    $step = 0;
53                    $b
54                },
55                b'<' => $step = 1,
56                _ => $step = 0,
57            },
58            10 => match $e {
59                b'-' => $step = 11,
60                b'<' => $step = 1,
61                _ => $step = 0,
62            },
63            11 => match $e {
64                b'-' => {
65                    $step = 0;
66                    $bc
67                },
68                b'<' => $step = 1,
69                _ => $step = 0,
70            },
71            _ => unreachable!(),
72        }
73    };
74}
75
76encode_impl! {
77    6;
78    /// The following substring is escaped:
79    ///
80    /// * `</style>` => `<\/style>`
81    /// * `<!--` => `<\!--`
82    ///
83    /// `</style` at the end of the text is also escaped, because the text after it can end the element.
84    /// Pass the whole element text in one call; separate calls do not share parsing state.
85    /// This scans text without parsing CSS and may change its meaning.
86    /// Existing escapes are kept, so encoding and decoding may not return the original text.
87    /// Use a quoted text encoder when inserting raw text into a CSS string.
88    parse_style_comment;
89    /// Encode text used in the `<style>` element.
90    encode_style;
91    /// Write text used in the `<style>` element to a mutable `String` reference and return the encoded string slice.
92    encode_style_to_string;
93    /// Write text used in the `<style>` element to a mutable `Vec<u8>` reference and return the encoded data slice.
94    encode_style_to_vec;
95    /// Write text used in the `<style>` element to a writer.
96    encode_style_to_writer;
97}
98
99encode_impl! {
100    quoted true, true, false;
101    /// The input is raw text; existing escapes are encoded as text.
102    /// The output is string content and does not include outer quotes.
103    /// Backslashes and `'` are escaped with a backslash.
104    /// `<` and C0 controls other than NUL use two uppercase hex digits and one ending space, such as `\3C `.
105    /// NUL is replaced with U+FFFD, so text containing NUL cannot round-trip without a change.
106    /// The ending space is part of the escape; an input space after it is kept.
107    /// Use the output in a CSS string inside `<style>`, not in a CSS identifier or an HTML attribute.
108    raw_text;
109    /// Encode raw text for a single-quoted CSS string inside `<style>`.
110    encode_style_single_quoted_text;
111    /// Encode content of a single-quoted CSS string to a mutable `String` and return the new string slice.
112    encode_style_single_quoted_text_to_string;
113    /// Encode content of a single-quoted CSS string to a mutable `Vec<u8>` and return the new data slice.
114    encode_style_single_quoted_text_to_vec;
115    /// Encode content of a single-quoted CSS string to a writer.
116    encode_style_single_quoted_text_to_writer;
117}
118
119encode_impl! {
120    quoted true, false, true;
121    /// The input is raw text; existing escapes are encoded as text.
122    /// The output is string content and does not include outer quotes.
123    /// Backslashes and `"` are escaped with a backslash.
124    /// `<` and C0 controls other than NUL use two uppercase hex digits and one ending space, such as `\3C `.
125    /// NUL is replaced with U+FFFD, so text containing NUL cannot round-trip without a change.
126    /// The ending space is part of the escape; an input space after it is kept.
127    /// Use the output in a CSS string inside `<style>`, not in a CSS identifier or an HTML attribute.
128    raw_text;
129    /// Encode raw text for a double-quoted CSS string inside `<style>`.
130    encode_style_double_quoted_text;
131    /// Encode content of a double-quoted CSS string to a mutable `String` and return the new string slice.
132    encode_style_double_quoted_text_to_string;
133    /// Encode content of a double-quoted CSS string to a mutable `Vec<u8>` and return the new data slice.
134    encode_style_double_quoted_text_to_vec;
135    /// Encode content of a double-quoted CSS string to a writer.
136    encode_style_double_quoted_text_to_writer;
137}
138
139encode_impl! {
140    quoted true, true, true;
141    /// The input is raw text; existing escapes are encoded as text.
142    /// The output is string content and does not include outer quotes.
143    /// Backslashes, `'`, and `"` are escaped with a backslash.
144    /// `<` and C0 controls other than NUL use two uppercase hex digits and one ending space, such as `\3C `.
145    /// NUL is replaced with U+FFFD, so text containing NUL cannot round-trip without a change.
146    /// The ending space is part of the escape; an input space after it is kept.
147    /// Use the output in a CSS string inside `<style>`, not in a CSS identifier or an HTML attribute.
148    raw_text;
149    /// Encode raw text for a single-quoted or double-quoted CSS string inside `<style>`.
150    encode_style_quoted_text;
151    /// Encode content of a single-quoted or double-quoted CSS string to a mutable `String` and return the new string slice.
152    encode_style_quoted_text_to_string;
153    /// Encode content of a single-quoted or double-quoted CSS string to a mutable `Vec<u8>` and return the new data slice.
154    encode_style_quoted_text_to_vec;
155    /// Encode content of a single-quoted or double-quoted CSS string to a writer.
156    encode_style_quoted_text_to_writer;
157}