export class StringDecoder { lastNeed : number ; lastTotal : number ; lastChar : Buffer ; constructor ( ) { this . lastNeed = 0 ; this . lastTotal = 0 ; this . lastChar = Buffer . allocUnsafe ( 4 ) ; } write ( buf ) { if ( buf . length === 0 ) { return buf ; } let r = undefined ; let i = 0 ; if ( this . lastNeed ) { r = this . fillLast ( buf ) ; if ( r === undefined ) { return Buffer . from ( '' ) ; } i = this . lastNeed ; this . lastNeed = 0 ; } if ( i < buf . length ) { return r ? Buffer . concat ( [ r , this . text ( buf , i ) ] ) : this . text ( buf , i ) ; } return r ; } end ( buf ? ) { const r = buf ?. length ? this . write ( buf ) : Buffer . from ( '' ) ; if ( this . lastNeed ) { console . log ( 'end' , r ) ; return Buffer . concat ( [ r , Buffer . from ( '\ufffd' ) ] ) ; } return r ; } private text ( buf , i ) { const total = this . utf8CheckIncomplete ( buf , i ) ; if ( ! this . lastNeed ) { return buf . slice ( i ) ; } this . lastTotal = total ; const end = buf . length - ( total - this . lastNeed ) ; buf . copy ( this . lastChar , 0 , end ) ; return buf . slice ( i , end ) ; } private fillLast ( buf ) { if ( this . lastNeed <= buf . length ) { buf . copy ( this . lastChar , this . lastTotal - this . lastNeed , 0 , this . lastNeed ) ; return this . lastChar . slice ( 0 , this . lastTotal ) ; } buf . copy ( this . lastChar , this . lastTotal - this . lastNeed , 0 , buf . length ) ; this . lastNeed -= buf . length ; return undefined ; } private utf8CheckByte ( byte ) { if ( byte <= 0x7F ) { return 0 ; } else if ( byte >> 5 === 0x06 ) { return 2 ; } else if ( byte >> 4 === 0x0E ) { return 3 ; } else if ( byte >> 3 === 0x1E ) { return 4 ; } return byte >> 6 === 0x02 ? - 1 : - 2 ; } private utf8CheckIncomplete ( buf , i ) { let j = buf . length - 1 ; if ( j < i ) { return 0 ; } let nb = this . utf8CheckByte ( buf [ j ] ) ; if ( nb >= 0 ) { if ( nb > 0 ) { this . lastNeed = nb - 1 ; } return nb ; } if ( -- j < i || nb === - 2 ) { return 0 ; } nb = this . utf8CheckByte ( buf [ j ] ) ; if ( nb >= 0 ) { if ( nb > 0 ) { this . lastNeed = nb - 2 ; } return nb ; } if ( -- j < i || nb === - 2 ) { return 0 ; } nb = this . utf8CheckByte ( buf [ j ] ) ; if ( nb >= 0 ) { if ( nb > 0 ) { if ( nb === 2 ) { nb = 0 ; } else { this . lastNeed = nb - 3 ; } } return nb ; } return 0 ; } }