Przeglądaj źródła

Merge branch 'master' into feature-threading

n1474335 8 lat temu
rodzic
commit
e977a1006c
45 zmienionych plików z 2295 dodań i 1838 usunięć
  1. 3 0
      .eslintrc.json
  2. 206 181
      package-lock.json
  3. 17 17
      package.json
  4. 1 1
      src/core/Ingredient.js
  5. 4 4
      src/core/Recipe.js
  6. 69 95
      src/core/Utils.js
  7. 2 0
      src/core/config/Categories.js
  8. 81 12
      src/core/config/OperationConfig.js
  9. 214 0
      src/core/operations/BCD.js
  10. 18 18
      src/core/operations/Base64.js
  11. 14 14
      src/core/operations/BitwiseOp.js
  12. 35 35
      src/core/operations/Code.js
  13. 21 21
      src/core/operations/Compress.js
  14. 190 190
      src/core/operations/Convert.js
  15. 31 4
      src/core/operations/DateTime.js
  16. 512 511
      src/core/operations/HTML.js
  17. 23 23
      src/core/operations/HTTP.js
  18. 2 2
      src/core/operations/IP.js
  19. 4 4
      src/core/operations/JS.js
  20. 19 19
      src/core/operations/OS.js
  21. 519 539
      src/core/operations/PublicKey.js
  22. 7 7
      src/core/operations/QuotedPrintable.js
  23. 24 24
      src/core/operations/StrUtils.js
  24. 12 12
      src/core/operations/Tidy.js
  25. 1 1
      src/core/operations/URL.js
  26. 6 6
      src/node/index.js
  27. 33 20
      src/web/App.js
  28. 6 6
      src/web/ControlsWaiter.js
  29. 8 7
      src/web/HighlighterWaiter.js
  30. 1 1
      src/web/InputWaiter.js
  31. 1 0
      src/web/Manager.js
  32. 11 0
      src/web/OutputWaiter.js
  33. 45 32
      src/web/html/index.html
  34. 9 9
      src/web/index.js
  35. 23 0
      src/web/static/structuredData.json
  36. 1 0
      src/web/stylesheets/components/_operation.css
  37. 2 6
      src/web/stylesheets/layout/_banner.css
  38. 1 2
      test/TestRegister.js
  39. 1 0
      test/index.js
  40. 103 0
      test/tests/operations/BCD.js
  41. 4 4
      test/tests/operations/Compress.js
  42. 2 2
      test/tests/operations/DateTime.js
  43. 5 5
      test/tests/operations/FlowControl.js
  44. 3 3
      test/tests/operations/Image.js
  45. 1 1
      test/tests/operations/StrUtils.js

+ 3 - 0
.eslintrc.json

@@ -52,6 +52,9 @@
         "no-trailing-spaces": "warn",
         "no-trailing-spaces": "warn",
         "eol-last": "error",
         "eol-last": "error",
         "func-call-spacing": "error",
         "func-call-spacing": "error",
+        "key-spacing": ["warn", {
+            "mode": "minimum"
+        }],
         "indent": ["error", 4, {
         "indent": ["error", 4, {
             "ArrayExpression": "first",
             "ArrayExpression": "first",
             "SwitchCase": 1
             "SwitchCase": 1

Plik diff jest za duży
+ 206 - 181
package-lock.json


+ 17 - 17
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "cyberchef",
   "name": "cyberchef",
-  "version": "5.11.0",
+  "version": "5.12.2",
   "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
   "description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
   "author": "n1474335 <n1474335@gmail.com>",
   "author": "n1474335 <n1474335@gmail.com>",
   "homepage": "https://gchq.github.io/CyberChef",
   "homepage": "https://gchq.github.io/CyberChef",
@@ -31,39 +31,39 @@
   "bugs": "https://github.com/gchq/CyberChef/issues",
   "bugs": "https://github.com/gchq/CyberChef/issues",
   "devDependencies": {
   "devDependencies": {
     "babel-core": "^6.24.0",
     "babel-core": "^6.24.0",
-    "babel-loader": "^6.4.0",
+    "babel-loader": "^7.1.1",
     "babel-polyfill": "^6.23.0",
     "babel-polyfill": "^6.23.0",
     "babel-preset-env": "^1.6.0",
     "babel-preset-env": "^1.6.0",
     "babel-regenerator-runtime": "^6.5.0",
     "babel-regenerator-runtime": "^6.5.0",
-    "css-loader": "^0.27.3",
+    "css-loader": "^0.28.4",
     "exports-loader": "^0.6.4",
     "exports-loader": "^0.6.4",
-    "extract-text-webpack-plugin": "^2.1.0",
-    "file-loader": "^0.10.1",
+    "extract-text-webpack-plugin": "^3.0.0",
+    "file-loader": "^0.11.2",
     "grunt": ">=0.4.5",
     "grunt": ">=0.4.5",
     "grunt-accessibility": "~5.0.0",
     "grunt-accessibility": "~5.0.0",
     "grunt-chmod": "~1.1.1",
     "grunt-chmod": "~1.1.1",
-    "grunt-contrib-clean": "~1.0.0",
+    "grunt-contrib-clean": "~1.1.0",
     "grunt-contrib-copy": "~1.0.0",
     "grunt-contrib-copy": "~1.0.0",
-    "grunt-eslint": "^19.0.0",
-    "grunt-exec": "~1.0.1",
+    "grunt-eslint": "^20.0.0",
+    "grunt-exec": "~2.0.0",
     "grunt-execute": "^0.2.2",
     "grunt-execute": "^0.2.2",
     "grunt-jsdoc": "^2.1.0",
     "grunt-jsdoc": "^2.1.0",
-    "grunt-webpack": "^2.0.1",
+    "grunt-webpack": "^3.0.2",
     "html-webpack-plugin": "^2.29.0",
     "html-webpack-plugin": "^2.29.0",
     "imports-loader": "^0.7.1",
     "imports-loader": "^0.7.1",
     "ink-docstrap": "^1.1.4",
     "ink-docstrap": "^1.1.4",
     "jsdoc-babel": "^0.3.0",
     "jsdoc-babel": "^0.3.0",
     "less": "^2.7.2",
     "less": "^2.7.2",
-    "less-loader": "^4.0.3",
+    "less-loader": "^4.0.5",
     "postcss-css-variables": "^0.7.0",
     "postcss-css-variables": "^0.7.0",
     "postcss-import": "^10.0.0",
     "postcss-import": "^10.0.0",
     "postcss-loader": "^2.0.5",
     "postcss-loader": "^2.0.5",
-    "style-loader": "^0.15.0",
+    "style-loader": "^0.18.2",
     "url-loader": "^0.5.8",
     "url-loader": "^0.5.8",
     "value-loader": "^0.1.3",
     "value-loader": "^0.1.3",
     "web-resource-inliner": "^4.1.0",
     "web-resource-inliner": "^4.1.0",
-    "webpack": "^2.2.1",
     "webpack-dev-server": "^2.5.0",
     "webpack-dev-server": "^2.5.0",
+    "webpack": "^3.3.0",
     "worker-loader": "^0.8.0"
     "worker-loader": "^0.8.0"
   },
   },
   "dependencies": {
   "dependencies": {
@@ -72,15 +72,15 @@
     "bootstrap-switch": "^3.3.4",
     "bootstrap-switch": "^3.3.4",
     "crypto-api": "^0.6.2",
     "crypto-api": "^0.6.2",
     "crypto-js": "^3.1.9-1",
     "crypto-js": "^3.1.9-1",
-    "diff": "^3.2.0",
+    "diff": "^3.3.0",
     "escodegen": "^1.8.1",
     "escodegen": "^1.8.1",
     "esmangle": "^1.0.1",
     "esmangle": "^1.0.1",
-    "esprima": "^3.1.3",
-    "exif-parser": "^0.1.9",
+    "esprima": "^4.0.0",
+    "exif-parser": "^0.1.12",
     "google-code-prettify": "^1.0.5",
     "google-code-prettify": "^1.0.5",
     "jquery": "^3.1.1",
     "jquery": "^3.1.1",
     "jsbn": "^1.1.0",
     "jsbn": "^1.1.0",
-    "jsrsasign": "7.1.3",
+    "jsrsasign": "8.0.3",
     "lodash": "^4.17.4",
     "lodash": "^4.17.4",
     "moment": "^2.17.1",
     "moment": "^2.17.1",
     "moment-timezone": "^0.5.11",
     "moment-timezone": "^0.5.11",
@@ -90,7 +90,7 @@
     "vkbeautify": "^0.99.1",
     "vkbeautify": "^0.99.1",
     "xmldom": "^0.1.27",
     "xmldom": "^0.1.27",
     "xpath": "0.0.24",
     "xpath": "0.0.24",
-    "zlibjs": "^0.2.0"
+    "zlibjs": "^0.3.1"
   },
   },
   "scripts": {
   "scripts": {
     "start": "grunt dev",
     "start": "grunt dev",

+ 1 - 1
src/core/Ingredient.js

@@ -73,7 +73,7 @@ Ingredient.prepare = function(data, type) {
         case "byteArray":
         case "byteArray":
             if (typeof data == "string") {
             if (typeof data == "string") {
                 data = data.replace(/\s+/g, "");
                 data = data.replace(/\s+/g, "");
-                return Utils.hexToByteArray(data);
+                return Utils.fromHex(data);
             } else {
             } else {
                 return data;
                 return data;
             }
             }

+ 4 - 4
src/core/Recipe.js

@@ -164,10 +164,10 @@ Recipe.prototype.execute = async function(dish, startFrom) {
             if (op.isFlowControl()) {
             if (op.isFlowControl()) {
                 // Package up the current state
                 // Package up the current state
                 let state = {
                 let state = {
-                    "progress" : i,
-                    "dish"     : dish,
-                    "opList"  : this.opList,
-                    "numJumps" : numJumps
+                    "progress": i,
+                    "dish":     dish,
+                    "opList":   this.opList,
+                    "numJumps": numJumps
                 };
                 };
 
 
                 state = await op.run(state);
                 state = await op.run(state);

+ 69 - 95
src/core/Utils.js

@@ -293,7 +293,7 @@ const Utils = {
      * Utils.escapeRegex("[example]");
      * Utils.escapeRegex("[example]");
      */
      */
     escapeRegex: function(str) {
     escapeRegex: function(str) {
-        return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
+        return str.replace(/([.*+?^=!:${}()|[\]/\\])/g, "\\$1");
     },
     },
 
 
 
 
@@ -340,50 +340,6 @@ const Utils = {
     },
     },
 
 
 
 
-    /**
-     * Translates a hex string into an array of bytes.
-     *
-     * @param {string} hexStr
-     * @returns {byteArray}
-     *
-     * @example
-     * // returns [0xfe, 0x09, 0xa7]
-     * Utils.hexToByteArray("fe09a7");
-     */
-    hexToByteArray: function(hexStr) {
-        // TODO: Handle errors i.e. input string is not hex
-        if (!hexStr) return [];
-        hexStr = hexStr.replace(/\s+/g, "");
-        const byteArray = [];
-        for (let i = 0; i < hexStr.length; i += 2) {
-            byteArray.push(parseInt(hexStr.substr(i, 2), 16));
-        }
-        return byteArray;
-    },
-
-
-    /**
-     * Translates an array of bytes to a hex string.
-     *
-     * @param {byteArray} byteArray
-     * @param {string} [delim=" "]
-     * @returns {string}
-     *
-     * @example
-     * // returns "fe09a7"
-     * Utils.byteArrayToHex([0xfe, 0x09, 0xa7], "");
-     */
-    byteArrayToHex: function(byteArray, delim) {
-        if (!byteArray) return "";
-        delim = typeof delim === "undefined" ? " " : delim;
-        let hexStr = "";
-        for (let i = 0; i < byteArray.length; i++) {
-            hexStr += Utils.hex(byteArray[i]) + delim;
-        }
-        return hexStr.slice(0, hexStr.length - delim.length);
-    },
-
-
     /**
     /**
      * Converts a string to a byte array.
      * Converts a string to a byte array.
      * Treats the string as UTF-8 if any values are over 255.
      * Treats the string as UTF-8 if any values are over 255.
@@ -636,7 +592,7 @@ const Utils = {
             i = 0;
             i = 0;
 
 
         if (removeNonAlphChars) {
         if (removeNonAlphChars) {
-            const re = new RegExp("[^" + alphabet.replace(/[\[\]\\\-^$]/g, "\\$&") + "]", "g");
+            const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
             data = data.replace(re, "");
             data = data.replace(re, "");
         }
         }
 
 
@@ -828,7 +784,7 @@ const Utils = {
         if (removeScriptAndStyle) {
         if (removeScriptAndStyle) {
             htmlStr = htmlStr.replace(/<(script|style)[^>]*>.*<\/(script|style)>/gmi, "");
             htmlStr = htmlStr.replace(/<(script|style)[^>]*>.*<\/(script|style)>/gmi, "");
         }
         }
-        return htmlStr.replace(/<[^>\n]+>/g, "");
+        return htmlStr.replace(/<[^>]+>/g, "");
     },
     },
 
 
 
 
@@ -854,7 +810,7 @@ const Utils = {
             "`": "&#x60;"
             "`": "&#x60;"
         };
         };
 
 
-        return str.replace(/[&<>"'\/`]/g, function (match) {
+        return str.replace(/[&<>"'/`]/g, function (match) {
             return HTML_CHARS[match];
             return HTML_CHARS[match];
         });
         });
     },
     },
@@ -946,16 +902,19 @@ const Utils = {
      * @returns {html}
      * @returns {html}
      */
      */
     displayFilesAsHTML: function(files) {
     displayFilesAsHTML: function(files) {
+        /* <NL> and <SP> used to denote newlines and spaces in HTML markup.
+         * If a non-html operation is used, all markup will be removed but these
+         * whitespace chars will remain for formatting purposes.
+         */
+
         const formatDirectory = function(file) {
         const formatDirectory = function(file) {
-            const html = "<div class='panel panel-default'>" +
-                   "<div class='panel-heading' role='tab'>" +
-                   "<h4 class='panel-title'>" +
-                   Utils.escapeHtml(file.fileName) +
-                   // The following line is for formatting when HTML is stripped
-                   "<span style='display: none'>\n0 bytes\n</span>" +
-                   "</h4>" +
-                   "</div>" +
-                   "</div>";
+            const html = `<div class='panel panel-default' style='white-space: normal;'>
+                    <div class='panel-heading' role='tab'>
+                        <h4 class='panel-title'>
+                            <NL>${Utils.escapeHtml(file.fileName)}
+                        </h4>
+                    </div>
+                </div>`;
             return html;
             return html;
         };
         };
 
 
@@ -966,45 +925,52 @@ const Utils = {
             );
             );
             const blobUrl = URL.createObjectURL(blob);
             const blobUrl = URL.createObjectURL(blob);
 
 
-            const downloadAnchorElem = "<a href='" + blobUrl + "' " +
-                "title='Download " + Utils.escapeHtml(file.fileName) + "' " +
-                "download='" + Utils.escapeHtml(file.fileName) + "'>\u21B4</a>";
-
-            const expandFileContentsElem = "<a href='#collapse" + i + "' " +
-                "class='collapsed' " +
-                "data-toggle='collapse' " +
-                "aria-expanded='true' " +
-                "aria-controls='collapse" + i + "' " +
-                "title=\"Show/hide contents of '" + Utils.escapeHtml(file.fileName) + "'\">&#x1F50D</a>";
-
-            const html = "<div class='panel panel-default'>" +
-                       "<div class='panel-heading' role='tab' id='heading" + i + "'>" +
-                       "<h4 class='panel-title'>" +
-                       "<div>" +
-                       Utils.escapeHtml(file.fileName) +
-                       " " +  expandFileContentsElem +
-                       " " + downloadAnchorElem +
-                       "<span class='pull-right'>" +
-                       // These are for formatting when stripping HTML
-                       "<span style='display: none'>\n</span>" +
-                       file.size.toLocaleString() + " bytes" +
-                       "<span style='display: none'>\n</span>" +
-                       "</span>" +
-                       "</div>" +
-                       "</h4>" +
-                       "</div>" +
-                       "<div id='collapse" + i + "' class='panel-collapse collapse' " +
-                       "role='tabpanel' aria-labelledby='heading" + i + "'>" +
-                       "<div class='panel-body'>" +
-                       "<pre><code>" + Utils.escapeHtml(file.contents) + "</pre></code></div>" +
-                       "</div>" +
-                       "</div>";
+            const viewFileElem = `<a href='#collapse${i}'
+                class='collapsed'
+                data-toggle='collapse'
+                aria-expanded='true'
+                aria-controls='collapse${i}'
+                title="Show/hide contents of '${Utils.escapeHtml(file.fileName)}'">&#x1f441;&#xfe0f;</a>`;
+
+            const downloadFileElem = `<a href='${blobUrl}'
+                title='Download ${Utils.escapeHtml(file.fileName)}'
+                download='${Utils.escapeHtml(file.fileName)}'>&#x1f4be;</a>`;
+
+            const hexFileData = Utils.toHexFast(new Uint8Array(file.bytes));
+
+            const switchToInputElem = `<a href='#switchFileToInput${i}'
+                class='file-switch'
+                title='Move file to input as hex'
+                fileValue='${hexFileData}'>&#x21e7;</a>`;
+
+            const html = `<div class='panel panel-default' style='white-space: normal;'>
+                    <div class='panel-heading' role='tab' id='heading${i}'>
+                        <h4 class='panel-title'>
+                            <div>
+                                ${Utils.escapeHtml(file.fileName)}<NL>
+                                ${viewFileElem}<SP>
+                                ${downloadFileElem}<SP>
+                                ${switchToInputElem}<SP>
+                                <span class='pull-right'>
+                                    <NL>${file.size.toLocaleString()} bytes
+                                </span>
+                            </div>
+                        </h4>
+                    </div>
+                    <div id='collapse${i}' class='panel-collapse collapse'
+                        role='tabpanel' aria-labelledby='heading${i}'>
+                        <div class='panel-body'>
+                            <NL><NL><pre><code>${Utils.escapeHtml(file.contents)}</code></pre>
+                        </div>
+                    </div>
+                </div>`;
             return html;
             return html;
         };
         };
 
 
-        let html = "<div style='padding: 5px;'>" +
-                   files.length +
-                   " file(s) found</div>\n";
+        let html = `<div style='padding: 5px; white-space: normal;'>
+                ${files.length} file(s) found<NL>
+            </div>`;
+
         files.forEach(function(file, i) {
         files.forEach(function(file, i) {
             if (typeof file.contents !== "undefined") {
             if (typeof file.contents !== "undefined") {
                 html += formatFile(file, i);
                 html += formatFile(file, i);
@@ -1012,7 +978,10 @@ const Utils = {
                 html += formatDirectory(file);
                 html += formatDirectory(file);
             }
             }
         });
         });
-        return html;
+
+        return html.replace(/(?:(<pre>(?:\n|.)*<\/pre>)|\s{2,})/g, "$1") // Remove whitespace from markup
+            .replace(/<NL>/g, "\n") // Replace <NP> with newlines
+            .replace(/<SP>/g, " "); // Replace <SP> with spaces
     },
     },
 
 
 
 
@@ -1031,9 +1000,14 @@ const Utils = {
         if (paramStr === "") return {};
         if (paramStr === "") return {};
 
 
         // Cut off ? or # and split on &
         // Cut off ? or # and split on &
-        const params = paramStr.substr(1).split("&");
+        if (paramStr[0] === "?" ||
+            paramStr[0] === "#") {
+            paramStr = paramStr.substr(1);
+        }
 
 
+        const params = paramStr.split("&");
         const result = {};
         const result = {};
+
         for (let i = 0; i < params.length; i++) {
         for (let i = 0; i < params.length; i++) {
             const param = params[i].split("=");
             const param = params[i].split("=");
             if (param.length !== 2) {
             if (param.length !== 2) {

+ 2 - 0
src/core/config/Categories.js

@@ -46,6 +46,8 @@ const Categories = [
             "From Base58",
             "From Base58",
             "To Base",
             "To Base",
             "From Base",
             "From Base",
+            "To BCD",
+            "From BCD",
             "To HTML Entity",
             "To HTML Entity",
             "From HTML Entity",
             "From HTML Entity",
             "URL Encode",
             "URL Encode",

+ 81 - 12
src/core/config/OperationConfig.js

@@ -2,6 +2,7 @@ import FlowControl from "../FlowControl.js";
 import Base from "../operations/Base.js";
 import Base from "../operations/Base.js";
 import Base58 from "../operations/Base58.js";
 import Base58 from "../operations/Base58.js";
 import Base64 from "../operations/Base64.js";
 import Base64 from "../operations/Base64.js";
+import BCD from "../operations/BCD.js";
 import BitwiseOp from "../operations/BitwiseOp.js";
 import BitwiseOp from "../operations/BitwiseOp.js";
 import ByteRepr from "../operations/ByteRepr.js";
 import ByteRepr from "../operations/ByteRepr.js";
 import CharEnc from "../operations/CharEnc.js";
 import CharEnc from "../operations/CharEnc.js";
@@ -330,29 +331,24 @@ const OperationConfig = {
                 value: BitwiseOp.XOR_BRUTE_KEY_LENGTH
                 value: BitwiseOp.XOR_BRUTE_KEY_LENGTH
             },
             },
             {
             {
-                name: "Length of sample",
+                name: "Sample length",
                 type: "number",
                 type: "number",
                 value: BitwiseOp.XOR_BRUTE_SAMPLE_LENGTH
                 value: BitwiseOp.XOR_BRUTE_SAMPLE_LENGTH
             },
             },
             {
             {
-                name: "Offset of sample",
+                name: "Sample offset",
                 type: "number",
                 type: "number",
                 value: BitwiseOp.XOR_BRUTE_SAMPLE_OFFSET
                 value: BitwiseOp.XOR_BRUTE_SAMPLE_OFFSET
             },
             },
             {
             {
-                name: "Null preserving",
-                type: "boolean",
-                value: BitwiseOp.XOR_PRESERVE_NULLS
+                name: "Scheme",
+                type: "option",
+                value: BitwiseOp.XOR_SCHEME
             },
             },
             {
             {
-                name: "Differential",
+                name: "Null preserving",
                 type: "boolean",
                 type: "boolean",
-                value: BitwiseOp.XOR_DIFFERENTIAL
-            },
-            {
-                name: "Crib (known plaintext string)",
-                type: "binaryString",
-                value: ""
+                value: BitwiseOp.XOR_PRESERVE_NULLS
             },
             },
             {
             {
                 name: "Print key",
                 name: "Print key",
@@ -363,6 +359,11 @@ const OperationConfig = {
                 name: "Output as hex",
                 name: "Output as hex",
                 type: "boolean",
                 type: "boolean",
                 value: BitwiseOp.XOR_BRUTE_OUTPUT_HEX
                 value: BitwiseOp.XOR_BRUTE_OUTPUT_HEX
+            },
+            {
+                name: "Crib (known plaintext string)",
+                type: "binaryString",
+                value: ""
             }
             }
         ]
         ]
     },
     },
@@ -2301,6 +2302,11 @@ const OperationConfig = {
                 name: "Output units",
                 name: "Output units",
                 type: "option",
                 type: "option",
                 value: DateTime.UNITS
                 value: DateTime.UNITS
+            },
+            {
+                name: "Input format",
+                type: "option",
+                value: DateTime.FILETIME_FORMATS
             }
             }
         ]
         ]
     },
     },
@@ -2314,6 +2320,11 @@ const OperationConfig = {
                 name: "Input units",
                 name: "Input units",
                 type: "option",
                 type: "option",
                 value: DateTime.UNITS
                 value: DateTime.UNITS
+            },
+            {
+                name: "Output format",
+                type: "option",
+                value: DateTime.FILETIME_FORMATS
             }
             }
         ]
         ]
     },
     },
