@@ -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,18 +460,25 @@ class TextDecoder {
446460 this [ kEncoding ] = enc ;
447461 this [ kIgnoreBOM ] = Boolean ( options ?. ignoreBOM ) ;
448462 this [ kFatal ] = Boolean ( options ?. fatal ) ;
449- this [ kUTF8FastPath ] = false ;
463+ this [ kBOMSeen ] = false ;
464+ this [ kUnicode ] = undefined ;
450465 this [ kHandle ] = undefined ;
451466 this [ kSingleByte ] = undefined ; // Does not care about streaming or BOM
452467 this [ kChunk ] = null ; // A copy of previous streaming tail or null
453468
454469 if ( enc === 'utf-8' ) {
455- this [ kUTF8FastPath ] = true ;
456- this [ kBOMSeen ] = false ;
457- } else if ( isSinglebyteEncoding ( enc ) ) {
458- this [ kSingleByte ] = createSinglebyteDecoder ( enc , this [ kFatal ] ) ;
470+ this [ kUnicode ] = decodeUTF8 ;
471+ } else if ( enc === 'utf-16le' ) {
472+ this [ kUnicode ] = decodeUTF16le ;
473+ } else if ( enc === 'utf-16be' ) {
474+ this [ kUnicode ] = decodeUTF16be ;
459475 } else {
460- this . #prepareConverter( ) ; // Need to throw early if we don't support the encoding
476+ this [ kUnicode ] = false ;
477+ if ( isSinglebyteEncoding ( enc ) ) {
478+ this [ kSingleByte ] = createSinglebyteDecoder ( enc , this [ kFatal ] ) ;
479+ } else {
480+ this . #prepareConverter( ) ; // Need to throw early if we don't support the encoding
481+ }
461482 }
462483 }
463484
@@ -469,10 +490,6 @@ class TextDecoder {
469490 if ( handle === undefined )
470491 throw new ERR_ENCODING_NOT_SUPPORTED ( this [ kEncoding ] ) ;
471492 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 ;
476493 } else {
477494 throw new ERR_ENCODING_NOT_SUPPORTED ( this [ kEncoding ] ) ;
478495 }
@@ -485,19 +502,19 @@ class TextDecoder {
485502 if ( this [ kSingleByte ] ) return this [ kSingleByte ] ( parseInput ( input ) ) ;
486503
487504 const stream = options ?. stream ;
488- if ( this [ kUTF8FastPath ] ) {
505+ if ( this [ kUnicode ] ) {
489506 const chunk = this [ kChunk ] ;
490507 const ignoreBom = this [ kIgnoreBOM ] || this [ kBOMSeen ] ;
491508 if ( ! stream ) {
492509 this [ kBOMSeen ] = false ;
493- if ( ! chunk ) return decodeUTF8 ( input , ignoreBom , this [ kFatal ] ) ;
510+ if ( ! chunk ) return this [ kUnicode ] ( input , ignoreBom , this [ kFatal ] ) ;
494511 }
495512
496513 let u = parseInput ( input ) ;
497514 if ( u . length === 0 && stream ) return '' ; // no state change
498515 let prefix ;
499516 if ( chunk ) {
500- const merged = mergePrefixUtf8 ( u , this [ kChunk ] ) ;
517+ const merged = mergePrefix ( u , this [ kChunk ] , this [ kEncoding ] ) ;
501518 if ( u . length < 3 ) {
502519 u = merged ; // Might be unfinished, but fully consumed old u
503520 } else {
@@ -510,7 +527,7 @@ class TextDecoder {
510527 }
511528
512529 if ( stream ) {
513- const trail = unfinishedBytesUtf8 ( u , u . length ) ;
530+ const trail = unfinishedBytes ( u , u . length , this [ kEncoding ] ) ;
514531 if ( trail > 0 ) {
515532 this [ kChunk ] = new FastBuffer ( u . subarray ( - trail ) ) ; // copy
516533 if ( ! prefix && trail === u . length ) return '' ; // No further state change
@@ -519,8 +536,8 @@ class TextDecoder {
519536 }
520537
521538 try {
522- const res = ( prefix ? decodeUTF8 ( prefix , ignoreBom , this [ kFatal ] ) : '' ) +
523- decodeUTF8 ( u , ignoreBom || prefix , this [ kFatal ] ) ;
539+ const res = ( prefix ? this [ kUnicode ] ( prefix , ignoreBom , this [ kFatal ] ) : '' ) +
540+ this [ kUnicode ] ( u , ignoreBom || prefix , this [ kFatal ] ) ;
524541
525542 // "BOM seen" is set on the current decode call only if it did not error,
526543 // in "serialize I/O queue" after decoding
@@ -541,22 +558,7 @@ class TextDecoder {
541558 return icuDecode ( this [ kHandle ] , input , flags , this [ kEncoding ] ) ;
542559 }
543560
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 ;
561+ // Unreachable
560562 }
561563}
562564
0 commit comments