Skip to content

Commit fed10f3

Browse files
authored
Merge pull request #1915 from Oshawk/take-nth-bytes
Add 'Take nth bytes' operation
2 parents dcf0bbb + 7cc3e58 commit fed10f3

File tree

4 files changed

+204
-0
lines changed

4 files changed

+204
-0
lines changed

src/core/config/Categories.json

+1
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,7 @@
327327
"Pseudo-Random Number Generator",
328328
"Sleep",
329329
"File Tree",
330+
"Take nth bytes",
330331
"Drop nth bytes"
331332
]
332333
},

src/core/operations/TakeNthBytes.mjs

+79
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/**
2+
* @author Oshawk [[email protected]]
3+
* @copyright Crown Copyright 2019
4+
* @license Apache-2.0
5+
*/
6+
7+
import Operation from "../Operation.mjs";
8+
import OperationError from "../errors/OperationError.mjs";
9+
10+
/**
11+
* Take nth bytes operation
12+
*/
13+
class TakeNthBytes extends Operation {
14+
15+
/**
16+
* TakeNthBytes constructor
17+
*/
18+
constructor() {
19+
super();
20+
21+
this.name = "Take nth bytes";
22+
this.module = "Default";
23+
this.description = "Takes every nth byte starting with a given byte.";
24+
this.infoURL = "";
25+
this.inputType = "byteArray";
26+
this.outputType = "byteArray";
27+
this.args = [
28+
{
29+
name: "Take every",
30+
type: "number",
31+
value: 4
32+
},
33+
{
34+
name: "Starting at",
35+
type: "number",
36+
value: 0
37+
},
38+
{
39+
name: "Apply to each line",
40+
type: "boolean",
41+
value: false
42+
}
43+
];
44+
}
45+
46+
/**
47+
* @param {byteArray} input
48+
* @param {Object[]} args
49+
* @returns {byteArray}
50+
*/
51+
run(input, args) {
52+
const n = args[0];
53+
const start = args[1];
54+
const eachLine = args[2];
55+
56+
if (parseInt(n, 10) !== n || n <= 0) {
57+
throw new OperationError("'Take every' must be a positive integer.");
58+
}
59+
if (parseInt(start, 10) !== start || start < 0) {
60+
throw new OperationError("'Starting at' must be a positive or zero integer.");
61+
}
62+
63+
let offset = 0;
64+
const output = [];
65+
for (let i = 0; i < input.length; i++) {
66+
if (eachLine && input[i] === 0x0a) {
67+
output.push(0x0a);
68+
offset = i + 1;
69+
} else if (i - offset >= start && (i - (start + offset)) % n === 0) {
70+
output.push(input[i]);
71+
}
72+
}
73+
74+
return output;
75+
}
76+
77+
}
78+
79+
export default TakeNthBytes;

tests/operations/index.mjs

+1
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ import "./tests/StripUDPHeader.mjs";
150150
import "./tests/Subsection.mjs";
151151
import "./tests/SwapCase.mjs";
152152
import "./tests/SymmetricDifference.mjs";
153+
import "./tests/TakeNthBytes.mjs";
153154
import "./tests/TextEncodingBruteForce.mjs";
154155
import "./tests/ToFromInsensitiveRegex.mjs";
155156
import "./tests/TranslateDateTimeFormat.mjs";
+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/**
2+
* @author Oshawk [[email protected]]
3+
* @copyright Crown Copyright 2019
4+
* @license Apache-2.0
5+
*/
6+
7+
import TestRegister from "../../lib/TestRegister.mjs";
8+
9+
/**
10+
* Take nth bytes tests
11+
*/
12+
TestRegister.addTests([
13+
{
14+
name: "Take nth bytes: Nothing",
15+
input: "",
16+
expectedOutput: "",
17+
recipeConfig: [
18+
{
19+
op: "Take nth bytes",
20+
args: [4, 0, false],
21+
},
22+
],
23+
},
24+
{
25+
name: "Take nth bytes: Nothing (apply to each line)",
26+
input: "",
27+
expectedOutput: "",
28+
recipeConfig: [
29+
{
30+
op: "Take nth bytes",
31+
args: [4, 0, true],
32+
},
33+
],
34+
},
35+
{
36+
name: "Take nth bytes: Basic single line",
37+
input: "0123456789",
38+
expectedOutput: "048",
39+
recipeConfig: [
40+
{
41+
op: "Take nth bytes",
42+
args: [4, 0, false],
43+
},
44+
],
45+
},
46+
{
47+
name: "Take nth bytes: Basic single line (apply to each line)",
48+
input: "0123456789",
49+
expectedOutput: "048",
50+
recipeConfig: [
51+
{
52+
op: "Take nth bytes",
53+
args: [4, 0, true],
54+
},
55+
],
56+
},
57+
{
58+
name: "Take nth bytes: Complex single line",
59+
input: "0123456789",
60+
expectedOutput: "59",
61+
recipeConfig: [
62+
{
63+
op: "Take nth bytes",
64+
args: [4, 5, false],
65+
},
66+
],
67+
},
68+
{
69+
name: "Take nth bytes: Complex single line (apply to each line)",
70+
input: "0123456789",
71+
expectedOutput: "59",
72+
recipeConfig: [
73+
{
74+
op: "Take nth bytes",
75+
args: [4, 5, true],
76+
},
77+
],
78+
},
79+
{
80+
name: "Take nth bytes: Basic multi line",
81+
input: "01234\n56789",
82+
expectedOutput: "047",
83+
recipeConfig: [
84+
{
85+
op: "Take nth bytes",
86+
args: [4, 0, false],
87+
},
88+
],
89+
},
90+
{
91+
name: "Take nth bytes: Basic multi line (apply to each line)",
92+
input: "01234\n56789",
93+
expectedOutput: "04\n59",
94+
recipeConfig: [
95+
{
96+
op: "Take nth bytes",
97+
args: [4, 0, true],
98+
},
99+
],
100+
},
101+
{
102+
name: "Take nth bytes: Complex multi line",
103+
input: "01234\n56789",
104+
expectedOutput: "\n8",
105+
recipeConfig: [
106+
{
107+
op: "Take nth bytes",
108+
args: [4, 5, false],
109+
},
110+
],
111+
},
112+
{
113+
name: "Take nth bytes: Complex multi line (apply to each line)",
114+
input: "012345\n6789ab",
115+
expectedOutput: "5\nb",
116+
recipeConfig: [
117+
{
118+
op: "Take nth bytes",
119+
args: [4, 5, true],
120+
},
121+
],
122+
}
123+
]);

0 commit comments

Comments
 (0)