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}