diff options
author | koichik <koichik@improvement.jp> | 2012-05-05 12:22:01 +0900 |
---|---|---|
committer | koichik <koichik@improvement.jp> | 2012-05-05 12:24:01 +0900 |
commit | ceb51ddaa187b188035dd0b01589f1d24d5e90c7 (patch) | |
tree | 12b57894b35e5c17ed545d1aff71326406ddfe55 /lib/string_decoder.js | |
parent | eaf607e88b632a80d59dde04bd08dae5cb2c7bb8 (diff) | |
download | node-new-ceb51ddaa187b188035dd0b01589f1d24d5e90c7.tar.gz |
string_decoder: add support for CESU-8
Fixes #3217.
Diffstat (limited to 'lib/string_decoder.js')
-rw-r--r-- | lib/string_decoder.js | 49 |
1 files changed, 35 insertions, 14 deletions
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 |