@@ -20,8 +20,8 @@ const { FastBuffer } = require('internal/buffer');
2020const {
2121 ERR_ENCODING_NOT_SUPPORTED ,
2222 ERR_INVALID_ARG_TYPE ,
23+ ERR_ENCODING_INVALID_ENCODED_DATA ,
2324 ERR_INVALID_THIS ,
24- ERR_NO_ICU ,
2525} = require ( 'internal/errors' ) . codes ;
2626const kSingleByte = Symbol ( 'single-byte' ) ;
2727const kHandle = Symbol ( 'handle' ) ;
@@ -30,11 +30,11 @@ const kEncoding = Symbol('encoding');
3030const kDecoder = Symbol ( 'decoder' ) ;
3131const kChunk = Symbol ( 'chunk' ) ;
3232const kFatal = Symbol ( 'kFatal' ) ;
33- const kUTF8FastPath = Symbol ( 'kUTF8FastPath ' ) ;
33+ const kUnicode = Symbol ( 'kUnicode ' ) ;
3434const kIgnoreBOM = Symbol ( 'kIgnoreBOM' ) ;
3535
3636const { isSinglebyteEncoding, createSinglebyteDecoder } = require ( 'internal/encoding/single-byte' ) ;
37- const { unfinishedBytesUtf8 , mergePrefixUtf8 } = require ( 'internal/encoding/util' ) ;
37+ const { unfinishedBytes , mergePrefix } = require ( 'internal/encoding/util' ) ;
3838
3939const {
4040 getConstructorOf,
@@ -419,11 +419,24 @@ if (hasIntl) {
419419
420420const kBOMSeen = Symbol ( 'BOM seen' ) ;
421421
422- let StringDecoder ;
423- function lazyStringDecoder ( ) {
424- if ( StringDecoder === undefined )
425- ( { StringDecoder } = require ( 'string_decoder' ) ) ;
426- return StringDecoder ;
422+ function fixupDecodedString ( res , ignoreBom , fatal , encoding ) {
423+ if ( res . length === 0 ) return '' ;
424+ if ( ! ignoreBom && res [ 0 ] === '\ufeff' ) res = StringPrototypeSlice ( res , 1 ) ;
425+ if ( ! fatal ) return res . toWellFormed ( ) ;
426+ if ( ! res . isWellFormed ( ) ) throw new ERR_ENCODING_INVALID_ENCODED_DATA ( encoding , undefined ) ;
427+ return res ;
428+ }
429+
430+ function decodeUTF16le ( input , ignoreBom , fatal ) {
431+ return fixupDecodedString ( parseInput ( input ) . ucs2Slice ( ) , ignoreBom , fatal , 'utf-16le' ) ;
432+ }
433+
434+ function decodeUTF16be ( input , ignoreBom , fatal ) {
435+ const be = parseInput ( input ) ;
436+ const le = new FastBuffer ( be . length ) ;
437+ le . set ( be ) ;
438+ le . swap16 ( ) ;
439+ return fixupDecodedString ( le . ucs2Slice ( ) , ignoreBom , fatal , 'utf-16be' ) ;
427440}
428441
429442class TextDecoder {
@@ -446,33 +459,29 @@ class TextDecoder {
446459 this [ kEncoding ] = enc ;
447460 this [ kIgnoreBOM ] = Boolean ( options ?. ignoreBOM ) ;
448461 this [ kFatal ] = Boolean ( options ?. fatal ) ;
449- this [ kUTF8FastPath ] = false ;
462+ this [ kUnicode ] = undefined ;
450463 this [ kHandle ] = undefined ;
451464 this [ kSingleByte ] = undefined ; // Does not care about streaming or BOM
452465 this [ kChunk ] = null ; // A copy of previous streaming tail or null
453466
454467 if ( enc === 'utf-8' ) {
455- this [ kUTF8FastPath ] = true ;
468+ this [ kUnicode ] = decodeUTF8 ;
469+ this [ kBOMSeen ] = false ;
470+ } else if ( enc === 'utf-16le' ) {
471+ this [ kUnicode ] = decodeUTF16le ;
472+ this [ kBOMSeen ] = false ;
473+ } else if ( enc === 'utf-16be' ) {
474+ this [ kUnicode ] = decodeUTF16be ;
456475 this [ kBOMSeen ] = false ;
457476 } else if ( isSinglebyteEncoding ( enc ) ) {
458477 this [ kSingleByte ] = createSinglebyteDecoder ( enc , this [ kFatal ] ) ;
459- } else {
460- this . #prepareConverter( ) ; // Need to throw early if we don't support the encoding
461- }
462- }
463-
464- #prepareConverter( ) {
465- if ( hasIntl ) {
478+ } if ( hasIntl ) {
466479 let icuEncoding = this [ kEncoding ] ;
467480 if ( icuEncoding === 'gbk' ) icuEncoding = 'gb18030' ; // 10.1.1. GBK's decoder is gb18030's decoder
468481 const handle = icuGetConverter ( icuEncoding , this [ kFlags ] ) ;
469482 if ( handle === undefined )
470483 throw new ERR_ENCODING_NOT_SUPPORTED ( this [ kEncoding ] ) ;
471484 this [ kHandle ] = handle ;
472- } else if ( this [ kEncoding ] === 'utf-16le' ) {
473- if ( this [ kFatal ] ) throw new ERR_NO_ICU ( '"fatal" option' ) ;
474- this [ kHandle ] = new ( lazyStringDecoder ( ) ) ( this [ kEncoding ] ) ;
475- this [ kBOMSeen ] = false ;
476485 } else {
477486 throw new ERR_ENCODING_NOT_SUPPORTED ( this [ kEncoding ] ) ;
478487 }
@@ -485,19 +494,19 @@ class TextDecoder {
485494 if ( this [ kSingleByte ] ) return this [ kSingleByte ] ( parseInput ( input ) ) ;
486495
487496 const stream = options ?. stream ;
488- if ( this [ kUTF8FastPath ] ) {
497+ if ( this [ kUnicode ] ) {
489498 const chunk = this [ kChunk ] ;
490499 const ignoreBom = this [ kIgnoreBOM ] || this [ kBOMSeen ] ;
491500 if ( ! stream ) {
492501 this [ kBOMSeen ] = false ;
493- if ( ! chunk ) return decodeUTF8 ( input , ignoreBom , this [ kFatal ] ) ;
502+ if ( ! chunk ) return this [ kUnicode ] ( input , ignoreBom , this [ kFatal ] ) ;
494503 }
495504
496505 let u = parseInput ( input ) ;
497506 if ( u . length === 0 && stream ) return '' ; // no state change
498507 let prefix ;
499508 if ( chunk ) {
500- const merged = mergePrefixUtf8 ( u , this [ kChunk ] ) ;
509+ const merged = mergePrefix ( u , this [ kChunk ] , this [ kEncoding ] ) ;
501510 if ( u . length < 3 ) {
502511 u = merged ; // Might be unfinished, but fully consumed old u
503512 } else {
@@ -510,7 +519,7 @@ class TextDecoder {
510519 }
511520
512521 if ( stream ) {
513- const trail = unfinishedBytesUtf8 ( u , u . length ) ;
522+ const trail = unfinishedBytes ( u , u . length , this [ kEncoding ] ) ;
514523 if ( trail > 0 ) {
515524 this [ kChunk ] = new FastBuffer ( u . subarray ( - trail ) ) ; // copy
516525 if ( ! prefix && trail === u . length ) return '' ; // No further state change
@@ -519,8 +528,8 @@ class TextDecoder {
519528 }
520529
521530 try {
522- const res = ( prefix ? decodeUTF8 ( prefix , ignoreBom , this [ kFatal ] ) : '' ) +
523- decodeUTF8 ( u , ignoreBom || prefix , this [ kFatal ] ) ;
531+ const res = ( prefix ? this [ kUnicode ] ( prefix , ignoreBom , this [ kFatal ] ) : '' ) +
532+ this [ kUnicode ] ( u , ignoreBom || prefix , this [ kFatal ] ) ;
524533
525534 // "BOM seen" is set on the current decode call only if it did not error,
526535 // in "serialize I/O queue" after decoding
@@ -541,22 +550,7 @@ class TextDecoder {
541550 return icuDecode ( this [ kHandle ] , input , flags , this [ kEncoding ] ) ;
542551 }
543552
544- input = parseInput ( input ) ;
545-
546- let result = stream ? this [ kHandle ] . write ( input ) : this [ kHandle ] . end ( input ) ;
547-
548- if ( result . length > 0 && ! this [ kBOMSeen ] && ! this [ kIgnoreBOM ] ) {
549- // If the very first result in the stream is a BOM, and we are not
550- // explicitly told to ignore it, then we discard it.
551- if ( result [ 0 ] === '\ufeff' ) {
552- result = StringPrototypeSlice ( result , 1 ) ;
553- }
554- this [ kBOMSeen ] = true ;
555- }
556-
557- if ( ! stream ) this [ kBOMSeen ] = false ;
558-
559- return result ;
553+ // Unreachable
560554 }
561555}
562556
0 commit comments