@SuppressWarnings("ConstantConditions")
  private List<JBBPAbstractField> parseStruct(final JBBPBitInputStream inStream, final JBBPIntCounter positionAtCompiledBlock, final JBBPVarFieldProcessor varFieldProcessor, final JBBPNamedNumericFieldMap namedNumericFieldMap, final JBBPIntCounter positionAtNamedFieldList, final JBBPIntCounter positionAtVarLengthProcessors, final boolean skipStructureFields) throws IOException {
    final List<JBBPAbstractField> structureFields = skipStructureFields ? null : new ArrayList<>();
    final byte[] compiled = this.compiledBlock.getCompiledData();

    boolean endStructureNotMet = true;

    while (endStructureNotMet && positionAtCompiledBlock.get() < compiled.length) {
      if (!inStream.hasAvailableData() && (flags & FLAG_SKIP_REMAINING_FIELDS_IF_EOF) != 0) {
        // Break reading because the ignore flag for EOF has been set
        break;
      }

      final int c = compiled[positionAtCompiledBlock.getAndIncrement()] & 0xFF;
      final boolean wideCode = (c & JBBPCompiler.FLAG_WIDE) != 0;
      final int ec = wideCode ? compiled[positionAtCompiledBlock.getAndIncrement()] & 0xFF : 0;
      final boolean extraFieldNumAsExpr = (ec & JBBPCompiler.EXT_FLAG_EXTRA_AS_EXPRESSION) != 0;
      final int code = (ec << 8) | c;
      final boolean fieldTypeDiff = (ec & JBBPCompiler.EXT_FLAG_EXTRA_DIFF_TYPE) != 0;

      final JBBPNamedFieldInfo name = (code & JBBPCompiler.FLAG_NAMED) == 0 ? null : compiledBlock.getNamedFields()[positionAtNamedFieldList.getAndIncrement()];
      final JBBPByteOrder byteOrder = (code & JBBPCompiler.FLAG_LITTLE_ENDIAN) == 0 ? JBBPByteOrder.BIG_ENDIAN : JBBPByteOrder.LITTLE_ENDIAN;

      final boolean resultNotIgnored = !skipStructureFields;

      final int extraFieldNumExprResult;
      if (extraFieldNumAsExpr) {
        final JBBPIntegerValueEvaluator evaluator = this.compiledBlock.getArraySizeEvaluators()[positionAtVarLengthProcessors.getAndIncrement()];
        int resultOfExpression;
        if (resultNotIgnored) {
          resultOfExpression = evaluator.eval(inStream, positionAtCompiledBlock.get(), this.compiledBlock, namedNumericFieldMap);
          if ((this.flags & FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO) != 0) {
            resultOfExpression = Math.max(resultOfExpression, 0);
          }
        } else {
          resultOfExpression = 0;
        }
        extraFieldNumExprResult = resultOfExpression;
      } else {
        extraFieldNumExprResult = 0;
      }

      final boolean wholeStreamArray;
      final int arrayLength;
      final int packedArraySizeOffset;
      switch (code & (JBBPCompiler.FLAG_ARRAY | (JBBPCompiler.EXT_FLAG_EXPRESSION_OR_WHOLESTREAM << 8))) {
        case JBBPCompiler.FLAG_ARRAY: {
          final int pos = positionAtCompiledBlock.get();
          arrayLength = JBBPUtils.unpackInt(compiled, positionAtCompiledBlock);
          packedArraySizeOffset = positionAtCompiledBlock.get() - pos;
          wholeStreamArray = false;
        }
        break;
        case (JBBPCompiler.EXT_FLAG_EXPRESSION_OR_WHOLESTREAM << 8): {
          wholeStreamArray = resultNotIgnored;
          packedArraySizeOffset = 0;
          arrayLength = 0;
        }
        break;
        case JBBPCompiler.FLAG_ARRAY | (JBBPCompiler.EXT_FLAG_EXPRESSION_OR_WHOLESTREAM << 8): {
          final JBBPIntegerValueEvaluator evaluator = this.compiledBlock.getArraySizeEvaluators()[positionAtVarLengthProcessors.getAndIncrement()];
          int resultOfExpression;
          if (resultNotIgnored) {
            resultOfExpression = evaluator.eval(inStream, positionAtCompiledBlock.get(), this.compiledBlock, namedNumericFieldMap);
            if ((this.flags & FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO) != 0) {
              resultOfExpression = Math.max(resultOfExpression, 0);
            }
          } else {
            resultOfExpression = 0;
          }
          arrayLength = resultOfExpression;
          packedArraySizeOffset = 0;
          assertArrayLength(arrayLength, name);
          wholeStreamArray = false;
        }
        break;
        default: {
          // it is not an array, just a single field
          packedArraySizeOffset = 0;
          wholeStreamArray = false;
          arrayLength = -1;
        }
        break;
      }

      JBBPAbstractField singleAtomicField = null;
      try {
        switch (code & 0xF) {
          case JBBPCompiler.CODE_RESET_COUNTER: {
            if (resultNotIgnored) {
              inStream.resetCounter();
            }
          }
          break;
          case JBBPCompiler.CODE_ALIGN: {
            final int alignValue = extraFieldNumAsExpr ? extraFieldNumExprResult : JBBPUtils.unpackInt(compiled, positionAtCompiledBlock);
            if (resultNotIgnored) {
              inStream.align(alignValue);
            }
          }
          break;
          case JBBPCompiler.CODE_SKIP: {
            final int skipByteNumber = extraFieldNumAsExpr ? extraFieldNumExprResult : JBBPUtils.unpackInt(compiled, positionAtCompiledBlock);
            if (resultNotIgnored) {
              if (fieldTypeDiff) {
                singleAtomicField = new JBBPFieldInt(name, skipByteNumber);
              } else {
                if (skipByteNumber > 0) {
                  final long skippedBytes = inStream.skip(skipByteNumber);
                  if (skippedBytes != skipByteNumber) {
                    throw new EOFException("Can't skip " + skipByteNumber + " byte(s), skipped only " + skippedBytes + " byte(s)");
                  }
                }
              }
            }
          }
          break;
          case JBBPCompiler.CODE_BIT: {
            final int numberOfBits = extraFieldNumAsExpr ? extraFieldNumExprResult : JBBPUtils.unpackInt(compiled, positionAtCompiledBlock);
            if (resultNotIgnored) {
              final JBBPBitNumber bitNumber = JBBPBitNumber.decode(numberOfBits);
              if (arrayLength < 0) {
                final int read = inStream.readBitField(bitNumber);
                singleAtomicField = new JBBPFieldBit(name, read & 0xFF, bitNumber);
              } else {
                structureFields.add(new JBBPFieldArrayBit(name, inStream.readBitsArray(wholeStreamArray ? -1 : arrayLength, bitNumber), bitNumber));
              }
            }
          }
          break;
          case JBBPCompiler.CODE_VAR: {
            final int extraField = extraFieldNumAsExpr ? extraFieldNumExprResult : JBBPUtils.unpackInt(compiled, positionAtCompiledBlock);
            if (resultNotIgnored) {
              if (arrayLength < 0) {
                singleAtomicField = varFieldProcessor.readVarField(inStream, name, extraField, byteOrder, namedNumericFieldMap);
                JBBPUtils.assertNotNull(singleAtomicField, "A Var processor must not return null as a result of a field reading");
                if (singleAtomicField instanceof JBBPAbstractArrayField) {
                  throw new JBBPParsingException("A Var field processor has returned an array value instead of a field value [" + name + ':' + extraField + ']');
                }
                if (singleAtomicField.getNameInfo() != name) {
                  throw new JBBPParsingException("Detected wrong name for a read field , must be " + name + " but detected " + singleAtomicField.getNameInfo() + ']');
                }
              } else {
                final JBBPAbstractArrayField<? extends JBBPAbstractField> array = varFieldProcessor.readVarArray(inStream, wholeStreamArray ? -1 : arrayLength, name, extraField, byteOrder, namedNumericFieldMap);
                JBBPUtils.assertNotNull(array, "A Var processor must not return null as a result of an array field reading [" + name + ':' + extraField + ']');
                if (array.getNameInfo() != name) {
                  throw new JBBPParsingException("Detected wrong name for a read field array, must be " + name + " but detected " + array.getNameInfo() + ']');
                }
                structureFields.add(array);
              }
            }
          }
          break;
          case JBBPCompiler.CODE_CUSTOMTYPE: {
            final int extraData = extraFieldNumAsExpr ? extraFieldNumExprResult : JBBPUtils.unpackInt(compiled, positionAtCompiledBlock);
            if (resultNotIgnored) {
              final JBBPFieldTypeParameterContainer fieldTypeInfo = this.compiledBlock.getCustomTypeFields()[JBBPUtils.unpackInt(compiled, positionAtCompiledBlock)];
              final JBBPAbstractField field = this.customFieldTypeProcessor.readCustomFieldType(inStream, this.bitOrder, this.flags, fieldTypeInfo, name, extraData, wholeStreamArray, arrayLength);
              JBBPUtils.assertNotNull(field, "Must not return null as read result");

              if (arrayLength < 0) {
                singleAtomicField = field;
              } else {
                structureFields.add(field);
              }
            }
          }
          break;
          case JBBPCompiler.CODE_BYTE: {
            if (resultNotIgnored) {
              if (arrayLength < 0) {
                singleAtomicField = new JBBPFieldByte(name, (byte) inStream.readByte());
              } else {
                structureFields.add(new JBBPFieldArrayByte(name, inStream.readByteArray(wholeStreamArray ? -1 : arrayLength, byteOrder)));
              }
            }
          }
          break;
          case JBBPCompiler.CODE_UBYTE: {
            if (resultNotIgnored) {
              if (arrayLength < 0) {
                singleAtomicField = new JBBPFieldUByte(name, (byte) inStream.readByte());
              } else {
                structureFields.add(new JBBPFieldArrayUByte(name, inStream.readByteArray(wholeStreamArray ? -1 : arrayLength, byteOrder)));
              }
            }
          }
          break;
          case JBBPCompiler.CODE_BOOL: {
            if (resultNotIgnored) {
              if (arrayLength < 0) {
                singleAtomicField = fieldTypeDiff ? new JBBPFieldString(name, inStream.readString(byteOrder)) : new JBBPFieldBoolean(name, inStream.readBoolean());
              } else {
                structureFields.add(fieldTypeDiff ?
                        new JBBPFieldArrayString(name, inStream.readStringArray(wholeStreamArray ? -1 : arrayLength, byteOrder)) :
                        new JBBPFieldArrayBoolean(name, inStream.readBoolArray(wholeStreamArray ? -1 : arrayLength))
                );
              }
            }
          }
          break;
          case JBBPCompiler.CODE_INT: {
            if (resultNotIgnored) {
              if (arrayLength < 0) {
                singleAtomicField = fieldTypeDiff ? new JBBPFieldFloat(name, inStream.readFloat(byteOrder)) : new JBBPFieldInt(name, inStream.readInt(byteOrder));
              } else {
                structureFields.add(fieldTypeDiff ?
                    new JBBPFieldArrayFloat(name, inStream.readFloatArray(wholeStreamArray ? -1 : arrayLength, byteOrder)) :
                    new JBBPFieldArrayInt(name, inStream.readIntArray(wholeStreamArray ? -1 : arrayLength, byteOrder))
                );
              }
            }
          }
          break;
          case JBBPCompiler.CODE_LONG: {
            if (resultNotIgnored) {
              if (arrayLength < 0) {
                singleAtomicField = fieldTypeDiff ? new JBBPFieldDouble(name, inStream.readDouble(byteOrder)) : new JBBPFieldLong(name, inStream.readLong(byteOrder));
              } else {
                structureFields.add(fieldTypeDiff ?
                    new JBBPFieldArrayDouble(name, inStream.readDoubleArray(wholeStreamArray ? -1 : arrayLength, byteOrder)) :
                    new JBBPFieldArrayLong(name, inStream.readLongArray(wholeStreamArray ? -1 : arrayLength, byteOrder))
                );
              }
            }
          }
          break;
          case JBBPCompiler.CODE_SHORT: {
            if (resultNotIgnored) {
              if (arrayLength < 0) {
                final int value = inStream.readUnsignedShort(byteOrder);
                singleAtomicField = new JBBPFieldShort(name, (short) value);
              } else {
                structureFields.add(new JBBPFieldArrayShort(name, inStream.readShortArray(wholeStreamArray ? -1 : arrayLength, byteOrder)));
              }
            }
          }
          break;
          case JBBPCompiler.CODE_USHORT: {
            if (resultNotIgnored) {
              if (arrayLength < 0) {
                final int value = inStream.readUnsignedShort(byteOrder);
                singleAtomicField = new JBBPFieldUShort(name, (short) value);
              } else {
                structureFields.add(new JBBPFieldArrayUShort(name, inStream.readShortArray(wholeStreamArray ? -1 : arrayLength, byteOrder)));
              }
            }
          }
          break;
          case JBBPCompiler.CODE_STRUCT_START: {
            if (arrayLength < 0) {
              final List<JBBPAbstractField> structFields = parseStruct(inStream, positionAtCompiledBlock, varFieldProcessor, namedNumericFieldMap, positionAtNamedFieldList, positionAtVarLengthProcessors, skipStructureFields);
              // skip offset
              JBBPUtils.unpackInt(compiled, positionAtCompiledBlock);
              if (resultNotIgnored) {
                structureFields.add(new JBBPFieldStruct(name, structFields.toArray(ARRAY_FIELD_EMPTY)));
              }
            } else {
              final int nameFieldCurrent = positionAtNamedFieldList.get();
              final int varLenProcCurrent = positionAtVarLengthProcessors.get();

              final JBBPFieldStruct[] result;
              if (resultNotIgnored) {
                if (wholeStreamArray) {
                  // read till the stream end
                  final List<JBBPFieldStruct> list = new ArrayList<>();
                  while (inStream.hasAvailableData()) {
                    positionAtNamedFieldList.set(nameFieldCurrent);
                    positionAtVarLengthProcessors.set(varLenProcCurrent);

                    final List<JBBPAbstractField> fieldsForStruct = parseStruct(inStream, positionAtCompiledBlock, varFieldProcessor, namedNumericFieldMap, positionAtNamedFieldList, positionAtVarLengthProcessors, skipStructureFields);
                    list.add(new JBBPFieldStruct(name, fieldsForStruct));

                    final int structStart = JBBPUtils.unpackInt(compiled, positionAtCompiledBlock);

                    if (inStream.hasAvailableData()) {
                      positionAtCompiledBlock.set(structStart + (wideCode ? 2 : 1));
                    }
                  }

                  result = list.isEmpty() ? EMPTY_STRUCT_ARRAY : list.toArray(EMPTY_STRUCT_ARRAY);
                } else {
                  // read number of items
                  if (arrayLength == 0) {
                    // skip the structure
                    result = EMPTY_STRUCT_ARRAY;
                    parseStruct(inStream, positionAtCompiledBlock, varFieldProcessor, namedNumericFieldMap, positionAtNamedFieldList, positionAtVarLengthProcessors, true);
                    JBBPUtils.unpackInt(compiled, positionAtCompiledBlock);
                  } else {
                    result = new JBBPFieldStruct[arrayLength];
                    for (int i = 0; i < arrayLength; i++) {

                      final List<JBBPAbstractField> fieldsForStruct = parseStruct(inStream, positionAtCompiledBlock, varFieldProcessor, namedNumericFieldMap, positionAtNamedFieldList, positionAtVarLengthProcessors, skipStructureFields);
                      final int structBodyStart = JBBPUtils.unpackInt(compiled, positionAtCompiledBlock);

                      result[i] = new JBBPFieldStruct(name, fieldsForStruct);

                      if (i < arrayLength - 1) {
                        // not the last
                        positionAtNamedFieldList.set(nameFieldCurrent);
                        positionAtVarLengthProcessors.set(varLenProcCurrent);
                        positionAtCompiledBlock.set(structBodyStart + packedArraySizeOffset + (wideCode ? 2 : 1));
                      }
                    }
                  }
                }

                if (result != null) {
                  structureFields.add(new JBBPFieldArrayStruct(name, result));
                }
              } else {
                parseStruct(inStream, positionAtCompiledBlock, varFieldProcessor, namedNumericFieldMap, positionAtNamedFieldList, positionAtVarLengthProcessors, skipStructureFields);
                JBBPUtils.unpackInt(compiled, positionAtCompiledBlock);
              }
            }
          }
          break;
          case JBBPCompiler.CODE_STRUCT_END: {
            // we just left the method and the caller must process the structure offset start address for the structure
            endStructureNotMet = false;
          }
          break;
          default:
            throw new Error("Detected unexpected field type! Contact developer! [" + code + ']');
        }
      } catch (IOException ex) {
        if (name == null) {
          throw ex;
        } else {
          throw new JBBPParsingException("Can't parse field '" + name.getFieldPath() + "' for IOException", ex);
        }
      }

      if (singleAtomicField != null) {
        structureFields.add(singleAtomicField);
        if (namedNumericFieldMap != null && singleAtomicField instanceof JBBPNumericField && name != null) {
          namedNumericFieldMap.putField((JBBPNumericField) singleAtomicField);
        }
      }

    }

    return structureFields;
  }
