-
-
Notifications
You must be signed in to change notification settings - Fork 37
/
Copy pathencode.js
136 lines (107 loc) · 3.25 KB
/
encode.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import { concat, text2arr } from 'uint8-util'
import { getType } from './util.js'
/**
* Encodes data in bencode.
*
* @param {Uint8Array|Array|String|Object|Number|Boolean} data
* @return {Uint8Array}
*/
function encode (data, buffer, offset) {
const buffers = []
let result = null
encode._encode(buffers, data)
result = concat(buffers)
encode.bytes = result.length
if (ArrayBuffer.isView(buffer)) {
buffer.set(result, offset)
return buffer
}
return result
}
encode.bytes = -1
encode._floatConversionDetected = false
encode._encode = function (buffers, data) {
if (data == null) { return }
switch (getType(data)) {
case 'object': encode.dict(buffers, data); break
case 'map': encode.dictMap(buffers, data); break
case 'array': encode.list(buffers, data); break
case 'set': encode.listSet(buffers, data); break
case 'string': encode.string(buffers, data); break
case 'number': encode.number(buffers, data); break
case 'boolean': encode.number(buffers, data); break
case 'arraybufferview': encode.buffer(buffers, new Uint8Array(data.buffer, data.byteOffset, data.byteLength)); break
case 'arraybuffer': encode.buffer(buffers, new Uint8Array(data)); break
}
}
const buffE = new Uint8Array([0x65])
const buffD = new Uint8Array([0x64])
const buffL = new Uint8Array([0x6C])
encode.buffer = function (buffers, data) {
buffers.push(text2arr(data.length + ':'), data)
}
encode.string = function (buffers, data) {
buffers.push(text2arr(text2arr(data).byteLength + ':' + data))
}
encode.number = function (buffers, data) {
if (Number.isInteger(data)) return buffers.push(text2arr('i' + BigInt(data) + 'e'))
const maxLo = 0x80000000
const hi = (data / maxLo) << 0
const lo = (data % maxLo) << 0
const val = hi * maxLo + lo
buffers.push(text2arr('i' + val + 'e'))
if (val !== data && !encode._floatConversionDetected) {
encode._floatConversionDetected = true
console.warn(
'WARNING: Possible data corruption detected with value "' + data + '":',
'Bencoding only defines support for integers, value was converted to "' + val + '"'
)
console.trace()
}
}
encode.dict = function (buffers, data) {
buffers.push(buffD)
let j = 0
let k
// fix for issue #13 - sorted dicts
const keys = Object.keys(data).sort()
const kl = keys.length
for (; j < kl; j++) {
k = keys[j]
if (data[k] == null) continue
encode.string(buffers, k)
encode._encode(buffers, data[k])
}
buffers.push(buffE)
}
encode.dictMap = function (buffers, data) {
buffers.push(buffD)
const keys = Array.from(data.keys()).sort()
for (const key of keys) {
if (data.get(key) == null) continue
ArrayBuffer.isView(key)
? encode._encode(buffers, key)
: encode.string(buffers, String(key))
encode._encode(buffers, data.get(key))
}
buffers.push(buffE)
}
encode.list = function (buffers, data) {
let i = 0
const c = data.length
buffers.push(buffL)
for (; i < c; i++) {
if (data[i] == null) continue
encode._encode(buffers, data[i])
}
buffers.push(buffE)
}
encode.listSet = function (buffers, data) {
buffers.push(buffL)
for (const item of data) {
if (item == null) continue
encode._encode(buffers, item)
}
buffers.push(buffE)
}
export default encode