Skip to content

Commit

Permalink
Add encode_attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
lukaslueg committed Jul 14, 2024
1 parent 9489997 commit 4d0fa37
Show file tree
Hide file tree
Showing 2 changed files with 314 additions and 0 deletions.
306 changes: 306 additions & 0 deletions src/notactuallysvg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,288 @@ pub fn encode_minimal(inp: &str) -> Cow<str> {
}
}

const ENTITIES: [Option<&'static str>; 256] = [
Some("&#x00;"),
Some("&#x01;"),
Some("&#x02;"),
Some("&#x03;"),
Some("&#x04;"),
Some("&#x05;"),
Some("&#x06;"),
Some("&#x07;"),
Some("&#x08;"),
Some("&#x09;"),
Some("&#x0A;"),
Some("&#x0B;"),
Some("&#x0C;"),
Some("&#x0D;"),
Some("&#x0E;"),
Some("&#x0F;"),
Some("&#x10;"),
Some("&#x11;"),
Some("&#x12;"),
Some("&#x13;"),
Some("&#x14;"),
Some("&#x15;"),
Some("&#x16;"),
Some("&#x17;"),
Some("&#x18;"),
Some("&#x19;"),
Some("&#x1A;"),
Some("&#x1B;"),
Some("&#x1C;"),
Some("&#x1D;"),
Some("&#x1E;"),
Some("&#x1F;"),
Some("&#x20;"),
Some("&#x21;"),
Some("&quot;"),
Some("&#x23;"),
Some("&#x24;"),
Some("&#x25;"),
Some("&amp;"),
Some("&#x27;"),
Some("&#x28;"),
Some("&#x29;"),
Some("&#x2A;"),
Some("&#x2B;"),
Some("&#x2C;"),
Some("&#x2D;"),
Some("&#x2E;"),
Some("&#x2F;"),
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
Some("&#x3A;"),
Some("&#x3B;"),
Some("&lt;"),
Some("&#x3D;"),
Some("&gt;"),
Some("&#x3F;"),
Some("&#x40;"),
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
Some("&#x5B;"),
Some("&#x5C;"),
Some("&#x5D;"),
Some("&#x5E;"),
Some("&#x5F;"),
Some("&#x60;"),
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
None,
Some("&#x7B;"),
Some("&#x7C;"),
Some("&#x7D;"),
Some("&#x7E;"),
Some("&#x7F;"),
Some("&#x80;"),
Some("&#x81;"),
Some("&#x82;"),
Some("&#x83;"),
Some("&#x84;"),
Some("&#x85;"),
Some("&#x86;"),
Some("&#x87;"),
Some("&#x88;"),
Some("&#x89;"),
Some("&#x8A;"),
Some("&#x8B;"),
Some("&#x8C;"),
Some("&#x8D;"),
Some("&#x8E;"),
Some("&#x8F;"),
Some("&#x90;"),
Some("&#x91;"),
Some("&#x92;"),
Some("&#x93;"),
Some("&#x94;"),
Some("&#x95;"),
Some("&#x96;"),
Some("&#x97;"),
Some("&#x98;"),
Some("&#x99;"),
Some("&#x9A;"),
Some("&#x9B;"),
Some("&#x9C;"),
Some("&#x9D;"),
Some("&#x9E;"),
Some("&#x9F;"),
Some("&#xA0;"),
Some("&#xA1;"),
Some("&#xA2;"),
Some("&#xA3;"),
Some("&#xA4;"),
Some("&#xA5;"),
Some("&#xA6;"),
Some("&#xA7;"),
Some("&#xA8;"),
Some("&#xA9;"),
Some("&#xAA;"),
Some("&#xAB;"),
Some("&#xAC;"),
Some("&#xAD;"),
Some("&#xAE;"),
Some("&#xAF;"),
Some("&#xB0;"),
Some("&#xB1;"),
Some("&#xB2;"),
Some("&#xB3;"),
Some("&#xB4;"),
Some("&#xB5;"),
Some("&#xB6;"),
Some("&#xB7;"),
Some("&#xB8;"),
Some("&#xB9;"),
Some("&#xBA;"),
Some("&#xBB;"),
Some("&#xBC;"),
Some("&#xBD;"),
Some("&#xBE;"),
Some("&#xBF;"),
Some("&#xC0;"),
Some("&#xC1;"),
Some("&#xC2;"),
Some("&#xC3;"),
Some("&#xC4;"),
Some("&#xC5;"),
Some("&#xC6;"),
Some("&#xC7;"),
Some("&#xC8;"),
Some("&#xC9;"),
Some("&#xCA;"),
Some("&#xCB;"),
Some("&#xCC;"),
Some("&#xCD;"),
Some("&#xCE;"),
Some("&#xCF;"),
Some("&#xD0;"),
Some("&#xD1;"),
Some("&#xD2;"),
Some("&#xD3;"),
Some("&#xD4;"),
Some("&#xD5;"),
Some("&#xD6;"),
Some("&#xD7;"),
Some("&#xD8;"),
Some("&#xD9;"),
Some("&#xDA;"),
Some("&#xDB;"),
Some("&#xDC;"),
Some("&#xDD;"),
Some("&#xDE;"),
Some("&#xDF;"),
Some("&#xE0;"),
Some("&#xE1;"),
Some("&#xE2;"),
Some("&#xE3;"),
Some("&#xE4;"),
Some("&#xE5;"),
Some("&#xE6;"),
Some("&#xE7;"),
Some("&#xE8;"),
Some("&#xE9;"),
Some("&#xEA;"),
Some("&#xEB;"),
Some("&#xEC;"),
Some("&#xED;"),
Some("&#xEE;"),
Some("&#xEF;"),
Some("&#xF0;"),
Some("&#xF1;"),
Some("&#xF2;"),
Some("&#xF3;"),
Some("&#xF4;"),
Some("&#xF5;"),
Some("&#xF6;"),
Some("&#xF7;"),
Some("&#xF8;"),
Some("&#xF9;"),
Some("&#xFA;"),
Some("&#xFB;"),
Some("&#xFC;"),
Some("&#xFD;"),
Some("&#xFE;"),
Some("&#xFF;"),
];

