-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathsffcEncoder.js
111 lines (103 loc) · 2.97 KB
/
sffcEncoder.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
var flagMask = 0xe0
var encodingSchemeTable =
[
{
'flag': 0x20,
'exponent': 4,
'byteSize': 2,
'mantis': 9
},
{
'flag': 0x40,
'exponent': 4,
'byteSize': 3,
'mantis': 17
},
{
'flag': 0x60,
'exponent': 4,
'byteSize': 4,
'mantis': 25
},
{
'flag': 0x80,
'exponent': 3,
'byteSize': 5,
'mantis': 34
},
{
'flag': 0xa0,
'exponent': 3,
'byteSize': 6,
'mantis': 42
},
{
'flag': 0xc0,
'exponent': 0,
'byteSize': 7,
'mantis': 54
}
]
var flagLookup = {}
var mantisLookup = {}
for (var i = 0; i < encodingSchemeTable.length; i++) {
var flagObject = encodingSchemeTable[i]
flagLookup[flagObject.flag] = flagObject
}
var currentIndex = 0
var currentMantis = encodingSchemeTable[currentIndex].mantis
var endMantis = encodingSchemeTable[encodingSchemeTable.length - 1].mantis
for (var i = 1; i <= endMantis; i++) {
if (i > currentMantis) {
currentIndex++
currentMantis = encodingSchemeTable[currentIndex].mantis
}
mantisLookup[i] = encodingSchemeTable[currentIndex]
}
var intToFloatArray = function (number, n) {
n = n || 0
return number % 10 ? [number, n] : intToFloatArray(number / 10, n + 1)
}
var padLeadingZeros = function (hex, byteSize) {
return (hex.length === byteSize * 2) ? hex : padLeadingZeros('0' + hex, byteSize)
}
module.exports = {
encode: function (number) {
var buf
if (number < 0) throw new Error('Number is out of bounds')
if (number > Number.MAX_SAFE_INTEGER) throw new Error('Number is out of bounds')
if (number < 32) {
buf = new Buffer([number])
return buf
}
var floatingNumberArray = intToFloatArray(number)
while (true) {
var encodingObject = mantisLookup[floatingNumberArray[0].toString(2).length]
if (!encodingObject) throw new Error('Number is out of bounds')
if ((Math.pow(2, encodingObject.exponent) - 1) >= floatingNumberArray[1]) break
floatingNumberArray[0] *= 10
floatingNumberArray[1] -= 1
}
var shiftedNumber = floatingNumberArray[0] * Math.pow(2, encodingObject.exponent)
var numberString = padLeadingZeros(shiftedNumber.toString(16), encodingObject.byteSize)
buf = new Buffer(numberString, 'hex')
buf[0] = buf[0] | encodingObject.flag
buf[buf.length - 1] = buf[buf.length - 1] | floatingNumberArray[1]
return buf
},
decode: function (consume) {
var flagByte = consume(1)[0]
var flag = flagByte & flagMask
if (flag === 0) return flagByte
if (flag === 0xe0) flag = 0xc0
var encodingObject = flagLookup[flag]
var headOfNumber = new Buffer([flagByte & (~flag)])
var tailOfNumber = consume(encodingObject.byteSize - 1)
var fullNumber = Buffer.concat([headOfNumber, tailOfNumber])
var number = parseInt(fullNumber.toString('hex'), 16)
var exponentShift = Math.pow(2, encodingObject.exponent)
var exponent = number % exponentShift
var mantis = Math.floor(number / exponentShift)
return mantis * Math.pow(10, exponent)
}
}