UNPKG

bencodec

Version:

Library for decoding and encoding bencode data

133 lines (132 loc) 3.67 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BencodeDecoder = void 0; const types_1 = require("./types"); const node_buffer_1 = require("node:buffer"); class BencodeDecoder { /** * Check if character in integer */ static _isInteger(char) { return char >= 0x30 && char <= 0x39; } /** * Constructor */ constructor(data, options) { if (!data) { throw new Error('Nothing to decode'); } this._index = 0; this._options = options || {}; this._buffer = typeof data === 'string' ? node_buffer_1.Buffer.from(data) : data; } /** * Decode bencoded data */ decode() { if (BencodeDecoder._isInteger(this._currentChar())) { return this._decodeString(); } if (this._currentChar() === types_1.FLAG.INTEGER) { return this._decodeInteger(); } if (this._currentChar() === types_1.FLAG.LIST) { return this._decodeList(); } if (this._currentChar() === types_1.FLAG.DICTIONARY) { return this._decodeDictionary(); } throw new Error('Invalid bencode data'); } /** * Get character by current index */ _currentChar() { return this._buffer[this._index]; } /** * Get character by current index and increment */ _next() { return this._buffer[this._index++]; } /** * Decode bencoded string */ _decodeString() { const length = this._decodeInteger(); const acc = []; for (let i = 0; i < length; i++) { acc.push(this._next()); } return this._options.stringify ? node_buffer_1.Buffer.from(acc).toString('utf8') : node_buffer_1.Buffer.from(acc); } /** * Decode bencoded integer */ _decodeInteger() { let sign = 1; let isFloat = false; let integer = 0; if (this._currentChar() === types_1.FLAG.INTEGER) { this._index++; } if (this._currentChar() === types_1.FLAG.PLUS) { this._index++; } if (this._currentChar() === types_1.FLAG.MINUS) { this._index++; sign = -1; } while (BencodeDecoder._isInteger(this._currentChar()) || this._currentChar() === types_1.FLAG.DOT) { if (this._currentChar() === types_1.FLAG.DOT) { isFloat = true; } isFloat === false ? integer = integer * 10 + (this._next() - 0x30) : this._index++; } if (this._currentChar() === types_1.FLAG.END) { this._index++; } if (this._currentChar() === types_1.FLAG.STR_DELIMITER) { this._index++; } return integer * sign; } /** * Decode bencoded list */ _decodeList() { const acc = []; // skip LIST flag this._next(); while (this._currentChar() !== types_1.FLAG.END) { acc.push(this.decode()); } // skip END flag this._next(); return acc; } /** * Decode bencoded dictionary */ _decodeDictionary() { const acc = {}; // skip DICTIONARY flag this._next(); while (this._currentChar() !== types_1.FLAG.END) { const key = this._decodeString(); acc[key.toString()] = this.decode(); } // skip END flag this._next(); return acc; } } exports.BencodeDecoder = BencodeDecoder;