@@ -3497,6 +3508,64 @@ const OperationConfig = {
             }
             }
         ]
         ]
     },
     },
+    "From BCD": {
+        description: "Binary-Coded Decimal (BCD) is a class of binary encodings of decimal numbers where each decimal digit is represented by a fixed number of bits, usually four or eight. Special bit patterns are sometimes used for a sign.",
+        run: BCD.runFromBCD,
+        inputType: "string",
+        outputType: "number",
+        args: [
+            {
+                name: "Scheme",
+                type: "option",
+                value: BCD.ENCODING_SCHEME
+            },
+            {
+                name: "Packed",
+                type: "boolean",
+                value: true
+            },
+            {
+                name: "Signed",
+                type: "boolean",
+                value: false
+            },
+            {
+                name: "Input format",
+                type: "option",
+                value: BCD.FORMAT
+            }
+        ]
+
+    },
+    "To BCD": {
+        description: "Binary-Coded Decimal (BCD) is a class of binary encodings of decimal numbers where each decimal digit is represented by a fixed number of bits, usually four or eight. Special bit patterns are sometimes used for a sign",
+        run: BCD.runToBCD,
+        inputType: "number",
+        outputType: "string",
+        args: [
+            {
+                name: "Scheme",
+                type: "option",
+                value: BCD.ENCODING_SCHEME
+            },
+            {
+                name: "Packed",
+                type: "boolean",
+                value: true
+            },
+            {
+                name: "Signed",
+                type: "boolean",
+                value: false
+            },
+            {
+                name: "Output format",
+                type: "option",
+                value: BCD.FORMAT
+            }
+        ]
+
+    },
 };
 };
 
 
 export default OperationConfig;
 export default OperationConfig;

+ 214 - 0
src/core/operations/BCD.js

@@ -0,0 +1,214 @@
+import Utils from "../Utils.js";
+
+
+/**
+ * Binary-Coded Decimal operations.
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ *
+ * @namespace
+ */
+const BCD = {
+
+    /**
+     * @constant
+     * @default
+     */
+    ENCODING_SCHEME: [
+        "8 4 2 1",
+        "7 4 2 1",
+        "4 2 2 1",
+        "2 4 2 1",
+        "8 4 -2 -1",
+        "Excess-3",
+        "IBM 8 4 2 1",
+    ],
+
+    /**
+     * Lookup table for the binary value of each digit representation.
+     *
+     * I wrote a very nice algorithm to generate 8 4 2 1 encoding programatically,
+     * but unfortunately it's much easier (if less elegant) to use lookup tables
+     * when supporting multiple encoding schemes.
+     *
+     * "Practicality beats purity" - PEP 20
+     *
+     * In some schemes it is possible to represent the same value in multiple ways.
+     * For instance, in 4 2 2 1 encoding, 0100 and 0010 both represent 2. Support
+     * has not yet been added for this.
+     *
+     * @constant
+     */
+    ENCODING_LOOKUP: {
+        "8 4 2 1":     [0,  1,  2,  3,  4,  5,  6,  7,  8,  9],
+        "7 4 2 1":     [0,  1,  2,  3,  4,  5,  6,  8,  9,  10],
+        "4 2 2 1":     [0,  1,  4,  5,  8,  9,  12, 13, 14, 15],
+        "2 4 2 1":     [0,  1,  2,  3,  4,  11, 12, 13, 14, 15],
+        "8 4 -2 -1":   [0,  7,  6,  5,  4,  11, 10, 9,  8,  15],
+        "Excess-3":    [3,  4,  5,  6,  7,  8,  9,  10, 11, 12],
+        "IBM 8 4 2 1": [10, 1,  2,  3,  4,  5,  6,  7,  8,  9],
+    },
+
+    /**
+     * @default
+     * @constant
+     */
+    FORMAT: ["Nibbles", "Bytes", "Raw"],
+
+
+    /**
+     * To BCD operation.
+     *
+     * @param {number} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    runToBCD: function(input, args) {
+        if (isNaN(input))
+            return "Invalid input";
+        if (Math.floor(input) !== input)
+            return "Fractional values are not supported by BCD";
+
+        const encoding = BCD.ENCODING_LOOKUP[args[0]],
+            packed = args[1],
+            signed = args[2],
+            outputFormat = args[3];
+
+        // Split input number up into separate digits
+        const digits = input.toString().split("");
+
+        if (digits[0] === "-" || digits[0] === "+") {
+            digits.shift();
+        }
+
+        let nibbles = [];
+
+        digits.forEach(d => {
+            const n = parseInt(d, 10);
+            nibbles.push(encoding[n]);
+        });
+
+        if (signed) {
+            if (packed && digits.length % 2 === 0) {
+                // If there are an even number of digits, we add a leading 0 so
+                // that the sign nibble doesn't sit in its own byte, leading to
+                // ambiguity around whether the number ends with a 0 or not.
+                nibbles.unshift(encoding[0]);
+            }
+
+            nibbles.push(input > 0 ? 12 : 13);
+            // 12 ("C") for + (credit)
+            // 13 ("D") for - (debit)
+        }
+
+        let bytes = [];
+
+        if (packed) {
+            let encoded = 0,
+                little = false;
+
+            nibbles.forEach(n => {
+                encoded ^= little ? n : (n << 4);
+                if (little) {
+                    bytes.push(encoded);
+                    encoded = 0;
+                }
+                little = !little;
+            });
+
+            if (little) bytes.push(encoded);
+        } else {
+            bytes = nibbles;
+
+            // Add null high nibbles
+            nibbles = nibbles.map(n => {
+                return [0, n];
+            }).reduce((a, b) => {
+                return a.concat(b);
+            });
+        }
+
+        // Output
+        switch (outputFormat) {
+            case "Nibbles":
+                return nibbles.map(n => {
+                    return Utils.padLeft(n.toString(2), 4);
+                }).join(" ");
+            case "Bytes":
+                return bytes.map(b => {
+                    return Utils.padLeft(b.toString(2), 8);
+                }).join(" ");
+            case "Raw":
+            default:
+                return Utils.byteArrayToChars(bytes);
+        }
+    },
+
+
+    /**
+     * From BCD operation.
+     *
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {number}
+     */
+    runFromBCD: function(input, args) {
+        const encoding = BCD.ENCODING_LOOKUP[args[0]],
+            packed = args[1],
+            signed = args[2],
+            inputFormat = args[3];
+
+        let nibbles = [],
+            output = "",
+            byteArray;
+
+        // Normalise the input
+        switch (inputFormat) {
+            case "Nibbles":
+            case "Bytes":
+                input = input.replace(/\s/g, "");
+                for (let i = 0; i < input.length; i += 4) {
+                    nibbles.push(parseInt(input.substr(i, 4), 2));
+                }
+                break;
+            case "Raw":
+            default:
+                byteArray = Utils.strToByteArray(input);
+                byteArray.forEach(b => {
+                    nibbles.push(b >>> 4);
+                    nibbles.push(b & 15);
+                });
+                break;
+        }
+
+        if (!packed) {
+            // Discard each high nibble
+            for (let i = 0; i < nibbles.length; i++) {
+                nibbles.splice(i, 1);
+            }
+        }
+
+        if (signed) {
+            const sign = nibbles.pop();
+            if (sign === 13 ||
+                sign === 11) {
+                // Negative
+                output += "-";
+            }
+        }
+
+        nibbles.forEach(n => {
+            if (isNaN(n)) throw "Invalid input";
+            let val = encoding.indexOf(n);
+            if (val < 0) throw `Value ${Utils.bin(n, 4)} not in encoding scheme`;
+            output += val.toString();
+        });
+
+        return parseInt(output, 10);
+    },
+
+};
+
+export default BCD;

+ 18 - 18
src/core/operations/Base64.js

