Skip to content

Commit 5cf0f2b

Browse files
committed
Complete system serializer
1 parent 2c0971b commit 5cf0f2b

File tree

10 files changed

+359
-12
lines changed

10 files changed

+359
-12
lines changed

core/src/main/java/com/github/flexca/enot/core/types/asn1/attribute/Asn1Attribute.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ public enum Asn1Attribute implements EnotAttribute {
1414

1515
TAG("tag", new EnotValueSpecification(CommonEnotValueType.TEXT, false)),
1616
IMPLICIT("implicit", new EnotValueSpecification(CommonEnotValueType.INTEGER, false)),
17-
EXPLICIT("explicit", new EnotValueSpecification(CommonEnotValueType.INTEGER, false));
17+
EXPLICIT("explicit", new EnotValueSpecification(CommonEnotValueType.INTEGER, false)),
18+
APPLY_PADDING("apply_padding", new EnotValueSpecification(CommonEnotValueType.BINARY, false));
1819

1920
private static final Map<String, Asn1Attribute> BY_NAME = new HashMap<>();
2021
static {

core/src/main/java/com/github/flexca/enot/core/types/asn1/serializer/Asn1BitStringSerializer.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import com.github.flexca.enot.core.types.asn1.Asn1EnotValueType;
1212
import com.github.flexca.enot.core.types.asn1.Asn1Tag;
1313
import org.apache.commons.collections4.CollectionUtils;
14+
import org.bouncycastle.asn1.DERBitString;
1415
import org.bouncycastle.asn1.DEROctetString;
1516

1617
import java.util.Collections;
@@ -54,7 +55,7 @@ protected List<ElementSerializationResult> serialize(EnotElement element, List<E
5455
}
5556

5657
return Collections.singletonList(ElementSerializationResult.of(Asn1EnotValueType.ASN1_ELEMENT,
57-
new DEROctetString(binaryInput)));
58+
new DERBitString(binaryInput)));
5859
}
5960

