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