@@ -221,15 +221,15 @@ const Base64 = {
             offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
             offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
                 Utils.escapeHtml(Utils.fromBase64(staticSection, alphabet).slice(0, -2)) + "'>" +
                 Utils.escapeHtml(Utils.fromBase64(staticSection, alphabet).slice(0, -2)) + "'>" +
                 staticSection + "</span>" +
                 staticSection + "</span>" +
-                "<span class='hlgreen'>" + offset0.substr(offset0.length - 3, 1) + "</span>" +
-                "<span class='hlred'>" + offset0.substr(offset0.length - 2) + "</span>";
+                "<span class='hl5'>" + offset0.substr(offset0.length - 3, 1) + "</span>" +
+                "<span class='hl3'>" + offset0.substr(offset0.length - 2) + "</span>";
         } else if (len0 % 4 === 3) {
         } else if (len0 % 4 === 3) {
             staticSection = offset0.slice(0, -2);
             staticSection = offset0.slice(0, -2);
             offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
             offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
                 Utils.escapeHtml(Utils.fromBase64(staticSection, alphabet).slice(0, -1)) + "'>" +
                 Utils.escapeHtml(Utils.fromBase64(staticSection, alphabet).slice(0, -1)) + "'>" +
                 staticSection + "</span>" +
                 staticSection + "</span>" +
-                "<span class='hlgreen'>" + offset0.substr(offset0.length - 2, 1) + "</span>" +
-                "<span class='hlred'>" + offset0.substr(offset0.length - 1) + "</span>";
+                "<span class='hl5'>" + offset0.substr(offset0.length - 2, 1) + "</span>" +
+                "<span class='hl3'>" + offset0.substr(offset0.length - 1) + "</span>";
         } else {
         } else {
             staticSection = offset0;
             staticSection = offset0;
             offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
             offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
@@ -243,23 +243,23 @@ const Base64 = {
 
 
 
 
         // Highlight offset 1
         // Highlight offset 1
-        padding = "<span class='hlred'>" + offset1.substr(0, 1) + "</span>" +
-            "<span class='hlgreen'>" + offset1.substr(1, 1) + "</span>";
+        padding = "<span class='hl3'>" + offset1.substr(0, 1) + "</span>" +
+            "<span class='hl5'>" + offset1.substr(1, 1) + "</span>";
         offset1 = offset1.substr(2);
         offset1 = offset1.substr(2);
         if (len1 % 4 === 2) {
         if (len1 % 4 === 2) {
             staticSection = offset1.slice(0, -3);
             staticSection = offset1.slice(0, -3);
             offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
             offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
                 Utils.escapeHtml(Utils.fromBase64("AA" + staticSection, alphabet).slice(1, -2)) + "'>" +
                 Utils.escapeHtml(Utils.fromBase64("AA" + staticSection, alphabet).slice(1, -2)) + "'>" +
                 staticSection + "</span>" +
                 staticSection + "</span>" +
-                "<span class='hlgreen'>" + offset1.substr(offset1.length - 3, 1) + "</span>" +
-                "<span class='hlred'>" + offset1.substr(offset1.length - 2) + "</span>";
+                "<span class='hl5'>" + offset1.substr(offset1.length - 3, 1) + "</span>" +
+                "<span class='hl3'>" + offset1.substr(offset1.length - 2) + "</span>";
         } else if (len1 % 4 === 3) {
         } else if (len1 % 4 === 3) {
             staticSection = offset1.slice(0, -2);
             staticSection = offset1.slice(0, -2);
             offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
             offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
                 Utils.escapeHtml(Utils.fromBase64("AA" + staticSection, alphabet).slice(1, -1)) + "'>" +
                 Utils.escapeHtml(Utils.fromBase64("AA" + staticSection, alphabet).slice(1, -1)) + "'>" +
                 staticSection + "</span>" +
                 staticSection + "</span>" +
-                "<span class='hlgreen'>" + offset1.substr(offset1.length - 2, 1) + "</span>" +
-                "<span class='hlred'>" + offset1.substr(offset1.length - 1) + "</span>";
+                "<span class='hl5'>" + offset1.substr(offset1.length - 2, 1) + "</span>" +
+                "<span class='hl3'>" + offset1.substr(offset1.length - 1) + "</span>";
         } else {
         } else {
             staticSection = offset1;
             staticSection = offset1;
             offset1 = padding +  "<span data-toggle='tooltip' data-placement='top' title='" +
             offset1 = padding +  "<span data-toggle='tooltip' data-placement='top' title='" +
@@ -272,23 +272,23 @@ const Base64 = {
         }
         }
 
 
         // Highlight offset 2
         // Highlight offset 2
-        padding = "<span class='hlred'>" + offset2.substr(0, 2) + "</span>" +
-            "<span class='hlgreen'>" + offset2.substr(2, 1) + "</span>";
+        padding = "<span class='hl3'>" + offset2.substr(0, 2) + "</span>" +
+            "<span class='hl5'>" + offset2.substr(2, 1) + "</span>";
         offset2 = offset2.substr(3);
         offset2 = offset2.substr(3);
         if (len2 % 4 === 2) {
         if (len2 % 4 === 2) {
             staticSection = offset2.slice(0, -3);
             staticSection = offset2.slice(0, -3);
             offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
             offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
                 Utils.escapeHtml(Utils.fromBase64("AAA" + staticSection, alphabet).slice(2, -2)) + "'>" +
                 Utils.escapeHtml(Utils.fromBase64("AAA" + staticSection, alphabet).slice(2, -2)) + "'>" +
                 staticSection + "</span>" +
                 staticSection + "</span>" +
-                "<span class='hlgreen'>" + offset2.substr(offset2.length - 3, 1) + "</span>" +
-                "<span class='hlred'>" + offset2.substr(offset2.length - 2) + "</span>";
+                "<span class='hl5'>" + offset2.substr(offset2.length - 3, 1) + "</span>" +
+                "<span class='hl3'>" + offset2.substr(offset2.length - 2) + "</span>";
         } else if (len2 % 4 === 3) {
         } else if (len2 % 4 === 3) {
             staticSection = offset2.slice(0, -2);
             staticSection = offset2.slice(0, -2);
             offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
             offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
                 Utils.escapeHtml(Utils.fromBase64("AAA" + staticSection, alphabet).slice(2, -2)) + "'>" +
                 Utils.escapeHtml(Utils.fromBase64("AAA" + staticSection, alphabet).slice(2, -2)) + "'>" +
                 staticSection + "</span>" +
                 staticSection + "</span>" +
-                "<span class='hlgreen'>" + offset2.substr(offset2.length - 2, 1) + "</span>" +
-                "<span class='hlred'>" + offset2.substr(offset2.length - 1) + "</span>";
+                "<span class='hl5'>" + offset2.substr(offset2.length - 2, 1) + "</span>" +
+                "<span class='hl3'>" + offset2.substr(offset2.length - 1) + "</span>";
         } else {
         } else {
             staticSection = offset2;
             staticSection = offset2;
             offset2 = padding +  "<span data-toggle='tooltip' data-placement='top' title='" +
             offset2 = padding +  "<span data-toggle='tooltip' data-placement='top' title='" +
@@ -300,8 +300,8 @@ const Base64 = {
             offset2 = staticSection;
             offset2 = staticSection;
         }
         }
 
 
-        return (showVariable ? "Characters highlighted in <span class='hlgreen'>green</span> could change if the input is surrounded by more data." +
-            "\nCharacters highlighted in <span class='hlred'>red</span> are for padding purposes only." +
+        return (showVariable ? "Characters highlighted in <span class='hl5'>green</span> could change if the input is surrounded by more data." +
+            "\nCharacters highlighted in <span class='hl3'>red</span> are for padding purposes only." +
             "\nUnhighlighted characters are <span data-toggle='tooltip' data-placement='top' title='Tooltip on left'>static</span>." +
             "\nUnhighlighted characters are <span data-toggle='tooltip' data-placement='top' title='Tooltip on left'>static</span>." +
             "\nHover over the static sections to see what they decode to on their own.\n" +
             "\nHover over the static sections to see what they decode to on their own.\n" +
             "\nOffset 0: " + offset0 +
             "\nOffset 0: " + offset0 +

+ 14 - 14
src/core/operations/BitwiseOp.js

@@ -36,7 +36,9 @@ const BitwiseOp = {
             o = input[i];
             o = input[i];
             x = nullPreserving && (o === 0 || o === k) ? o : func(o, k);
             x = nullPreserving && (o === 0 || o === k) ? o : func(o, k);
             result.push(x);
             result.push(x);
-            if (scheme !== "Standard" && !(nullPreserving && (o === 0 || o === k))) {
+            if (scheme &&
+                scheme !== "Standard" &&
+                !(nullPreserving && (o === 0 || o === k))) {
                 switch (scheme) {
                 switch (scheme) {
                     case "Input differential":
                     case "Input differential":
                         key[i % key.length] = x;
                         key[i % key.length] = x;
@@ -120,19 +122,19 @@ const BitwiseOp = {
      * @returns {string}
      * @returns {string}
      */
      */
     runXorBrute: function (input, args) {
     runXorBrute: function (input, args) {
-        let keyLength = parseInt(args[0], 10),
+        const keyLength = parseInt(args[0], 10),
             sampleLength = args[1],
             sampleLength = args[1],
             sampleOffset = args[2],
             sampleOffset = args[2],
-            nullPreserving = args[3],
-            differential = args[4],
-            crib = args[5],
-            printKey = args[6],
-            outputHex = args[7],
-            regex;
+            scheme = args[3],
+            nullPreserving = args[4],
+            printKey = args[5],
+            outputHex = args[6],
+            crib = args[7];
 
 
         let output = "",
         let output = "",
             result,
             result,
-            resultUtf8;
+            resultUtf8,
+            regex;
 
 
         input = input.slice(sampleOffset, sampleOffset + sampleLength);
         input = input.slice(sampleOffset, sampleOffset + sampleLength);
 
 
@@ -142,14 +144,12 @@ const BitwiseOp = {
 
 
 
 
         for (let key = 1, l = Math.pow(256, keyLength); key < l; key++) {
         for (let key = 1, l = Math.pow(256, keyLength); key < l; key++) {
-            result = BitwiseOp._bitOp(input, Utils.hexToByteArray(key.toString(16)), BitwiseOp._xor, nullPreserving, differential);
+            result = BitwiseOp._bitOp(input, Utils.fromHex(key.toString(16)), BitwiseOp._xor, nullPreserving, scheme);
             resultUtf8 = Utils.byteArrayToUtf8(result);
             resultUtf8 = Utils.byteArrayToUtf8(result);
             if (crib !== "" && resultUtf8.search(regex) === -1) continue;
             if (crib !== "" && resultUtf8.search(regex) === -1) continue;
             if (printKey) output += "Key = " + Utils.hex(key, (2*keyLength)) + ": ";
             if (printKey) output += "Key = " + Utils.hex(key, (2*keyLength)) + ": ";
-            if (outputHex)
-                output += Utils.byteArrayToHex(result) + "\n";
-            else
-                output += Utils.printable(resultUtf8, false) + "\n";
+            if (outputHex) output += Utils.toHex(result) + "\n";
+            else output += Utils.printable(resultUtf8, false) + "\n";
             if (printKey) output += "\n";
             if (printKey) output += "\n";
         }
         }
         return output;
         return output;

+ 35 - 35
src/core/operations/Code.js

@@ -228,19 +228,19 @@ const Code = {
         }
         }
 
 
         code = code
         code = code
-                // Create newlines after ;
-                .replace(/;/g, ";\n")
-                // Create newlines after { and around }
-                .replace(/{/g, "{\n")
-                .replace(/}/g, "\n}\n")
-                // Remove carriage returns
-                .replace(/\r/g, "")
-                // Remove all indentation
-                .replace(/^\s+/g, "")
-                .replace(/\n\s+/g, "\n")
-                // Remove trailing spaces
-                .replace(/\s*$/g, "")
-                .replace(/\n{/g, "{");
+            // Create newlines after ;
+            .replace(/;/g, ";\n")
+            // Create newlines after { and around }
+            .replace(/{/g, "{\n")
+            .replace(/}/g, "\n}\n")
+            // Remove carriage returns
+            .replace(/\r/g, "")
+            // Remove all indentation
+            .replace(/^\s+/g, "")
+            .replace(/\n\s+/g, "\n")
+            // Remove trailing spaces
+            .replace(/\s*$/g, "")
+            .replace(/\n{/g, "{");
 
 
         // Indent
         // Indent
         let i = 0,
         let i = 0,
@@ -265,27 +265,27 @@ const Code = {
         }
         }
 
 
         code = code
         code = code
-                // Add strategic spaces
-                .replace(/\s*([!<>=+-/*]?)=\s*/g, " $1= ")
-                .replace(/\s*<([=]?)\s*/g, " <$1 ")
-                .replace(/\s*>([=]?)\s*/g, " >$1 ")
-                .replace(/([^+])\+([^+=])/g, "$1 + $2")
-                .replace(/([^-])-([^-=])/g, "$1 - $2")
-                .replace(/([^*])\*([^*=])/g, "$1 * $2")
-                .replace(/([^/])\/([^/=])/g, "$1 / $2")
-                .replace(/\s*,\s*/g, ", ")
-                .replace(/\s*{/g, " {")
-                .replace(/}\n/g, "}\n\n")
-                // Hacky horribleness
-                .replace(/(if|for|while|with|elif|elseif)\s*\(([^\n]*)\)\s*\n([^{])/gim, "$1 ($2)\n    $3")
-                .replace(/(if|for|while|with|elif|elseif)\s*\(([^\n]*)\)([^{])/gim, "$1 ($2) $3")
-                .replace(/else\s*\n([^{])/gim, "else\n    $1")
-                .replace(/else\s+([^{])/gim, "else $1")
-                // Remove strategic spaces
-                .replace(/\s+;/g, ";")
-                .replace(/\{\s+\}/g, "{}")
-                .replace(/\[\s+\]/g, "[]")
-                .replace(/}\s*(else|catch|except|finally|elif|elseif|else if)/gi, "} $1");
+            // Add strategic spaces
+            .replace(/\s*([!<>=+-/*]?)=\s*/g, " $1= ")
+            .replace(/\s*<([=]?)\s*/g, " <$1 ")
+            .replace(/\s*>([=]?)\s*/g, " >$1 ")
+            .replace(/([^+])\+([^+=])/g, "$1 + $2")
+            .replace(/([^-])-([^-=])/g, "$1 - $2")
+            .replace(/([^*])\*([^*=])/g, "$1 * $2")
+            .replace(/([^/])\/([^/=])/g, "$1 / $2")
+            .replace(/\s*,\s*/g, ", ")
+            .replace(/\s*{/g, " {")
+            .replace(/}\n/g, "}\n\n")
+            // Hacky horribleness
+            .replace(/(if|for|while|with|elif|elseif)\s*\(([^\n]*)\)\s*\n([^{])/gim, "$1 ($2)\n    $3")
+            .replace(/(if|for|while|with|elif|elseif)\s*\(([^\n]*)\)([^{])/gim, "$1 ($2) $3")
+            .replace(/else\s*\n([^{])/gim, "else\n    $1")
+            .replace(/else\s+([^{])/gim, "else $1")
+            // Remove strategic spaces
+            .replace(/\s+;/g, ";")
+            .replace(/\{\s+\}/g, "{}")
+            .replace(/\[\s+\]/g, "[]")
+            .replace(/}\s*(else|catch|except|finally|elif|elseif|else if)/gi, "} $1");
 
 
         // Replace preserved tokens
         // Replace preserved tokens
         const ptokens = /###preservedToken(\d+)###/g;
         const ptokens = /###preservedToken(\d+)###/g;
@@ -329,7 +329,7 @@ const Code = {
      * @param {Object[]} args
      * @param {Object[]} args
      * @returns {string}
      * @returns {string}
      */
      */
-    runXpath:function(input, args) {
+    runXpath: function(input, args) {
         let query = args[0],
         let query = args[0],
             delimiter = args[1];
             delimiter = args[1];
 
 

+ 21 - 21
src/core/operations/Compress.js

@@ -9,12 +9,12 @@ import bzip2 from "exports-loader?bzip2!../lib/bzip2.js";
 const Zlib = {
 const Zlib = {
     RawDeflate: rawdeflate.Zlib.RawDeflate,
     RawDeflate: rawdeflate.Zlib.RawDeflate,
     RawInflate: rawinflate.Zlib.RawInflate,
     RawInflate: rawinflate.Zlib.RawInflate,
-    Deflate: zlibAndGzip.Zlib.Deflate,
-    Inflate: zlibAndGzip.Zlib.Inflate,
-    Gzip: zlibAndGzip.Zlib.Gzip,
-    Gunzip: zlibAndGzip.Zlib.Gunzip,
-    Zip: zip.Zlib.Zip,
-    Unzip: unzip.Zlib.Unzip,
+    Deflate:    zlibAndGzip.Zlib.Deflate,
+    Inflate:    zlibAndGzip.Zlib.Inflate,
+    Gzip:       zlibAndGzip.Zlib.Gzip,
+    Gunzip:     zlibAndGzip.Zlib.Gunzip,
+    Zip:        zip.Zlib.Zip,
+    Unzip:      unzip.Zlib.Unzip,
 };
 };
 
 
 
 
@@ -54,9 +54,9 @@ const Compress = {
      * @default
      * @default
      */
      */
     RAW_COMPRESSION_TYPE_LOOKUP: {
     RAW_COMPRESSION_TYPE_LOOKUP: {
-        "Fixed Huffman Coding"   : Zlib.RawDeflate.CompressionType.FIXED,
-        "Dynamic Huffman Coding" : Zlib.RawDeflate.CompressionType.DYNAMIC,
-        "None (Store)"           : Zlib.RawDeflate.CompressionType.NONE,
+        "Fixed Huffman Coding":   Zlib.RawDeflate.CompressionType.FIXED,
+        "Dynamic Huffman Coding": Zlib.RawDeflate.CompressionType.DYNAMIC,
+        "None (Store)":           Zlib.RawDeflate.CompressionType.NONE,
     },
     },
 
 
     /**
     /**
@@ -99,8 +99,8 @@ const Compress = {
      * @default
      * @default
      */
      */
     RAW_BUFFER_TYPE_LOOKUP: {
     RAW_BUFFER_TYPE_LOOKUP: {
-        "Adaptive" : Zlib.RawInflate.BufferType.ADAPTIVE,
-        "Block"    : Zlib.RawInflate.BufferType.BLOCK,
+        "Adaptive": Zlib.RawInflate.BufferType.ADAPTIVE,
+        "Block":    Zlib.RawInflate.BufferType.BLOCK,
     },
     },
 
 
     /**
     /**
@@ -150,9 +150,9 @@ const Compress = {
      * @default
      * @default
      */
      */
     ZLIB_COMPRESSION_TYPE_LOOKUP: {
     ZLIB_COMPRESSION_TYPE_LOOKUP: {
-        "Fixed Huffman Coding"   : Zlib.Deflate.CompressionType.FIXED,
-        "Dynamic Huffman Coding" : Zlib.Deflate.CompressionType.DYNAMIC,
-        "None (Store)"           : Zlib.Deflate.CompressionType.NONE,
+        "Fixed Huffman Coding":   Zlib.Deflate.CompressionType.FIXED,
+        "Dynamic Huffman Coding": Zlib.Deflate.CompressionType.DYNAMIC,
+        "None (Store)":           Zlib.Deflate.CompressionType.NONE,
     },
     },
 
 
     /**
     /**
@@ -175,8 +175,8 @@ const Compress = {
      * @default
      * @default
      */
      */
     ZLIB_BUFFER_TYPE_LOOKUP: {
     ZLIB_BUFFER_TYPE_LOOKUP: {
-        "Adaptive" : Zlib.Inflate.BufferType.ADAPTIVE,
-        "Block"    : Zlib.Inflate.BufferType.BLOCK,
+        "Adaptive": Zlib.Inflate.BufferType.ADAPTIVE,
+        "Block":    Zlib.Inflate.BufferType.BLOCK,
     },
     },
 
 
     /**
     /**
@@ -264,17 +264,17 @@ const Compress = {
      * @default
      * @default
      */
      */
     ZIP_COMPRESSION_METHOD_LOOKUP: {
     ZIP_COMPRESSION_METHOD_LOOKUP: {
-        "Deflate"      : Zlib.Zip.CompressionMethod.DEFLATE,
-        "None (Store)" : Zlib.Zip.CompressionMethod.STORE
+        "Deflate":      Zlib.Zip.CompressionMethod.DEFLATE,
+        "None (Store)": Zlib.Zip.CompressionMethod.STORE
     },
     },
     /**
     /**
      * @constant
      * @constant
      * @default
      * @default
      */
      */
     ZIP_OS_LOOKUP: {
     ZIP_OS_LOOKUP: {
-        "MSDOS"     : Zlib.Zip.OperatingSystem.MSDOS,
-        "Unix"      : Zlib.Zip.OperatingSystem.UNIX,
-        "Macintosh" : Zlib.Zip.OperatingSystem.MACINTOSH
+        "MSDOS":     Zlib.Zip.OperatingSystem.MSDOS,
+        "Unix":      Zlib.Zip.OperatingSystem.UNIX,
+        "Macintosh": Zlib.Zip.OperatingSystem.MACINTOSH
     },
     },
 
 
     /**
     /**

+ 190 - 190
src/core/operations/Convert.js

@@ -25,36 +25,36 @@ const Convert = {
      * @default
      * @default
      */
      */
     DISTANCE_FACTOR: { // Multiples of a metre
     DISTANCE_FACTOR: { // Multiples of a metre
-        "Nanometres (nm)"   : 1e-9,
-        "Micrometres (µm)"  : 1e-6,
-        "Millimetres (mm)"  : 1e-3,
-        "Centimetres (cm)"  : 1e-2,
-        "Metres (m)"        : 1,
-        "Kilometers (km)"   : 1e3,
-
-        "Thou (th)"         : 0.0000254,
-        "Inches (in)"       : 0.0254,
-        "Feet (ft)"         : 0.3048,
-        "Yards (yd)"        : 0.9144,
-        "Chains (ch)"       : 20.1168,
-        "Furlongs (fur)"    : 201.168,
-        "Miles (mi)"        : 1609.344,
-        "Leagues (lea)"     : 4828.032,
-
-        "Fathoms (ftm)"     : 1.853184,
-        "Cables"            : 185.3184,
-        "Nautical miles"    : 1853.184,
-
-        "Cars (4m)"         : 4,
-        "Buses (8.4m)"      : 8.4,
+        "Nanometres (nm)":         1e-9,
+        "Micrometres (µm)":        1e-6,
+        "Millimetres (mm)":        1e-3,
+        "Centimetres (cm)":        1e-2,
+        "Metres (m)":              1,
+        "Kilometers (km)":         1e3,
+
+        "Thou (th)":               0.0000254,
+        "Inches (in)":             0.0254,
+        "Feet (ft)":               0.3048,
+        "Yards (yd)":              0.9144,
+        "Chains (ch)":             20.1168,
+        "Furlongs (fur)":          201.168,
+        "Miles (mi)":              1609.344,
+        "Leagues (lea)":           4828.032,
+
+        "Fathoms (ftm)":           1.853184,
+        "Cables":                  185.3184,
+        "Nautical miles":          1853.184,
+
+        "Cars (4m)":               4,
+        "Buses (8.4m)":            8.4,
         "American football fields (91m)": 91,
         "American football fields (91m)": 91,
         "Football pitches (105m)": 105,
         "Football pitches (105m)": 105,
 
 
-        "Earth-to-Moons"    : 380000000,
-        "Earth's equators"  : 40075016.686,
+        "Earth-to-Moons":          380000000,
+        "Earth's equators":        40075016.686,
         "Astronomical units (au)": 149597870700,
         "Astronomical units (au)": 149597870700,
-        "Light-years (ly)"  : 9460730472580800,
-        "Parsecs (pc)"      : 3.0856776e16
+        "Light-years (ly)":        9460730472580800,
+        "Parsecs (pc)":            3.0856776e16
     },
     },
 
 
     /**
     /**
@@ -90,52 +90,52 @@ const Convert = {
      * @default
      * @default
      */
      */
     DATA_FACTOR: { // Multiples of a bit
     DATA_FACTOR: { // Multiples of a bit
-        "Bits (b)"        : 1,
-        "Nibbles"         : 4,
-        "Octets"          : 8,
-        "Bytes (B)"       : 8,
+        "Bits (b)":        1,
+        "Nibbles":         4,
+        "Octets":          8,
+        "Bytes (B)":       8,
 
 
         // Binary bits (2^n)
         // Binary bits (2^n)
-        "Kibibits (Kib)"  : 1024,
-        "Mebibits (Mib)"  : 1048576,
-        "Gibibits (Gib)"  : 1073741824,
-        "Tebibits (Tib)"  : 1099511627776,
-        "Pebibits (Pib)"  : 1125899906842624,
-        "Exbibits (Eib)"  : 1152921504606846976,
-        "Zebibits (Zib)"  : 1180591620717411303424,
-        "Yobibits (Yib)"  : 1208925819614629174706176,
+        "Kibibits (Kib)":  1024,
+        "Mebibits (Mib)":  1048576,
+        "Gibibits (Gib)":  1073741824,
+        "Tebibits (Tib)":  1099511627776,
+        "Pebibits (Pib)":  1125899906842624,
+        "Exbibits (Eib)":  1152921504606846976,
+        "Zebibits (Zib)":  1180591620717411303424,
+        "Yobibits (Yib)":  1208925819614629174706176,
 
 
         // Decimal bits (10^n)
         // Decimal bits (10^n)
-        "Decabits"        : 10,
-        "Hectobits"       : 100,
-        "Kilobits (Kb)"   : 1e3,
-        "Megabits (Mb)"   : 1e6,
-        "Gigabits (Gb)"   : 1e9,
-        "Terabits (Tb)"   : 1e12,
-        "Petabits (Pb)"   : 1e15,
-        "Exabits (Eb)"    : 1e18,
-        "Zettabits (Zb)"  : 1e21,
-        "Yottabits (Yb)"  : 1e24,
+        "Decabits":        10,
+        "Hectobits":       100,
+        "Kilobits (Kb)":   1e3,
+        "Megabits (Mb)":   1e6,
+        "Gigabits (Gb)":   1e9,
+        "Terabits (Tb)":   1e12,
+        "Petabits (Pb)":   1e15,
+        "Exabits (Eb)":    1e18,
+        "Zettabits (Zb)":  1e21,
+        "Yottabits (Yb)":  1e24,
 
 
         // Binary bytes (8 x 2^n)
         // Binary bytes (8 x 2^n)
-        "Kibibytes (KiB)" : 8192,
-        "Mebibytes (MiB)" : 8388608,
-        "Gibibytes (GiB)" : 8589934592,
-        "Tebibytes (TiB)" : 8796093022208,
-        "Pebibytes (PiB)" : 9007199254740992,
-        "Exbibytes (EiB)" : 9223372036854775808,
-        "Zebibytes (ZiB)" : 9444732965739290427392,
-        "Yobibytes (YiB)" : 9671406556917033397649408,
+        "Kibibytes (KiB)": 8192,
+        "Mebibytes (MiB)": 8388608,
+        "Gibibytes (GiB)": 8589934592,
+        "Tebibytes (TiB)": 8796093022208,
+        "Pebibytes (PiB)": 9007199254740992,
+        "Exbibytes (EiB)": 9223372036854775808,
+        "Zebibytes (ZiB)": 9444732965739290427392,
+        "Yobibytes (YiB)": 9671406556917033397649408,
 
 
         // Decimal bytes (8 x 10^n)
         // Decimal bytes (8 x 10^n)
-        "Kilobytes (KB)"  : 8e3,
-        "Megabytes (MB)"  : 8e6,
-        "Gigabytes (GB)"  : 8e9,
-        "Terabytes (TB)"  : 8e12,
-        "Petabytes (PB)"  : 8e15,
-        "Exabytes (EB)"   : 8e18,
-        "Zettabytes (ZB)" : 8e21,
-        "Yottabytes (YB)" : 8e24,
+        "Kilobytes (KB)":  8e3,
+        "Megabytes (MB)":  8e6,
+        "Gigabytes (GB)":  8e9,
+        "Terabytes (TB)":  8e12,
+        "Petabytes (PB)":  8e15,
+        "Exabytes (EB)":   8e18,
+        "Zettabytes (ZB)": 8e21,
+        "Yottabytes (YB)": 8e24,
     },
     },
 
 
     /**
     /**
@@ -171,51 +171,51 @@ const Convert = {
      */
      */
     AREA_FACTOR: { // Multiples of a square metre
     AREA_FACTOR: { // Multiples of a square metre
         // Metric
         // Metric
-        "Square metre (sq m)"       : 1,
-        "Square kilometre (sq km)"  : 1e6,
+        "Square metre (sq m)":      1,
+        "Square kilometre (sq km)": 1e6,
 
 
-        "Centiare (ca)"             : 1,
-        "Deciare (da)"              : 10,
-        "Are (a)"                   : 100,
-        "Decare (daa)"              : 1e3,
-        "Hectare (ha)"              : 1e4,
+        "Centiare (ca)":            1,
+        "Deciare (da)":             10,
+        "Are (a)":                  100,
+        "Decare (daa)":             1e3,
+        "Hectare (ha)":             1e4,
 
 
         // Imperial
         // Imperial
-        "Square inch (sq in)"       : 0.00064516,
-        "Square foot (sq ft)"       : 0.09290304,
-        "Square yard (sq yd)"       : 0.83612736,
-        "Square mile (sq mi)"       : 2589988.110336,
-        "Perch (sq per)"            : 42.21,
-        "Rood (ro)"                 : 1011,
-        "International acre (ac)"   : 4046.8564224,
+        "Square inch (sq in)":      0.00064516,
+        "Square foot (sq ft)":      0.09290304,
+        "Square yard (sq yd)":      0.83612736,
+        "Square mile (sq mi)":      2589988.110336,
+        "Perch (sq per)":           42.21,
+        "Rood (ro)":                1011,
+        "International acre (ac)":  4046.8564224,
 
 
         // US customary units
         // US customary units
-        "US survey acre (ac)"       : 4046.87261,
-        "US survey square mile (sq mi)" : 2589998.470305239,
-        "US survey township"        : 93239944.9309886,
+        "US survey acre (ac)":      4046.87261,
+        "US survey square mile (sq mi)": 2589998.470305239,
+        "US survey township":       93239944.9309886,
 
 
         // Nuclear physics
         // Nuclear physics
-        "Yoctobarn (yb)"            : 1e-52,
-        "Zeptobarn (zb)"            : 1e-49,
-        "Attobarn (ab)"             : 1e-46,
-        "Femtobarn (fb)"            : 1e-43,
-        "Picobarn (pb)"             : 1e-40,
-        "Nanobarn (nb)"             : 1e-37,
-        "Microbarn (μb)"            : 1e-34,
-        "Millibarn (mb)"            : 1e-31,
-        "Barn (b)"                  : 1e-28,
-        "Kilobarn (kb)"             : 1e-25,
-        "Megabarn (Mb)"             : 1e-22,
-
-        "Planck area"               : 2.6e-70,
-        "Shed"                      : 1e-52,
-        "Outhouse"                  : 1e-34,
+        "Yoctobarn (yb)":           1e-52,
+        "Zeptobarn (zb)":           1e-49,
+        "Attobarn (ab)":            1e-46,
+        "Femtobarn (fb)":           1e-43,
+        "Picobarn (pb)":            1e-40,
+        "Nanobarn (nb)":            1e-37,
+        "Microbarn (μb)":           1e-34,
+        "Millibarn (mb)":           1e-31,
+        "Barn (b)":                 1e-28,
+        "Kilobarn (kb)":            1e-25,
+        "Megabarn (Mb)":            1e-22,
+
+        "Planck area":              2.6e-70,
+        "Shed":                     1e-52,
+        "Outhouse":                 1e-34,
 
 
         // Comparisons
         // Comparisons
-        "Washington D.C."           : 176119191.502848,
-        "Isle of Wight"             : 380000000,
-        "Wales"                     : 20779000000,
-        "Texas"                     : 696241000000,
+        "Washington D.C.":          176119191.502848,
+        "Isle of Wight":            380000000,
+        "Wales":                    20779000000,
+        "Texas":                    696241000000,
     },
     },
 
 
     /**
     /**
@@ -252,81 +252,81 @@ const Convert = {
      */
      */
     MASS_FACTOR: { // Multiples of a gram
     MASS_FACTOR: { // Multiples of a gram
         // Metric
         // Metric
-        "Yoctogram (yg)"    : 1e-24,
-        "Zeptogram (zg)"    : 1e-21,
-        "Attogram (ag)"     : 1e-18,
-        "Femtogram (fg)"    : 1e-15,
-        "Picogram (pg)"     : 1e-12,
-        "Nanogram (ng)"     : 1e-9,
-        "Microgram (μg)"    : 1e-6,
-        "Milligram (mg)"    : 1e-3,
-        "Centigram (cg)"    : 1e-2,
-        "Decigram (dg)"     : 1e-1,
-        "Gram (g)"          : 1,
-        "Decagram (dag)"    : 10,
-        "Hectogram (hg)"    : 100,
-        "Kilogram (kg)"     : 1000,
-        "Megagram (Mg)"     : 1e6,
-        "Tonne (t)"         : 1e6,
-        "Gigagram (Gg)"     : 1e9,
-        "Teragram (Tg)"     : 1e12,
-        "Petagram (Pg)"     : 1e15,
-        "Exagram (Eg)"      : 1e18,
-        "Zettagram (Zg)"    : 1e21,
-        "Yottagram (Yg)"    : 1e24,
+        "Yoctogram (yg)":     1e-24,
+        "Zeptogram (zg)":     1e-21,
+        "Attogram (ag)":      1e-18,
+        "Femtogram (fg)":     1e-15,
+        "Picogram (pg)":      1e-12,
+        "Nanogram (ng)":      1e-9,
+        "Microgram (μg)":     1e-6,
+        "Milligram (mg)":     1e-3,
+        "Centigram (cg)":     1e-2,
+        "Decigram (dg)":      1e-1,
+        "Gram (g)":           1,
+        "Decagram (dag)":     10,
+        "Hectogram (hg)":     100,
+        "Kilogram (kg)":      1000,
+        "Megagram (Mg)":      1e6,
+        "Tonne (t)":          1e6,
+        "Gigagram (Gg)":      1e9,
+        "Teragram (Tg)":      1e12,
+        "Petagram (Pg)":      1e15,
+        "Exagram (Eg)":       1e18,
+        "Zettagram (Zg)":     1e21,
+        "Yottagram (Yg)":     1e24,
 
 
         // Imperial Avoirdupois
         // Imperial Avoirdupois
-        "Grain (gr)"        : 64.79891e-3,
-        "Dram (dr)"         : 1.7718451953125,
-        "Ounce (oz)"        : 28.349523125,
-        "Pound (lb)"        : 453.59237,
-        "Nail"              : 3175.14659,
-        "Stone (st)"        : 6.35029318e3,
-        "Quarter (gr)"      : 12700.58636,
-        "Tod"               : 12700.58636,
-        "US hundredweight (cwt)" : 45.359237e3,
-        "Imperial hundredweight (cwt)" : 50.80234544e3,
-        "US ton (t)"        : 907.18474e3,
-        "Imperial ton (t)"  : 1016.0469088e3,
+        "Grain (gr)":         64.79891e-3,
+        "Dram (dr)":          1.7718451953125,
+        "Ounce (oz)":         28.349523125,
+        "Pound (lb)":         453.59237,
+        "Nail":               3175.14659,
+        "Stone (st)":         6.35029318e3,
+        "Quarter (gr)":       12700.58636,
+        "Tod":                12700.58636,
+        "US hundredweight (cwt)": 45.359237e3,
+        "Imperial hundredweight (cwt)": 50.80234544e3,
+        "US ton (t)":         907.18474e3,
+        "Imperial ton (t)":   1016.0469088e3,
 
 
         // Imperial Troy
         // Imperial Troy
-        "Pennyweight (dwt)" : 1.55517384,
-        "Troy dram (dr t)"  : 3.8879346,
-        "Troy ounce (oz t)" : 31.1034768,
-        "Troy pound (lb t)" : 373.2417216,
-        "Mark"              : 248.8278144,
+        "Pennyweight (dwt)":  1.55517384,
+        "Troy dram (dr t)":   3.8879346,
+        "Troy ounce (oz t)":  31.1034768,
+        "Troy pound (lb t)":  373.2417216,
+        "Mark":               248.8278144,
 
 
         // Archaic
         // Archaic
-        "Wey"               : 76.5e3,
-        "Wool wey"          : 101.7e3,
-        "Suffolk wey"       : 161.5e3,
-        "Wool sack"         : 153000,
-        "Coal sack"         : 50.80234544e3,
-        "Load"              : 918000,
-        "Last"              : 1836000,
-        "Flax or feather last" : 770e3,
-        "Gunpowder last"    : 1090e3,
-        "Picul"             : 60.478982e3,
-        "Rice last"         : 1200e3,
+        "Wey":                76.5e3,
+        "Wool wey":           101.7e3,
+        "Suffolk wey":        161.5e3,
+        "Wool sack":          153000,
+        "Coal sack":          50.80234544e3,
+        "Load":               918000,
+        "Last":               1836000,
+        "Flax or feather last": 770e3,
+        "Gunpowder last":     1090e3,
+        "Picul":              60.478982e3,
+        "Rice last":          1200e3,
 
 
         // Comparisons
         // Comparisons
-        "Big Ben (14 tonnes)"                      : 14e6,
-        "Blue whale (180 tonnes)"                  : 180e6,
-        "International Space Station (417 tonnes)" : 417e6,
-        "Space Shuttle (2,041 tonnes)"             : 2041e6,
-        "RMS Titanic (52,000 tonnes)"              : 52000e6,
-        "Great Pyramid of Giza (6,000,000 tonnes)" : 6e12,
-        "Earth's oceans (1.4 yottagrams)"          : 1.4e24,
+        "Big Ben (14 tonnes)": 14e6,
+        "Blue whale (180 tonnes)": 180e6,
+        "International Space Station (417 tonnes)": 417e6,
+        "Space Shuttle (2,041 tonnes)": 2041e6,
+        "RMS Titanic (52,000 tonnes)": 52000e6,
+        "Great Pyramid of Giza (6,000,000 tonnes)": 6e12,
+        "Earth's oceans (1.4 yottagrams)": 1.4e24,
 
 
         // Astronomical
         // Astronomical
-        "A teaspoon of neutron star (5,500 million tonnes)" : 5.5e15,
-        "Lunar mass (ML)"                          : 7.342e25,
-        "Earth mass (M⊕)"                          : 5.97219e27,
-        "Jupiter mass (MJ)"                        : 1.8981411476999997e30,
-        "Solar mass (M☉)"                         : 1.98855e33,
-        "Sagittarius A* (7.5 x 10^36 kgs-ish)"     : 7.5e39,
-        "Milky Way galaxy (1.2 x 10^42 kgs)"       : 1.2e45,
-        "The observable universe (1.45 x 10^53 kgs)" : 1.45e56,
+        "A teaspoon of neutron star (5,500 million tonnes)": 5.5e15,
+        "Lunar mass (ML)":    7.342e25,
+        "Earth mass (M⊕)":    5.97219e27,
+        "Jupiter mass (MJ)":  1.8981411476999997e30,
+        "Solar mass (M☉)":    1.98855e33,
+        "Sagittarius A* (7.5 x 10^36 kgs-ish)": 7.5e39,
+        "Milky Way galaxy (1.2 x 10^42 kgs)": 1.2e45,
+        "The observable universe (1.45 x 10^53 kgs)": 1.45e56,
     },
     },
 
 
     /**
     /**
@@ -361,37 +361,37 @@ const Convert = {
      */
      */
     SPEED_FACTOR: { // Multiples of m/s
     SPEED_FACTOR: { // Multiples of m/s
         // Metric
         // Metric
-        "Metres per second (m/s)"        : 1,
-        "Kilometres per hour (km/h)"     : 0.2778,
+        "Metres per second (m/s)":           1,
+        "Kilometres per hour (km/h)":        0.2778,
 
 
         // Imperial
         // Imperial
-        "Miles per hour (mph)"           : 0.44704,
-        "Knots (kn)"                     : 0.5144,
+        "Miles per hour (mph)":              0.44704,
+        "Knots (kn)":                        0.5144,
 
 
         // Comparisons
         // Comparisons
-        "Human hair growth rate"         : 4.8e-9,
-        "Bamboo growth rate"             : 1.4e-5,
-        "World's fastest snail"          : 0.00275,
-        "Usain Bolt's top speed"         : 12.42,
-        "Jet airliner cruising speed"    : 250,
-        "Concorde"                       : 603,
-        "SR-71 Blackbird"                : 981,
-        "Space Shuttle"                  : 1400,
-        "International Space Station"    : 7700,
+        "Human hair growth rate":            4.8e-9,
+        "Bamboo growth rate":                1.4e-5,
+        "World's fastest snail":             0.00275,
+        "Usain Bolt's top speed":            12.42,
+        "Jet airliner cruising speed":       250,
+        "Concorde":                          603,
+        "SR-71 Blackbird":                   981,
+        "Space Shuttle":                     1400,
+        "International Space Station":       7700,
 
 
         // Scientific
         // Scientific
-        "Sound in standard atmosphere"   : 340.3,
-        "Sound in water"                 : 1500,
-        "Lunar escape velocity"          : 2375,
-        "Earth escape velocity"          : 11200,
-        "Earth's solar orbit"            : 29800,
-        "Solar system's Milky Way orbit" : 200000,
-        "Milky Way relative to the cosmic microwave background" : 552000,
-        "Solar escape velocity"          : 617700,
-        "Neutron star escape velocity (0.3c)" : 100000000,
-        "Light in a diamond (0.4136c)"   : 124000000,
-        "Signal in an optical fibre (0.667c)" : 200000000,
-        "Light (c)"                      : 299792458,
+        "Sound in standard atmosphere":      340.3,
+        "Sound in water":                    1500,
+        "Lunar escape velocity":             2375,
+        "Earth escape velocity":             11200,
+        "Earth's solar orbit":               29800,
+        "Solar system's Milky Way orbit":    200000,
+        "Milky Way relative to the cosmic microwave background": 552000,
+        "Solar escape velocity":             617700,
+        "Neutron star escape velocity (0.3c)": 100000000,
+        "Light in a diamond (0.4136c)":      124000000,
+        "Signal in an optical fibre (0.667c)": 200000000,
+        "Light (c)":                         299792458,
     },
     },
 
 
     /**
     /**

+ 31 - 4
src/core/operations/DateTime.js

@@ -89,8 +89,17 @@ const DateTime = {
      * @returns {string}
      * @returns {string}
      */
      */
     runFromFiletimeToUnix: function(input, args) {
     runFromFiletimeToUnix: function(input, args) {
-        let units = args[0];
-        input = new BigInteger(input).subtract(new BigInteger("116444736000000000"));
+        let units = args[0],
+            format = args[1];
+
+        if (format === "Hex") {
+            input = new BigInteger(input, 16);
+        } else {
+            input = new BigInteger(input);
+        }
+
+        input = input.subtract(new BigInteger("116444736000000000"));
+
         if (units === "Seconds (s)"){
         if (units === "Seconds (s)"){
             input = input.divide(new BigInteger("10000000"));
             input = input.divide(new BigInteger("10000000"));
         } else if (units === "Milliseconds (ms)") {
         } else if (units === "Milliseconds (ms)") {
@@ -102,6 +111,7 @@ const DateTime = {
         } else {
         } else {
             throw "Unrecognised unit";
             throw "Unrecognised unit";
         }
         }
+
         return input.toString();
         return input.toString();
     },
     },
 
 
@@ -115,8 +125,11 @@ const DateTime = {
      * @returns {string}
      * @returns {string}
      */
      */
     runToFiletimeFromUnix: function(input, args) {
     runToFiletimeFromUnix: function(input, args) {
-        let units = args[0];
+        let units = args[0],
+            format = args[1];
+
         input = new BigInteger(input);
         input = new BigInteger(input);
+
         if (units === "Seconds (s)"){
         if (units === "Seconds (s)"){
             input = input.multiply(new BigInteger("10000000"));
             input = input.multiply(new BigInteger("10000000"));
         } else if (units === "Milliseconds (ms)") {
         } else if (units === "Milliseconds (ms)") {
@@ -128,10 +141,24 @@ const DateTime = {
         } else {
         } else {
             throw "Unrecognised unit";
             throw "Unrecognised unit";
         }
         }
-        return input.add(new BigInteger("116444736000000000")).toString();
+
+        input = input.add(new BigInteger("116444736000000000"));
+
+        if (format === "Hex"){
+            return input.toString(16);
+        } else {
+            return input.toString();
+        }
     },
     },
 
 
 
 
+    /**
+     * @constant
+     * @default
+     */
+    FILETIME_FORMATS: ["Decimal", "Hex"],
+
+
     /**
     /**
      * @constant
      * @constant
      * @default
      * @default

+ 512 - 511
src/core/operations/HTML.js

@@ -144,8 +144,9 @@ const HTML = {
         }
         }
 
 
         if (removeLineBreaks) {
         if (removeLineBreaks) {
-            input = input.replace(/^\s*\n/, "") // first line
-                         .replace(/(\n\s*){2,}/g, "\n"); // all others
+            input = input
+                .replace(/^\s*\n/, "") // first line
+                .replace(/(\n\s*){2,}/g, "\n"); // all others
         }
         }
 
 
         return input;
         return input;
@@ -331,260 +332,260 @@ const HTML = {
      * @constant
      * @constant
      */
      */
     _byteToEntity: {
     _byteToEntity: {
-        34 : "&quot;",
-        38 : "&amp;",
-        39 : "&apos;",
-        60 : "&lt;",
-        62 : "&gt;",
-        160 : "&nbsp;",
-        161 : "&iexcl;",
-        162 : "&cent;",
-        163 : "&pound;",
-        164 : "&curren;",
-        165 : "&yen;",
-        166 : "&brvbar;",
-        167 : "&sect;",
-        168 : "&uml;",
-        169 : "&copy;",
-        170 : "&ordf;",
-        171 : "&laquo;",
-        172 : "&not;",
-        173 : "&shy;",
-        174 : "&reg;",
-        175 : "&macr;",
-        176 : "&deg;",
-        177 : "&plusmn;",
-        178 : "&sup2;",
-        179 : "&sup3;",
-        180 : "&acute;",
-        181 : "&micro;",
-        182 : "&para;",
-        183 : "&middot;",
-        184 : "&cedil;",
-        185 : "&sup1;",
-        186 : "&ordm;",
-        187 : "&raquo;",
-        188 : "&frac14;",
-        189 : "&frac12;",
-        190 : "&frac34;",
-        191 : "&iquest;",
-        192 : "&Agrave;",
-        193 : "&Aacute;",
-        194 : "&Acirc;",
-        195 : "&Atilde;",
-        196 : "&Auml;",
-        197 : "&Aring;",
-        198 : "&AElig;",
-        199 : "&Ccedil;",
-        200 : "&Egrave;",
-        201 : "&Eacute;",
-        202 : "&Ecirc;",
-        203 : "&Euml;",
-        204 : "&Igrave;",
-        205 : "&Iacute;",
-        206 : "&Icirc;",
-        207 : "&Iuml;",
-        208 : "&ETH;",
-        209 : "&Ntilde;",
-        210 : "&Ograve;",
-        211 : "&Oacute;",
-        212 : "&Ocirc;",
-        213 : "&Otilde;",
-        214 : "&Ouml;",
-        215 : "&times;",
-        216 : "&Oslash;",
-        217 : "&Ugrave;",
-        218 : "&Uacute;",
-        219 : "&Ucirc;",
-        220 : "&Uuml;",
-        221 : "&Yacute;",
-        222 : "&THORN;",
-        223 : "&szlig;",
-        224 : "&agrave;",
-        225 : "&aacute;",
-        226 : "&acirc;",
-        227 : "&atilde;",
-        228 : "&auml;",
-        229 : "&aring;",
-        230 : "&aelig;",
-        231 : "&ccedil;",
-        232 : "&egrave;",
-        233 : "&eacute;",
-        234 : "&ecirc;",
-        235 : "&euml;",
-        236 : "&igrave;",
-        237 : "&iacute;",
-        238 : "&icirc;",
-        239 : "&iuml;",
-        240 : "&eth;",
-        241 : "&ntilde;",
-        242 : "&ograve;",
-        243 : "&oacute;",
-        244 : "&ocirc;",
-        245 : "&otilde;",
-        246 : "&ouml;",
-        247 : "&divide;",
-        248 : "&oslash;",
-        249 : "&ugrave;",
-        250 : "&uacute;",
-        251 : "&ucirc;",
-        252 : "&uuml;",
-        253 : "&yacute;",
-        254 : "&thorn;",
-        255 : "&yuml;",
-        338 : "&OElig;",
-        339 : "&oelig;",
-        352 : "&Scaron;",
-        353 : "&scaron;",
-        376 : "&Yuml;",
-        402 : "&fnof;",
-        710 : "&circ;",
-        732 : "&tilde;",
-        913 : "&Alpha;",
-        914 : "&Beta;",
-        915 : "&Gamma;",
-        916 : "&Delta;",
-        917 : "&Epsilon;",
-        918 : "&Zeta;",
-        919 : "&Eta;",
-        920 : "&Theta;",
-        921 : "&Iota;",
-        922 : "&Kappa;",
-        923 : "&Lambda;",
-        924 : "&Mu;",
-        925 : "&Nu;",
-        926 : "&Xi;",
-        927 : "&Omicron;",
-        928 : "&Pi;",
-        929 : "&Rho;",
-        931 : "&Sigma;",
-        932 : "&Tau;",
-        933 : "&Upsilon;",
-        934 : "&Phi;",
-        935 : "&Chi;",
-        936 : "&Psi;",
-        937 : "&Omega;",
-        945 : "&alpha;",
-        946 : "&beta;",
-        947 : "&gamma;",
-        948 : "&delta;",
-        949 : "&epsilon;",
-        950 : "&zeta;",
-        951 : "&eta;",
-        952 : "&theta;",
-        953 : "&iota;",
-        954 : "&kappa;",
-        955 : "&lambda;",
-        956 : "&mu;",
-        957 : "&nu;",
-        958 : "&xi;",
-        959 : "&omicron;",
-        960 : "&pi;",
-        961 : "&rho;",
-        962 : "&sigmaf;",
-        963 : "&sigma;",
-        964 : "&tau;",
-        965 : "&upsilon;",
-        966 : "&phi;",
-        967 : "&chi;",
-        968 : "&psi;",
-        969 : "&omega;",
-        977 : "&thetasym;",
-        978 : "&upsih;",
-        982 : "&piv;",
-        8194 : "&ensp;",
-        8195 : "&emsp;",
-        8201 : "&thinsp;",
-        8204 : "&zwnj;",
-        8205 : "&zwj;",
-        8206 : "&lrm;",
-        8207 : "&rlm;",
-        8211 : "&ndash;",
-        8212 : "&mdash;",
-        8216 : "&lsquo;",
-        8217 : "&rsquo;",
-        8218 : "&sbquo;",
-        8220 : "&ldquo;",
-        8221 : "&rdquo;",
-        8222 : "&bdquo;",
-        8224 : "&dagger;",
-        8225 : "&Dagger;",
-        8226 : "&bull;",
-        8230 : "&hellip;",
-        8240 : "&permil;",
-        8242 : "&prime;",
-        8243 : "&Prime;",
-        8249 : "&lsaquo;",
-        8250 : "&rsaquo;",
-        8254 : "&oline;",
-        8260 : "&frasl;",
-        8364 : "&euro;",
-        8465 : "&image;",
-        8472 : "&weierp;",
-        8476 : "&real;",
-        8482 : "&trade;",
-        8501 : "&alefsym;",
-        8592 : "&larr;",
-        8593 : "&uarr;",
-        8594 : "&rarr;",
-        8595 : "&darr;",
-        8596 : "&harr;",
-        8629 : "&crarr;",
-        8656 : "&lArr;",
-        8657 : "&uArr;",
-        8658 : "&rArr;",
-        8659 : "&dArr;",
-        8660 : "&hArr;",
-        8704 : "&forall;",
-        8706 : "&part;",
-        8707 : "&exist;",
-        8709 : "&empty;",
-        8711 : "&nabla;",
-        8712 : "&isin;",
-        8713 : "&notin;",
-        8715 : "&ni;",
-        8719 : "&prod;",
-        8721 : "&sum;",
-        8722 : "&minus;",
-        8727 : "&lowast;",
-        8730 : "&radic;",
-        8733 : "&prop;",
-        8734 : "&infin;",
-        8736 : "&ang;",
-        8743 : "&and;",
-        8744 : "&or;",
-        8745 : "&cap;",
-        8746 : "&cup;",
-        8747 : "&int;",
-        8756 : "&there4;",
-        8764 : "&sim;",
-        8773 : "&cong;",
-        8776 : "&asymp;",
-        8800 : "&ne;",
-        8801 : "&equiv;",
-        8804 : "&le;",
-        8805 : "&ge;",
-        8834 : "&sub;",
-        8835 : "&sup;",
-        8836 : "&nsub;",
-        8838 : "&sube;",
-        8839 : "&supe;",
-        8853 : "&oplus;",
-        8855 : "&otimes;",
-        8869 : "&perp;",
-        8901 : "&sdot;",
-        8942 : "&vellip;",
-        8968 : "&lceil;",
-        8969 : "&rceil;",
-        8970 : "&lfloor;",
-        8971 : "&rfloor;",
-        9001 : "&lang;",
-        9002 : "&rang;",
-        9674 : "&loz;",
-        9824 : "&spades;",
-        9827 : "&clubs;",
-        9829 : "&hearts;",
-        9830 : "&diams;",
+        34: "&quot;",
+        38: "&amp;",
+        39: "&apos;",
+        60: "&lt;",
+        62: "&gt;",
+        160: "&nbsp;",
+        161: "&iexcl;",
+        162: "&cent;",
+        163: "&pound;",
+        164: "&curren;",
+        165: "&yen;",
+        166: "&brvbar;",
+        167: "&sect;",
+        168: "&uml;",
+        169: "&copy;",
+        170: "&ordf;",
+        171: "&laquo;",
+        172: "&not;",
+        173: "&shy;",
+        174: "&reg;",
+        175: "&macr;",
+        176: "&deg;",
+        177: "&plusmn;",
+        178: "&sup2;",
+        179: "&sup3;",
+        180: "&acute;",
+        181: "&micro;",
+        182: "&para;",
+        183: "&middot;",
+        184: "&cedil;",
+        185: "&sup1;",
+        186: "&ordm;",
+        187: "&raquo;",
+        188: "&frac14;",
+        189: "&frac12;",
+        190: "&frac34;",
+        191: "&iquest;",
+        192: "&Agrave;",
+        193: "&Aacute;",
+        194: "&Acirc;",
+        195: "&Atilde;",
+        196: "&Auml;",
+        197: "&Aring;",
+        198: "&AElig;",
+        199: "&Ccedil;",
+        200: "&Egrave;",
+        201: "&Eacute;",
+        202: "&Ecirc;",
+        203: "&Euml;",
+        204: "&Igrave;",
+        205: "&Iacute;",
+        206: "&Icirc;",
+        207: "&Iuml;",
+        208: "&ETH;",
+        209: "&Ntilde;",
+        210: "&Ograve;",
+        211: "&Oacute;",
+        212: "&Ocirc;",
+        213: "&Otilde;",
+        214: "&Ouml;",
+        215: "&times;",
+        216: "&Oslash;",
+        217: "&Ugrave;",
+        218: "&Uacute;",
+        219: "&Ucirc;",
+        220: "&Uuml;",
+        221: "&Yacute;",
+        222: "&THORN;",
+        223: "&szlig;",
+        224: "&agrave;",
+        225: "&aacute;",
+        226: "&acirc;",
+        227: "&atilde;",
+        228: "&auml;",
+        229: "&aring;",
+        230: "&aelig;",
+        231: "&ccedil;",
+        232: "&egrave;",
+        233: "&eacute;",
+        234: "&ecirc;",
+        235: "&euml;",
+        236: "&igrave;",
+        237: "&iacute;",
+        238: "&icirc;",
+        239: "&iuml;",
+        240: "&eth;",
+        241: "&ntilde;",
+        242: "&ograve;",
+        243: "&oacute;",
+        244: "&ocirc;",
+        245: "&otilde;",
+        246: "&ouml;",
+        247: "&divide;",
+        248: "&oslash;",
+        249: "&ugrave;",
+        250: "&uacute;",
+        251: "&ucirc;",
+        252: "&uuml;",
+        253: "&yacute;",
+        254: "&thorn;",
+        255: "&yuml;",
+        338: "&OElig;",
+        339: "&oelig;",
+        352: "&Scaron;",
+        353: "&scaron;",
+        376: "&Yuml;",
+        402: "&fnof;",
+        710: "&circ;",
+        732: "&tilde;",
+        913: "&Alpha;",
+        914: "&Beta;",
+        915: "&Gamma;",
+        916: "&Delta;",
+        917: "&Epsilon;",
+        918: "&Zeta;",
+        919: "&Eta;",
+        920: "&Theta;",
+        921: "&Iota;",
+        922: "&Kappa;",
+        923: "&Lambda;",
+        924: "&Mu;",
+        925: "&Nu;",
+        926: "&Xi;",
+        927: "&Omicron;",
+        928: "&Pi;",
+        929: "&Rho;",
+        931: "&Sigma;",
+        932: "&Tau;",
+        933: "&Upsilon;",
+        934: "&Phi;",
+        935: "&Chi;",
+        936: "&Psi;",
+        937: "&Omega;",
+        945: "&alpha;",
+        946: "&beta;",
+        947: "&gamma;",
+        948: "&delta;",
+        949: "&epsilon;",
+        950: "&zeta;",
+        951: "&eta;",
+        952: "&theta;",
+        953: "&iota;",
+        954: "&kappa;",
+        955: "&lambda;",
+        956: "&mu;",
+        957: "&nu;",
+        958: "&xi;",
+        959: "&omicron;",
+        960: "&pi;",
+        961: "&rho;",
+        962: "&sigmaf;",
+        963: "&sigma;",
+        964: "&tau;",
+        965: "&upsilon;",
+        966: "&phi;",
+        967: "&chi;",
+        968: "&psi;",
+        969: "&omega;",
+        977: "&thetasym;",
+        978: "&upsih;",
+        982: "&piv;",
+        8194: "&ensp;",
+        8195: "&emsp;",
+        8201: "&thinsp;",
+        8204: "&zwnj;",
+        8205: "&zwj;",
+        8206: "&lrm;",
+        8207: "&rlm;",
+        8211: "&ndash;",
+        8212: "&mdash;",
+        8216: "&lsquo;",
+        8217: "&rsquo;",
+        8218: "&sbquo;",
+        8220: "&ldquo;",
+        8221: "&rdquo;",
+        8222: "&bdquo;",
+        8224: "&dagger;",
+        8225: "&Dagger;",
+        8226: "&bull;",
+        8230: "&hellip;",
+        8240: "&permil;",
+        8242: "&prime;",
+        8243: "&Prime;",
+        8249: "&lsaquo;",
+        8250: "&rsaquo;",
+        8254: "&oline;",
+        8260: "&frasl;",
+        8364: "&euro;",
+        8465: "&image;",
+        8472: "&weierp;",
+        8476: "&real;",
+        8482: "&trade;",
+        8501: "&alefsym;",
+        8592: "&larr;",
+        8593: "&uarr;",
+        8594: "&rarr;",
+        8595: "&darr;",
+        8596: "&harr;",
+        8629: "&crarr;",
+        8656: "&lArr;",
+        8657: "&uArr;",
+        8658: "&rArr;",
+        8659: "&dArr;",
+        8660: "&hArr;",
+        8704: "&forall;",
+        8706: "&part;",
+        8707: "&exist;",
+        8709: "&empty;",
+        8711: "&nabla;",
+        8712: "&isin;",
+        8713: "&notin;",
+        8715: "&ni;",
+        8719: "&prod;",
+        8721: "&sum;",
+        8722: "&minus;",
+        8727: "&lowast;",
+        8730: "&radic;",
+        8733: "&prop;",
+        8734: "&infin;",
+        8736: "&ang;",
+        8743: "&and;",
+        8744: "&or;",
+        8745: "&cap;",
+        8746: "&cup;",
+        8747: "&int;",
+        8756: "&there4;",
+        8764: "&sim;",
+        8773: "&cong;",
+        8776: "&asymp;",
+        8800: "&ne;",
+        8801: "&equiv;",
+        8804: "&le;",
+        8805: "&ge;",
+        8834: "&sub;",
+        8835: "&sup;",
+        8836: "&nsub;",
+        8838: "&sube;",
+        8839: "&supe;",
+        8853: "&oplus;",
+        8855: "&otimes;",
+        8869: "&perp;",
+        8901: "&sdot;",
+        8942: "&vellip;",
+        8968: "&lceil;",
+        8969: "&rceil;",
+        8970: "&lfloor;",
+        8971: "&rfloor;",
+        9001: "&lang;",
+        9002: "&rang;",
+        9674: "&loz;",
+        9824: "&spades;",
+        9827: "&clubs;",
+        9829: "&hearts;",
+        9830: "&diams;",
     },
     },
 
 
 
 
@@ -594,261 +595,261 @@ const HTML = {
      * @private
      * @private
      * @constant
      * @constant
      */
      */
-    _entityToByte : {
-        "quot" : 34,
-        "amp" : 38,
-        "apos" : 39,
-        "lt" : 60,
-        "gt" : 62,
-        "nbsp" : 160,
-        "iexcl" : 161,
-        "cent" : 162,
-        "pound" : 163,
-        "curren" : 164,
-        "yen" : 165,
-        "brvbar" : 166,
-        "sect" : 167,
-        "uml" : 168,
-        "copy" : 169,
-        "ordf" : 170,
-        "laquo" : 171,
-        "not" : 172,
-        "shy" : 173,
-        "reg" : 174,
-        "macr" : 175,
-        "deg" : 176,
-        "plusmn" : 177,
-        "sup2" : 178,
-        "sup3" : 179,
-        "acute" : 180,
-        "micro" : 181,
-        "para" : 182,
-        "middot" : 183,
-        "cedil" : 184,
-        "sup1" : 185,
-        "ordm" : 186,
-        "raquo" : 187,
-        "frac14" : 188,
-        "frac12" : 189,
-        "frac34" : 190,
-        "iquest" : 191,
-        "Agrave" : 192,
-        "Aacute" : 193,
-        "Acirc" : 194,
-        "Atilde" : 195,
-        "Auml" : 196,
-        "Aring" : 197,
-        "AElig" : 198,
-        "Ccedil" : 199,
-        "Egrave" : 200,
-        "Eacute" : 201,
-        "Ecirc" : 202,
-        "Euml" : 203,
-        "Igrave" : 204,
-        "Iacute" : 205,
-        "Icirc" : 206,
-        "Iuml" : 207,
-        "ETH" : 208,
-        "Ntilde" : 209,
-        "Ograve" : 210,
-        "Oacute" : 211,
-        "Ocirc" : 212,
-        "Otilde" : 213,
-        "Ouml" : 214,
-        "times" : 215,
-        "Oslash" : 216,
-        "Ugrave" : 217,
-        "Uacute" : 218,
-        "Ucirc" : 219,
-        "Uuml" : 220,
-        "Yacute" : 221,
-        "THORN" : 222,
-        "szlig" : 223,
-        "agrave" : 224,
-        "aacute" : 225,
-        "acirc" : 226,
-        "atilde" : 227,
-        "auml" : 228,
-        "aring" : 229,
-        "aelig" : 230,
-        "ccedil" : 231,
-        "egrave" : 232,
-        "eacute" : 233,
-        "ecirc" : 234,
-        "euml" : 235,
-        "igrave" : 236,
-        "iacute" : 237,
-        "icirc" : 238,
-        "iuml" : 239,
-        "eth" : 240,
-        "ntilde" : 241,
-        "ograve" : 242,
-        "oacute" : 243,
-        "ocirc" : 244,
-        "otilde" : 245,
-        "ouml" : 246,
-        "divide" : 247,
-        "oslash" : 248,
-        "ugrave" : 249,
-        "uacute" : 250,
-        "ucirc" : 251,
-        "uuml" : 252,
-        "yacute" : 253,
-        "thorn" : 254,
-        "yuml" : 255,
-        "OElig" : 338,
-        "oelig" : 339,
-        "Scaron" : 352,
-        "scaron" : 353,
-        "Yuml" : 376,
-        "fnof" : 402,
-        "circ" : 710,
-        "tilde" : 732,
-        "Alpha" : 913,
-        "Beta" : 914,
-        "Gamma" : 915,
-        "Delta" : 916,
-        "Epsilon" : 917,
-        "Zeta" : 918,
-        "Eta" : 919,
-        "Theta" : 920,
-        "Iota" : 921,
-        "Kappa" : 922,
-        "Lambda" : 923,
-        "Mu" : 924,
-        "Nu" : 925,
-        "Xi" : 926,
-        "Omicron" : 927,
-        "Pi" : 928,
-        "Rho" : 929,
-        "Sigma" : 931,
-        "Tau" : 932,
-        "Upsilon" : 933,
-        "Phi" : 934,
-        "Chi" : 935,
-        "Psi" : 936,
-        "Omega" : 937,
-        "alpha" : 945,
-        "beta" : 946,
-        "gamma" : 947,
-        "delta" : 948,
-        "epsilon" : 949,
-        "zeta" : 950,
-        "eta" : 951,
-        "theta" : 952,
-        "iota" : 953,
-        "kappa" : 954,
-        "lambda" : 955,
-        "mu" : 956,
-        "nu" : 957,
-        "xi" : 958,
-        "omicron" : 959,
-        "pi" : 960,
-        "rho" : 961,
-        "sigmaf" : 962,
-        "sigma" : 963,
-        "tau" : 964,
-        "upsilon" : 965,
-        "phi" : 966,
-        "chi" : 967,
-        "psi" : 968,
-        "omega" : 969,
-        "thetasym" : 977,
-        "upsih" : 978,
-        "piv" : 982,
-        "ensp" : 8194,
-        "emsp" : 8195,
-        "thinsp" : 8201,
-        "zwnj" : 8204,
-        "zwj" : 8205,
-        "lrm" : 8206,
-        "rlm" : 8207,
-        "ndash" : 8211,
-        "mdash" : 8212,
-        "lsquo" : 8216,
-        "rsquo" : 8217,
-        "sbquo" : 8218,
-        "ldquo" : 8220,
-        "rdquo" : 8221,
-        "bdquo" : 8222,
-        "dagger" : 8224,
-        "Dagger" : 8225,
-        "bull" : 8226,
-        "hellip" : 8230,
-        "permil" : 8240,
-        "prime" : 8242,
-        "Prime" : 8243,
-        "lsaquo" : 8249,
-        "rsaquo" : 8250,
-        "oline" : 8254,
-        "frasl" : 8260,
-        "euro" : 8364,
-        "image" : 8465,
-        "weierp" : 8472,
-        "real" : 8476,
-        "trade" : 8482,
-        "alefsym" : 8501,
-        "larr" : 8592,
-        "uarr" : 8593,
-        "rarr" : 8594,
-        "darr" : 8595,
-        "harr" : 8596,
-        "crarr" : 8629,
-        "lArr" : 8656,
-        "uArr" : 8657,
-        "rArr" : 8658,
-        "dArr" : 8659,
-        "hArr" : 8660,
-        "forall" : 8704,
-        "part" : 8706,
-        "exist" : 8707,
-        "empty" : 8709,
-        "nabla" : 8711,
-        "isin" : 8712,
-        "notin" : 8713,
-        "ni" : 8715,
-        "prod" : 8719,
-        "sum" : 8721,
-        "minus" : 8722,
-        "lowast" : 8727,
-        "radic" : 8730,
-        "prop" : 8733,
-        "infin" : 8734,
-        "ang" : 8736,
-        "and" : 8743,
-        "or" : 8744,
-        "cap" : 8745,
-        "cup" : 8746,
-        "int" : 8747,
-        "there4" : 8756,
-        "sim" : 8764,
-        "cong" : 8773,
-        "asymp" : 8776,
-        "ne" : 8800,
-        "equiv" : 8801,
-        "le" : 8804,
-        "ge" : 8805,
-        "sub" : 8834,
-        "sup" : 8835,
-        "nsub" : 8836,
-        "sube" : 8838,
-        "supe" : 8839,
-        "oplus" : 8853,
-        "otimes" : 8855,
-        "perp" : 8869,
-        "sdot" : 8901,
-        "vellip" : 8942,
-        "lceil" : 8968,
-        "rceil" : 8969,
-        "lfloor" : 8970,
-        "rfloor" : 8971,
-        "lang" : 9001,
-        "rang" : 9002,
-        "loz" : 9674,
-        "spades" : 9824,
-        "clubs" : 9827,
-        "hearts" : 9829,
-        "diams" : 9830,
+    _entityToByte: {
+        "quot": 34,
+        "amp": 38,
+        "apos": 39,
+        "lt": 60,
+        "gt": 62,
+        "nbsp": 160,
+        "iexcl": 161,
+        "cent": 162,
+        "pound": 163,
+        "curren": 164,
+        "yen": 165,
+        "brvbar": 166,
+        "sect": 167,
+        "uml": 168,
+        "copy": 169,
+        "ordf": 170,
+        "laquo": 171,
+        "not": 172,
+        "shy": 173,
+        "reg": 174,
+        "macr": 175,
+        "deg": 176,
+        "plusmn": 177,
+        "sup2": 178,
+        "sup3": 179,
+        "acute": 180,
+        "micro": 181,
+        "para": 182,
+        "middot": 183,
+        "cedil": 184,
+        "sup1": 185,
+        "ordm": 186,
+        "raquo": 187,
+        "frac14": 188,
+        "frac12": 189,
+        "frac34": 190,
+        "iquest": 191,
+        "Agrave": 192,
+        "Aacute": 193,
+        "Acirc": 194,
+        "Atilde": 195,
+        "Auml": 196,
+        "Aring": 197,
+        "AElig": 198,
+        "Ccedil": 199,
+        "Egrave": 200,
+        "Eacute": 201,
+        "Ecirc": 202,
+        "Euml": 203,
+        "Igrave": 204,
+        "Iacute": 205,
+        "Icirc": 206,
+        "Iuml": 207,
+        "ETH": 208,
+        "Ntilde": 209,
+        "Ograve": 210,
+        "Oacute": 211,
+        "Ocirc": 212,
+        "Otilde": 213,
+        "Ouml": 214,
+        "times": 215,
+        "Oslash": 216,
+        "Ugrave": 217,
+        "Uacute": 218,
+        "Ucirc": 219,
+        "Uuml": 220,
+        "Yacute": 221,
+        "THORN": 222,
+        "szlig": 223,
+        "agrave": 224,
+        "aacute": 225,
+        "acirc": 226,
+        "atilde": 227,
+        "auml": 228,
+        "aring": 229,
+        "aelig": 230,
+        "ccedil": 231,
+        "egrave": 232,
+        "eacute": 233,
+        "ecirc": 234,
+        "euml": 235,
+        "igrave": 236,
+        "iacute": 237,
+        "icirc": 238,
+        "iuml": 239,
+        "eth": 240,
+        "ntilde": 241,
+        "ograve": 242,
+        "oacute": 243,
+        "ocirc": 244,
+        "otilde": 245,
+        "ouml": 246,
+        "divide": 247,
+        "oslash": 248,
+        "ugrave": 249,
+        "uacute": 250,
+        "ucirc": 251,
+        "uuml": 252,
+        "yacute": 253,
+        "thorn": 254,
+        "yuml": 255,
+        "OElig": 338,
+        "oelig": 339,
+        "Scaron": 352,
+        "scaron": 353,
+        "Yuml": 376,
+        "fnof": 402,
+        "circ": 710,
+        "tilde": 732,
+        "Alpha": 913,
+        "Beta": 914,
+        "Gamma": 915,
+        "Delta": 916,
+        "Epsilon": 917,
+        "Zeta": 918,
+        "Eta": 919,
+        "Theta": 920,
+        "Iota": 921,
+        "Kappa": 922,
+        "Lambda": 923,
+        "Mu": 924,
+        "Nu": 925,
+        "Xi": 926,
+        "Omicron": 927,
+        "Pi": 928,
+        "Rho": 929,
+        "Sigma": 931,
+        "Tau": 932,
+        "Upsilon": 933,
+        "Phi": 934,
+        "Chi": 935,
+        "Psi": 936,
+        "Omega": 937,
+        "alpha": 945,
+        "beta": 946,
+        "gamma": 947,
+        "delta": 948,
+        "epsilon": 949,
+        "zeta": 950,
+        "eta": 951,
+        "theta": 952,
+        "iota": 953,
+        "kappa": 954,
+        "lambda": 955,
+        "mu": 956,
+        "nu": 957,
+        "xi": 958,
+        "omicron": 959,
+        "pi": 960,
+        "rho": 961,
+        "sigmaf": 962,
+        "sigma": 963,
+        "tau": 964,
+        "upsilon": 965,
+        "phi": 966,
+        "chi": 967,
+        "psi": 968,
+        "omega": 969,
+        "thetasym": 977,
+        "upsih": 978,
+        "piv": 982,
+        "ensp": 8194,
+        "emsp": 8195,
+        "thinsp": 8201,
+        "zwnj": 8204,
+        "zwj": 8205,
+        "lrm": 8206,
+        "rlm": 8207,
+        "ndash": 8211,
+        "mdash": 8212,
+        "lsquo": 8216,
+        "rsquo": 8217,
+        "sbquo": 8218,
+        "ldquo": 8220,
+        "rdquo": 8221,
+        "bdquo": 8222,
+        "dagger": 8224,
+        "Dagger": 8225,
+        "bull": 8226,
+        "hellip": 8230,
+        "permil": 8240,
+        "prime": 8242,
+        "Prime": 8243,
+        "lsaquo": 8249,
+        "rsaquo": 8250,
+        "oline": 8254,
+        "frasl": 8260,
+        "euro": 8364,
+        "image": 8465,
+        "weierp": 8472,
+        "real": 8476,
+        "trade": 8482,
+        "alefsym": 8501,
+        "larr": 8592,
+        "uarr": 8593,
+        "rarr": 8594,
+        "darr": 8595,
+        "harr": 8596,
+        "crarr": 8629,
+        "lArr": 8656,
+        "uArr": 8657,
+        "rArr": 8658,
+        "dArr": 8659,
+        "hArr": 8660,
+        "forall": 8704,
+        "part": 8706,
+        "exist": 8707,
+        "empty": 8709,
+        "nabla": 8711,
+        "isin": 8712,
+        "notin": 8713,
+        "ni": 8715,
+        "prod": 8719,
+        "sum": 8721,
+        "minus": 8722,
+        "lowast": 8727,
+        "radic": 8730,
+        "prop": 8733,
+        "infin": 8734,
+        "ang": 8736,
+        "and": 8743,
+        "or": 8744,
+        "cap": 8745,
+        "cup": 8746,
+        "int": 8747,
+        "there4": 8756,
+        "sim": 8764,
+        "cong": 8773,
+        "asymp": 8776,
+        "ne": 8800,
+        "equiv": 8801,
+        "le": 8804,
+        "ge": 8805,
+        "sub": 8834,
+        "sup": 8835,
+        "nsub": 8836,
+        "sube": 8838,
+        "supe": 8839,
+        "oplus": 8853,
+        "otimes": 8855,
+        "perp": 8869,
+        "sdot": 8901,
+        "vellip": 8942,
+        "lceil": 8968,
+        "rceil": 8969,
+        "lfloor": 8970,
+        "rfloor": 8971,
+        "lang": 9001,
+        "rang": 9002,
+        "loz": 9674,
+        "spades": 9824,
+        "clubs": 9827,
+        "hearts": 9829,
+        "diams": 9830,
     },
     },
 
 
 };
 };

+ 23 - 23
src/core/operations/HTTP.js

@@ -125,30 +125,30 @@ const HTTP = {
         }
         }
 
 
         return fetch(url, config)
         return fetch(url, config)
-        .then(r => {
-            if (r.status === 0 && r.type === "opaque") {
-                return "Error: Null response. Try setting the connection mode to CORS.";
-            }
-
-            if (showResponseMetadata) {
-                let headers = "";
-                for (let pair of r.headers.entries()) {
-                    headers += "    " + pair[0] + ": " + pair[1] + "\n";
+            .then(r => {
+                if (r.status === 0 && r.type === "opaque") {
+                    return "Error: Null response. Try setting the connection mode to CORS.";
                 }
                 }
-                return r.text().then(b => {
-                    return "####\n  Status: " + r.status + " " + r.statusText +
-                        "\n  Exposed headers:\n" + headers + "####\n\n" + b;
-                });
-            }
-            return r.text();
-        })
-        .catch(e => {
-            return e.toString() +
-                "\n\nThis error could be caused by one of the following:\n" +
-                " - An invalid URL\n" +
-                " - Making a request to an insecure resource (HTTP) from a secure source (HTTPS)\n" +
-                " - Making a cross-origin request to a server which does not support CORS\n";
-        });
+
+                if (showResponseMetadata) {
+                    let headers = "";
+                    for (let pair of r.headers.entries()) {
+                        headers += "    " + pair[0] + ": " + pair[1] + "\n";
+                    }
+                    return r.text().then(b => {
+                        return "####\n  Status: " + r.status + " " + r.statusText +
+                            "\n  Exposed headers:\n" + headers + "####\n\n" + b;
+                    });
+                }
+                return r.text();
+            })
+            .catch(e => {
+                return e.toString() +
+                    "\n\nThis error could be caused by one of the following:\n" +
+                    " - An invalid URL\n" +
+                    " - Making a request to an insecure resource (HTTP) from a secure source (HTTPS)\n" +
+                    " - Making a cross-origin request to a server which does not support CORS\n";
+            });
     },
     },
 
 
 };
 };

+ 2 - 2
src/core/operations/IP.js

@@ -283,7 +283,7 @@ const IP = {
                     baIp.push(decimal & 255);
                     baIp.push(decimal & 255);
                     break;
                     break;
                 case "Hex":
                 case "Hex":
-                    baIp = Utils.hexToByteArray(lines[i]);
+                    baIp = Utils.fromHex(lines[i]);
                     break;
                     break;
                 default:
                 default:
                     throw "Unsupported input IP format";
                     throw "Unsupported input IP format";
@@ -516,7 +516,7 @@ const IP = {
             "<tr><td>Destination IP address</td><td>" + IP._ipv4ToStr(dstIP) + "</td></tr>";
             "<tr><td>Destination IP address</td><td>" + IP._ipv4ToStr(dstIP) + "</td></tr>";
 
 
         if (ihl > 5) {
         if (ihl > 5) {
-            output += "<tr><td>Options</td><td>" + Utils.byteArrayToHex(options) + "</td></tr>";
+            output += "<tr><td>Options</td><td>" + Utils.toHex(options) + "</td></tr>";
         }
         }
 
 
         return output + "</table>";
         return output + "</table>";

+ 4 - 4
src/core/operations/JS.js

@@ -1,4 +1,4 @@
-import esprima from "esprima";
+import * as esprima from "esprima";
 import escodegen from "escodegen";
 import escodegen from "escodegen";
 import esmangle from "esmangle";
 import esmangle from "esmangle";
 
 
@@ -62,7 +62,7 @@ const JS = {
                 tolerant: parseTolerant
                 tolerant: parseTolerant
             };
             };
 
 
-        result = esprima.parse(input, options);
+        result = esprima.parseScript(input, options);
         return JSON.stringify(result, null, 2);
         return JSON.stringify(result, null, 2);
     },
     },
 
 
@@ -104,7 +104,7 @@ const JS = {
             AST;
             AST;
 
 
         try {
         try {
-            AST = esprima.parse(input, {
+            AST = esprima.parseScript(input, {
                 range: true,
                 range: true,
                 tokens: true,
                 tokens: true,
                 comment: true
                 comment: true
@@ -142,7 +142,7 @@ const JS = {
      */
      */
     runMinify: function(input, args) {
     runMinify: function(input, args) {
         let result = "",
         let result = "",
-            AST = esprima.parse(input),
+            AST = esprima.parseScript(input),
             optimisedAST = esmangle.optimize(AST, null),
             optimisedAST = esmangle.optimize(AST, null),
             mangledAST = esmangle.mangle(optimisedAST);
             mangledAST = esmangle.mangle(optimisedAST);
 
 

+ 19 - 19
src/core/operations/OS.js

@@ -18,25 +18,25 @@ const OS = {
      */
      */
     runParseUnixPerms: function(input, args) {
     runParseUnixPerms: function(input, args) {
         let perms = {
         let perms = {
-                d : false,  // directory
-                sl : false, // symbolic link
-                np : false, // named pipe
-                s : false,  // socket
-                cd : false, // character device
-                bd : false, // block device
-                dr : false, // door
-                sb : false, // sticky bit
-                su : false, // setuid
-                sg : false, // setgid
-                ru : false, // read user
-                wu : false, // write user
-                eu : false, // execute user
-                rg : false, // read group
-                wg : false, // write group
-                eg : false, // execute group
-                ro : false, // read other
-                wo : false, // write other
-                eo : false // execute other
+                d:  false, // directory
+                sl: false, // symbolic link
+                np: false, // named pipe
+                s:  false, // socket
+                cd: false, // character device
+                bd: false, // block device
+                dr: false, // door
+                sb: false, // sticky bit
+                su: false, // setuid
+                sg: false, // setgid
+                ru: false, // read user
+                wu: false, // write user
+                eu: false, // execute user
+                rg: false, // read group
+                wg: false, // write group
+                eg: false, // execute group
+                ro: false, // read other
+                wo: false, // write other
+                eo: false  // execute other
             },
             },
             d = 0,
             d = 0,
             u = 0,
             u = 0,

Plik diff jest za duży
+ 519 - 539
src/core/operations/PublicKey.js


+ 7 - 7
src/core/operations/QuotedPrintable.js

@@ -61,7 +61,7 @@ const QuotedPrintable = {
      * @returns {byteArray}
      * @returns {byteArray}
      */
      */
     runFrom: function (input, args) {
     runFrom: function (input, args) {
-        const str = input.replace(/\=(?:\r?\n|$)/g, "");
+        const str = input.replace(/=(?:\r?\n|$)/g, "");
         return QuotedPrintable.mimeDecode(str);
         return QuotedPrintable.mimeDecode(str);
     },
     },
 
 
@@ -73,7 +73,7 @@ const QuotedPrintable = {
      * @returns {byteArray}
      * @returns {byteArray}
      */
      */
     mimeDecode: function(str) {
     mimeDecode: function(str) {
-        let encodedBytesCount = (str.match(/\=[\da-fA-F]{2}/g) || []).length,
+        let encodedBytesCount = (str.match(/=[\da-fA-F]{2}/g) || []).length,
             bufferLength = str.length - encodedBytesCount * 2,
             bufferLength = str.length - encodedBytesCount * 2,
             chr, hex,
             chr, hex,
             buffer = new Array(bufferLength),
             buffer = new Array(bufferLength),
@@ -219,21 +219,21 @@ const QuotedPrintable = {
                 result += line;
                 result += line;
                 pos += line.length;
                 pos += line.length;
                 continue;
                 continue;
-            } else if (line.length > lineLengthMax - lineMargin && (match = line.substr(-lineMargin).match(/[ \t\.,!\?][^ \t\.,!\?]*$/))) {
+            } else if (line.length > lineLengthMax - lineMargin && (match = line.substr(-lineMargin).match(/[ \t.,!?][^ \t.,!?]*$/))) {
                 // truncate to nearest space
                 // truncate to nearest space
                 line = line.substr(0, line.length - (match[0].length - 1));
                 line = line.substr(0, line.length - (match[0].length - 1));
             } else if (line.substr(-1) === "\r") {
             } else if (line.substr(-1) === "\r") {
                 line = line.substr(0, line.length - 1);
                 line = line.substr(0, line.length - 1);
             } else {
             } else {
-                if (line.match(/\=[\da-f]{0,2}$/i)) {
+                if (line.match(/=[\da-f]{0,2}$/i)) {
 
 
                     // push incomplete encoding sequences to the next line
                     // push incomplete encoding sequences to the next line
-                    if ((match = line.match(/\=[\da-f]{0,1}$/i))) {
+                    if ((match = line.match(/=[\da-f]{0,1}$/i))) {
                         line = line.substr(0, line.length - match[0].length);
                         line = line.substr(0, line.length - match[0].length);
                     }
                     }
 
 
                     // ensure that utf-8 sequences are not split
                     // ensure that utf-8 sequences are not split
-                    while (line.length > 3 && line.length < len - pos && !line.match(/^(?:=[\da-f]{2}){1,4}$/i) && (match = line.match(/\=[\da-f]{2}$/ig))) {
+                    while (line.length > 3 && line.length < len - pos && !line.match(/^(?:=[\da-f]{2}){1,4}$/i) && (match = line.match(/=[\da-f]{2}$/ig))) {
                         code = parseInt(match[0].substr(1, 2), 16);
                         code = parseInt(match[0].substr(1, 2), 16);
                         if (code < 128) {
                         if (code < 128) {
                             break;
                             break;
@@ -250,7 +250,7 @@ const QuotedPrintable = {
             }
             }
 
 
             if (pos + line.length < len && line.substr(-1) !== "\n") {
             if (pos + line.length < len && line.substr(-1) !== "\n") {
-                if (line.length === 76 && line.match(/\=[\da-f]{2}$/i)) {
+                if (line.length === 76 && line.match(/=[\da-f]{2}$/i)) {
                     line = line.substr(0, line.length - 3);
                     line = line.substr(0, line.length - 3);
                 } else if (line.length === 76) {
                 } else if (line.length === 76) {
                     line = line.substr(0, line.length - 1);
                     line = line.substr(0, line.length - 1);

+ 24 - 24
src/core/operations/StrUtils.js

@@ -193,17 +193,17 @@ const StrUtils = {
      * @constant
      * @constant
      * @default
      * @default
      */
      */
-    FIND_REPLACE_GLOBAL : true,
+    FIND_REPLACE_GLOBAL: true,
     /**
     /**
      * @constant
      * @constant
      * @default
      * @default
      */
      */
-    FIND_REPLACE_CASE : false,
+    FIND_REPLACE_CASE: false,
     /**
     /**
      * @constant
      * @constant
      * @default
      * @default
      */
      */
-    FIND_REPLACE_MULTILINE : true,
+    FIND_REPLACE_MULTILINE: true,
 
 
     /**
     /**
      * Find / Replace operation.
      * Find / Replace operation.
@@ -359,9 +359,9 @@ const StrUtils = {
 
 
         for (let i = 0; i < diff.length; i++) {
         for (let i = 0; i < diff.length; i++) {
             if (diff[i].added) {
             if (diff[i].added) {
-                if (showAdded) output += "<span class='hlgreen'>" + Utils.escapeHtml(diff[i].value) + "</span>";
+                if (showAdded) output += "<span class='hl5'>" + Utils.escapeHtml(diff[i].value) + "</span>";
             } else if (diff[i].removed) {
             } else if (diff[i].removed) {
-                if (showRemoved) output += "<span class='hlred'>" + Utils.escapeHtml(diff[i].value) + "</span>";
+                if (showRemoved) output += "<span class='hl3'>" + Utils.escapeHtml(diff[i].value) + "</span>";
             } else {
             } else {
                 output += Utils.escapeHtml(diff[i].value);
                 output += Utils.escapeHtml(diff[i].value);
             }
             }
@@ -424,7 +424,7 @@ const StrUtils = {
                 }
                 }
 
 
                 if (match && !inMatch) {
                 if (match && !inMatch) {
-                    outputs[s] += "<span class='hlgreen'>" + Utils.escapeHtml(samples[s][i]);
+                    outputs[s] += "<span class='hl5'>" + Utils.escapeHtml(samples[s][i]);
                     if (samples[s].length === i + 1) outputs[s] += "</span>";
                     if (samples[s].length === i + 1) outputs[s] += "</span>";
                     if (s === samples.length - 1) inMatch = true;
                     if (s === samples.length - 1) inMatch = true;
                 } else if (!match && inMatch) {
                 } else if (!match && inMatch) {
@@ -476,16 +476,16 @@ const StrUtils = {
         const splitInput = input.split(delimiter);
         const splitInput = input.split(delimiter);
 
 
         return splitInput
         return splitInput
-        .filter((line, lineIndex) => {
-            lineIndex += 1;
+            .filter((line, lineIndex) => {
+                lineIndex += 1;
 
 
-            if (number < 0) {
-                return lineIndex <= splitInput.length + number;
-            } else {
-                return lineIndex <= number;
-            }
-        })
-        .join(delimiter);
+                if (number < 0) {
+                    return lineIndex <= splitInput.length + number;
+                } else {
+                    return lineIndex <= number;
+                }
+            })
+            .join(delimiter);
     },
     },
 
 
 
 
@@ -504,16 +504,16 @@ const StrUtils = {
         const splitInput = input.split(delimiter);
         const splitInput = input.split(delimiter);
 
 
         return splitInput
         return splitInput
-        .filter((line, lineIndex) => {
-            lineIndex += 1;
+            .filter((line, lineIndex) => {
+                lineIndex += 1;
 
 
-            if (number < 0) {
-                return lineIndex > -number;
-            } else {
-                return lineIndex > splitInput.length - number;
-            }
-        })
-        .join(delimiter);
+                if (number < 0) {
+                    return lineIndex > -number;
+                } else {
+                    return lineIndex > splitInput.length - number;
+                }
+            })
+            .join(delimiter);
     },
     },
 
 
 
 

+ 12 - 12
src/core/operations/Tidy.js

@@ -16,32 +16,32 @@ const Tidy = {
      * @constant
      * @constant
      * @default
      * @default
      */
      */
-    REMOVE_SPACES : true,
+    REMOVE_SPACES: true,
     /**
     /**
      * @constant
      * @constant
      * @default
      * @default
      */
      */
-    REMOVE_CARIAGE_RETURNS : true,
+    REMOVE_CARIAGE_RETURNS: true,
     /**
     /**
      * @constant
      * @constant
      * @default
      * @default
      */
      */
-    REMOVE_LINE_FEEDS : true,
+    REMOVE_LINE_FEEDS: true,
     /**
     /**
      * @constant
      * @constant
      * @default
      * @default
      */
      */
-    REMOVE_TABS : true,
+    REMOVE_TABS: true,
     /**
     /**
      * @constant
      * @constant
      * @default
      * @default
      */
      */
-    REMOVE_FORM_FEEDS : true,
+    REMOVE_FORM_FEEDS: true,
     /**
     /**
      * @constant
      * @constant
      * @default
      * @default
      */
      */
-    REMOVE_FULL_STOPS : false,
+    REMOVE_FULL_STOPS: false,
 
 
     /**
     /**
      * Remove whitespace operation.
      * Remove whitespace operation.
@@ -89,17 +89,17 @@ const Tidy = {
      * @constant
      * @constant
      * @default
      * @default
      */
      */
-    APPLY_TO_EACH_LINE : false,
+    APPLY_TO_EACH_LINE: false,
     /**
     /**
      * @constant
      * @constant
      * @default
      * @default
      */
      */
-    DROP_START : 0,
+    DROP_START: 0,
     /**
     /**
      * @constant
      * @constant
      * @default
      * @default
      */
      */
-    DROP_LENGTH : 5,
+    DROP_LENGTH: 5,
 
 
     /**
     /**
      * Drop bytes operation.
      * Drop bytes operation.
@@ -200,17 +200,17 @@ const Tidy = {
      * @constant
      * @constant
      * @default
      * @default
      */
      */
-    PAD_POSITION : ["Start", "End"],
+    PAD_POSITION: ["Start", "End"],
     /**
     /**
      * @constant
      * @constant
      * @default
      * @default
      */
      */
-    PAD_LENGTH : 5,
+    PAD_LENGTH: 5,
     /**
     /**
      * @constant
      * @constant
      * @default
      * @default
      */
      */
-    PAD_CHAR : " ",
+    PAD_CHAR: " ",
 
 
     /**
     /**
      * Pad lines operation.
      * Pad lines operation.

+ 1 - 1
src/core/operations/URL.js

@@ -127,7 +127,7 @@ const URL_ = {
             .replace(/\(/g, "%28")
             .replace(/\(/g, "%28")
             .replace(/\)/g, "%29")
             .replace(/\)/g, "%29")
             .replace(/\*/g, "%2A")
             .replace(/\*/g, "%2A")
-            .replace(/\-/g, "%2D")
+            .replace(/-/g, "%2D")
             .replace(/\./g, "%2E")
             .replace(/\./g, "%2E")
             .replace(/_/g, "%5F")
             .replace(/_/g, "%5F")
             .replace(/~/g, "%7E");
             .replace(/~/g, "%7E");

+ 6 - 6
src/node/index.js

@@ -14,12 +14,12 @@ const CyberChef = module.exports = {
     bake: function(input, recipeConfig) {
     bake: function(input, recipeConfig) {
         this.chef = new Chef();
         this.chef = new Chef();
         return this.chef.bake(
         return this.chef.bake(
-		input,
-		recipeConfig,
-		{},
-		0,
-		false
-	);
+            input,
+            recipeConfig,
+            {},
+            0,
+            false
+        );
     }
     }
 
 
 };
 };

+ 33 - 20
src/web/App.js

@@ -266,13 +266,7 @@ App.prototype.silentBake = function() {
  * @returns {string}
  * @returns {string}
  */
  */
 App.prototype.getInput = function() {
 App.prototype.getInput = function() {
-    const input = this.manager.input.get();
-
-    // Save to session storage in case we need to restore it later
-    sessionStorage.setItem("inputLength", input.length);
-    sessionStorage.setItem("input", input);
-
-    return input;
+    return this.manager.input.get();
 };
 };
 
 
 
 
@@ -282,8 +276,6 @@ App.prototype.getInput = function() {
  * @param {string} input - The string to set the input to
  * @param {string} input - The string to set the input to
  */
  */
 App.prototype.setInput = function(input) {
 App.prototype.setInput = function(input) {
-    sessionStorage.setItem("inputLength", input.length);
-    sessionStorage.setItem("input", input);
     this.manager.input.set(input);
     this.manager.input.set(input);
 };
 };
 
 
@@ -466,7 +458,12 @@ App.prototype.addFavourite = function(name) {
  */
  */
 App.prototype.loadURIParams = function() {
 App.prototype.loadURIParams = function() {
     // Load query string or hash from URI (depending on which is populated)
     // Load query string or hash from URI (depending on which is populated)
-    const params = window.location.search || window.location.hash;
+    // We prefer getting the hash by splitting the href rather than referencing
+    // location.hash as some browsers (Firefox) automatically URL decode it,
+    // which cause issues.
+    const params = window.location.search ||
+        window.location.href.split("#")[1] ||
+        window.location.hash;
     this.uriParams = Utils.parseURIParams(params);
     this.uriParams = Utils.parseURIParams(params);
 
 
     // Pause auto-bake while loading but don't modify `this.autoBake_`
     // Pause auto-bake while loading but don't modify `this.autoBake_`
@@ -529,9 +526,7 @@ App.prototype.nextIngId = function() {
  * @returns {Object[]}
  * @returns {Object[]}
  */
  */
 App.prototype.getRecipeConfig = function() {
 App.prototype.getRecipeConfig = function() {
-    const recipeConfig = this.manager.recipe.getConfig();
-    sessionStorage.setItem("recipeConfig", JSON.stringify(recipeConfig));
-    return recipeConfig;
+    return this.manager.recipe.getConfig();
 };
 };
 
 
 
 
@@ -541,7 +536,6 @@ App.prototype.getRecipeConfig = function() {
  * @param {Object[]} recipeConfig - The recipe configuration
  * @param {Object[]} recipeConfig - The recipe configuration
  */
  */
 App.prototype.setRecipeConfig = function(recipeConfig) {
 App.prototype.setRecipeConfig = function(recipeConfig) {
-    sessionStorage.setItem("recipeConfig", JSON.stringify(recipeConfig));
     document.getElementById("rec-list").innerHTML = null;
     document.getElementById("rec-list").innerHTML = null;
 
 
     for (let i = 0; i < recipeConfig.length; i++) {
     for (let i = 0; i < recipeConfig.length; i++) {
@@ -596,15 +590,24 @@ App.prototype.resetLayout = function() {
 App.prototype.setCompileMessage = function() {
 App.prototype.setCompileMessage = function() {
     // Display time since last build and compile message
     // Display time since last build and compile message
     let now = new Date(),
     let now = new Date(),
-        timeSinceCompile = Utils.fuzzyTime(now.getTime() - window.compileTime),
-        compileInfo = "<span style=\"font-weight: normal\">Last build: " +
-            timeSinceCompile.substr(0, 1).toUpperCase() + timeSinceCompile.substr(1) + " ago";
+        timeSinceCompile = Utils.fuzzyTime(now.getTime() - window.compileTime);
+
+    // Calculate previous version to compare to
+    let prev = PKG_VERSION.split(".").map(n => {
+        return parseInt(n, 10);
+    });
+    if (prev[2] > 0) prev[2]--;
+    else if (prev[1] > 0) prev[1]--;
+    else prev[0]--;
+
+    const compareURL = `https://github.com/gchq/CyberChef/compare/v${prev.join(".")}...v${PKG_VERSION}`;
+
+    let compileInfo = `<a href='${compareURL}'>Last build: ${timeSinceCompile.substr(0, 1).toUpperCase() + timeSinceCompile.substr(1)} ago</a>`;
 
 
     if (window.compileMessage !== "") {
     if (window.compileMessage !== "") {
         compileInfo += " - " + window.compileMessage;
         compileInfo += " - " + window.compileMessage;
     }
     }
 
 
-    compileInfo += "</span>";
     document.getElementById("notice").innerHTML = compileInfo;
     document.getElementById("notice").innerHTML = compileInfo;
 };
 };
 
 
@@ -729,10 +732,20 @@ App.prototype.alertCloseClick = function() {
 App.prototype.stateChange = function(e) {
 App.prototype.stateChange = function(e) {
     this.autoBake();
     this.autoBake();
 
 
+    // Set title
+    const recipeConfig = this.getRecipeConfig();
+    let title = "CyberChef";
+    if (recipeConfig.length === 1) {
+        title = `${recipeConfig[0].op} - ${title}`;
+    } else if (recipeConfig.length > 1) {
+        title = `${recipeConfig.length} operations - ${title}`;
+    }
+    document.title = title;
+
     // Update the current history state (not creating a new one)
     // Update the current history state (not creating a new one)
     if (this.options.updateUrl) {
     if (this.options.updateUrl) {
-        this.lastStateUrl = this.manager.controls.generateStateUrl(true, true);
-        window.history.replaceState({}, "CyberChef", this.lastStateUrl);
+        this.lastStateUrl = this.manager.controls.generateStateUrl(true, true, recipeConfig);
+        window.history.replaceState({}, title, this.lastStateUrl);
     }
     }
 };
 };
 
 

+ 6 - 6
src/web/ControlsWaiter.js

@@ -181,9 +181,9 @@ ControlsWaiter.prototype.generateStateUrl = function(includeRecipe, includeInput
     ];
     ];
 
 
     const hash = params
     const hash = params
-       .filter(v => v)
-       .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
-       .join("&");
+        .filter(v => v)
+        .map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
+        .join("&");
 
 
     if (hash) {
     if (hash) {
         return `${link}#${hash}`;
         return `${link}#${hash}`;
@@ -286,7 +286,7 @@ ControlsWaiter.prototype.populateLoadRecipesList = function() {
 
 
     // Add recipes to select
     // Add recipes to select
     const savedRecipes = localStorage.savedRecipes ?
     const savedRecipes = localStorage.savedRecipes ?
-            JSON.parse(localStorage.savedRecipes) : [];
+        JSON.parse(localStorage.savedRecipes) : [];
 
 
     for (i = 0; i < savedRecipes.length; i++) {
     for (i = 0; i < savedRecipes.length; i++) {
         const opt = document.createElement("option");
         const opt = document.createElement("option");
@@ -308,7 +308,7 @@ ControlsWaiter.prototype.populateLoadRecipesList = function() {
 ControlsWaiter.prototype.loadDeleteClick = function() {
 ControlsWaiter.prototype.loadDeleteClick = function() {
     const id = parseInt(document.getElementById("load-name").value, 10);
     const id = parseInt(document.getElementById("load-name").value, 10);
     const rawSavedRecipes = localStorage.savedRecipes ?
     const rawSavedRecipes = localStorage.savedRecipes ?
-            JSON.parse(localStorage.savedRecipes) : [];
+        JSON.parse(localStorage.savedRecipes) : [];
 
 
     const savedRecipes = rawSavedRecipes.filter(r => r.id !== id);
     const savedRecipes = rawSavedRecipes.filter(r => r.id !== id);
 
 
@@ -323,7 +323,7 @@ ControlsWaiter.prototype.loadDeleteClick = function() {
 ControlsWaiter.prototype.loadNameChange = function(e) {
 ControlsWaiter.prototype.loadNameChange = function(e) {
     const el = e.target;
     const el = e.target;
     const savedRecipes = localStorage.savedRecipes ?
     const savedRecipes = localStorage.savedRecipes ?
-            JSON.parse(localStorage.savedRecipes) : [];
+        JSON.parse(localStorage.savedRecipes) : [];
     const id = parseInt(el.value, 10);
     const id = parseInt(el.value, 10);
 
 
     const recipe = savedRecipes.find(r => r.id === id);
     const recipe = savedRecipes.find(r => r.id === id);

+ 8 - 7
src/web/HighlighterWaiter.js

@@ -493,13 +493,14 @@ HighlighterWaiter.prototype.highlight = function(textarea, highlighter, pos) {
     //if (colour) cssClass += "-"+colour;
     //if (colour) cssClass += "-"+colour;
 
 
     // Remove HTML tags
     // Remove HTML tags
-    text = text.replace(/&/g, "&amp;")
-                .replace(/</g, "&lt;")
-                .replace(/>/g, "&gt;")
-                .replace(/\n/g, "&#10;")
-                // Convert placeholders to tags
-                .replace(startPlaceholderRegex, "<span class=\""+cssClass+"\">")
-                .replace(endPlaceholderRegex, "</span>") + "&nbsp;";
+    text = text
+        .replace(/&/g, "&amp;")
+        .replace(/</g, "&lt;")
+        .replace(/>/g, "&gt;")
+        .replace(/\n/g, "&#10;")
+        // Convert placeholders to tags
+        .replace(startPlaceholderRegex, "<span class=\""+cssClass+"\">")
+        .replace(endPlaceholderRegex, "</span>") + "&nbsp;";
 
 
     // Adjust width to allow for scrollbars
     // Adjust width to allow for scrollbars
     highlighter.style.width = textarea.clientWidth + "px";
     highlighter.style.width = textarea.clientWidth + "px";

+ 1 - 1
src/web/InputWaiter.js

@@ -166,7 +166,7 @@ InputWaiter.prototype.inputDrop = function(e) {
         this.set(inputCharcode);
         this.set(inputCharcode);
         const recipeConfig = this.app.getRecipeConfig();
         const recipeConfig = this.app.getRecipeConfig();
         if (!recipeConfig[0] || recipeConfig[0].op !== "From Hex") {
         if (!recipeConfig[0] || recipeConfig[0].op !== "From Hex") {
-            recipeConfig.unshift({op:"From Hex", args:["Space"]});
+            recipeConfig.unshift({op: "From Hex", args: ["Space"]});
             this.app.setRecipeConfig(recipeConfig);
             this.app.setRecipeConfig(recipeConfig);
         }
         }
 
 

+ 1 - 0
src/web/Manager.js

@@ -145,6 +145,7 @@ Manager.prototype.initialiseEventListeners = function() {
     document.getElementById("output-html").addEventListener("mousemove", this.highlighter.outputHtmlMousemove.bind(this.highlighter));
     document.getElementById("output-html").addEventListener("mousemove", this.highlighter.outputHtmlMousemove.bind(this.highlighter));
     this.addMultiEventListener("#output-text", "mousedown dblclick select",  this.highlighter.outputMousedown, this.highlighter);
     this.addMultiEventListener("#output-text", "mousedown dblclick select",  this.highlighter.outputMousedown, this.highlighter);
     this.addMultiEventListener("#output-html", "mousedown dblclick select",  this.highlighter.outputHtmlMousedown, this.highlighter);
     this.addMultiEventListener("#output-html", "mousedown dblclick select",  this.highlighter.outputHtmlMousedown, this.highlighter);
+    this.addDynamicListener(".file-switch", "click", this.output.fileSwitch, this.output);
 
 
     // Options
     // Options
     document.getElementById("options").addEventListener("click", this.options.optionsClick.bind(this.options));
     document.getElementById("options").addEventListener("click", this.options.optionsClick.bind(this.options));

+ 11 - 0
src/web/OutputWaiter.js

@@ -167,6 +167,17 @@ OutputWaiter.prototype.undoSwitchClick = function() {
     document.getElementById("undo-switch").disabled = true;
     document.getElementById("undo-switch").disabled = true;
 };
 };
 
 
+/**
+ * Handler for file switch click events.
+ * Moves a files data for items created via Utils.displayFilesAsHTML to the input.
+ */
+OutputWaiter.prototype.fileSwitch = function(e) {
+    e.preventDefault();
+    this.switchOrigData = this.manager.input.get();
+    this.app.setInput(e.target.getAttribute("fileValue"));
+    document.getElementById("undo-switch").disabled = false;
+};
+
 
 
 /**
 /**
  * Handler for maximise output click events.
  * Handler for maximise output click events.

+ 45 - 32
src/web/html/index.html

@@ -26,12 +26,14 @@
         <title>CyberChef</title>
         <title>CyberChef</title>
         
         
         <meta name="copyright" content="Crown Copyright 2016" />
         <meta name="copyright" content="Crown Copyright 2016" />
-        <meta name="description" content="The Cyber Swiss Army Knife" />
+        <meta name="description" content="The Cyber Swiss Army Knife - a web app for encryption, encoding, compression and data analysis" />
         <meta name="keywords" content="base64, hex, decode, encode, encrypt, decrypt, compress, decompress, regex, regular expressions, hash, crypt, hexadecimal, user agent, url, certificate, x.509, parser, JSON, gzip,  md5, sha1, aes, des, blowfish, xor" />
         <meta name="keywords" content="base64, hex, decode, encode, encrypt, decrypt, compress, decompress, regex, regular expressions, hash, crypt, hexadecimal, user agent, url, certificate, x.509, parser, JSON, gzip,  md5, sha1, aes, des, blowfish, xor" />
 
 
         <link rel="icon" type="image/ico" href="<%- require('../static/images/favicon.ico') %>" />
         <link rel="icon" type="image/ico" href="<%- require('../static/images/favicon.ico') %>" />
 
 
         <script type="application/javascript">
         <script type="application/javascript">
+            "use strict";
+
             // Load theme before the preloader is shown
             // Load theme before the preloader is shown
             document.querySelector(":root").className = (JSON.parse(localStorage.getItem("options")) || {}).theme;
             document.querySelector(":root").className = (JSON.parse(localStorage.getItem("options")) || {}).theme;
 
 
@@ -72,6 +74,11 @@
             changeLoadingMsg();
             changeLoadingMsg();
             window.loadingMsgsInt = setInterval(changeLoadingMsg, (Math.random() * 1000) + 1000);
             window.loadingMsgsInt = setInterval(changeLoadingMsg, (Math.random() * 1000) + 1000);
         </script>
         </script>
+        <% if (!htmlWebpackPlugin.options.inline) { %>
+            <script type="application/ld+json">
+                <% print(JSON.stringify(require("../static/structuredData.json"))); %>
+            </script>
+        <% } %>
     </head>
     </head>
     <body>
     <body>
         <!-- Preloader overlay -->
         <!-- Preloader overlay -->
@@ -87,23 +94,29 @@
         </div>
         </div>
         <div id="content-wrapper">
         <div id="content-wrapper">
             <div id="banner">
             <div id="banner">
-                <% if (htmlWebpackPlugin.options.inline) { %>
-                    <span style="float: left; margin-left: 10px;">Compile time: <%= htmlWebpackPlugin.options.compileTime %></span>
-                <% } else { %>
-                    <a href="cyberchef.htm" style="float: left; margin-left: 10px; margin-right: 80px;" download>Download CyberChef<img aria-hidden="true" src="<%- require('../static/images/download-24x24.png') %>" alt="Download Icon"/></a>
-                <% } %>
-                <span id="notice">
-                    <script type="text/javascript">
-                        // Must be text/javascript rather than application/javascript otherwise IE won't recognise it...
-                        if (navigator.userAgent && navigator.userAgent.match(/MSIE \d\d?\./)) {
-                            document.write("Internet Explorer is not supported, please use Firefox or Chrome instead");
-                            alert("Internet Explorer is not supported, please use Firefox or Chrome instead");
-                        }
-                    </script>
-                    <noscript>JavaScript is not enabled. Good luck.</noscript>
-                </span>
-                <a href="#" id="support" class="banner-right" data-toggle="modal" data-target="#support-modal">About / Support<img aria-hidden="true" src="<%- require('../static/images/help-22x22.png') %>" alt="Question Mark Icon"/></a>
-                <a href="#" id="options" class="banner-right">Options<img aria-hidden="true" src="<%- require('../static/images/settings-22x22.png') %>" alt="Settings Icon"/></a>
+                <div class="col-md-4" style="text-align: left; padding-left: 10px;">
+                    <% if (htmlWebpackPlugin.options.inline) { %>
+                        <span>Version <%= htmlWebpackPlugin.options.version %></span>
+                    <% } else { %>
+                        <a href="cyberchef.htm" download>Download CyberChef<img aria-hidden="true" src="<%- require('../static/images/download-24x24.png') %>" alt="Download Icon"/></a>
+                    <% } %>
+                </div>
+                <div class="col-md-4" style="text-align: center;">
+                    <span id="notice">
+                        <script type="text/javascript">
+                            // Must be text/javascript rather than application/javascript otherwise IE won't recognise it...
+                            if (navigator.userAgent && navigator.userAgent.match(/MSIE \d\d?\./)) {
+                                document.write("Internet Explorer is not supported, please use Firefox or Chrome instead");
+                                alert("Internet Explorer is not supported, please use Firefox or Chrome instead");
+                            }
+                        </script>
+                        <noscript>JavaScript is not enabled. Good luck.</noscript>
+                    </span>
+                </div>
+                <div class="col-md-4" style="text-align: right; padding-right: 0;">
+                    <a href="#" id="options">Options<img aria-hidden="true" src="<%- require('../static/images/settings-22x22.png') %>" alt="Settings Icon"/></a>
+                    <a href="#" id="support" data-toggle="modal" data-target="#support-modal">About / Support<img aria-hidden="true" src="<%- require('../static/images/help-22x22.png') %>" alt="Question Mark Icon"/></a>
+                </div>
             </div>
             </div>
             <div id="workspace-wrapper">
             <div id="workspace-wrapper">
                 <div id="operations" class="split split-horizontal no-select">
                 <div id="operations" class="split split-horizontal no-select">
@@ -266,32 +279,32 @@
                             <label for="theme"> Theme (only supported in modern browsers)</label>
                             <label for="theme"> Theme (only supported in modern browsers)</label>
                         </div>
                         </div>
                         <div class="option-item">
                         <div class="option-item">
-                            <input type="checkbox" option="update_url" id="update_url" checked />
-                            <label for="update_url"> Update the URL when the input or recipe changes </label>
+                            <input type="checkbox" option="updateUrl" id="updateUrl" checked />
+                            <label for="updateUrl"> Update the URL when the input or recipe changes </label>
                         </div>
                         </div>
                         <div class="option-item">
                         <div class="option-item">
-                            <input type="checkbox" option="show_highlighter" id="show_highlighter" checked />
-                            <label for="show_highlighter"> Highlight selected bytes in output and input (when possible) </label>
+                            <input type="checkbox" option="showHighlighter" id="showHighlighter" checked />
+                            <label for="showHighlighter"> Highlight selected bytes in output and input (when possible) </label>
                         </div>
                         </div>
                         <div class="option-item">
                         <div class="option-item">
-                            <input type="checkbox" option="treat_as_utf8" id="treat_as_utf8" checked />
-                            <label for="treat_as_utf8"> Treat output as UTF-8 if possible </label>
+                            <input type="checkbox" option="treatAsUtf8" id="treatAsUtf8" checked />
+                            <label for="treatAsUtf8"> Treat output as UTF-8 if possible </label>
                         </div>
                         </div>
                         <div class="option-item">
                         <div class="option-item">
-                            <input type="checkbox" option="word_wrap" id="word_wrap" checked />
-                            <label for="word_wrap"> Word wrap the input and output </label>
+                            <input type="checkbox" option="wordWrap" id="wordWrap" checked />
+                            <label for="wordWrap"> Word wrap the input and output </label>
                         </div>
                         </div>
                         <div class="option-item">
                         <div class="option-item">
-                            <input type="checkbox" option="show_errors" id="show_errors" checked />
-                            <label for="show_errors"> Operation error reporting (recommended) </label>
+                            <input type="checkbox" option="showErrors" id="showErrors" checked />
+                            <label for="showErrors"> Operation error reporting (recommended) </label>
                         </div>
                         </div>
                         <div class="option-item">
                         <div class="option-item">
-                            <input type="number" option="error_timeout" id="error_timeout" />
-                            <label for="error_timeout"> Operation error timeout in ms (0 for never) </label>
+                            <input type="number" option="errorTimeout" id="errorTimeout" />
+                            <label for="errorTimeout"> Operation error timeout in ms (0 for never) </label>
                         </div>
                         </div>
                         <div class="option-item">
                         <div class="option-item">
-                            <input type="number" option="auto_bake_threshold" id="auto_bake_threshold"/>
-                            <label for="auto_bake_threshold"> Auto Bake threshold in ms </label>
+                            <input type="number" option="autoBakeThreshold" id="autoBakeThreshold"/>
+                            <label for="autoBakeThreshold"> Auto Bake threshold in ms </label>
                         </div>
                         </div>
                     </div>
                     </div>
                     <div class="modal-footer">
                     <div class="modal-footer">

+ 9 - 9
src/web/index.js

@@ -38,15 +38,15 @@ function main() {
     ];
     ];
 
 
     const defaultOptions = {
     const defaultOptions = {
-        updateUrl         : true,
-        showHighlighter   : true,
-        treatAsUtf8       : true,
-        wordWrap          : true,
-        showErrors        : true,
-        errorTimeout      : 4000,
-        autoBakeThreshold : 200,
-        attemptHighlight  : true,
-        theme             : "classic",
+        updateUrl:         true,
+        showHighlighter:   true,
+        treatAsUtf8:       true,
+        wordWrap:          true,
+        showErrors:        true,
+        errorTimeout:      4000,
+        autoBakeThreshold: 200,
+        attemptHighlight:  true,
+        theme:             "classic",
     };
     };
 
 
     document.removeEventListener("DOMContentLoaded", main, false);
     document.removeEventListener("DOMContentLoaded", main, false);

+ 23 - 0
src/web/static/structuredData.json

@@ -0,0 +1,23 @@
+[
+    {
+        "@context": "http://schema.org",
+        "@type": "Organization",
+        "url": "https://gchq.github.io/CyberChef/",
+        "logo": "https://gchq.github.io/CyberChef/images/cyberchef-128x128.png",
+        "sameAs": [
+            "https://github.com/gchq/CyberChef",
+            "https://www.npmjs.com/package/cyberchef"
+        ]
+    },
+    {
+        "@context": "http://schema.org",
+        "@type": "WebSite",
+        "url": "https://gchq.github.io/CyberChef/",
+        "name": "CyberChef",
+        "potentialAction": {
+            "@type": "SearchAction",
+            "target": "https://gchq.github.io/CyberChef/?op={operation_search_term}",
+            "query-input": "required name=operation_search_term"
+        }
+    }
+]

+ 1 - 0
src/web/stylesheets/components/_operation.css

@@ -59,6 +59,7 @@
     background-color: var(--arg-background);
     background-color: var(--arg-background);
     border: 1px solid var(--arg-border-colour);
     border: 1px solid var(--arg-border-colour);
     font-family: var(--fixed-width-font-family);
     font-family: var(--fixed-width-font-family);
+    text-overflow: ellipsis;
 }
 }
 
 
 .short-string {
 .short-string {

+ 2 - 6
src/web/stylesheets/layout/_banner.css

@@ -10,19 +10,15 @@
     position: absolute;
     position: absolute;
     height: 30px;
     height: 30px;
     width: 100%;
     width: 100%;
-    text-align: center;
     line-height: 30px;
     line-height: 30px;
     border-bottom: 1px solid var(--primary-border-colour);
     border-bottom: 1px solid var(--primary-border-colour);
     color: var(--banner-font-colour);
     color: var(--banner-font-colour);
     background-color: var(--banner-bg-colour);
     background-color: var(--banner-bg-colour);
 }
 }
 
 
-.banner-right {
-    float: right;
-    margin-right: 10px;
-}
-
 #banner img {
 #banner img {
     margin-bottom: 2px;
     margin-bottom: 2px;
     margin-left: 8px;
     margin-left: 8px;
+    padding-right: 10px;
 }
 }
+

+ 1 - 2
test/TestRegister.js

@@ -46,8 +46,7 @@ import Chef from "../src/core/Chef.js";
                     {},
                     {},
                     0,
                     0,
                     false
                     false
-                )
-                .then(function(result) {
+                ).then(function(result) {
                     const ret = {
                     const ret = {
                         test: test,
                         test: test,
                         status: null,
                         status: null,

+ 1 - 0
test/index.js

@@ -12,6 +12,7 @@ import "babel-polyfill";
 
 
 import TestRegister from "./TestRegister.js";
 import TestRegister from "./TestRegister.js";
 import "./tests/operations/Base58.js";
 import "./tests/operations/Base58.js";
+import "./tests/operations/BCD.js";
 import "./tests/operations/ByteRepr.js";
 import "./tests/operations/ByteRepr.js";
 import "./tests/operations/CharEnc.js";
 import "./tests/operations/CharEnc.js";
 import "./tests/operations/Cipher.js";
 import "./tests/operations/Cipher.js";

+ 103 - 0
test/tests/operations/BCD.js

@@ -0,0 +1,103 @@
+/**
+ * BCD tests
+ *
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2017
+ * @license Apache-2.0
+ */
+import TestRegister from "../../TestRegister.js";
+
+TestRegister.addTests([
+    {
+        name: "To BCD: default 0",
+        input: "0",
+        expectedOutput: "0000",
+        recipeConfig: [
+            {
+                "op": "To BCD",
+                "args": ["8 4 2 1", true, false, "Nibbles"]
+            }
+        ]
+    },
+    {
+        name: "To BCD: unpacked nibbles",
+        input: "1234567890",
+        expectedOutput: "0000 0001 0000 0010 0000 0011 0000 0100 0000 0101 0000 0110 0000 0111 0000 1000 0000 1001 0000 0000",
+        recipeConfig: [
+            {
+                "op": "To BCD",
+                "args": ["8 4 2 1", false, false, "Nibbles"]
+            }
+        ]
+    },
+    {
+        name: "To BCD: packed, signed bytes",
+        input: "1234567890",
+        expectedOutput: "00000001 00100011 01000101 01100111 10001001 00001100",
+        recipeConfig: [
+            {
+                "op": "To BCD",
+                "args": ["8 4 2 1", true, true, "Bytes"]
+            }
+        ]
+    },
+    {
+        name: "To BCD: packed, signed nibbles, 8 4 -2 -1",
+        input: "-1234567890",
+        expectedOutput: "0000 0111 0110 0101 0100 1011 1010 1001 1000 1111 0000 1101",
+        recipeConfig: [
+            {
+                "op": "To BCD",
+                "args": ["8 4 -2 -1", true, true, "Nibbles"]
+            }
+        ]
+    },
+    {
+        name: "From BCD: default 0",
+        input: "0000",
+        expectedOutput: "0",
+        recipeConfig: [
+            {
+                "op": "From BCD",
+                "args": ["8 4 2 1", true, false, "Nibbles"]
+            }
+        ]
+    },
+    {
+        name: "From BCD: packed, signed bytes",
+        input: "00000001 00100011 01000101 01100111 10001001 00001101",
+        expectedOutput: "-1234567890",
+        recipeConfig: [
+            {
+                "op": "From BCD",
+                "args": ["8 4 2 1", true, true, "Bytes"]
+            }
+        ]
+    },
+    {
+        name: "From BCD: Excess-3, unpacked, unsigned",
+        input: "00000100 00000101 00000110 00000111 00001000 00001001 00001010 00001011 00001100 00000011",
+        expectedOutput: "1234567890",
+        recipeConfig: [
+            {
+                "op": "From BCD",
+                "args": ["Excess-3", false, false, "Nibbles"]
+            }
+        ]
+    },
+    {
+        name: "BCD: raw 4 2 2 1, packed, signed",
+        input: "1234567890",
+        expectedOutput: "1234567890",
+        recipeConfig: [
+            {
+                "op": "To BCD",
+                "args": ["4 2 2 1", true, true, "Raw"]
+            },
+            {
+                "op": "From BCD",
+                "args": ["4 2 2 1", true, true, "Raw"]
+            }
+        ]
+    },
+]);

+ 4 - 4
test/tests/operations/Compress.js

@@ -14,12 +14,12 @@ TestRegister.addTests([
         expectedOutput: "The cat sat on the mat.",
         expectedOutput: "The cat sat on the mat.",
         recipeConfig: [
         recipeConfig: [
             {
             {
-                "op" : "From Hex",
-                "args" : ["Space"]
+                "op": "From Hex",
+                "args": ["Space"]
             },
             },
             {
             {
-                "op" : "Bzip2 Decompress",
-                "args" : []
+                "op": "Bzip2 Decompress",
+                "args": []
             }
             }
         ],
         ],
     },
     },

+ 2 - 2
test/tests/operations/DateTime.js

@@ -16,7 +16,7 @@ TestRegister.addTests([
         recipeConfig: [
         recipeConfig: [
             {
             {
                 op: "Windows Filetime to UNIX Timestamp",
                 op: "Windows Filetime to UNIX Timestamp",
-                args: ["Nanoseconds (ns)"],
+                args: ["Nanoseconds (ns)", "Decimal"],
             },
             },
         ],
         ],
     },
     },
@@ -27,7 +27,7 @@ TestRegister.addTests([
         recipeConfig: [
         recipeConfig: [
             {
             {
                 op: "UNIX Timestamp to Windows Filetime",
                 op: "UNIX Timestamp to Windows Filetime",
-                args: ["Nanoseconds (ns)"],
+                args: ["Nanoseconds (ns)", "Decimal"],
             },
             },
         ],
         ],
     },
     },

+ 5 - 5
test/tests/operations/FlowControl.js

@@ -59,11 +59,11 @@ TestRegister.addTests([
         input: "Some data with a 1 in it\nSome data with a 2 in it",
         input: "Some data with a 1 in it\nSome data with a 2 in it",
         expectedOutput: "U29tZSBkYXRhIHdpdGggYSAxIGluIGl0\n53 6f 6d 65 20 64 61 74 61 20 77 69 74 68 20 61 20 32 20 69 6e 20 69 74\n",
         expectedOutput: "U29tZSBkYXRhIHdpdGggYSAxIGluIGl0\n53 6f 6d 65 20 64 61 74 61 20 77 69 74 68 20 61 20 32 20 69 6e 20 69 74\n",
         recipeConfig: [
         recipeConfig: [
-            {"op":"Fork", "args":["\\n", "\\n", false]},
-            {"op":"Conditional Jump", "args":["1", "2", "10"]},
-            {"op":"To Hex", "args":["Space"]},
-            {"op":"Return", "args":[]},
-            {"op":"To Base64", "args":["A-Za-z0-9+/="]}
+            {"op": "Fork", "args": ["\\n", "\\n", false]},
+            {"op": "Conditional Jump", "args": ["1", "2", "10"]},
+            {"op": "To Hex", "args": ["Space"]},
+            {"op": "Return", "args": []},
+            {"op": "To Base64", "args": ["A-Za-z0-9+/="]}
         ]
         ]
     },
     },
     {
     {

+ 3 - 3
test/tests/operations/Image.js

@@ -73,11 +73,11 @@ TestRegister.addTests([
             "",
             "",
             "Make: SONY",
             "Make: SONY",
             "Model: DSC-H5",
             "Model: DSC-H5",
-            "XResolution: 72",
-            "YResolution: 72",
+            "XResolution: 70",
+            "YResolution: 70",
             "ResolutionUnit: 2",
             "ResolutionUnit: 2",
             "Software: Pictomio 1.2.31.0",
             "Software: Pictomio 1.2.31.0",
-            "ModifyDate: 2010:07:04 23:31:13",
+            "ModifyDate: 1278286273",
             "ExposureTime: 0.008",
             "ExposureTime: 0.008",
             "FNumber: 3.7",
             "FNumber: 3.7",
             "ExposureProgram: 3",
             "ExposureProgram: 3",

+ 1 - 1
test/tests/operations/StrUtils.js

@@ -26,7 +26,7 @@ TestRegister.addTests([
     {
     {
         name: "Diff, basic usage",
         name: "Diff, basic usage",
         input: "testing23\n\ntesting123",
         input: "testing23\n\ntesting123",
-        expectedOutput: "testing<span class='hlgreen'>1</span>23",
+        expectedOutput: "testing<span class='hl5'>1</span>23",
         recipeConfig: [
         recipeConfig: [
             {
             {
                 "op": "Diff",
                 "op": "Diff",

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików