- Add GETTING_STARTED.md with quick start guide and development modes - Add INSTALL.sh automated installation script - Add INSTALLATION_CHECKLIST.md, INSTALLATION_SUCCESS.md, and INSTALLATION_SUMMARY.md - Add QUICK_REFERENCE.md for common commands - Add SETUP_GUIDE.md with detailed setup instructions - Update README.md with improved project overview - Add did-wallet app dependencies and node_modules
137 lines
3.3 KiB
JavaScript
137 lines
3.3 KiB
JavaScript
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
|