@@ -151,30 +151,38 @@ private StructStackItem(final int namedFieldCounter, final int startStructureOff
151151 * The Byte-Code Flag shows that the field is a named one.
152152 */
153153 public static final int FLAG_NAMED = 0x10 ;
154-
154+
155155 /**
156156 * The Byte-Code Flag shows that the field is an array but it must be omitted
157157 * for unlimited field arrays.
158158 */
159159 public static final int FLAG_ARRAY = 0x20 ;
160-
160+
161161 /**
162162 * The Byte-Code Flag shows that a multi-byte field must be decoded as
163163 * Little-endian one.
164164 */
165165 public static final int FLAG_LITTLE_ENDIAN = 0x40 ;
166166
167167 /**
168- * The Flag shows that the byte code is wide and contains extra byte in the next position of compiled block.
168+ * The Flag shows that the byte code is wide and contains extra byte in the
169+ * next position of compiled block.
169170 */
170171 public static final int FLAG_WIDE = 0x80 ;
171172
172173 /**
173- * The flag (placed only in the second byte of wide codes) shows that the field is an array which calculated size or unlimited and must be read till the end of a
174- * stream.
174+ * The flag (placed only in the second byte of wide codes) shows that the
175+ * field is an array which calculated size or unlimited and must be read till
176+ * the end of a stream.
175177 */
176178 public static final int EXT_FLAG_EXPRESSION_OR_WHOLESTREAM = 0x01 ;
177179
180+ /**
181+ * The flag shows that the extra numeric value for field should be recognized
182+ * not as number but as expression.
183+ */
184+ public static final int EXT_FLAG_EXTRA_AS_EXPRESSION = 0x02 ;
185+
178186 public static JBBPCompiledBlock compile (final String script ) throws IOException {
179187 return compile (script , null );
180188 }
@@ -218,25 +226,27 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie
218226 final int startFieldOffset = offset ;
219227
220228 final int extracode = code >>> 8 ;
221-
229+
222230 out .write (code );
223231 offset ++;
224232
225- if ((code & FLAG_WIDE )!= 0 ) {
233+ if ((code & FLAG_WIDE ) != 0 ) {
226234 out .write (extracode );
227235 offset ++;
228236 }
229-
237+
230238 StructStackItem currentClosedStructure = null ;
231- boolean extraFieldPresented = false ;
232- int extraField = -1 ;
239+ boolean writeExtraFieldNumberInCompiled = false ;
240+ int extraFieldNumberAsInt = -1 ;
233241 int customTypeFieldIndex = -1 ;
234242
235243 // check that the field is not in the current structure which is a whole stream one
236244 if ((code & 0xF ) != CODE_STRUCT_END && fieldUnrestrictedArrayOffset >= 0 && (structureStack .isEmpty () || structureStack .get (structureStack .size () - 1 ).startStructureOffset != fieldUnrestrictedArrayOffset )) {
237245 throw new JBBPCompilationException ("Attempt to read after a 'till-the-end' field" , token );
238246 }
239247
248+ final boolean extraFieldNumericDataAsExpression = ((code >>> 8 ) & EXT_FLAG_EXTRA_AS_EXPRESSION ) != 0 ;
249+
240250 switch (code & 0xF ) {
241251 case CODE_BOOL :
242252 case CODE_BYTE :
@@ -247,20 +257,25 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie
247257 case CODE_CUSTOMTYPE :
248258 case CODE_LONG : {
249259 if ((code & 0x0F ) == CODE_CUSTOMTYPE ) {
250- final String extraDataAsStr = token .getFieldTypeParameters ().getExtraData ();
251- if (extraDataAsStr == null ) {
252- extraField = 0 ;
260+ if (extraFieldNumericDataAsExpression ) {
261+ varLengthEvaluators .add (JBBPEvaluatorFactory .getInstance ().make (token .getFieldTypeParameters ().getExtraDataExpression (), namedFields , out .toByteArray ()));
253262 }
254263 else {
255- try {
256- extraField = Integer .parseInt (extraDataAsStr );
264+ final String extraDataAsStr = token .getFieldTypeParameters ().getExtraData ();
265+ if (extraDataAsStr == null ) {
266+ extraFieldNumberAsInt = 0 ;
257267 }
258- catch (NumberFormatException ex ) {
259- throw new JBBPCompilationException ("Can't parse extra data, must be numeric" , token );
268+ else {
269+ try {
270+ extraFieldNumberAsInt = Integer .parseInt (extraDataAsStr );
271+ }
272+ catch (NumberFormatException ex ) {
273+ throw new JBBPCompilationException ("Can't parse extra data, must be numeric" , token );
274+ }
260275 }
276+ writeExtraFieldNumberInCompiled = true ;
261277 }
262- extraFieldPresented = true ;
263- if (customTypeFieldProcessor .isAllowed (token .getFieldTypeParameters (), token .getFieldName (), extraField , token .isArray ())) {
278+ if (customTypeFieldProcessor .isAllowed (token .getFieldTypeParameters (), token .getFieldName (), extraFieldNumberAsInt , token .isArray ())) {
264279 customTypeFieldIndex = customTypeFields .size ();
265280 customTypeFields .add (token .getFieldTypeParameters ());
266281 }
@@ -277,18 +292,23 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie
277292 if (token .getFieldName () != null ) {
278293 throw new JBBPCompilationException ("'skip' must not be named" , token );
279294 }
280- final String parsedSkipByteNumber = token .getFieldTypeParameters ().getExtraData ();
281- extraFieldPresented = true ;
282- if (parsedSkipByteNumber == null ) {
283- extraField = 1 ;
295+ if (extraFieldNumericDataAsExpression ) {
296+ varLengthEvaluators .add (JBBPEvaluatorFactory .getInstance ().make (token .getFieldTypeParameters ().getExtraDataExpression (), namedFields , out .toByteArray ()));
284297 }
285298 else {
286- try {
287- extraField = Integer .parseInt (parsedSkipByteNumber );
288- assertNonNegativeValue (extraField , token );
299+ final String extraNumberAsStr = token .getFieldTypeParameters ().getExtraData ();
300+ writeExtraFieldNumberInCompiled = true ;
301+ if (extraNumberAsStr == null ) {
302+ extraFieldNumberAsInt = 1 ;
289303 }
290- catch (NumberFormatException ex ) {
291- extraField = -1 ;
304+ else {
305+ try {
306+ extraFieldNumberAsInt = Integer .parseInt (extraNumberAsStr );
307+ assertNonNegativeValue (extraFieldNumberAsInt , token );
308+ }
309+ catch (NumberFormatException ex ) {
310+ extraFieldNumberAsInt = -1 ;
311+ }
292312 }
293313 }
294314 }
@@ -301,58 +321,79 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie
301321 throw new JBBPCompilationException ("'align' must not be named" , token );
302322 }
303323
304- final String parsedAlignBytesNumber = token .getFieldTypeParameters ().getExtraData ();
305- extraFieldPresented = true ;
306- if (parsedAlignBytesNumber == null ) {
307- extraField = 1 ;
324+ if (extraFieldNumericDataAsExpression ) {
325+ varLengthEvaluators .add (JBBPEvaluatorFactory .getInstance ().make (token .getFieldTypeParameters ().getExtraDataExpression (), namedFields , out .toByteArray ()));
308326 }
309327 else {
310- try {
311- extraField = Integer .parseInt (parsedAlignBytesNumber );
312- assertNonNegativeValue (extraField , token );
328+ final String extraNumberAsStr = token .getFieldTypeParameters ().getExtraData ();
329+ writeExtraFieldNumberInCompiled = true ;
330+ if (extraNumberAsStr == null ) {
331+ extraFieldNumberAsInt = 1 ;
313332 }
314- catch (NumberFormatException ex ) {
315- extraField = -1 ;
316- }
317- if (extraField <= 0 ) {
318- throw new JBBPCompilationException ("'align' size must be greater than zero [" + token .getFieldTypeParameters ().getExtraData () + ']' , token );
333+ else {
334+ try {
335+ extraFieldNumberAsInt = Integer .parseInt (extraNumberAsStr );
336+ assertNonNegativeValue (extraFieldNumberAsInt , token );
337+ }
338+ catch (NumberFormatException ex ) {
339+ extraFieldNumberAsInt = -1 ;
340+ }
341+ if (extraFieldNumberAsInt <= 0 ) {
342+ throw new JBBPCompilationException ("'align' size must be greater than zero [" + token .getFieldTypeParameters ().getExtraData () + ']' , token );
343+ }
319344 }
320345 }
321346 }
322347 break ;
323348 case CODE_BIT : {
324- final String parsedBitNumber = token .getFieldTypeParameters ().getExtraData ();
325- extraFieldPresented = true ;
326- if (parsedBitNumber == null ) {
327- extraField = 1 ;
349+ if (extraFieldNumericDataAsExpression ) {
350+ varLengthEvaluators .add (JBBPEvaluatorFactory .getInstance ().make (token .getFieldTypeParameters ().getExtraDataExpression (), namedFields , out .toByteArray ()));
328351 }
329352 else {
330- try {
331- extraField = Integer .parseInt (parsedBitNumber );
332- assertNonNegativeValue (extraField , token );
353+ final String extraFieldNumAsStr = token .getFieldTypeParameters ().getExtraData ();
354+ writeExtraFieldNumberInCompiled = true ;
355+ if (extraFieldNumAsStr == null ) {
356+ extraFieldNumberAsInt = 1 ;
333357 }
334- catch (NumberFormatException ex ) {
335- extraField = -1 ;
336- }
337- if (extraField < 1 || extraField > 8 ) {
338- throw new JBBPCompilationException ("Bit-width must be 1..8 [" + token .getFieldTypeParameters ().getExtraData () + ']' , token );
358+ else {
359+ try {
360+ extraFieldNumberAsInt = Integer .parseInt (extraFieldNumAsStr );
361+ assertNonNegativeValue (extraFieldNumberAsInt , token );
362+ }
363+ catch (NumberFormatException ex ) {
364+ extraFieldNumberAsInt = -1 ;
365+ }
366+ if (extraFieldNumberAsInt < 1 || extraFieldNumberAsInt > 8 ) {
367+ throw new JBBPCompilationException ("Bit-width must be 1..8 [" + token .getFieldTypeParameters ().getExtraData () + ']' , token );
368+ }
339369 }
340370 }
341371 }
342372 break ;
343373 case CODE_VAR : {
344374 hasVarFields = true ;
345- final String parsedExtraField = token .getFieldTypeParameters ().getExtraData ();
346- extraFieldPresented = true ;
347- if (parsedExtraField == null ) {
348- extraField = 0 ;
375+ if (extraFieldNumericDataAsExpression ) {
376+ varLengthEvaluators .add (JBBPEvaluatorFactory .getInstance ().make (token .getFieldTypeParameters ().getExtraDataExpression (), namedFields , out .toByteArray ()));
349377 }
350378 else {
351- try {
352- extraField = Integer .parseInt (parsedExtraField );
379+ final String extraFieldNumStr = token .getFieldTypeParameters ().getExtraData ();
380+ writeExtraFieldNumberInCompiled = true ;
381+ if (extraFieldNumStr == null ) {
382+ extraFieldNumberAsInt = 0 ;
353383 }
354- catch (NumberFormatException ex ) {
355- throw new JBBPCompilationException ("Can't parse the extra value of a VAR field, must be integer [" + token .getFieldTypeParameters ().getExtraData () + ']' , token );
384+ else {
385+ if ((code & EXT_FLAG_EXTRA_AS_EXPRESSION ) != 0 ) {
386+ varLengthEvaluators .add (JBBPEvaluatorFactory .getInstance ().make (token .getFieldTypeParameters ().getExtraData (), namedFields , out .toByteArray ()));
387+ writeExtraFieldNumberInCompiled = false ;
388+ }
389+ else {
390+ try {
391+ extraFieldNumberAsInt = Integer .parseInt (extraFieldNumStr );
392+ }
393+ catch (NumberFormatException ex ) {
394+ throw new JBBPCompilationException ("Can't parse the extra value of a VAR field, must be integer [" + token .getFieldTypeParameters ().getExtraData () + ']' , token );
395+ }
396+ }
356397 }
357398 }
358399 }
@@ -410,8 +451,8 @@ public static JBBPCompiledBlock compile(final String script, final JBBPCustomFie
410451 }
411452 }
412453
413- if (extraFieldPresented ) {
414- offset += writePackedInt (out , extraField );
454+ if (writeExtraFieldNumberInCompiled ) {
455+ offset += writePackedInt (out , extraFieldNumberAsInt );
415456 }
416457
417458 if (customTypeFieldIndex >= 0 ) {
@@ -533,7 +574,11 @@ private static int prepareCodeForToken(final JBBPToken token, final JBBPCustomFi
533574 final JBBPFieldTypeParameterContainer descriptor = token .getFieldTypeParameters ();
534575
535576 result = descriptor .getByteOrder () == JBBPByteOrder .LITTLE_ENDIAN ? FLAG_LITTLE_ENDIAN : 0 ;
536- result |= token .getArraySizeAsString () == null ? 0 : (token .isVarArrayLength () ? FLAG_ARRAY | FLAG_WIDE | (EXT_FLAG_EXPRESSION_OR_WHOLESTREAM <<8 ) : FLAG_ARRAY );
577+
578+ final boolean hasExpressionAsExtraNumber = descriptor .hasExpressionAsExtraData ();
579+
580+ result |= token .getArraySizeAsString () == null ? 0 : (token .isVarArrayLength () ? FLAG_ARRAY | FLAG_WIDE | (EXT_FLAG_EXPRESSION_OR_WHOLESTREAM << 8 ) : FLAG_ARRAY );
581+ result |= hasExpressionAsExtraNumber ? FLAG_WIDE | (EXT_FLAG_EXTRA_AS_EXPRESSION << 8 ) : 0 ;
537582 result |= token .getFieldName () == null ? 0 : FLAG_NAMED ;
538583
539584 final String name = descriptor .getTypeName ().toLowerCase (Locale .ENGLISH );
0 commit comments