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