large-numbers.js 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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 = exports.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 = exports.parse = (buf) => {
  40. var post = buf[buf.length - 1]
  41. var pre = buf[0]
  42. var value;
  43. if (pre === 0x80)
  44. value = pos(buf.slice(1, buf.length))
  45. else if (pre === 0xff)
  46. value = twos(buf)
  47. else
  48. throw Error('invalid base256 encoding')
  49. if (!Number.isSafeInteger(value))
  50. // The number is so large that javascript cannot represent it with integer
  51. // precision.
  52. throw Error('parsed number outside of javascript safe integer range')
  53. return value
  54. }
  55. const twos = (buf) => {
  56. var len = buf.length
  57. var sum = 0
  58. var flipped = false
  59. for (var i = len - 1; i > -1; i--) {
  60. var byte = buf[i]
  61. var f
  62. if (flipped)
  63. f = onesComp(byte)
  64. else if (byte === 0)
  65. f = byte
  66. else {
  67. flipped = true
  68. f = twosComp(byte)
  69. }
  70. if (f !== 0)
  71. sum -= f * Math.pow(256, len - i - 1)
  72. }
  73. return sum
  74. }
  75. const pos = (buf) => {
  76. var len = buf.length
  77. var sum = 0
  78. for (var i = len - 1; i > -1; i--) {
  79. var byte = buf[i]
  80. if (byte !== 0)
  81. sum += byte * Math.pow(256, len - i - 1)
  82. }
  83. return sum
  84. }
  85. const onesComp = byte => (0xff ^ byte) & 0xff
  86. const twosComp = byte => ((0xff ^ byte) + 1) & 0xff