Skip to content

Commit 18cdb52

Browse files
committedNov 3, 2024
#45 added controller to control evaluated values for array size
1 parent f3b8c44 commit 18cdb52

File tree

4 files changed

+136
-2
lines changed

4 files changed

+136
-2
lines changed
 

‎jbbp/src/main/java/com/igormaznitsa/jbbp/JBBPParser.java

+45-1
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
import java.util.Collections;
7373
import java.util.List;
7474
import java.util.Map;
75+
import java.util.Objects;
7576
import java.util.Properties;
7677

7778
/**
@@ -93,6 +94,15 @@ public final class JBBPParser {
9394
* @since 1.4.0
9495
*/
9596
public static final int FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO = 2;
97+
98+
/**
99+
* Default expression array size controller. It is doing nothing.
100+
*
101+
* @since 2.1.0
102+
*/
103+
public static final JBBPParserExpressionArraySizeController
104+
DEFAULT_EXPRESSION_ARRAY_SIZE_CONTROLLER =
105+
(parser, expressionEvaluator, fieldName, arraySize) -> arraySize;
96106
/**
97107
* Empty structure array
98108
*/
@@ -113,11 +123,17 @@ public final class JBBPParser {
113123
* Custom field type processor for the parser, it can be null.
114124
*/
115125
private final JBBPCustomFieldTypeProcessor customFieldTypeProcessor;
126+
/**
127+
* Controller to get and change values calculated by expressions as size for array fields.
128+
*
129+
* @since 2.1.0
130+
*/
131+
private JBBPParserExpressionArraySizeController expressionArraySizeController =
132+
DEFAULT_EXPRESSION_ARRAY_SIZE_CONTROLLER;
116133
/**
117134
* The Variable contains the last parsing counter value.
118135
*/
119136
private long finalStreamByteCounter;
120-
121137
/**
122138
* Constructor.
123139
*
@@ -248,6 +264,31 @@ public static JBBPParser prepare(final String script, final int flags) {
248264
return JBBPParser.prepare(script, JBBPBitOrder.LSB0, flags);
249265
}
250266

267+
/**
268+
* Get current registered instance of controller to check array size calculated by expression.
269+
*
270+
* @return current instance of array size observer, can't be null
271+
* @since 2.1.0
272+
*/
273+
public JBBPParserExpressionArraySizeController getExpressionArraySizeController() {
274+
return this.expressionArraySizeController;
275+
}
276+
277+
/**
278+
* Set current registered instance of controller to check array size calculated by expression.
279+
*
280+
* @param arraySizeObserver instance of array size observer, must not be null.
281+
* @return instance of the parser.
282+
* @throws NullPointerException if argument is null
283+
* @see #DEFAULT_EXPRESSION_ARRAY_SIZE_CONTROLLER
284+
* @since 2.1.0
285+
*/
286+
public JBBPParser setExpressionArraySizeController(
287+
final JBBPParserExpressionArraySizeController arraySizeObserver) {
288+
this.expressionArraySizeController = Objects.requireNonNull(arraySizeObserver);
289+
return this;
290+
}
291+
251292
/**
252293
* Inside method to parse a structure.
253294
*
@@ -355,6 +396,9 @@ private List<JBBPAbstractField> parseStruct(final JBBPBitInputStream inStream,
355396
if ((this.flags & FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO) != 0) {
356397
resultOfExpression = Math.max(resultOfExpression, 0);
357398
}
399+
resultOfExpression =
400+
this.expressionArraySizeController.onCalculatedArraySize(this, evaluator, name,
401+
resultOfExpression);
358402
} else {
359403
resultOfExpression = 0;
360404
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package com.igormaznitsa.jbbp;
2+
3+
import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo;
4+
import com.igormaznitsa.jbbp.compiler.varlen.JBBPIntegerValueEvaluator;
5+
6+
/**
7+
* Controller to get value for every array field which size calculated by expression.
8+
*
9+
* @see JBBPParser#setExpressionArraySizeController(JBBPParserExpressionArraySizeController)
10+
* @see JBBPParser#getExpressionArraySizeController()
11+
* @since 2.1.0
12+
*/
13+
@FunctionalInterface
14+
public interface JBBPParserExpressionArraySizeController {
15+
/**
16+
* Called for every calculation of an array size by expression.
17+
*
18+
* @param parser source parser, must not be null
19+
* @param expressionEvaluator expression evaluator used for calculation, must not be null
20+
* @param fieldInfo target field info, must not be null
21+
* @param calculatedArraySize calculated array size
22+
* @return array size which can be same as provided size or changed
23+
*/
24+
int onCalculatedArraySize(JBBPParser parser, JBBPIntegerValueEvaluator expressionEvaluator,
25+
JBBPNamedFieldInfo fieldInfo, int calculatedArraySize);
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.igormaznitsa.jbbp;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
import static org.junit.jupiter.api.Assertions.assertSame;
5+
import static org.junit.jupiter.api.Assertions.assertThrows;
6+
7+
import com.igormaznitsa.jbbp.model.JBBPFieldArrayByte;
8+
import java.io.ByteArrayInputStream;
9+
import java.util.concurrent.atomic.AtomicInteger;
10+
import org.junit.jupiter.api.Test;
11+
12+
class JBBPParserExpressionArraySizeControllerTest {
13+
14+
@Test
15+
public void testGetterAndSetter() {
16+
final JBBPParserExpressionArraySizeController controller =
17+
(parser, expressionEvaluator, fieldInfo, calculatedArraySize) -> 0;
18+
final JBBPParser parser = JBBPParser.prepare("ubyte len; byte [len*2] a;")
19+
.setExpressionArraySizeController(controller);
20+
assertSame(controller, parser.getExpressionArraySizeController());
21+
}
22+
23+
@Test
24+
public void testNoChangeSize() throws Exception {
25+
final AtomicInteger calls = new AtomicInteger();
26+
final JBBPParser parser =
27+
JBBPParser.prepare("ubyte len; byte [len*2] a;").setExpressionArraySizeController(
28+
(parser1, expressionEvaluator, fieldInfo, calculatedArraySize) -> {
29+
calls.incrementAndGet();
30+
assertEquals("a", fieldInfo.getFieldName());
31+
assertEquals(4, calculatedArraySize);
32+
return calculatedArraySize;
33+
});
34+
parser.parse(new ByteArrayInputStream(new byte[] {2, 1, 2, 3, 4}));
35+
assertEquals(1, calls.get());
36+
}
37+
38+
@Test
39+
public void testThrowException() {
40+
final JBBPParser parser =
41+
JBBPParser.prepare("ubyte len; byte [len*2] a;").setExpressionArraySizeController(
42+
(parser1, expressionEvaluator, fieldInfo, calculatedArraySize) -> {
43+
assertEquals("a", fieldInfo.getFieldName());
44+
if (calculatedArraySize > 2) {
45+
throw new IllegalArgumentException();
46+
}
47+
return calculatedArraySize;
48+
});
49+
assertThrows(IllegalArgumentException.class,
50+
() -> parser.parse(new ByteArrayInputStream(new byte[] {2, 1, 2, 3, 4})));
51+
}
52+
53+
@Test
54+
public void testChangeSize() throws Exception {
55+
final JBBPParser parser =
56+
JBBPParser.prepare("ubyte len; byte [len*2] a;").setExpressionArraySizeController(
57+
(parser1, expressionEvaluator, fieldInfo, calculatedArraySize) -> {
58+
assertEquals("a", fieldInfo.getFieldName());
59+
return calculatedArraySize - 1;
60+
});
61+
assertEquals(3, parser.parse(new ByteArrayInputStream(new byte[] {2, 1, 2, 3, 4}))
62+
.findFieldForNameAndType("a",
63+
JBBPFieldArrayByte.class).size());
64+
}
65+
}

‎jbbp/src/test/java/com/igormaznitsa/jbbp/JBBPParserTest.java

-1
Original file line numberDiff line numberDiff line change
@@ -2611,7 +2611,6 @@ public JBBPAbstractField readCustomFieldType(JBBPBitInputStream in, JBBPBitOrder
26112611
return new JBBPFieldArrayByte(fieldName, read);
26122612
}
26132613
});
2614-
26152614
}
26162615

26172616
}

0 commit comments

Comments
 (0)
Please sign in to comment.