2222
2323
2424import com .igormaznitsa .jbbp .JBBPCustomFieldTypeProcessor ;
25+ import com .igormaznitsa .jbbp .JBBPExternalValueProvider ;
26+ import com .igormaznitsa .jbbp .JBBPNamedNumericFieldMap ;
2527import com .igormaznitsa .jbbp .JBBPParser ;
28+ import com .igormaznitsa .jbbp .compiler .JBBPCompiledBlock ;
2629import com .igormaznitsa .jbbp .compiler .JBBPNamedFieldInfo ;
2730import com .igormaznitsa .jbbp .compiler .tokenizer .JBBPFieldTypeParameterContainer ;
2831import com .igormaznitsa .jbbp .io .JBBPBitInputStream ;
@@ -85,13 +88,16 @@ class YearMonthDay {
8588 @ Bin (type = BinType .BIT , bitNumber = JBBPBitNumber .BITS_5 , order = 3 , bitOrder = JBBPBitOrder .MSB0 )
8689 byte day ;
8790 }
88- final YearMonthDay parsed = JBBPParser .prepare ("bit:6 year; bit:4 month; bit:5 day;" , JBBPBitOrder .MSB0 ).parse (new byte [] {(byte ) 0x3D , (byte ) 0xF8 }).mapTo (new YearMonthDay ());
91+ final YearMonthDay parsed =
92+ JBBPParser .prepare ("bit:6 year; bit:4 month; bit:5 day;" , JBBPBitOrder .MSB0 )
93+ .parse (new byte [] {(byte ) 0x3D , (byte ) 0xF8 }).mapTo (new YearMonthDay ());
8994
9095 assertEquals (0x0F , parsed .year );
9196 assertEquals (0x07 , parsed .month );
9297 assertEquals (0x1C , parsed .day & 0xFF );
9398
94- assertArrayEquals (new byte [] {(byte ) 0x3D , (byte ) 0xF8 }, JBBPOut .BeginBin (JBBPBitOrder .MSB0 ).Bin (parsed ).End ().toByteArray ());
99+ assertArrayEquals (new byte [] {(byte ) 0x3D , (byte ) 0xF8 },
100+ JBBPOut .BeginBin (JBBPBitOrder .MSB0 ).Bin (parsed ).End ().toByteArray ());
95101 }
96102
97103 /**
@@ -122,14 +128,17 @@ class TetraTimestamp {
122128 }
123129
124130
125- TetraTimestamp parsed = JBBPParser .prepare ("bit:2 timezone; bit:2 reserved; bit:4 month; bit:5 day; bit:5 hour; bit:6 minute;" , JBBPBitOrder .MSB0 ).parse (TEST_DATA ).mapTo (new TetraTimestamp ());
131+ TetraTimestamp parsed = JBBPParser .prepare (
132+ "bit:2 timezone; bit:2 reserved; bit:4 month; bit:5 day; bit:5 hour; bit:6 minute;" ,
133+ JBBPBitOrder .MSB0 ).parse (TEST_DATA ).mapTo (new TetraTimestamp ());
126134
127135 assertEquals (2 , parsed .month );
128136 assertEquals (8 , parsed .day );
129137 assertEquals (10 , parsed .hour );
130138 assertEquals (1 , parsed .minute );
131139
132- assertArrayEquals (TEST_DATA , JBBPOut .BeginBin (JBBPBitOrder .MSB0 ).Bin (parsed ).End ().toByteArray ());
140+ assertArrayEquals (TEST_DATA ,
141+ JBBPOut .BeginBin (JBBPBitOrder .MSB0 ).Bin (parsed ).End ().toByteArray ());
133142 }
134143
135144 /**
@@ -200,9 +209,13 @@ public void testMutlithredUsageOfParser() throws Exception {
200209 for (int i = 0 ; i < ITERATIONS ; i ++) {
201210 try {
202211 Thread .sleep (System .nanoTime () & 0xF );
203- final byte [] ippacket = parserTCP .parse (theData ).findFieldForNameAndType ("Data" , JBBPFieldArrayByte .class ).getArray ();
212+ final byte [] ippacket =
213+ parserTCP .parse (theData ).findFieldForNameAndType ("Data" , JBBPFieldArrayByte .class )
214+ .getArray ();
204215 assertEquals (119 , ippacket .length );
205- final byte [] optionsip = parserIP .parse (ippacket ).findFieldForNameAndType ("Options" , JBBPFieldArrayByte .class ).getArray ();
216+ final byte [] optionsip =
217+ parserIP .parse (ippacket ).findFieldForNameAndType ("Options" , JBBPFieldArrayByte .class )
218+ .getArray ();
206219 assertEquals (4 , optionsip .length );
207220 parsingCounter .incrementAndGet ();
208221 } catch (Exception ex ) {
@@ -236,7 +249,8 @@ class Bits {
236249 byte [] bit ;
237250 }
238251
239- JBBPParser parser = JBBPParser .prepare (JBBPDslBuilder .Begin ().AnnotatedClassFields (Bits .class ).End ());
252+ JBBPParser parser =
253+ JBBPParser .prepare (JBBPDslBuilder .Begin ().AnnotatedClassFields (Bits .class ).End ());
240254
241255 Bits parsed = parser .parse (new byte [] {73 }).mapTo (new Bits ());
242256
@@ -253,11 +267,14 @@ class Bits {
253267 */
254268 @ Test
255269 public void testStringMsb0 () throws Exception {
256- JBBPOut joparam = JBBPOut .BeginBin (JBBPByteOrder .BIG_ENDIAN , JBBPBitOrder .MSB0 ).String ("zzzz" ).Int (12345 );
270+ JBBPOut joparam =
271+ JBBPOut .BeginBin (JBBPByteOrder .BIG_ENDIAN , JBBPBitOrder .MSB0 ).String ("zzzz" ).Int (12345 );
257272 final byte [] array = joparam .End ().toByteArray ();
258273 assertArrayEquals (new byte [] {32 , 94 , 94 , 94 , 94 , 0 , 0 , 0x0C , (byte ) 0x9C }, array );
259- final JBBPFieldStruct bitflds = JBBPParser .prepare ("stringj fin; int i;" , JBBPBitOrder .MSB0 ).parse (array );
260- assertEquals ("zzzz" , bitflds .findFieldForNameAndType ("fin" , JBBPFieldString .class ).getAsString ());
274+ final JBBPFieldStruct bitflds =
275+ JBBPParser .prepare ("stringj fin; int i;" , JBBPBitOrder .MSB0 ).parse (array );
276+ assertEquals ("zzzz" ,
277+ bitflds .findFieldForNameAndType ("fin" , JBBPFieldString .class ).getAsString ());
261278 assertEquals (12345 , bitflds .findFieldForNameAndType ("i" , JBBPFieldInt .class ).getAsInt ());
262279 }
263280
@@ -324,15 +341,22 @@ private String readPascalAscIIString(final JBBPBitInputStream in) throws IOExcep
324341 }
325342 }
326343
327- final JBBPParser parserSingle = JBBPParser .prepare ("asciistr str1; asciistr str2;" , new AscIIPascalString ());
344+ final JBBPParser parserSingle =
345+ JBBPParser .prepare ("asciistr str1; asciistr str2;" , new AscIIPascalString ());
328346 final JBBPFieldStruct parsedSingle = parserSingle .parse (new byte [] {5 , 65 , 66 , 67 , 68 , 69 , 0 });
329- assertEquals ("ABCDE" , parsedSingle .findFieldForNameAndType ("str1" , JBBPFieldString .class ).getAsString ());
330- assertEquals ("" , parsedSingle .findFieldForNameAndType ("str2" , JBBPFieldString .class ).getAsString ());
331-
332- final JBBPParser parserArray = JBBPParser .prepare ("asciistr [2] str1; asciistr [_] str2;" , new AscIIPascalString ());
333- final JBBPFieldStruct parsedArrays = parserArray .parse (new byte [] {2 , 65 , 66 , 1 , 67 , 3 , 68 , 69 , 70 , 2 , 71 , 72 , 1 , 73 });
334- assertArrayEquals (new String [] {"AB" , "C" }, parsedArrays .findFieldForNameAndType ("str1" , JBBPFieldArrayString .class ).getArray ());
335- assertArrayEquals (new String [] {"DEF" , "GH" , "I" }, parsedArrays .findFieldForNameAndType ("str2" , JBBPFieldArrayString .class ).getArray ());
347+ assertEquals ("ABCDE" ,
348+ parsedSingle .findFieldForNameAndType ("str1" , JBBPFieldString .class ).getAsString ());
349+ assertEquals ("" ,
350+ parsedSingle .findFieldForNameAndType ("str2" , JBBPFieldString .class ).getAsString ());
351+
352+ final JBBPParser parserArray =
353+ JBBPParser .prepare ("asciistr [2] str1; asciistr [_] str2;" , new AscIIPascalString ());
354+ final JBBPFieldStruct parsedArrays =
355+ parserArray .parse (new byte [] {2 , 65 , 66 , 1 , 67 , 3 , 68 , 69 , 70 , 2 , 71 , 72 , 1 , 73 });
356+ assertArrayEquals (new String [] {"AB" , "C" },
357+ parsedArrays .findFieldForNameAndType ("str1" , JBBPFieldArrayString .class ).getArray ());
358+ assertArrayEquals (new String [] {"DEF" , "GH" , "I" },
359+ parsedArrays .findFieldForNameAndType ("str2" , JBBPFieldArrayString .class ).getArray ());
336360 }
337361
338362 /**
@@ -349,7 +373,8 @@ final class Uint32 implements JBBPCustomFieldTypeProcessor {
349373
350374 private final String [] TYPES = new String [] {"uint32" };
351375
352- private long uint32_read (final JBBPBitInputStream in , final JBBPByteOrder byteOrder , final JBBPBitOrder bitOrder ) throws IOException {
376+ private long uint32_read (final JBBPBitInputStream in , final JBBPByteOrder byteOrder ,
377+ final JBBPBitOrder bitOrder ) throws IOException {
353378 final int signedInt = in .readInt (byteOrder );
354379 return signedInt & 0xffffffffL ;
355380 }
@@ -360,7 +385,8 @@ public String[] getCustomFieldTypes() {
360385 }
361386
362387 @ Override
363- public boolean isAllowed (final JBBPFieldTypeParameterContainer fieldType , final String fieldName , final int extraData , final boolean isArray ) {
388+ public boolean isAllowed (final JBBPFieldTypeParameterContainer fieldType ,
389+ final String fieldName , final int extraData , final boolean isArray ) {
364390 return extraData == 0 ;
365391 }
366392
@@ -374,10 +400,14 @@ private long[] convertLongs(List<Long> longs) {
374400 }
375401
376402 @ Override
377- public JBBPAbstractField readCustomFieldType (final JBBPBitInputStream in , final JBBPBitOrder bitOrder ,
378- final int parserFlags , final JBBPFieldTypeParameterContainer customTypeFieldInfo ,
379- final JBBPNamedFieldInfo fieldName , final int extraData ,
380- final boolean readWholeStream , final int arrayLength ) throws IOException {
403+ public JBBPAbstractField readCustomFieldType (final JBBPBitInputStream in ,
404+ final JBBPBitOrder bitOrder ,
405+ final int parserFlags ,
406+ final JBBPFieldTypeParameterContainer customTypeFieldInfo ,
407+ final JBBPNamedFieldInfo fieldName ,
408+ final int extraData ,
409+ final boolean readWholeStream ,
410+ final int arrayLength ) throws IOException {
381411 if (arrayLength < 0 ) {
382412 final long uint32_val = uint32_read (in , customTypeFieldInfo .getByteOrder (), bitOrder );
383413 return new JBBPFieldLong (fieldName , uint32_val );
@@ -423,6 +453,48 @@ public JBBPAbstractField readCustomFieldType(final JBBPBitInputStream in, final
423453 assertEquals (2 , ((JBBPNumericField ) result .findFieldForName ("keycount" )).getAsInt ());
424454 }
425455
456+ /**
457+ * Case 09-jun-2020
458+ * Example how to use external variable value provider.
459+ *
460+ * @throws Exception for any error
461+ */
462+ @ Test
463+ public void testByteArrayWhichLengthProvidedExternally () throws Exception {
464+ class BKlazz {
465+ @ Bin (order = 1 , type = BinType .BYTE_ARRAY )
466+ byte [] a ;
467+ @ Bin (order = 2 , type = BinType .BYTE_ARRAY )
468+ byte [] b ;
469+ @ Bin (order = 3 , type = BinType .BYTE_ARRAY )
470+ byte [] c ;
471+ }
472+
473+ JBBPParser parser = JBBPParser .prepare ("byte [$alen] a; byte [$blen] b; byte [$clen] c;" );
474+
475+ BKlazz parsed = parser .parse (new byte [] {1 ,2 ,3 }, null , new JBBPExternalValueProvider () {
476+ @ Override
477+ public int provideArraySize (String fieldName ,
478+ JBBPNamedNumericFieldMap numericFieldMap ,
479+ JBBPCompiledBlock compiledBlock ) {
480+ if ("alen" .equals (fieldName )) {
481+ return 0 ;
482+ } else if ("blen" .equals (fieldName )) {
483+ return 3 ;
484+ } else if ("clen" .equals (fieldName )) {
485+ return 0 ;
486+ } else {
487+ throw new IllegalArgumentException ("Unknown name: " + fieldName );
488+ }
489+
490+ }
491+ }).mapTo (new BKlazz ());
492+
493+ assertArrayEquals (new byte [0 ], parsed .a );
494+ assertArrayEquals (new byte []{1 ,2 ,3 }, parsed .b );
495+ assertArrayEquals (new byte [0 ], parsed .c );
496+ }
497+
426498 /**
427499 * Case 09-jun-2020
428500 * Example how to write custom field type read-write-mapping processor for nullable byte array.
0 commit comments