binary-utils.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. function toByteArray(bytes) {
  2. if (!bytes) return []
  3. if (bytes instanceof ArrayBuffer) return Array.prototype.slice.call(new Uint8Array(bytes))
  4. if (ArrayBuffer.isView(bytes)) return Array.prototype.slice.call(new Uint8Array(bytes.buffer, bytes.byteOffset, bytes.byteLength))
  5. return Array.prototype.slice.call(bytes)
  6. }
  7. function bytesToBase64(bytes) {
  8. const source = toByteArray(bytes)
  9. const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
  10. let output = ''
  11. for (let index = 0; index < source.length; index += 3) {
  12. const first = source[index] & 0xFF
  13. const second = index + 1 < source.length ? source[index + 1] & 0xFF : 0
  14. const third = index + 2 < source.length ? source[index + 2] & 0xFF : 0
  15. const triple = (first << 16) | (second << 8) | third
  16. output += alphabet[(triple >> 18) & 0x3F]
  17. output += alphabet[(triple >> 12) & 0x3F]
  18. output += index + 1 < source.length ? alphabet[(triple >> 6) & 0x3F] : '='
  19. output += index + 2 < source.length ? alphabet[triple & 0x3F] : '='
  20. }
  21. return output
  22. }
  23. function bytesToBin(bytes) {
  24. return toByteArray(bytes).map((byte) => (byte & 0xFF).toString(2).padStart(8, '0')).join('')
  25. }
  26. function bytesToHex(bytes, separator = '') {
  27. return toByteArray(bytes).map((byte) => (byte & 0xFF).toString(16).toUpperCase().padStart(2, '0')).join(separator)
  28. }
  29. function bytesToAsciiText(bytes = []) {
  30. return String.fromCharCode.apply(null, trimTrailingNullBytes(bytes).map((byte) => byte & 0xFF))
  31. }
  32. function bytesToUtf8Text(bytes = []) {
  33. const trimmed = trimTrailingNullBytes(bytes)
  34. if (!trimmed.length) return ''
  35. let encoded = ''
  36. trimmed.forEach((byte) => {
  37. encoded += `%${(byte & 0xFF).toString(16).padStart(2, '0').toUpperCase()}`
  38. })
  39. try {
  40. return decodeURIComponent(encoded)
  41. } catch (error) {
  42. return bytesToAsciiText(trimmed)
  43. }
  44. }
  45. function formatBytes(byteLength) {
  46. const length = Number(byteLength) || 0
  47. if (length >= 1024 && length % 1024 === 0) return `${length / 1024} KB`
  48. if (length >= 1024) return `${(length / 1024).toFixed(2)} KB`
  49. return `${length} bytes`
  50. }
  51. function bytesToWords(bytes = []) {
  52. const words = []
  53. for (let index = 0; index + 1 < bytes.length; index += 2) {
  54. const highByte = bytes[index] || 0
  55. const lowByte = bytes[index + 1] || 0
  56. words.push(((highByte << 8) | lowByte) & 0xFFFF)
  57. }
  58. return words
  59. }
  60. function getByteFromWord(word, byteOffset = 0) {
  61. const value = Number(word) & 0xFFFF
  62. return byteOffset === 0 ? ((value >> 8) & 0xFF) : (value & 0xFF)
  63. }
  64. function stringToUtf8Bytes(text) {
  65. const bytes = []
  66. const encoded = encodeURIComponent(String(text || ''))
  67. for (let index = 0; index < encoded.length; index += 1) {
  68. const char = encoded[index]
  69. if (char === '%') {
  70. bytes.push(parseInt(encoded.slice(index + 1, index + 3), 16) & 0xFF)
  71. index += 2
  72. } else {
  73. bytes.push(char.charCodeAt(0) & 0xFF)
  74. }
  75. }
  76. return bytes
  77. }
  78. function trimTrailingNullBytes(bytes = []) {
  79. let end = bytes.length
  80. while (end > 0 && bytes[end - 1] === 0x00) {
  81. end -= 1
  82. }
  83. return bytes.slice(0, end)
  84. }
  85. function wordsToBytes(words = [], byteLength = words.length * 2) {
  86. const bytes = []
  87. for (let index = 0; index < words.length; index += 1) {
  88. const word = Number(words[index]) & 0xFFFF
  89. bytes.push((word >> 8) & 0xFF, word & 0xFF)
  90. }
  91. return bytes.slice(0, Math.max(0, byteLength))
  92. }
  93. module.exports = {
  94. bytesToBase64,
  95. bytesToBin,
  96. bytesToHex,
  97. bytesToAsciiText,
  98. bytesToUtf8Text,
  99. bytesToWords,
  100. formatBytes,
  101. getByteFromWord,
  102. stringToUtf8Bytes,
  103. toByteArray,
  104. trimTrailingNullBytes,
  105. wordsToBytes
  106. }