large-numbers.js 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  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. }
  14. return buf
  15. }
  16. const encodePositive = (num, buf) => {
  17. buf[0] = 0x80
  18. for (var i = buf.length; i > 1; i--) {
  19. buf[i - 1] = num & 0xff
  20. num = Math.floor(num / 0x100)
  21. }
  22. }
  23. const encodeNegative = (num, buf) => {
  24. buf[0] = 0xff
  25. var flipped = false
  26. num = num * -1
  27. for (var i = buf.length; i > 1; i--) {
  28. var byte = num & 0xff
  29. num = Math.floor(num / 0x100)
  30. if (flipped) {
  31. buf[i - 1] = onesComp(byte)
  32. } else if (byte === 0) {
  33. buf[i - 1] = 0
  34. } else {
  35. flipped = true
  36. buf[i - 1] = twosComp(byte)
  37. }
  38. }
  39. }
  40. const parse = (buf) => {
  41. const pre = buf[0]
  42. const value = pre === 0x80 ? pos(buf.slice(1, buf.length))
  43. : pre === 0xff ? twos(buf)
  44. : null
  45. if (value === null) {
  46. throw Error('invalid base256 encoding')
  47. }
  48. if (!Number.isSafeInteger(value)) {
  49. // The number is so large that javascript cannot represent it with integer
  50. // precision.
  51. throw Error('parsed number outside of javascript safe integer range')
  52. }
  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. }
  74. return sum
  75. }
  76. const pos = (buf) => {
  77. var len = buf.length
  78. var sum = 0
  79. for (var i = len - 1; i > -1; i--) {
  80. var byte = buf[i]
  81. if (byte !== 0) {
  82. sum += byte * Math.pow(256, len - i - 1)
  83. }
  84. }
  85. return sum
  86. }
  87. const onesComp = byte => (0xff ^ byte) & 0xff
  88. const twosComp = byte => ((0xff ^ byte) + 1) & 0xff
  89. module.exports = {
  90. encode,
  91. parse,
  92. }