| 157 | } |
| 158 | |
| 159 | static _encodeCodePointsToUTF8Bytes (codePoints) { |
| 160 | // In the worst case every code point needs to be represented by 4 bytes |
| 161 | // Create a fixed size array that gets sliced at the end |
| 162 | const bytes = new Uint8Array(codePoints.length * 4) |
| 163 | let j = 0 |
| 164 | let i, codePoint |
| 165 | |
| 166 | for (i = 0; i < codePoints.length; i++) { |
| 167 | codePoint = codePoints[i] |
| 168 | |
| 169 | if (codePoint <= 0x7F) { |
| 170 | // 1 byte: 0xxxxxxx |
| 171 | bytes[j++] = codePoint |
| 172 | } else if (codePoint <= 0x7FF) { |
| 173 | // 2 bytes: 110xxxxx 10xxxxxx |
| 174 | bytes[j++] = 0b11000000 | (codePoint >> 6) |
| 175 | bytes[j++] = 0b10000000 | (codePoint & 0x3F) |
| 176 | } else if (codePoint <= 0xFFFF) { |
| 177 | // 3 bytes: 1110xxxx 10xxxxxx 10xxxxxx |
| 178 | bytes[j++] = 0b11100000 | (codePoint >> 12) |
| 179 | bytes[j++] = 0b10000000 | ((codePoint & 0xFFF) >> 6) |
| 180 | bytes[j++] = 0b10000000 | (codePoint & 0x3F) |
| 181 | } else { |
| 182 | // 4 bytes: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
| 183 | bytes[j++] = 0b11110000 | (codePoint >> 18) |
| 184 | bytes[j++] = 0b10000000 | ((codePoint & 0x3FFFF) >> 12) |
| 185 | bytes[j++] = 0b10000000 | ((codePoint & 0xFFF) >> 6) |
| 186 | bytes[j++] = 0b10000000 | (codePoint & 0x3F) |
| 187 | } |
| 188 | } |
| 189 | |
| 190 | // Slice the fixed size array to the portion actually in use |
| 191 | return bytes.slice(0, j) |
| 192 | } |
| 193 | |
| 194 | static _decodeCodePointsFromUTF8Bytes (bytes) { |
| 195 | // In the worst case byte needs to be represented by one code point |