@ SuppressWarnings ( "ConstantConditions" ) private List < JBBPAbstractField > parseStruct ( final JBBPBitInputStream inStream , final JBBPIntCounter positionAtCompiledBlock , final JBBPVarFieldProcessor varFieldProcessor , final JBBPNamedNumericFieldMap namedNumericFieldMap , final JBBPIntCounter positionAtNamedFieldList , final JBBPIntCounter positionAtVarLengthProcessors , final boolean skipStructureFields ) throws IOException { final List < JBBPAbstractField > structureFields = skipStructureFields ? null : new ArrayList < > ( ) ; final byte [ ] compiled = this . compiledBlock . getCompiledData ( ) ; boolean endStructureNotMet = true ; while ( endStructureNotMet && positionAtCompiledBlock . get ( ) < compiled . length ) { if ( ! inStream . hasAvailableData ( ) && ( flags & FLAG_SKIP_REMAINING_FIELDS_IF_EOF ) != 0 ) { break ; } final int c = compiled [ positionAtCompiledBlock . getAndIncrement ( ) ] & 0xFF ; final boolean wideCode = ( c & JBBPCompiler . FLAG_WIDE ) != 0 ; final int ec = wideCode ? compiled [ positionAtCompiledBlock . getAndIncrement ( ) ] & 0xFF : 0 ; final boolean extraFieldNumAsExpr = ( ec & JBBPCompiler . EXT_FLAG_EXTRA_AS_EXPRESSION ) != 0 ; final int code = ( ec << 8 ) | c ; final boolean fieldTypeDiff = ( ec & JBBPCompiler . EXT_FLAG_EXTRA_DIFF_TYPE ) != 0 ; final JBBPNamedFieldInfo name = ( code & JBBPCompiler . FLAG_NAMED ) == 0 ? null : compiledBlock . getNamedFields ( ) [ positionAtNamedFieldList . getAndIncrement ( ) ] ; final JBBPByteOrder byteOrder = ( code & JBBPCompiler . FLAG_LITTLE_ENDIAN ) == 0 ? JBBPByteOrder . BIG_ENDIAN : JBBPByteOrder . LITTLE_ENDIAN ; final boolean resultNotIgnored = ! skipStructureFields ; final int extraFieldNumExprResult ; if ( extraFieldNumAsExpr ) { final JBBPIntegerValueEvaluator evaluator = this . compiledBlock . getArraySizeEvaluators ( ) [ positionAtVarLengthProcessors . getAndIncrement ( ) ] ; int resultOfExpression ; if ( resultNotIgnored ) { resultOfExpression = evaluator . eval ( inStream , positionAtCompiledBlock . get ( ) , this . compiledBlock , namedNumericFieldMap ) ; if ( ( this . flags & FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO ) != 0 ) { resultOfExpression = Math . max ( resultOfExpression , 0 ) ; } } else { resultOfExpression = 0 ; } extraFieldNumExprResult = resultOfExpression ; } else { extraFieldNumExprResult = 0 ; } final boolean wholeStreamArray ; final int arrayLength ; final int packedArraySizeOffset ; switch ( code & ( JBBPCompiler . FLAG_ARRAY | ( JBBPCompiler . EXT_FLAG_EXPRESSION_OR_WHOLESTREAM << 8 ) ) ) { case JBBPCompiler . FLAG_ARRAY : { final int pos = positionAtCompiledBlock . get ( ) ; arrayLength = JBBPUtils . unpackInt ( compiled , positionAtCompiledBlock ) ; packedArraySizeOffset = positionAtCompiledBlock . get ( ) - pos ; wholeStreamArray = false ; } break ; case ( JBBPCompiler . EXT_FLAG_EXPRESSION_OR_WHOLESTREAM << 8 ) : { wholeStreamArray = resultNotIgnored ; packedArraySizeOffset = 0 ; arrayLength = 0 ; } break ; case JBBPCompiler . FLAG_ARRAY | ( JBBPCompiler . EXT_FLAG_EXPRESSION_OR_WHOLESTREAM << 8 ) : { final JBBPIntegerValueEvaluator evaluator = this . compiledBlock . getArraySizeEvaluators ( ) [ positionAtVarLengthProcessors . getAndIncrement ( ) ] ; int resultOfExpression ; if ( resultNotIgnored ) { resultOfExpression = evaluator . eval ( inStream , positionAtCompiledBlock . get ( ) , this . compiledBlock , namedNumericFieldMap ) ; if ( ( this . flags & FLAG_NEGATIVE_EXPRESSION_RESULT_AS_ZERO ) != 0 ) { resultOfExpression = Math . max ( resultOfExpression , 0 ) ; } } else { resultOfExpression = 0 ; } arrayLength = resultOfExpression ; packedArraySizeOffset = 0 ; assertArrayLength ( arrayLength , name ) ; wholeStreamArray = false ; } break ; default : { packedArraySizeOffset = 0 ; wholeStreamArray = false ; arrayLength = - 1 ; } break ; } JBBPAbstractField singleAtomicField = null ; try { switch ( code & 0xF ) { case JBBPCompiler . CODE_RESET_COUNTER : { if ( resultNotIgnored ) { inStream . resetCounter ( ) ; } } break ; case JBBPCompiler . CODE_ALIGN : { final int alignValue = extraFieldNumAsExpr ? extraFieldNumExprResult : JBBPUtils . unpackInt ( compiled , positionAtCompiledBlock ) ; if ( resultNotIgnored ) { inStream . align ( alignValue ) ; } } break ; case JBBPCompiler . CODE_SKIP : { final int skipByteNumber = extraFieldNumAsExpr ? extraFieldNumExprResult : JBBPUtils . unpackInt ( compiled , positionAtCompiledBlock ) ; if ( resultNotIgnored ) { if ( fieldTypeDiff ) { singleAtomicField = new JBBPFieldInt ( name , skipByteNumber ) ; } else { if ( skipByteNumber > 0 ) { final long skippedBytes = inStream . skip ( skipByteNumber ) ; if ( skippedBytes != skipByteNumber ) { throw new EOFException ( "Can't skip " + skipByteNumber + " byte(s), skipped only " + skippedBytes + " byte(s)" ) ; } } } } } break ; case JBBPCompiler . CODE_BIT : { final int numberOfBits = extraFieldNumAsExpr ? extraFieldNumExprResult : JBBPUtils . unpackInt ( compiled , positionAtCompiledBlock ) ; if ( resultNotIgnored ) { final JBBPBitNumber bitNumber = JBBPBitNumber . decode ( numberOfBits ) ; if ( arrayLength < 0 ) { final int read = inStream . readBitField ( bitNumber ) ; singleAtomicField = new JBBPFieldBit ( name , read & 0xFF , bitNumber ) ; } else { structureFields . add ( new JBBPFieldArrayBit ( name , inStream . readBitsArray ( wholeStreamArray ? - 1 : arrayLength , bitNumber ) , bitNumber ) ) ; } } } break ; case JBBPCompiler . CODE_VAR : { final int extraField = extraFieldNumAsExpr ? extraFieldNumExprResult : JBBPUtils . unpackInt ( compiled , positionAtCompiledBlock ) ; if ( resultNotIgnored ) { if ( arrayLength < 0 ) { singleAtomicField = varFieldProcessor . readVarField ( inStream , name , extraField , byteOrder , namedNumericFieldMap ) ; JBBPUtils . assertNotNull ( singleAtomicField , "A Var processor must not return null as a result of a field reading" ) ; if ( singleAtomicField instanceof JBBPAbstractArrayField ) { throw new JBBPParsingException ( "A Var field processor has returned an array value instead of a field value [" + name + ':' + extraField + ']' ) ; } if ( singleAtomicField . getNameInfo ( ) != name ) { throw new JBBPParsingException ( "Detected wrong name for a read field , must be " + name + " but detected " + singleAtomicField . getNameInfo ( ) + ']' ) ; } } else { final JBBPAbstractArrayField < ? extends JBBPAbstractField > array = varFieldProcessor . readVarArray ( inStream , wholeStreamArray ? - 1 : arrayLength , name , extraField , byteOrder , namedNumericFieldMap ) ; JBBPUtils . assertNotNull ( array , "A Var processor must not return null as a result of an array field reading [" + name + ':' + extraField + ']' ) ; if ( array . getNameInfo ( ) != name ) { throw new JBBPParsingException ( "Detected wrong name for a read field array, must be " + name + " but detected " + array . getNameInfo ( ) + ']' ) ; } structureFields . add ( array ) ; } } } break ; case JBBPCompiler . CODE_CUSTOMTYPE : { final int extraData = extraFieldNumAsExpr ? extraFieldNumExprResult : JBBPUtils . unpackInt ( compiled , positionAtCompiledBlock ) ; if ( resultNotIgnored ) { final JBBPFieldTypeParameterContainer fieldTypeInfo = this . compiledBlock . getCustomTypeFields ( ) [ JBBPUtils . unpackInt ( compiled , positionAtCompiledBlock ) ] ; final JBBPAbstractField field = this . customFieldTypeProcessor . readCustomFieldType ( inStream , this . bitOrder , this . flags , fieldTypeInfo , name , extraData , wholeStreamArray , arrayLength ) ; JBBPUtils . assertNotNull ( field , "Must not return null as read result" ) ; if ( arrayLength < 0 ) { singleAtomicField = field ; } else { structureFields . add ( field ) ; } } } break ; case JBBPCompiler . CODE_BYTE : { if ( resultNotIgnored ) { if ( arrayLength < 0 ) { singleAtomicField = new JBBPFieldByte ( name , ( byte ) inStream . readByte ( ) ) ; } else { structureFields . add ( new JBBPFieldArrayByte ( name , inStream . readByteArray ( wholeStreamArray ? - 1 : arrayLength , byteOrder ) ) ) ; } } } break ; case JBBPCompiler . CODE_UBYTE : { if ( resultNotIgnored ) { if ( arrayLength < 0 ) { singleAtomicField = new JBBPFieldUByte ( name , ( byte ) inStream . readByte ( ) ) ; } else { structureFields . add ( new JBBPFieldArrayUByte ( name , inStream . readByteArray ( wholeStreamArray ? - 1 : arrayLength , byteOrder ) ) ) ; } } } break ; case JBBPCompiler . CODE_BOOL : { if ( resultNotIgnored ) { if ( arrayLength < 0 ) { singleAtomicField = fieldTypeDiff ? new JBBPFieldString ( name , inStream . readString ( byteOrder ) ) : new JBBPFieldBoolean ( name , inStream . readBoolean ( ) ) ; } else { structureFields . add ( fieldTypeDiff ? new JBBPFieldArrayString ( name , inStream . readStringArray ( wholeStreamArray ? - 1 : arrayLength , byteOrder ) ) : new JBBPFieldArrayBoolean ( name , inStream . readBoolArray ( wholeStreamArray ? - 1 : arrayLength ) ) ) ; } } } break ; case JBBPCompiler . CODE_INT : { if ( resultNotIgnored ) { if ( arrayLength < 0 ) { singleAtomicField = fieldTypeDiff ? new JBBPFieldFloat ( name , inStream . readFloat ( byteOrder ) ) : new JBBPFieldInt ( name , inStream . readInt ( byteOrder ) ) ; } else { structureFields . add ( fieldTypeDiff ? new JBBPFieldArrayFloat ( name , inStream . readFloatArray ( wholeStreamArray ? - 1 : arrayLength , byteOrder ) ) : new JBBPFieldArrayInt ( name , inStream . readIntArray ( wholeStreamArray ? - 1 : arrayLength , byteOrder ) ) ) ; } } } break ; case JBBPCompiler . CODE_LONG : { if ( resultNotIgnored ) { if ( arrayLength < 0 ) { singleAtomicField = fieldTypeDiff ? new JBBPFieldDouble ( name , inStream . readDouble ( byteOrder ) ) : new JBBPFieldLong ( name , inStream . readLong ( byteOrder ) ) ; } else { structureFields . add ( fieldTypeDiff ? new JBBPFieldArrayDouble ( name , inStream . readDoubleArray ( wholeStreamArray ? - 1 : arrayLength , byteOrder ) ) : new JBBPFieldArrayLong ( name , inStream . readLongArray ( wholeStreamArray ? - 1 : arrayLength , byteOrder ) ) ) ; } } } break ; case JBBPCompiler . CODE_SHORT : { if ( resultNotIgnored ) { if ( arrayLength < 0 ) { final int value = inStream . readUnsignedShort ( byteOrder ) ; singleAtomicField = new JBBPFieldShort ( name , ( short ) value ) ; } else { structureFields . add ( new JBBPFieldArrayShort ( name , inStream . readShortArray ( wholeStreamArray ? - 1 : arrayLength , byteOrder ) ) ) ; } } } break ; case JBBPCompiler . CODE_USHORT : { if ( resultNotIgnored ) { if ( arrayLength < 0 ) { final int value = inStream . readUnsignedShort ( byteOrder ) ; singleAtomicField = new JBBPFieldUShort ( name , ( short ) value ) ; } else { structureFields . add ( new JBBPFieldArrayUShort ( name , inStream . readShortArray ( wholeStreamArray ? - 1 : arrayLength , byteOrder ) ) ) ; } } } break ; case JBBPCompiler . CODE_STRUCT_START : { if ( arrayLength < 0 ) { final List < JBBPAbstractField > structFields = parseStruct ( inStream , positionAtCompiledBlock , varFieldProcessor , namedNumericFieldMap , positionAtNamedFieldList , positionAtVarLengthProcessors , skipStructureFields ) ; JBBPUtils . unpackInt ( compiled , positionAtCompiledBlock ) ; if ( resultNotIgnored ) { structureFields . add ( new JBBPFieldStruct ( name , structFields . toArray ( ARRAY_FIELD_EMPTY ) ) ) ; } } else { final int nameFieldCurrent = positionAtNamedFieldList . get ( ) ; final int varLenProcCurrent = positionAtVarLengthProcessors . get ( ) ; final JBBPFieldStruct [ ] result ; if ( resultNotIgnored ) { if ( wholeStreamArray ) { final List < JBBPFieldStruct > list = new ArrayList < > ( ) ; while ( inStream . hasAvailableData ( ) ) { positionAtNamedFieldList . set ( nameFieldCurrent ) ; positionAtVarLengthProcessors . set ( varLenProcCurrent ) ; final List < JBBPAbstractField > fieldsForStruct = parseStruct ( inStream , positionAtCompiledBlock , varFieldProcessor , namedNumericFieldMap , positionAtNamedFieldList , positionAtVarLengthProcessors , skipStructureFields ) ; list . add ( new JBBPFieldStruct ( name , fieldsForStruct ) ) ; final int structStart = JBBPUtils . unpackInt ( compiled , positionAtCompiledBlock ) ; if ( inStream . hasAvailableData ( ) ) { positionAtCompiledBlock . set ( structStart + ( wideCode ? 2 : 1 ) ) ; } } result = list . isEmpty ( ) ? EMPTY_STRUCT_ARRAY : list . toArray ( EMPTY_STRUCT_ARRAY ) ; } else { if ( arrayLength == 0 ) { result = EMPTY_STRUCT_ARRAY ; parseStruct ( inStream , positionAtCompiledBlock , varFieldProcessor , namedNumericFieldMap , positionAtNamedFieldList , positionAtVarLengthProcessors , true ) ; JBBPUtils . unpackInt ( compiled , positionAtCompiledBlock ) ; } else { result = new JBBPFieldStruct [ arrayLength ] ; for ( int i = 0 ; i < arrayLength ; i ++ ) { final List < JBBPAbstractField > fieldsForStruct = parseStruct ( inStream , positionAtCompiledBlock , varFieldProcessor , namedNumericFieldMap , positionAtNamedFieldList , positionAtVarLengthProcessors , skipStructureFields ) ; final int structBodyStart = JBBPUtils . unpackInt ( compiled , positionAtCompiledBlock ) ; result [ i ] = new JBBPFieldStruct ( name , fieldsForStruct ) ; if ( i < arrayLength - 1 ) { positionAtNamedFieldList . set ( nameFieldCurrent ) ; positionAtVarLengthProcessors . set ( varLenProcCurrent ) ; positionAtCompiledBlock . set ( structBodyStart + packedArraySizeOffset + ( wideCode ? 2 : 1 ) ) ; } } } } if ( result != null ) { structureFields . add ( new JBBPFieldArrayStruct ( name , result ) ) ; } } else { parseStruct ( inStream , positionAtCompiledBlock , varFieldProcessor , namedNumericFieldMap , positionAtNamedFieldList , positionAtVarLengthProcessors , skipStructureFields ) ; JBBPUtils . unpackInt ( compiled , positionAtCompiledBlock ) ; } } } break ; case JBBPCompiler . CODE_STRUCT_END : { endStructureNotMet = false ; } break ; default : throw new Error ( "Detected unexpected field type! Contact developer! [" + code + ']' ) ; } } catch ( IOException ex ) { if ( name == null ) { throw ex ; } else { throw new JBBPParsingException ( "Can't parse field '" + name . getFieldPath ( ) + "' for IOException" , ex ) ; } } if ( singleAtomicField != null ) { structureFields . add ( singleAtomicField ) ; if ( namedNumericFieldMap != null && singleAtomicField instanceof JBBPNumericField && name != null ) { namedNumericFieldMap . putField ( ( JBBPNumericField ) singleAtomicField ) ; } } } return structureFields ; }
Inside method to parse a structure.

@param inStream                      the input stream, must not be null
@param positionAtCompiledBlock       the current position in the compiled script
block
@param varFieldProcessor             a processor to process var fields, it can be null
but it will thrown NPE if a var field is met
@param namedNumericFieldMap          the named numeric field map
@param positionAtNamedFieldList      the current position at the named field
list
@param positionAtVarLengthProcessors the current position at the variable
array length processor list
@param skipStructureFields           the flag shows that content of fields must be
skipped because the structure is skipped
@return list of read fields for the structure
@throws IOException it will be thrown for transport errors