2018-05-16 12:39:30 +02:00
|
|
|
/**
|
|
|
|
* @author n1474335 [n1474335@gmail.com]
|
|
|
|
* @copyright Crown Copyright 2016
|
|
|
|
* @license Apache-2.0
|
|
|
|
*/
|
|
|
|
|
2019-07-09 13:23:59 +02:00
|
|
|
import Operation from "../Operation.mjs";
|
|
|
|
import Utils from "../Utils.mjs";
|
|
|
|
import OperationError from "../errors/OperationError.mjs";
|
2018-05-16 12:39:30 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Frequency distribution operation
|
|
|
|
*/
|
|
|
|
class FrequencyDistribution extends Operation {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* FrequencyDistribution constructor
|
|
|
|
*/
|
|
|
|
constructor() {
|
|
|
|
super();
|
|
|
|
|
|
|
|
this.name = "Frequency distribution";
|
|
|
|
this.module = "Default";
|
|
|
|
this.description = "Displays the distribution of bytes in the data as a graph.";
|
2018-08-21 20:07:13 +02:00
|
|
|
this.infoURL = "https://wikipedia.org/wiki/Frequency_distribution";
|
2018-05-16 12:39:30 +02:00
|
|
|
this.inputType = "ArrayBuffer";
|
|
|
|
this.outputType = "json";
|
|
|
|
this.presentType = "html";
|
|
|
|
this.args = [
|
|
|
|
{
|
|
|
|
"name": "Show 0%s",
|
|
|
|
"type": "boolean",
|
2020-04-16 09:59:43 +02:00
|
|
|
"value": true
|
2021-02-07 16:51:20 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"name": "Show ASCII",
|
|
|
|
"type": "boolean",
|
|
|
|
"value": true
|
2018-05-16 12:39:30 +02:00
|
|
|
}
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param {ArrayBuffer} input
|
|
|
|
* @param {Object[]} args
|
|
|
|
* @returns {json}
|
|
|
|
*/
|
|
|
|
run(input, args) {
|
|
|
|
const data = new Uint8Array(input);
|
|
|
|
if (!data.length) throw new OperationError("No data");
|
|
|
|
|
|
|
|
const distrib = new Array(256).fill(0),
|
|
|
|
percentages = new Array(256),
|
|
|
|
len = data.length;
|
|
|
|
let i;
|
|
|
|
|
|
|
|
// Count bytes
|
|
|
|
for (i = 0; i < len; i++) {
|
|
|
|
distrib[data[i]]++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate percentages
|
|
|
|
let repr = 0;
|
|
|
|
for (i = 0; i < 256; i++) {
|
|
|
|
if (distrib[i] > 0) repr++;
|
|
|
|
percentages[i] = distrib[i] / len * 100;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
"dataLength": len,
|
|
|
|
"percentages": percentages,
|
|
|
|
"distribution": distrib,
|
|
|
|
"bytesRepresented": repr
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Displays the frequency distribution as a bar chart for web apps.
|
|
|
|
*
|
|
|
|
* @param {json} freq
|
|
|
|
* @returns {html}
|
|
|
|
*/
|
|
|
|
present(freq, args) {
|
2021-02-09 15:46:04 +01:00
|
|
|
const [showZeroes, showAscii] = args;
|
|
|
|
|
2018-05-16 12:39:30 +02:00
|
|
|
// Print
|
|
|
|
let output = `<canvas id='chart-area'></canvas><br>
|
|
|
|
Total data length: ${freq.dataLength}
|
|
|
|
Number of bytes represented: ${freq.bytesRepresented}
|
|
|
|
Number of bytes not represented: ${256 - freq.bytesRepresented}
|
|
|
|
|
|
|
|
<script>
|
|
|
|
var canvas = document.getElementById("chart-area"),
|
2023-03-08 18:44:51 +01:00
|
|
|
parentRect = canvas.closest(".cm-scroller").getBoundingClientRect(),
|
2018-05-16 12:39:30 +02:00
|
|
|
scores = ${JSON.stringify(freq.percentages)};
|
|
|
|
|
|
|
|
canvas.width = parentRect.width * 0.95;
|
|
|
|
canvas.height = parentRect.height * 0.9;
|
|
|
|
|
|
|
|
CanvasComponents.drawBarChart(canvas, scores, "Byte", "Frequency %", 16, 6);
|
2021-02-09 15:46:04 +01:00
|
|
|
</script>
|
|
|
|
<table class="table table-hover table-sm">
|
|
|
|
<tr><th>Byte</th>${showAscii ? "<th>ASCII</th>" : ""}<th>Percentage</th><th></th></tr>`;
|
2018-05-16 12:39:30 +02:00
|
|
|
|
|
|
|
for (let i = 0; i < 256; i++) {
|
|
|
|
if (freq.distribution[i] || showZeroes) {
|
2021-02-09 15:46:04 +01:00
|
|
|
let c = "";
|
2021-02-07 16:51:20 +01:00
|
|
|
if (showAscii) {
|
|
|
|
if (i <= 32) {
|
|
|
|
c = String.fromCharCode(0x2400 + i);
|
|
|
|
} else if (i === 127) {
|
|
|
|
c = String.fromCharCode(0x2421);
|
|
|
|
} else {
|
|
|
|
c = String.fromCharCode(i);
|
|
|
|
}
|
|
|
|
}
|
2021-02-09 15:46:04 +01:00
|
|
|
const bite = `<td>${Utils.hex(i, 2)}</td>`,
|
|
|
|
ascii = showAscii ? `<td>${c}</td>` : "",
|
|
|
|
percentage = `<td>${(freq.percentages[i].toFixed(2).replace(".00", "") + "%").padEnd(8, " ")}</td>`,
|
|
|
|
bars = `<td>${Array(Math.ceil(freq.percentages[i])+1).join("|")}</td>`;
|
|
|
|
|
|
|
|
output += `<tr>${bite}${ascii}${percentage}${bars}</tr>`;
|
2018-05-16 12:39:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-09 15:46:04 +01:00
|
|
|
output += "</table>";
|
2018-05-16 12:39:30 +02:00
|
|
|
return output;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
export default FrequencyDistribution;
|