diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 5c74c0c2..240ddbc3 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -457,6 +457,7 @@ "Frequency distribution", "Index of Coincidence", "Chi Square", + "PLIST Viewer", "Disassemble x86", "Pseudo-Random Number Generator", "Generate UUID", diff --git a/src/core/operations/PLISTViewer.mjs b/src/core/operations/PLISTViewer.mjs new file mode 100644 index 00000000..b8a90c5b --- /dev/null +++ b/src/core/operations/PLISTViewer.mjs @@ -0,0 +1,146 @@ +/** + * @author n1073645 [n1073645@gmail.com] + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; + +/** + * PLIST Viewer operation + */ +class PLISTViewer extends Operation { + + /** + * PLISTViewer constructor + */ + constructor() { + super(); + + this.name = "PLIST Viewer"; + this.module = "Other"; + this.description = "Converts PLISTXML file into a human readable format."; + this.infoURL = ""; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + /* Example arguments. See the project wiki for full details. + { + name: "First arg", + type: "string", + value: "Don't Panic" + }, + { + name: "Second arg", + type: "number", + value: 42 + } + */ + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + + // Regexes are designed to transform the xml format into a reasonably more readable string format. + input = input.slice(input.indexOf("/g, "plist => ") + .replace(//g, "{") + .replace(/<\/dict>/g, "}") + .replace(//g, "[") + .replace(/<\/array>/g, "]") + .replace(/.+<\/key>/g, m => `${m.slice(5, m.indexOf(/<\/key>/g)-5)}\t=> `) + .replace(/.+<\/real>/g, m => `${m.slice(6, m.indexOf(/<\/real>/g)-6)}\n`) + .replace(/.+<\/string>/g, m => `"${m.slice(8, m.indexOf(/<\/string>/g)-8)}"\n`) + .replace(/.+<\/integer>/g, m => `${m.slice(9, m.indexOf(/<\/integer>/g)-9)}\n`) + .replace(//g, m => "false") + .replace(//g, m => "true") + .replace(/<\/plist>/g, "/plist") + .replace(/.+<\/date>/g, m => `${m.slice(6, m.indexOf(/<\/integer>/g)-6)}`) + .replace(/(\s|.)+?<\/data>/g, m => `${m.slice(6, m.indexOf(/<\/data>/g)-6)}`) + .replace(/[ \t\r\f\v]/g, ""); + + /** + * Depending on the type of brace, it will increment the depth and amount of arrays accordingly. + * + * @param {string} elem + * @param {array} vals + * @param {number} offset + */ + function braces(elem, vals, offset) { + const temp = vals.indexOf(elem); + if (temp !== -1) { + depthCount += offset; + if (temp === 1) + arrCount += offset; + } + } + + let result = ""; + let arrCount = 0; + let depthCount = 0; + + /** + * Formats the input after the regex has replaced all of the relevant parts. + * + * @param {array} input + * @param {number} index + */ + function printIt(input, index) { + if (!(input.length)) + return; + + let temp = ""; + const origArr = arrCount; + let currElem = input[0]; + + // If the current position points at a larger dynamic structure. + if (currElem.indexOf("=>") !== -1) { + + // If the LHS also points at a larger structure (nested plists in a dictionary). + if (input[1].indexOf("=>") !== -1) + temp = currElem.slice(0, -2) + " => " + input[1].slice(0, -2) + " =>\n"; + else + temp = currElem.slice(0, -2) + " => " + input[1] + "\n"; + + input = input.slice(1); + } else { + // Controls the tab depth for how many closing braces there have been. + + braces(currElem, ["}", "]"], -1); + + // Has to be here since the formatting breaks otherwise. + temp = currElem + "\n"; + } + + currElem = input[0]; + + // Tab out to the correct distance. + result += ("\t".repeat(depthCount)); + + // If it is enclosed in an array show index. + if (arrCount > 0 && currElem !== "]") + result += index.toString() + " => "; + + result += temp; + + // Controls the tab depth for how many opening braces there have been. + braces(currElem, ["{", "["], 1); + + // If there has been a new array then reset index. + if (arrCount > origArr) + return printIt(input.slice(1), 0); + return printIt(input.slice(1), ++index); + } + + input = input.split("\n").filter(e => e !== ""); + printIt(input, 0); + return result; + } +} + +export default PLISTViewer;