large-numbers.js 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. 'use strict'
  2. // Tar can encode large and negative numbers using a leading byte of
  3. // 0xff for negative, and 0x80 for positive.
  4. const encode = (num, buf) => {
  5. if (!Number.isSafeInteger(num))
  6. // The number is so large that javascript cannot represent it with integer
  7. // precision.
  8. throw Error('cannot encode number outside of javascript safe integer range')
  9. else if (num < 0)
  10. encodeNegative(num, buf)
  11. else
  12. encodePositive(num, buf)
  13. return buf
  14. }
  15. const encodePositive = (num, buf) => {
  16. buf[0] = 0x80
  17. for (var i = buf.length; i > 1; i--) {
  18. buf[i - 1] = num & 0xff
  19. num = Math.floor(num / 0x100)
  20. }
  21. }
  22. const encodeNegative = (num, buf) => {
  23. buf[0] = 0xff
  24. var flipped = false
  25. num = num * -1
  26. for (var i = buf.length; i > 1; i--) {
  27. var byte = num & 0xff
  28. num = Math.floor(num / 0x100)
  29. if (flipped)
  30. buf[i - 1] = onesComp(byte)
  31. else if (byte === 0)
  32. buf[i - 1] = 0
  33. else {
  34. flipped = true
  35. buf[i - 1] = twosComp(byte)
  36. }
  37. }
  38. }
  39. const parse = (buf) => {
  40. const pre = buf[0]
  41. const value = pre === 0x80 ? pos(buf.slice(1, buf.length))
  42. : pre === 0xff ? twos(buf)
  43. : null
  44. if (value === null)
  45. throw Error('invalid base256 encoding')
  46. if (!Number.isSafeInteger(value))
  47. // The number is so large that javascript cannot represent it with integer
  48. // precision.
  49. throw Error('parsed number outside of javascript safe integer range')
  50. return value
  51. }
  52. const twos = (buf) => {
  53. var len = buf.length
  54. var sum = 0
  55. var flipped = false
  56. for (var i = len - 1; i > -1; i--) {
  57. var byte = buf[i]
  58. var f
  59. if (flipped)
  60. f = onesComp(byte)
  61. else if (byte === 0)
  62. f = byte
  63. else {
  64. flipped = true
  65. f = twosComp(byte)
  66. }
  67. if (f !== 0)
  68. sum -= f * Math.pow(256, len - i - 1)
  69. }
  70. return sum
  71. }
  72. const pos = (buf) => {
  73. var len = buf.length
  74. var sum = 0
  75. for (var i = len - 1; i > -1; i--) {
  76. var byte = buf[i]
  77. if (byte !== 0)
  78. sum += byte * Math.pow(256, len - i - 1)
  79. }
  80. return sum
  81. }
  82. const onesComp = byte => (0xff ^ byte) & 0xff
  83. const twosComp = byte => ((0xff ^ byte) + 1) & 0xff
  84. module.exports = {
  85. encode,
  86. parse,
  87. }