diff --git a/src/core/config/Categories.js b/src/core/config/Categories.js index b3e40b33..270c1e1e 100755 --- a/src/core/config/Categories.js +++ b/src/core/config/Categories.js @@ -173,7 +173,6 @@ const Categories = [ "Tail", "Count occurrences", "Expand alphabet range", - "Parse escaped string", "Drop bytes", "Take bytes", "Pad lines", @@ -188,6 +187,8 @@ const Categories = [ "Parse UNIX file permissions", "Swap endianness", "Parse colour code", + "Escape string", + "Unescape string", ] }, { diff --git a/src/core/config/OperationConfig.js b/src/core/config/OperationConfig.js index 38aa35cd..40571293 100755 --- a/src/core/config/OperationConfig.js +++ b/src/core/config/OperationConfig.js @@ -3224,13 +3224,6 @@ const OperationConfig = { } ] }, - "Parse escaped string": { - description: "Replaces escaped characters with the bytes they represent.

e.g.Hello\\nWorld becomes Hello
World
", - run: StrUtils.runParseEscapedString, - inputType: "string", - outputType: "string", - args: [] - }, "TCP/IP Checksum": { description: "Calculates the checksum for a TCP (Transport Control Protocol) or IP (Internet Protocol) header from an input of raw bytes.", run: Checksum.runTCPIP, @@ -3270,6 +3263,20 @@ const OperationConfig = { } ] }, + "Escape string": { + description: "Escapes special characters in a string so that they do not cause conflicts. For example, Don't stop me now becomes Don\\'t stop me now.", + run: StrUtils.runEscape, + inputType: "string", + outputType: "string", + args: [] + }, + "Unescape string": { + description: "Unescapes characters in a string that have been escaped. For example, Don\\'t stop me now becomes Don't stop me now.", + run: StrUtils.runUnescape, + inputType: "string", + outputType: "string", + args: [] + }, "To Morse Code": { description: "Translates alphanumeric characters into International Morse Code.

Ignores non-Morse characters.

e.g. SOS becomes ... --- ...", run: MorseCode.runTo, diff --git a/src/core/operations/StrUtils.js b/src/core/operations/StrUtils.js index 698e7eef..21b19e8a 100755 --- a/src/core/operations/StrUtils.js +++ b/src/core/operations/StrUtils.js @@ -450,14 +450,84 @@ const StrUtils = { /** - * Parse escaped string operation. + * @constant + * @default + */ + ESCAPE_REPLACEMENTS: [ + {"escaped": "\\\\", "unescaped": "\\"}, // Must be first + {"escaped": "\\'", "unescaped": "'"}, + {"escaped": "\\\"", "unescaped": "\""}, + {"escaped": "\\n", "unescaped": "\n"}, + {"escaped": "\\r", "unescaped": "\r"}, + {"escaped": "\\t", "unescaped": "\t"}, + {"escaped": "\\b", "unescaped": "\b"}, + {"escaped": "\\f", "unescaped": "\f"}, + ], + + /** + * Escape string operation. + * + * @author Vel0x [dalemy@microsoft.com] * * @param {string} input * @param {Object[]} args * @returns {string} + * + * @example + * StrUtils.runUnescape("Don't do that", []) + * > "Don\'t do that" + * StrUtils.runUnescape(`Hello + * World`, []) + * > "Hello\nWorld" */ - runParseEscapedString: function(input, args) { - return Utils.parseEscapedChars(input); + runEscape: function(input, args) { + return StrUtils._replaceByKeys(input, "unescaped", "escaped"); + }, + + + /** + * Unescape string operation. + * + * @author Vel0x [dalemy@microsoft.com] + * + * @param {string} input + * @param {Object[]} args + * @returns {string} + * + * @example + * StrUtils.runUnescape("Don\'t do that", []) + * > "Don't do that" + * StrUtils.runUnescape("Hello\nWorld", []) + * > `Hello + * World` + */ + runUnescape: function(input, args) { + return StrUtils._replaceByKeys(input, "escaped", "unescaped"); + }, + + + /** + * Replaces all matching tokens in ESCAPE_REPLACEMENTS with the correction. The + * ordering is determined by the patternKey and the replacementKey. + * + * @author Vel0x [dalemy@microsoft.com] + * @author Matt C [matt@artemisbot.uk] + * + * @param {string} input + * @param {string} pattern_key + * @param {string} replacement_key + * @returns {string} + */ + _replaceByKeys: function(input, patternKey, replacementKey) { + let output = input; + + // Catch the \\x encoded characters + if (patternKey === "escaped") output = Utils.parseEscapedChars(input); + + StrUtils.ESCAPE_REPLACEMENTS.forEach(replacement => { + output = output.split(replacement[patternKey]).join(replacement[replacementKey]); + }); + return output; }, diff --git a/test/tests/operations/StrUtils.js b/test/tests/operations/StrUtils.js index 478ab1f3..159916c7 100644 --- a/test/tests/operations/StrUtils.js +++ b/test/tests/operations/StrUtils.js @@ -232,4 +232,48 @@ TestRegister.addTests([ } ], }, + { + name: "Escape String: quotes", + input: "Hello \"World\"! Escape 'these' quotes.", + expectedOutput: "Hello \\\"World\\\"! Escape \\'these\\' quotes.", + recipeConfig: [ + { + "op": "Escape String", + "args": [] + } + ], + }, + { + name: "Escape String: special characters", + input: "Fizz & buzz\n\ttabbed newline\rcarriage returned line\nbackspace character: \"\" form feed character: \" \"", + expectedOutput: "Fizz & buzz\\n\\ttabbed newline\\rcarriage returned line\\nbackspace character: \\\"\\b\\\" form feed character: \\\"\\f\\\"", + recipeConfig: [ + { + "op": "Escape String", + "args": [] + } + ], + }, + { + name: "Unescape String: quotes", + input: "Hello \\\"World\\\"! Escape \\'these\\' quotes.", + expectedOutput: "Hello \"World\"! Escape 'these' quotes.", + recipeConfig: [ + { + "op": "Unescape String", + "args": [] + } + ], + }, + { + name: "Unescape String: special characters", + input: "Fizz \x26 buzz\\n\\ttabbed newline\\rcarriage returned line\\nbackspace character: \\\"\\b\\\" form feed character: \\\"\\f\\\"", + expectedOutput: "Fizz & buzz\n\ttabbed newline\rcarriage returned line\nbackspace character: \"\" form feed character: \" \"", + recipeConfig: [ + { + "op": "Unescape String", + "args": [] + } + ], + }, ]);