diff --git a/src/core/config/Categories.js b/src/core/config/Categories.js index 8b828bc..177c71f 100755 --- a/src/core/config/Categories.js +++ b/src/core/config/Categories.js @@ -113,7 +113,7 @@ const Categories = [ ] }, { - name: "Logical operations", + name: "Arithmetic / Logic", ops: [ "XOR", "XOR Brute Force", @@ -127,6 +127,13 @@ const Categories = [ "Rotate left", "Rotate right", "ROT13", + "Sum", + "Subtract", + "Multiply", + "Divide", + "Mean", + "Median", + "Standard Deviation", ] }, { diff --git a/src/core/config/OperationConfig.js b/src/core/config/OperationConfig.js index 1e97511..55c5ff4 100755 --- a/src/core/config/OperationConfig.js +++ b/src/core/config/OperationConfig.js @@ -1,3 +1,4 @@ +import Arithmetic from "../operations/Arithmetic.js"; import Base from "../operations/Base.js"; import Base58 from "../operations/Base58.js"; import Base64 from "../operations/Base64.js"; @@ -676,6 +677,97 @@ const OperationConfig = { } ] }, + "Sum": { + module: "Default", + description: "Sums a list of numbers. If an item in the string is not a number it is excluded from the list.

e.g. 0x0a 8 .5 becomes 18.5", + inputType: "string", + outputType: "string", + args: [ + { + name: "Delimiter", + type: "option", + value: Arithmetic.DELIM_OPTIONS + } + ] + }, + "Subtract": { + module: "Default", + description: "Subtracts a list of numbers. If an item in the string is not a number it is excluded from the list.

e.g. 0x0a 8 .5 becomes 1.5", + inputType: "string", + outputType: "string", + args: [ + { + name: "Delimiter", + type: "option", + value: Arithmetic.DELIM_OPTIONS + } + ] + }, + "Multiply": { + module: "Default", + description: "Multiplies a list of numbers. If an item in the string is not a number it is excluded from the list.

e.g. 0x0a 8 .5 becomes 40", + inputType: "string", + outputType: "string", + args: [ + { + name: "Delimiter", + type: "option", + value: Arithmetic.DELIM_OPTIONS + } + ] + }, + "Divide": { + module: "Default", + description: "Divides a list of numbers. If an item in the string is not a number it is excluded from the list.

e.g. 0x0a 8 .5 becomes 2.5", + inputType: "string", + outputType: "string", + args: [ + { + name: "Delimiter", + type: "option", + value: Arithmetic.DELIM_OPTIONS + } + ] + }, + "Mean": { + module: "Default", + description: "Computes the mean (average) of a number list. If an item in the string is not a number it is excluded from the list.

e.g. 0x0a 8 .5 .5 becomes 4.75", + inputType: "string", + outputType: "string", + args: [ + { + name: "Delimiter", + type: "option", + value: Arithmetic.DELIM_OPTIONS + } + ] + }, + "Median": { + module: "Default", + description: "Computes the median of a number list. If an item in the string is not a number it is excluded from the list.

e.g. 0x0a 8 1 .5 becomes 4.5", + inputType: "string", + outputType: "string", + args: [ + { + name: "Delimiter", + type: "option", + value: Arithmetic.DELIM_OPTIONS + } + ] + }, + "Standard Deviation": { + module: "Default", + description: "Computes the standard deviation of a number list. If an item in the string is not a number it is excluded from the list.

e.g. 0x0a 8 .5 becomes 4.089281382128433", + inputType: "string", + outputType: "string", + args: [ + { + name: "Delimiter", + type: "option", + value: Arithmetic.DELIM_OPTIONS + } + ] + }, "From Hexdump": { module: "Default", description: "Attempts to convert a hexdump back into raw data. This operation supports many different hexdump variations, but probably not all. Make sure you verify that the data it gives you is correct before continuing analysis.", diff --git a/src/core/config/modules/Default.js b/src/core/config/modules/Default.js index a0e8bd2..4fb7688 100644 --- a/src/core/config/modules/Default.js +++ b/src/core/config/modules/Default.js @@ -1,4 +1,5 @@ import FlowControl from "../../FlowControl.js"; +import Arithmetic from "../../operations/Arithmetic.js"; import Base from "../../operations/Base.js"; import Base58 from "../../operations/Base58.js"; import Base64 from "../../operations/Base64.js"; @@ -159,6 +160,13 @@ OpModules.Default = { "Return": FlowControl.runReturn, "Comment": FlowControl.runComment, "PHP Deserialize": PHP.runDeserialize, + "Sum": Arithmetic.runSum, + "Subtract": Arithmetic.runSub, + "Multiply": Arithmetic.runMulti, + "Divide": Arithmetic.runDiv, + "Mean": Arithmetic.runMean, + "Median": Arithmetic.runMedian, + "Standard Deviation": Arithmetic.runStdDev, /* diff --git a/src/core/operations/Arithmetic.js b/src/core/operations/Arithmetic.js new file mode 100644 index 0000000..9b07f8a --- /dev/null +++ b/src/core/operations/Arithmetic.js @@ -0,0 +1,243 @@ +import Utils from "../Utils.js"; + +/** + * Math operations on numbers. + * + * @author bwhitn [brian.m.whitney@outlook.com] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + * + * @namespace + */ +const Arithmetic = { + + /** + * @constant + * @default + */ + DELIM_OPTIONS: ["Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF"], + + + /** + * Splits a string based on a delimiter and calculates the sum of numbers. + * + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + runSum: function(input, args) { + const val = Arithmetic._sum(Arithmetic._createNumArray(input, args[0])); + return typeof(val) === "number" ? val.toString() : ""; + }, + + + /** + * Splits a string based on a delimiter and subtracts all the numbers. + * + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + runSub: function(input, args) { + let val = Arithmetic._sub(Arithmetic._createNumArray(input, args[0])); + return typeof(val) === "number" ? val.toString() : ""; + }, + + + /** + * Splits a string based on a delimiter and multiplies the numbers. + * + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + runMulti: function(input, args) { + let val = Arithmetic._multi(Arithmetic._createNumArray(input, args[0])); + return typeof(val) === "number" ? val.toString() : ""; + }, + + + /** + * Splits a string based on a delimiter and divides the numbers. + * + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + runDiv: function(input, args) { + let val = Arithmetic._div(Arithmetic._createNumArray(input, args[0])); + return typeof(val) === "number" ? val.toString() : ""; + }, + + + /** + * Splits a string based on a delimiter and computes the mean (average). + * + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + runMean: function(input, args) { + let val = Arithmetic._mean(Arithmetic._createNumArray(input, args[0])); + return typeof(val) === "number" ? val.toString() : ""; + }, + + + /** + * Splits a string based on a delimiter and finds the median. + * + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + runMedian: function(input, args) { + let val = Arithmetic._median(Arithmetic._createNumArray(input, args[0])); + return typeof(val) === "number" ? val.toString() : ""; + }, + + + /** + * splits a string based on a delimiter and computes the standard deviation. + * + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + runStdDev: function(input, args) { + let val = Arithmetic._stdDev(Arithmetic._createNumArray(input, args[0])); + return typeof(val) === "number" ? val.toString() : ""; + }, + + + /** + * Converts a string array to a number array. + * + * @param {string[]} input + * @param {string} delim + * @returns {number[]} + */ + _createNumArray: function(input, delim) { + delim = Utils.charRep[delim || "Space"]; + let splitNumbers = input.split(delim), + numbers = [], + num; + for (let i = 0; i < splitNumbers.length; i++) { + if (splitNumbers[i].indexOf(".") >= 0) { + num = parseFloat(splitNumbers[i].trim()); + } else { + num = parseInt(splitNumbers[i].trim(), 0); + } + if (!isNaN(num)) { + numbers.push(num); + } + } + return numbers; + }, + + + /** + * Adds an array of numbers and returns the value. + * + * @private + * @param {number[]} data + * @returns {number} + */ + _sum: function(data) { + if (data.length > 0) { + return data.reduce((acc, curr) => acc + curr); + } + }, + + /** + * Subtracts an array of numbers and returns the value. + * + * @private + * @param {number[]} data + * @returns {number} + */ + _sub: function(data) { + if (data.length > 0) { + return data.reduce((acc, curr) => acc - curr); + } + }, + + /** + * Multiplies an array of numbers and returns the value. + * + * @private + * @param {number[]} data + * @returns {number} + */ + _multi: function(data) { + if (data.length > 0) { + return data.reduce((acc, curr) => acc * curr); + } + }, + + /** + * Divides an array of numbers and returns the value. + * + * @private + * @param {number[]} data + * @returns {number} + */ + _div: function(data) { + if (data.length > 0) { + return data.reduce((acc, curr) => acc / curr); + } + }, + + /** + * Computes mean of a number array and returns the value. + * + * @private + * @param {number[]} data + * @returns {number} + */ + _mean: function(data) { + if (data.length > 0) { + return Arithmetic._sum(data) / data.length; + } + }, + + /** + * Computes median of a number array and returns the value. + * + * @private + * @param {number[]} data + * @returns {number} + */ + _median: function (data) { + if ((data.length % 2) === 0) { + let first, second; + data.sort(function(a, b){ + return a - b; + }); + first = data[Math.floor(data.length / 2)]; + second = data[Math.floor(data.length / 2) - 1]; + return Arithmetic._mean([first, second]); + } else { + return data[Math.floor(data.length / 2)]; + } + }, + + /** + * Computes standard deviation of a number array and returns the value. + * + * @private + * @param {number[]} data + * @returns {number} + */ + _stdDev: function (data) { + if (data.length > 0) { + let avg = Arithmetic._mean(data); + let devSum = 0; + for (let i = 0; i < data.length; i++) { + devSum += (data[i] - avg) ** 2; + } + return Math.sqrt(devSum / data.length); + } + }, +}; + +export default Arithmetic;