From e6b89d571e6a7cc17f8b6259e84787b6da0db028 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Wed, 10 Oct 2018 13:56:20 +0000 Subject: [PATCH] Tidied up TLV operation and tests --- src/core/config/Categories.json | 2 +- .../lib/{LengthValue.mjs => TLVParser.mjs} | 21 +++-- src/core/operations/LVDecode.mjs | 81 ------------------- src/core/operations/ParseTLV.mjs | 76 +++++++++++++++++ test/index.mjs | 2 +- test/tests/operations/LVDecode.mjs | 56 ------------- test/tests/operations/ParseTLV.mjs | 56 +++++++++++++ 7 files changed, 148 insertions(+), 146 deletions(-) rename src/core/lib/{LengthValue.mjs => TLVParser.mjs} (74%) delete mode 100644 src/core/operations/LVDecode.mjs create mode 100644 src/core/operations/ParseTLV.mjs delete mode 100644 test/tests/operations/LVDecode.mjs create mode 100644 test/tests/operations/ParseTLV.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 2c716d31..6f02abb8 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -54,7 +54,7 @@ "From MessagePack", "To Braille", "From Braille", - "LV Decode" + "Parse TLV" ] }, { diff --git a/src/core/lib/LengthValue.mjs b/src/core/lib/TLVParser.mjs similarity index 74% rename from src/core/lib/LengthValue.mjs rename to src/core/lib/TLVParser.mjs index 3ec0c5e5..9e9395ff 100644 --- a/src/core/lib/LengthValue.mjs +++ b/src/core/lib/TLVParser.mjs @@ -1,5 +1,8 @@ /** + * Parser for Type-length-value data. + * * @author gchq77703 [] + * @author n1474335 [n1474335@gmail.com] * @copyright Crown Copyright 2018 * @license Apache-2.0 */ @@ -11,12 +14,15 @@ const defaults = { }; /** - * Length Value library + * TLVParser library */ -export default class LengthValue { +export default class TLVParser { /** - * LengthValue constructor + * TLVParser constructor + * + * @param {byteArray} input + * @param {Object} options */ constructor(input, options) { this.input = input; @@ -24,7 +30,7 @@ export default class LengthValue { } /** - * @returns {Number} + * @returns {number} */ getLength() { if (this.basicEncodingRules) { @@ -48,13 +54,14 @@ export default class LengthValue { } /** - * @param {Number} length - * @returns {Number[]} + * @param {number} length + * @returns {number[]} */ getValue(length) { const value = []; for (let i = 0; i < length; i++) { + if (this.location > this.input.length) return value; value.push(this.input[this.location]); this.location++; } @@ -63,7 +70,7 @@ export default class LengthValue { } /** - * @returns {Boolean} + * @returns {boolean} */ atEnd() { return this.input.length <= this.location; diff --git a/src/core/operations/LVDecode.mjs b/src/core/operations/LVDecode.mjs deleted file mode 100644 index 63af65f6..00000000 --- a/src/core/operations/LVDecode.mjs +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @author gchq77703 [] - * @copyright Crown Copyright 2018 - * @license Apache-2.0 - */ - -import Operation from "../Operation"; -import LengthValue from "../lib/LengthValue"; - -/** - * From LV Decode operation - */ -class LVDecode extends Operation { - - /** - * LVDecode constructor - */ - constructor() { - super(); - - this.name = "LV Decode"; - this.module = "Default"; - this.description = "Converts a Length-Value (LV) encoded string into a JSON object. Can optionally include a Key / Type entry."; - this.infoURL = "https://wikipedia.org/wiki/KLV"; - this.inputType = "byteArray"; - this.outputType = "JSON"; - this.args = [ - { - name: "Bytes in Key Value", - type: "option", - value: [ - "0 Bytes (No Key)", - "1 Byte", - "2 Bytes", - "4 Bytes" - ] - }, - { - name: "Bytes in Length Value", - type: "option", - value: [ - "1 Byte", - "2 Bytes", - "4 Bytes" - ] - }, - { - name: "Use Basic Encoding Rules", - type: "boolean" - } - ]; - } - - /** - * @param {byteArray} input - * @param {Object[]} args - * @returns {string} - */ - run(input, args) { - const bytesInKey = parseInt(args[0].split(" ")[0], 10); - const bytesInLength = parseInt(args[1].split(" ")[0], 10); - const basicEncodingRules = args[2]; - - const lv = new LengthValue(input, { bytesInLength, basicEncodingRules }); - - const data = []; - - while (!lv.atEnd()) { - const key = bytesInKey ? lv.getValue(bytesInKey) : undefined; - const length = lv.getLength(); - const value = lv.getValue(length); - - data.push({ key, length, value }); - } - - return data; - } - -} - -export default LVDecode; diff --git a/src/core/operations/ParseTLV.mjs b/src/core/operations/ParseTLV.mjs new file mode 100644 index 00000000..a87144a8 --- /dev/null +++ b/src/core/operations/ParseTLV.mjs @@ -0,0 +1,76 @@ +/** + * @author gchq77703 [] + * @author n1474335 [n1474335@gmail.com] + * @copyright Crown Copyright 2018 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import TLVParser from "../lib/TLVParser"; +import OperationError from "../errors/OperationError"; + +/** + * Parse TLV operation + */ +class ParseTLV extends Operation { + + /** + * ParseTLV constructor + */ + constructor() { + super(); + + this.name = "Parse TLV"; + this.module = "Default"; + this.description = "Converts a Type-Length-Value (TLV) encoded string into a JSON object. Can optionally include a Key / Type entry.

Tags: Key-Length-Value, KLV, Length-Value, LV"; + this.infoURL = "https://wikipedia.org/wiki/Type-length-value"; + this.inputType = "byteArray"; + this.outputType = "JSON"; + this.args = [ + { + name: "Type/Key size", + type: "number", + value: 1 + }, + { + name: "Length size", + type: "number", + value: 1 + }, + { + name: "Use BER", + type: "boolean", + value: false + } + ]; + } + + /** + * @param {byteArray} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const [bytesInKey, bytesInLength, basicEncodingRules] = args; + + if (bytesInKey <= 0 && bytesInLength <= 0) + throw new OperationError("Type or Length size must be greater than 0"); + + const tlv = new TLVParser(input, { bytesInLength, basicEncodingRules }); + + const data = []; + + while (!tlv.atEnd()) { + const key = bytesInKey ? tlv.getValue(bytesInKey) : undefined; + const length = tlv.getLength(); + const value = tlv.getValue(length); + + data.push({ key, length, value }); + } + + return data; + } + +} + +export default ParseTLV; diff --git a/test/index.mjs b/test/index.mjs index 89f4c44e..9bb93a60 100644 --- a/test/index.mjs +++ b/test/index.mjs @@ -71,7 +71,7 @@ import "./tests/operations/SymmetricDifference"; import "./tests/operations/ToGeohash.mjs"; import "./tests/operations/TranslateDateTimeFormat"; import "./tests/operations/Magic"; -import "./tests/operations/LVDecode"; +import "./tests/operations/ParseTLV"; let allTestsPassing = true; const testStatusCounts = { diff --git a/test/tests/operations/LVDecode.mjs b/test/tests/operations/LVDecode.mjs deleted file mode 100644 index 4fd7fc83..00000000 --- a/test/tests/operations/LVDecode.mjs +++ /dev/null @@ -1,56 +0,0 @@ -/** - * LV Decoder tests. - * - * @author gchq77703 [] - * @copyright Crown Copyright 2018 - * @license Apache-2.0 - */ - -import TestRegister from "../../TestRegister"; - -TestRegister.addTests([ - { - name: "LVDecode: LengthValue", - input: "\x05\x48\x6f\x75\x73\x65\x04\x72\x6f\x6f\x6d\x04\x64\x6f\x6f\x72", - expectedOutput: JSON.stringify([{"length": 5, "value": [72, 111, 117, 115, 101]}, {"length": 4, "value": [114, 111, 111, 109]}, {"length": 4, "value": [100, 111, 111, 114]}]), - recipeConfig: [ - { - "op": "LV Decode", - "args": ["0 Bytes (No Key)", "1 Byte", false] - } - ] - }, - { - name: "LVDecode: LengthValue with BER", - input: "\x05\x48\x6f\x75\x73\x65\x04\x72\x6f\x6f\x6d\x04\x64\x6f\x6f\x72", - expectedOutput: JSON.stringify([{"length": 5, "value": [72, 111, 117, 115, 101]}, {"length": 4, "value": [114, 111, 111, 109]}, {"length": 4, "value": [100, 111, 111, 114]}]), - recipeConfig: [ - { - "op": "LV Decode", - "args": ["0 Bytes (No Key)", "4 Bytes", false] // length value is patently wrong, should be ignored by BER. - } - ] - }, - { - name: "LVDecode: KeyLengthValue", - input: "\x04\x05\x48\x6f\x75\x73\x65\x05\x04\x72\x6f\x6f\x6d\x42\x04\x64\x6f\x6f\x72", - expectedOutput: JSON.stringify([{"key":[4],"length":5,"value":[72,111,117,115,101]},{"key":[5],"length":4,"value":[114,111,111,109]},{"key":[66],"length":4,"value":[100,111,111,114]}]), - recipeConfig: [ - { - "op": "LV Decode", - "args": ["1 Byte", "1 Byte", false] - } - ] - }, - { - name: "LVDecode: KeyLengthValue with BER", - input: "\x04\x05\x48\x6f\x75\x73\x65\x05\x04\x72\x6f\x6f\x6d\x42\x04\x64\x6f\x6f\x72", - expectedOutput: JSON.stringify([{"key":[4],"length":5,"value":[72,111,117,115,101]},{"key":[5],"length":4,"value":[114,111,111,109]},{"key":[66],"length":4,"value":[100,111,111,114]}]), - recipeConfig: [ - { - "op": "LV Decode", - "args": ["1 Byte", "4 Byte", true] // length value is patently wrong, should be ignored by BER. - } - ] - } -]); diff --git a/test/tests/operations/ParseTLV.mjs b/test/tests/operations/ParseTLV.mjs new file mode 100644 index 00000000..43cc02d7 --- /dev/null +++ b/test/tests/operations/ParseTLV.mjs @@ -0,0 +1,56 @@ +/** + * Parse TLV tests. + * + * @author gchq77703 [] + * @copyright Crown Copyright 2018 + * @license Apache-2.0 + */ + +import TestRegister from "../../TestRegister"; + +TestRegister.addTests([ + { + name: "Parse TLV: LengthValue", + input: "\x05\x48\x6f\x75\x73\x65\x04\x72\x6f\x6f\x6d\x04\x64\x6f\x6f\x72", + expectedOutput: JSON.stringify([{"length": 5, "value": [72, 111, 117, 115, 101]}, {"length": 4, "value": [114, 111, 111, 109]}, {"length": 4, "value": [100, 111, 111, 114]}], null, 4), + recipeConfig: [ + { + "op": "Parse TLV", + "args": [0, 1, false] + } + ] + }, + { + name: "Parse TLV: LengthValue with BER", + input: "\x05\x48\x6f\x75\x73\x65\x04\x72\x6f\x6f\x6d\x04\x64\x6f\x6f\x72", + expectedOutput: JSON.stringify([{"length": 5, "value": [72, 111, 117, 115, 101]}, {"length": 4, "value": [114, 111, 111, 109]}, {"length": 4, "value": [100, 111, 111, 114]}], null, 4), + recipeConfig: [ + { + "op": "Parse TLV", + "args": [0, 4, true] // length value is patently wrong, should be ignored by BER. + } + ] + }, + { + name: "Parse TLV: KeyLengthValue", + input: "\x04\x05\x48\x6f\x75\x73\x65\x05\x04\x72\x6f\x6f\x6d\x42\x04\x64\x6f\x6f\x72", + expectedOutput: JSON.stringify([{"key": [4], "length": 5, "value": [72, 111, 117, 115, 101]}, {"key": [5], "length": 4, "value": [114, 111, 111, 109]}, {"key": [66], "length": 4, "value": [100, 111, 111, 114]}], null, 4), + recipeConfig: [ + { + "op": "Parse TLV", + "args": [1, 1, false] + } + ] + }, + { + name: "Parse TLV: KeyLengthValue with BER", + input: "\x04\x05\x48\x6f\x75\x73\x65\x05\x04\x72\x6f\x6f\x6d\x42\x04\x64\x6f\x6f\x72", + expectedOutput: JSON.stringify([{"key": [4], "length": 5, "value": [72, 111, 117, 115, 101]}, {"key": [5], "length": 4, "value": [114, 111, 111, 109]}, {"key": [66], "length": 4, "value": [100, 111, 111, 114]}], null, 4), + recipeConfig: [ + { + "op": "Parse TLV", + "args": [1, 4, true] // length value is patently wrong, should be ignored by BER. + } + ] + } +]);