html_escape/encode/html_entity/
unquoted_attribute.rs

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