1mod unquoted_attribute;
2
3use core::str::from_utf8_unchecked;
4
5use alloc::borrow::Cow;
6use alloc::string::String;
7use alloc::vec::Vec;
8
9#[cfg(feature = "std")]
10use std::io::{self, Write};
11
12pub use unquoted_attribute::*;
13
14macro_rules! escape_impl {
15 (@inner [$dollar:tt] $name:ident; $($l:expr => $r:expr),+ $(,)*) => {
16 macro_rules! $name {
17 ($dollar e:expr) => {
18 match $dollar e {
19 $($l => break $r,)+
20 _ => (),
21 }
22 };
23 (vec $dollar e:expr, $dollar v:ident, $dollar b:ident, $dollar start:ident, $dollar end:ident) => {
24 match $dollar e {
25 $($l => {
26 $dollar v.extend_from_slice(&$dollar b[$dollar start..$dollar end]);
27 $dollar start = $dollar end + 1;
28 $dollar v.extend_from_slice($r);
29 })+
30 _ => (),
31 }
32
33 $dollar end += 1;
34 };
35 (writer $dollar e:expr, $dollar w:ident, $dollar b:ident, $dollar start:ident, $dollar end:ident) => {
36 match $dollar e {
37 $($l => {
38 $dollar w.write_all(&$dollar b[$dollar start..$dollar end])?;
39 $dollar start = $dollar end + 1;
40 $dollar w.write_all($r)?;
41 })+
42 _ => (),
43 }
44
45 $dollar end += 1;
46 };
47 }
48 };
49 ($name:ident; $($l:expr => $r:expr),+ $(,)*) => {
50 escape_impl! {
51 @inner [$]
52 $name;
53 $($l => $r.as_ref(),)*
54 }
55 };
56}
57
58escape_impl! {
59 escape_text_minimal;
60 b'&' => b"&",
61 b'<' => b"&lt;",
62}
63
64escape_impl! {
65 escape_text;
66 b'&' => b"&amp;",
67 b'<' => b"&lt;",
68 b'>' => b"&gt;",
69}
70
71escape_impl! {
72 escape_double_quote;
73 b'&' => b"&amp;",
74 b'<' => b"&lt;",
75 b'>' => b"&gt;",
76 b'"' => b"&quot;",
77}
78
79escape_impl! {
80 escape_single_quote;
81 b'&' => b"&amp;",
82 b'<' => b"&lt;",
83 b'>' => b"&gt;",
84 b'\'' => b"&#x27;",
85}
86
87escape_impl! {
88 escape_quote;
89 b'&' => b"&amp;",
90 b'<' => b"&lt;",
91 b'>' => b"&gt;",
92 b'"' => b"&quot;",
93 b'\'' => b"&#x27;",
94}
95
96escape_impl! {
97 escape_safe;
98 b'&' => b"&amp;",
99 b'<' => b"&lt;",
100 b'>' => b"&gt;",
101 b'"' => b"&quot;",
102 b'\'' => b"&#x27;",
103 b'/' => b"&#x2F;",
104}
105
106macro_rules! encode_impl {
107 ($(#[$attr: meta])* $escape_macro:ident; $(#[$encode_attr: meta])* $encode_name: ident; $(#[$encode_to_string_attr: meta])* $encode_to_string_name: ident; $(#[$encode_to_vec_attr: meta])* $encode_to_vec_name: ident; $(#[$encode_to_writer_attr: meta])* $encode_to_writer_name: ident $(;)*) => {
108 $(#[$encode_attr])*
109 ///
110 $(#[$attr])*
111 #[inline]
112 pub fn $encode_name<S: ?Sized + AsRef<str>>(text: &S) -> Cow<str> {
113 let text = text.as_ref();
114 let text_bytes = text.as_bytes();
115 let text_length = text_bytes.len();
116
117 let mut p = 0;
118 let mut e;
119
120 let first = loop {
121 if p == text_length {
122 return Cow::from(text);
123 }
124
125 e = text_bytes[p];
126
127 $escape_macro!(e);
128
129 p += 1;
130 };
131
132 let mut v = Vec::with_capacity(text_length + 5);
133
134 v.extend_from_slice(&text_bytes[..p]);
135 v.extend_from_slice(first);
136
137 $encode_to_vec_name(unsafe { from_utf8_unchecked(&text_bytes[(p + 1)..]) }, &mut v);
138
139 Cow::from(unsafe { String::from_utf8_unchecked(v) })
140 }
141
142 $(#[$encode_to_string_attr])*
143 ///
144 $(#[$attr])*
145 #[inline]
146 pub fn $encode_to_string_name<S: AsRef<str>>(text: S, output: &mut String) -> &str {
147 unsafe { from_utf8_unchecked($encode_to_vec_name(text, output.as_mut_vec())) }
148 }
149
150 $(#[$encode_to_vec_attr])*
151 ///
152 $(#[$attr])*
153 #[inline]
154 pub fn $encode_to_vec_name<S: AsRef<str>>(text: S, output: &mut Vec<u8>) -> &[u8] {
155 let text = text.as_ref();
156 let text_bytes = text.as_bytes();
157 let text_length = text_bytes.len();
158
159 output.reserve(text_length);
160
161 let current_length = output.len();
162
163 let mut start = 0;
164 let mut end = 0;
165
166 for e in text_bytes.iter().copied() {
167 $escape_macro!(vec e, output, text_bytes, start, end);
168 }
169
170 output.extend_from_slice(&text_bytes[start..end]);
171
172 &output[current_length..]
173 }
174
175 #[cfg(feature = "std")]
176 $(#[$encode_to_writer_attr])*
177 ///
178 $(#[$attr])*
179 #[inline]
180 pub fn $encode_to_writer_name<S: AsRef<str>, W: Write>(text: S, output: &mut W) -> Result<(), io::Error> {
181 let text = text.as_ref();
182 let text_bytes = text.as_bytes();
183
184 let mut start = 0;
185 let mut end = 0;
186
187 for e in text_bytes.iter().copied() {
188 $escape_macro!(writer e, output, text_bytes, start, end);
189 }
190
191 output.write_all(&text_bytes[start..end])
192 }
193 };
194}
195
196encode_impl! {
197 /// The following characters are escaped:
198 ///
199 /// * `&` => `&amp;`
200 /// * `<` => `&lt;`
201 escape_text_minimal;
202 /// Encode text used as regular HTML text.
203 encode_text_minimal;
204 /// Write text used as regular HTML text to a mutable `String` reference and return the encoded string slice.
205 encode_text_minimal_to_string;
206 /// Write text used as regular HTML text to a mutable `Vec<u8>` reference and return the encoded data slice.
207 encode_text_minimal_to_vec;
208 /// Write text used as regular HTML text to a writer.
209 encode_text_minimal_to_writer;
210}
211
212encode_impl! {
213 /// The following characters are escaped:
214 ///
215 /// * `&` => `&amp;`
216 /// * `<` => `&lt;`
217 /// * `>` => `&gt;`
218 escape_text;
219 /// Encode text used as regular HTML text.
220 encode_text;
221 /// Write text used as regular HTML text to a mutable `String` reference and return the encoded string slice.
222 encode_text_to_string;
223 /// Write text used as regular HTML text to a mutable `Vec<u8>` reference and return the encoded data slice.
224 encode_text_to_vec;
225 /// Write text used as regular HTML text to a writer.
226 encode_text_to_writer;
227}
228
229encode_impl! {
230 /// The following characters are escaped:
231 ///
232 /// * `&` => `&amp;`
233 /// * `<` => `&lt;`
234 /// * `>` => `&gt;`
235 /// * `"` => `&quot;`
236 escape_double_quote;
237 /// Encode text used in a double-quoted attribute.
238 encode_double_quoted_attribute;
239 /// Write text used in a double-quoted attribute to a mutable `String` reference and return the encoded string slice.
240 encode_double_quoted_attribute_to_string;
241 /// Write text used in a double-quoted attribute to a mutable `Vec<u8>` reference and return the encoded data slice.
242 encode_double_quoted_attribute_to_vec;
243 /// Write text used in a double-quoted attribute to a writer.
244 encode_double_quoted_attribute_to_writer;
245}
246
247encode_impl! {
248 /// The following characters are escaped:
249 ///
250 /// * `&` => `&amp;`
251 /// * `<` => `&lt;`
252 /// * `>` => `&gt;`
253 /// * `'` => `&#x27;`
254 escape_single_quote;
255 /// Encode text used in a single-quoted attribute.
256 encode_single_quoted_attribute;
257 /// Write text used in a single-quoted attribute to a mutable `String` reference and return the encoded string slice.
258 encode_single_quoted_attribute_to_string;
259 /// Write text used in a single-quoted attribute to a mutable `Vec<u8>` reference and return the encoded data slice.
260 encode_single_quoted_attribute_to_vec;
261 /// Write text used in a single-quoted attribute to a writer.
262 encode_single_quoted_attribute_to_writer;
263}
264
265encode_impl! {
266 /// The following characters (HTML reserved characters) are escaped:
267 ///
268 /// * `&` => `&amp;`
269 /// * `<` => `&lt;`
270 /// * `>` => `&gt;`
271 /// * `"` => `&quot;`
272 /// * `'` => `&#x27;`
273 escape_quote;
274 /// Encode text used in a quoted attribute.
275 encode_quoted_attribute;
276 /// Write text used in a quoted attribute to a mutable `String` reference and return the encoded string slice.
277 encode_quoted_attribute_to_string;
278 /// Write text used in a quoted attribute to a mutable `Vec<u8>` reference and return the encoded data slice.
279 encode_quoted_attribute_to_vec;
280 /// Write text used in a quoted attribute to a writer.
281 encode_quoted_attribute_to_writer;
282}
283
284encode_impl! {
285 /// The following characters are escaped:
286 ///
287 /// * `&` => `&amp;`
288 /// * `<` => `&lt;`
289 /// * `>` => `&gt;`
290 /// * `"` => `&quot;`
291 /// * `'` => `&#x27;`
292 /// * `/` => `&#x2F;`
293 escape_safe;
294 /// Encode text to prevent special characters functioning.
295 encode_safe;
296 /// Encode text to prevent special characters functioning and write it to a mutable `String` reference and return the encoded string slice.
297 encode_safe_to_string;
298 /// Encode text to prevent special characters functioning and write it to a mutable `Vec<u8>` reference and return the encoded data slice.
299 encode_safe_to_vec;
300 /// Encode text to prevent special characters functioning and write it to a writer.
301 encode_safe_to_writer;
302}
303