From 92a9213fd0239045a8f4467de9f4814cf7237156 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Tue, 8 Apr 2014 12:34:02 -0700 Subject: [PATCH] GUAC-608: Implement UTF-8 encode in StringWriter. --- .../src/main/webapp/modules/StringWriter.js | 129 +++++++++++++++++- 1 file changed, 126 insertions(+), 3 deletions(-) diff --git a/guacamole-common-js/src/main/webapp/modules/StringWriter.js b/guacamole-common-js/src/main/webapp/modules/StringWriter.js index b11c159ce..a9a06240a 100644 --- a/guacamole-common-js/src/main/webapp/modules/StringWriter.js +++ b/guacamole-common-js/src/main/webapp/modules/StringWriter.js @@ -38,19 +38,142 @@ Guacamole.StringWriter = function(stream) { */ var guac_writer = this; + /** + * Wrapped Guacamole.ArrayBufferWriter. + * @private + * @type Guacamole.ArrayBufferWriter + */ + var array_writer = new Guacamole.ArrayBufferWriter(stream); + + /** + * Internal buffer for UTF-8 output. + * @private + */ + var buffer = new Uint8Array(8192); + + /** + * The number of bytes currently in the buffer. + * @private + */ + var length = 0; + // Simply call onack for acknowledgements - stream.onack = function(status) { + array_writer.onack = function(status) { if (guac_writer.onack) guac_writer.onack(status); }; + /** + * Expands the size of the underlying buffer by the given number of bytes, + * updating the length appropriately. + * + * @private + * @param {Number} bytes The number of bytes to add to the underlying + * buffer. + */ + function __expand(bytes) { + + // Resize buffer if more space needed + if (length+bytes >= buffer.length) { + var new_buffer = new Uint8Array((length+bytes)*2); + new_buffer.set(buffer); + buffer = new_buffer; + } + + length += bytes; + + } + + /** + * Appends a single Unicode character to the current buffer, resizing the + * buffer if necessary. The character will be encoded as UTF-8. + * + * @private + * @param {Number} codepoint The codepoint of the Unicode character to + * append. + */ + function __append_utf8(codepoint) { + + var mask; + var bytes; + + // 1 byte + if (codepoint <= 0x7F) { + mask = 0x00; + bytes = 1; + } + + // 2 byte + else if (codepoint <= 0x7FF) { + mask = 0xC0; + bytes = 2; + } + + // 3 byte + else if (codepoint <= 0xFFFF) { + mask = 0xE0; + bytes = 3; + } + + // 4 byte + else if (codepoint <= 0x1FFFFF) { + mask = 0xF0; + bytes = 4; + } + + // If invalid codepoint, append replacement character + else { + __append_utf8(0xFFFD); + return; + } + + // Offset buffer by size + __expand(bytes); + var offset = length - 1; + + // Add trailing bytes, if any + for (var i=1; i>= 6; + } + + // Set initial byte + buffer[offset] = mask | codepoint; + + } + + /** + * Encodes the given string as UTF-8, returning an ArrayBuffer containing + * the resulting bytes. + * + * @private + * @param {String} text The string to encode as UTF-8. + * @return {Uint8Array} The encoded UTF-8 data. + */ + function __encode_utf8(text) { + + // Fill buffer with UTF-8 + for (var i=0; i 0) { + var out_buffer = buffer.subarray(0, length); + length = 0; + return out_buffer; + } + + } + /** * Sends the given text. * * @param {String} text The text to send. */ this.sendText = function(text) { - stream.sendBlob(window.btoa(text)); + array_writer.sendData(__encode_utf8(text)); }; /** @@ -58,7 +181,7 @@ Guacamole.StringWriter = function(stream) { * stream. */ this.sendEnd = function() { - stream.sendEnd(); + array_writer.sendEnd(); }; /**