JScriptでBase64変換

なげぇ・・

JScript/JavaScriptではバイナリを直接扱えないので、COMの力を借ります。

半分くらいバイナリ扱う為のクラスの定義(BinaryStream)

俺々JScriptフレームワーク(wscjsfw)の一部です。

 

ファイル

Base64.zip
Base64エンコード、デコードJScript

 

以下コード

Object.extend = function(destination, source)
{
    for (var property in source) {
        destination[property] = source[property];
    }
    return destination;
}
String.prototype.ToCharArray = function()
{
    var str = this;
    var ret = [];
    while(str != "")
    {
        ret.push(str.substring(0, 1));
        str = str.substring(1);
    }
    return ret;
}

var SeekOrign = function(){};
SeekOrign.Begin = 1;                        // シークモード(ストリームの最初から)
SeekOrign.Current = 2;                        // シークモード(現在位置から)
SeekOrign.End = 3;                            // シークモード(ストリームの最後から)
/**
 * バイナリストリーム
 */
var BinaryStream = function()
{
    this.stream = new ActiveXObject("ADODB.Stream");
};
Object.extend(BinaryStream.prototype, {
    /**
     * 内部ストリーム
     */
    stream : null,
    /**
     * ストリームを開く
     */
    Open : function()
    {
        this.stream.Type = 2; //adTypeText
        this.stream.Charset = 'iso-8859-1';
        this.stream.Open();
    },
    /**
     * ファイルからデータをロードする
     * param
     *     file ファイルまたはファイルパス
     */
    LoadFromFile : function(file)
    {
        var filename = file.path ? String(file.path) : String(file);
        this.stream.LoadFromFile(filename);
    },
    /**
     * ファイルにデータを保存する
     * param
     *     file ファイルまたはファイルパス
     */
    SaveToFile : function(file)
    {
        var filename = file.path ? String(file.path) : String(file);
        this.stream.SaveToFile(filename, 2); // adSaveCreateOverWrite
    },
    /**
     * ストリームを閉じる
     */
    Close : function()
    {
        this.stream.Close();
    },
    /**
     * ストリームの終わりかを返却する
     * return true:ストリームの終わり / ストリームの終わりでない
     */
    IsEnd : function()
    {
        return this.stream.EOS;
    },
    /**
     * サイズを取得する
     * return ストリームサイズ(byte)
     */
    GetSize : function()
    {
        return this.stream.Size;
    },
    /**
     * 現在位置を取得する
     * return 現在位置
     */
    GetPosition : function()
    {
        return this.stream.Position;
    },
    /**
     * ストリームからデータを読み込む
     * param
     *     size 取得するデータのサイズ(byte)
     * return 取得したデータ
     */
    Read : function(size)
    {
        var len = this.stream.Size - this.stream.Position;
        size = Math.min(len, size);

        var result = [];
        var _position = this.stream.Position;
        this.stream.Position = 0;
        this.stream.Charset = "ascii";
        this.stream.Position = _position;
        var s1 = this.stream.ReadText(size);

        this.stream.Position = 0;
        this.stream.Charset = "iso-8859-1";
        this.stream.Position = _position;
        var s2 = this.stream.ReadText(size);

        for(var i = 0; i < s1.length; i++)
        {
            result.push(s1.charCodeAt(i) | (s2.charCodeAt(i) < 0x80 ? 0 : 0x80));
        }

        return result;
    },
    /**
     * 現在位置からストリームから末尾までのデータを読み込む
     * return 取得したデータ
     */
    ReadToEnd : function()
    {
        return this.Read(this.stream.Size);
    },
    /**
     * ストリームにデータを書き込む
     * param
     *     size 書き込むデータ
     */
    Write : function(data)
    {
        var _position = this.stream.Position;
        this.stream.Position = 0;
        this.stream.Charset = 'iso-8859-1';
        this.stream.Position = _position;
        for(var i = 0; i< data.length; i++)
        {
            this.stream.WriteText(String.fromCharCode(data[i] & 0xFF));
        }
    },
    /**
     * シークを行う
     * param
     *     position シークの相対距離
     *     [orign] シークモード(SeekOrign)
     */
    Seek : function(position, orign)
    {
        switch(orign)
        {
            case SeekOrign.Current: position += this.stream.Position; break;
            case SeekOrign.End: position = this.stream.Size - position;
        }
        this.stream.Position = Math.max(Math.min(position, this.stream.Size), 0);
    }
});

