Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-20395] iOS: Ti.Utils.base64encode is not encoding unicode correctly

GitHub Issuen/a
TypeBug
PriorityLow
StatusClosed
ResolutionDuplicate
Resolution Date2017-08-08T22:25:39.000+0000
Affected Version/sRelease 5.1.2, Release 5.1.1
Fix Version/sn/a
ComponentsTiAPI
Labelsbase64
Reporter Ricardo Ramirez
AssigneeHans Knöchel
Created2016-02-12T19:41:21.000+0000
Updated2018-08-06T17:41:05.000+0000

Description

Issue Description

Trying to encode the string using Ti.Utils.base64enocde method as below,
Ti.Utils.base64encode('Test実験室じっけんしつ').
It returns the encoded string : VGVzdOWun+mok+WupA== But trying to encode the same string in https://www.base64encode.org/ returns the encoded string : VGVzdOWun+mok+WupOOBmOOBo+OBkeOCk+OBl+OBpA== Ti.Utils.base64encode method encodes the partial string only.

Steps to reproduce/Testcase

Create a new classic default application

open the app.js file

replace the code

var win = Ti.UI.createWindow({backgroundColor:"white"});
var testStr = "Test実験室じっけんしつ";
var encoded = Ti.Utils.base64encode(testStr);
Ti.API.info(encoded);
win.open();
#Run The return string don't match with the https://www.base64encode.org/ string

Comments

  1. Ricardo Ramirez 2016-02-12

    Workaround:
       var win = Ti.UI.createWindow({backgroundColor:"white"});
       
       var Base64 = {
       
       
           _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
       
       
           encode: function(input) {
               var output = "";
               var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
               var i = 0;
       
               input = Base64._utf8_encode(input);
       
               while (i < input.length) {
       
                   chr1 = input.charCodeAt(i++);
                   chr2 = input.charCodeAt(i++);
                   chr3 = input.charCodeAt(i++);
       
                   enc1 = chr1 >> 2;
                   enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
                   enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
                   enc4 = chr3 & 63;
       
                   if (isNaN(chr2)) {
                       enc3 = enc4 = 64;
                   } else if (isNaN(chr3)) {
                       enc4 = 64;
                   }
       
                   output = output + this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) + this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
       
               }
       
               return output;
           },
       
       
           decode: function(input) {
               var output = "";
               var chr1, chr2, chr3;
               var enc1, enc2, enc3, enc4;
               var i = 0;
       
               input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
       
               while (i < input.length) {
       
                   enc1 = this._keyStr.indexOf(input.charAt(i++));
                   enc2 = this._keyStr.indexOf(input.charAt(i++));
                   enc3 = this._keyStr.indexOf(input.charAt(i++));
                   enc4 = this._keyStr.indexOf(input.charAt(i++));
       
                   chr1 = (enc1 << 2) | (enc2 >> 4);
                   chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
                   chr3 = ((enc3 & 3) << 6) | enc4;
       
                   output = output + String.fromCharCode(chr1);
       
                   if (enc3 != 64) {
                       output = output + String.fromCharCode(chr2);
                   }
                   if (enc4 != 64) {
                       output = output + String.fromCharCode(chr3);
                   }
       
               }
       
               output = Base64._utf8_decode(output);
       
               return output;
       
           },
       
           _utf8_encode: function(string) {
               string = string.replace(/\r\n/g, "\n");
               var utftext = "";
       
               for (var n = 0; n < string.length; n++) {
       
                   var c = string.charCodeAt(n);
       
                   if (c < 128) {
                       utftext += String.fromCharCode(c);
                   }
                   else if ((c > 127) && (c < 2048)) {
                       utftext += String.fromCharCode((c >> 6) | 192);
                       utftext += String.fromCharCode((c & 63) | 128);
                   }
                   else {
                       utftext += String.fromCharCode((c >> 12) | 224);
                       utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                       utftext += String.fromCharCode((c & 63) | 128);
                   }
       
               }
       
               return utftext;
           },
       
           _utf8_decode: function(utftext) {
               var string = "";
               var i = 0;
               var c = c1 = c2 = 0;
       
               while (i < utftext.length) {
       
                   c = utftext.charCodeAt(i);
       
                   if (c < 128) {
                       string += String.fromCharCode(c);
                       i++;
                   }
                   else if ((c > 191) && (c < 224)) {
                       c2 = utftext.charCodeAt(i + 1);
                       string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                       i += 2;
                   }
                   else {
                       c2 = utftext.charCodeAt(i + 1);
                       c3 = utftext.charCodeAt(i + 2);
                       string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                       i += 3;
                   }
       
               }
       
               return string;
           }
       
       };
       
       var testStr = "Test実験室じっけんしつ";
       //var encoded = Ti.Utils.base64encode('testStr');
       var encoded = Base64.encode(testStr);
       Ti.API.info(encoded);
       
       win.open();
       
  2. Hans Knöchel 2017-08-08

    [~emerriman] We should do this together with the related issues (TIMOB-16606, TIMOB-15590) and TIMOB-9111 which would be a breaking change by removing the "\n" characters from the string. I would do it for 7.0.0 then, but if this urges, we can do the encoding fix before and the new-line changes in 7.0.0. *EDIT*: TIMOB-9111 is ready for review and will be part of 7.0.0. In the mean-time, here is a tiny Hyperloop solution that can be used to use the correct encoding today - without an SDK upgrade or native module:
       var NSUTF8StringEncoding = require('Foundation').NSUTF8StringEncoding;
       
       var myString = 'Test実験室じっけんしつ';
       var base64EncodedData = myString.dataUsingEncoding(NSUTF8StringEncoding);
       var base64EncodedString = base64EncodedData.base64EncodedStringWithOptions(0);
       
       Ti.API.info('Base 64 Encoded: ' + base64EncodedString);
       
  3. Eric Merriman 2018-08-06

    Closing as a duplicate. If this is in error, please reopen.

JSON Source