|
70 | 70 | // Throw INVALID_CHARACTER_ERR exception here -- won't be hit in the tests.
|
71 | 71 | }
|
72 | 72 |
|
73 |
| -/** |
74 |
| - * Implementation of atob() according to the HTML spec, except that instead of |
75 |
| - * throwing INVALID_CHARACTER_ERR we return null. |
76 |
| - */ |
77 |
| -function myatob(input) { |
78 |
| - // WebIDL requires DOMStrings to just be converted using ECMAScript |
79 |
| - // ToString, which in our case amounts to calling String(). |
80 |
| - input = String(input); |
81 |
| - |
82 |
| - // "Remove all space characters from input." |
83 |
| - input = input.replace(/[ \t\n\f\r]/g, ""); |
84 |
| - |
85 |
| - // "If the length of input divides by 4 leaving no remainder, then: if |
86 |
| - // input ends with one or two U+003D EQUALS SIGN (=) characters, remove |
87 |
| - // them from input." |
88 |
| - if (input.length % 4 == 0 && /==?$/.test(input)) { |
89 |
| - input = input.replace(/==?$/, ""); |
90 |
| - } |
91 |
| - |
92 |
| - // "If the length of input divides by 4 leaving a remainder of 1, throw an |
93 |
| - // INVALID_CHARACTER_ERR exception and abort these steps." |
94 |
| - // |
95 |
| - // "If input contains a character that is not in the following list of |
96 |
| - // characters and character ranges, throw an INVALID_CHARACTER_ERR |
97 |
| - // exception and abort these steps: |
98 |
| - // |
99 |
| - // U+002B PLUS SIGN (+) |
100 |
| - // U+002F SOLIDUS (/) |
101 |
| - // U+0030 DIGIT ZERO (0) to U+0039 DIGIT NINE (9) |
102 |
| - // U+0041 LATIN CAPITAL LETTER A to U+005A LATIN CAPITAL LETTER Z |
103 |
| - // U+0061 LATIN SMALL LETTER A to U+007A LATIN SMALL LETTER Z" |
104 |
| - if (input.length % 4 == 1 |
105 |
| - || !/^[+/0-9A-Za-z]*$/.test(input)) { |
106 |
| - return null; |
107 |
| - } |
108 |
| - |
109 |
| - // "Let output be a string, initially empty." |
110 |
| - var output = ""; |
111 |
| - |
112 |
| - // "Let buffer be a buffer that can have bits appended to it, initially |
113 |
| - // empty." |
114 |
| - // |
115 |
| - // We append bits via left-shift and or. accumulatedBits is used to track |
116 |
| - // when we've gotten to 24 bits. |
117 |
| - var buffer = 0; |
118 |
| - var accumulatedBits = 0; |
119 |
| - |
120 |
| - // "While position does not point past the end of input, run these |
121 |
| - // substeps:" |
122 |
| - for (var i = 0; i < input.length; i++) { |
123 |
| - // "Find the character pointed to by position in the first column of |
124 |
| - // the following table. Let n be the number given in the second cell of |
125 |
| - // the same row." |
126 |
| - // |
127 |
| - // "Append to buffer the six bits corresponding to number, most |
128 |
| - // significant bit first." |
129 |
| - // |
130 |
| - // atobLookup() implements the table from the spec. |
131 |
| - buffer <<= 6; |
132 |
| - buffer |= atobLookup(input[i]); |
133 |
| - |
134 |
| - // "If buffer has accumulated 24 bits, interpret them as three 8-bit |
135 |
| - // big-endian numbers. Append the three characters with code points |
136 |
| - // equal to those numbers to output, in the same order, and then empty |
137 |
| - // buffer." |
138 |
| - accumulatedBits += 6; |
139 |
| - if (accumulatedBits == 24) { |
140 |
| - output += String.fromCharCode((buffer & 0xff0000) >> 16); |
141 |
| - output += String.fromCharCode((buffer & 0xff00) >> 8); |
142 |
| - output += String.fromCharCode(buffer & 0xff); |
143 |
| - buffer = accumulatedBits = 0; |
144 |
| - } |
145 |
| - |
146 |
| - // "Advance position by one character." |
147 |
| - } |
148 |
| - |
149 |
| - // "If buffer is not empty, it contains either 12 or 18 bits. If it |
150 |
| - // contains 12 bits, discard the last four and interpret the remaining |
151 |
| - // eight as an 8-bit big-endian number. If it contains 18 bits, discard the |
152 |
| - // last two and interpret the remaining 16 as two 8-bit big-endian numbers. |
153 |
| - // Append the one or two characters with code points equal to those one or |
154 |
| - // two numbers to output, in the same order." |
155 |
| - if (accumulatedBits == 12) { |
156 |
| - buffer >>= 4; |
157 |
| - output += String.fromCharCode(buffer); |
158 |
| - } else if (accumulatedBits == 18) { |
159 |
| - buffer >>= 2; |
160 |
| - output += String.fromCharCode((buffer & 0xff00) >> 8); |
161 |
| - output += String.fromCharCode(buffer & 0xff); |
162 |
| - } |
163 |
| - |
164 |
| - // "Return output." |
165 |
| - return output; |
166 |
| -} |
167 |
| - |
168 |
| -/** |
169 |
| - * A lookup table for atob(), which converts an ASCII character to the |
170 |
| - * corresponding six-bit number. |
171 |
| - */ |
172 |
| -function atobLookup(chr) { |
173 |
| - if (/[A-Z]/.test(chr)) { |
174 |
| - return chr.charCodeAt(0) - "A".charCodeAt(0); |
175 |
| - } |
176 |
| - if (/[a-z]/.test(chr)) { |
177 |
| - return chr.charCodeAt(0) - "a".charCodeAt(0) + 26; |
178 |
| - } |
179 |
| - if (/[0-9]/.test(chr)) { |
180 |
| - return chr.charCodeAt(0) - "0".charCodeAt(0) + 52; |
181 |
| - } |
182 |
| - if (chr == "+") { |
183 |
| - return 62; |
184 |
| - } |
185 |
| - if (chr == "/") { |
186 |
| - return 63; |
187 |
| - } |
188 |
| - // Throw exception; should not be hit in tests |
189 |
| -} |
190 |
| - |
191 | 73 | function btoaException(input) {
|
192 | 74 | input = String(input);
|
193 | 75 | for (var i = 0; i < input.length; i++) {
|
|
252 | 134 |
|
253 | 135 | generate_tests(testBtoa, tests);
|
254 | 136 |
|
255 |
| -function testAtob(input) { |
256 |
| - var expected = myatob(input); |
257 |
| - if (expected === null) { |
258 |
| - assert_throws("InvalidCharacterError", function() { atob(input) }); |
259 |
| - return; |
260 |
| - } |
261 |
| - |
262 |
| - assert_equals(atob(input), expected); |
263 |
| -} |
264 |
| - |
265 |
| -var tests = ["", "abcd", " abcd", "abcd ", " abcd===", "abcd=== ", |
266 |
| - "abcd ===", "a", "ab", "abc", "abcde", String.fromCharCode(0xd800, 0xdc00), |
267 |
| - "=", "==", "===", "====", "=====", |
268 |
| - "a=", "a==", "a===", "a====", "a=====", |
269 |
| - "ab=", "ab==", "ab===", "ab====", "ab=====", |
270 |
| - "abc=", "abc==", "abc===", "abc====", "abc=====", |
271 |
| - "abcd=", "abcd==", "abcd===", "abcd====", "abcd=====", |
272 |
| - "abcde=", "abcde==", "abcde===", "abcde====", "abcde=====", |
273 |
| - "=a", "=a=", "a=b", "a=b=", "ab=c", "ab=c=", "abc=d", "abc=d=", |
274 |
| - // With whitespace |
275 |
| - "ab\tcd", "ab\ncd", "ab\fcd", "ab\rcd", "ab cd", "ab\u00a0cd", |
276 |
| - "ab\t\n\f\r cd", " \t\n\f\r ab\t\n\f\r cd\t\n\f\r ", |
277 |
| - "ab\t\n\f\r =\t\n\f\r =\t\n\f\r ", |
278 |
| - // Test if any bits are set at the end. These should all be fine, since |
279 |
| - // they end with A, which becomes 0: |
280 |
| - "A", "/A", "//A", "///A", "////A", |
281 |
| - // These are all bad, since they end in / (= 63, all bits set) but their |
282 |
| - // length isn't a multiple of four characters, so they can't be output by |
283 |
| - // btoa(). Thus one might expect some UAs to throw exceptions or otherwise |
284 |
| - // object, since they could never be output by btoa(), so they're good to |
285 |
| - // test. |
286 |
| - "/", "A/", "AA/", "AAAA/", |
287 |
| - // But this one is possible: |
288 |
| - "AAA/", |
289 |
| - // Binary-safety tests |
290 |
| - "\0nonsense", "abcd\0nonsense", |
291 |
| - // WebIDL tests |
292 |
| - undefined, null, 7, 12, 1.5, true, false, NaN, +Infinity, -Infinity, 0, -0, |
293 |
| - {toString: function() { return "foo" }}, |
294 |
| - {toString: function() { return "abcd" }}, |
| 137 | +promise_test(() => fetch("../../../fetch/data-urls/resources/base64.json").then(res => res.json()).then(runAtobTests), "atob() setup."); |
| 138 | + |
| 139 | +const idlTests = [ |
| 140 | + [undefined, null], |
| 141 | + [null, [158, 233, 101]], |
| 142 | + [7, null], |
| 143 | + [12, [215]], |
| 144 | + [1.5, null], |
| 145 | + [true, [182, 187]], |
| 146 | + [false, null], |
| 147 | + [NaN, [53, 163]], |
| 148 | + [+Infinity, [34, 119, 226, 158, 43, 114]], |
| 149 | + [-Infinity, null], |
| 150 | + [0, null], |
| 151 | + [-0, null], |
| 152 | + [{toString: function() { return "foo" }}, [126, 138]], |
| 153 | + [{toString: function() { return "abcd" }}, [105, 183, 29]] |
295 | 154 | ];
|
296 |
| -tests = tests.map( |
297 |
| - function(elem) { |
298 |
| - if (myatob(elem) === null) { |
299 |
| - return ["atob(" + format_value(elem) + ") must raise InvalidCharacterError", elem]; |
300 |
| - } |
301 |
| - return ["atob(" + format_value(elem) + ") == " + format_value(myatob(elem)), elem]; |
302 |
| - } |
303 |
| -); |
304 | 155 |
|
305 |
| -generate_tests(testAtob, tests); |
| 156 | +function runAtobTests(tests) { |
| 157 | + const allTests = tests.concat(idlTests); |
| 158 | + for(let i = 0; i < allTests.length; i++) { |
| 159 | + const input = allTests[i][0], |
| 160 | + output = allTests[i][1]; |
| 161 | + test(() => { |
| 162 | + if(output === null) { |
| 163 | + assert_throws("InvalidCharacterError", () => window.atob(input)); |
| 164 | + } else { |
| 165 | + const result = window.atob(input); |
| 166 | + for(let ii = 0; ii < output.length; ii++) { |
| 167 | + assert_equals(result.charCodeAt(ii), output[ii]); |
| 168 | + } |
| 169 | + } |
| 170 | + }, "atob(" + format_value(input) + ")"); |
| 171 | + } |
| 172 | +} |
306 | 173 | </script>
|
0 commit comments