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"
)
}
}
}