diff --git a/src/core/FlowControl.js b/src/core/FlowControl.js
index e886be6c..5b7728ff 100755
--- a/src/core/FlowControl.js
+++ b/src/core/FlowControl.js
@@ -283,6 +283,18 @@ const FlowControl = {
Properties |
`;
+ /**
+ * Returns a CSS colour value based on an integer input.
+ *
+ * @param {number} val
+ * @returns {string}
+ */
+ function chooseColour(val) {
+ if (val < 3) return "green";
+ if (val < 5) return "goldenrod";
+ return "red";
+ }
+
options.forEach(option => {
// Construct recipe URL
// Replace this Magic op with the generated recipe
@@ -295,18 +307,20 @@ const FlowControl = {
fileType = "",
matchingOps = "",
useful = "",
- validUTF8 = option.isUTF8 ? "Valid UTF8\n" : "";
+ entropy = `Entropy: ${option.entropy.toFixed(2)}`,
+ validUTF8 = option.isUTF8 ? "Valid UTF8\n" : "";
if (option.languageScores[0].probability > 0) {
let likelyLangs = option.languageScores.filter(l => l.probability > 0);
if (likelyLangs.length < 1) likelyLangs = [option.languageScores[0]];
- language = "Possible languages:\n " + likelyLangs.map(lang => {
- return Magic.codeToLanguage(lang.lang);
- }).join("\n ") + "\n";
+ language = "" +
+ "Possible languages:\n " + likelyLangs.map(lang => {
+ return Magic.codeToLanguage(lang.lang);
+ }).join("\n ") + "\n";
}
if (option.fileType) {
- fileType = `File type: ${option.fileType.mime} (${option.fileType.ext})\n`;
+ fileType = `File type: ${option.fileType.mime} (${option.fileType.ext})\n`;
}
if (option.matchingOps.length) {
@@ -314,17 +328,17 @@ const FlowControl = {
}
if (option.useful) {
- useful = "Useful op detected\n";
+ useful = "Useful op detected\n";
}
output += `
${Utils.generatePrettyRecipe(option.recipe, true)} |
${Utils.escapeHtml(Utils.printable(Utils.truncate(option.data, 99)))} |
- ${language}${fileType}${matchingOps}${useful}${validUTF8} |
+ ${language}${fileType}${matchingOps}${useful}${validUTF8}${entropy} |
`;
});
- output += "";
+ output += "";
if (!options.length) {
output = "Nothing of interest could be detected about the input data.\nHave you tried modifying the operation arguments?";
diff --git a/src/core/lib/Magic.js b/src/core/lib/Magic.js
index 47dadb9e..868ad976 100644
--- a/src/core/lib/Magic.js
+++ b/src/core/lib/Magic.js
@@ -173,6 +173,24 @@ class Magic {
return true;
}
+ /**
+ * Calculates the Shannon entropy of the input data.
+ *
+ * @returns {number}
+ */
+ calcEntropy() {
+ let prob = this._freqDist(),
+ entropy = 0,
+ p;
+
+ for (let i = 0; i < prob.length; i++) {
+ p = prob[i] / 100;
+ if (p === 0) continue;
+ entropy += p * Math.log(p) / Math.log(2);
+ }
+ return -entropy;
+ }
+
/**
* Generate various simple brute-forced encodings of the data (trucated to 100 bytes).
*
@@ -262,6 +280,7 @@ class Magic {
languageScores: this.detectLanguage(extLang),
fileType: this.detectFileType(),
isUTF8: this.isUTF8(),
+ entropy: this.calcEntropy(),
matchingOps: matchingOps,
useful: useful
});
@@ -324,6 +343,10 @@ class Magic {
aScore += a.recipe.length;
bScore += b.recipe.length;
+ // Lower entropy is "better", so we add the entropy to the score
+ aScore += a.entropy;
+ bScore += b.entropy;
+
return aScore - bScore;
});
}
@@ -351,12 +374,14 @@ class Magic {
}
/**
- * Calculates the number of times each byte appears in the input
+ * Calculates the number of times each byte appears in the input as a percentage
*
* @private
* @returns {number[]}
*/
_freqDist() {
+ if (this.freqDist) return this.freqDist;
+
const len = this.inputBuffer.length;
let i = len,
counts = new Array(256).fill(0);
@@ -367,9 +392,10 @@ class Magic {
counts[this.inputBuffer[i]]++;
}
- return counts.map(c => {
+ this.freqDist = counts.map(c => {
return c / len * 100;
});
+ return this.freqDist;
}
/**