html_escape/decode/element/script.rs
1use alloc::{borrow::Cow, string::String, vec::Vec};
2use core::str::from_utf8_unchecked;
3#[cfg(feature = "std")]
4use std::io::{self, Write};
5
6macro_rules! parse_script {
7 (@eof $step:ident, $b:block) => {
8 // The text ends right after `<\/script`.
9 if $step == 9 {
10 $b
11 }
12 };
13 ($e:expr, $step:ident, $b:block, $bc:block) => {
14 match $step {
15 0 => match $e {
16 b'<' => $step = 1,
17 _ => (),
18 },
19 1 => match $e {
20 b'\\' => $step = 2,
21 b'<' => $step = 1,
22 _ => $step = 0,
23 },
24 2 => match $e {
25 b'/' => $step = 3,
26 b'!' => $step = 10,
27 b'<' => $step = 1,
28 _ => $step = 0,
29 },
30 3 => match $e {
31 b's' | b'S' => $step = 4,
32 b'<' => $step = 1,
33 _ => $step = 0,
34 },
35 4 => match $e {
36 b'c' | b'C' => $step = 5,
37 b'<' => $step = 1,
38 _ => $step = 0,
39 },
40 5 => match $e {
41 b'r' | b'R' => $step = 6,
42 b'<' => $step = 1,
43 _ => $step = 0,
44 },
45 6 => match $e {
46 b'i' | b'I' => $step = 7,
47 b'<' => $step = 1,
48 _ => $step = 0,
49 },
50 7 => match $e {
51 b'p' | b'P' => $step = 8,
52 b'<' => $step = 1,
53 _ => $step = 0,
54 },
55 8 => match $e {
56 b't' | b'T' => $step = 9,
57 b'<' => $step = 1,
58 _ => $step = 0,
59 },
60 9 => match $e {
61 b'/' | b'>' | 9..=13 | 28..=32 => {
62 $step = 0;
63 $b
64 },
65 b'<' => $step = 1,
66 _ => $step = 0,
67 },
68 10 => match $e {
69 b'-' => $step = 11,
70 b'<' => $step = 1,
71 _ => $step = 0,
72 },
73 11 => match $e {
74 b'-' => {
75 $step = 0;
76 $bc
77 },
78 b'<' => $step = 1,
79 _ => $step = 0,
80 },
81 _ => unreachable!(),
82 }
83 };
84}
85
86decode_impl! {
87 7;
88 /// The following substring is unescaped:
89 ///
90 /// * `<\/script>` => `</script>`
91 /// * `<\!--` => `<!--`
92 ///
93 /// `<\/script` at the end of the text is also unescaped.
94 /// This only removes the listed escapes and does not parse JavaScript.
95 /// Existing escapes in the original text may also be removed, so encoding and decoding may not return the original text.
96 parse_script;
97 /// Decode text from the `<script>` element.
98 decode_script;
99 /// Write text from the `<script>` element to a mutable `String` reference and return the decoded string slice.
100 decode_script_to_string;
101 /// Write text from the `<script>` element to a mutable `Vec<u8>` reference and return the decoded data slice.
102 decode_script_to_vec;
103 /// Write text from the `<script>` element to a writer.
104 decode_script_to_writer;
105}
106
107decode_impl! {
108 quoted false, true, false;
109 /// Escapes emitted by the matching encoder are decoded.
110 /// Hex escapes use `\xHH` with uppercase digits; only escaped C0 controls and `<` are decoded.
111 /// `\u2028` and `\u2029` are also decoded.
112 /// Backslashes and `'` escaped with a backslash are decoded.
113 /// Legacy `<\/script>` and `<\!--` escapes are also decoded.
114 /// Unknown or incomplete escapes are kept, and decoded text is not decoded again.
115 raw_text;
116 /// Decode content of a single-quoted JavaScript string from `<script>`.
117 decode_script_single_quoted_text;
118 /// Decode content of a single-quoted JavaScript string to a mutable `String` and return the new string slice.
119 decode_script_single_quoted_text_to_string;
120 /// Decode content of a single-quoted JavaScript string to a mutable `Vec<u8>` and return the new data slice.
121 decode_script_single_quoted_text_to_vec;
122 /// Decode content of a single-quoted JavaScript string to a writer.
123 decode_script_single_quoted_text_to_writer;
124}
125
126decode_impl! {
127 quoted false, false, true;
128 /// Escapes emitted by the matching encoder are decoded.
129 /// Hex escapes use `\xHH` with uppercase digits; only escaped C0 controls and `<` are decoded.
130 /// `\u2028` and `\u2029` are also decoded.
131 /// Backslashes and `"` escaped with a backslash are decoded.
132 /// Legacy `<\/script>` and `<\!--` escapes are also decoded.
133 /// Unknown or incomplete escapes are kept, and decoded text is not decoded again.
134 raw_text;
135 /// Decode content of a double-quoted JavaScript string from `<script>`.
136 decode_script_double_quoted_text;
137 /// Decode content of a double-quoted JavaScript string to a mutable `String` and return the new string slice.
138 decode_script_double_quoted_text_to_string;
139 /// Decode content of a double-quoted JavaScript string to a mutable `Vec<u8>` and return the new data slice.
140 decode_script_double_quoted_text_to_vec;
141 /// Decode content of a double-quoted JavaScript string to a writer.
142 decode_script_double_quoted_text_to_writer;
143}
144
145decode_impl! {
146 quoted false, true, true;
147 /// Escapes emitted by the matching encoder are decoded.
148 /// Hex escapes use `\xHH` with uppercase digits; only escaped C0 controls and `<` are decoded.
149 /// `\u2028` and `\u2029` are also decoded.
150 /// Backslashes, `'`, and `"` escaped with a backslash are decoded.
151 /// Legacy `<\/script>` and `<\!--` escapes are also decoded.
152 /// Unknown or incomplete escapes are kept, and decoded text is not decoded again.
153 raw_text;
154 /// Decode content of a single-quoted or double-quoted JavaScript string from `<script>`.
155 decode_script_quoted_text;
156 /// Decode content of a single-quoted or double-quoted JavaScript string to a mutable `String` and return the new string slice.
157 decode_script_quoted_text_to_string;
158 /// Decode content of a single-quoted or double-quoted JavaScript string to a mutable `Vec<u8>` and return the new data slice.
159 decode_script_quoted_text_to_vec;
160 /// Decode content of a single-quoted or double-quoted JavaScript string to a writer.
161 decode_script_quoted_text_to_writer;
162}