6061
throw new EnotSerializationException(EnotSerializer.COMMON_ERROR_MESSAGE, Collections.singletonList(

core/src/main/java/com/github/flexca/enot/core/types/system/SystemKind.java

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,28 @@
22

33
import com.fasterxml.jackson.annotation.JsonCreator;
44
import com.fasterxml.jackson.annotation.JsonValue;
5-
import com.github.flexca.enot.core.registry.EnotElementBodyResolver;
6-
import com.github.flexca.enot.core.registry.EnotElementSpecification;
75
import com.github.flexca.enot.core.element.attribute.EnotAttribute;
8-
import com.github.flexca.enot.core.element.value.EnotValueSpecification;
96
import com.github.flexca.enot.core.element.value.CommonEnotValueType;
7+
import com.github.flexca.enot.core.element.value.EnotValueSpecification;
8+
import com.github.flexca.enot.core.registry.EnotElementBodyResolver;
9+
import com.github.flexca.enot.core.registry.EnotElementSpecification;
1010
import com.github.flexca.enot.core.registry.EnotElementValidator;
1111
import com.github.flexca.enot.core.serializer.ElementSerializer;
1212
import com.github.flexca.enot.core.types.system.attribute.SystemAttribute;
13+
import com.github.flexca.enot.core.types.system.serializer.SystemBinToHexSerializer;
14+
import com.github.flexca.enot.core.types.system.serializer.SystemBitMapSerializer;
1315
import com.github.flexca.enot.core.types.system.serializer.SystemConditionSerializer;
1416
import com.github.flexca.enot.core.types.system.serializer.SystemGroupSerializer;
17+
import com.github.flexca.enot.core.types.system.serializer.SystemHexToBinSerializer;
1518
import com.github.flexca.enot.core.types.system.serializer.SystemLoopSerializer;
1619
import com.github.flexca.enot.core.types.system.serializer.SystemReferenceSerializer;
17-
import com.github.flexca.enot.core.types.system.SystemReferenceBodyResolver;
20+
import com.github.flexca.enot.core.types.system.serializer.SystemSha1Serializer;
1821

19-
import java.util.*;
22+
import java.util.Collections;
23+
import java.util.HashMap;
24+
import java.util.Locale;
25+
import java.util.Map;
26+
import java.util.Set;
2027

2128
public enum SystemKind implements EnotElementSpecification {
2229

@@ -63,7 +70,7 @@ public enum SystemKind implements EnotElementSpecification {
6370
Set.of(SystemAttribute.KIND, SystemAttribute.BYTE_ORDER, SystemAttribute.BIT_ORDER),
6471
null,
6572
null,
66-
null),
73+
new SystemBitMapSerializer()),
6774

6875
SHA1("sha1",
6976
new EnotValueSpecification(CommonEnotValueType.BINARY, false),
@@ -72,7 +79,7 @@ public enum SystemKind implements EnotElementSpecification {
7279
Set.of(SystemAttribute.KIND),
7380
null,
7481
null,
75-
null),
82+
new SystemSha1Serializer()),
7683

7784
HEX_TO_BIN("hex_to_bin",
7885
new EnotValueSpecification(CommonEnotValueType.TEXT, false),
@@ -81,7 +88,7 @@ public enum SystemKind implements EnotElementSpecification {
8188
Set.of(SystemAttribute.KIND),
8289
null,
8390
null,
84-
null),
91+
new SystemHexToBinSerializer()),
8592

8693
BIN_TO_HEX("bin_to_hex",
8794
new EnotValueSpecification(CommonEnotValueType.BINARY, false),
@@ -90,7 +97,7 @@ public enum SystemKind implements EnotElementSpecification {
9097
Set.of(SystemAttribute.KIND),
9198
null,
9299
null,
93-
null);
100+
new SystemBinToHexSerializer());
94101

95102
private static final Map<String, SystemKind> BY_NAME = new HashMap<>();
96103
static {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.github.flexca.enot.core.types.system.attribute;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
public enum BitOrder {
7+
8+
MSB_FIRST("msb_first"), LSB_FIRST("lsb_first");
9+
10+
private static final Map<String, BitOrder> BY_NAME = new HashMap<>();
11+
static {
12+
for(BitOrder value : values()) {
13+
BY_NAME.put(value.getName(), value);
14+
}
15+
}
16+
17+
private final String name;
18+
19+
private BitOrder(String name) {
20+
this.name = name;
21+
}
22+
23+
public String getName() {
24+
return name;
25+
}
26+
27+
public static BitOrder fromName(String name) {
28+
return name == null ? null : BY_NAME.get(name.toLowerCase());
29+
}
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.github.flexca.enot.core.types.system.attribute;
2+
3+
import java.util.HashMap;
4+
import java.util.Map;
5+
6+
public enum ByteOrder {
7+
8+
BIG_ENDIAN("big_endian"), LITTLE_ENDIAN("little_endian");
9+
10+
private static final Map<String, ByteOrder> BY_NAME = new HashMap<>();
11+
static {
12+
for(ByteOrder value : values()) {
13+
BY_NAME.put(value.getName(), value);
14+
}
15+
}
16+
17+
private final String name;
18+
19+
private ByteOrder(String name) {
20+
this.name = name;
21+
}
22+
23+
public String getName() {
24+
return name;
25+
}
26+
27+
public static ByteOrder fromName(String name) {
28+
return name == null ? null : BY_NAME.get(name.toLowerCase());
29+
}
30+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.github.flexca.enot.core.types.system.serializer;
2+
3+
import com.github.flexca.enot.core.element.EnotElement;
4+
import com.github.flexca.enot.core.element.value.CommonEnotValueType;
5+
import com.github.flexca.enot.core.exception.EnotSerializationException;
6+
import com.github.flexca.enot.core.parser.EnotJsonError;
7+
import com.github.flexca.enot.core.parser.EnotParser;
8+
import com.github.flexca.enot.core.serializer.ElementSerializationResult;
9+
import com.github.flexca.enot.core.serializer.EnotSerializer;
10+
import com.github.flexca.enot.core.serializer.SimpleElementSerializer;
11+
import org.apache.commons.collections4.CollectionUtils;
12+
13+
import java.util.Collections;
14+
import java.util.HexFormat;
15+
import java.util.List;
16+
17+
public class SystemBinToHexSerializer extends SimpleElementSerializer {
18+
19+
@Override
20+
protected List<ElementSerializationResult> serialize(EnotElement element, List<ElementSerializationResult> serializedBody, String jsonPath) throws EnotSerializationException {
21+
22+
if (CollectionUtils.isEmpty(serializedBody)) {
23+
if(element.isOptional()) {
24+
return Collections.emptyList();
25+
} else {
26+
throw new EnotSerializationException(EnotSerializer.COMMON_ERROR_MESSAGE, EnotJsonError.of( jsonPath
27+
+ "/" + EnotParser.ENOT_ELEMENT_BODY_NAME, "empty body for non optional element"));
28+
}
29+
}
30+
31+
if (serializedBody.size() != 1) {
32+
throw new EnotSerializationException(EnotSerializer.COMMON_ERROR_MESSAGE, EnotJsonError.of( jsonPath
33+
+ "/" + EnotParser.ENOT_ELEMENT_BODY_NAME, "bin_to_hex can serialize only single binary input"));
34+
}
35+
36+
ElementSerializationResult toSerialize = serializedBody.get(0);
37+
38+
if (CommonEnotValueType.BINARY.canConsume(toSerialize.getValueType())) {
39+
try {
40+
byte[] input = toSerialize.getValueType().getBinaryConverter().toBinary(toSerialize.getData());
41+
String result = HexFormat.of().formatHex(input);
42+
return Collections.singletonList(ElementSerializationResult.of(CommonEnotValueType.TEXT, result));
43+
} catch(Exception e) {
44+
throw new EnotSerializationException(EnotSerializer.COMMON_ERROR_MESSAGE, EnotJsonError.of( jsonPath
45+
+ "/" + EnotParser.ENOT_ELEMENT_BODY_NAME, "failure during bin to hex conversion, reason: " + e.getMessage()), e);
46+
}
47+
} else {
48+
throw new EnotSerializationException(EnotSerializer.COMMON_ERROR_MESSAGE, EnotJsonError.of( jsonPath
49+
+ "/" + EnotParser.ENOT_ELEMENT_BODY_NAME, "body of bin_to_hex element must be binary"));
50+
}
51+
}
52+
}
Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,107 @@
11
package com.github.flexca.enot.core.types.system.serializer;
22

3-
public class SystemBitMapSerializer {
3+
import com.github.flexca.enot.core.element.EnotElement;
4+
import com.github.flexca.enot.core.element.value.CommonEnotValueType;
5+
import com.github.flexca.enot.core.exception.EnotSerializationException;
6+
import com.github.flexca.enot.core.parser.EnotJsonError;
7+
import com.github.flexca.enot.core.parser.EnotParser;
8+
import com.github.flexca.enot.core.serializer.ElementSerializationResult;
9+
import com.github.flexca.enot.core.serializer.EnotSerializer;
10+
import com.github.flexca.enot.core.serializer.SimpleElementSerializer;
11+
import com.github.flexca.enot.core.types.system.attribute.BitOrder;
12+
import com.github.flexca.enot.core.types.system.attribute.ByteOrder;
13+
import com.github.flexca.enot.core.types.system.attribute.SystemAttribute;
14+
import org.apache.commons.collections4.CollectionUtils;
15+
16+
import java.util.Arrays;
17+
import java.util.Collections;
18+
import java.util.List;
19+
20+
public class SystemBitMapSerializer extends SimpleElementSerializer {
21+
22+
@Override
23+
protected List<ElementSerializationResult> serialize(EnotElement element, List<ElementSerializationResult> serializedBody,
24+
String jsonPath) throws EnotSerializationException {
25+
26+
if (CollectionUtils.isEmpty(serializedBody)) {
27+
if (element.isOptional()) {
28+
return Collections.emptyList();
29+
} else {
30+
throw new EnotSerializationException(EnotSerializer.COMMON_ERROR_MESSAGE, EnotJsonError.of(jsonPath
31+
+ "/" + EnotParser.ENOT_ELEMENT_BODY_NAME, "empty body for non optional element"));
32+
}
33+
}
34+
35+
ByteOrder byteOrder = resolveByteOrder(element);
36+
if (byteOrder == null) {
37+
throw new EnotSerializationException(EnotSerializer.COMMON_ERROR_MESSAGE, EnotJsonError.of(jsonPath
38+
+ "/" + SystemAttribute.BYTE_ORDER, "empty or unsupported byte_order attribute, use one of: "
39+
+ Arrays.toString(ByteOrder.values())));
40+
}
41+
42+
BitOrder bitOrder = resolveBitOrder(element);
43+
if (bitOrder == null) {
44+
throw new EnotSerializationException(EnotSerializer.COMMON_ERROR_MESSAGE, EnotJsonError.of(jsonPath
45+
+ "/" + SystemAttribute.BIT_ORDER, "empty or unsupported bit_order attribute, use one of: "
46+
+ Arrays.toString(BitOrder.values())));
47+
}
48+
49+
byte[] result = inputToBytes(serializedBody, byteOrder, bitOrder, jsonPath);
50+
return Collections.singletonList(ElementSerializationResult.of(CommonEnotValueType.BINARY, result));
51+
}
52+
53+
private ByteOrder resolveByteOrder(EnotElement element) {
54+
55+
Object byteOrderObject = element.getAttribute(SystemAttribute.BYTE_ORDER);
56+
ByteOrder byteOrder = null;
57+
if (byteOrderObject instanceof String byteOrderString) {
58+
byteOrder = ByteOrder.fromName(byteOrderString);
59+
}
60+
return byteOrder;
61+
}
62+
63+
private BitOrder resolveBitOrder(EnotElement element) {
64+
65+
Object bitOrderObject = element.getAttribute(SystemAttribute.BIT_ORDER);
66+
BitOrder bitOrder = null;
67+
if (bitOrderObject instanceof String bitOrderString) {
68+
bitOrder = BitOrder.fromName(bitOrderString);
69+
}
70+
return bitOrder;
71+
}
72+
73+
private byte[] inputToBytes(List<ElementSerializationResult> serializedBody, ByteOrder byteOrder, BitOrder bitOrder,
74+
String jsonPath) throws EnotSerializationException {
75+
76+
int bytesLength = serializedBody.size() / 8;
77+
if (serializedBody.size() % 8 != 0) {
78+
bytesLength++;
79+
}
80+
byte[] bytes = new byte[bytesLength];
81+
int bitCount = 0;
82+
int byteValue = 0;
83+
int byteCount = 0;
84+
for (ElementSerializationResult item : serializedBody) {
85+
if (item.getData() instanceof Boolean booleanItem) {
86+
int shift = BitOrder.LSB_FIRST.equals(bitOrder) ? bitCount : 7 - bitCount;
87+
byteValue |= (booleanItem ? 1 : 0) << shift;
88+
} else {
89+
throw new EnotSerializationException(EnotSerializer.COMMON_ERROR_MESSAGE, EnotJsonError.of(jsonPath
90+
+ "/" + EnotParser.ENOT_ELEMENT_BODY_NAME, "system element bit_map expect array of boolean values"));
91+
}
92+
bitCount++;
93+
if (bitCount >= 8) {
94+
int index = ByteOrder.LITTLE_ENDIAN.equals(byteOrder) ? byteCount : (bytesLength - byteCount - 1);
95+
bytes[index] = (byte) (byteValue & 0xFF);
96+
byteValue = 0;
97+
bitCount = 0;
98+
byteCount++;
99+
}
100+
}
101+
if (serializedBody.size() % 8 != 0) {
102+
int index = ByteOrder.LITTLE_ENDIAN.equals(byteOrder) ? byteCount : (bytesLength - byteCount - 1);
103+
bytes[index] = (byte) (byteValue & 0xFF);
104+
}
105+
return bytes;
106+
}
4107
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.github.flexca.enot.core.types.system.serializer;
2+
3+
import com.github.flexca.enot.core.element.EnotElement;
4+
import com.github.flexca.enot.core.element.value.CommonEnotValueType;
5+
import com.github.flexca.enot.core.exception.EnotSerializationException;
6+
import com.github.flexca.enot.core.parser.EnotJsonError;
7+
import com.github.flexca.enot.core.parser.EnotParser;
8+
import com.github.flexca.enot.core.serializer.ElementSerializationResult;
9+
import com.github.flexca.enot.core.serializer.EnotSerializer;
10+
import com.github.flexca.enot.core.serializer.SimpleElementSerializer;
11+
import org.apache.commons.collections4.CollectionUtils;
12+
13+
import java.util.Collections;
14+
import java.util.HexFormat;
15+
import java.util.List;
16+
17+
public class SystemHexToBinSerializer extends SimpleElementSerializer {
18+
19+
@Override
20+
protected List<ElementSerializationResult> serialize(EnotElement element, List<ElementSerializationResult> serializedBody,
21+
String jsonPath) throws EnotSerializationException {
22+
23+
if (CollectionUtils.isEmpty(serializedBody)) {
24+
if(element.isOptional()) {
25+
return Collections.emptyList();
26+
} else {
27+
throw new EnotSerializationException(EnotSerializer.COMMON_ERROR_MESSAGE, EnotJsonError.of( jsonPath
28+
+ "/" + EnotParser.ENOT_ELEMENT_BODY_NAME, "empty body for non optional element"));
29+
}
30+
}
31+
32+
if (serializedBody.size() != 1) {
33+
throw new EnotSerializationException(EnotSerializer.COMMON_ERROR_MESSAGE, EnotJsonError.of( jsonPath
34+
+ "/" + EnotParser.ENOT_ELEMENT_BODY_NAME, "hex_to_bin element can serialize only single text input"));
35+
}
36+
37+
ElementSerializationResult toSerialize = serializedBody.get(0);
38+
39+
if (toSerialize.getData() instanceof String textBody) {
40+
try {
41+
byte[] result = HexFormat.of().parseHex(textBody);
42+
return Collections.singletonList(ElementSerializationResult.of(CommonEnotValueType.BINARY, result));
43+
} catch(Exception e) {
44+
throw new EnotSerializationException(EnotSerializer.COMMON_ERROR_MESSAGE, EnotJsonError.of( jsonPath
45+
+ "/" + EnotParser.ENOT_ELEMENT_BODY_NAME, "failure during hex to binary conversion, reason: "
46+
+ e.getMessage()), e);
47+
}
48+
} else {
49+
throw new EnotSerializationException(EnotSerializer.COMMON_ERROR_MESSAGE, EnotJsonError.of( jsonPath
50+
+ "/" + EnotParser.ENOT_ELEMENT_BODY_NAME, "body of hex_to_bin element must be string"));
51+
}
52+
}
53+
}

0 commit comments

Comments
 (0)