/**
* This class contains utilities to help parse the data
*
* Copyright (C) 2013-2016 Regents of the University of California.
* @author: Meki Cheraoui
* @author: Jeff Thompson <jefft0@remap.ucla.edu>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* A copy of the GNU Lesser General Public License is in the file COPYING.
*/
/**
* A DataUtils has static methods for converting data.
* @constructor
*/
var DataUtils = {};
exports.DataUtils = DataUtils;
/*
* NOTE THIS IS CURRENTLY NOT BEING USED
*
*/
DataUtils.keyStr = "ABCDEFGHIJKLMNOP" +
"QRSTUVWXYZabcdef" +
"ghijklmnopqrstuv" +
"wxyz0123456789+/" +
"=";
/**
* Raw String to Base 64
*/
DataUtils.stringtoBase64 = function stringtoBase64(input)
{
//input = escape(input);
var output = "";
var chr1, chr2, chr3 = "";
var enc1, enc2, enc3, enc4 = "";
var i = 0;
do {
chr1 = input.charCodeAt(i++);
chr2 = input.charCodeAt(i++);
chr3 = input.charCodeAt(i++);
enc1 = chr1 >> 2;
enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
enc4 = chr3 & 63;
if (isNaN(chr2))
enc3 = enc4 = 64;
else if (isNaN(chr3))
enc4 = 64;
output = output +
DataUtils.keyStr.charAt(enc1) +
DataUtils.keyStr.charAt(enc2) +
DataUtils.keyStr.charAt(enc3) +
DataUtils.keyStr.charAt(enc4);
chr1 = chr2 = chr3 = "";
enc1 = enc2 = enc3 = enc4 = "";
} while (i < input.length);
return output;
};
/**
* Base 64 to Raw String
*/
DataUtils.base64toString = function base64toString(input)
{
var output = "";
var chr1, chr2, chr3 = "";
var enc1, enc2, enc3, enc4 = "";
var i = 0;
// remove all characters that are not A-Z, a-z, 0-9, +, /, or =
var base64test = /[^A-Za-z0-9\+\/\=]/g;
/* Test for invalid characters. */
if (base64test.exec(input)) {
alert("There were invalid base64 characters in the input text.\n" +
"Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
"Expect errors in decoding.");
}
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
do {
enc1 = DataUtils.keyStr.indexOf(input.charAt(i++));
enc2 = DataUtils.keyStr.indexOf(input.charAt(i++));
enc3 = DataUtils.keyStr.indexOf(input.charAt(i++));
enc4 = DataUtils.keyStr.indexOf(input.charAt(i++));
chr1 = (enc1 << 2) | (enc2 >> 4);
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
chr3 = ((enc3 & 3) << 6) | enc4;
output = output + String.fromCharCode(chr1);
if (enc3 != 64)
output = output + String.fromCharCode(chr2);
if (enc4 != 64)
output = output + String.fromCharCode(chr3);
chr1 = chr2 = chr3 = "";
enc1 = enc2 = enc3 = enc4 = "";
} while (i < input.length);
return output;
};
/**
* Buffer to Hex String
*/
DataUtils.toHex = function(buffer)
{
return buffer.toString('hex');
};
/**
* Raw string to hex string.
*/
DataUtils.stringToHex = function(args)
{
var ret = "";
for (var i = 0; i < args.length; ++i) {
var value = args.charCodeAt(i);
ret += (value < 16 ? "0" : "") + value.toString(16);
}
return ret;
};
/**
* Buffer to raw string.
*/
DataUtils.toString = function(buffer)
{
return buffer.toString('binary');
};
/**
* Hex String to Buffer.
*/
DataUtils.toNumbers = function(str)
{
return new Buffer(str, 'hex');
};
/**
* Hex String to raw string.
*/
DataUtils.hexToRawString = function(str)
{
if (typeof str =='string') {
var ret = "";
str.replace(/(..)/g, function(s) {
ret += String.fromCharCode(parseInt(s, 16));
});
return ret;
}
};
/**
* Raw String to Buffer.
*/
DataUtils.toNumbersFromString = function(str)
{
return new Buffer(str, 'binary');
};
/**
* If value is a string, then interpret it as a raw string and convert to
* a Buffer. Otherwise assume it is a Buffer or array type and just return it.
* @param {string|any} value
* @returns {Buffer}
*/
DataUtils.toNumbersIfString = function(value)
{
if (typeof value === 'string')
return new Buffer(value, 'binary');
else
return value;
};
/**
* Encode str as utf8 and return as Buffer.
*/
DataUtils.stringToUtf8Array = function(str)
{
return new Buffer(str, 'utf8');
};
/**
* arrays is an array of Buffer. Return a new Buffer which is the concatenation of all.
*/
DataUtils.concatArrays = function(arrays)
{
return Buffer.concat(arrays);
};
// TODO: Take Buffer and use TextDecoder when available.
DataUtils.decodeUtf8 = function(utftext)
{
var string = "";
var i = 0;
var c = 0;
var c1 = 0;
var c2 = 0;
while (i < utftext.length) {
c = utftext.charCodeAt(i);
if (c < 128) {
string += String.fromCharCode(c);
i++;
}
else if (c > 191 && c < 224) {
c2 = utftext.charCodeAt(i + 1);
string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
i += 2;
}
else {
c2 = utftext.charCodeAt(i+1);
var c3 = utftext.charCodeAt(i+2);
string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
i += 3;
}
}
return string;
};
/**
* Return true if a1 and a2 are the same length with equal elements.
*/
DataUtils.arraysEqual = function(a1, a2)
{
// A simple sanity check that it is an array.
if (!a1.slice)
throw new Error("DataUtils.arraysEqual: a1 is not an array");
if (!a2.slice)
throw new Error("DataUtils.arraysEqual: a2 is not an array");
if (a1.length != a2.length)
return false;
for (var i = 0; i < a1.length; ++i) {
if (a1[i] != a2[i])
return false;
}
return true;
};
/**
* Convert the big endian Buffer to an unsigned int.
* Don't check for overflow.
*/
DataUtils.bigEndianToUnsignedInt = function(bytes)
{
var result = 0;
for (var i = 0; i < bytes.length; ++i) {
// Multiply by 0x100 instead of shift by 8 because << is restricted to 32 bits.
result *= 0x100;
result += bytes[i];
}
return result;
};
/**
* Convert the int value to a new big endian Buffer and return.
* If value is 0 or negative, return new Buffer(0).
*/
DataUtils.nonNegativeIntToBigEndian = function(value)
{
value = Math.round(value);
if (value <= 0)
return new Buffer(0);
// Assume value is not over 64 bits.
var size = 8;
var result = new Buffer(size);
var i = 0;
while (value != 0) {
++i;
result[size - i] = value & 0xff;
// Divide by 0x100 and floor instead of shift by 8 because >> is restricted to 32 bits.
value = Math.floor(value / 0x100);
}
return result.slice(size - i, size);
};
/**
* Modify array to randomly shuffle the elements.
*/
DataUtils.shuffle = function(array)
{
for (var i = array.length - 1; i >= 1; --i) {
// j is from 0 to i.
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
};
/**
* Decode the base64-encoded private key PEM and return the binary DER.
* @param {string} The PEM-encoded private key.
* @returns {Buffer} The binary DER.
*
*/
DataUtils.privateKeyPemToDer = function(privateKeyPem)
{
// Remove the '-----XXX-----' from the beginning and the end of the key and
// also remove any \n in the key string.
var lines = privateKeyPem.split('\n');
var privateKey = "";
for (var i = 1; i < lines.length - 1; i++)
privateKey += lines[i];
return new Buffer(privateKey, 'base64');
};