var StringDecoder = exports.StringDecoder = function (encoding){ this.encoding = _AN_Call_replace('replace', (encoding || 'utf8').toLowerCase(), /[-_]/, ''); switch (this.encoding){ case 'utf8': this.surrogateSize = 3; break ; case 'ucs2': case 'utf16le': this.surrogateSize = 2; this.detectIncompleteChar = utf16DetectIncompleteChar; break ; default : { this.write = passThroughWrite; return ; } } this.charBuffer = new Buffer(6); this.charReceived = 0; this.charLength = 0; } ; StringDecoder.prototype.write = function (buffer){ var charStr = ''; var offset = 0; while (this.charLength){ var i = (_AN_Read_length('length', buffer) >= this.charLength - this.charReceived)? this.charLength - this.charReceived: _AN_Read_length('length', buffer); buffer.copy(this.charBuffer, this.charReceived, offset, i); this.charReceived += (i - offset); offset = i; if (this.charReceived < this.charLength) { return ''; } charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding); var charCode = charStr.charCodeAt(_AN_Read_length('length', charStr) - 1); if (charCode >= 55296 && charCode <= 56319) { this.charLength += this.surrogateSize; charStr = ''; continue ; } this.charReceived = this.charLength = 0; if (i == _AN_Read_length('length', buffer)) return charStr; buffer = buffer.slice(i, _AN_Read_length('length', buffer)); break ; } var lenIncomplete = this.detectIncompleteChar(buffer); var end = _AN_Read_length('length', buffer); if (this.charLength) { buffer.copy(this.charBuffer, 0, _AN_Read_length('length', buffer) - lenIncomplete, end); this.charReceived = lenIncomplete; end -= lenIncomplete; } charStr += buffer.toString(this.encoding, 0, end); var end = _AN_Read_length('length', charStr) - 1; var charCode = charStr.charCodeAt(end); if (charCode >= 55296 && charCode <= 56319) { var size = this.surrogateSize; this.charLength += size; this.charReceived += size; this.charBuffer.copy(this.charBuffer, size, 0, size); _AN_Call_write('write', this.charBuffer, charStr.charAt(_AN_Read_length('length', charStr) - 1), this.encoding); return charStr.substring(0, end); } return charStr; } ; StringDecoder.prototype.detectIncompleteChar = function (buffer){ var i = (_AN_Read_length('length', buffer) >= 3)? 3: _AN_Read_length('length', buffer); for (; i > 0; i-- ){ var c = buffer[_AN_Read_length('length', buffer) - i]; if (i == 1 && c >> 5 == 6) { this.charLength = 2; break ; } if (i <= 2 && c >> 4 == 14) { this.charLength = 3; break ; } if (i <= 3 && c >> 3 == 30) { this.charLength = 4; break ; } } return i; } ; function passThroughWrite(buffer){ return buffer.toString(this.encoding); } function utf16DetectIncompleteChar(buffer){ var incomplete = this.charReceived = _AN_Read_length('length', buffer) % 2; this.charLength = incomplete? 2: 0; return incomplete; }