pub(crate) fn extract_encoded_values(text: &str) -> Vec<String> {
let mut values = Vec::new();
let mut b64_block = String::new();
let mut pct_block = String::new();
let is_b64_char = |ch: char| -> bool {
ch.is_ascii_alphanumeric() || ch == '+' || ch == '/' || ch == '=' || ch == '-' || ch == '_'
};
let is_pct_run_char = |ch: char| -> bool { ch == '%' || ch.is_ascii_hexdigit() };
fn flush_pct(values: &mut Vec<String>, pct_block: &mut String) {
const MIN_PCT_TRIPLETS: usize = 1;
if pct_block.len() >= MIN_PCT_TRIPLETS * 3
&& pct_block.matches('%').count() >= MIN_PCT_TRIPLETS
{
values.push(std::mem::take(pct_block));
}
pct_block.clear();
}
let mut chars = text.char_indices().peekable();
while let Some(&(_, ch)) = chars.peek() {
if ch == '"' || ch == '\'' || ch == '`' {
if b64_block.len() >= 16 {
values.push(std::mem::take(&mut b64_block));
}
b64_block.clear();
flush_pct(&mut values, &mut pct_block);
let quote = ch;
chars.next();
let mut escaping = false;
let mut cleaned = String::with_capacity(32);
while let Some(&(_, current)) = chars.peek() {
chars.next();
if escaping {
cleaned.push(current);
escaping = false;
} else if current == '\\' {
escaping = true;
} else if current == quote {
if cleaned.len() >= 4 {
values.push(cleaned);
}
break;
} else if !current.is_ascii_whitespace() {
cleaned.push(current);
}
}
continue;
}
if ch == ':' || ch == '=' {
if b64_block.len() >= 16 {
values.push(std::mem::take(&mut b64_block));
}
b64_block.clear();
flush_pct(&mut values, &mut pct_block);
chars.next();
while chars.peek().is_some_and(|&(_, c)| c.is_ascii_whitespace()) {
chars.next();
}
let mut cleaned = String::with_capacity(32);
while let Some(&(_, c)) = chars.peek() {
if c.is_ascii_whitespace()
|| c == ';'
|| c == ','
|| c == '"'
|| c == '\''
|| c == '`'
{
break;
}
cleaned.push(c);
chars.next();
}
if cleaned.len() >= 4 {
values.push(cleaned);
}
continue;
}
if is_pct_run_char(ch) {
if pct_block.is_empty() && ch != '%' {
} else {
pct_block.push(ch);
chars.next();
continue;
}
} else if !pct_block.is_empty() {
flush_pct(&mut values, &mut pct_block);
}
if is_b64_char(ch) {
b64_block.push(ch);
} else if !ch.is_whitespace() {
if b64_block.len() >= 16 {
values.push(std::mem::take(&mut b64_block));
}
b64_block.clear();
}
chars.next();
}
if b64_block.len() >= 16 {
values.push(b64_block);
}
flush_pct(&mut values, &mut pct_block);
values
}
pub(crate) use crate::util_hash::hash_fast;