@@ -20,6 +20,7 @@ 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 ,
2425 ERR_NO_ICU ,
2526} = require ( 'internal/errors' ) . codes ;
@@ -30,11 +31,11 @@ const kEncoding = Symbol('encoding');
3031const kDecoder = Symbol ( 'decoder' ) ;
3132const kChunk = Symbol ( 'chunk' ) ;
3233const kFatal = Symbol ( 'kFatal' ) ;
33- const kUTF8FastPath = Symbol ( 'kUTF8FastPath ' ) ;
34+ const kUnicode = Symbol ( 'kUnicode ' ) ;
3435const kIgnoreBOM = Symbol ( 'kIgnoreBOM' ) ;
3536
3637const { isSinglebyteEncoding, createSinglebyteDecoder } = require ( 'internal/encoding/single-byte' ) ;
37- const { unfinishedBytesUtf8 , mergePrefixUtf8 } = require ( 'internal/encoding/util' ) ;
38+ const { unfinishedBytes , mergePrefix } = require ( 'internal/encoding/util' ) ;
3839
3940const {
4041 getConstructorOf,
@@ -419,11 +420,24 @@ if (hasIntl) {
419420
420421const kBOMSeen = Symbol ( 'BOM seen' ) ;
421422
422- let StringDecoder ;
423- function lazyStringDecoder ( ) {
424- if ( StringDecoder === undefined )
425- ( { StringDecoder } = require ( 'string_decoder' ) ) ;
426- return StringDecoder ;
423+ function fixupDecodedString ( res , ignoreBom , fatal , encoding ) {
424+ if ( res . length === 0 ) return '' ;
425+ if ( ! ignoreBom && res [ 0 ] === '\ufeff' ) res = res . slice ( 1 ) ;
426+ if ( ! fatal ) return res . toWellFormed ( ) ;
427+ if ( ! res . isWellFormed ( ) ) throw new ERR_ENCODING_INVALID_ENCODED_DATA ( encoding , undefined ) ;
428+ return res ;
429+ }
430+
431+ function decodeUTF16le ( input , ignoreBom , fatal ) {
432+ return fixupDecodedString ( parseInput ( input ) . ucs2Slice ( ) , ignoreBom , fatal , 'utf-16le' ) ;
433+ }
434+
435+ function decodeUTF16be ( input , ignoreBom , fatal ) {
436+ const be = parseInput ( input )
437+ const le = new FastBuffer ( be . length )
438+ le . set ( be )
439+ le . swap16 ( )
440+ return fixupDecodedString ( le . ucs2Slice ( ) , ignoreBom , fatal , 'utf-16be' ) ;
427441}
428442
429443class TextDecoder {
@@ -446,33 +460,29 @@ class TextDecoder {
446460 this [ kEncoding ] = enc ;
447461 this [ kIgnoreBOM ] = Boolean ( options ?. ignoreBOM ) ;
448462 this [ kFatal ] = Boolean ( options ?. fatal ) ;
449- this [ kUTF8FastPath ] = false ;
463+ this [ kUnicode ] = undefined ;
450464 this [ kHandle ] = undefined ;
451465 this [ kSingleByte ] = undefined ; // Does not care about streaming or BOM
452466 this [ kChunk ] = null ; // A copy of previous streaming tail or null
453467
454468 if ( enc === 'utf-8' ) {
455- this [ kUTF8FastPath ] = true ;
469+ this [ kUnicode ] = decodeUTF8 ;
470+ this [ kBOMSeen ] = false ;
471+ } else if ( enc === 'utf-16le' ) {
472+ this [ kUnicode ] = decodeUTF16le ;
473+ this [ kBOMSeen ] = false ;
474+ } else if ( enc === 'utf-16be' ) {
475+ this [ kUnicode ] = decodeUTF16be ;
456476 this [ kBOMSeen ] = false ;
457477 } else if ( isSinglebyteEncoding ( enc ) ) {
458478 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 ) {
479+ } if ( hasIntl ) {
466480 let icuEncoding = this [ kEncoding ] ;
467481 if ( icuEncoding === 'gbk' ) icuEncoding = 'gb18030' ; // 10.1.1. GBK's decoder is gb18030's decoder
468482 const handle = icuGetConverter ( icuEncoding , this [ kFlags ] ) ;
469483 if ( handle === undefined )
470484 throw new ERR_ENCODING_NOT_SUPPORTED ( this [ kEncoding ] ) ;
471485 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 ;
476486 } else {
477487 throw new ERR_ENCODING_NOT_SUPPORTED ( this [ kEncoding ] ) ;
478488 }
@@ -485,19 +495,19 @@ class TextDecoder {
485495 if ( this [ kSingleByte ] ) return this [ kSingleByte ] ( parseInput ( input ) ) ;
486496
487497 const stream = options ?. stream ;
488- if ( this [ kUTF8FastPath ] ) {
498+ if ( this [ kUnicode ] ) {
489499 const chunk = this [ kChunk ] ;
490500 const ignoreBom = this [ kIgnoreBOM ] || this [ kBOMSeen ] ;
491501 if ( ! stream ) {
492502 this [ kBOMSeen ] = false ;
493- if ( ! chunk ) return decodeUTF8 ( input , ignoreBom , this [ kFatal ] ) ;
503+ if ( ! chunk ) return this [ kUnicode ] ( input , ignoreBom , this [ kFatal ] ) ;
494504 }
495505
496506 let u = parseInput ( input ) ;
497507 if ( u . length === 0 && stream ) return '' ; // no state change
498508 let prefix ;
499509 if ( chunk ) {
500- const merged = mergePrefixUtf8 ( u , this [ kChunk ] ) ;
510+ const merged = mergePrefix ( u , this [ kChunk ] , this [ kEncoding ] ) ;
501511 if ( u . length < 3 ) {
502512 u = merged ; // Might be unfinished, but fully consumed old u
503513 } else {
@@ -510,7 +520,7 @@ class TextDecoder {
510520 }
511521
512522 if ( stream ) {
513- const trail = unfinishedBytesUtf8 ( u , u . length ) ;
523+ const trail = unfinishedBytes ( u , u . length , this [ kEncoding ] ) ;
514524 if ( trail > 0 ) {
515525 this [ kChunk ] = new FastBuffer ( u . subarray ( - trail ) ) ; // copy
516526 if ( ! prefix && trail === u . length ) return '' ; // No further state change
@@ -519,8 +529,8 @@ class TextDecoder {
519529 }
520530
521531 try {
522- const res = ( prefix ? decodeUTF8 ( prefix , ignoreBom , this [ kFatal ] ) : '' ) +
523- decodeUTF8 ( u , ignoreBom || prefix , this [ kFatal ] ) ;
532+ const res = ( prefix ? this [ kUnicode ] ( prefix , ignoreBom , this [ kFatal ] ) : '' ) +
533+ this [ kUnicode ] ( u , ignoreBom || prefix , this [ kFatal ] ) ;
524534
525535 // "BOM seen" is set on the current decode call only if it did not error,
526536 // in "serialize I/O queue" after decoding
@@ -541,22 +551,7 @@ class TextDecoder {
541551 return icuDecode ( this [ kHandle ] , input , flags , this [ kEncoding ] ) ;
542552 }
543553
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 ;
554+ // Unreachable
560555 }
561556}
562557
0 commit comments