1use memchr::{memchr, memchr2_iter, memchr3};
4use std::borrow::Cow;
5use std::fmt::{self, Write};
6use std::num::ParseIntError;
7use std::ops::Range;
8use std::slice::Iter;
9
10#[derive(Clone, Debug, PartialEq)]
12pub enum ParseCharRefError {
13 UnexpectedSign,
15 InvalidNumber(ParseIntError),
17 InvalidCodepoint(u32),
19 IllegalCharacter(u32),
23}
24
25impl std::fmt::Display for ParseCharRefError {
26 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
27 match self {
28 Self::UnexpectedSign => f.write_str("unexpected number sign"),
29 Self::InvalidNumber(e) => e.fmt(f),
30 Self::InvalidCodepoint(n) => write!(f, "`{}` is not a valid codepoint", n),
31 Self::IllegalCharacter(n) => write!(f, "0x{:x} character is not permitted in XML", n),
32 }
33 }
34}
35
36impl std::error::Error for ParseCharRefError {
37 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
38 match self {
39 Self::InvalidNumber(e) => Some(e),
40 _ => None,
41 }
42 }
43}
44
45#[derive(Clone, Debug, PartialEq)]
47pub enum EscapeError {
48 UnrecognizedEntity(Range<usize>, String),
50 UnterminatedEntity(Range<usize>),
52 InvalidCharRef(ParseCharRefError),
55 TooManyNestedEntities,
61}
62
63impl std::fmt::Display for EscapeError {
64 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
65 match self {
66 Self::UnrecognizedEntity(rge, res) => {
67 write!(f, "at {:?}: unrecognized entity `{}`", rge, res)
68 }
69 Self::UnterminatedEntity(e) => write!(
70 f,
71 "Error while escaping character at range {:?}: Cannot find ';' after '&'",
72 e
73 ),
74 Self::InvalidCharRef(e) => {
75 write!(f, "invalid character reference: {}", e)
76 }
77 Self::TooManyNestedEntities => {
78 f.write_str("too many nested entities in an attribute value")
79 }
80 }
81 }
82}
83
84impl std::error::Error for EscapeError {
85 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
86 match self {
87 Self::InvalidCharRef(e) => Some(e),
88 _ => None,
89 }
90 }
91}
92
93pub fn escape<'a>(raw: impl Into<Cow<'a, str>>) -> Cow<'a, str> {
108 _escape(raw, |ch| {
109 matches!(ch, b'<' | b'>' | b'&' | b'\'' | b'\"' | b'\r')
110 })
111}
112
113pub fn partial_escape<'a>(raw: impl Into<Cow<'a, str>>) -> Cow<'a, str> {
129 _escape(raw, |ch| matches!(ch, b'<' | b'>' | b'&' | b'\r'))
130}
131
132pub fn minimal_escape<'a>(raw: impl Into<Cow<'a, str>>) -> Cow<'a, str> {
148 _escape(raw, |ch| matches!(ch, b'<' | b'&' | b'\r'))
149}
150
151pub(crate) fn escape_attribute<'a>(raw: impl Into<Cow<'a, str>>) -> Cow<'a, str> {
168 _escape(raw, |ch| {
169 matches!(
170 ch,
171 b'<' | b'>' | b'&' | b'\'' | b'\"' | b'\r' | b'\n' | b'\t'
172 )
173 })
174}
175
176pub(crate) fn escape_char<W>(writer: &mut W, value: &str, from: usize, to: usize) -> fmt::Result
177where
178 W: fmt::Write,
179{
180 writer.write_str(&value[from..to])?;
181 match value.as_bytes()[to] {
182 b'<' => writer.write_str("<")?,
183 b'>' => writer.write_str(">")?,
184 b'\'' => writer.write_str("'")?,
185 b'&' => writer.write_str("&")?,
186 b'"' => writer.write_str(""")?,
187
188 b'\t' => writer.write_str("	")?,
191 b'\n' => writer.write_str(" ")?,
192 b'\r' => writer.write_str(" ")?,
193 b' ' => writer.write_str(" ")?,
194 _ => unreachable!("Only '<', '>','\', '&', '\"', '\\t', '\\r', '\\n', and ' ' are escaped"),
195 }
196 Ok(())
197}
198
199fn _escape<'a, F: Fn(u8) -> bool>(raw: impl Into<Cow<'a, str>>, escape_chars: F) -> Cow<'a, str> {
202 let raw = raw.into();
203 let bytes = raw.as_bytes();
204 let mut escaped = None;
205 let mut iter = bytes.iter();
206 let mut pos = 0;
207 while let Some(i) = iter.position(|&b| escape_chars(b)) {
208 if escaped.is_none() {
209 escaped = Some(String::with_capacity(raw.len()));
210 }
211 let escaped = escaped.as_mut().expect("initialized");
212 let new_pos = pos + i;
213 escape_char(escaped, &raw, pos, new_pos).unwrap();
215 pos = new_pos + 1;
216 }
217
218 if let Some(mut escaped) = escaped {
219 if let Some(raw) = raw.get(pos..) {
220 escaped.write_str(raw).unwrap();
222 }
223 Cow::Owned(escaped)
224 } else {
225 raw
226 }
227}
228
229pub fn unescape(raw: &str) -> Result<Cow<'_, str>, EscapeError> {
237 unescape_with(raw, resolve_predefined_entity)
238}
239
240pub fn unescape_with<'input, 'entity, F>(
280 raw: &'input str,
281 mut resolve_entity: F,
282) -> Result<Cow<'input, str>, EscapeError>
283where
284 F: FnMut(&str) -> Option<&'entity str>,
286{
287 let bytes = raw.as_bytes();
288 let mut unescaped = None;
289 let mut last_end = 0;
290 let mut iter = memchr2_iter(b'&', b';', bytes);
291 while let Some(start) = iter.by_ref().find(|p| bytes[*p] == b'&') {
292 match iter.next() {
293 Some(end) if bytes[end] == b';' => {
294 if unescaped.is_none() {
296 unescaped = Some(String::with_capacity(raw.len()));
297 }
298 let unescaped = unescaped.as_mut().expect("initialized");
299 unescaped.push_str(&raw[last_end..start]);
300
301 let pat = &raw[start + 1..end];
303 if let Some(entity) = pat.strip_prefix('#') {
304 let codepoint = parse_number(entity).map_err(EscapeError::InvalidCharRef)?;
305 unescaped.push_str(codepoint.encode_utf8(&mut [0u8; 4]));
306 } else if let Some(value) = resolve_entity(pat) {
307 unescaped.push_str(value);
308 } else {
309 return Err(EscapeError::UnrecognizedEntity(
310 start + 1..end,
311 pat.to_string(),
312 ));
313 }
314
315 last_end = end + 1;
316 }
317 _ => return Err(EscapeError::UnterminatedEntity(start..raw.len())),
318 }
319 }
320
321 if let Some(mut unescaped) = unescaped {
322 if let Some(raw) = raw.get(last_end..) {
323 unescaped.push_str(raw);
324 }
325 Ok(Cow::Owned(unescaped))
326 } else {
327 Ok(Cow::Borrowed(raw))
328 }
329}
330
331pub(crate) fn normalize_xml11_eols<'input>(text: &'input str) -> Cow<'input, str> {
335 let bytes = text.as_bytes();
336
337 if let Some(i) = memchr3(b'\r', 0xC2, 0xE2, bytes) {
348 let mut normalized = String::with_capacity(text.len());
351 normalized.push_str(&text[0..i]);
354
355 let mut pos = normalize_xml11_eol_step(&mut normalized, text, i, '\n');
356 while let Some(i) = memchr3(b'\r', 0xC2, 0xE2, &bytes[pos..]) {
357 let index = pos + i;
358 normalized.push_str(&text[pos..index]);
361 pos = normalize_xml11_eol_step(&mut normalized, text, index, '\n');
362 }
363 if let Some(rest) = text.get(pos..) {
364 normalized.push_str(rest);
365 }
366 return normalized.into();
367 }
368 Cow::Borrowed(text)
369}
370
371fn normalize_xml11_eol_step(normalized: &mut String, text: &str, index: usize, ch: char) -> usize {
408 let input = text.as_bytes();
409 match input[index] {
410 b'\r' => {
411 if index + 1 < input.len() {
412 let next = input[index + 1];
413 if next == b'\n' {
414 normalized.push(ch);
415 return index + 2; }
417 if next == 0xC2 {
418 if index + 2 < input.len() && input[index + 2] == 0x85 {
420 normalized.push(ch);
421 } else {
422 normalized.push(ch);
423 normalized.push_str(&text[index + 1..index + 3]);
426 }
427 return index + 3; }
429 }
430 normalized.push(ch);
431 index + 1 }
433 b'\n' => {
434 normalized.push(ch);
435 index + 1 }
437 0xC2 => {
439 if index + 1 < input.len() && input[index + 1] == 0x85 {
440 normalized.push(ch);
441 } else {
442 normalized.push_str(&text[index..index + 2]);
445 }
446 index + 2 }
448 0xE2 => {
450 if index + 2 < input.len() && input[index + 1] == 0x80 && input[index + 2] == 0xA8 {
451 normalized.push(ch);
452 } else {
453 normalized.push_str(&text[index..index + 3]);
456 }
457 index + 3 }
459
460 x => unreachable!(
461 "at {}: expected ''\\n', '\\r', '\\xC2', or '\\xE2', found '{}' / {} / `0x{:X}`",
462 index, x as char, x, x
463 ),
464 }
465}
466
467pub(crate) fn normalize_xml10_eols<'input>(text: &'input str) -> Cow<'input, str> {
471 let bytes = text.as_bytes();
472
473 if let Some(i) = memchr(b'\r', bytes) {
481 let mut normalized = String::with_capacity(text.len());
484 normalized.push_str(&text[0..i]);
487
488 let mut pos = normalize_xml10_eol_step(&mut normalized, text, i, '\n');
489 while let Some(i) = memchr(b'\r', &bytes[pos..]) {
490 let index = pos + i;
491 normalized.push_str(&text[pos..index]);
494 pos = normalize_xml10_eol_step(&mut normalized, text, index, '\n');
495 }
496 if let Some(rest) = text.get(pos..) {
497 normalized.push_str(rest);
498 }
499 return normalized.into();
500 }
501 Cow::Borrowed(text)
502}
503
504fn normalize_xml10_eol_step(normalized: &mut String, text: &str, index: usize, ch: char) -> usize {
517 let input = text.as_bytes();
518 match input[index] {
519 b'\r' => {
520 normalized.push(ch);
521 if index + 1 < input.len() && input[index + 1] == b'\n' {
522 return index + 2; }
524 index + 1 }
526 b'\n' => {
527 normalized.push(ch);
528 index + 1 }
530
531 x => unreachable!(
532 "at {}: expected ''\\n' or '\\r', found '{}' / {} / `0x{:X}`",
533 index, x as char, x, x
534 ),
535 }
536}
537
538pub(crate) fn normalize_xml10_attribute_value<'input, 'entity, F>(
541 value: &'input str,
542 depth: usize,
543 resolve_entity: F,
544) -> Result<Cow<'input, str>, EscapeError>
545where
546 F: FnMut(&str) -> Option<&'entity str>,
548{
549 normalize_attribute_value(
550 value,
551 depth,
552 is_xml10_normalization_char,
553 normalize_xml10_eol_step,
554 resolve_entity,
555 )
556}
557
558const fn is_xml10_normalization_char(b: &u8) -> bool {
559 matches!(*b, b'\t' | b'\r' | b'\n' | b'&')
567}
568
569pub(crate) fn normalize_xml11_attribute_value<'input, 'entity, F>(
572 value: &'input str,
573 depth: usize,
574 resolve_entity: F,
575) -> Result<Cow<'input, str>, EscapeError>
576where
577 F: FnMut(&str) -> Option<&'entity str>,
579{
580 normalize_attribute_value(
581 value,
582 depth,
583 is_xml11_normalization_char,
584 normalize_xml11_eol_step,
585 resolve_entity,
586 )
587}
588
589const fn is_xml11_normalization_char(b: &u8) -> bool {
590 matches!(*b, b'\t' | b'\r' | b'\n' | 0xC2 | 0xE2 | b'&')
601}
602
603pub fn normalize_attribute_value<'input, 'entity, C, E, F>(
637 value: &'input str,
638 depth: usize,
639 is_normalization_char: C,
640 normalize_eol_step: E,
641 mut resolve_entity: F,
642) -> Result<Cow<'input, str>, EscapeError>
643where
644 C: Fn(&u8) -> bool,
645 E: Fn(&mut String, &str, usize, char) -> usize,
646 F: FnMut(&str) -> Option<&'entity str>,
648{
649 let mut iter = value.as_bytes().iter();
650
651 if let Some(i) = iter.position(&is_normalization_char) {
654 let mut normalized = String::with_capacity(value.len());
655 let pos = normalize_attr_step(
656 &mut normalized,
657 &mut iter,
658 value,
659 0,
660 i,
661 depth,
662 &is_normalization_char,
663 &normalize_eol_step,
664 &mut resolve_entity,
665 )?;
666
667 normalize_attr_steps(
668 &mut normalized,
669 &mut iter,
670 value,
671 pos,
672 depth,
673 &is_normalization_char,
674 &normalize_eol_step,
675 &mut resolve_entity,
676 )?;
677 return Ok(normalized.into());
678 }
679 Ok(Cow::Borrowed(value))
680}
681
682fn normalize_attr_steps<'entity, C, E, F>(
683 normalized: &mut String,
684 iter: &mut Iter<u8>,
685 input: &str,
686 mut pos: usize,
687 depth: usize,
688 is_normalization_char: &C,
689 normalize_eol_step: &E,
690 resolve_entity: &mut F,
691) -> Result<(), EscapeError>
692where
693 C: Fn(&u8) -> bool,
694 E: Fn(&mut String, &str, usize, char) -> usize,
695 F: FnMut(&str) -> Option<&'entity str>,
697{
698 while let Some(i) = iter.position(is_normalization_char) {
699 pos = normalize_attr_step(
700 normalized,
701 iter,
702 input,
703 pos,
704 pos + i,
705 depth,
706 is_normalization_char,
707 normalize_eol_step,
708 resolve_entity,
709 )?;
710 }
711 if let Some(rest) = input.get(pos..) {
712 normalized.push_str(rest);
713 }
714 Ok(())
715}
716
717fn normalize_attr_step<'entity, C, E, F>(
757 normalized: &mut String,
758 iter: &mut Iter<u8>,
759 input: &str,
760 last_pos: usize,
761 index: usize,
762 depth: usize,
763 is_normalization_char: &C,
764 normalize_eol_step: &E,
765 resolve_entity: &mut F,
766) -> Result<usize, EscapeError>
767where
768 C: Fn(&u8) -> bool,
769 E: Fn(&mut String, &str, usize, char) -> usize,
770 F: FnMut(&str) -> Option<&'entity str>,
772{
773 if depth == 0 {
774 return Err(EscapeError::TooManyNestedEntities);
775 }
776 normalized.push_str(&input[last_pos..index]);
778
779 match input.as_bytes()[index] {
780 b'&' => {
781 let start = index + 1; let end = start
783 + match iter.position(|&b| b == b';') {
784 Some(end) => end,
785 None => return Err(EscapeError::UnterminatedEntity(index..input.len())),
786 };
787
788 let pat = &input[start..end];
796 if let Some(entity) = pat.strip_prefix('#') {
799 let codepoint = parse_number(entity).map_err(EscapeError::InvalidCharRef)?;
800 normalized.push_str(codepoint.encode_utf8(&mut [0u8; 4]));
801 } else
802 if pat == "amp" {
805 normalized.push('&');
806 } else
807 if let Some(value) = resolve_entity(pat) {
810 normalize_attr_steps(
811 normalized,
812 &mut value.as_bytes().iter(),
813 value,
814 0,
815 depth.saturating_sub(1),
816 is_normalization_char,
817 normalize_eol_step,
818 resolve_entity,
819 )?;
820 } else {
821 return Err(EscapeError::UnrecognizedEntity(start..end, pat.to_string()));
822 }
823 Ok(end + 1) }
825 b'\t' => {
829 normalized.push(' ');
830 Ok(index + 1) }
832 _ => {
833 let pos = normalize_eol_step(normalized, input, index, ' ');
834 for _ in 0..pos - index - 1 {
836 iter.next();
837 }
838 Ok(pos)
839 }
840 }
841}
842
843#[inline]
851pub const fn resolve_predefined_entity(entity: &str) -> Option<&'static str> {
852 #[cfg(not(feature = "escape-html"))]
853 {
854 resolve_xml_entity(entity)
855 }
856
857 #[cfg(feature = "escape-html")]
858 {
859 resolve_html5_entity(entity)
860 }
861}
862
863pub const fn resolve_xml_entity(entity: &str) -> Option<&'static str> {
882 let s = match entity.as_bytes() {
884 b"lt" => "<",
885 b"gt" => ">",
886 b"amp" => "&",
887 b"apos" => "'",
888 b"quot" => "\"",
889 _ => return None,
890 };
891 Some(s)
892}
893
894#[cfg(feature = "escape-html")]
896pub const fn resolve_html5_entity(entity: &str) -> Option<&'static str> {
897 let s = match entity.as_bytes() {
904 b"Tab" => "\u{09}",
905 b"NewLine" => "\u{0A}",
906 b"excl" => "\u{21}",
907 b"quot" | b"QUOT" => "\u{22}",
908 b"num" => "\u{23}",
909 b"dollar" => "\u{24}",
910 b"percnt" => "\u{25}",
911 b"amp" | b"AMP" => "\u{26}",
912 b"apos" => "\u{27}",
913 b"lpar" => "\u{28}",
914 b"rpar" => "\u{29}",
915 b"ast" | b"midast" => "\u{2A}",
916 b"plus" => "\u{2B}",
917 b"comma" => "\u{2C}",
918 b"period" => "\u{2E}",
919 b"sol" => "\u{2F}",
920 b"colon" => "\u{3A}",
921 b"semi" => "\u{3B}",
922 b"lt" | b"LT" => "\u{3C}",
923 b"equals" => "\u{3D}",
924 b"gt" | b"GT" => "\u{3E}",
925 b"quest" => "\u{3F}",
926 b"commat" => "\u{40}",
927 b"lsqb" | b"lbrack" => "\u{5B}",
928 b"bsol" => "\u{5C}",
929 b"rsqb" | b"rbrack" => "\u{5D}",
930 b"Hat" => "\u{5E}",
931 b"lowbar" => "\u{5F}",
932 b"grave" | b"DiacriticalGrave" => "\u{60}",
933 b"lcub" | b"lbrace" => "\u{7B}",
934 b"verbar" | b"vert" | b"VerticalLine" => "\u{7C}",
935 b"rcub" | b"rbrace" => "\u{7D}",
936 b"nbsp" | b"NonBreakingSpace" => "\u{A0}",
937 b"iexcl" => "\u{A1}",
938 b"cent" => "\u{A2}",
939 b"pound" => "\u{A3}",
940 b"curren" => "\u{A4}",
941 b"yen" => "\u{A5}",
942 b"brvbar" => "\u{A6}",
943 b"sect" => "\u{A7}",
944 b"Dot" | b"die" | b"DoubleDot" | b"uml" => "\u{A8}",
945 b"copy" | b"COPY" => "\u{A9}",
946 b"ordf" => "\u{AA}",
947 b"laquo" => "\u{AB}",
948 b"not" => "\u{AC}",
949 b"shy" => "\u{AD}",
950 b"reg" | b"circledR" | b"REG" => "\u{AE}",
951 b"macr" | b"OverBar" | b"strns" => "\u{AF}",
952 b"deg" => "\u{B0}",
953 b"plusmn" | b"pm" | b"PlusMinus" => "\u{B1}",
954 b"sup2" => "\u{B2}",
955 b"sup3" => "\u{B3}",
956 b"acute" | b"DiacriticalAcute" => "\u{B4}",
957 b"micro" => "\u{B5}",
958 b"para" => "\u{B6}",
959 b"middot" | b"centerdot" | b"CenterDot" => "\u{B7}",
960 b"cedil" | b"Cedilla" => "\u{B8}",
961 b"sup1" => "\u{B9}",
962 b"ordm" => "\u{BA}",
963 b"raquo" => "\u{BB}",
964 b"frac14" => "\u{BC}",
965 b"frac12" | b"half" => "\u{BD}",
966 b"frac34" => "\u{BE}",
967 b"iquest" => "\u{BF}",
968 b"Agrave" => "\u{C0}",
969 b"Aacute" => "\u{C1}",
970 b"Acirc" => "\u{C2}",
971 b"Atilde" => "\u{C3}",
972 b"Auml" => "\u{C4}",
973 b"Aring" => "\u{C5}",
974 b"AElig" => "\u{C6}",
975 b"Ccedil" => "\u{C7}",
976 b"Egrave" => "\u{C8}",
977 b"Eacute" => "\u{C9}",
978 b"Ecirc" => "\u{CA}",
979 b"Euml" => "\u{CB}",
980 b"Igrave" => "\u{CC}",
981 b"Iacute" => "\u{CD}",
982 b"Icirc" => "\u{CE}",
983 b"Iuml" => "\u{CF}",
984 b"ETH" => "\u{D0}",
985 b"Ntilde" => "\u{D1}",
986 b"Ograve" => "\u{D2}",
987 b"Oacute" => "\u{D3}",
988 b"Ocirc" => "\u{D4}",
989 b"Otilde" => "\u{D5}",
990 b"Ouml" => "\u{D6}",
991 b"times" => "\u{D7}",
992 b"Oslash" => "\u{D8}",
993 b"Ugrave" => "\u{D9}",
994 b"Uacute" => "\u{DA}",
995 b"Ucirc" => "\u{DB}",
996 b"Uuml" => "\u{DC}",
997 b"Yacute" => "\u{DD}",
998 b"THORN" => "\u{DE}",
999 b"szlig" => "\u{DF}",
1000 b"agrave" => "\u{E0}",
1001 b"aacute" => "\u{E1}",
1002 b"acirc" => "\u{E2}",
1003 b"atilde" => "\u{E3}",
1004 b"auml" => "\u{E4}",
1005 b"aring" => "\u{E5}",
1006 b"aelig" => "\u{E6}",
1007 b"ccedil" => "\u{E7}",
1008 b"egrave" => "\u{E8}",
1009 b"eacute" => "\u{E9}",
1010 b"ecirc" => "\u{EA}",
1011 b"euml" => "\u{EB}",
1012 b"igrave" => "\u{EC}",
1013 b"iacute" => "\u{ED}",
1014 b"icirc" => "\u{EE}",
1015 b"iuml" => "\u{EF}",
1016 b"eth" => "\u{F0}",
1017 b"ntilde" => "\u{F1}",
1018 b"ograve" => "\u{F2}",
1019 b"oacute" => "\u{F3}",
1020 b"ocirc" => "\u{F4}",
1021 b"otilde" => "\u{F5}",
1022 b"ouml" => "\u{F6}",
1023 b"divide" | b"div" => "\u{F7}",
1024 b"oslash" => "\u{F8}",
1025 b"ugrave" => "\u{F9}",
1026 b"uacute" => "\u{FA}",
1027 b"ucirc" => "\u{FB}",
1028 b"uuml" => "\u{FC}",
1029 b"yacute" => "\u{FD}",
1030 b"thorn" => "\u{FE}",
1031 b"yuml" => "\u{FF}",
1032 b"Amacr" => "\u{10}",
1033 b"amacr" => "\u{10}",
1034 b"Abreve" => "\u{10}",
1035 b"abreve" => "\u{10}",
1036 b"Aogon" => "\u{10}",
1037 b"aogon" => "\u{10}",
1038 b"Cacute" => "\u{10}",
1039 b"cacute" => "\u{10}",
1040 b"Ccirc" => "\u{10}",
1041 b"ccirc" => "\u{10}",
1042 b"Cdot" => "\u{10}",
1043 b"cdot" => "\u{10}",
1044 b"Ccaron" => "\u{10}",
1045 b"ccaron" => "\u{10}",
1046 b"Dcaron" => "\u{10}",
1047 b"dcaron" => "\u{10}",
1048 b"Dstrok" => "\u{11}",
1049 b"dstrok" => "\u{11}",
1050 b"Emacr" => "\u{11}",
1051 b"emacr" => "\u{11}",
1052 b"Edot" => "\u{11}",
1053 b"edot" => "\u{11}",
1054 b"Eogon" => "\u{11}",
1055 b"eogon" => "\u{11}",
1056 b"Ecaron" => "\u{11}",
1057 b"ecaron" => "\u{11}",
1058 b"Gcirc" => "\u{11}",
1059 b"gcirc" => "\u{11}",
1060 b"Gbreve" => "\u{11}",
1061 b"gbreve" => "\u{11}",
1062 b"Gdot" => "\u{12}",
1063 b"gdot" => "\u{12}",
1064 b"Gcedil" => "\u{12}",
1065 b"Hcirc" => "\u{12}",
1066 b"hcirc" => "\u{12}",
1067 b"Hstrok" => "\u{12}",
1068 b"hstrok" => "\u{12}",
1069 b"Itilde" => "\u{12}",
1070 b"itilde" => "\u{12}",
1071 b"Imacr" => "\u{12}",
1072 b"imacr" => "\u{12}",
1073 b"Iogon" => "\u{12}",
1074 b"iogon" => "\u{12}",
1075 b"Idot" => "\u{13}",
1076 b"imath" | b"inodot" => "\u{13}",
1077 b"IJlig" => "\u{13}",
1078 b"ijlig" => "\u{13}",
1079 b"Jcirc" => "\u{13}",
1080 b"jcirc" => "\u{13}",
1081 b"Kcedil" => "\u{13}",
1082 b"kcedil" => "\u{13}",
1083 b"kgreen" => "\u{13}",
1084 b"Lacute" => "\u{13}",
1085 b"lacute" => "\u{13}",
1086 b"Lcedil" => "\u{13}",
1087 b"lcedil" => "\u{13}",
1088 b"Lcaron" => "\u{13}",
1089 b"lcaron" => "\u{13}",
1090 b"Lmidot" => "\u{13}",
1091 b"lmidot" => "\u{14}",
1092 b"Lstrok" => "\u{14}",
1093 b"lstrok" => "\u{14}",
1094 b"Nacute" => "\u{14}",
1095 b"nacute" => "\u{14}",
1096 b"Ncedil" => "\u{14}",
1097 b"ncedil" => "\u{14}",
1098 b"Ncaron" => "\u{14}",
1099 b"ncaron" => "\u{14}",
1100 b"napos" => "\u{14}",
1101 b"ENG" => "\u{14}",
1102 b"eng" => "\u{14}",
1103 b"Omacr" => "\u{14}",
1104 b"omacr" => "\u{14}",
1105 b"Odblac" => "\u{15}",
1106 b"odblac" => "\u{15}",
1107 b"OElig" => "\u{15}",
1108 b"oelig" => "\u{15}",
1109 b"Racute" => "\u{15}",
1110 b"racute" => "\u{15}",
1111 b"Rcedil" => "\u{15}",
1112 b"rcedil" => "\u{15}",
1113 b"Rcaron" => "\u{15}",
1114 b"rcaron" => "\u{15}",
1115 b"Sacute" => "\u{15}",
1116 b"sacute" => "\u{15}",
1117 b"Scirc" => "\u{15}",
1118 b"scirc" => "\u{15}",
1119 b"Scedil" => "\u{15}",
1120 b"scedil" => "\u{15}",
1121 b"Scaron" => "\u{16}",
1122 b"scaron" => "\u{16}",
1123 b"Tcedil" => "\u{16}",
1124 b"tcedil" => "\u{16}",
1125 b"Tcaron" => "\u{16}",
1126 b"tcaron" => "\u{16}",
1127 b"Tstrok" => "\u{16}",
1128 b"tstrok" => "\u{16}",
1129 b"Utilde" => "\u{16}",
1130 b"utilde" => "\u{16}",
1131 b"Umacr" => "\u{16}",
1132 b"umacr" => "\u{16}",
1133 b"Ubreve" => "\u{16}",
1134 b"ubreve" => "\u{16}",
1135 b"Uring" => "\u{16}",
1136 b"uring" => "\u{16}",
1137 b"Udblac" => "\u{17}",
1138 b"udblac" => "\u{17}",
1139 b"Uogon" => "\u{17}",
1140 b"uogon" => "\u{17}",
1141 b"Wcirc" => "\u{17}",
1142 b"wcirc" => "\u{17}",
1143 b"Ycirc" => "\u{17}",
1144 b"ycirc" => "\u{17}",
1145 b"Yuml" => "\u{17}",
1146 b"Zacute" => "\u{17}",
1147 b"zacute" => "\u{17}",
1148 b"Zdot" => "\u{17}",
1149 b"zdot" => "\u{17}",
1150 b"Zcaron" => "\u{17}",
1151 b"zcaron" => "\u{17}",
1152 b"fnof" => "\u{19}",
1153 b"imped" => "\u{1B}",
1154 b"gacute" => "\u{1F}",
1155 b"jmath" => "\u{23}",
1156 b"circ" => "\u{2C}",
1157 b"caron" | b"Hacek" => "\u{2C}",
1158 b"breve" | b"Breve" => "\u{2D}",
1159 b"dot" | b"DiacriticalDot" => "\u{2D}",
1160 b"ring" => "\u{2D}",
1161 b"ogon" => "\u{2D}",
1162 b"tilde" | b"DiacriticalTilde" => "\u{2D}",
1163 b"dblac" | b"DiacriticalDoubleAcute" => "\u{2D}",
1164 b"DownBreve" => "\u{31}",
1165 b"UnderBar" => "\u{33}",
1166 b"Alpha" => "\u{39}",
1167 b"Beta" => "\u{39}",
1168 b"Gamma" => "\u{39}",
1169 b"Delta" => "\u{39}",
1170 b"Epsilon" => "\u{39}",
1171 b"Zeta" => "\u{39}",
1172 b"Eta" => "\u{39}",
1173 b"Theta" => "\u{39}",
1174 b"Iota" => "\u{39}",
1175 b"Kappa" => "\u{39}",
1176 b"Lambda" => "\u{39}",
1177 b"Mu" => "\u{39}",
1178 b"Nu" => "\u{39}",
1179 b"Xi" => "\u{39}",
1180 b"Omicron" => "\u{39}",
1181 b"Pi" => "\u{3A}",
1182 b"Rho" => "\u{3A}",
1183 b"Sigma" => "\u{3A}",
1184 b"Tau" => "\u{3A}",
1185 b"Upsilon" => "\u{3A}",
1186 b"Phi" => "\u{3A}",
1187 b"Chi" => "\u{3A}",
1188 b"Psi" => "\u{3A}",
1189 b"Omega" => "\u{3A}",
1190 b"alpha" => "\u{3B}",
1191 b"beta" => "\u{3B}",
1192 b"gamma" => "\u{3B}",
1193 b"delta" => "\u{3B}",
1194 b"epsiv" | b"varepsilon" | b"epsilon" => "\u{3B}",
1195 b"zeta" => "\u{3B}",
1196 b"eta" => "\u{3B}",
1197 b"theta" => "\u{3B}",
1198 b"iota" => "\u{3B}",
1199 b"kappa" => "\u{3B}",
1200 b"lambda" => "\u{3B}",
1201 b"mu" => "\u{3B}",
1202 b"nu" => "\u{3B}",
1203 b"xi" => "\u{3B}",
1204 b"omicron" => "\u{3B}",
1205 b"pi" => "\u{3C}",
1206 b"rho" => "\u{3C}",
1207 b"sigmav" | b"varsigma" | b"sigmaf" => "\u{3C}",
1208 b"sigma" => "\u{3C}",
1209 b"tau" => "\u{3C}",
1210 b"upsi" | b"upsilon" => "\u{3C}",
1211 b"phi" | b"phiv" | b"varphi" => "\u{3C}",
1212 b"chi" => "\u{3C}",
1213 b"psi" => "\u{3C}",
1214 b"omega" => "\u{3C}",
1215 b"thetav" | b"vartheta" | b"thetasym" => "\u{3D}",
1216 b"Upsi" | b"upsih" => "\u{3D}",
1217 b"straightphi" => "\u{3D}",
1218 b"piv" | b"varpi" => "\u{3D}",
1219 b"Gammad" => "\u{3D}",
1220 b"gammad" | b"digamma" => "\u{3D}",
1221 b"kappav" | b"varkappa" => "\u{3F}",
1222 b"rhov" | b"varrho" => "\u{3F}",
1223 b"epsi" | b"straightepsilon" => "\u{3F}",
1224 b"bepsi" | b"backepsilon" => "\u{3F}",
1225 b"IOcy" => "\u{40}",
1226 b"DJcy" => "\u{40}",
1227 b"GJcy" => "\u{40}",
1228 b"Jukcy" => "\u{40}",
1229 b"DScy" => "\u{40}",
1230 b"Iukcy" => "\u{40}",
1231 b"YIcy" => "\u{40}",
1232 b"Jsercy" => "\u{40}",
1233 b"LJcy" => "\u{40}",
1234 b"NJcy" => "\u{40}",
1235 b"TSHcy" => "\u{40}",
1236 b"KJcy" => "\u{40}",
1237 b"Ubrcy" => "\u{40}",
1238 b"DZcy" => "\u{40}",
1239 b"Acy" => "\u{41}",
1240 b"Bcy" => "\u{41}",
1241 b"Vcy" => "\u{41}",
1242 b"Gcy" => "\u{41}",
1243 b"Dcy" => "\u{41}",
1244 b"IEcy" => "\u{41}",
1245 b"ZHcy" => "\u{41}",
1246 b"Zcy" => "\u{41}",
1247 b"Icy" => "\u{41}",
1248 b"Jcy" => "\u{41}",
1249 b"Kcy" => "\u{41}",
1250 b"Lcy" => "\u{41}",
1251 b"Mcy" => "\u{41}",
1252 b"Ncy" => "\u{41}",
1253 b"Ocy" => "\u{41}",
1254 b"Pcy" => "\u{41}",
1255 b"Rcy" => "\u{42}",
1256 b"Scy" => "\u{42}",
1257 b"Tcy" => "\u{42}",
1258 b"Ucy" => "\u{42}",
1259 b"Fcy" => "\u{42}",
1260 b"KHcy" => "\u{42}",
1261 b"TScy" => "\u{42}",
1262 b"CHcy" => "\u{42}",
1263 b"SHcy" => "\u{42}",
1264 b"SHCHcy" => "\u{42}",
1265 b"HARDcy" => "\u{42}",
1266 b"Ycy" => "\u{42}",
1267 b"SOFTcy" => "\u{42}",
1268 b"Ecy" => "\u{42}",
1269 b"YUcy" => "\u{42}",
1270 b"YAcy" => "\u{42}",
1271 b"acy" => "\u{43}",
1272 b"bcy" => "\u{43}",
1273 b"vcy" => "\u{43}",
1274 b"gcy" => "\u{43}",
1275 b"dcy" => "\u{43}",
1276 b"iecy" => "\u{43}",
1277 b"zhcy" => "\u{43}",
1278 b"zcy" => "\u{43}",
1279 b"icy" => "\u{43}",
1280 b"jcy" => "\u{43}",
1281 b"kcy" => "\u{43}",
1282 b"lcy" => "\u{43}",
1283 b"mcy" => "\u{43}",
1284 b"ncy" => "\u{43}",
1285 b"ocy" => "\u{43}",
1286 b"pcy" => "\u{43}",
1287 b"rcy" => "\u{44}",
1288 b"scy" => "\u{44}",
1289 b"tcy" => "\u{44}",
1290 b"ucy" => "\u{44}",
1291 b"fcy" => "\u{44}",
1292 b"khcy" => "\u{44}",
1293 b"tscy" => "\u{44}",
1294 b"chcy" => "\u{44}",
1295 b"shcy" => "\u{44}",
1296 b"shchcy" => "\u{44}",
1297 b"hardcy" => "\u{44}",
1298 b"ycy" => "\u{44}",
1299 b"softcy" => "\u{44}",
1300 b"ecy" => "\u{44}",
1301 b"yucy" => "\u{44}",
1302 b"yacy" => "\u{44}",
1303 b"iocy" => "\u{45}",
1304 b"djcy" => "\u{45}",
1305 b"gjcy" => "\u{45}",
1306 b"jukcy" => "\u{45}",
1307 b"dscy" => "\u{45}",
1308 b"iukcy" => "\u{45}",
1309 b"yicy" => "\u{45}",
1310 b"jsercy" => "\u{45}",
1311 b"ljcy" => "\u{45}",
1312 b"njcy" => "\u{45}",
1313 b"tshcy" => "\u{45}",
1314 b"kjcy" => "\u{45}",
1315 b"ubrcy" => "\u{45}",
1316 b"dzcy" => "\u{45}",
1317 b"ensp" => "\u{2002}",
1318 b"emsp" => "\u{2003}",
1319 b"emsp13" => "\u{2004}",
1320 b"emsp14" => "\u{2005}",
1321 b"numsp" => "\u{2007}",
1322 b"puncsp" => "\u{2008}",
1323 b"thinsp" | b"ThinSpace" => "\u{2009}",
1324 b"hairsp" | b"VeryThinSpace" => "\u{200A}",
1325 b"ZeroWidthSpace"
1326 | b"NegativeVeryThinSpace"
1327 | b"NegativeThinSpace"
1328 | b"NegativeMediumSpace"
1329 | b"NegativeThickSpace" => "\u{200B}",
1330 b"zwnj" => "\u{200C}",
1331 b"zwj" => "\u{200D}",
1332 b"lrm" => "\u{200E}",
1333 b"rlm" => "\u{200F}",
1334 b"hyphen" | b"dash" => "\u{2010}",
1335 b"ndash" => "\u{2013}",
1336 b"mdash" => "\u{2014}",
1337 b"horbar" => "\u{2015}",
1338 b"Verbar" | b"Vert" => "\u{2016}",
1339 b"lsquo" | b"OpenCurlyQuote" => "\u{2018}",
1340 b"rsquo" | b"rsquor" | b"CloseCurlyQuote" => "\u{2019}",
1341 b"lsquor" | b"sbquo" => "\u{201A}",
1342 b"ldquo" | b"OpenCurlyDoubleQuote" => "\u{201C}",
1343 b"rdquo" | b"rdquor" | b"CloseCurlyDoubleQuote" => "\u{201D}",
1344 b"ldquor" | b"bdquo" => "\u{201E}",
1345 b"dagger" => "\u{2020}",
1346 b"Dagger" | b"ddagger" => "\u{2021}",
1347 b"bull" | b"bullet" => "\u{2022}",
1348 b"nldr" => "\u{2025}",
1349 b"hellip" | b"mldr" => "\u{2026}",
1350 b"permil" => "\u{2030}",
1351 b"pertenk" => "\u{2031}",
1352 b"prime" => "\u{2032}",
1353 b"Prime" => "\u{2033}",
1354 b"tprime" => "\u{2034}",
1355 b"bprime" | b"backprime" => "\u{2035}",
1356 b"lsaquo" => "\u{2039}",
1357 b"rsaquo" => "\u{203A}",
1358 b"oline" => "\u{203E}",
1359 b"caret" => "\u{2041}",
1360 b"hybull" => "\u{2043}",
1361 b"frasl" => "\u{2044}",
1362 b"bsemi" => "\u{204F}",
1363 b"qprime" => "\u{2057}",
1364 b"MediumSpace" => "\u{205F}",
1365 b"NoBreak" => "\u{2060}",
1366 b"ApplyFunction" | b"af" => "\u{2061}",
1367 b"InvisibleTimes" | b"it" => "\u{2062}",
1368 b"InvisibleComma" | b"ic" => "\u{2063}",
1369 b"euro" => "\u{20AC}",
1370 b"tdot" | b"TripleDot" => "\u{20DB}",
1371 b"DotDot" => "\u{20DC}",
1372 b"Copf" | b"complexes" => "\u{2102}",
1373 b"incare" => "\u{2105}",
1374 b"gscr" => "\u{210A}",
1375 b"hamilt" | b"HilbertSpace" | b"Hscr" => "\u{210B}",
1376 b"Hfr" | b"Poincareplane" => "\u{210C}",
1377 b"quaternions" | b"Hopf" => "\u{210D}",
1378 b"planckh" => "\u{210E}",
1379 b"planck" | b"hbar" | b"plankv" | b"hslash" => "\u{210F}",
1380 b"Iscr" | b"imagline" => "\u{2110}",
1381 b"image" | b"Im" | b"imagpart" | b"Ifr" => "\u{2111}",
1382 b"Lscr" | b"lagran" | b"Laplacetrf" => "\u{2112}",
1383 b"ell" => "\u{2113}",
1384 b"Nopf" | b"naturals" => "\u{2115}",
1385 b"numero" => "\u{2116}",
1386 b"copysr" => "\u{2117}",
1387 b"weierp" | b"wp" => "\u{2118}",
1388 b"Popf" | b"primes" => "\u{2119}",
1389 b"rationals" | b"Qopf" => "\u{211A}",
1390 b"Rscr" | b"realine" => "\u{211B}",
1391 b"real" | b"Re" | b"realpart" | b"Rfr" => "\u{211C}",
1392 b"reals" | b"Ropf" => "\u{211D}",
1393 b"rx" => "\u{211E}",
1394 b"trade" | b"TRADE" => "\u{2122}",
1395 b"integers" | b"Zopf" => "\u{2124}",
1396 b"ohm" => "\u{2126}",
1397 b"mho" => "\u{2127}",
1398 b"Zfr" | b"zeetrf" => "\u{2128}",
1399 b"iiota" => "\u{2129}",
1400 b"angst" => "\u{212B}",
1401 b"bernou" | b"Bernoullis" | b"Bscr" => "\u{212C}",
1402 b"Cfr" | b"Cayleys" => "\u{212D}",
1403 b"escr" => "\u{212F}",
1404 b"Escr" | b"expectation" => "\u{2130}",
1405 b"Fscr" | b"Fouriertrf" => "\u{2131}",
1406 b"phmmat" | b"Mellintrf" | b"Mscr" => "\u{2133}",
1407 b"order" | b"orderof" | b"oscr" => "\u{2134}",
1408 b"alefsym" | b"aleph" => "\u{2135}",
1409 b"beth" => "\u{2136}",
1410 b"gimel" => "\u{2137}",
1411 b"daleth" => "\u{2138}",
1412 b"CapitalDifferentialD" | b"DD" => "\u{2145}",
1413 b"DifferentialD" | b"dd" => "\u{2146}",
1414 b"ExponentialE" | b"exponentiale" | b"ee" => "\u{2147}",
1415 b"ImaginaryI" | b"ii" => "\u{2148}",
1416 b"frac13" => "\u{2153}",
1417 b"frac23" => "\u{2154}",
1418 b"frac15" => "\u{2155}",
1419 b"frac25" => "\u{2156}",
1420 b"frac35" => "\u{2157}",
1421 b"frac45" => "\u{2158}",
1422 b"frac16" => "\u{2159}",
1423 b"frac56" => "\u{215A}",
1424 b"frac18" => "\u{215B}",
1425 b"frac38" => "\u{215C}",
1426 b"frac58" => "\u{215D}",
1427 b"frac78" => "\u{215E}",
1428 b"larr" | b"leftarrow" | b"LeftArrow" | b"slarr" | b"ShortLeftArrow" => "\u{2190}",
1429 b"uarr" | b"uparrow" | b"UpArrow" | b"ShortUpArrow" => "\u{2191}",
1430 b"rarr" | b"rightarrow" | b"RightArrow" | b"srarr" | b"ShortRightArrow" => "\u{2192}",
1431 b"darr" | b"downarrow" | b"DownArrow" | b"ShortDownArrow" => "\u{2193}",
1432 b"harr" | b"leftrightarrow" | b"LeftRightArrow" => "\u{2194}",
1433 b"varr" | b"updownarrow" | b"UpDownArrow" => "\u{2195}",
1434 b"nwarr" | b"UpperLeftArrow" | b"nwarrow" => "\u{2196}",
1435 b"nearr" | b"UpperRightArrow" | b"nearrow" => "\u{2197}",
1436 b"searr" | b"searrow" | b"LowerRightArrow" => "\u{2198}",
1437 b"swarr" | b"swarrow" | b"LowerLeftArrow" => "\u{2199}",
1438 b"nlarr" | b"nleftarrow" => "\u{219A}",
1439 b"nrarr" | b"nrightarrow" => "\u{219B}",
1440 b"rarrw" | b"rightsquigarrow" => "\u{219D}",
1441 b"Larr" | b"twoheadleftarrow" => "\u{219E}",
1442 b"Uarr" => "\u{219F}",
1443 b"Rarr" | b"twoheadrightarrow" => "\u{21A0}",
1444 b"Darr" => "\u{21A1}",
1445 b"larrtl" | b"leftarrowtail" => "\u{21A2}",
1446 b"rarrtl" | b"rightarrowtail" => "\u{21A3}",
1447 b"LeftTeeArrow" | b"mapstoleft" => "\u{21A4}",
1448 b"UpTeeArrow" | b"mapstoup" => "\u{21A5}",
1449 b"map" | b"RightTeeArrow" | b"mapsto" => "\u{21A6}",
1450 b"DownTeeArrow" | b"mapstodown" => "\u{21A7}",
1451 b"larrhk" | b"hookleftarrow" => "\u{21A9}",
1452 b"rarrhk" | b"hookrightarrow" => "\u{21AA}",
1453 b"larrlp" | b"looparrowleft" => "\u{21AB}",
1454 b"rarrlp" | b"looparrowright" => "\u{21AC}",
1455 b"harrw" | b"leftrightsquigarrow" => "\u{21AD}",
1456 b"nharr" | b"nleftrightarrow" => "\u{21AE}",
1457 b"lsh" | b"Lsh" => "\u{21B0}",
1458 b"rsh" | b"Rsh" => "\u{21B1}",
1459 b"ldsh" => "\u{21B2}",
1460 b"rdsh" => "\u{21B3}",
1461 b"crarr" => "\u{21B5}",
1462 b"cularr" | b"curvearrowleft" => "\u{21B6}",
1463 b"curarr" | b"curvearrowright" => "\u{21B7}",
1464 b"olarr" | b"circlearrowleft" => "\u{21BA}",
1465 b"orarr" | b"circlearrowright" => "\u{21BB}",
1466 b"lharu" | b"LeftVector" | b"leftharpoonup" => "\u{21BC}",
1467 b"lhard" | b"leftharpoondown" | b"DownLeftVector" => "\u{21BD}",
1468 b"uharr" | b"upharpoonright" | b"RightUpVector" => "\u{21BE}",
1469 b"uharl" | b"upharpoonleft" | b"LeftUpVector" => "\u{21BF}",
1470 b"rharu" | b"RightVector" | b"rightharpoonup" => "\u{21C0}",
1471 b"rhard" | b"rightharpoondown" | b"DownRightVector" => "\u{21C1}",
1472 b"dharr" | b"RightDownVector" | b"downharpoonright" => "\u{21C2}",
1473 b"dharl" | b"LeftDownVector" | b"downharpoonleft" => "\u{21C3}",
1474 b"rlarr" | b"rightleftarrows" | b"RightArrowLeftArrow" => "\u{21C4}",
1475 b"udarr" | b"UpArrowDownArrow" => "\u{21C5}",
1476 b"lrarr" | b"leftrightarrows" | b"LeftArrowRightArrow" => "\u{21C6}",
1477 b"llarr" | b"leftleftarrows" => "\u{21C7}",
1478 b"uuarr" | b"upuparrows" => "\u{21C8}",
1479 b"rrarr" | b"rightrightarrows" => "\u{21C9}",
1480 b"ddarr" | b"downdownarrows" => "\u{21CA}",
1481 b"lrhar" | b"ReverseEquilibrium" | b"leftrightharpoons" => "\u{21CB}",
1482 b"rlhar" | b"rightleftharpoons" | b"Equilibrium" => "\u{21CC}",
1483 b"nlArr" | b"nLeftarrow" => "\u{21CD}",
1484 b"nhArr" | b"nLeftrightarrow" => "\u{21CE}",
1485 b"nrArr" | b"nRightarrow" => "\u{21CF}",
1486 b"lArr" | b"Leftarrow" | b"DoubleLeftArrow" => "\u{21D0}",
1487 b"uArr" | b"Uparrow" | b"DoubleUpArrow" => "\u{21D1}",
1488 b"rArr" | b"Rightarrow" | b"Implies" | b"DoubleRightArrow" => "\u{21D2}",
1489 b"dArr" | b"Downarrow" | b"DoubleDownArrow" => "\u{21D3}",
1490 b"hArr" | b"Leftrightarrow" | b"DoubleLeftRightArrow" | b"iff" => "\u{21D4}",
1491 b"vArr" | b"Updownarrow" | b"DoubleUpDownArrow" => "\u{21D5}",
1492 b"nwArr" => "\u{21D6}",
1493 b"neArr" => "\u{21D7}",
1494 b"seArr" => "\u{21D8}",
1495 b"swArr" => "\u{21D9}",
1496 b"lAarr" | b"Lleftarrow" => "\u{21DA}",
1497 b"rAarr" | b"Rrightarrow" => "\u{21DB}",
1498 b"zigrarr" => "\u{21DD}",
1499 b"larrb" | b"LeftArrowBar" => "\u{21E4}",
1500 b"rarrb" | b"RightArrowBar" => "\u{21E5}",
1501 b"duarr" | b"DownArrowUpArrow" => "\u{21F5}",
1502 b"loarr" => "\u{21FD}",
1503 b"roarr" => "\u{21FE}",
1504 b"hoarr" => "\u{21FF}",
1505 b"forall" | b"ForAll" => "\u{2200}",
1506 b"comp" | b"complement" => "\u{2201}",
1507 b"part" | b"PartialD" => "\u{2202}",
1508 b"exist" | b"Exists" => "\u{2203}",
1509 b"nexist" | b"NotExists" | b"nexists" => "\u{2204}",
1510 b"empty" | b"emptyset" | b"emptyv" | b"varnothing" => "\u{2205}",
1511 b"nabla" | b"Del" => "\u{2207}",
1512 b"isin" | b"isinv" | b"Element" | b"in" => "\u{2208}",
1513 b"notin" | b"NotElement" | b"notinva" => "\u{2209}",
1514 b"niv" | b"ReverseElement" | b"ni" | b"SuchThat" => "\u{220B}",
1515 b"notni" | b"notniva" | b"NotReverseElement" => "\u{220C}",
1516 b"prod" | b"Product" => "\u{220F}",
1517 b"coprod" | b"Coproduct" => "\u{2210}",
1518 b"sum" | b"Sum" => "\u{2211}",
1519 b"minus" => "\u{2212}",
1520 b"mnplus" | b"mp" | b"MinusPlus" => "\u{2213}",
1521 b"plusdo" | b"dotplus" => "\u{2214}",
1522 b"setmn" | b"setminus" | b"Backslash" | b"ssetmn" | b"smallsetminus" => "\u{2216}",
1523 b"lowast" => "\u{2217}",
1524 b"compfn" | b"SmallCircle" => "\u{2218}",
1525 b"radic" | b"Sqrt" => "\u{221A}",
1526 b"prop" | b"propto" | b"Proportional" | b"vprop" | b"varpropto" => "\u{221D}",
1527 b"infin" => "\u{221E}",
1528 b"angrt" => "\u{221F}",
1529 b"ang" | b"angle" => "\u{2220}",
1530 b"angmsd" | b"measuredangle" => "\u{2221}",
1531 b"angsph" => "\u{2222}",
1532 b"mid" | b"VerticalBar" | b"smid" | b"shortmid" => "\u{2223}",
1533 b"nmid" | b"NotVerticalBar" | b"nsmid" | b"nshortmid" => "\u{2224}",
1534 b"par" | b"parallel" | b"DoubleVerticalBar" | b"spar" | b"shortparallel" => "\u{2225}",
1535 b"npar" | b"nparallel" | b"NotDoubleVerticalBar" | b"nspar" | b"nshortparallel" => {
1536 "\u{2226}"
1537 }
1538 b"and" | b"wedge" => "\u{2227}",
1539 b"or" | b"vee" => "\u{2228}",
1540 b"cap" => "\u{2229}",
1541 b"cup" => "\u{222A}",
1542 b"int" | b"Integral" => "\u{222B}",
1543 b"Int" => "\u{222C}",
1544 b"tint" | b"iiint" => "\u{222D}",
1545 b"conint" | b"oint" | b"ContourIntegral" => "\u{222E}",
1546 b"Conint" | b"DoubleContourIntegral" => "\u{222F}",
1547 b"Cconint" => "\u{2230}",
1548 b"cwint" => "\u{2231}",
1549 b"cwconint" | b"ClockwiseContourIntegral" => "\u{2232}",
1550 b"awconint" | b"CounterClockwiseContourIntegral" => "\u{2233}",
1551 b"there4" | b"therefore" | b"Therefore" => "\u{2234}",
1552 b"becaus" | b"because" | b"Because" => "\u{2235}",
1553 b"ratio" => "\u{2236}",
1554 b"Colon" | b"Proportion" => "\u{2237}",
1555 b"minusd" | b"dotminus" => "\u{2238}",
1556 b"mDDot" => "\u{223A}",
1557 b"homtht" => "\u{223B}",
1558 b"sim" | b"Tilde" | b"thksim" | b"thicksim" => "\u{223C}",
1559 b"bsim" | b"backsim" => "\u{223D}",
1560 b"ac" | b"mstpos" => "\u{223E}",
1561 b"acd" => "\u{223F}",
1562 b"wreath" | b"VerticalTilde" | b"wr" => "\u{2240}",
1563 b"nsim" | b"NotTilde" => "\u{2241}",
1564 b"esim" | b"EqualTilde" | b"eqsim" => "\u{2242}",
1565 b"sime" | b"TildeEqual" | b"simeq" => "\u{2243}",
1566 b"nsime" | b"nsimeq" | b"NotTildeEqual" => "\u{2244}",
1567 b"cong" | b"TildeFullEqual" => "\u{2245}",
1568 b"simne" => "\u{2246}",
1569 b"ncong" | b"NotTildeFullEqual" => "\u{2247}",
1570 b"asymp" | b"ap" | b"TildeTilde" | b"approx" | b"thkap" | b"thickapprox" => "\u{2248}",
1571 b"nap" | b"NotTildeTilde" | b"napprox" => "\u{2249}",
1572 b"ape" | b"approxeq" => "\u{224A}",
1573 b"apid" => "\u{224B}",
1574 b"bcong" | b"backcong" => "\u{224C}",
1575 b"asympeq" | b"CupCap" => "\u{224D}",
1576 b"bump" | b"HumpDownHump" | b"Bumpeq" => "\u{224E}",
1577 b"bumpe" | b"HumpEqual" | b"bumpeq" => "\u{224F}",
1578 b"esdot" | b"DotEqual" | b"doteq" => "\u{2250}",
1579 b"eDot" | b"doteqdot" => "\u{2251}",
1580 b"efDot" | b"fallingdotseq" => "\u{2252}",
1581 b"erDot" | b"risingdotseq" => "\u{2253}",
1582 b"colone" | b"coloneq" | b"Assign" => "\u{2254}",
1583 b"ecolon" | b"eqcolon" => "\u{2255}",
1584 b"ecir" | b"eqcirc" => "\u{2256}",
1585 b"cire" | b"circeq" => "\u{2257}",
1586 b"wedgeq" => "\u{2259}",
1587 b"veeeq" => "\u{225A}",
1588 b"trie" | b"triangleq" => "\u{225C}",
1589 b"equest" | b"questeq" => "\u{225F}",
1590 b"ne" | b"NotEqual" => "\u{2260}",
1591 b"equiv" | b"Congruent" => "\u{2261}",
1592 b"nequiv" | b"NotCongruent" => "\u{2262}",
1593 b"le" | b"leq" => "\u{2264}",
1594 b"ge" | b"GreaterEqual" | b"geq" => "\u{2265}",
1595 b"lE" | b"LessFullEqual" | b"leqq" => "\u{2266}",
1596 b"gE" | b"GreaterFullEqual" | b"geqq" => "\u{2267}",
1597 b"lnE" | b"lneqq" => "\u{2268}",
1598 b"gnE" | b"gneqq" => "\u{2269}",
1599 b"Lt" | b"NestedLessLess" | b"ll" => "\u{226A}",
1600 b"Gt" | b"NestedGreaterGreater" | b"gg" => "\u{226B}",
1601 b"twixt" | b"between" => "\u{226C}",
1602 b"NotCupCap" => "\u{226D}",
1603 b"nlt" | b"NotLess" | b"nless" => "\u{226E}",
1604 b"ngt" | b"NotGreater" | b"ngtr" => "\u{226F}",
1605 b"nle" | b"NotLessEqual" | b"nleq" => "\u{2270}",
1606 b"nge" | b"NotGreaterEqual" | b"ngeq" => "\u{2271}",
1607 b"lsim" | b"LessTilde" | b"lesssim" => "\u{2272}",
1608 b"gsim" | b"gtrsim" | b"GreaterTilde" => "\u{2273}",
1609 b"nlsim" | b"NotLessTilde" => "\u{2274}",
1610 b"ngsim" | b"NotGreaterTilde" => "\u{2275}",
1611 b"lg" | b"lessgtr" | b"LessGreater" => "\u{2276}",
1612 b"gl" | b"gtrless" | b"GreaterLess" => "\u{2277}",
1613 b"ntlg" | b"NotLessGreater" => "\u{2278}",
1614 b"ntgl" | b"NotGreaterLess" => "\u{2279}",
1615 b"pr" | b"Precedes" | b"prec" => "\u{227A}",
1616 b"sc" | b"Succeeds" | b"succ" => "\u{227B}",
1617 b"prcue" | b"PrecedesSlantEqual" | b"preccurlyeq" => "\u{227C}",
1618 b"sccue" | b"SucceedsSlantEqual" | b"succcurlyeq" => "\u{227D}",
1619 b"prsim" | b"precsim" | b"PrecedesTilde" => "\u{227E}",
1620 b"scsim" | b"succsim" | b"SucceedsTilde" => "\u{227F}",
1621 b"npr" | b"nprec" | b"NotPrecedes" => "\u{2280}",
1622 b"nsc" | b"nsucc" | b"NotSucceeds" => "\u{2281}",
1623 b"sub" | b"subset" => "\u{2282}",
1624 b"sup" | b"supset" | b"Superset" => "\u{2283}",
1625 b"nsub" => "\u{2284}",
1626 b"nsup" => "\u{2285}",
1627 b"sube" | b"SubsetEqual" | b"subseteq" => "\u{2286}",
1628 b"supe" | b"supseteq" | b"SupersetEqual" => "\u{2287}",
1629 b"nsube" | b"nsubseteq" | b"NotSubsetEqual" => "\u{2288}",
1630 b"nsupe" | b"nsupseteq" | b"NotSupersetEqual" => "\u{2289}",
1631 b"subne" | b"subsetneq" => "\u{228A}",
1632 b"supne" | b"supsetneq" => "\u{228B}",
1633 b"cupdot" => "\u{228D}",
1634 b"uplus" | b"UnionPlus" => "\u{228E}",
1635 b"sqsub" | b"SquareSubset" | b"sqsubset" => "\u{228F}",
1636 b"sqsup" | b"SquareSuperset" | b"sqsupset" => "\u{2290}",
1637 b"sqsube" | b"SquareSubsetEqual" | b"sqsubseteq" => "\u{2291}",
1638 b"sqsupe" | b"SquareSupersetEqual" | b"sqsupseteq" => "\u{2292}",
1639 b"sqcap" | b"SquareIntersection" => "\u{2293}",
1640 b"sqcup" | b"SquareUnion" => "\u{2294}",
1641 b"oplus" | b"CirclePlus" => "\u{2295}",
1642 b"ominus" | b"CircleMinus" => "\u{2296}",
1643 b"otimes" | b"CircleTimes" => "\u{2297}",
1644 b"osol" => "\u{2298}",
1645 b"odot" | b"CircleDot" => "\u{2299}",
1646 b"ocir" | b"circledcirc" => "\u{229A}",
1647 b"oast" | b"circledast" => "\u{229B}",
1648 b"odash" | b"circleddash" => "\u{229D}",
1649 b"plusb" | b"boxplus" => "\u{229E}",
1650 b"minusb" | b"boxminus" => "\u{229F}",
1651 b"timesb" | b"boxtimes" => "\u{22A0}",
1652 b"sdotb" | b"dotsquare" => "\u{22A1}",
1653 b"vdash" | b"RightTee" => "\u{22A2}",
1654 b"dashv" | b"LeftTee" => "\u{22A3}",
1655 b"top" | b"DownTee" => "\u{22A4}",
1656 b"bottom" | b"bot" | b"perp" | b"UpTee" => "\u{22A5}",
1657 b"models" => "\u{22A7}",
1658 b"vDash" | b"DoubleRightTee" => "\u{22A8}",
1659 b"Vdash" => "\u{22A9}",
1660 b"Vvdash" => "\u{22AA}",
1661 b"VDash" => "\u{22AB}",
1662 b"nvdash" => "\u{22AC}",
1663 b"nvDash" => "\u{22AD}",
1664 b"nVdash" => "\u{22AE}",
1665 b"nVDash" => "\u{22AF}",
1666 b"prurel" => "\u{22B0}",
1667 b"vltri" | b"vartriangleleft" | b"LeftTriangle" => "\u{22B2}",
1668 b"vrtri" | b"vartriangleright" | b"RightTriangle" => "\u{22B3}",
1669 b"ltrie" | b"trianglelefteq" | b"LeftTriangleEqual" => "\u{22B4}",
1670 b"rtrie" | b"trianglerighteq" | b"RightTriangleEqual" => "\u{22B5}",
1671 b"origof" => "\u{22B6}",
1672 b"imof" => "\u{22B7}",
1673 b"mumap" | b"multimap" => "\u{22B8}",
1674 b"hercon" => "\u{22B9}",
1675 b"intcal" | b"intercal" => "\u{22BA}",
1676 b"veebar" => "\u{22BB}",
1677 b"barvee" => "\u{22BD}",
1678 b"angrtvb" => "\u{22BE}",
1679 b"lrtri" => "\u{22BF}",
1680 b"xwedge" | b"Wedge" | b"bigwedge" => "\u{22C0}",
1681 b"xvee" | b"Vee" | b"bigvee" => "\u{22C1}",
1682 b"xcap" | b"Intersection" | b"bigcap" => "\u{22C2}",
1683 b"xcup" | b"Union" | b"bigcup" => "\u{22C3}",
1684 b"diam" | b"diamond" | b"Diamond" => "\u{22C4}",
1685 b"sdot" => "\u{22C5}",
1686 b"sstarf" | b"Star" => "\u{22C6}",
1687 b"divonx" | b"divideontimes" => "\u{22C7}",
1688 b"bowtie" => "\u{22C8}",
1689 b"ltimes" => "\u{22C9}",
1690 b"rtimes" => "\u{22CA}",
1691 b"lthree" | b"leftthreetimes" => "\u{22CB}",
1692 b"rthree" | b"rightthreetimes" => "\u{22CC}",
1693 b"bsime" | b"backsimeq" => "\u{22CD}",
1694 b"cuvee" | b"curlyvee" => "\u{22CE}",
1695 b"cuwed" | b"curlywedge" => "\u{22CF}",
1696 b"Sub" | b"Subset" => "\u{22D0}",
1697 b"Sup" | b"Supset" => "\u{22D1}",
1698 b"Cap" => "\u{22D2}",
1699 b"Cup" => "\u{22D3}",
1700 b"fork" | b"pitchfork" => "\u{22D4}",
1701 b"epar" => "\u{22D5}",
1702 b"ltdot" | b"lessdot" => "\u{22D6}",
1703 b"gtdot" | b"gtrdot" => "\u{22D7}",
1704 b"Ll" => "\u{22D8}",
1705 b"Gg" | b"ggg" => "\u{22D9}",
1706 b"leg" | b"LessEqualGreater" | b"lesseqgtr" => "\u{22DA}",
1707 b"gel" | b"gtreqless" | b"GreaterEqualLess" => "\u{22DB}",
1708 b"cuepr" | b"curlyeqprec" => "\u{22DE}",
1709 b"cuesc" | b"curlyeqsucc" => "\u{22DF}",
1710 b"nprcue" | b"NotPrecedesSlantEqual" => "\u{22E0}",
1711 b"nsccue" | b"NotSucceedsSlantEqual" => "\u{22E1}",
1712 b"nsqsube" | b"NotSquareSubsetEqual" => "\u{22E2}",
1713 b"nsqsupe" | b"NotSquareSupersetEqual" => "\u{22E3}",
1714 b"lnsim" => "\u{22E6}",
1715 b"gnsim" => "\u{22E7}",
1716 b"prnsim" | b"precnsim" => "\u{22E8}",
1717 b"scnsim" | b"succnsim" => "\u{22E9}",
1718 b"nltri" | b"ntriangleleft" | b"NotLeftTriangle" => "\u{22EA}",
1719 b"nrtri" | b"ntriangleright" | b"NotRightTriangle" => "\u{22EB}",
1720 b"nltrie" | b"ntrianglelefteq" | b"NotLeftTriangleEqual" => "\u{22EC}",
1721 b"nrtrie" | b"ntrianglerighteq" | b"NotRightTriangleEqual" => "\u{22ED}",
1722 b"vellip" => "\u{22EE}",
1723 b"ctdot" => "\u{22EF}",
1724 b"utdot" => "\u{22F0}",
1725 b"dtdot" => "\u{22F1}",
1726 b"disin" => "\u{22F2}",
1727 b"isinsv" => "\u{22F3}",
1728 b"isins" => "\u{22F4}",
1729 b"isindot" => "\u{22F5}",
1730 b"notinvc" => "\u{22F6}",
1731 b"notinvb" => "\u{22F7}",
1732 b"isinE" => "\u{22F9}",
1733 b"nisd" => "\u{22FA}",
1734 b"xnis" => "\u{22FB}",
1735 b"nis" => "\u{22FC}",
1736 b"notnivc" => "\u{22FD}",
1737 b"notnivb" => "\u{22FE}",
1738 b"barwed" | b"barwedge" => "\u{2305}",
1739 b"Barwed" | b"doublebarwedge" => "\u{2306}",
1740 b"lceil" | b"LeftCeiling" => "\u{2308}",
1741 b"rceil" | b"RightCeiling" => "\u{2309}",
1742 b"lfloor" | b"LeftFloor" => "\u{230A}",
1743 b"rfloor" | b"RightFloor" => "\u{230B}",
1744 b"drcrop" => "\u{230C}",
1745 b"dlcrop" => "\u{230D}",
1746 b"urcrop" => "\u{230E}",
1747 b"ulcrop" => "\u{230F}",
1748 b"bnot" => "\u{2310}",
1749 b"profline" => "\u{2312}",
1750 b"profsurf" => "\u{2313}",
1751 b"telrec" => "\u{2315}",
1752 b"target" => "\u{2316}",
1753 b"ulcorn" | b"ulcorner" => "\u{231C}",
1754 b"urcorn" | b"urcorner" => "\u{231D}",
1755 b"dlcorn" | b"llcorner" => "\u{231E}",
1756 b"drcorn" | b"lrcorner" => "\u{231F}",
1757 b"frown" | b"sfrown" => "\u{2322}",
1758 b"smile" | b"ssmile" => "\u{2323}",
1759 b"cylcty" => "\u{232D}",
1760 b"profalar" => "\u{232E}",
1761 b"topbot" => "\u{2336}",
1762 b"ovbar" => "\u{233D}",
1763 b"solbar" => "\u{233F}",
1764 b"angzarr" => "\u{237C}",
1765 b"lmoust" | b"lmoustache" => "\u{23B0}",
1766 b"rmoust" | b"rmoustache" => "\u{23B1}",
1767 b"tbrk" | b"OverBracket" => "\u{23B4}",
1768 b"bbrk" | b"UnderBracket" => "\u{23B5}",
1769 b"bbrktbrk" => "\u{23B6}",
1770 b"OverParenthesis" => "\u{23DC}",
1771 b"UnderParenthesis" => "\u{23DD}",
1772 b"OverBrace" => "\u{23DE}",
1773 b"UnderBrace" => "\u{23DF}",
1774 b"trpezium" => "\u{23E2}",
1775 b"elinters" => "\u{23E7}",
1776 b"blank" => "\u{2423}",
1777 b"oS" | b"circledS" => "\u{24C8}",
1778 b"boxh" | b"HorizontalLine" => "\u{2500}",
1779 b"boxv" => "\u{2502}",
1780 b"boxdr" => "\u{250C}",
1781 b"boxdl" => "\u{2510}",
1782 b"boxur" => "\u{2514}",
1783 b"boxul" => "\u{2518}",
1784 b"boxvr" => "\u{251C}",
1785 b"boxvl" => "\u{2524}",
1786 b"boxhd" => "\u{252C}",
1787 b"boxhu" => "\u{2534}",
1788 b"boxvh" => "\u{253C}",
1789 b"boxH" => "\u{2550}",
1790 b"boxV" => "\u{2551}",
1791 b"boxdR" => "\u{2552}",
1792 b"boxDr" => "\u{2553}",
1793 b"boxDR" => "\u{2554}",
1794 b"boxdL" => "\u{2555}",
1795 b"boxDl" => "\u{2556}",
1796 b"boxDL" => "\u{2557}",
1797 b"boxuR" => "\u{2558}",
1798 b"boxUr" => "\u{2559}",
1799 b"boxUR" => "\u{255A}",
1800 b"boxuL" => "\u{255B}",
1801 b"boxUl" => "\u{255C}",
1802 b"boxUL" => "\u{255D}",
1803 b"boxvR" => "\u{255E}",
1804 b"boxVr" => "\u{255F}",
1805 b"boxVR" => "\u{2560}",
1806 b"boxvL" => "\u{2561}",
1807 b"boxVl" => "\u{2562}",
1808 b"boxVL" => "\u{2563}",
1809 b"boxHd" => "\u{2564}",
1810 b"boxhD" => "\u{2565}",
1811 b"boxHD" => "\u{2566}",
1812 b"boxHu" => "\u{2567}",
1813 b"boxhU" => "\u{2568}",
1814 b"boxHU" => "\u{2569}",
1815 b"boxvH" => "\u{256A}",
1816 b"boxVh" => "\u{256B}",
1817 b"boxVH" => "\u{256C}",
1818 b"uhblk" => "\u{2580}",
1819 b"lhblk" => "\u{2584}",
1820 b"block" => "\u{2588}",
1821 b"blk14" => "\u{2591}",
1822 b"blk12" => "\u{2592}",
1823 b"blk34" => "\u{2593}",
1824 b"squ" | b"square" | b"Square" => "\u{25A1}",
1825 b"squf" | b"squarf" | b"blacksquare" | b"FilledVerySmallSquare" => "\u{25AA}",
1826 b"EmptyVerySmallSquare" => "\u{25AB}",
1827 b"rect" => "\u{25AD}",
1828 b"marker" => "\u{25AE}",
1829 b"fltns" => "\u{25B1}",
1830 b"xutri" | b"bigtriangleup" => "\u{25B3}",
1831 b"utrif" | b"blacktriangle" => "\u{25B4}",
1832 b"utri" | b"triangle" => "\u{25B5}",
1833 b"rtrif" | b"blacktriangleright" => "\u{25B8}",
1834 b"rtri" | b"triangleright" => "\u{25B9}",
1835 b"xdtri" | b"bigtriangledown" => "\u{25BD}",
1836 b"dtrif" | b"blacktriangledown" => "\u{25BE}",
1837 b"dtri" | b"triangledown" => "\u{25BF}",
1838 b"ltrif" | b"blacktriangleleft" => "\u{25C2}",
1839 b"ltri" | b"triangleleft" => "\u{25C3}",
1840 b"loz" | b"lozenge" => "\u{25CA}",
1841 b"cir" => "\u{25CB}",
1842 b"tridot" => "\u{25EC}",
1843 b"xcirc" | b"bigcirc" => "\u{25EF}",
1844 b"ultri" => "\u{25F8}",
1845 b"urtri" => "\u{25F9}",
1846 b"lltri" => "\u{25FA}",
1847 b"EmptySmallSquare" => "\u{25FB}",
1848 b"FilledSmallSquare" => "\u{25FC}",
1849 b"starf" | b"bigstar" => "\u{2605}",
1850 b"star" => "\u{2606}",
1851 b"phone" => "\u{260E}",
1852 b"female" => "\u{2640}",
1853 b"male" => "\u{2642}",
1854 b"spades" | b"spadesuit" => "\u{2660}",
1855 b"clubs" | b"clubsuit" => "\u{2663}",
1856 b"hearts" | b"heartsuit" => "\u{2665}",
1857 b"diams" | b"diamondsuit" => "\u{2666}",
1858 b"sung" => "\u{266A}",
1859 b"flat" => "\u{266D}",
1860 b"natur" | b"natural" => "\u{266E}",
1861 b"sharp" => "\u{266F}",
1862 b"check" | b"checkmark" => "\u{2713}",
1863 b"cross" => "\u{2717}",
1864 b"malt" | b"maltese" => "\u{2720}",
1865 b"sext" => "\u{2736}",
1866 b"VerticalSeparator" => "\u{2758}",
1867 b"lbbrk" => "\u{2772}",
1868 b"rbbrk" => "\u{2773}",
1869 b"lobrk" | b"LeftDoubleBracket" => "\u{27E6}",
1870 b"robrk" | b"RightDoubleBracket" => "\u{27E7}",
1871 b"lang" | b"LeftAngleBracket" | b"langle" => "\u{27E8}",
1872 b"rang" | b"RightAngleBracket" | b"rangle" => "\u{27E9}",
1873 b"Lang" => "\u{27EA}",
1874 b"Rang" => "\u{27EB}",
1875 b"loang" => "\u{27EC}",
1876 b"roang" => "\u{27ED}",
1877 b"xlarr" | b"longleftarrow" | b"LongLeftArrow" => "\u{27F5}",
1878 b"xrarr" | b"longrightarrow" | b"LongRightArrow" => "\u{27F6}",
1879 b"xharr" | b"longleftrightarrow" | b"LongLeftRightArrow" => "\u{27F7}",
1880 b"xlArr" | b"Longleftarrow" | b"DoubleLongLeftArrow" => "\u{27F8}",
1881 b"xrArr" | b"Longrightarrow" | b"DoubleLongRightArrow" => "\u{27F9}",
1882 b"xhArr" | b"Longleftrightarrow" | b"DoubleLongLeftRightArrow" => "\u{27FA}",
1883 b"xmap" | b"longmapsto" => "\u{27FC}",
1884 b"dzigrarr" => "\u{27FF}",
1885 b"nvlArr" => "\u{2902}",
1886 b"nvrArr" => "\u{2903}",
1887 b"nvHarr" => "\u{2904}",
1888 b"Map" => "\u{2905}",
1889 b"lbarr" => "\u{290C}",
1890 b"rbarr" | b"bkarow" => "\u{290D}",
1891 b"lBarr" => "\u{290E}",
1892 b"rBarr" | b"dbkarow" => "\u{290F}",
1893 b"RBarr" | b"drbkarow" => "\u{2910}",
1894 b"DDotrahd" => "\u{2911}",
1895 b"UpArrowBar" => "\u{2912}",
1896 b"DownArrowBar" => "\u{2913}",
1897 b"Rarrtl" => "\u{2916}",
1898 b"latail" => "\u{2919}",
1899 b"ratail" => "\u{291A}",
1900 b"lAtail" => "\u{291B}",
1901 b"rAtail" => "\u{291C}",
1902 b"larrfs" => "\u{291D}",
1903 b"rarrfs" => "\u{291E}",
1904 b"larrbfs" => "\u{291F}",
1905 b"rarrbfs" => "\u{2920}",
1906 b"nwarhk" => "\u{2923}",
1907 b"nearhk" => "\u{2924}",
1908 b"searhk" | b"hksearow" => "\u{2925}",
1909 b"swarhk" | b"hkswarow" => "\u{2926}",
1910 b"nwnear" => "\u{2927}",
1911 b"nesear" | b"toea" => "\u{2928}",
1912 b"seswar" | b"tosa" => "\u{2929}",
1913 b"swnwar" => "\u{292A}",
1914 b"rarrc" => "\u{2933}",
1915 b"cudarrr" => "\u{2935}",
1916 b"ldca" => "\u{2936}",
1917 b"rdca" => "\u{2937}",
1918 b"cudarrl" => "\u{2938}",
1919 b"larrpl" => "\u{2939}",
1920 b"curarrm" => "\u{293C}",
1921 b"cularrp" => "\u{293D}",
1922 b"rarrpl" => "\u{2945}",
1923 b"harrcir" => "\u{2948}",
1924 b"Uarrocir" => "\u{2949}",
1925 b"lurdshar" => "\u{294A}",
1926 b"ldrushar" => "\u{294B}",
1927 b"LeftRightVector" => "\u{294E}",
1928 b"RightUpDownVector" => "\u{294F}",
1929 b"DownLeftRightVector" => "\u{2950}",
1930 b"LeftUpDownVector" => "\u{2951}",
1931 b"LeftVectorBar" => "\u{2952}",
1932 b"RightVectorBar" => "\u{2953}",
1933 b"RightUpVectorBar" => "\u{2954}",
1934 b"RightDownVectorBar" => "\u{2955}",
1935 b"DownLeftVectorBar" => "\u{2956}",
1936 b"DownRightVectorBar" => "\u{2957}",
1937 b"LeftUpVectorBar" => "\u{2958}",
1938 b"LeftDownVectorBar" => "\u{2959}",
1939 b"LeftTeeVector" => "\u{295A}",
1940 b"RightTeeVector" => "\u{295B}",
1941 b"RightUpTeeVector" => "\u{295C}",
1942 b"RightDownTeeVector" => "\u{295D}",
1943 b"DownLeftTeeVector" => "\u{295E}",
1944 b"DownRightTeeVector" => "\u{295F}",
1945 b"LeftUpTeeVector" => "\u{2960}",
1946 b"LeftDownTeeVector" => "\u{2961}",
1947 b"lHar" => "\u{2962}",
1948 b"uHar" => "\u{2963}",
1949 b"rHar" => "\u{2964}",
1950 b"dHar" => "\u{2965}",
1951 b"luruhar" => "\u{2966}",
1952 b"ldrdhar" => "\u{2967}",
1953 b"ruluhar" => "\u{2968}",
1954 b"rdldhar" => "\u{2969}",
1955 b"lharul" => "\u{296A}",
1956 b"llhard" => "\u{296B}",
1957 b"rharul" => "\u{296C}",
1958 b"lrhard" => "\u{296D}",
1959 b"udhar" | b"UpEquilibrium" => "\u{296E}",
1960 b"duhar" | b"ReverseUpEquilibrium" => "\u{296F}",
1961 b"RoundImplies" => "\u{2970}",
1962 b"erarr" => "\u{2971}",
1963 b"simrarr" => "\u{2972}",
1964 b"larrsim" => "\u{2973}",
1965 b"rarrsim" => "\u{2974}",
1966 b"rarrap" => "\u{2975}",
1967 b"ltlarr" => "\u{2976}",
1968 b"gtrarr" => "\u{2978}",
1969 b"subrarr" => "\u{2979}",
1970 b"suplarr" => "\u{297B}",
1971 b"lfisht" => "\u{297C}",
1972 b"rfisht" => "\u{297D}",
1973 b"ufisht" => "\u{297E}",
1974 b"dfisht" => "\u{297F}",
1975 b"lopar" => "\u{2985}",
1976 b"ropar" => "\u{2986}",
1977 b"lbrke" => "\u{298B}",
1978 b"rbrke" => "\u{298C}",
1979 b"lbrkslu" => "\u{298D}",
1980 b"rbrksld" => "\u{298E}",
1981 b"lbrksld" => "\u{298F}",
1982 b"rbrkslu" => "\u{2990}",
1983 b"langd" => "\u{2991}",
1984 b"rangd" => "\u{2992}",
1985 b"lparlt" => "\u{2993}",
1986 b"rpargt" => "\u{2994}",
1987 b"gtlPar" => "\u{2995}",
1988 b"ltrPar" => "\u{2996}",
1989 b"vzigzag" => "\u{299A}",
1990 b"vangrt" => "\u{299C}",
1991 b"angrtvbd" => "\u{299D}",
1992 b"ange" => "\u{29A4}",
1993 b"range" => "\u{29A5}",
1994 b"dwangle" => "\u{29A6}",
1995 b"uwangle" => "\u{29A7}",
1996 b"angmsdaa" => "\u{29A8}",
1997 b"angmsdab" => "\u{29A9}",
1998 b"angmsdac" => "\u{29AA}",
1999 b"angmsdad" => "\u{29AB}",
2000 b"angmsdae" => "\u{29AC}",
2001 b"angmsdaf" => "\u{29AD}",
2002 b"angmsdag" => "\u{29AE}",
2003 b"angmsdah" => "\u{29AF}",
2004 b"bemptyv" => "\u{29B0}",
2005 b"demptyv" => "\u{29B1}",
2006 b"cemptyv" => "\u{29B2}",
2007 b"raemptyv" => "\u{29B3}",
2008 b"laemptyv" => "\u{29B4}",
2009 b"ohbar" => "\u{29B5}",
2010 b"omid" => "\u{29B6}",
2011 b"opar" => "\u{29B7}",
2012 b"operp" => "\u{29B9}",
2013 b"olcross" => "\u{29BB}",
2014 b"odsold" => "\u{29BC}",
2015 b"olcir" => "\u{29BE}",
2016 b"ofcir" => "\u{29BF}",
2017 b"olt" => "\u{29C0}",
2018 b"ogt" => "\u{29C1}",
2019 b"cirscir" => "\u{29C2}",
2020 b"cirE" => "\u{29C3}",
2021 b"solb" => "\u{29C4}",
2022 b"bsolb" => "\u{29C5}",
2023 b"boxbox" => "\u{29C9}",
2024 b"trisb" => "\u{29CD}",
2025 b"rtriltri" => "\u{29CE}",
2026 b"LeftTriangleBar" => "\u{29CF}",
2027 b"RightTriangleBar" => "\u{29D0}",
2028 b"race" => "\u{29DA}",
2029 b"iinfin" => "\u{29DC}",
2030 b"infintie" => "\u{29DD}",
2031 b"nvinfin" => "\u{29DE}",
2032 b"eparsl" => "\u{29E3}",
2033 b"smeparsl" => "\u{29E4}",
2034 b"eqvparsl" => "\u{29E5}",
2035 b"lozf" | b"blacklozenge" => "\u{29EB}",
2036 b"RuleDelayed" => "\u{29F4}",
2037 b"dsol" => "\u{29F6}",
2038 b"xodot" | b"bigodot" => "\u{2A00}",
2039 b"xoplus" | b"bigoplus" => "\u{2A01}",
2040 b"xotime" | b"bigotimes" => "\u{2A02}",
2041 b"xuplus" | b"biguplus" => "\u{2A04}",
2042 b"xsqcup" | b"bigsqcup" => "\u{2A06}",
2043 b"qint" | b"iiiint" => "\u{2A0C}",
2044 b"fpartint" => "\u{2A0D}",
2045 b"cirfnint" => "\u{2A10}",
2046 b"awint" => "\u{2A11}",
2047 b"rppolint" => "\u{2A12}",
2048 b"scpolint" => "\u{2A13}",
2049 b"npolint" => "\u{2A14}",
2050 b"pointint" => "\u{2A15}",
2051 b"quatint" => "\u{2A16}",
2052 b"intlarhk" => "\u{2A17}",
2053 b"pluscir" => "\u{2A22}",
2054 b"plusacir" => "\u{2A23}",
2055 b"simplus" => "\u{2A24}",
2056 b"plusdu" => "\u{2A25}",
2057 b"plussim" => "\u{2A26}",
2058 b"plustwo" => "\u{2A27}",
2059 b"mcomma" => "\u{2A29}",
2060 b"minusdu" => "\u{2A2A}",
2061 b"loplus" => "\u{2A2D}",
2062 b"roplus" => "\u{2A2E}",
2063 b"Cross" => "\u{2A2F}",
2064 b"timesd" => "\u{2A30}",
2065 b"timesbar" => "\u{2A31}",
2066 b"smashp" => "\u{2A33}",
2067 b"lotimes" => "\u{2A34}",
2068 b"rotimes" => "\u{2A35}",
2069 b"otimesas" => "\u{2A36}",
2070 b"Otimes" => "\u{2A37}",
2071 b"odiv" => "\u{2A38}",
2072 b"triplus" => "\u{2A39}",
2073 b"triminus" => "\u{2A3A}",
2074 b"tritime" => "\u{2A3B}",
2075 b"iprod" | b"intprod" => "\u{2A3C}",
2076 b"amalg" => "\u{2A3F}",
2077 b"capdot" => "\u{2A40}",
2078 b"ncup" => "\u{2A42}",
2079 b"ncap" => "\u{2A43}",
2080 b"capand" => "\u{2A44}",
2081 b"cupor" => "\u{2A45}",
2082 b"cupcap" => "\u{2A46}",
2083 b"capcup" => "\u{2A47}",
2084 b"cupbrcap" => "\u{2A48}",
2085 b"capbrcup" => "\u{2A49}",
2086 b"cupcup" => "\u{2A4A}",
2087 b"capcap" => "\u{2A4B}",
2088 b"ccups" => "\u{2A4C}",
2089 b"ccaps" => "\u{2A4D}",
2090 b"ccupssm" => "\u{2A50}",
2091 b"And" => "\u{2A53}",
2092 b"Or" => "\u{2A54}",
2093 b"andand" => "\u{2A55}",
2094 b"oror" => "\u{2A56}",
2095 b"orslope" => "\u{2A57}",
2096 b"andslope" => "\u{2A58}",
2097 b"andv" => "\u{2A5A}",
2098 b"orv" => "\u{2A5B}",
2099 b"andd" => "\u{2A5C}",
2100 b"ord" => "\u{2A5D}",
2101 b"wedbar" => "\u{2A5F}",
2102 b"sdote" => "\u{2A66}",
2103 b"simdot" => "\u{2A6A}",
2104 b"congdot" => "\u{2A6D}",
2105 b"easter" => "\u{2A6E}",
2106 b"apacir" => "\u{2A6F}",
2107 b"apE" => "\u{2A70}",
2108 b"eplus" => "\u{2A71}",
2109 b"pluse" => "\u{2A72}",
2110 b"Esim" => "\u{2A73}",
2111 b"Colone" => "\u{2A74}",
2112 b"Equal" => "\u{2A75}",
2113 b"eDDot" | b"ddotseq" => "\u{2A77}",
2114 b"equivDD" => "\u{2A78}",
2115 b"ltcir" => "\u{2A79}",
2116 b"gtcir" => "\u{2A7A}",
2117 b"ltquest" => "\u{2A7B}",
2118 b"gtquest" => "\u{2A7C}",
2119 b"les" | b"LessSlantEqual" | b"leqslant" => "\u{2A7D}",
2120 b"ges" | b"GreaterSlantEqual" | b"geqslant" => "\u{2A7E}",
2121 b"lesdot" => "\u{2A7F}",
2122 b"gesdot" => "\u{2A80}",
2123 b"lesdoto" => "\u{2A81}",
2124 b"gesdoto" => "\u{2A82}",
2125 b"lesdotor" => "\u{2A83}",
2126 b"gesdotol" => "\u{2A84}",
2127 b"lap" | b"lessapprox" => "\u{2A85}",
2128 b"gap" | b"gtrapprox" => "\u{2A86}",
2129 b"lne" | b"lneq" => "\u{2A87}",
2130 b"gne" | b"gneq" => "\u{2A88}",
2131 b"lnap" | b"lnapprox" => "\u{2A89}",
2132 b"gnap" | b"gnapprox" => "\u{2A8A}",
2133 b"lEg" | b"lesseqqgtr" => "\u{2A8B}",
2134 b"gEl" | b"gtreqqless" => "\u{2A8C}",
2135 b"lsime" => "\u{2A8D}",
2136 b"gsime" => "\u{2A8E}",
2137 b"lsimg" => "\u{2A8F}",
2138 b"gsiml" => "\u{2A90}",
2139 b"lgE" => "\u{2A91}",
2140 b"glE" => "\u{2A92}",
2141 b"lesges" => "\u{2A93}",
2142 b"gesles" => "\u{2A94}",
2143 b"els" | b"eqslantless" => "\u{2A95}",
2144 b"egs" | b"eqslantgtr" => "\u{2A96}",
2145 b"elsdot" => "\u{2A97}",
2146 b"egsdot" => "\u{2A98}",
2147 b"el" => "\u{2A99}",
2148 b"eg" => "\u{2A9A}",
2149 b"siml" => "\u{2A9D}",
2150 b"simg" => "\u{2A9E}",
2151 b"simlE" => "\u{2A9F}",
2152 b"simgE" => "\u{2AA0}",
2153 b"LessLess" => "\u{2AA1}",
2154 b"GreaterGreater" => "\u{2AA2}",
2155 b"glj" => "\u{2AA4}",
2156 b"gla" => "\u{2AA5}",
2157 b"ltcc" => "\u{2AA6}",
2158 b"gtcc" => "\u{2AA7}",
2159 b"lescc" => "\u{2AA8}",
2160 b"gescc" => "\u{2AA9}",
2161 b"smt" => "\u{2AAA}",
2162 b"lat" => "\u{2AAB}",
2163 b"smte" => "\u{2AAC}",
2164 b"late" => "\u{2AAD}",
2165 b"bumpE" => "\u{2AAE}",
2166 b"pre" | b"preceq" | b"PrecedesEqual" => "\u{2AAF}",
2167 b"sce" | b"succeq" | b"SucceedsEqual" => "\u{2AB0}",
2168 b"prE" => "\u{2AB3}",
2169 b"scE" => "\u{2AB4}",
2170 b"prnE" | b"precneqq" => "\u{2AB5}",
2171 b"scnE" | b"succneqq" => "\u{2AB6}",
2172 b"prap" | b"precapprox" => "\u{2AB7}",
2173 b"scap" | b"succapprox" => "\u{2AB8}",
2174 b"prnap" | b"precnapprox" => "\u{2AB9}",
2175 b"scnap" | b"succnapprox" => "\u{2ABA}",
2176 b"Pr" => "\u{2ABB}",
2177 b"Sc" => "\u{2ABC}",
2178 b"subdot" => "\u{2ABD}",
2179 b"supdot" => "\u{2ABE}",
2180 b"subplus" => "\u{2ABF}",
2181 b"supplus" => "\u{2AC0}",
2182 b"submult" => "\u{2AC1}",
2183 b"supmult" => "\u{2AC2}",
2184 b"subedot" => "\u{2AC3}",
2185 b"supedot" => "\u{2AC4}",
2186 b"subE" | b"subseteqq" => "\u{2AC5}",
2187 b"supE" | b"supseteqq" => "\u{2AC6}",
2188 b"subsim" => "\u{2AC7}",
2189 b"supsim" => "\u{2AC8}",
2190 b"subnE" | b"subsetneqq" => "\u{2ACB}",
2191 b"supnE" | b"supsetneqq" => "\u{2ACC}",
2192 b"csub" => "\u{2ACF}",
2193 b"csup" => "\u{2AD0}",
2194 b"csube" => "\u{2AD1}",
2195 b"csupe" => "\u{2AD2}",
2196 b"subsup" => "\u{2AD3}",
2197 b"supsub" => "\u{2AD4}",
2198 b"subsub" => "\u{2AD5}",
2199 b"supsup" => "\u{2AD6}",
2200 b"suphsub" => "\u{2AD7}",
2201 b"supdsub" => "\u{2AD8}",
2202 b"forkv" => "\u{2AD9}",
2203 b"topfork" => "\u{2ADA}",
2204 b"mlcp" => "\u{2ADB}",
2205 b"Dashv" | b"DoubleLeftTee" => "\u{2AE4}",
2206 b"Vdashl" => "\u{2AE6}",
2207 b"Barv" => "\u{2AE7}",
2208 b"vBar" => "\u{2AE8}",
2209 b"vBarv" => "\u{2AE9}",
2210 b"Vbar" => "\u{2AEB}",
2211 b"Not" => "\u{2AEC}",
2212 b"bNot" => "\u{2AED}",
2213 b"rnmid" => "\u{2AEE}",
2214 b"cirmid" => "\u{2AEF}",
2215 b"midcir" => "\u{2AF0}",
2216 b"topcir" => "\u{2AF1}",
2217 b"nhpar" => "\u{2AF2}",
2218 b"parsim" => "\u{2AF3}",
2219 b"parsl" => "\u{2AFD}",
2220 b"fflig" => "\u{FB00}",
2221 b"filig" => "\u{FB01}",
2222 b"fllig" => "\u{FB02}",
2223 b"ffilig" => "\u{FB03}",
2224 b"ffllig" => "\u{FB04}",
2225 b"Ascr" => "\u{1D49}",
2226 b"Cscr" => "\u{1D49}",
2227 b"Dscr" => "\u{1D49}",
2228 b"Gscr" => "\u{1D4A}",
2229 b"Jscr" => "\u{1D4A}",
2230 b"Kscr" => "\u{1D4A}",
2231 b"Nscr" => "\u{1D4A}",
2232 b"Oscr" => "\u{1D4A}",
2233 b"Pscr" => "\u{1D4A}",
2234 b"Qscr" => "\u{1D4A}",
2235 b"Sscr" => "\u{1D4A}",
2236 b"Tscr" => "\u{1D4A}",
2237 b"Uscr" => "\u{1D4B}",
2238 b"Vscr" => "\u{1D4B}",
2239 b"Wscr" => "\u{1D4B}",
2240 b"Xscr" => "\u{1D4B}",
2241 b"Yscr" => "\u{1D4B}",
2242 b"Zscr" => "\u{1D4B}",
2243 b"ascr" => "\u{1D4B}",
2244 b"bscr" => "\u{1D4B}",
2245 b"cscr" => "\u{1D4B}",
2246 b"dscr" => "\u{1D4B}",
2247 b"fscr" => "\u{1D4B}",
2248 b"hscr" => "\u{1D4B}",
2249 b"iscr" => "\u{1D4B}",
2250 b"jscr" => "\u{1D4B}",
2251 b"kscr" => "\u{1D4C}",
2252 b"lscr" => "\u{1D4C}",
2253 b"mscr" => "\u{1D4C}",
2254 b"nscr" => "\u{1D4C}",
2255 b"pscr" => "\u{1D4C}",
2256 b"qscr" => "\u{1D4C}",
2257 b"rscr" => "\u{1D4C}",
2258 b"sscr" => "\u{1D4C}",
2259 b"tscr" => "\u{1D4C}",
2260 b"uscr" => "\u{1D4C}",
2261 b"vscr" => "\u{1D4C}",
2262 b"wscr" => "\u{1D4C}",
2263 b"xscr" => "\u{1D4C}",
2264 b"yscr" => "\u{1D4C}",
2265 b"zscr" => "\u{1D4C}",
2266 b"Afr" => "\u{1D50}",
2267 b"Bfr" => "\u{1D50}",
2268 b"Dfr" => "\u{1D50}",
2269 b"Efr" => "\u{1D50}",
2270 b"Ffr" => "\u{1D50}",
2271 b"Gfr" => "\u{1D50}",
2272 b"Jfr" => "\u{1D50}",
2273 b"Kfr" => "\u{1D50}",
2274 b"Lfr" => "\u{1D50}",
2275 b"Mfr" => "\u{1D51}",
2276 b"Nfr" => "\u{1D51}",
2277 b"Ofr" => "\u{1D51}",
2278 b"Pfr" => "\u{1D51}",
2279 b"Qfr" => "\u{1D51}",
2280 b"Sfr" => "\u{1D51}",
2281 b"Tfr" => "\u{1D51}",
2282 b"Ufr" => "\u{1D51}",
2283 b"Vfr" => "\u{1D51}",
2284 b"Wfr" => "\u{1D51}",
2285 b"Xfr" => "\u{1D51}",
2286 b"Yfr" => "\u{1D51}",
2287 b"afr" => "\u{1D51}",
2288 b"bfr" => "\u{1D51}",
2289 b"cfr" => "\u{1D52}",
2290 b"dfr" => "\u{1D52}",
2291 b"efr" => "\u{1D52}",
2292 b"ffr" => "\u{1D52}",
2293 b"gfr" => "\u{1D52}",
2294 b"hfr" => "\u{1D52}",
2295 b"ifr" => "\u{1D52}",
2296 b"jfr" => "\u{1D52}",
2297 b"kfr" => "\u{1D52}",
2298 b"lfr" => "\u{1D52}",
2299 b"mfr" => "\u{1D52}",
2300 b"nfr" => "\u{1D52}",
2301 b"ofr" => "\u{1D52}",
2302 b"pfr" => "\u{1D52}",
2303 b"qfr" => "\u{1D52}",
2304 b"rfr" => "\u{1D52}",
2305 b"sfr" => "\u{1D53}",
2306 b"tfr" => "\u{1D53}",
2307 b"ufr" => "\u{1D53}",
2308 b"vfr" => "\u{1D53}",
2309 b"wfr" => "\u{1D53}",
2310 b"xfr" => "\u{1D53}",
2311 b"yfr" => "\u{1D53}",
2312 b"zfr" => "\u{1D53}",
2313 b"Aopf" => "\u{1D53}",
2314 b"Bopf" => "\u{1D53}",
2315 b"Dopf" => "\u{1D53}",
2316 b"Eopf" => "\u{1D53}",
2317 b"Fopf" => "\u{1D53}",
2318 b"Gopf" => "\u{1D53}",
2319 b"Iopf" => "\u{1D54}",
2320 b"Jopf" => "\u{1D54}",
2321 b"Kopf" => "\u{1D54}",
2322 b"Lopf" => "\u{1D54}",
2323 b"Mopf" => "\u{1D54}",
2324 b"Oopf" => "\u{1D54}",
2325 b"Sopf" => "\u{1D54}",
2326 b"Topf" => "\u{1D54}",
2327 b"Uopf" => "\u{1D54}",
2328 b"Vopf" => "\u{1D54}",
2329 b"Wopf" => "\u{1D54}",
2330 b"Xopf" => "\u{1D54}",
2331 b"Yopf" => "\u{1D55}",
2332 b"aopf" => "\u{1D55}",
2333 b"bopf" => "\u{1D55}",
2334 b"copf" => "\u{1D55}",
2335 b"dopf" => "\u{1D55}",
2336 b"eopf" => "\u{1D55}",
2337 b"fopf" => "\u{1D55}",
2338 b"gopf" => "\u{1D55}",
2339 b"hopf" => "\u{1D55}",
2340 b"iopf" => "\u{1D55}",
2341 b"jopf" => "\u{1D55}",
2342 b"kopf" => "\u{1D55}",
2343 b"lopf" => "\u{1D55}",
2344 b"mopf" => "\u{1D55}",
2345 b"nopf" => "\u{1D55}",
2346 b"oopf" => "\u{1D56}",
2347 b"popf" => "\u{1D56}",
2348 b"qopf" => "\u{1D56}",
2349 b"ropf" => "\u{1D56}",
2350 b"sopf" => "\u{1D56}",
2351 b"topf" => "\u{1D56}",
2352 b"uopf" => "\u{1D56}",
2353 b"vopf" => "\u{1D56}",
2354 b"wopf" => "\u{1D56}",
2355 b"xopf" => "\u{1D56}",
2356 b"yopf" => "\u{1D56}",
2357 b"zopf" => "\u{1D56}",
2358 _ => return None,
2359 };
2360 Some(s)
2361}
2362
2363pub(crate) fn parse_number(num: &str) -> Result<char, ParseCharRefError> {
2364 let code = if let Some(hex) = num.strip_prefix('x') {
2365 from_str_radix(hex, 16)?
2366 } else {
2367 from_str_radix(num, 10)?
2368 };
2369 if code == 0 {
2370 return Err(ParseCharRefError::IllegalCharacter(code));
2371 }
2372 match std::char::from_u32(code) {
2373 Some(c) => Ok(c),
2374 None => Err(ParseCharRefError::InvalidCodepoint(code)),
2375 }
2376}
2377
2378#[inline]
2379fn from_str_radix(src: &str, radix: u32) -> Result<u32, ParseCharRefError> {
2380 match src.as_bytes().first().copied() {
2381 Some(b'+') | Some(b'-') => Err(ParseCharRefError::UnexpectedSign),
2384 _ => u32::from_str_radix(src, radix).map_err(ParseCharRefError::InvalidNumber),
2385 }
2386}
2387
2388#[cfg(test)]
2391mod normalization {
2392 use super::*;
2393
2394 mod eol {
2395 use super::*;
2396
2397 mod xml11 {
2398 use super::*;
2399 use pretty_assertions::assert_eq;
2400
2401 #[test]
2402 fn empty() {
2403 assert_eq!(normalize_xml11_eols(""), "");
2404 }
2405
2406 #[test]
2407 fn already_normalized() {
2408 assert_eq!(
2409 normalize_xml11_eols("\nalready \n\n normalized\n"),
2410 "\nalready \n\n normalized\n",
2411 );
2412 }
2413
2414 #[test]
2415 fn cr_lf() {
2416 assert_eq!(
2417 normalize_xml11_eols("\r\nsome\r\n\r\ntext"),
2418 "\nsome\n\ntext"
2419 );
2420 }
2421
2422 #[test]
2423 fn cr_u0085() {
2424 assert_eq!(
2425 normalize_xml11_eols("\r\u{0085}some\r\u{0085}\r\u{0085}text"),
2426 "\nsome\n\ntext",
2427 );
2428 }
2429
2430 #[test]
2431 fn u0085() {
2432 assert_eq!(
2433 normalize_xml11_eols("\u{0085}some\u{0085}\u{0085}text"),
2434 "\nsome\n\ntext",
2435 );
2436 }
2437
2438 #[test]
2439 fn u2028() {
2440 assert_eq!(
2441 normalize_xml11_eols("\u{2028}some\u{2028}\u{2028}text"),
2442 "\nsome\n\ntext",
2443 );
2444 }
2445
2446 #[test]
2447 fn mixed() {
2448 assert_eq!(
2449 normalize_xml11_eols("\r\r\r\u{2028}\n\r\nsome\n\u{0085}\r\u{0085}text"),
2450 "\n\n\n\n\n\nsome\n\n\ntext",
2451 );
2452 }
2453
2454 #[test]
2455 fn utf8_0xc2() {
2456 let first = std::str::from_utf8(&[0b11000010, 0b10000000])
2459 .unwrap()
2460 .chars()
2461 .next()
2462 .unwrap();
2463 let last = std::str::from_utf8(&[0b11000010, 0b10111111])
2464 .unwrap()
2465 .chars()
2466 .next()
2467 .unwrap();
2468 let mut utf8 = [0; 2];
2469 for ch in first..=last {
2470 ch.encode_utf8(&mut utf8);
2471 let description = format!("UTF-8 [{:02x} {:02x}] = `{}`", utf8[0], utf8[1], ch);
2472 let input = std::str::from_utf8(&utf8).expect(&description);
2473
2474 dbg!((input, &description));
2475 if ch == '\u{0085}' {
2476 assert_eq!(normalize_xml11_eols(input), "\n", "{}", description);
2477 } else {
2478 assert_eq!(normalize_xml11_eols(input), input, "{}", description);
2479 }
2480 }
2481 assert_eq!((first..=last).count(), 64);
2482 }
2483
2484 #[test]
2485 fn utf8_0x0d_0xc2() {
2486 let first = std::str::from_utf8(&[0b11000010, 0b10000000])
2489 .unwrap()
2490 .chars()
2491 .next()
2492 .unwrap();
2493 let last = std::str::from_utf8(&[0b11000010, 0b10111111])
2494 .unwrap()
2495 .chars()
2496 .next()
2497 .unwrap();
2498 let mut utf8 = [b'\r', 0, 0];
2499 for ch in first..=last {
2500 ch.encode_utf8(&mut utf8[1..]);
2501 let description = format!(
2502 "UTF-8 [{:02x} {:02x} {:02x}] = `{}`",
2503 utf8[0], utf8[1], utf8[2], ch
2504 );
2505 let input = std::str::from_utf8(&utf8).expect(&description);
2506
2507 dbg!((input, &description));
2508 if ch == '\u{0085}' {
2509 assert_eq!(normalize_xml11_eols(input), "\n", "{}", description);
2510 } else {
2511 let mut expected = utf8;
2513 expected[0] = b'\n';
2514 let expected = std::str::from_utf8(&expected).expect(&description);
2515 assert_eq!(normalize_xml11_eols(input), expected, "{}", description);
2516 }
2517 }
2518 assert_eq!((first..=last).count(), 64);
2519 }
2520
2521 #[test]
2522 fn utf8_0xe2() {
2523 let first = std::str::from_utf8(&[0b11100010, 0b10000000, 0b10000000])
2526 .unwrap()
2527 .chars()
2528 .next()
2529 .unwrap();
2530 let last = std::str::from_utf8(&[0b11100010, 0b10111111, 0b10111111])
2531 .unwrap()
2532 .chars()
2533 .next()
2534 .unwrap();
2535 let mut buf = [0; 3];
2536 for ch in first..=last {
2537 let input = &*ch.encode_utf8(&mut buf);
2538 let buf = input.as_bytes();
2539 let description = format!(
2540 "UTF-8 [{:02x} {:02x} {:02x}] = `{}`",
2541 buf[0], buf[1], buf[2], ch
2542 );
2543
2544 dbg!((input, &description));
2545 if ch == '\u{2028}' {
2546 assert_eq!(normalize_xml11_eols(input), "\n", "{}", description);
2547 } else {
2548 assert_eq!(normalize_xml11_eols(input), input, "{}", description);
2549 }
2550 }
2551 assert_eq!((first..=last).count(), 4096);
2552 }
2553 }
2554
2555 mod xml10 {
2556 use super::*;
2557 use pretty_assertions::assert_eq;
2558
2559 #[test]
2560 fn empty() {
2561 assert_eq!(normalize_xml10_eols(""), "");
2562 }
2563
2564 #[test]
2565 fn already_normalized() {
2566 assert_eq!(
2567 normalize_xml10_eols("\nalready \n\n normalized\n"),
2568 "\nalready \n\n normalized\n",
2569 );
2570 }
2571
2572 #[test]
2573 fn cr_lf() {
2574 assert_eq!(
2575 normalize_xml10_eols("\r\nsome\r\n\r\ntext"),
2576 "\nsome\n\ntext"
2577 );
2578 }
2579
2580 #[test]
2581 fn cr_u0085() {
2582 assert_eq!(
2583 normalize_xml10_eols("\r\u{0085}some\r\u{0085}\r\u{0085}text"),
2584 "\n\u{0085}some\n\u{0085}\n\u{0085}text",
2585 );
2586 }
2587
2588 #[test]
2589 fn u0085() {
2590 assert_eq!(
2591 normalize_xml10_eols("\u{0085}some\u{0085}\u{0085}text"),
2592 "\u{0085}some\u{0085}\u{0085}text",
2593 );
2594 }
2595
2596 #[test]
2597 fn u2028() {
2598 assert_eq!(
2599 normalize_xml10_eols("\u{2028}some\u{2028}\u{2028}text"),
2600 "\u{2028}some\u{2028}\u{2028}text",
2601 );
2602 }
2603
2604 #[test]
2605 fn mixed() {
2606 assert_eq!(
2607 normalize_xml10_eols("\r\r\r\u{2028}\n\r\nsome\n\u{0085}\r\u{0085}text"),
2608 "\n\n\n\u{2028}\n\nsome\n\u{0085}\n\u{0085}text",
2609 );
2610 }
2611 }
2612 }
2613
2614 mod attribute {
2615 use super::*;
2616 use pretty_assertions::assert_eq;
2617
2618 #[test]
2619 fn empty() {
2620 assert_eq!(
2621 normalize_xml10_attribute_value("", 5, |_| { None }),
2622 Ok("".into())
2623 );
2624 assert_eq!(
2625 normalize_xml11_attribute_value("", 5, |_| { None }),
2626 Ok("".into())
2627 );
2628 }
2629
2630 #[test]
2631 fn already_normalized() {
2632 assert_eq!(
2633 normalize_xml10_attribute_value("already normalized", 5, |_| { None }),
2634 Ok("already normalized".into())
2635 );
2636 assert_eq!(
2637 normalize_xml11_attribute_value("already normalized", 5, |_| { None }),
2638 Ok("already normalized".into())
2639 );
2640 }
2641
2642 #[test]
2643 fn only_spaces() {
2644 assert_eq!(
2645 normalize_xml10_attribute_value(" ", 5, |_| { None }),
2646 Ok(" ".into())
2647 );
2648 assert_eq!(
2649 normalize_xml11_attribute_value(" ", 5, |_| { None }),
2650 Ok(" ".into())
2651 );
2652
2653 assert_eq!(
2654 normalize_xml10_attribute_value("\t\t\t", 5, |_| { None }),
2655 Ok(" ".into())
2656 );
2657 assert_eq!(
2658 normalize_xml11_attribute_value("\t\t\t", 5, |_| { None }),
2659 Ok(" ".into())
2660 );
2661
2662 assert_eq!(
2663 normalize_xml10_attribute_value("\r\r\r", 5, |_| { None }),
2664 Ok(" ".into())
2665 );
2666 assert_eq!(
2667 normalize_xml11_attribute_value("\r\r\r", 5, |_| { None }),
2668 Ok(" ".into())
2669 );
2670
2671 assert_eq!(
2672 normalize_xml10_attribute_value("\n\n\n", 5, |_| { None }),
2673 Ok(" ".into())
2674 );
2675 assert_eq!(
2676 normalize_xml11_attribute_value("\n\n\n", 5, |_| { None }),
2677 Ok(" ".into())
2678 );
2679
2680 assert_eq!(
2681 normalize_xml10_attribute_value("\r\n\r\n\r\n", 5, |_| { None }),
2682 Ok(" ".into())
2683 );
2684 assert_eq!(
2685 normalize_xml11_attribute_value("\r\n\r\n\r\n", 5, |_| { None }),
2686 Ok(" ".into())
2687 );
2688
2689 assert_eq!(
2690 normalize_xml10_attribute_value("\t\t\n\n\r\r ", 5, |_| None),
2691 Ok(" ".into())
2692 );
2693 assert_eq!(
2694 normalize_xml11_attribute_value("\t\t\n\n\r\r ", 5, |_| None),
2695 Ok(" ".into())
2696 );
2697
2698 assert_eq!(
2699 normalize_xml10_attribute_value("\u{0085}\u{0085}\u{0085}", 5, |_| { None }),
2700 Ok("\u{0085}\u{0085}\u{0085}".into())
2701 );
2702 assert_eq!(
2703 normalize_xml11_attribute_value("\u{0085}\u{0085}\u{0085}", 5, |_| { None }),
2704 Ok(" ".into())
2705 );
2706
2707 assert_eq!(
2708 normalize_xml10_attribute_value("\r\u{0085}\r\u{0085}\r\u{0085}", 5, |_| { None }),
2709 Ok(" \u{0085} \u{0085} \u{0085}".into())
2710 );
2711 assert_eq!(
2712 normalize_xml11_attribute_value("\r\u{0085}\r\u{0085}\r\u{0085}", 5, |_| { None }),
2713 Ok(" ".into())
2714 );
2715
2716 assert_eq!(
2717 normalize_xml10_attribute_value("\u{2028}\u{2028}\u{2028}", 5, |_| { None }),
2718 Ok("\u{2028}\u{2028}\u{2028}".into())
2719 );
2720 assert_eq!(
2721 normalize_xml11_attribute_value("\u{2028}\u{2028}\u{2028}", 5, |_| { None }),
2722 Ok(" ".into())
2723 );
2724 }
2725
2726 #[test]
2727 fn mixed_content_normalization() {
2728 assert_eq!(
2730 normalize_xml10_attribute_value("hello\t \nworld", 5, |_| None),
2731 Ok("hello world".into())
2732 );
2733 assert_eq!(
2734 normalize_xml11_attribute_value("hello\t \nworld", 5, |_| None),
2735 Ok("hello world".into())
2736 );
2737
2738 assert_eq!(
2740 normalize_xml10_attribute_value("text &entity; \n more", 5, |_| {
2741 Some("replacement")
2742 }),
2743 Ok("text replacement more".into())
2744 );
2745 assert_eq!(
2746 normalize_xml11_attribute_value("text &entity; \n more", 5, |_| {
2747 Some("replacement")
2748 }),
2749 Ok("text replacement more".into())
2750 );
2751
2752 assert_eq!(
2755 normalize_xml10_attribute_value("\tA\r\nB\t", 5, |_| None),
2756 Ok(" A B ".into())
2757 );
2758 assert_eq!(
2759 normalize_xml11_attribute_value("\tA\r\nB\t", 5, |_| None),
2760 Ok(" A B ".into())
2761 );
2762 }
2763
2764 #[test]
2765 fn leading_trailing_whitespace() {
2766 assert_eq!(
2768 normalize_xml10_attribute_value(" text", 5, |_| None),
2769 Ok(" text".into())
2770 );
2771 assert_eq!(
2772 normalize_xml11_attribute_value(" text", 5, |_| None),
2773 Ok(" text".into())
2774 );
2775
2776 assert_eq!(
2777 normalize_xml10_attribute_value("\t\ttext", 5, |_| None),
2778 Ok(" text".into())
2779 );
2780 assert_eq!(
2781 normalize_xml11_attribute_value("\t\ttext", 5, |_| None),
2782 Ok(" text".into())
2783 );
2784
2785 assert_eq!(
2787 normalize_xml10_attribute_value("text ", 5, |_| None),
2788 Ok("text ".into())
2789 );
2790 assert_eq!(
2791 normalize_xml11_attribute_value("text ", 5, |_| None),
2792 Ok("text ".into())
2793 );
2794
2795 assert_eq!(
2796 normalize_xml10_attribute_value("text\n\n", 5, |_| None),
2797 Ok("text ".into())
2798 );
2799 assert_eq!(
2800 normalize_xml11_attribute_value("text\n\n", 5, |_| None),
2801 Ok("text ".into())
2802 );
2803
2804 assert_eq!(
2806 normalize_xml10_attribute_value("\n\ntext\n\n", 5, |_| None),
2807 Ok(" text ".into())
2808 );
2809 assert_eq!(
2810 normalize_xml11_attribute_value("\n\ntext\n\n", 5, |_| None),
2811 Ok(" text ".into())
2812 );
2813 }
2814
2815 #[test]
2816 fn characters() {
2817 assert_eq!(
2818 normalize_xml10_attribute_value("string with   character", 5, |_| { None }),
2819 Ok("string with character".into())
2820 );
2821 assert_eq!(
2822 normalize_xml10_attribute_value("string with   character", 5, |_| { None }),
2823 Ok("string with character".into())
2824 );
2825
2826 assert_eq!(
2827 normalize_xml11_attribute_value("string with   character", 5, |_| { None }),
2828 Ok("string with character".into())
2829 );
2830 assert_eq!(
2831 normalize_xml11_attribute_value("string with   character", 5, |_| { None }),
2832 Ok("string with character".into())
2833 );
2834 }
2835
2836 #[test]
2837 fn character_reference_edge_cases() {
2838 assert!(matches!(
2840 normalize_xml10_attribute_value("&#xGG;", 5, |_| None),
2841 Err(EscapeError::InvalidCharRef(
2842 ParseCharRefError::InvalidNumber(_)
2843 ))
2844 ));
2845 assert!(matches!(
2846 normalize_xml11_attribute_value("&#xGG;", 5, |_| None),
2847 Err(EscapeError::InvalidCharRef(
2848 ParseCharRefError::InvalidNumber(_)
2849 ))
2850 ));
2851
2852 assert!(matches!(
2854 normalize_xml10_attribute_value("&#ABC;", 5, |_| None),
2855 Err(EscapeError::InvalidCharRef(
2856 ParseCharRefError::InvalidNumber(_)
2857 ))
2858 ));
2859
2860 assert_eq!(
2862 normalize_xml10_attribute_value("�", 5, |_| None),
2863 Err(EscapeError::InvalidCharRef(
2864 ParseCharRefError::InvalidCodepoint(0x110000)
2865 ))
2866 );
2867 assert_eq!(
2868 normalize_xml11_attribute_value("�", 5, |_| None),
2869 Err(EscapeError::InvalidCharRef(
2870 ParseCharRefError::InvalidCodepoint(0x110000)
2871 ))
2872 );
2873
2874 assert_eq!(
2876 normalize_xml10_attribute_value("�", 5, |_| None),
2877 Err(EscapeError::InvalidCharRef(
2878 ParseCharRefError::InvalidCodepoint(999999999)
2879 ))
2880 );
2881
2882 assert_eq!(
2884 normalize_xml10_attribute_value("ABC", 5, |_| None),
2885 Ok("ABC".into())
2886 );
2887 assert_eq!(
2888 normalize_xml11_attribute_value("ABC", 5, |_| None),
2889 Ok("ABC".into())
2890 );
2891
2892 assert_eq!(
2894 normalize_xml10_attribute_value(" text", 5, |_| None),
2895 Ok(" text".into())
2896 );
2897 assert_eq!(
2898 normalize_xml10_attribute_value("text ", 5, |_| None),
2899 Ok("text ".into())
2900 );
2901 assert_eq!(
2902 normalize_xml11_attribute_value(" text", 5, |_| None),
2903 Ok(" text".into())
2904 );
2905 assert_eq!(
2906 normalize_xml11_attribute_value("text ", 5, |_| None),
2907 Ok("text ".into())
2908 );
2909 }
2910
2911 #[test]
2912 fn entities() {
2913 assert_eq!(
2914 normalize_xml10_attribute_value("string with &entity; reference", 5, |_| {
2915 Some("replacement")
2916 }),
2917 Ok("string with replacement reference".into())
2918 );
2919 assert_eq!(
2920 normalize_xml10_attribute_value("string with &entity-1; reference", 5, |entity| {
2921 match entity {
2922 "entity-1" => Some("recursive &entity-2;"),
2923 "entity-2" => Some("entity 2"),
2924 _ => None,
2925 }
2926 }),
2927 Ok("string with recursive entity 2 reference".into())
2928 );
2929 assert_eq!(
2931 normalize_xml10_attribute_value(
2932 "string with &entity;amp; reference",
2933 5,
2934 |entity| {
2935 match entity {
2936 "entity" => Some("&"),
2937 "amp" => Some("&"),
2938 _ => None,
2939 }
2940 }
2941 ),
2942 Ok("string with & reference".into())
2943 );
2944
2945 assert_eq!(
2946 normalize_xml11_attribute_value("string with &entity; reference", 5, |_| {
2947 Some("replacement")
2948 }),
2949 Ok("string with replacement reference".into())
2950 );
2951 assert_eq!(
2952 normalize_xml11_attribute_value("string with &entity-1; reference", 5, |entity| {
2953 match entity {
2954 "entity-1" => Some("recursive &entity-2;"),
2955 "entity-2" => Some("entity 2"),
2956 _ => None,
2957 }
2958 }),
2959 Ok("string with recursive entity 2 reference".into())
2960 );
2961 assert_eq!(
2963 normalize_xml11_attribute_value(
2964 "string with &entity;amp; reference",
2965 5,
2966 |entity| {
2967 match entity {
2968 "entity" => Some("&"),
2969 "amp" => Some("&"),
2970 _ => None,
2971 }
2972 }
2973 ),
2974 Ok("string with & reference".into())
2975 );
2976 }
2977
2978 #[test]
2979 fn unknown_entity() {
2980 assert_eq!(
2981 normalize_xml10_attribute_value(
2982 "string with unknown &entity; reference",
2983 5,
2985 |_| None
2986 ),
2987 Err(EscapeError::UnrecognizedEntity(
2988 21..27,
2989 "entity".to_string(),
2990 ))
2991 );
2992
2993 assert_eq!(
2994 normalize_xml11_attribute_value(
2995 "string with unknown &entity; reference",
2996 5,
2998 |_| None
2999 ),
3000 Err(EscapeError::UnrecognizedEntity(
3001 21..27,
3002 "entity".to_string(),
3003 ))
3004 );
3005 }
3006
3007 #[test]
3008 fn predefined_entities() {
3009 assert_eq!(
3011 normalize_xml10_attribute_value(
3012 "<>"'",
3013 5,
3014 resolve_predefined_entity
3015 ),
3016 Ok("<>\"'".into())
3017 );
3018 assert_eq!(
3019 normalize_xml11_attribute_value(
3020 "<>"'",
3021 5,
3022 resolve_predefined_entity
3023 ),
3024 Ok("<>\"'".into())
3025 );
3026
3027 assert_eq!(
3029 normalize_xml10_attribute_value("&<", 5, resolve_predefined_entity),
3030 Ok("&<".into())
3031 );
3032 assert_eq!(
3033 normalize_xml11_attribute_value("&<", 5, resolve_predefined_entity),
3034 Ok("&<".into())
3035 );
3036
3037 assert_eq!(
3039 normalize_xml10_attribute_value("&&&", 5, resolve_predefined_entity),
3040 Ok("&&&".into())
3041 );
3042 }
3043
3044 #[test]
3045 fn unclosed_entity() {
3046 assert_eq!(
3048 normalize_xml10_attribute_value("& ", 5, |_| None),
3049 Err(EscapeError::UnterminatedEntity(0..2))
3050 );
3051 assert_eq!(
3052 normalize_xml11_attribute_value("& ", 5, |_| None),
3053 Err(EscapeError::UnterminatedEntity(0..2))
3054 );
3055
3056 assert_eq!(
3058 normalize_xml10_attribute_value("&# ", 5, |_| None),
3059 Err(EscapeError::UnterminatedEntity(0..3))
3060 );
3061 assert_eq!(
3062 normalize_xml11_attribute_value("&# ", 5, |_| None),
3063 Err(EscapeError::UnterminatedEntity(0..3))
3064 );
3065
3066 assert_eq!(
3068 normalize_xml10_attribute_value("&entity", 5, |_| Some("text")),
3069 Err(EscapeError::UnterminatedEntity(0..7))
3070 );
3071 assert_eq!(
3072 normalize_xml11_attribute_value("&entity", 5, |_| Some("text")),
3073 Err(EscapeError::UnterminatedEntity(0..7))
3074 );
3075
3076 assert_eq!(
3078 normalize_xml10_attribute_value(
3079 "string with unclosed &entity reference",
3080 5,
3082 |_| Some("replacement")
3083 ),
3084 Err(EscapeError::UnterminatedEntity(21..38))
3085 );
3086 assert_eq!(
3087 normalize_xml11_attribute_value(
3088 "string with unclosed &entity reference",
3089 5,
3091 |_| Some("replacement")
3092 ),
3093 Err(EscapeError::UnterminatedEntity(21..38))
3094 );
3095
3096 assert_eq!(
3098 normalize_xml10_attribute_value(
3099 "string with unclosed   (character) reference",
3100 5,
3102 |_| None
3103 ),
3104 Err(EscapeError::UnterminatedEntity(21..47))
3105 );
3106 assert_eq!(
3107 normalize_xml11_attribute_value(
3108 "string with unclosed   (character) reference",
3109 5,
3111 |_| None
3112 ),
3113 Err(EscapeError::UnterminatedEntity(21..47))
3114 );
3115 }
3116
3117 #[test]
3118 fn malformed_entity() {
3119 assert_eq!(
3121 normalize_xml10_attribute_value("&;", 5, |_| None),
3122 Err(EscapeError::UnrecognizedEntity(1..1, "".to_string()))
3123 );
3124 assert_eq!(
3125 normalize_xml11_attribute_value("&;", 5, |_| None),
3126 Err(EscapeError::UnrecognizedEntity(1..1, "".to_string()))
3127 );
3128
3129 assert_eq!(
3131 normalize_xml10_attribute_value("&123;", 5, |_| None),
3132 Err(EscapeError::UnrecognizedEntity(1..4, "123".to_string()))
3133 );
3134 assert_eq!(
3135 normalize_xml11_attribute_value("&123;", 5, |_| None),
3136 Err(EscapeError::UnrecognizedEntity(1..4, "123".to_string()))
3137 );
3138
3139 assert!(matches!(
3141 normalize_xml10_attribute_value("&#;", 5, |_| None),
3142 Err(EscapeError::InvalidCharRef(
3143 ParseCharRefError::InvalidNumber(_)
3144 ))
3145 ));
3146 assert!(matches!(
3147 normalize_xml10_attribute_value("&#x;", 5, |_| None),
3148 Err(EscapeError::InvalidCharRef(
3149 ParseCharRefError::InvalidNumber(_)
3150 ))
3151 ));
3152 }
3153
3154 #[test]
3155 fn recursive_entity() {
3156 assert_eq!(
3157 normalize_xml10_attribute_value("&entity; reference", 5, |_| Some(
3158 "recursive &entity;"
3159 )),
3160 Err(EscapeError::TooManyNestedEntities),
3161 );
3162
3163 assert_eq!(
3164 normalize_xml11_attribute_value("&entity; reference", 5, |_| Some(
3165 "recursive &entity;"
3166 )),
3167 Err(EscapeError::TooManyNestedEntities),
3168 );
3169 }
3170
3171 #[test]
3172 fn recursion_depth() {
3173 assert_eq!(
3176 normalize_xml10_attribute_value("&e1;", 5, |entity| {
3177 match entity {
3178 "e1" => Some("&e2;"),
3179 "e2" => Some("&e3;"),
3180 "e3" => Some("&e4;"),
3181 "e4" => Some("text"),
3182 _ => None,
3183 }
3184 }),
3185 Ok("text".into())
3186 );
3187
3188 assert_eq!(
3191 normalize_xml10_attribute_value("&e1;", 5, |entity| {
3192 match entity {
3193 "e1" => Some("&e2;"),
3194 "e2" => Some("&e3;"),
3195 "e3" => Some("&e4;"),
3196 "e4" => Some("&e5;"),
3197 "e5" => Some("text"),
3198 _ => None,
3199 }
3200 }),
3201 Ok("text".into())
3202 );
3203
3204 assert_eq!(
3207 normalize_xml10_attribute_value("&e1;", 5, |entity| {
3208 match entity {
3209 "e1" => Some("&e2;"),
3210 "e2" => Some("&e3;"),
3211 "e3" => Some("&e4;"),
3212 "e4" => Some("&e5;"),
3213 "e5" => Some("&e6;"),
3214 "e6" => Some("text"),
3215 _ => None,
3216 }
3217 }),
3218 Err(EscapeError::TooManyNestedEntities)
3219 );
3220 }
3221 }
3222}