| 'use strict'; |
| |
| const { |
| Array, |
| Int8Array, |
| NumberPrototypeToString, |
| StringPrototypeCharCodeAt, |
| StringPrototypeSlice, |
| StringPrototypeToUpperCase, |
| } = primordials; |
| |
| const { ERR_INVALID_URI } = require('internal/errors').codes; |
| |
| const hexTable = new Array(256); |
| for (let i = 0; i < 256; ++i) |
| hexTable[i] = '%' + |
| StringPrototypeToUpperCase((i < 16 ? '0' : '') + |
| NumberPrototypeToString(i, 16)); |
| |
| const isHexTable = new Int8Array([ |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15 |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31 |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32 - 47 |
| 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63 |
| 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 64 - 79 |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80 - 95 |
| 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 96 - 111 |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 112 - 127 |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128 ... |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ... 256 |
| ]); |
| |
| /** |
| * @param {string} str |
| * @param {Int8Array} noEscapeTable |
| * @param {string[]} hexTable |
| * @returns {string} |
| */ |
| function encodeStr(str, noEscapeTable, hexTable) { |
| const len = str.length; |
| if (len === 0) |
| return ''; |
| |
| let out = ''; |
| let lastPos = 0; |
| let i = 0; |
| |
| outer: |
| for (; i < len; i++) { |
| let c = StringPrototypeCharCodeAt(str, i); |
| |
| // ASCII |
| while (c < 0x80) { |
| if (noEscapeTable[c] !== 1) { |
| if (lastPos < i) |
| out += StringPrototypeSlice(str, lastPos, i); |
| lastPos = i + 1; |
| out += hexTable[c]; |
| } |
| |
| if (++i === len) |
| break outer; |
| |
| c = StringPrototypeCharCodeAt(str, i); |
| } |
| |
| if (lastPos < i) |
| out += StringPrototypeSlice(str, lastPos, i); |
| |
| // Multi-byte characters ... |
| if (c < 0x800) { |
| lastPos = i + 1; |
| out += hexTable[0xC0 | (c >> 6)] + |
| hexTable[0x80 | (c & 0x3F)]; |
| continue; |
| } |
| if (c < 0xD800 || c >= 0xE000) { |
| lastPos = i + 1; |
| out += hexTable[0xE0 | (c >> 12)] + |
| hexTable[0x80 | ((c >> 6) & 0x3F)] + |
| hexTable[0x80 | (c & 0x3F)]; |
| continue; |
| } |
| // Surrogate pair |
| ++i; |
| |
| // This branch should never happen because all URLSearchParams entries |
| // should already be converted to USVString. But, included for |
| // completion's sake anyway. |
| if (i >= len) |
| throw new ERR_INVALID_URI(); |
| |
| const c2 = StringPrototypeCharCodeAt(str, i) & 0x3FF; |
| |
| lastPos = i + 1; |
| c = 0x10000 + (((c & 0x3FF) << 10) | c2); |
| out += hexTable[0xF0 | (c >> 18)] + |
| hexTable[0x80 | ((c >> 12) & 0x3F)] + |
| hexTable[0x80 | ((c >> 6) & 0x3F)] + |
| hexTable[0x80 | (c & 0x3F)]; |
| } |
| if (lastPos === 0) |
| return str; |
| if (lastPos < len) |
| return out + StringPrototypeSlice(str, lastPos); |
| return out; |
| } |
| |
| module.exports = { |
| encodeStr, |
| hexTable, |
| isHexTable |
| }; |