* Performs decode on given content. * @protected * @param {Chain} content * @return {number[]|string|Uint8Array|Chain|Promise} Decoded content
(content)
| 164 | * @return {number[]|string|Uint8Array|Chain|Promise} Decoded content |
| 165 | */ |
| 166 | performDecode (content) { |
| 167 | const { alphabet, decodeMap, padding, decodeContentFilter } = |
| 168 | this.getVariantOptions() |
| 169 | |
| 170 | // Apply variant filter before decoding |
| 171 | if (decodeContentFilter === 'uppercase') { |
| 172 | content = content.toUpperCase() |
| 173 | } |
| 174 | |
| 175 | // Add alphabet characters to decode map |
| 176 | for (let i = 0; i < alphabet.getLength(); i++) { |
| 177 | decodeMap[alphabet.getCodePointAt(i)] = i |
| 178 | } |
| 179 | |
| 180 | // Prepare input and output arrays |
| 181 | const input = content.getCodePoints() |
| 182 | const inputLength = input.length |
| 183 | const resultSize = Math.ceil(inputLength / 8) * 5 |
| 184 | const result = new Uint8Array(resultSize) |
| 185 | let j = 0 |
| 186 | |
| 187 | let shift = 8 |
| 188 | let carry = 0 |
| 189 | let codePoint, index |
| 190 | |
| 191 | // Go through every input code point |
| 192 | for (let i = 0; i < inputLength; i++) { |
| 193 | codePoint = input[i] |
| 194 | |
| 195 | if (codePoint === padding) { |
| 196 | // Ignore padding |
| 197 | } else if (decodeMap[codePoint] === undefined) { |
| 198 | // Unexpected code point not being part of the alphabet or map |
| 199 | throw new InvalidInputError(`Unexpected code point at index ${i}`) |
| 200 | } else { |
| 201 | // Decode character |
| 202 | index = decodeMap[codePoint] & 0xff |
| 203 | shift -= 5 |
| 204 | if (shift > 0) { |
| 205 | carry |= index << shift |
| 206 | } else if (shift < 0) { |
| 207 | result[j++] = carry | (index >> -shift) |
| 208 | shift += 8 |
| 209 | carry = (index << shift) & 0xff |
| 210 | } else { |
| 211 | result[j++] = carry | index |
| 212 | shift = 8 |
| 213 | carry = 0 |
| 214 | } |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | // Slice result to remove padding |
| 219 | return result.slice(0, j) |
| 220 | } |
| 221 | |
| 222 | /** |
| 223 | * Triggered when a setting field has changed. |
nothing calls this directly
no test coverage detected