From f0414d30d8e88e2ef55e1916c18726777fdcb1e3 Mon Sep 17 00:00:00 2001 From: Shuanglei Tao Date: Fri, 3 Feb 2017 11:23:59 +0800 Subject: [PATCH] Improve base64 decode and utf8 handling --- html/index.html | 5 +- html/js/app.js | 2 +- html/js/{overlay => }/overlay.js | 2 + html/js/utf8.js | 118 +++++++++++++++++++++++++++++++ src/index.html | 5 +- src/utils.c | 2 +- src/utils.h | 2 +- 7 files changed, 129 insertions(+), 7 deletions(-) rename html/js/{overlay => }/overlay.js (95%) create mode 100644 html/js/utf8.js diff --git a/html/index.html b/html/index.html index b5ed756..d252eaf 100644 --- a/html/index.html +++ b/html/index.html @@ -9,11 +9,12 @@ - + +
- \ No newline at end of file + diff --git a/html/js/app.js b/html/js/app.js index 3e085ba..c9127e6 100644 --- a/html/js/app.js +++ b/html/js/app.js @@ -52,7 +52,7 @@ var data = event.data.slice(1); switch(event.data[0]) { case '0': - term.write(decodeURIComponent(escape(window.atob(data)))); + term.writeUTF8(window.atob(data)); break; case '1': // pong break; diff --git a/html/js/overlay/overlay.js b/html/js/overlay.js similarity index 95% rename from html/js/overlay/overlay.js rename to html/js/overlay.js index d212368..d777276 100644 --- a/html/js/overlay/overlay.js +++ b/html/js/overlay.js @@ -1,4 +1,6 @@ // ported from hterm.Terminal.prototype.showOverlay +// https://chromium.googlesource.com/apps/libapps/+/master/hterm/js/hterm_terminal.js + Terminal.prototype.showOverlay = function(msg, timeout) { if (!this.overlayNode_) { if (!this.element) diff --git a/html/js/utf8.js b/html/js/utf8.js new file mode 100644 index 0000000..5a10144 --- /dev/null +++ b/html/js/utf8.js @@ -0,0 +1,118 @@ +// ported from hterm.Terminal.IO.prototype.writeUTF8 +// https://chromium.googlesource.com/apps/libapps/+/master/hterm/js/hterm_terminal_io.js + +UTF8Decoder = function() { + this.bytesLeft = 0; + this.codePoint = 0; + this.lowerBound = 0; +}; + +UTF8Decoder.prototype.decode = function(str) { + var ret = ''; + for (var i = 0; i < str.length; i++) { + var c = str.charCodeAt(i); + if (this.bytesLeft == 0) { + if (c <= 0x7F) { + ret += str.charAt(i); + } else if (0xC0 <= c && c <= 0xDF) { + this.codePoint = c - 0xC0; + this.bytesLeft = 1; + this.lowerBound = 0x80; + } else if (0xE0 <= c && c <= 0xEF) { + this.codePoint = c - 0xE0; + this.bytesLeft = 2; + this.lowerBound = 0x800; + } else if (0xF0 <= c && c <= 0xF7) { + this.codePoint = c - 0xF0; + this.bytesLeft = 3; + this.lowerBound = 0x10000; + } else if (0xF8 <= c && c <= 0xFB) { + this.codePoint = c - 0xF8; + this.bytesLeft = 4; + this.lowerBound = 0x200000; + } else if (0xFC <= c && c <= 0xFD) { + this.codePoint = c - 0xFC; + this.bytesLeft = 5; + this.lowerBound = 0x4000000; + } else { + ret += '\ufffd'; + } + } else { + if (0x80 <= c && c <= 0xBF) { + this.bytesLeft--; + this.codePoint = (this.codePoint << 6) + (c - 0x80); + if (this.bytesLeft == 0) { + var codePoint = this.codePoint; + if (codePoint < this.lowerBound + || (0xD800 <= codePoint && codePoint <= 0xDFFF) + || codePoint > 0x10FFFF) { + ret += '\ufffd'; + } else { + if (codePoint < 0x10000) { + ret += String.fromCharCode(codePoint); + } else { + codePoint -= 0x10000; + ret += String.fromCharCode( + 0xD800 + ((codePoint >>> 10) & 0x3FF), + 0xDC00 + (codePoint & 0x3FF)); + } + } + } + } else { + ret += '\ufffd'; + this.bytesLeft = 0; + i--; + } + } + } + return ret; +}; + +Terminal.prototype.decodeUTF8 = function(str) { + return (new UTF8Decoder()).decode(str); +}; + +Terminal.prototype.encodeUTF8 = function(str) { + var ret = ''; + for (var i = 0; i < str.length; i++) { + var c = str.charCodeAt(i); + if (0xDC00 <= c && c <= 0xDFFF) { + c = 0xFFFD; + } else if (0xD800 <= c && c <= 0xDBFF) { + if (i+1 < str.length) { + var d = str.charCodeAt(i+1); + if (0xDC00 <= d && d <= 0xDFFF) { + c = 0x10000 + ((c & 0x3FF) << 10) + (d & 0x3FF); + i++; + } else { + c = 0xFFFD; + } + } else { + c = 0xFFFD; + } + } + var bytesLeft; + if (c <= 0x7F) { + ret += str.charAt(i); + continue; + } else if (c <= 0x7FF) { + ret += String.fromCharCode(0xC0 | (c >>> 6)); + bytesLeft = 1; + } else if (c <= 0xFFFF) { + ret += String.fromCharCode(0xE0 | (c >>> 12)); + bytesLeft = 2; + } else { + ret += String.fromCharCode(0xF0 | (c >>> 18)); + bytesLeft = 3; + } + while (bytesLeft > 0) { + bytesLeft--; + ret += String.fromCharCode(0x80 | ((c >>> (6 * bytesLeft)) & 0x3F)); + } + } + return ret; +}; + +Terminal.prototype.writeUTF8 = function (str) { + this.write(this.decodeUTF8(str)); +}; diff --git a/src/index.html b/src/index.html index 7dddfb5..fb3ab57 100644 --- a/src/index.html +++ b/src/index.html @@ -10,11 +10,12 @@ +
- + - \ No newline at end of file + diff --git a/src/utils.c b/src/utils.c index be5cd16..180d495 100644 --- a/src/utils.c +++ b/src/utils.c @@ -37,7 +37,7 @@ uppercase(char *str) { } bool -endswith(const char * str, const char * suffix) { +endswith(const char *str, const char *suffix) { size_t str_len = strlen(str); size_t suffix_len = strlen(suffix); return str_len > suffix_len && !strcmp(str + (str_len - suffix_len), suffix); diff --git a/src/utils.h b/src/utils.h index 92b639a..ba75252 100644 --- a/src/utils.h +++ b/src/utils.h @@ -15,7 +15,7 @@ uppercase(char *str); // Check whether str ends with suffix bool -endswith(const char * str, const char * suffix); +endswith(const char *str, const char *suffix); // Get human readable signal string int -- 2.43.4