/*
name: workspace.encoding
extends: workspace
*/
workspace.encoding = {}
workspace.encoding._construct = function()
{
	var chrsz = this.chrsz
	var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

		/*
	* Convert a string to an array of little-endian words
	* If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
	*/
	this.str2binl = function(str)
	{
		var bin = Array();
		var mask = (1 << chrsz) - 1;
		for(var i = 0; i < str.length * chrsz; i += chrsz)
			bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
		return bin;
	}
	
	this.str2binw = function(str)
	{
		var bin = Array();
		var mask = (1 << chrsz) - 1;
		for(var i = 0; i < str.length * chrsz; i += chrsz)
			bin[i>>4] |= (str.charCodeAt(i / chrsz) & mask) << (i%16);
		return bin;
	}

	this.str2bin = function(str)
	{
		var bin = Array();
		var mask = (1 << chrsz) - 1;
		for(var i = 0; i < str.length * chrsz; i += chrsz)
		{
			var chr = (str.charCodeAt(i / chrsz) & mask);
			for(var j = 0; j < chrsz; j += 8)
				bin[(i + j) >> 3] = (chr >>> j) & 0xFF;
		}
		return bin;
	}

	/*
	* Convert an array of little-endian words to a string
	*/
	this.binl2str = function(bin)
	{
		var str = "";
		var mask = (1 << chrsz) - 1;
		for(var i = 0; i < bin.length * 32; i += chrsz)
			str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
		return str;
	}

	this.binw2str = function(bin)
	{
		var str = "";
		var mask = (1 << chrsz) - 1;
		for(var i = 0; i < bin.length * 16; i += chrsz)
			str += String.fromCharCode((bin[i>>4] >>> (i % 16)) & mask);
		return str;
	}

	this.bin2str = function(bin)
	{
		var str = "";
		var mask = (1 << chrsz) - 1;
		for(var i = 0; i < bin.length * 8; i += chrsz)
		{
			var chrCode = 0; 
			for(j=0; j < chrsz; j+=8)
				chrCode |= bin[(i + j) >> 3] << j;	
			str += String.fromCharCode(chrCode);
		}
		return str;
	}


	/*
	* Convert an array of little-endian words to a base-64 string
	*/
	this.binl2b64 = function(binarray)
	{
		var str = "";
		for(var i = 0; i < binarray.length * 4; i += 3)
		{
			var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
									| (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
									|  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
			for(var j = 0; j < 4; j++)
			{
				if(i*8 + j*6 > binarray.length * 32) str += "=";
				else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
			}
		}
		return str;
	}

	this.binw2b64 = function(binarray)
	{
		var str = "";
		for (var i = 0; i < binarray.length * 2; i += 3)
		{
			var triplet = (((binarray[i   >> 1] >> 8 * ( i   %2)) & 0xFF) << 16)
									| (((binarray[i+1 >> 1] >> 8 * ((i+1)%2)) & 0xFF) << 8 )
									|  ((binarray[i+2 >> 1] >> 8 * ((i+2)%2)) & 0xFF);
			for(var j = 0; j < 4; j++)
			{
				if(i*8 + j*6 > binarray.length * 16) str += "=";
				else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
			}
		}
		return str
	}

	this.bin2b64 = function(binarray)
	{
		var str = "";
		for (var i = 0; i < binarray.length; i += 3)
		{
			var triplet = (((binarray[i  ]) & 0xFF) << 16)
									| (((binarray[i+1]) & 0xFF) << 8 )
									|  ((binarray[i+2]) & 0xFF);
			for(var j = 0; j < 4; j++)
			{
				if(i*8 + j*6 > binarray.length * 8) str += "=";
				else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
			}
		}
		return str
	}

	this.b642binl = function(str)
	{
		var binarray = new Array();
		var length = (str.length - ((str.lastIndexOf("==") != -1) ? 2 : ((str.lastIndexOf("=") != -1) ? 1 : 0) ))
		length = (Math.floor(length / 4) * 3 + (length % 4 ? (length % 4) - 1 : 0)) * 8

		for (var i = 0; i < length; i += 24)
		{
			var triplet = 0;
			for(var j = i; j < length && j - i < 24; j += 6)
				triplet |= tab.indexOf(str.charAt(j / 6)) << (18 - (j - i))
				
			for(var j = i; j < length && j - i < 24; j += 8)
				binarray[j >>> 5] |= ((triplet >>> 16 - (j - i)) & 0xFF) << j % 32
		}
		return binarray;
	}

	this.b642binw = function(str)
	{
		var binarray = new Array();
		var length = (str.length - ((str.lastIndexOf("==") != -1) ? 2 : ((str.lastIndexOf("=") != -1) ? 1 : 0) ))
		length = (Math.floor(length / 4) * 3 + (length % 4 ? (length % 4) - 1 : 0)) * 8

		for (var i = 0; i < length ; i += 24)
		{
			var triplet = 0;
			for(var j = i; j < length && j - i < 24; j += 6)
				triplet |= tab.indexOf(str.charAt(j / 6)) << (18 - (j - i))
				
			for(var j = i; j < length && j - i < 24; j += 8)
				binarray[j >>> 4] |= ((triplet >>> 16 - (j - i)) & 0xFF) << j % 16
		}
		return binarray;
	}

	this.b642bin = function(str)
	{
		var binarray = new Array();
		var length = (str.length - ((str.lastIndexOf("==") != -1) ? 2 : ((str.lastIndexOf("=") != -1) ? 1 : 0) ))
		length = (Math.floor(length / 4) * 3 + (length % 4 ? (length % 4) - 1 : 0)) * 8

		for (var i = 0; i < length; i += 24)
		{
			var triplet = 0;
			for(var j = i; j < length && j - i < 24; j += 6)
				triplet |= tab.indexOf(str.charAt(j / 6)) << (18 - (j - i))
				 			
			for(var j = i; j < length && j - i < 24; j += 8)
				binarray[j >>> 3] = (triplet >>> 16 - (j - i)) & 0xFF
		}
		return binarray;
	}


	/*
	* Convert an array of little-endian words to a hex string.
	*/
	this.binl2hex = function(binarray)
	{
		var hex_tab = "0123456789abcdef";
		var str = "";
		for(var i = 0; i < binarray.length * 4; i++)
		{
			str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
						hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
		}
		return str;
	}

}
workspace.encoding.chrsz = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode  */
workspace.encoding._construct()

