* Minimal UTF-8 decoder * @param {Uint8Array} bytes * @returns {string}
(bytes)
| 366 | * @returns {string} |
| 367 | */ |
| 368 | function decodeUtf8(bytes) { |
| 369 | let i = 0; |
| 370 | const l = bytes.length; |
| 371 | const codeUnits = []; |
| 372 | let result = ''; |
| 373 | |
| 374 | while (i < l) { |
| 375 | const byte1 = bytes[i++]; |
| 376 | |
| 377 | // 1-byte (ASCII) |
| 378 | if (byte1 < 0x80) { |
| 379 | codeUnits.push(byte1); |
| 380 | } |
| 381 | // 2-byte |
| 382 | else if (byte1 < 0xe0) { |
| 383 | const byte2 = bytes[i++] & 0x3f; |
| 384 | codeUnits.push(((byte1 & 0x1f) << 6) | byte2); |
| 385 | } |
| 386 | // 3-byte |
| 387 | else if (byte1 < 0xf0) { |
| 388 | const byte2 = bytes[i++] & 0x3f; |
| 389 | const byte3 = bytes[i++] & 0x3f; |
| 390 | codeUnits.push(((byte1 & 0x0f) << 12) | (byte2 << 6) | byte3); |
| 391 | } |
| 392 | // 4-byte (→ surrogate pair) |
| 393 | else { |
| 394 | const byte2 = bytes[i++] & 0x3f; |
| 395 | const byte3 = bytes[i++] & 0x3f; |
| 396 | const byte4 = bytes[i++] & 0x3f; |
| 397 | let cp = ((byte1 & 0x07) << 18) | (byte2 << 12) | (byte3 << 6) | byte4; |
| 398 | cp -= 0x10000; |
| 399 | codeUnits.push(0xd800 + (cp >> 10), 0xdc00 + (cp & 0x3ff)); |
| 400 | } |
| 401 | |
| 402 | // Flush periodically to avoid huge apply() calls |
| 403 | if (codeUnits.length > 0x8000) { |
| 404 | result += String.fromCharCode.apply(null, codeUnits); |
| 405 | codeUnits.length = 0; |
| 406 | } |
| 407 | } |
| 408 | |
| 409 | return result + String.fromCharCode.apply(null, codeUnits); |
| 410 | } |
no test coverage detected