Source: encoding/data-utils.js

  1. /**
  2. * This class contains utilities to help parse the data
  3. *
  4. * Copyright (C) 2013-2016 Regents of the University of California.
  5. * @author: Meki Cheraoui
  6. * @author: Jeff Thompson <jefft0@remap.ucla.edu>
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Lesser General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Lesser General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. * A copy of the GNU Lesser General Public License is in the file COPYING.
  21. */
  22. /**
  23. * A DataUtils has static methods for converting data.
  24. * @constructor
  25. */
  26. var DataUtils = {};
  27. exports.DataUtils = DataUtils;
  28. /*
  29. * NOTE THIS IS CURRENTLY NOT BEING USED
  30. *
  31. */
  32. DataUtils.keyStr = "ABCDEFGHIJKLMNOP" +
  33. "QRSTUVWXYZabcdef" +
  34. "ghijklmnopqrstuv" +
  35. "wxyz0123456789+/" +
  36. "=";
  37. /**
  38. * Raw String to Base 64
  39. */
  40. DataUtils.stringtoBase64 = function stringtoBase64(input)
  41. {
  42. //input = escape(input);
  43. var output = "";
  44. var chr1, chr2, chr3 = "";
  45. var enc1, enc2, enc3, enc4 = "";
  46. var i = 0;
  47. do {
  48. chr1 = input.charCodeAt(i++);
  49. chr2 = input.charCodeAt(i++);
  50. chr3 = input.charCodeAt(i++);
  51. enc1 = chr1 >> 2;
  52. enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
  53. enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
  54. enc4 = chr3 & 63;
  55. if (isNaN(chr2))
  56. enc3 = enc4 = 64;
  57. else if (isNaN(chr3))
  58. enc4 = 64;
  59. output = output +
  60. DataUtils.keyStr.charAt(enc1) +
  61. DataUtils.keyStr.charAt(enc2) +
  62. DataUtils.keyStr.charAt(enc3) +
  63. DataUtils.keyStr.charAt(enc4);
  64. chr1 = chr2 = chr3 = "";
  65. enc1 = enc2 = enc3 = enc4 = "";
  66. } while (i < input.length);
  67. return output;
  68. };
  69. /**
  70. * Base 64 to Raw String
  71. */
  72. DataUtils.base64toString = function base64toString(input)
  73. {
  74. var output = "";
  75. var chr1, chr2, chr3 = "";
  76. var enc1, enc2, enc3, enc4 = "";
  77. var i = 0;
  78. // remove all characters that are not A-Z, a-z, 0-9, +, /, or =
  79. var base64test = /[^A-Za-z0-9\+\/\=]/g;
  80. /* Test for invalid characters. */
  81. if (base64test.exec(input)) {
  82. alert("There were invalid base64 characters in the input text.\n" +
  83. "Valid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\n" +
  84. "Expect errors in decoding.");
  85. }
  86. input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
  87. do {
  88. enc1 = DataUtils.keyStr.indexOf(input.charAt(i++));
  89. enc2 = DataUtils.keyStr.indexOf(input.charAt(i++));
  90. enc3 = DataUtils.keyStr.indexOf(input.charAt(i++));
  91. enc4 = DataUtils.keyStr.indexOf(input.charAt(i++));
  92. chr1 = (enc1 << 2) | (enc2 >> 4);
  93. chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
  94. chr3 = ((enc3 & 3) << 6) | enc4;
  95. output = output + String.fromCharCode(chr1);
  96. if (enc3 != 64)
  97. output = output + String.fromCharCode(chr2);
  98. if (enc4 != 64)
  99. output = output + String.fromCharCode(chr3);
  100. chr1 = chr2 = chr3 = "";
  101. enc1 = enc2 = enc3 = enc4 = "";
  102. } while (i < input.length);
  103. return output;
  104. };
  105. /**
  106. * Buffer to Hex String
  107. */
  108. DataUtils.toHex = function(buffer)
  109. {
  110. return buffer.toString('hex');
  111. };
  112. /**
  113. * Raw string to hex string.
  114. */
  115. DataUtils.stringToHex = function(args)
  116. {
  117. var ret = "";
  118. for (var i = 0; i < args.length; ++i) {
  119. var value = args.charCodeAt(i);
  120. ret += (value < 16 ? "0" : "") + value.toString(16);
  121. }
  122. return ret;
  123. };
  124. /**
  125. * Buffer to raw string.
  126. */
  127. DataUtils.toString = function(buffer)
  128. {
  129. return buffer.toString('binary');
  130. };
  131. /**
  132. * Hex String to Buffer.
  133. */
  134. DataUtils.toNumbers = function(str)
  135. {
  136. return new Buffer(str, 'hex');
  137. };
  138. /**
  139. * Hex String to raw string.
  140. */
  141. DataUtils.hexToRawString = function(str)
  142. {
  143. if (typeof str =='string') {
  144. var ret = "";
  145. str.replace(/(..)/g, function(s) {
  146. ret += String.fromCharCode(parseInt(s, 16));
  147. });
  148. return ret;
  149. }
  150. };
  151. /**
  152. * Raw String to Buffer.
  153. */
  154. DataUtils.toNumbersFromString = function(str)
  155. {
  156. return new Buffer(str, 'binary');
  157. };
  158. /**
  159. * If value is a string, then interpret it as a raw string and convert to
  160. * a Buffer. Otherwise assume it is a Buffer or array type and just return it.
  161. * @param {string|any} value
  162. * @returns {Buffer}
  163. */
  164. DataUtils.toNumbersIfString = function(value)
  165. {
  166. if (typeof value === 'string')
  167. return new Buffer(value, 'binary');
  168. else
  169. return value;
  170. };
  171. /**
  172. * Encode str as utf8 and return as Buffer.
  173. */
  174. DataUtils.stringToUtf8Array = function(str)
  175. {
  176. return new Buffer(str, 'utf8');
  177. };
  178. /**
  179. * arrays is an array of Buffer. Return a new Buffer which is the concatenation of all.
  180. */
  181. DataUtils.concatArrays = function(arrays)
  182. {
  183. return Buffer.concat(arrays);
  184. };
  185. // TODO: Take Buffer and use TextDecoder when available.
  186. DataUtils.decodeUtf8 = function(utftext)
  187. {
  188. var string = "";
  189. var i = 0;
  190. var c = 0;
  191. var c1 = 0;
  192. var c2 = 0;
  193. while (i < utftext.length) {
  194. c = utftext.charCodeAt(i);
  195. if (c < 128) {
  196. string += String.fromCharCode(c);
  197. i++;
  198. }
  199. else if (c > 191 && c < 224) {
  200. c2 = utftext.charCodeAt(i + 1);
  201. string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
  202. i += 2;
  203. }
  204. else {
  205. c2 = utftext.charCodeAt(i+1);
  206. var c3 = utftext.charCodeAt(i+2);
  207. string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
  208. i += 3;
  209. }
  210. }
  211. return string;
  212. };
  213. /**
  214. * Return true if a1 and a2 are the same length with equal elements.
  215. */
  216. DataUtils.arraysEqual = function(a1, a2)
  217. {
  218. // A simple sanity check that it is an array.
  219. if (!a1.slice)
  220. throw new Error("DataUtils.arraysEqual: a1 is not an array");
  221. if (!a2.slice)
  222. throw new Error("DataUtils.arraysEqual: a2 is not an array");
  223. if (a1.length != a2.length)
  224. return false;
  225. for (var i = 0; i < a1.length; ++i) {
  226. if (a1[i] != a2[i])
  227. return false;
  228. }
  229. return true;
  230. };
  231. /**
  232. * Convert the big endian Buffer to an unsigned int.
  233. * Don't check for overflow.
  234. */
  235. DataUtils.bigEndianToUnsignedInt = function(bytes)
  236. {
  237. var result = 0;
  238. for (var i = 0; i < bytes.length; ++i) {
  239. // Multiply by 0x100 instead of shift by 8 because << is restricted to 32 bits.
  240. result *= 0x100;
  241. result += bytes[i];
  242. }
  243. return result;
  244. };
  245. /**
  246. * Convert the int value to a new big endian Buffer and return.
  247. * If value is 0 or negative, return new Buffer(0).
  248. */
  249. DataUtils.nonNegativeIntToBigEndian = function(value)
  250. {
  251. value = Math.round(value);
  252. if (value <= 0)
  253. return new Buffer(0);
  254. // Assume value is not over 64 bits.
  255. var size = 8;
  256. var result = new Buffer(size);
  257. var i = 0;
  258. while (value != 0) {
  259. ++i;
  260. result[size - i] = value & 0xff;
  261. // Divide by 0x100 and floor instead of shift by 8 because >> is restricted to 32 bits.
  262. value = Math.floor(value / 0x100);
  263. }
  264. return result.slice(size - i, size);
  265. };
  266. /**
  267. * Modify array to randomly shuffle the elements.
  268. */
  269. DataUtils.shuffle = function(array)
  270. {
  271. for (var i = array.length - 1; i >= 1; --i) {
  272. // j is from 0 to i.
  273. var j = Math.floor(Math.random() * (i + 1));
  274. var temp = array[i];
  275. array[i] = array[j];
  276. array[j] = temp;
  277. }
  278. };
  279. /**
  280. * Decode the base64-encoded private key PEM and return the binary DER.
  281. * @param {string} The PEM-encoded private key.
  282. * @returns {Buffer} The binary DER.
  283. *
  284. */
  285. DataUtils.privateKeyPemToDer = function(privateKeyPem)
  286. {
  287. // Remove the '-----XXX-----' from the beginning and the end of the key and
  288. // also remove any \n in the key string.
  289. var lines = privateKeyPem.split('\n');
  290. var privateKey = "";
  291. for (var i = 1; i < lines.length - 1; i++)
  292. privateKey += lines[i];
  293. return new Buffer(privateKey, 'base64');
  294. };