bytes.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. const A = require("./array.js");
  2. const at = (bytes, index) => parseInt(bytes.slice(index * 2 + 2, index * 2 + 4), 16);
  3. const random = bytes => {
  4. let rnd;
  5. if (typeof window !== "undefined" && window.crypto && window.crypto.getRandomValues) rnd = window.crypto.getRandomValues(new Uint8Array(bytes));else if (typeof require !== "undefined") rnd = require("c" + "rypto").randomBytes(bytes);else throw "Safe random numbers not available.";
  6. let hex = "0x";
  7. for (let i = 0; i < bytes; ++i) hex += ("00" + rnd[i].toString(16)).slice(-2);
  8. return hex;
  9. };
  10. const length = a => (a.length - 2) / 2;
  11. const flatten = a => "0x" + a.reduce((r, s) => r + s.slice(2), "");
  12. const slice = (i, j, bs) => "0x" + bs.slice(i * 2 + 2, j * 2 + 2);
  13. const reverse = hex => {
  14. let rev = "0x";
  15. for (let i = 0, l = length(hex); i < l; ++i) {
  16. rev += hex.slice((l - i) * 2, (l - i + 1) * 2);
  17. }
  18. return rev;
  19. };
  20. const pad = (l, hex) => hex.length === l * 2 + 2 ? hex : pad(l, "0x" + "0" + hex.slice(2));
  21. const padRight = (l, hex) => hex.length === l * 2 + 2 ? hex : padRight(l, hex + "0");
  22. const toArray = hex => {
  23. let arr = [];
  24. for (let i = 2, l = hex.length; i < l; i += 2) arr.push(parseInt(hex.slice(i, i + 2), 16));
  25. return arr;
  26. };
  27. const fromArray = arr => {
  28. let hex = "0x";
  29. for (let i = 0, l = arr.length; i < l; ++i) {
  30. let b = arr[i];
  31. hex += (b < 16 ? "0" : "") + b.toString(16);
  32. }
  33. return hex;
  34. };
  35. const toUint8Array = hex => new Uint8Array(toArray(hex));
  36. const fromUint8Array = arr => fromArray([].slice.call(arr, 0));
  37. const fromNumber = num => {
  38. let hex = num.toString(16);
  39. return hex.length % 2 === 0 ? "0x" + hex : "0x0" + hex;
  40. };
  41. const toNumber = hex => parseInt(hex.slice(2), 16);
  42. const concat = (a, b) => a.concat(b.slice(2));
  43. const fromNat = bn => bn === "0x0" ? "0x" : bn.length % 2 === 0 ? bn : "0x0" + bn.slice(2);
  44. const toNat = bn => bn[2] === "0" ? "0x" + bn.slice(3) : bn;
  45. const fromAscii = ascii => {
  46. let hex = "0x";
  47. for (let i = 0; i < ascii.length; ++i) hex += ("00" + ascii.charCodeAt(i).toString(16)).slice(-2);
  48. return hex;
  49. };
  50. const toAscii = hex => {
  51. let ascii = "";
  52. for (let i = 2; i < hex.length; i += 2) ascii += String.fromCharCode(parseInt(hex.slice(i, i + 2), 16));
  53. return ascii;
  54. };
  55. // From https://gist.github.com/pascaldekloe/62546103a1576803dade9269ccf76330
  56. const fromString = s => {
  57. const makeByte = uint8 => {
  58. const b = uint8.toString(16);
  59. return b.length < 2 ? "0" + b : b;
  60. };
  61. let bytes = "0x";
  62. for (let ci = 0; ci != s.length; ci++) {
  63. let c = s.charCodeAt(ci);
  64. if (c < 128) {
  65. bytes += makeByte(c);
  66. continue;
  67. }
  68. if (c < 2048) {
  69. bytes += makeByte(c >> 6 | 192);
  70. } else {
  71. if (c > 0xd7ff && c < 0xdc00) {
  72. if (++ci == s.length) return null;
  73. let c2 = s.charCodeAt(ci);
  74. if (c2 < 0xdc00 || c2 > 0xdfff) return null;
  75. c = 0x10000 + ((c & 0x03ff) << 10) + (c2 & 0x03ff);
  76. bytes += makeByte(c >> 18 | 240);
  77. bytes += makeByte(c >> 12 & 63 | 128);
  78. } else {
  79. // c <= 0xffff
  80. bytes += makeByte(c >> 12 | 224);
  81. }
  82. bytes += makeByte(c >> 6 & 63 | 128);
  83. }
  84. bytes += makeByte(c & 63 | 128);
  85. }
  86. return bytes;
  87. };
  88. const toString = bytes => {
  89. let s = '';
  90. let i = 0;
  91. let l = length(bytes);
  92. while (i < l) {
  93. let c = at(bytes, i++);
  94. if (c > 127) {
  95. if (c > 191 && c < 224) {
  96. if (i >= l) return null;
  97. c = (c & 31) << 6 | at(bytes, i) & 63;
  98. } else if (c > 223 && c < 240) {
  99. if (i + 1 >= l) return null;
  100. c = (c & 15) << 12 | (at(bytes, i) & 63) << 6 | at(bytes, ++i) & 63;
  101. } else if (c > 239 && c < 248) {
  102. if (i + 2 >= l) return null;
  103. c = (c & 7) << 18 | (at(bytes, i) & 63) << 12 | (at(bytes, ++i) & 63) << 6 | at(bytes, ++i) & 63;
  104. } else return null;
  105. ++i;
  106. }
  107. if (c <= 0xffff) s += String.fromCharCode(c);else if (c <= 0x10ffff) {
  108. c -= 0x10000;
  109. s += String.fromCharCode(c >> 10 | 0xd800);
  110. s += String.fromCharCode(c & 0x3FF | 0xdc00);
  111. } else return null;
  112. }
  113. return s;
  114. };
  115. module.exports = {
  116. random,
  117. length,
  118. concat,
  119. flatten,
  120. slice,
  121. reverse,
  122. pad,
  123. padRight,
  124. fromAscii,
  125. toAscii,
  126. fromString,
  127. toString,
  128. fromNumber,
  129. toNumber,
  130. fromNat,
  131. toNat,
  132. fromArray,
  133. toArray,
  134. fromUint8Array,
  135. toUint8Array
  136. };