From d8d594a493e299518db6dffc90d65cb0634f86b4 Mon Sep 17 00:00:00 2001
From: jg42526 <210032080+jg42526@users.noreply.github.com>
Date: Mon, 12 May 2025 15:24:44 +0000
Subject: [PATCH 1/3] Add Bencode function operation
---
package-lock.json | 37 ++++++++++++
package.json | 1 +
src/core/config/Categories.json | 4 +-
src/core/operations/BencodeDecode.mjs | 63 +++++++++++++++++++++
src/core/operations/BencodeEncode.mjs | 55 ++++++++++++++++++
tests/operations/index.mjs | 2 +
tests/operations/tests/BencodeDecode.mjs | 66 ++++++++++++++++++++++
tests/operations/tests/BencodeEncode.mjs | 72 ++++++++++++++++++++++++
8 files changed, 299 insertions(+), 1 deletion(-)
create mode 100644 src/core/operations/BencodeDecode.mjs
create mode 100644 src/core/operations/BencodeEncode.mjs
create mode 100644 tests/operations/tests/BencodeDecode.mjs
create mode 100644 tests/operations/tests/BencodeEncode.mjs
diff --git a/package-lock.json b/package-lock.json
index 8dd38b7a..974f9810 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,6 +19,7 @@
"arrive": "^2.4.1",
"avsc": "^5.7.7",
"bcryptjs": "^2.4.3",
+ "bencodec": "^3.0.1",
"bignumber.js": "^9.1.2",
"blakejs": "^1.2.1",
"bootstrap": "4.6.2",
@@ -5403,6 +5404,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/base64-arraybuffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
+ "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -5473,6 +5483,24 @@
"integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==",
"license": "MIT"
},
+ "node_modules/bencode": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/bencode/-/bencode-4.0.0.tgz",
+ "integrity": "sha512-AERXw18df0pF3ziGOCyUjqKZBVNH8HV3lBxnx5w0qtgMIk4a1wb9BkcCQbkp9Zstfrn/dzRwl7MmUHHocX3sRQ==",
+ "license": "MIT",
+ "dependencies": {
+ "uint8-util": "^2.2.2"
+ },
+ "engines": {
+ "node": ">=12.20.0"
+ }
+ },
+ "node_modules/bencodec": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/bencodec/-/bencodec-3.0.1.tgz",
+ "integrity": "sha512-5Ntc3E7R1vSnBcOddG65L9kObEmZGI0Vool6z/7apwO5Hc9OlziwK0LyxvaTK5Il+nSWNxlVSuh2zJM+TN9O3g==",
+ "license": "MIT"
+ },
"node_modules/big.js": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
@@ -17850,6 +17878,15 @@
"integrity": "sha512-w+VZSp8hSZ/xWZfZNMppWNF6iqY+dcMYtG5CpwRDgxi94HIE6ematSdkzHGzVC4SDEaTsG65zrajN+oKoWG6ew==",
"license": "MIT"
},
+ "node_modules/uint8-util": {
+ "version": "2.2.5",
+ "resolved": "https://registry.npmjs.org/uint8-util/-/uint8-util-2.2.5.tgz",
+ "integrity": "sha512-/QxVQD7CttWpVUKVPz9znO+3Dd4BdTSnFQ7pv/4drVhC9m4BaL2LFHTkJn6EsYoxT79VDq/2Gg8L0H22PrzyMw==",
+ "license": "MIT",
+ "dependencies": {
+ "base64-arraybuffer": "^1.0.2"
+ }
+ },
"node_modules/ultron": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
diff --git a/package.json b/package.json
index feb18bc8..4b116619 100644
--- a/package.json
+++ b/package.json
@@ -105,6 +105,7 @@
"arrive": "^2.4.1",
"avsc": "^5.7.7",
"bcryptjs": "^2.4.3",
+ "bencodec": "^3.0.1",
"bignumber.js": "^9.1.2",
"blakejs": "^1.2.1",
"bootstrap": "4.6.2",
diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json
index 7f9591e0..a44b65a7 100644
--- a/src/core/config/Categories.json
+++ b/src/core/config/Categories.json
@@ -162,7 +162,9 @@
"Typex",
"Lorenz",
"Colossus",
- "SIGABA"
+ "SIGABA",
+ "Bencode Encode",
+ "Bencode Decode"
]
},
{
diff --git a/src/core/operations/BencodeDecode.mjs b/src/core/operations/BencodeDecode.mjs
new file mode 100644
index 00000000..a4a680bf
--- /dev/null
+++ b/src/core/operations/BencodeDecode.mjs
@@ -0,0 +1,63 @@
+/**
+ * @author jg42526
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation.mjs";
+import bencodec from "bencodec";
+
+/**
+ * URL Decode operation
+ */
+class BencodeDecode extends Operation {
+
+ /**
+ * URLDecode constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "Bencode Decode";
+ this.module = "Encodings";
+ this.description = "Decodes a Bencoded string.
e.g. 7:bencode
becomes bencode
";
+ this.infoURL = "https://en.wikipedia.org/wiki/Bencode";
+ this.inputType = "string";
+ this.outputType = "string";
+ this.args = [];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ run(input, args) {
+ if (input) return toStringRepresentation(bencodec.decode(input, { stringify: true }));
+ return "";
+ }
+
+}
+
+export default BencodeDecode;
+
+/**
+ * Returns string representation of object
+ */
+function toStringRepresentation(value) {
+ if (typeof value === "string") {
+ return value;
+ }
+
+ if (typeof value === "number" || typeof value === "boolean") {
+ return String(value);
+ }
+
+ if (Array.isArray(value) || (value !== null && typeof value === "object")) {
+ // For arrays and objects, output JSON string
+ return JSON.stringify(value);
+ }
+
+ // For other types (undefined, null), handle as you see fit, e.g.:
+ return String(value);
+}
diff --git a/src/core/operations/BencodeEncode.mjs b/src/core/operations/BencodeEncode.mjs
new file mode 100644
index 00000000..91d519ed
--- /dev/null
+++ b/src/core/operations/BencodeEncode.mjs
@@ -0,0 +1,55 @@
+/**
+ * @author jg42526
+ * @copyright Crown Copyright 2016
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation.mjs";
+import bencodec from "bencodec";
+
+/**
+ * URL Decode operation
+ */
+class BencodeEncode extends Operation {
+
+ /**
+ * URLDecode constructor
+ */
+ constructor() {
+ super();
+
+ this.name = "Bencode Encode";
+ this.module = "Encodings";
+ this.description = "Bencodes a string.
e.g. bencode
becomes 7:bencode
";
+ this.infoURL = "https://en.wikipedia.org/wiki/Bencode";
+ this.inputType = "string";
+ this.outputType = "string";
+ this.args = [];
+ }
+
+ /**
+ * @param {string} input
+ * @param {Object[]} args
+ * @returns {string}
+ */
+ run(input, args) {
+ return bencodec.encode(parseValue(input), { stringify: true });
+ }
+
+}
+
+export default BencodeEncode;
+
+/**
+ * Parses string, returns appropraite data structure
+ */
+function parseValue(str) {
+ const trimmed = str.trim();
+ try {
+ // Attempt to parse with JSON.parse
+ return JSON.parse(trimmed);
+ } catch (e) {
+ // If JSON.parse fails, treat input as a plain string (assuming it's unquoted)
+ return trimmed;
+ }
+}
diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs
index ab1ceb8f..8d195553 100644
--- a/tests/operations/index.mjs
+++ b/tests/operations/index.mjs
@@ -26,6 +26,8 @@ import "./tests/Base64.mjs";
import "./tests/Base85.mjs";
import "./tests/Base92.mjs";
import "./tests/BCD.mjs";
+import "./tests/BencodeEncode.mjs";
+import "./tests/BencodeDecode.mjs";
import "./tests/BitwiseOp.mjs";
import "./tests/BLAKE2b.mjs";
import "./tests/BLAKE2s.mjs";
diff --git a/tests/operations/tests/BencodeDecode.mjs b/tests/operations/tests/BencodeDecode.mjs
new file mode 100644
index 00000000..c0297d8b
--- /dev/null
+++ b/tests/operations/tests/BencodeDecode.mjs
@@ -0,0 +1,66 @@
+/**
+ * Bencode Encode tests.
+ *
+ * @author jg42526
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+import TestRegister from "../../lib/TestRegister.mjs";
+
+TestRegister.addTests([
+ {
+ name: "Bencode Decode: nothing",
+ input: "",
+ expectedOutput: "",
+ recipeConfig: [
+ {
+ "op": "Bencode Decode",
+ "args": []
+ }
+ ]
+ },
+ {
+ name: "Bencode Decode: integer",
+ input: "i42e",
+ expectedOutput: "42",
+ recipeConfig: [
+ {
+ "op": "Bencode Decode",
+ "args": []
+ }
+ ]
+ },
+ {
+ name: "Bencode Decode: byte string",
+ input: "7:bencode",
+ expectedOutput: "bencode",
+ recipeConfig: [
+ {
+ "op": "Bencode Decode",
+ "args": []
+ }
+ ]
+ },
+ {
+ name: "Bencode Decode: list",
+ input: "l7:bencodei-20ee",
+ expectedOutput: `["bencode",-20]`,
+ recipeConfig: [
+ {
+ "op": "Bencode Decode",
+ "args": []
+ }
+ ]
+ },
+ {
+ name: "Bencode Decode: dictionary",
+ input: "d7:meaningi42e4:wiki7:bencodee",
+ expectedOutput: `{"meaning":42,"wiki":"bencode"}`,
+ recipeConfig: [
+ {
+ "op": "Bencode Decode",
+ "args": []
+ }
+ ]
+ },
+]);
diff --git a/tests/operations/tests/BencodeEncode.mjs b/tests/operations/tests/BencodeEncode.mjs
new file mode 100644
index 00000000..51b96826
--- /dev/null
+++ b/tests/operations/tests/BencodeEncode.mjs
@@ -0,0 +1,72 @@
+/**
+ * Bencode Encode tests.
+ *
+ * @author jg42526
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+import TestRegister from "../../lib/TestRegister.mjs";
+
+TestRegister.addTests([
+ {
+ name: "Bencode Encode: nothing",
+ input: "",
+ expectedOutput: "0:",
+ recipeConfig: [
+ {
+ "op": "Bencode Encode",
+ "args": []
+ }
+ ]
+ },
+ {
+ name: "Bencode Encode: integer",
+ input: "42",
+ expectedOutput: "i42e",
+ recipeConfig: [
+ {
+ "op": "Bencode Encode",
+ "args": []
+ }
+ ]
+ },
+ {
+ name: "Bencode Encode: byte string",
+ input: "bencode",
+ expectedOutput: "7:bencode",
+ recipeConfig: [
+ {
+ "op": "Bencode Encode",
+ "args": []
+ }
+ ]
+ },
+ {
+ name: "Bencode Encode: list",
+ input: `[
+ "bencode",
+ -20
+ ]`,
+ expectedOutput: "l7:bencodei-20ee",
+ recipeConfig: [
+ {
+ "op": "Bencode Encode",
+ "args": []
+ }
+ ]
+ },
+ {
+ name: "Bencode Encode: dictionary",
+ input: `{
+ "meaning": 42,
+ "wiki": "bencode"
+ }`,
+ expectedOutput: "d7:meaningi42e4:wiki7:bencodee",
+ recipeConfig: [
+ {
+ "op": "Bencode Encode",
+ "args": []
+ }
+ ]
+ },
+]);
From 41ce2eceffcabcd5db2fe61d2246997ae0a50c86 Mon Sep 17 00:00:00 2001
From: jg42526 <210032080+jg42526@users.noreply.github.com>
Date: Fri, 16 May 2025 09:35:46 +0000
Subject: [PATCH 2/3] Removed dependency on external package by bringing it
in-line
---
package-lock.json | 1 -
package.json | 1 -
src/core/operations/BencodeDecode.mjs | 145 +++++++++++++++++++++++++-
src/core/operations/BencodeEncode.mjs | 139 +++++++++++++++++++++++-
4 files changed, 278 insertions(+), 8 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 974f9810..3a3e200a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -19,7 +19,6 @@
"arrive": "^2.4.1",
"avsc": "^5.7.7",
"bcryptjs": "^2.4.3",
- "bencodec": "^3.0.1",
"bignumber.js": "^9.1.2",
"blakejs": "^1.2.1",
"bootstrap": "4.6.2",
diff --git a/package.json b/package.json
index 4b116619..feb18bc8 100644
--- a/package.json
+++ b/package.json
@@ -105,7 +105,6 @@
"arrive": "^2.4.1",
"avsc": "^5.7.7",
"bcryptjs": "^2.4.3",
- "bencodec": "^3.0.1",
"bignumber.js": "^9.1.2",
"blakejs": "^1.2.1",
"bootstrap": "4.6.2",
diff --git a/src/core/operations/BencodeDecode.mjs b/src/core/operations/BencodeDecode.mjs
index a4a680bf..0f7c659b 100644
--- a/src/core/operations/BencodeDecode.mjs
+++ b/src/core/operations/BencodeDecode.mjs
@@ -5,7 +5,6 @@
*/
import Operation from "../Operation.mjs";
-import bencodec from "bencodec";
/**
* URL Decode operation
@@ -13,7 +12,7 @@ import bencodec from "bencodec";
class BencodeDecode extends Operation {
/**
- * URLDecode constructor
+ * URL Decode constructor
*/
constructor() {
super();
@@ -33,7 +32,10 @@ class BencodeDecode extends Operation {
* @returns {string}
*/
run(input, args) {
- if (input) return toStringRepresentation(bencodec.decode(input, { stringify: true }));
+ if (input) {
+ const decoder = new BencodeDecoder(input, {stringify: true}).decode();
+ return toStringRepresentation(decoder);
+ }
return "";
}
@@ -61,3 +63,140 @@ function toStringRepresentation(value) {
// For other types (undefined, null), handle as you see fit, e.g.:
return String(value);
}
+
+const FLAG = {
+ INTEGER: 0x69, // 'i'
+ STR_DELIMITER: 0x3a, // ':'
+ LIST: 0x6c, // 'l'
+ DICTIONARY: 0x64, // 'd'
+ END: 0x65, // 'e'
+ MINUS: 0x2d, // '-'
+ PLUS: 0x2b, // '+'
+ DOT: 0x2e, // '.'
+};
+
+/**
+ * Class for decoding data from the Bencode format.
+ */
+class BencodeDecoder {
+ /**
+ * Creates an instance of BencodeDecoder.
+ * @param {Buffer|string} data - The bencoded data to decode.
+ * @param {Object} [options={}] - Optional decoding options.
+ * @param {boolean} [options.stringify=false] - Whether to return strings instead of Buffers.
+ */
+ constructor(data, options = {}) {
+ if (!data) throw new Error("Nothing to decode");
+ this._index = 0;
+ this._options = options;
+ this._buffer = typeof data === "string" ? Buffer.from(data) : data;
+ }
+
+ /**
+ * Checks if a character code represents a digit (0–9).
+ * @param {number} char - The character code to check.
+ * @returns {boolean} - True if the character is a digit.
+ */
+ static _isInteger(char) {
+ return char >= 0x30 && char <= 0x39;
+ }
+
+ /**
+ * Returns the current character code in the buffer.
+ * @returns {number} - The current character code.
+ */
+ _currentChar() {
+ return this._buffer[this._index];
+ }
+
+ /**
+ * Returns the next character code in the buffer and advances the index.
+ * @returns {number} - The next character code.
+ */
+ _next() {
+ return this._buffer[this._index++];
+ }
+
+ /**
+ * Decodes the bencoded data.
+ * @returns {*} - The decoded value (string, number, list, or dictionary).
+ */
+ decode() {
+ const char = this._currentChar();
+ if (BencodeDecoder._isInteger(char)) return this._decodeString();
+ if (char === FLAG.INTEGER) return this._decodeInteger();
+ if (char === FLAG.LIST) return this._decodeList();
+ if (char === FLAG.DICTIONARY) return this._decodeDictionary();
+ throw new Error("Invalid bencode data");
+ }
+
+ /**
+ * Decodes a bencoded string.
+ * @returns {Buffer|string} - The decoded string or Buffer.
+ */
+ _decodeString() {
+ const length = this._decodeInteger();
+ const acc = [];
+ for (let i = 0; i < length; i++) acc.push(this._next());
+ const result = Buffer.from(acc);
+ return this._options.stringify ? result.toString("utf8") : result;
+ }
+
+ /**
+ * Decodes a bencoded integer.
+ * @returns {number} - The decoded integer.
+ */
+ _decodeInteger() {
+ let sign = 1;
+ let integer = 0;
+
+ if (this._currentChar() === FLAG.INTEGER) this._index++;
+ if (this._currentChar() === FLAG.PLUS) this._index++;
+ if (this._currentChar() === FLAG.MINUS) {
+ this._index++;
+ sign = -1;
+ }
+
+ while (BencodeDecoder._isInteger(this._currentChar()) || this._currentChar() === FLAG.DOT) {
+ if (this._currentChar() === FLAG.DOT) {
+ this._index++; // Skip dot (float not supported)
+ } else {
+ integer = integer * 10 + (this._next() - 0x30);
+ }
+ }
+
+ if (this._currentChar() === FLAG.END) this._index++;
+ if (this._currentChar() === FLAG.STR_DELIMITER) this._index++;
+
+ return integer * sign;
+ }
+
+ /**
+ * Decodes a bencoded list.
+ * @returns {Array} - The decoded list.
+ */
+ _decodeList() {
+ const acc = [];
+ this._next(); // Skip 'l'
+ while (this._currentChar() !== FLAG.END) {
+ acc.push(this.decode());
+ }
+ this._next(); // Skip 'e'
+ return acc;
+ }
+
+ /**
+ * Decodes a bencoded dictionary.
+ * @returns {Object} - The decoded dictionary.
+ */
+ _decodeDictionary() {
+ const acc = {};
+ this._next(); // Skip 'd'
+ while (this._currentChar() !== FLAG.END) {
+ const key = this._decodeString();
+ acc[key.toString()] = this.decode();
+ }
+ this._next(); // Skip 'e'
+ return acc;
+ }
+}
diff --git a/src/core/operations/BencodeEncode.mjs b/src/core/operations/BencodeEncode.mjs
index 91d519ed..2cedac8b 100644
--- a/src/core/operations/BencodeEncode.mjs
+++ b/src/core/operations/BencodeEncode.mjs
@@ -5,7 +5,6 @@
*/
import Operation from "../Operation.mjs";
-import bencodec from "bencodec";
/**
* URL Decode operation
@@ -33,7 +32,8 @@ class BencodeEncode extends Operation {
* @returns {string}
*/
run(input, args) {
- return bencodec.encode(parseValue(input), { stringify: true });
+ const encoder = new BencodeEncoder({ stringify: true });
+ return encoder.encode(parseValue(input));
}
}
@@ -41,7 +41,7 @@ class BencodeEncode extends Operation {
export default BencodeEncode;
/**
- * Parses string, returns appropraite data structure
+ * Parses string, returns appropriate data structure
*/
function parseValue(str) {
const trimmed = str.trim();
@@ -53,3 +53,136 @@ function parseValue(str) {
return trimmed;
}
}
+
+const FLAG = {
+ INTEGER: 0x69, // 'i'
+ STR_DELIMITER: 0x3a, // ':'
+ LIST: 0x6c, // 'l'
+ DICTIONARY: 0x64, // 'd'
+ END: 0x65, // 'e'
+};
+
+/**
+ * BencodeEncoder class for encoding data into bencode format.
+ */
+class BencodeEncoder {
+ /**
+ *
+ */
+ constructor(options = {}) {
+ this._integerIdentifier = Buffer.from([FLAG.INTEGER]);
+ this._stringDelimiterIdentifier = Buffer.from([FLAG.STR_DELIMITER]);
+ this._listIdentifier = Buffer.from([FLAG.LIST]);
+ this._dictionaryIdentifier = Buffer.from([FLAG.DICTIONARY]);
+ this._endIdentifier = Buffer.from([FLAG.END]);
+ this._buffer = [];
+ this._options = options;
+ }
+
+ /**
+ * Encodes the given data into bencode format.
+ * @param {*} data - The data to encode.
+ * @returns {Buffer|string} - The encoded data as a Buffer or string.
+ */
+ encode(data) {
+ this._encodeType(data);
+ const result = Buffer.concat(this._buffer);
+ return this._options.stringify ? result.toString("utf8") : result;
+ }
+
+ /**
+ * Determines the type of data and encodes it accordingly.
+ * @param {*} data - The data to encode.
+ */
+ _encodeType(data) {
+ if (Buffer.isBuffer(data)) {
+ return this._encodeBuffer(data);
+ }
+ if (Array.isArray(data)) {
+ return this._encodeList(data);
+ }
+ if (ArrayBuffer.isView(data)) {
+ return this._encodeBuffer(Buffer.from(data.buffer, data.byteOffset, data.byteLength));
+ }
+ if (data instanceof ArrayBuffer) {
+ return this._encodeBuffer(Buffer.from(data));
+ }
+ if (typeof data === "boolean") {
+ return this._encodeInteger(data ? 1 : 0);
+ }
+ if (typeof data === "number") {
+ return this._encodeInteger(data);
+ }
+ if (typeof data === "string") {
+ return this._encodeString(data);
+ }
+ if (typeof data === "object") {
+ return this._encodeDictionary(data);
+ }
+ throw new Error(`${typeof data} is unsupported type.`);
+ }
+
+ /**
+ * Buffer into bencode format.
+ * @param {Buffer} data - The buffer to encode.
+ */
+ _encodeBuffer(data) {
+ this._buffer.push(
+ Buffer.from(String(data.length)),
+ this._stringDelimiterIdentifier,
+ data
+ );
+ }
+
+ /**
+ * Encodes a string into bencode format.
+ * @param {string} data - The string to encode.
+ */
+ _encodeString(data) {
+ this._buffer.push(
+ Buffer.from(String(Buffer.byteLength(data))),
+ this._stringDelimiterIdentifier,
+ Buffer.from(data)
+ );
+ }
+
+ /**
+ * Encodes an integer into bencode format.
+ * @param {number} data - The integer to encode.
+ */
+ _encodeInteger(data) {
+ this._buffer.push(
+ this._integerIdentifier,
+ Buffer.from(String(Math.round(data))),
+ this._endIdentifier
+ );
+ }
+
+ /**
+ * Encodes a list (array) into bencode format.
+ * @param {Array} data - The list to encode.
+ */
+ _encodeList(data) {
+ this._buffer.push(this._listIdentifier);
+ for (const item of data) {
+ if (item === null || item === undefined) continue;
+ this._encodeType(item);
+ }
+ this._buffer.push(this._endIdentifier);
+ }
+
+ /**
+ * Encodes a dictionary (object) into bencode format.
+ * @param {Object} data - The dictionary to encode.
+ */
+ _encodeDictionary(data) {
+ this._buffer.push(this._dictionaryIdentifier);
+ const keys = Object.keys(data).sort();
+ for (const key of keys) {
+ if (data[key] === null || data[key] === undefined) continue;
+ this._encodeString(key);
+ this._encodeType(data[key]);
+ }
+ this._buffer.push(this._endIdentifier);
+ }
+}
From 7b0a92ad1e87a2aed71bf8990389114a046afed6 Mon Sep 17 00:00:00 2001
From: jg42526 <210032080+jg42526@users.noreply.github.com>
Date: Fri, 16 May 2025 09:37:08 +0000
Subject: [PATCH 3/3] Giving credit to author of bencoding operation
---
src/core/operations/BencodeDecode.mjs | 2 ++
src/core/operations/BencodeEncode.mjs | 2 ++
2 files changed, 4 insertions(+)
diff --git a/src/core/operations/BencodeDecode.mjs b/src/core/operations/BencodeDecode.mjs
index 0f7c659b..7b76820f 100644
--- a/src/core/operations/BencodeDecode.mjs
+++ b/src/core/operations/BencodeDecode.mjs
@@ -77,6 +77,8 @@ const FLAG = {
/**
* Class for decoding data from the Bencode format.
+ * Credit to @isolomak:
+ * https://github.com/isolomak/bencodec
*/
class BencodeDecoder {
/**
diff --git a/src/core/operations/BencodeEncode.mjs b/src/core/operations/BencodeEncode.mjs
index 2cedac8b..7e952ef2 100644
--- a/src/core/operations/BencodeEncode.mjs
+++ b/src/core/operations/BencodeEncode.mjs
@@ -64,6 +64,8 @@ const FLAG = {
/**
* BencodeEncoder class for encoding data into bencode format.
+ * Credit to @isolomak:
+ * https://github.com/isolomak/bencodec
*/
class BencodeEncoder {
/**