lol_html/html/
mod.rs

1use crate::base::Bytes;
2use memchr::{memchr, memchr3};
3
4#[macro_use]
5mod tag;
6
7mod local_name;
8mod namespace;
9mod text_type;
10
11pub use self::local_name::{LocalName, LocalNameHash};
12pub use self::namespace::Namespace;
13pub use self::tag::Tag;
14pub use self::text_type::TextType;
15
16/// Convert text to HTML
17#[inline]
18pub(crate) fn escape_body_text(mut content: &str, output_handler: &mut impl FnMut(&str)) {
19    loop {
20        if let Some(pos) = memchr3(b'&', b'<', b'>', content.as_bytes()) {
21            let Some((chunk_before, rest)) = content.split_at_checked(pos) else {
22                return;
23            };
24            let Some((matched, rest)) = rest.split_at_checked(1) else {
25                return;
26            };
27
28            content = rest;
29            let matched = matched.as_bytes()[0];
30
31            if !chunk_before.is_empty() {
32                (output_handler)(chunk_before);
33            }
34            (output_handler)(match matched {
35                b'<' => "&lt;",
36                b'>' => "&gt;",
37                _ => "&amp;",
38            });
39        } else {
40            if !content.is_empty() {
41                (output_handler)(content);
42            }
43            return;
44        }
45    }
46}
47
48/// Replace `"` with `&quot;` ONLY, leaving `&` unescaped
49pub(crate) fn escape_double_quotes_only(content: Bytes<'_>, output_handler: &mut dyn FnMut(&[u8])) {
50    let mut content = &*content;
51    loop {
52        if let Some(pos) = memchr(b'"', content) {
53            let Some((chunk_before, rest)) = content
54                .split_at_checked(pos)
55                .and_then(|(before, rest)| Some((before, rest.get(1..)?)))
56            else {
57                return;
58            };
59            content = rest;
60
61            if !chunk_before.is_empty() {
62                (output_handler)(chunk_before);
63            }
64            (output_handler)(b"&quot;");
65        } else {
66            if !content.is_empty() {
67                (output_handler)(content);
68            }
69            return;
70        }
71    }
72}