private def specifiedLength()

in daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/ElementBaseGrammarMixin.scala [1324:1395]


  private def specifiedLength(bodyArg: => Gram) = {
    // we need this to evaluate before we wrap in specified length parser,
    // so it can do any internal checks for example blobValue's check for
    // non-explicit lengthKind
    val body = bodyArg

    // there are essentially two categories of processors that read/write data input/output
    // stream: those that calculate lengths themselves and those that expect another
    // processor to calculate the length and set the bit limit which this processor will use as
    // the length. The following determines if this element requires another processor to
    // calculate and set the bit limit, and if so adds the appropriate grammar to do that
    val bodyRequiresSpecifiedLengthBitLimit = lengthKind != LengthKind.Delimited && (
      isSimpleType && impliedRepresentation == Representation.Text ||
        isSimpleType && isNillable ||
        isComplexType && lengthKind != LengthKind.Implicit ||
        lengthKind == LengthKind.Prefixed ||
        isSimpleType && primType == PrimType.HexBinary && lengthKind == LengthKind.Pattern
    )
    if (!bodyRequiresSpecifiedLengthBitLimit) {
      body
    } else {
      lazy val bitsMultiplier = lengthUnits match {
        case LengthUnits.Bits => 1
        case LengthUnits.Bytes => 8
        case LengthUnits.Characters if knownEncodingIsFixedWidth =>
          this.knownEncodingWidthInBits
        case _ => 0 // zero means can't multiply to get width in bits.
      }
      val lk = lengthKind
      lk match {
        case LengthKind.Pattern => new SpecifiedLengthPattern(this, body)
        case LengthKind.Explicit if bitsMultiplier != 0 =>
          new SpecifiedLengthExplicit(this, body, bitsMultiplier)
        case LengthKind.Explicit => {
          Assert.invariant(!knownEncodingIsFixedWidth)
          Assert.invariant(lengthUnits eq LengthUnits.Characters)
          new SpecifiedLengthExplicitCharacters(this, body)
        }
        case LengthKind.Prefixed if (bitsMultiplier != 0) =>
          new SpecifiedLengthPrefixed(this, body, bitsMultiplier)
        case LengthKind.Prefixed => {
          Assert.invariant(!knownEncodingIsFixedWidth)
          Assert.invariant(lengthUnits eq LengthUnits.Characters)
          new SpecifiedLengthPrefixedCharacters(this, body)
        }
        case LengthKind.Implicit
            if isSimpleType && primType == PrimType.String &&
              encodingInfo.knownEncodingIsFixedWidth => {
          //
          // Important case to optimize
          // If we can convert to a number of bits, then we should do so
          //
          val nBits =
            encodingInfo.knownFixedWidthEncodingInCharsToBits(this.maxLength.longValue)
          new SpecifiedLengthImplicit(this, body, nBits)
        }
        case LengthKind.Implicit if isSimpleType && primType == PrimType.String =>
          new SpecifiedLengthImplicitCharacters(this, body, this.maxLength.longValue)
        case LengthKind.Implicit
            if isSimpleType && impliedRepresentation == Representation.Binary =>
          new SpecifiedLengthImplicit(this, body, implicitBinaryLengthInBits)
        case LengthKind.EndOfParent if isComplexType =>
          notYetImplemented("lengthKind='endOfParent' for complex type")
        case LengthKind.EndOfParent =>
          notYetImplemented("lengthKind='endOfParent' for simple type")
        case LengthKind.Delimited | LengthKind.Implicit =>
          Assert.impossibleCase(
            "Delimited and ComplexType Implicit cases should not be reached"
          )
      }
    }
  }