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