/**
 * Add binary-safe padding to a string.
 *
 * @param string the string to add padding
 * @param int number for the string be divisible by
 * @param int the string length
 * @return the padded string
 * @author www.farfarfar.com
 * @version 0.2
 */


var charBit = 8;
 
var standardPadding = false;

function addPadding(str, divisible, len)
{
	if (divisible % len != 0)
		var paddingLen = divisible - (len % divisible);
  	else
	  var paddingLen = 0;
         
    if (standardPadding) {
        for (var i = 0; i < paddingLen; i++)
        {
                str += String.fromCharCode(paddingLen);
        }
    } else {
        for (var i = 0; i < paddingLen; i++)
        {
                str += String.fromCharCode(0);
        }
    }

	return str;
};

/**
 * Remove binary-safe padding from a string
 *
 * @param string the string to remove padding
 * @param int the string length
 * @return the unpadded string
 * @author www.farfarfar.com
 * @version 0.1
 */

function removePadding(str, len)
{
    if (standardPadding) {
		return str.substr(0, len - (str.charCodeAt(str.length - 1)));
	} else {
	    return str;
	}
};

/**
 * Converts a string into a little endian binary array
 *
 * @param string the string to convert
 * @return int[]
 * @author www.farfarfar.com
 * @version 0.1
 */

function strToLittleEndianArray(str)
{
	var x = Array();
	var mask = (1 << charBit) - 1;

	var len = str.length;

	for (var i=0, j=0; j < len; i+=charBit)
	{
		x[i>>5] |= (str.charCodeAt(j++) & mask) << (i & 0x1f);
	}

	return x;
};

/**
 * Converts a string into a big endian binary array
 *
 * @param string the string to convert
 * @return int[]
 * @author www.farfarfar.com
 * @version 0.1
 */

function strToBigEndianArray(str)
{
	var x = Array();
	var mask = (1 << charBit) - 1;

	var len = str.length;
	
	var i=0;

	for (var j=0; j < len; i+=charBit)
	{
		x[i>>5] |= (str.charCodeAt(j++) & mask) << (32 - charBit - (i & 0x1f));
	}

	return x;
};

/**
 * Converts a little endian binary array into a hex-formatted string
 *
 * @param int[] the array to convert
 * @return string
 * @author www.farfarfar.com
 * @version 0.1
 */

function littleEndianArrayToHex(ar)
{
	var charHex = new Array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f');

	var str = "";

	var len = ar.length;

	for(var i = 0, tmp = len << 2; i < tmp; i++)
	{
		str += charHex[((ar[i >> 2] >> (((i & 3) << 3) + 4)) & 0xF)] +
		charHex[((ar[i >> 2] >> ((i & 3) << 3)) & 0xF)];
	}

	return str;
};

/**
 * Converts a big endian binary array into a hex-formatted string
 *
 * @param int[] the array to convert
 * @return string
 * @author www.farfarfar.com
 * @version 0.1
 */

function bigEndianArrayToHex(ar)
{
	var charHex = new Array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f');

	var str = "";

	var len = ar.length;

	for(var i = 0, tmp = len << 2; i < tmp; i++)
	{
		str += charHex[((ar[i>>2] >> (((3 - (i & 3)) << 3) + 4)) & 0xF)] +
		charHex[((ar[i>>2] >> ((3 - (i & 3)) << 3)) & 0xF)];
	}

	return str;
};

/**
 * @param int the integer to rotate
 * @param int the distance to rotate left
 * @return int
 */

function rotateLeft(val, n)
{
	return (val << n) | (val >>> (32 - n));
};

/**
 * @param int the integer to rotate
 * @param int the distance to rotate right
 * @return int
 */

function rotateRight(val, n)
{
	return ( val >>> n ) | (val << (32 - n));
};

/**
 * @param int the first integer
 * @param int the second integer
 * @return int
 */

function modularAdd(a, b)
{	
	var lowerSum = (a & 0xffff) + (b & 0xffff);
	var upperSum = (a >> 16) + (b >> 16) + (lowerSum >> 16);
	return (upperSum << 16) + (lowerSum & 0xffff);
};

/**
 * @param int the first integer
 * @param int the second integer
 * @return int
 */

function modularSubtract(a, b)
{	
	return modularAdd(a, -b);
};

function binxor(l, r)
{
        var x = ((l < 0) ? (l + 4294967296) : l)
             ^ ((r < 0) ? (r + 4294967296) : r);
        return ((x < 0) ? x + 4294967296 : x);
};

/**
 * Unencodes a hex-encoded string to a binary string
 * @param str the string to unencode
 * @return string the unencoded string
 * @author www.farfarfar.com
 */

function hexToStr(str)
{
	var charHex = new Array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f');
	var stringHex = "0123456789abcdef";
	
	var out = "";
	var len = str.length;
	str = new String(str);
	str = str.toLowerCase();
	if ((len % 2) == 1)
	{
		str += "0";
	}
	for (var i = 0; i < len; i+=2)
	{
	    var s1 = str.substr(i, 1);
	    var s2 = str.substr(i+1, 1);
		var index1 = stringHex.indexOf(s1);
		var index2 = stringHex.indexOf(s2);
		
		if (index1 == -1 || index2 == -1)
		{
			throw HEX_BROKEN;
		}
		
		var val = (index1 << 4) | index2;
		
	    out += "" + String.fromCharCode(parseInt(val));
	}
	return out;
};

/**
 * Encodes a string string to a hex-encoded string
 * @param str the string to unencode
 * @return string the unencoded string
 * @author www.farfarfar.com
 */

function strToHex(str)
{
	var charHex = new Array('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f');
	
	var out = "";
	var len = str.length;
	str = new String(str);
	for (var i = 0; i < len; i++)
	{
	    var s = str.charCodeAt(i);
	    var h = "" + charHex[s >> 4] + "" + charHex[0xf & s];
	    
	    out += "" + h;
	}
	return out;
};

/**
 * Converts a string to an array of longs
 *
 * @param string the string to convert
 * @return long[]
 * @version 0.1
 */
function strToInt(str)
{
	var ar = new Array();

	var len = str.length;

  	var i = 0;
  	var j = 0;
  	
  	do {
		ar[j++] = str.charCodeAt(i++) +
		(str.charCodeAt(i++) << 8) +
		(str.charCodeAt(i++) << 16) +
		(str.charCodeAt(i++) << 24);
 	} while (i < len);
 	
	return ar;
};

/**
 * Converts an array of longs to a string
 *
 * @param long[] the array to convert
 * @return string
 * @version 0.1
 */

function intToStr(ar)
{
	var len = ar.length;
	for (var i=0; i<len; i++)
	{
		ar[i] = String.fromCharCode(ar[i] & 0xff, ar[i] >>> 8 & 0xff,
		ar[i] >>> 16 & 0xff, ar[i] >>> 24 & 0xff);
	}
	return ar.join('');
};



