(input = empty, options = kEmptyObject)
| 479 | } |
| 480 | |
| 481 | decode(input = empty, options = kEmptyObject) { |
| 482 | validateDecoder(this); |
| 483 | validateObject(options, 'options', kValidateObjectAllowObjectsAndNull); |
| 484 | |
| 485 | if (this[kSingleByte]) return this[kSingleByte](parseInput(input)); |
| 486 | |
| 487 | const stream = options?.stream; |
| 488 | if (this[kUTF8FastPath]) { |
| 489 | const chunk = this[kChunk]; |
| 490 | const ignoreBom = this[kIgnoreBOM] || this[kBOMSeen]; |
| 491 | if (!stream) { |
| 492 | this[kBOMSeen] = false; |
| 493 | if (!chunk) return decodeUTF8(input, ignoreBom, this[kFatal]); |
| 494 | } |
| 495 | |
| 496 | let u = parseInput(input); |
| 497 | if (u.length === 0 && stream) return ''; // no state change |
| 498 | let prefix; |
| 499 | if (chunk) { |
| 500 | const merged = mergePrefixUtf8(u, this[kChunk]); |
| 501 | if (u.length < 3) { |
| 502 | u = merged; // Might be unfinished, but fully consumed old u |
| 503 | } else { |
| 504 | prefix = merged; // Stops at complete chunk |
| 505 | const add = prefix.length - this[kChunk].length; |
| 506 | if (add > 0) u = u.subarray(add); |
| 507 | } |
| 508 | |
| 509 | this[kChunk] = null; |
| 510 | } |
| 511 | |
| 512 | if (stream) { |
| 513 | const trail = unfinishedBytesUtf8(u, u.length); |
| 514 | if (trail > 0) { |
| 515 | this[kChunk] = new FastBuffer(u.subarray(-trail)); // copy |
| 516 | if (!prefix && trail === u.length) return ''; // No further state change |
| 517 | u = u.subarray(0, -trail); |
| 518 | } |
| 519 | } |
| 520 | |
| 521 | try { |
| 522 | const res = (prefix ? decodeUTF8(prefix, ignoreBom, this[kFatal]) : '') + |
| 523 | decodeUTF8(u, ignoreBom || prefix, this[kFatal]); |
| 524 | |
| 525 | // "BOM seen" is set on the current decode call only if it did not error, |
| 526 | // in "serialize I/O queue" after decoding |
| 527 | // We don't get here if we had no complete data to process, |
| 528 | // and we don't want BOM processing after that if streaming |
| 529 | if (stream) this[kBOMSeen] = true; |
| 530 | |
| 531 | return res; |
| 532 | } catch (e) { |
| 533 | this[kChunk] = null; // Reset unfinished chunk on errors |
| 534 | // The correct way per spec seems to be not destroying the decoder state (aka BOM here) in stream mode |
| 535 | throw e; |
| 536 | } |
| 537 | } |
| 538 |
no test coverage detected