UNPKG

@substrate-system/bencode

Version:
8 lines (7 loc) 8.17 kB
{ "version": 3, "sources": ["../src/decode.ts"], "sourcesContent": ["import { arr2text, text2arr, arr2hex } from '@substrate-system/uint8-util'\n\nconst INTEGER_START = 0x69 // 'i'\nconst STRING_DELIM = 0x3A // ':'\nconst DICTIONARY_START = 0x64 // 'd'\nconst LIST_START = 0x6C // 'l'\nconst END_OF_TYPE = 0x65 // 'e'\n\nexport type Decoded =\n | Record<string, any>\n | Array<any>\n | string\n | number;\n\nexport interface Decoder {\n (data:Uint8Array|string):Decoded|null\n (data:Uint8Array|string, encoding:string):Decoded|null\n (data:Uint8Array|string, start:number, encoding:string):Decoded|null\n (data:Uint8Array|string, start:number, end:number, encoding:string):Decoded|null\n data:Uint8Array|null;\n bytes:number;\n position:number;\n encoding:string|null;\n next:()=>Record<string, any>|Array<any>|Uint8Array|string|number|null;\n dictionary:()=>Record<string, any>|null;\n list:()=>any[];\n buffer:()=>Uint8Array|string;\n find:(ch:number)=>number|null;\n integer:()=>number;\n}\n\n/**\n * Decode bencoded data.\n *\n * @param {Uint8Array|string} data The buffer to decode\n * @param {number} [start] Optional start index\n * @param {number} [end] Optional end index\n * @param {string} [encoding] Optional encoding type (utf8, etc)\n * @return {Decoded}\n */\nconst decode:Decoder = function decode (\n data:Uint8Array|string,\n start?:number|string,\n end?:number|string,\n encoding?:string\n):Decoded|null {\n if (!data || data.length === 0) {\n throw new Error('Missing data to decode.')\n }\n\n if (typeof start !== 'number' && encoding == null) {\n encoding = start\n start = undefined\n }\n\n if (typeof end !== 'number' && encoding == null) {\n encoding = end\n end = undefined\n }\n\n decode.position = 0\n decode.encoding = encoding || null\n\n decode.data = !(ArrayBuffer.isView(data)) ?\n text2arr(data) :\n new Uint8Array(data.slice(\n start as number|undefined,\n end as number|undefined)\n )\n\n decode.bytes = decode.data.length\n\n return decode.next()\n}\n\ndecode.bytes = 0\ndecode.position = 0\ndecode.data = null\ndecode.encoding = null\n\ndecode.next = function ():Record<string, any>|Array<any>|Uint8Array|string|number|null {\n switch (decode.data![decode.position]) {\n case DICTIONARY_START:\n return decode.dictionary()\n case LIST_START:\n return decode.list()\n case INTEGER_START:\n return decode.integer()\n default:\n return decode.buffer()\n }\n}\n\ndecode.find = function (chr:number):number|null {\n if (!decode.data?.length) return null\n let i = decode.position\n const c = decode.data.length\n const d = decode.data\n\n while (i < c) {\n if (d[i] === chr) return i\n i++\n }\n\n throw new Error(\n 'Invalid data: Missing delimiter \"' +\n String.fromCharCode(chr) + '\" [0x' +\n chr.toString(16) + ']'\n )\n}\n\ndecode.dictionary = function ():Record<string, any>|null {\n if (!decode.data) return null\n decode.position++\n\n const dict = {}\n\n while (decode.data[decode.position] !== END_OF_TYPE) {\n const buffer = decode.buffer()\n if (typeof buffer === 'string') {\n dict[buffer] = decode.next()\n continue\n }\n let key = arr2text(buffer)\n if (key.includes('\\uFFFD')) key = arr2hex(buffer)\n dict[key] = decode.next()\n }\n\n decode.position++\n\n return dict\n}\n\ndecode.list = function ():any[] {\n decode.position++\n\n const lst:any[] = []\n\n while (decode.data![decode.position] !== END_OF_TYPE) {\n lst.push(decode.next())\n }\n\n decode.position++\n\n return lst\n}\n\ndecode.integer = function () {\n const end = decode.find(END_OF_TYPE)\n const number = getIntFromBuffer(decode.data, decode.position + 1, end)\n if (!end) throw new Error('not end')\n\n decode.position += end + 1 - decode.position\n\n return number\n}\n\ndecode.buffer = function ():Uint8Array|string {\n const sep = decode.find(STRING_DELIM)\n const newIndex = (sep || 0) + 1\n const length = getIntFromBuffer(decode.data, decode.position, sep)\n const end = newIndex + length\n\n decode.position = end\n\n return decode.encoding ?\n arr2text(decode.data!.slice(newIndex, end)) :\n decode.data!.slice(newIndex, end)\n}\n\nexport default decode\n\n/**\n * replaces parseInt(buffer.toString('ascii', start, end)).\n * For strings with less then ~30 charachters, this is actually a lot faster.\n *\n * @param {Uint8Array} data\n * @param {Number} start\n * @param {Number} end\n * @return {Number} calculated number\n */\nfunction getIntFromBuffer (buffer, start, end) {\n let sum = 0\n let sign = 1\n\n for (let i = start; i < end; i++) {\n const num = buffer[i]\n\n if (num < 58 && num >= 48) {\n sum = sum * 10 + (num - 48)\n continue\n }\n\n if (i === start && num === 43) { // +\n continue\n }\n\n if (i === start && num === 45) { // -\n sign = -1\n continue\n }\n\n if (num === 46) { // .\n // its a float. break here.\n break\n }\n\n throw new Error('not a number: buffer[' + i + '] = ' + num)\n }\n\n return sum * sign\n}\n"], "mappings": "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", "names": ["decode"] }