Skip to main content

html_escape/encode/html_entity/
unquoted_attribute.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
6use crate::functions::*;
7
8/// Encode text used in an unquoted attribute. Except for alphanumeric characters, escape all characters which are less than 128.
9///
10/// The following characters are escaped to named entities:
11///
12/// * `&` => `&`
13/// * `<` => `&lt;`
14/// * `>` => `&gt;`
15/// * `"` => `&quot;`
16///
17/// Other non-alphanumeric characters are escaped to `&#xHH;`.
18pub fn encode_unquoted_attribute<S: ?Sized + AsRef<str>>(text: &S) -> Cow<'_, str> {
19    let text = text.as_ref();
20    let text_bytes = text.as_bytes();
21
22    let text_length = text_bytes.len();
23
24    let mut p = 0;
25    let mut e;
26
27    loop {
28        if p == text_length {
29            return Cow::from(text);
30        }
31
32        e = text_bytes[p];
33
34        if e.is_ascii() && !e.is_ascii_alphanumeric() {
35            break;
36        }
37
38        p += 1;
39    }
40
41    let mut v = Vec::with_capacity(text_length);
42
43    v.extend_from_slice(&text_bytes[..p]);
44
45    write_html_entity_to_vec(e, &mut v);
46
47    encode_unquoted_attribute_to_vec(
48        unsafe { from_utf8_unchecked(&text_bytes[(p + 1)..]) },
49        &mut v,
50    );
51
52    Cow::from(unsafe { String::from_utf8_unchecked(v) })
53}
54
55/// Write text used in an unquoted attribute to a mutable `String` reference and return the encoded string slice. Except for alphanumeric characters, escape all characters which are less than 128.
56///
57/// The following characters are escaped to named entities:
58///
59/// * `&` => `&amp;`
60/// * `<` => `&lt;`
61/// * `>` => `&gt;`
62/// * `"` => `&quot;`
63///
64/// Other non-alphanumeric characters are escaped to `&#xHH;`.
65#[inline]
66pub fn encode_unquoted_attribute_to_string<S: AsRef<str>>(text: S, output: &mut String) -> &str {
67    unsafe { from_utf8_unchecked(encode_unquoted_attribute_to_vec(text, output.as_mut_vec())) }
68}
69
70/// Write text used in an unquoted attribute to a mutable `Vec<u8>` reference and return the encoded data slice. Except for alphanumeric characters, escape all characters which are less than 128.
71///
72/// The following characters are escaped to named entities:
73///
74/// * `&` => `&amp;`
75/// * `<` => `&lt;`
76/// * `>` => `&gt;`
77/// * `"` => `&quot;`
78///
79/// Other non-alphanumeric characters are escaped to `&#xHH;`.
80pub fn encode_unquoted_attribute_to_vec<S: AsRef<str>>(text: S, output: &mut Vec<u8>) -> &[u8] {
81    let text = text.as_ref();
82    let text_bytes = text.as_bytes();
83    let text_length = text_bytes.len();
84
85    output.reserve(text_length);
86
87    let current_length = output.len();
88
89    let mut p = 0;
90    let mut e;
91
92    let mut start = 0;
93
94    while p < text_length {
95        e = text_bytes[p];
96
97        if e.is_ascii() && !e.is_ascii_alphanumeric() {
98            output.extend_from_slice(&text_bytes[start..p]);
99            start = p + 1;
100            write_html_entity_to_vec(e, output);
101        }
102
103        p += 1;
104    }
105
106    output.extend_from_slice(&text_bytes[start..p]);
107
108    &output[current_length..]
109}
110
111#[cfg(feature = "std")]
112/// Write text used in an unquoted attribute to a writer. Except for alphanumeric characters, escape all characters which are less than 128.
113///
114/// The following characters are escaped to named entities:
115///
116/// * `&` => `&amp;`
117/// * `<` => `&lt;`
118/// * `>` => `&gt;`
119/// * `"` => `&quot;`
120///
121/// Other non-alphanumeric characters are escaped to `&#xHH;`.
122pub fn encode_unquoted_attribute_to_writer<S: AsRef<str>, W: Write>(
123    text: S,
124    output: &mut W,
125) -> Result<(), io::Error> {
126    let text = text.as_ref();
127    let text_bytes = text.as_bytes();
128    let text_length = text_bytes.len();
129
130    let mut p = 0;
131    let mut e;
132
133    let mut start = 0;
134
135    while p < text_length {
136        e = text_bytes[p];
137
138        if e.is_ascii() && !e.is_ascii_alphanumeric() {
139            output.write_all(&text_bytes[start..p])?;
140            start = p + 1;
141            write_html_entity_to_writer(e, output)?;
142        }
143
144        p += 1;
145    }
146
147    output.write_all(&text_bytes[start..p])
148}