From ceb51ddaa187b188035dd0b01589f1d24d5e90c7 Mon Sep 17 00:00:00 2001 From: koichik Date: Sat, 5 May 2012 12:22:01 +0900 Subject: string_decoder: add support for CESU-8 Fixes #3217. --- lib/string_decoder.js | 49 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 14 deletions(-) (limited to 'lib/string_decoder.js') diff --git a/lib/string_decoder.js b/lib/string_decoder.js index 991b255e83..6e730c2fbd 100644 --- a/lib/string_decoder.js +++ b/lib/string_decoder.js @@ -22,7 +22,7 @@ var StringDecoder = exports.StringDecoder = function(encoding) { this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, ''); if (this.encoding === 'utf8') { - this.charBuffer = new Buffer(4); + this.charBuffer = new Buffer(6); this.charReceived = 0; this.charLength = 0; } @@ -36,16 +36,18 @@ StringDecoder.prototype.write = function(buffer) { } var charStr = ''; + var offset = 0; // if our last write ended with an incomplete multibyte character - if (this.charLength) { + while (this.charLength) { // determine how many remaining bytes this buffer has to offer for this char var i = (buffer.length >= this.charLength - this.charReceived) ? this.charLength - this.charReceived : buffer.length; // add the new bytes to the char buffer - buffer.copy(this.charBuffer, this.charReceived, 0, i); - this.charReceived += i; + buffer.copy(this.charBuffer, this.charReceived, offset, i); + this.charReceived += (i - offset); + offset = i; if (this.charReceived < this.charLength) { // still not enough chars in this buffer? wait for more ... @@ -54,6 +56,16 @@ StringDecoder.prototype.write = function(buffer) { // get the character that was split charStr = this.charBuffer.slice(0, this.charLength).toString(); + + // lead surrogate (D800-DBFF) is also the incomplete character + if (this.charLength === 3) { + var charCode = charStr.charCodeAt(0); + if (charCode >= 0xD800 && charCode <= 0xDBFF) { + charStr = ''; + this.charLength += 3; // size of trail surrogate (DC00-DFFF) + continue; + } + } this.charReceived = this.charLength = 0; // if there are no more bytes in this buffer, just emit our char @@ -61,6 +73,7 @@ StringDecoder.prototype.write = function(buffer) { // otherwise cut off the characters end from the beginning of this buffer buffer = buffer.slice(i, buffer.length); + break; } @@ -93,18 +106,26 @@ StringDecoder.prototype.write = function(buffer) { } } - if (!this.charLength) { - // no incomplete char at the end of this buffer, emit the whole thing - return charStr + buffer.toString(); + var end = buffer.length; + if (this.charLength) { + // buffer the incomplete character bytes we got + buffer.copy(this.charBuffer, 0, buffer.length - i, buffer.length); + this.charReceived = i; + end -= i; } - // buffer the incomplete character bytes we got - buffer.copy(this.charBuffer, 0, buffer.length - i, buffer.length); - this.charReceived = i; - - if (buffer.length - i > 0) { - // buffer had more bytes before the incomplete char, emit them - return charStr + buffer.toString('utf8', 0, buffer.length - i); + charStr += buffer.toString('utf8', 0, end); + + // lead surrogate (D800-DBFF) is also the incomplete character + end = charStr.length - 1; + var charCode = charStr.charCodeAt(end); + if (charCode >= 0xD800 && charCode <= 0xDBFF) { + // CESU-8 represents each of Surrogate Pair by 3-bytes + this.charLength += 3 + this.charReceived += 3 + this.charBuffer.copy(this.charBuffer, 3, 0, 3); + this.charBuffer.write(charStr.charAt(end)); + return charStr.substring(0, end); } // or just emit the charStr -- cgit v1.2.3