miércoles, 10 de julio de 2013

Codificación de base 2 a base 63 en JavaScript

El método toString sólo admite hasta la base 36, así que hay que partir de una nueva codificación. Base32 no tiene la especificación rfc4648, pero con el presente objeto se pueden codificar todos los caracteres desde la base 2 a la 63 (aunque podrían ser más):
//------------------------------------------------------------------------------------------------
// Engines      JavaScript 1.3+
//              JScript    5.5+
// Environments NN4.06+ IE5.5+ MOZILLA1+ SAFARI1+
//------------------------------------------------------------------------------------------------
var Coding =
{
      Num:
      {
            codec : '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_'
          , getBlockSize : function (b /* radix [2..63] */)
            {
                if      (b == 2)          b = 8;
                else if (b == 3)          b = 6;
                else if (b > 3 && b < 7)  b = 4;
                else if (b > 6 && b < 16) b = 3;
                else                      b = 2;
 
                return b;  
            }

            //------------------------------------------------------------------------------------

          , encode: function (n /* number */, b /* radix [2..63] */)
            {
                var s = '';
                if (!isNaN(n) && !isNaN(b)) 
                {
                    if (typeof n == 'string')
                        n = parseInt(n);
 
                    b = Math.min(Math.max(2, b), 63);
       
                    do
                    {
                        s = this.codec.charAt(n % b) + s;
                        n = Math.floor(n / b)
                    }
 
                    while (n > 0);
     
                    n = Coding.Num.getBlockSize(b);
                    b = s.length;
     
                    while (b++ < n)
                        s = '0' + s;
                }

                return s;
            }

            //------------------------------------------------------------------------------------

          , decode: function (s /* src */, b /* radix [2..63] */)
            {
                var n = 0;
                if (s != null && !isNaN(b))
                {
                    b = Math.min(Math.max(2, b), 63);
        
                    for (var i = 0, l = (s += '').length; i < l; ++i)
                        n = n * b + this.codec.indexOf(s.charAt(i));
                }

                return n;
            }
      }

      //-----------------------------------------------------------------------------------------

    , Base2x63:
      {
            encode: function (s /* src */, b /* base [2..63] */)
            {
                var r = '';
                if (s != null && !isNaN(b))
                {
                    b = Math.min(Math.max(b, 2), 63);

                    for (var i = 0, l = (s += '').length; i < l; ++i)
                        r += Coding.Num.encode(s.charCodeAt(i), b);
                }

                return r;
            }

            //------------------------------------------------------------------------------------

         , decode: function (s /* src */, b /* base [2..63] */)
           {
                var n, r = '';
                if (s != null && !isNaN(b))
                {
                    b = Math.min(Math.max(b, 2), 63);
                    n = Coding.Num.getBlockSize(b);
     
                    for (var i = 0, l = (s += '').length; i < l; i += n)
                        r += String.fromCharCode(Coding.Num.decode(s.substr(i, n), b));
                }

                return r;
           }
      }
};
Test:
var e, s = 'Tomaré una decisión con la cigüeña.';
for (var i = 2; i < 64; ++i)
{
    e = Coding.Base2x63.encode(s, i);
    alert
    (
        'base: ' + i + ', length: ' + e.length + ', encoded: ' + e + ', decoded: ' + 
        Coding.Base2x63.decode(e, i)
    );
}

No hay comentarios:

Publicar un comentario