文字列をバイナリデータの配列に変換する方法について

ayaka_u
Kilo Contributor

こんにちは。

スコープアプリケーションで
GlideStringUtil.base64DecodeAsBytesと同等のことを実行したいと思っています。

スコープアプリケーション側で下記のようなスクリプトを作成してみたのですが、
出力される値がグローバル側でbase64DecodeAsBytesを使用した時と異なっているため、
同じように生成する方法がないかご教示頂きたいです。

以上、よろしくお願い致します。

 

Scoped

var str = "test";

var bytes = [];
for (var i = 0; i < str.length; i++) {
bytes.push(str.charCodeAt(i));
}
gs.info(JSON.stringify(bytes)); //[116,101,115,116]


Global

var str = "test";
var bytes = GlideStringUtil.base64DecodeAsBytes(str);
gs.print(JSON.stringify(bytes)); //[-75,-21,45]
1 ACCEPTED SOLUTION

Decodeと配列化を手作りしたScriptを作成しました。今回は投稿時のint8bit形式で出力するようにしました。Base64Decodeのために使用したScriptは下記のlinkです。

Base64 encoding and decoding in client-side Javascript - Stack Overflow

もし、Stringで良い場合はgs.base64Decodeで良いと思います。[65533,65533,45]になってしまったのは、Decodeで対応する文字コードがなくて文字化けしているからではないでしょうか。

"test"をEncode してから Decodeをすると下記のようになります。
base64Encode => "dGVzdA=="
base64Decode => "test"

int8bit 以外の数値化が良ければ下記Scriptの
r.push(a % 128 - (a >= 128 ? 128 : 0))
を変更してみてください。

decodeBase64 = function(s) {
    // String r=''
    //var e={},i,b=0,c,x,l=0,a,r='',w=String.fromCharCode,L=s.length;
    // Array r=[]
    var e={},i,b=0,c,x,l=0,a,r=[],w=String.fromCharCode,L=s.length;
    var A="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    for(i=0;i<64;i++){e[A.charAt(i)]=i;}
    for(x=0;x<L;x++){
        c=e[s.charAt(x)];b=(b<<6)+c;l+=6;
        //String (Original code)
        //while(l>=8){((a=(b>>>(l-=8))&0xff)||(x<(L-2)))&&(r+=w(a));}
        //int8bit
        while(l>=8){((a=(b>>>(l-=8))&0xff)||(x<(L-2)))&&(r.push(a % 128 - (a >= 128 ? 128 : 0)));}
    }
    return r;
};
var int8bit = decodeBase64('test');
gs.info(JSON.stringify(int8bit));

View solution in original post

3 REPLIES 3

iwai
Giga Sage

Scoped application で使えない機能であれば、無理して特殊な実装したりすべて手作りしたりしないで、Global Scope の Script include で 処理をして、値を取得するのはどうでしょうか。

それと、質問の件名では「文字列をバイナリデータの配列に変換する方法」となっていますが、質問の本文のScriptではBase64をデコードしてからバイナリーを受け取っています。単純な文字列なのか、Base64なのか、どちらのデータになるかによって処理は異なるので、少し気になりました。

下記に、Global Scope の Script include で実装した場合の参考例を作ってみました。単純な文字列の場合と、Base64それぞれでバイナリを取得します。Script include を作成するときは必ずGlobal Scopeで作成し、"Accessible from" を "All application scopes"としてください。

// Script include
// Name: testGlobalfunction
// Accessible from: All application scopes
// Scope: Global

var testGlobalfunction = Class.create();
testGlobalfunction.prototype = {
    initialize: function() {},

    base64DecodeAsBytes: function(str) {
        var bytes = global.GlideStringUtil.base64DecodeAsBytes(str);
        // return bytes; // そのままBytesでは扱えないので変換
        return j2js(bytes);
    },

    stringToBytes: function(str) {
        var bytes = Packages.java.lang.String(str).getBytes('UTF-8');
        return j2js(bytes);
    },

    type: 'testGlobalfunction'
};

 

呼び出す参考例

var str = "test";
var bytes;
bytes = new global.testGlobalfunction().base64DecodeAsBytes(str);
gs.info(str + ' => base64DecodeAsBytes '+JSON.stringify(bytes));

bytes = new global.testGlobalfunction().stringToBytes(str);
gs.info(str + ' => stringToBytes '+JSON.stringify(bytes));

//実行結果
//test => base64DecodeAsBytes [-75,-21,45]
//test => stringToBytes [116,101,115,116]

ayaka_u
Kilo Contributor

こんにちは、iwaiさん。

ご回答およびご提案ありがとうございます。
ですが、Scoped applicationで作成しないといけないため、
Global Scope の Script includeの処理だとダメそうです。
サンプルまで頂いたのにすみません。

また、質問の件名について、
正しくは「base64をバイナリデータの配列に変換する方法」ですね。
ややこしい内容で失礼いたしました。


ちなみに、ScopedApplicationで
strをbase64デコードしてから、変換してみましたが、
欲しい結果にはなりませんでした。(何かが違うみたいです…)

var str = "test";
str = gs.base64Decode(str);

var bytes = [];
for (var i = 0; i < str.length; i++) {
bytes.push(str.charCodeAt(i));
}
gs.info(JSON.stringify(bytes)); //[65533,65533,45]

 

Decodeと配列化を手作りしたScriptを作成しました。今回は投稿時のint8bit形式で出力するようにしました。Base64Decodeのために使用したScriptは下記のlinkです。

Base64 encoding and decoding in client-side Javascript - Stack Overflow

もし、Stringで良い場合はgs.base64Decodeで良いと思います。[65533,65533,45]になってしまったのは、Decodeで対応する文字コードがなくて文字化けしているからではないでしょうか。

"test"をEncode してから Decodeをすると下記のようになります。
base64Encode => "dGVzdA=="
base64Decode => "test"

int8bit 以外の数値化が良ければ下記Scriptの
r.push(a % 128 - (a >= 128 ? 128 : 0))
を変更してみてください。

decodeBase64 = function(s) {
    // String r=''
    //var e={},i,b=0,c,x,l=0,a,r='',w=String.fromCharCode,L=s.length;
    // Array r=[]
    var e={},i,b=0,c,x,l=0,a,r=[],w=String.fromCharCode,L=s.length;
    var A="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    for(i=0;i<64;i++){e[A.charAt(i)]=i;}
    for(x=0;x<L;x++){
        c=e[s.charAt(x)];b=(b<<6)+c;l+=6;
        //String (Original code)
        //while(l>=8){((a=(b>>>(l-=8))&0xff)||(x<(L-2)))&&(r+=w(a));}
        //int8bit
        while(l>=8){((a=(b>>>(l-=8))&0xff)||(x<(L-2)))&&(r.push(a % 128 - (a >= 128 ? 128 : 0)));}
    }
    return r;
};
var int8bit = decodeBase64('test');
gs.info(JSON.stringify(int8bit));