/**********************************************************************
 ** PROJECT        XA Base64 handling Alogorithms v1.0.0
 ** MODUL          xa-base64 v1.0.0
 ** Filename       xa-base64.js
 ** $Id: $
 ** Purpose
 ** Copyright      Copyright(C) by XenoAntares, XI 2004.
 **                All rights reserved.
 **********************************************************************/

function xa_base64_type ()
{

   /// encode_string (String sdata)
   /// Encode a string into a string containing a base64 encoded representation.
   this.encode_string = function (sdata)
   {
      var adata = new Array(sdata.length);
      for (var i = 0; i < sdata.length; ++i) adata[i] = sdata.charCodeAt(i);
      return this.encode_array(adata);
   }

   /// encode (String|Array_OfBytes data)
   /// Encode a string or an array of numerically represented bytes into a
   /// string containing a base64 encoded representation.
   this.encode = function (data)
   {
      if (typeof(data) == "string") return this.encode_string(data);
      else return this.encode_array(data);
   }
      
   /// encode (Array_OfBytes adata)
   /// Encode an array of numerically represented bytes into a string
   /// containing a base64 encoded representation.
   this.encode_array = function (adata)
   {
      var base64xlatdata = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/==";
      var rounds = Math.floor(adata.length / 3); var rem = adata.length % 3;
      var data = new String();
      var i = 0;
      // ..00 0000  ..00 1111  ..11 1122  ..22 2222
      // ..76 5432  ..10 7654  ..32 1076  ..54 3210
      for (var r = 0; r < rounds; ++r) { // complete triplets
         var d0 = adata[i++]; var d1 = adata[i++]; var d2 = adata[i++];
         data += base64xlatdata.charAt((d0 & 0xFC) >> 2);
         data += base64xlatdata.charAt(((d0 & 0x03) << 4) | ((d1 & 0xF0) >> 4));
         data += base64xlatdata.charAt(((d1 & 0x0F) << 2) | ((d2 & 0xC0) >> 6));
         data += base64xlatdata.charAt(d2 & 0x3F);
      }
      if (rem > 0) { // incomplete triplets (ie 1- or 2-tuples)
         var d0 = adata[i++];
         var d1 = (rem > 1)? adata[i++]: 0;
         var d2 = 0; //(rem > 2)? adata[i++]: 0;
         data += base64xlatdata.charAt((d0 & 0xFC) >> 2);
         data += base64xlatdata.charAt(((d0 & 0x03) << 4) | ((d1 & 0xF0) >> 4));
         if (rem > 1) {
            data += base64xlatdata.charAt(((d1 & 0x0F) << 2) | ((d2 & 0xC0) >> 6));
            //if (rem > 2)
            //   data += base64xlatdata.charAt(d2 & 0x3F);
            //else
               data += "=";
         } else data += "==";
      }  
      return data;   
   }
   
   /// decode (String data)
   /// Decode a string containing a base64 encoded representation of an array
   /// of numerically represented bytes into a such an array.
   this.decode_array = function (data)
   {
      function asc2val (n)
      {
         if ((n > 0x40) && (n < 0x5B)) return (n - 0x41);      // A-Z
         if ((n > 0x60) && (n < 0x7B)) return (n - 0x61) + 26; // a-z
         if ((n > 0x2F) && (n < 0x3A)) return (n - 0x30) + 52; // 0-9
         if (n == 0x2B) return 62; // +
         if (n == 0x2F) return 63; // /
         if (n == 0x3D) return 0; // =
         return 0;
      }
      var l = data.length;
      var i = l % 4;
      if (i != 0) { data += "===".substr(0,4-i); i = 0; l += 4-i; }
      var adata = new Array();      
      while (i < l) {
      // ..00 0000  ..00 1111  ..11 1122  ..22 2222
      // ..76 5432  ..10 7654  ..32 1076  ..54 3210
         var n0 = asc2val(data.charCodeAt(i++));
         var n1 = asc2val(data.charCodeAt(i++));
         var n2 = asc2val(data.charCodeAt(i++));
         var n3 = asc2val(data.charCodeAt(i++));
         adata.push(((n0 << 2) & 0xFC) | (n1 >> 4));
         adata.push(((n1 << 4) & 0xF0) | (n2 >> 2));
         adata.push(((n2 << 6) & 0xC0) | n3);
         //adata.push(((n0 << 2) & 0xFC) | ((n1 >> 4) & 0x03));
         //adata.push(((n1 << 4) & 0xF0) | ((n2 >> 2) & 0x0F));
         //adata.push(((n2 << 6) & 0xC0) | (n3 & 0x3F));
      }
      return adata;
   }
   
   /// decode (String data)
   /// Decode a string containing a base64 encoded representation of an array
   /// of numerically represented bytes into a such a string.
   this.decode_string = function (data)
   {
      var adata = this.decode_array(data);
      var sdata = new String();
      for (var i = 0; i < adata.length; ++i)
         sdata += String.fromCharCode(adata[i]);
      return sdata;
   }

}


/* ** static object instance **/

var xa_base64 = new xa_base64_type();
