Skip to content

Commit caeb41d

Browse files
committed
added extra constructor into JBBPParser and added test for custom type parsing "BCD"
1 parent 531e0f1 commit caeb41d

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,20 @@ public static JBBPParser prepare(final String script) {
579579
return JBBPParser.prepare(script, JBBPBitOrder.LSB0);
580580
}
581581

582+
/**
583+
* Prepare a parser for a script with default bit order (LSB0) use and with defined custom type field processor.
584+
*
585+
* @param script a text script contains field order and types reference, it
586+
* must not be null
587+
* @param customFieldTypeProcessor custom field type processor, can be null
588+
* @return the prepared parser for the script
589+
* @see JBBPBitOrder#LSB0
590+
* @since 1.2.0
591+
*/
592+
public static JBBPParser prepare(final String script, final JBBPCustomFieldTypeProcessor customFieldTypeProcessor) {
593+
return JBBPParser.prepare(script, JBBPBitOrder.LSB0, customFieldTypeProcessor, 0);
594+
}
595+
582596
/**
583597
* Prepare a parser for a script with default bit order (LSB0) use and special flags
584598
*
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Copyright 2015 Igor Maznitsa.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.igormaznitsa.jbbp.it;
17+
18+
import com.igormaznitsa.jbbp.JBBPCustomFieldTypeProcessor;
19+
import com.igormaznitsa.jbbp.JBBPParser;
20+
import com.igormaznitsa.jbbp.compiler.JBBPNamedFieldInfo;
21+
import com.igormaznitsa.jbbp.compiler.tokenizer.JBBPFieldTypeParameterContainer;
22+
import com.igormaznitsa.jbbp.exceptions.JBBPCompilationException;
23+
import com.igormaznitsa.jbbp.io.*;
24+
import com.igormaznitsa.jbbp.model.*;
25+
import java.io.IOException;
26+
import static org.junit.Assert.assertEquals;
27+
import org.junit.Test;
28+
29+
public class PackedBCDCustomFieldTest implements JBBPCustomFieldTypeProcessor {
30+
31+
private static final String [] types = new String[]{"bcd", "sbcd"};
32+
33+
public String[] getCustomFieldTypes() {
34+
return types;
35+
}
36+
37+
public boolean isAllowed(final JBBPFieldTypeParameterContainer fieldType, final String fieldName, final int extraData, final boolean isArray) {
38+
if (fieldType.getByteOrder() == JBBPByteOrder.LITTLE_ENDIAN){
39+
System.err.println("Packed Decimal does not support little endian...using big endian instead");
40+
return false;
41+
}
42+
43+
return extraData>0 && extraData<15;
44+
}
45+
46+
public static long readValueFromPackedDecimal(final JBBPBitInputStream in, final int len, final boolean signed) throws IOException {
47+
final byte [] data = in.readByteArray(len);
48+
49+
StringBuilder digitStr = new StringBuilder();
50+
for (int i = 0; i < len * 2; i++) {
51+
byte currentByte = data[i / 2];
52+
byte digit = (i % 2 == 0) ? (byte) ((currentByte & 0xff) >>> 4) : (byte) (currentByte & 0x0f);
53+
if (digit < 10) {
54+
digitStr.append(digit);
55+
}
56+
}
57+
58+
if (signed) {
59+
byte sign = (byte) (data[len - 1] & 0x0f);
60+
if (sign == 0x0b || sign == 0x0d) {
61+
digitStr.insert(0, '-');
62+
}
63+
}
64+
65+
return Long.parseLong(digitStr.toString());
66+
}
67+
68+
69+
public JBBPAbstractField readCustomFieldType(final JBBPBitInputStream in, final JBBPBitOrder bitOrder, final int parserFlags, final JBBPFieldTypeParameterContainer customTypeFieldInfo, JBBPNamedFieldInfo fieldName, int extraData, boolean readWholeStream, int arrayLength) throws IOException {
70+
final boolean signed = "sbcd".equals(customTypeFieldInfo.getTypeName());
71+
72+
if (readWholeStream){
73+
throw new UnsupportedOperationException("Whole stream reading unsupported");
74+
}else{
75+
if (arrayLength<=0){
76+
return new JBBPFieldLong(fieldName, readValueFromPackedDecimal(in, extraData, signed));
77+
}else{
78+
final long [] result = new long[arrayLength];
79+
for(int i=0;i<arrayLength;i++){
80+
result[i] = readValueFromPackedDecimal(in, extraData, signed);
81+
}
82+
return new JBBPFieldArrayLong(fieldName, result);
83+
}
84+
}
85+
}
86+
87+
@Test
88+
public void testParse_SingleDefaultNonamedPackedDecimal_Default() throws Exception {
89+
final JBBPParser parser = JBBPParser.prepare("bcd:4;",this);
90+
final JBBPFieldStruct result = parser.parse(new byte[]{0x12, 0x34, 0x56, 0x7F});
91+
assertEquals(1234567L, result.findFieldForType(JBBPFieldLong.class).getAsLong());
92+
}
93+
94+
@Test
95+
public void testParse_SingleDefaultNonamedPackedDecimal_BigEndian() throws Exception {
96+
final JBBPParser parser = JBBPParser.prepare(">bcd:4;", this);
97+
final JBBPFieldStruct result = parser.parse(new byte[]{0x12, 0x34, 0x56, 0x7F});
98+
assertEquals(1234567L, result.findFieldForType(JBBPFieldLong.class).getAsLong());
99+
}
100+
101+
@Test(expected = JBBPCompilationException.class)
102+
public void testParse_SingleDefaultNonamedPackedDecimal_LittleEndian_Exception() throws Exception {
103+
final JBBPParser parser = JBBPParser.prepare("<bcd:4;", this);
104+
}
105+
106+
}

0 commit comments

Comments
 (0)