UNPKG

@thi.ng/bencode

Version:

Bencode binary encoder / decoder with optional UTF8 encoding & floating point support

46 lines (45 loc) 1.68 kB
import { isArrayLike } from "@thi.ng/checks/is-arraylike"; import { isBoolean } from "@thi.ng/checks/is-boolean"; import { isNumber } from "@thi.ng/checks/is-number"; import { isPlainObject } from "@thi.ng/checks/is-plain-object"; import { isString } from "@thi.ng/checks/is-string"; import { assert } from "@thi.ng/errors/assert"; import { unsupported } from "@thi.ng/errors/unsupported"; import { utf8Length } from "@thi.ng/strings/utf8"; import { bytes, str, u8, u8array } from "@thi.ng/transducers-binary/bytes"; import { mapcat } from "@thi.ng/transducers/mapcat"; const FLOAT_RE = /^[0-9.-]+$/; const ENCODERS = { i: (x) => { __ensureValidNumber(x); return [str(`i${Math.floor(x)}e`)]; }, f: (x) => { __ensureValidNumber(x); assert( FLOAT_RE.test(x.toString()), `values requiring exponential notation not allowed (${x})` ); return [str(`f${x}e`)]; }, b: (buf) => [str(buf.length + ":"), u8array(buf)], s: (x) => [str(utf8Length(x) + ":" + x)], l: (x) => [u8(108), ...mapcat(__encodeBin, x), u8(101)], d: (x) => [ u8(100), ...mapcat( (k) => __encodeBin(k).concat(__encodeBin(x[k])), Object.keys(x).sort() ), u8(101) ] }; const encode = (x, cap = 1024) => bytes(cap, __encodeBin(x)); const __encodeBin = (x) => ENCODERS[isNumber(x) ? Math.floor(x) !== x ? "f" : "i" : isBoolean(x) ? "i" : isString(x) ? "s" : x instanceof Uint8Array ? "b" : isPlainObject(x) ? "d" : isArrayLike(x) ? "l" : unsupported(`unsupported data type: ${x}`)](x); const __ensureValidNumber = (x) => { assert(isFinite(x), `can't encode infinite value`); assert(!isNaN(x), `can't encode NaN`); }; export { encode };