/// Encode the given string to allow safely using that string as an attribute-value.
pub fn encode_attribute(inp: &str) -> Cow<str> {
let mut buf = String::new();
let mut last_idx = 0;
for (idx, c) in inp.char_indices() {
if let Ok(b) = <char as TryInto<u8>>::try_into(c) {
if let Some(entity) = ENTITIES[b as usize] {
let fragment = &inp[last_idx..idx];
buf.reserve(fragment.len() + entity.len());
buf.push_str(fragment);
buf.push_str(entity);
last_idx = idx + c.len_utf8();
}
}
}
if !buf.is_empty() {
buf.push_str(&inp[last_idx..]);
Cow::Owned(buf)
} else {
Cow::Borrowed(inp)
}
}

#[cfg(test)]
mod tests {
use std::borrow::Cow;
Expand Down Expand Up @@ -400,4 +682,28 @@ mod tests {
));
}
}

#[test]
fn test_encode_attribute() {
let data = [
("", None),
("foobar", None),
("0 3px", Some("0&#x20;3px")),
("<img \"\"\">", Some("&lt;img&#x20;&quot;&quot;&quot;&gt;")),
("hej; hå", Some("hej&#x3B;&#x20;h&#xE5;")),
("d-none m-0", Some("d&#x2D;none&#x20;m&#x2D;0")),
(
"\"bread\" & 奶油",
Some("&quot;bread&quot;&#x20;&amp;&#x20;奶油"),
),
];
for &(input, expected) in data.iter() {
let actual = super::encode_attribute(input);
assert_eq!(&actual, expected.unwrap_or(input));
assert!(matches!(
(expected, actual),
(Some(_), Cow::Owned(_)) | (None, Cow::Borrowed(_))
));
}
}
}
8 changes: 8 additions & 0 deletions tests/test_lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,11 @@
fn test_encode_minimal() {
assert_eq!(railroad::svg::encode_minimal("foo<bar>"), "foo&lt;bar&gt;");
}

#[test]
fn test_encode_attribute() {
assert_eq!(
railroad::svg::encode_attribute("fö bör"),
"f&#xF6;&#x20;bo\u{308}r"
);
}

0 comments on commit 4d0fa37

Please sign in to comment.