bencodec
Version:
Library for decoding and encoding bencode data
133 lines (132 loc) • 3.67 kB
JavaScript
"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;