/**
 * Base64クラス
 */
var Base64 = function(){};
/**
 * Base64エンコードテーブル
 */
Base64.EncTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".ToCharArray();
/**
 * Base64デコードテーブル
 */
Base64.DecTable = function(){};
// Base64デコードテーブル作成
for(var i = 0 ; i < Base64.EncTable.length; i++)
{
    Base64.DecTable[Base64.EncTable[i]] = i;
}
/**
 * Base64エンコード
 * param
 *     data エンコードするバイナリデータ
 * return エンコード後の文字列
 */
Base64.Encode = function(data)
{
    var result = "";
    var l = Math.floor(data.length / 3);
    var index = 0;
    for(var i = 0 ; i < l ; i++)
    {
        result +=
            Base64.EncTable[data[index]>>2] +
            Base64.EncTable[((data[index  ]<<4) | (data[index+1]>>4)) & 0x3F] +
            Base64.EncTable[((data[index+1]<<2) | (data[index+2]>>6)) & 0x3F] +
            Base64.EncTable[( data[index+2]                         ) & 0x3F];
        index += 3;
    }
    
    switch(data.length % 3)
    {
        case 1:
            result +=
                Base64.EncTable[data[index]>>2] +
                Base64.EncTable[(data[index  ]<<4) & 0x30] + "==";
            break;
        case 2:
            result +=
                Base64.EncTable[data[index]>>2] +
                Base64.EncTable[((data[index  ]<<4) | (data[index+1]>>4)) & 0x3F] +
                Base64.EncTable[ (data[index+1]<<2) & 0x3C] + "=";
            break;
    }

    return result;
}
/**
 * Base64デコード
 * param
 *     data デコードする文字列
 * return デコード後のバイナリデータ
 */
Base64.Decode = function(data)
{
    var result = [];
    var l = Math.floor(data.length / 4) - 1;
    var work = data.ToCharArray();
    var index = 0;
    for(var i = 0 ; i < l ; i++)
    {
        result.push(((Base64.DecTable[work[index  ]]<<2) | (Base64.DecTable[work[index+1]]>>4)) & 0xFF);
        result.push(((Base64.DecTable[work[index+1]]<<4) | (Base64.DecTable[work[index+2]]>>2)) & 0xFF);
        result.push(((Base64.DecTable[work[index+2]]<<6) | (Base64.DecTable[work[index+3]]   )) & 0xFF);
        index+=4;
    }
    
    if(work[index+2] == "=")
    {
        result.push(((Base64.DecTable[work[index  ]]<<2) | (Base64.DecTable[work[index+1]]>>4)) & 0xFF);
    }
    else if(work[index+3] == "=")
    {
        result.push(((Base64.DecTable[work[index  ]]<<2) | (Base64.DecTable[work[index+1]]>>4)) & 0xFF);
        result.push(((Base64.DecTable[work[index+1]]<<4) | (Base64.DecTable[work[index+2]]>>2)) & 0xFF);
    }
    else
    {
        result.push(((Base64.DecTable[work[index  ]]<<2) | (Base64.DecTable[work[index+1]]>>4)) & 0xFF);
        result.push(((Base64.DecTable[work[index+1]]<<4) | (Base64.DecTable[work[index+2]]>>2)) & 0xFF);
        result.push(((Base64.DecTable[work[index+2]]<<6) | (Base64.DecTable[work[index+3]]   )) & 0xFF);
    }

    return result;
}

// テストコード
var binaryData = [1,2,3,4,5];
var base64String = Base64.Encode(binaryData); // Base64エンコード
WScript.Echo(base64String); // 表示
var decodedData = Base64.Decode(base64String) // Base64デコード
var validate = true; // 検証結果

// デコード前のデータと比較して検証
validate = binaryData.length == decodedData.length;
for(var i = 0; (i < binaryData.length) && validate; i++)
    validate = binaryData[i] == decodedData[i];

WScript.Echo(validate ? "検証成功" : "検証失敗");

2010.08.06