From 018570f7c2050db9e5b0e02c4d958193cc4baf51 Mon Sep 17 00:00:00 2001 From: olabusayoT <50379531+olabusayoT@users.noreply.github.com> Date: Wed, 9 Oct 2024 14:06:23 -0400 Subject: [PATCH] Fix Bug with valueLength being overwritten after Trim - currently after trimming the value of the element, we set the valueLength, and then overwrite it after returning from the parse that does the trimming. This results in the wrong value for value length. This fixes it by checking if the valueLength has already been set, and only setting it in SpecifiedLengthParserBase.parse if it hasn't - add asserts to setAbsStartPos0bInBits and setAbsEndPos0bInBits to ensure they're not being overwritten - do not capture the value lengths of choices/complexTypes in specified length parser base - fix bug where padding is being added around prefixed length element (DAFFODIL-2943) by changing CaptureLengthRegion to wrap around contentlengthStart and padding - fix bug where we use the valuelength to calculate the prefix length, according to the spec it should be the content length - fix bug where we were missing return after PE for Out of Range Binary Integers (DAFFODIL-2942) - refactor Prefixed parsers to use state's bitLimit to get the prefix length (BitLengthFromBitLimitMixin) since the specifiedLengthPrefixedParser will take care of parsing the prefix length - refactored Prefixed unparsers to not try to unparse prefix length since that is taken care of by SpecifiedLengthPrefixedUnparser - refactored prefixed parsers and unparsers to remove unused prefixed length parser related members - rename custom prefixedlength parsers to *BitLengthParsers to more accurately reflect what they're doing - rename custom prefixedlength unparsers to MinimumLengthUnparsers to more accurately reflect what they're doing - add tests DAFFODIL-2658 --- .../codegen/c/DaffodilCCodeGenerator.scala | 9 ++ .../grammar/ElementBaseGrammarMixin.scala | 149 ++++++++++-------- .../grammar/primitives/PrimitivesBCD.scala | 44 ++---- .../primitives/PrimitivesBinaryBoolean.scala | 18 +-- .../primitives/PrimitivesBinaryNumber.scala | 43 ++--- .../primitives/PrimitivesIBM4690Packed.scala | 41 ++--- .../primitives/PrimitivesLengthKind.scala | 20 +-- .../grammar/primitives/PrimitivesPacked.scala | 44 ++---- .../runtime1/ElementBaseRuntime1Mixin.scala | 18 ++- .../unparsers/runtime1/BCDUnparsers.scala | 34 +--- .../runtime1/BinaryBooleanUnparsers.scala | 23 +-- .../runtime1/BinaryNumberUnparsers.scala | 35 +--- .../runtime1/HexBinaryLengthUnparser.scala | 26 --- .../IBM4690PackedDecimalUnparsers.scala | 34 +--- .../runtime1/PackedDecimalUnparsers.scala | 35 +--- .../unparsers/runtime1/SpecifiedLength2.scala | 4 +- .../runtime1/SpecifiedLengthUnparsers.scala | 98 ++---------- .../runtime1/infoset/InfosetImpl.scala | 8 + .../runtime1/processors/BCDParsers.scala | 36 +---- .../IBM4690PackedDecimalParsers.scala | 34 +--- .../processors/PackedDecimalParsers.scala | 34 +--- .../parsers/BinaryBooleanParsers.scala | 13 +- .../parsers/BinaryNumberParsers.scala | 36 +---- .../parsers/BinaryNumberTraits.scala | 22 ++- .../parsers/HexBinaryLengthParsers.scala | 19 --- .../parsers/SpecifiedLengthParsers.scala | 6 +- .../section12/lengthKind/PrefixedTests.tdml | 88 ++++++++++- .../lengthKind/TestLengthKindPrefixed.scala | 6 +- 28 files changed, 348 insertions(+), 629 deletions(-) diff --git a/daffodil-codegen-c/src/main/scala/org/apache/daffodil/codegen/c/DaffodilCCodeGenerator.scala b/daffodil-codegen-c/src/main/scala/org/apache/daffodil/codegen/c/DaffodilCCodeGenerator.scala index 92348ee819..a42fab04f7 100644 --- a/daffodil-codegen-c/src/main/scala/org/apache/daffodil/codegen/c/DaffodilCCodeGenerator.scala +++ b/daffodil-codegen-c/src/main/scala/org/apache/daffodil/codegen/c/DaffodilCCodeGenerator.scala @@ -59,6 +59,7 @@ import org.apache.daffodil.core.grammar.primitives.RightFill import org.apache.daffodil.core.grammar.primitives.ScalarOrderedSequenceChild import org.apache.daffodil.core.grammar.primitives.SpecifiedLengthExplicit import org.apache.daffodil.core.grammar.primitives.SpecifiedLengthImplicit +import org.apache.daffodil.core.grammar.primitives.SpecifiedLengthPrefixed import org.apache.daffodil.lib.api.Diagnostic import org.apache.daffodil.lib.api.WarnID import org.apache.daffodil.lib.schema.annotation.props.gen.FailureType @@ -301,6 +302,7 @@ object DaffodilCCodeGenerator case g: SeqComp => seqCompGenerateCode(g, cgState) case g: SpecifiedLengthExplicit => specifiedLengthExplicit(g, cgState) case g: SpecifiedLengthImplicit => specifiedLengthImplicit(g, cgState) + case g: SpecifiedLengthPrefixed => specifiedLengthPrefixed(g, cgState) case _ => gram.SDE("Code generation not supported for: %s", Misc.getNameFromClass(gram)) } } @@ -409,4 +411,11 @@ object DaffodilCCodeGenerator ): Unit = { DaffodilCCodeGenerator.generateCode(g.eGram, cgState) } + + private def specifiedLengthPrefixed( + g: SpecifiedLengthPrefixed, + cgState: CodeGeneratorState + ): Unit = { + DaffodilCCodeGenerator.generateCode(g.eGram, cgState) + } } diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/ElementBaseGrammarMixin.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/ElementBaseGrammarMixin.scala index 12b53c352a..6f33784500 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/ElementBaseGrammarMixin.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/ElementBaseGrammarMixin.scala @@ -72,7 +72,9 @@ trait ElementBaseGrammarMixin } } - protected lazy val isDelimitedPrefixedPattern = { + lazy val isPrefixed: Boolean = lengthKind == LengthKind.Prefixed + + protected lazy val isDelimitedPrefixedPattern: Boolean = { import LengthKind._ lengthKind match { case Delimited => @@ -474,12 +476,16 @@ trait ElementBaseGrammarMixin lazy val leftPadding = leftPaddingArg lazy val rightPadFill = rightPadFillArg lazy val body = bodyArg - CaptureContentLengthStart(this) ~ - leftPadding ~ - CaptureValueLengthStart(this) ~ - body ~ - CaptureValueLengthEnd(this) ~ - rightPadFill ~ + specifiedLength( + CaptureContentLengthStart(this) ~ + leftPadding ~ + CaptureValueLengthStart(this) ~ + body ~ + CaptureValueLengthEnd(this) ~ + rightPadFill + ) ~ + // CaptureContentLengthEnd must be outside the specified length so it can + // do any skipping of bits it needs to before capturing the end of content length CaptureContentLengthEnd(this) } @@ -623,14 +629,14 @@ trait ElementBaseGrammarMixin private lazy val stringPrim = { lengthKind match { - case LengthKind.Explicit => specifiedLength(StringOfSpecifiedLength(this)) - case LengthKind.Prefixed => specifiedLength(StringOfSpecifiedLength(this)) + case LengthKind.Explicit => StringOfSpecifiedLength(this) + case LengthKind.Prefixed => StringOfSpecifiedLength(this) case LengthKind.Delimited => stringDelimitedEndOfData - case LengthKind.Pattern => specifiedLength(StringOfSpecifiedLength(this)) + case LengthKind.Pattern => StringOfSpecifiedLength(this) case LengthKind.Implicit => { val pt = this.simpleType.primType Assert.invariant(pt == PrimType.String) - specifiedLength(StringOfSpecifiedLength(this)) + StringOfSpecifiedLength(this) } case LengthKind.EndOfParent if isComplexType => notYetImplemented("lengthKind='endOfParent' for complex type") @@ -645,7 +651,7 @@ trait ElementBaseGrammarMixin } private lazy val hexBinaryLengthPattern = prod("hexBinaryLengthPattern") { - new SpecifiedLengthPattern(this, new HexBinaryEndOfBitLimit(this)) + new HexBinaryEndOfBitLimit(this) } private lazy val hexBinaryLengthPrefixed = prod("hexBinaryLengthPrefixed") { @@ -1219,7 +1225,7 @@ trait ElementBaseGrammarMixin } private lazy val nilLitSimple = prod("nilLitSimple", isSimpleType) { - captureLengthRegions(leftPadding, specifiedLength(nilLitContent), rightPadding ~ rightFill) + captureLengthRegions(leftPadding, nilLitContent, rightPadding ~ rightFill) } private lazy val nilLitComplex = prod("nilLitComplex", isComplexType) { @@ -1322,59 +1328,70 @@ trait ElementBaseGrammarMixin * as well, by not enclosing the body in a specified length enforcer. */ private def specifiedLength(bodyArg: => Gram) = { - lazy val body = bodyArg - 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.Delimited => body - 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) + // 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. } - case LengthKind.Implicit if isSimpleType && primType == PrimType.String => - new SpecifiedLengthImplicitCharacters(this, body, this.maxLength.longValue) - - case LengthKind.Implicit if isSimpleType && primType == PrimType.HexBinary => - new SpecifiedLengthImplicit(this, body, this.maxLength.longValue * bitsMultiplier) - case LengthKind.Implicit - if isSimpleType && impliedRepresentation == Representation.Binary => - new SpecifiedLengthImplicit(this, body, implicitBinaryLengthInBits) - case LengthKind.Implicit if isComplexType => - body // for complex types, implicit means "roll up from the bottom" - case LengthKind.EndOfParent if isComplexType => - notYetImplemented("lengthKind='endOfParent' for complex type") - case LengthKind.EndOfParent => - notYetImplemented("lengthKind='endOfParent' for simple type") - case _ => { - // TODO: implement other specified length like end of parent - // for now, no restriction - body + 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") } } } @@ -1396,7 +1413,7 @@ trait ElementBaseGrammarMixin private lazy val sharedComplexContentRegion: Gram = schemaSet.sharedComplexContentFactory.getShared( shareKey, - captureLengthRegions(EmptyGram, specifiedLength(complexContent), elementUnused) ~ + captureLengthRegions(EmptyGram, complexContent, elementUnused) ~ terminatorRegion ) diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBCD.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBCD.scala index 550daffa76..154e221376 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBCD.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBCD.scala @@ -19,18 +19,18 @@ package org.apache.daffodil.core.grammar.primitives import org.apache.daffodil.core.dsom.ElementBase import org.apache.daffodil.core.grammar.Terminal +import org.apache.daffodil.runtime1.processors.parsers.BCDDecimalBitLimitLengthParser import org.apache.daffodil.runtime1.processors.parsers.BCDDecimalKnownLengthParser -import org.apache.daffodil.runtime1.processors.parsers.BCDDecimalPrefixedLengthParser import org.apache.daffodil.runtime1.processors.parsers.BCDDecimalRuntimeLengthParser +import org.apache.daffodil.runtime1.processors.parsers.BCDIntegerBitLimitLengthParser import org.apache.daffodil.runtime1.processors.parsers.BCDIntegerKnownLengthParser -import org.apache.daffodil.runtime1.processors.parsers.BCDIntegerPrefixedLengthParser import org.apache.daffodil.runtime1.processors.parsers.BCDIntegerRuntimeLengthParser import org.apache.daffodil.runtime1.processors.unparsers.Unparser import org.apache.daffodil.unparsers.runtime1.BCDDecimalKnownLengthUnparser -import org.apache.daffodil.unparsers.runtime1.BCDDecimalPrefixedLengthUnparser +import org.apache.daffodil.unparsers.runtime1.BCDDecimalMinimumLengthUnparser import org.apache.daffodil.unparsers.runtime1.BCDDecimalRuntimeLengthUnparser import org.apache.daffodil.unparsers.runtime1.BCDIntegerKnownLengthUnparser -import org.apache.daffodil.unparsers.runtime1.BCDIntegerPrefixedLengthUnparser +import org.apache.daffodil.unparsers.runtime1.BCDIntegerMinimumLengthUnparser import org.apache.daffodil.unparsers.runtime1.BCDIntegerRuntimeLengthUnparser class BCDIntegerRuntimeLength(val e: ElementBase) extends Terminal(e, true) { @@ -52,20 +52,10 @@ class BCDIntegerKnownLength(val e: ElementBase, lengthInBits: Long) extends Term class BCDIntegerPrefixedLength(val e: ElementBase) extends Terminal(e, true) { - override lazy val parser = new BCDIntegerPrefixedLengthParser( - e.elementRuntimeData, - e.prefixedLengthBody.parser, - e.prefixedLengthElementDecl.elementRuntimeData, - e.lengthUnits, - e.prefixedLengthAdjustmentInUnits - ) + override lazy val parser = new BCDIntegerBitLimitLengthParser(e.elementRuntimeData) - override lazy val unparser: Unparser = new BCDIntegerPrefixedLengthUnparser( - e.elementRuntimeData, - e.prefixedLengthBody.unparser, - e.prefixedLengthElementDecl.elementRuntimeData, - e.lengthUnits, - e.prefixedLengthAdjustmentInUnits + override lazy val unparser: Unparser = new BCDIntegerMinimumLengthUnparser( + e.elementRuntimeData ) } @@ -102,21 +92,9 @@ class BCDDecimalKnownLength(val e: ElementBase, lengthInBits: Long) extends Term class BCDDecimalPrefixedLength(val e: ElementBase) extends Terminal(e, true) { - override lazy val parser = new BCDDecimalPrefixedLengthParser( - e.elementRuntimeData, - e.prefixedLengthBody.parser, - e.prefixedLengthElementDecl.elementRuntimeData, - e.binaryDecimalVirtualPoint, - e.lengthUnits, - e.prefixedLengthAdjustmentInUnits - ) + override lazy val parser = + new BCDDecimalBitLimitLengthParser(e.elementRuntimeData, e.binaryDecimalVirtualPoint) - override lazy val unparser: Unparser = new BCDDecimalPrefixedLengthUnparser( - e.elementRuntimeData, - e.prefixedLengthBody.unparser, - e.prefixedLengthElementDecl.elementRuntimeData, - e.binaryDecimalVirtualPoint, - e.lengthUnits, - e.prefixedLengthAdjustmentInUnits - ) + override lazy val unparser: Unparser = + new BCDDecimalMinimumLengthUnparser(e.elementRuntimeData, e.binaryDecimalVirtualPoint) } diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBinaryBoolean.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBinaryBoolean.scala index 05a6dfd9b8..b934a24fb5 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBinaryBoolean.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBinaryBoolean.scala @@ -19,10 +19,10 @@ package org.apache.daffodil.core.grammar.primitives import org.apache.daffodil.core.dsom.ElementBase import org.apache.daffodil.core.grammar.Terminal +import org.apache.daffodil.runtime1.processors.parsers.BinaryBooleanBitLimitLengthParser import org.apache.daffodil.runtime1.processors.parsers.BinaryBooleanParser -import org.apache.daffodil.runtime1.processors.parsers.BinaryBooleanPrefixedLengthParser import org.apache.daffodil.runtime1.processors.unparsers.Unparser -import org.apache.daffodil.unparsers.runtime1.BinaryBooleanPrefixedLengthUnparser +import org.apache.daffodil.unparsers.runtime1.BinaryBooleanMinimumLengthUnparser import org.apache.daffodil.unparsers.runtime1.BinaryBooleanUnparser class BinaryBoolean(val e: ElementBase) extends Terminal(e, true) { @@ -46,23 +46,17 @@ class BinaryBoolean(val e: ElementBase) extends Terminal(e, true) { } class BinaryBooleanPrefixedLength(val e: ElementBase) extends Terminal(e, true) { - override lazy val parser = new BinaryBooleanPrefixedLengthParser( + override lazy val parser = new BinaryBooleanBitLimitLengthParser( e.elementRuntimeData, - e.prefixedLengthBody.parser, - e.prefixedLengthElementDecl.elementRuntimeData, e.binaryBooleanTrueRep, e.binaryBooleanFalseRep, - e.lengthUnits, - e.prefixedLengthAdjustmentInUnits + e.lengthUnits ) - override lazy val unparser: Unparser = new BinaryBooleanPrefixedLengthUnparser( + override lazy val unparser: Unparser = new BinaryBooleanMinimumLengthUnparser( e.elementRuntimeData, - e.prefixedLengthBody.unparser, - e.prefixedLengthElementDecl.elementRuntimeData, e.binaryBooleanTrueRep, e.binaryBooleanFalseRep, - e.lengthUnits, - e.prefixedLengthAdjustmentInUnits + e.lengthUnits ) } diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBinaryNumber.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBinaryNumber.scala index 8c2b4b5940..655f580bfe 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBinaryNumber.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesBinaryNumber.scala @@ -22,22 +22,22 @@ import org.apache.daffodil.core.grammar.Terminal import org.apache.daffodil.lib.exceptions.Assert import org.apache.daffodil.lib.util.MaybeInt import org.apache.daffodil.runtime1.dpath.NodeInfo +import org.apache.daffodil.runtime1.processors.parsers.BinaryDecimalBitLimitLengthParser import org.apache.daffodil.runtime1.processors.parsers.BinaryDecimalKnownLengthParser -import org.apache.daffodil.runtime1.processors.parsers.BinaryDecimalPrefixedLengthParser import org.apache.daffodil.runtime1.processors.parsers.BinaryDecimalRuntimeLengthParser import org.apache.daffodil.runtime1.processors.parsers.BinaryDoubleParser import org.apache.daffodil.runtime1.processors.parsers.BinaryFloatParser +import org.apache.daffodil.runtime1.processors.parsers.BinaryIntegerBitLimitLengthParser import org.apache.daffodil.runtime1.processors.parsers.BinaryIntegerKnownLengthParser -import org.apache.daffodil.runtime1.processors.parsers.BinaryIntegerPrefixedLengthParser import org.apache.daffodil.runtime1.processors.parsers.BinaryIntegerRuntimeLengthParser import org.apache.daffodil.runtime1.processors.unparsers.Unparser import org.apache.daffodil.unparsers.runtime1.BinaryDecimalKnownLengthUnparser -import org.apache.daffodil.unparsers.runtime1.BinaryDecimalPrefixedLengthUnparser +import org.apache.daffodil.unparsers.runtime1.BinaryDecimalMinimumLengthUnparser import org.apache.daffodil.unparsers.runtime1.BinaryDecimalRuntimeLengthUnparser import org.apache.daffodil.unparsers.runtime1.BinaryDoubleUnparser import org.apache.daffodil.unparsers.runtime1.BinaryFloatUnparser import org.apache.daffodil.unparsers.runtime1.BinaryIntegerKnownLengthUnparser -import org.apache.daffodil.unparsers.runtime1.BinaryIntegerPrefixedLengthUnparser +import org.apache.daffodil.unparsers.runtime1.BinaryIntegerMinimumLengthUnparser import org.apache.daffodil.unparsers.runtime1.BinaryIntegerRuntimeLengthUnparser class BinaryIntegerRuntimeLength(val e: ElementBase) extends Terminal(e, true) { @@ -69,17 +69,9 @@ class BinaryIntegerKnownLength(val e: ElementBase, val lengthInBits: Long) class BinaryIntegerPrefixedLength(val e: ElementBase) extends Terminal(e, true) { private lazy val erd = e.elementRuntimeData - private lazy val plerd = e.prefixedLengthElementDecl.elementRuntimeData - private lazy val pladj = e.prefixedLengthAdjustmentInUnits override lazy val parser = - new BinaryIntegerPrefixedLengthParser( - erd, - e.prefixedLengthBody.parser, - plerd, - e.lengthUnits, - pladj - ) + new BinaryIntegerBitLimitLengthParser(erd) override lazy val unparser: Unparser = { val maybeNBits = e.primType match { @@ -91,14 +83,7 @@ class BinaryIntegerPrefixedLength(val e: ElementBase) extends Terminal(e, true) case _ => Assert.invariantFailed("Only integer base types should be used for this primitive") } - new BinaryIntegerPrefixedLengthUnparser( - erd, - e.prefixedLengthBody.unparser, - plerd, - maybeNBits, - e.lengthUnits, - pladj - ) + new BinaryIntegerMinimumLengthUnparser(erd, maybeNBits) } } @@ -143,25 +128,17 @@ class BinaryDecimalKnownLength(val e: ElementBase, lengthInBits: Long) class BinaryDecimalPrefixedLength(val e: ElementBase) extends Terminal(e, true) { override lazy val parser = - new BinaryDecimalPrefixedLengthParser( + new BinaryDecimalBitLimitLengthParser( e.elementRuntimeData, - e.prefixedLengthBody.parser, - e.prefixedLengthElementDecl.elementRuntimeData, e.decimalSigned, - e.binaryDecimalVirtualPoint, - e.lengthUnits, - e.prefixedLengthAdjustmentInUnits + e.binaryDecimalVirtualPoint ) override lazy val unparser: Unparser = - new BinaryDecimalPrefixedLengthUnparser( + new BinaryDecimalMinimumLengthUnparser( e.elementRuntimeData, - e.prefixedLengthBody.unparser, - e.prefixedLengthElementDecl.elementRuntimeData, e.decimalSigned, - e.binaryDecimalVirtualPoint, - e.lengthUnits, - e.prefixedLengthAdjustmentInUnits + e.binaryDecimalVirtualPoint ) } diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesIBM4690Packed.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesIBM4690Packed.scala index a5380474f5..1316426de5 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesIBM4690Packed.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesIBM4690Packed.scala @@ -19,18 +19,18 @@ package org.apache.daffodil.core.grammar.primitives import org.apache.daffodil.core.dsom.ElementBase import org.apache.daffodil.core.grammar.Terminal +import org.apache.daffodil.runtime1.processors.parsers.IBM4690PackedDecimalBitLimitLengthParser import org.apache.daffodil.runtime1.processors.parsers.IBM4690PackedDecimalKnownLengthParser -import org.apache.daffodil.runtime1.processors.parsers.IBM4690PackedDecimalPrefixedLengthParser import org.apache.daffodil.runtime1.processors.parsers.IBM4690PackedDecimalRuntimeLengthParser +import org.apache.daffodil.runtime1.processors.parsers.IBM4690PackedIntegerBitLimitLengthParser import org.apache.daffodil.runtime1.processors.parsers.IBM4690PackedIntegerKnownLengthParser -import org.apache.daffodil.runtime1.processors.parsers.IBM4690PackedIntegerPrefixedLengthParser import org.apache.daffodil.runtime1.processors.parsers.IBM4690PackedIntegerRuntimeLengthParser import org.apache.daffodil.runtime1.processors.unparsers.Unparser import org.apache.daffodil.unparsers.runtime1.IBM4690PackedDecimalKnownLengthUnparser -import org.apache.daffodil.unparsers.runtime1.IBM4690PackedDecimalPrefixedLengthUnparser +import org.apache.daffodil.unparsers.runtime1.IBM4690PackedDecimalMinimumLengthUnparser import org.apache.daffodil.unparsers.runtime1.IBM4690PackedDecimalRuntimeLengthUnparser import org.apache.daffodil.unparsers.runtime1.IBM4690PackedIntegerKnownLengthUnparser -import org.apache.daffodil.unparsers.runtime1.IBM4690PackedIntegerPrefixedLengthUnparser +import org.apache.daffodil.unparsers.runtime1.IBM4690PackedIntegerMinimumLengthUnparser import org.apache.daffodil.unparsers.runtime1.IBM4690PackedIntegerRuntimeLengthUnparser class IBM4690PackedIntegerRuntimeLength(val e: ElementBase) extends Terminal(e, true) { @@ -58,20 +58,11 @@ class IBM4690PackedIntegerKnownLength(val e: ElementBase, lengthInBits: Long) } class IBM4690PackedIntegerPrefixedLength(val e: ElementBase) extends Terminal(e, true) { - override lazy val parser = new IBM4690PackedIntegerPrefixedLengthParser( - e.elementRuntimeData, - e.prefixedLengthBody.parser, - e.prefixedLengthElementDecl.elementRuntimeData, - e.lengthUnits, - e.prefixedLengthAdjustmentInUnits - ) + override lazy val parser = + new IBM4690PackedIntegerBitLimitLengthParser(e.elementRuntimeData) - override lazy val unparser: Unparser = new IBM4690PackedIntegerPrefixedLengthUnparser( - e.elementRuntimeData, - e.prefixedLengthBody.unparser, - e.prefixedLengthElementDecl.elementRuntimeData, - e.lengthUnits, - e.prefixedLengthAdjustmentInUnits + override lazy val unparser: Unparser = new IBM4690PackedIntegerMinimumLengthUnparser( + e.elementRuntimeData ) } @@ -108,21 +99,13 @@ class IBM4690PackedDecimalKnownLength(val e: ElementBase, lengthInBits: Long) } class IBM4690PackedDecimalPrefixedLength(val e: ElementBase) extends Terminal(e, true) { - override lazy val parser = new IBM4690PackedDecimalPrefixedLengthParser( + override lazy val parser = new IBM4690PackedDecimalBitLimitLengthParser( e.elementRuntimeData, - e.prefixedLengthBody.parser, - e.prefixedLengthElementDecl.elementRuntimeData, - e.binaryDecimalVirtualPoint, - e.lengthUnits, - e.prefixedLengthAdjustmentInUnits + e.binaryDecimalVirtualPoint ) - override lazy val unparser: Unparser = new IBM4690PackedDecimalPrefixedLengthUnparser( + override lazy val unparser: Unparser = new IBM4690PackedDecimalMinimumLengthUnparser( e.elementRuntimeData, - e.prefixedLengthBody.unparser, - e.prefixedLengthElementDecl.elementRuntimeData, - e.binaryDecimalVirtualPoint, - e.lengthUnits, - e.prefixedLengthAdjustmentInUnits + e.binaryDecimalVirtualPoint ) } diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesLengthKind.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesLengthKind.scala index 21baad5654..09ce2c1df1 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesLengthKind.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesLengthKind.scala @@ -34,7 +34,6 @@ import org.apache.daffodil.runtime1.processors.parsers.BCDIntegerDelimitedParser import org.apache.daffodil.runtime1.processors.parsers.BlobSpecifiedLengthParser import org.apache.daffodil.runtime1.processors.parsers.HexBinaryDelimitedParser import org.apache.daffodil.runtime1.processors.parsers.HexBinaryEndOfBitLimitParser -import org.apache.daffodil.runtime1.processors.parsers.HexBinaryLengthPrefixedParser import org.apache.daffodil.runtime1.processors.parsers.HexBinarySpecifiedLengthParser import org.apache.daffodil.runtime1.processors.parsers.IBM4690PackedDecimalDelimitedParser import org.apache.daffodil.runtime1.processors.parsers.IBM4690PackedIntegerDelimitedParser @@ -48,7 +47,6 @@ import org.apache.daffodil.runtime1.processors.unparsers.{ Unparser => DaffodilU import org.apache.daffodil.unparsers.runtime1.BCDDecimalDelimitedUnparser import org.apache.daffodil.unparsers.runtime1.BCDIntegerDelimitedUnparser import org.apache.daffodil.unparsers.runtime1.BlobSpecifiedLengthUnparser -import org.apache.daffodil.unparsers.runtime1.HexBinaryLengthPrefixedUnparser import org.apache.daffodil.unparsers.runtime1.HexBinaryMinLengthInBytesUnparser import org.apache.daffodil.unparsers.runtime1.HexBinarySpecifiedLengthUnparser import org.apache.daffodil.unparsers.runtime1.IBM4690PackedDecimalDelimitedUnparser @@ -185,22 +183,12 @@ case class HexBinaryEndOfBitLimit(e: ElementBase) extends Terminal(e, true) { case class HexBinaryLengthPrefixed(e: ElementBase) extends Terminal(e, true) { - override lazy val parser: DaffodilParser = new HexBinaryLengthPrefixedParser( - e.elementRuntimeData, - e.prefixedLengthBody.parser, - e.prefixedLengthElementDecl.elementRuntimeData, - e.lengthUnits, - e.prefixedLengthAdjustmentInUnits + override lazy val parser: DaffodilParser = new HexBinaryEndOfBitLimitParser( + e.elementRuntimeData ) - override lazy val unparser: DaffodilUnparser = new HexBinaryLengthPrefixedUnparser( - e.elementRuntimeData, - e.prefixedLengthBody.unparser, - e.prefixedLengthElementDecl.elementRuntimeData, - e.minLength.longValue, - e.lengthUnits, - e.prefixedLengthAdjustmentInUnits - ) + override lazy val unparser: DaffodilUnparser = + new HexBinaryMinLengthInBytesUnparser(e.minLength.longValue, e.elementRuntimeData) } abstract class PackedIntegerDelimited( diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesPacked.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesPacked.scala index c0f7a73ecd..109abfef9c 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesPacked.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/primitives/PrimitivesPacked.scala @@ -20,18 +20,18 @@ package org.apache.daffodil.core.grammar.primitives import org.apache.daffodil.core.dsom.ElementBase import org.apache.daffodil.core.grammar.Terminal import org.apache.daffodil.lib.util.PackedSignCodes +import org.apache.daffodil.runtime1.processors.parsers.PackedDecimalBitLimitLengthParser import org.apache.daffodil.runtime1.processors.parsers.PackedDecimalKnownLengthParser -import org.apache.daffodil.runtime1.processors.parsers.PackedDecimalPrefixedLengthParser import org.apache.daffodil.runtime1.processors.parsers.PackedDecimalRuntimeLengthParser +import org.apache.daffodil.runtime1.processors.parsers.PackedIntegerBitLimitLengthParser import org.apache.daffodil.runtime1.processors.parsers.PackedIntegerKnownLengthParser -import org.apache.daffodil.runtime1.processors.parsers.PackedIntegerPrefixedLengthParser import org.apache.daffodil.runtime1.processors.parsers.PackedIntegerRuntimeLengthParser import org.apache.daffodil.runtime1.processors.unparsers.Unparser import org.apache.daffodil.unparsers.runtime1.PackedDecimalKnownLengthUnparser -import org.apache.daffodil.unparsers.runtime1.PackedDecimalPrefixedLengthUnparser +import org.apache.daffodil.unparsers.runtime1.PackedDecimalMinimumLengthUnparser import org.apache.daffodil.unparsers.runtime1.PackedDecimalRuntimeLengthUnparser import org.apache.daffodil.unparsers.runtime1.PackedIntegerKnownLengthUnparser -import org.apache.daffodil.unparsers.runtime1.PackedIntegerPrefixedLengthUnparser +import org.apache.daffodil.unparsers.runtime1.PackedIntegerMinimumLengthUnparser import org.apache.daffodil.unparsers.runtime1.PackedIntegerRuntimeLengthUnparser class PackedIntegerRuntimeLength( @@ -77,23 +77,11 @@ class PackedIntegerPrefixedLength( packedSignCodes: PackedSignCodes ) extends Terminal(e, true) { - override lazy val parser = new PackedIntegerPrefixedLengthParser( - e.elementRuntimeData, - e.prefixedLengthBody.parser, - e.prefixedLengthElementDecl.elementRuntimeData, - packedSignCodes, - e.lengthUnits, - e.prefixedLengthAdjustmentInUnits - ) + override lazy val parser = + new PackedIntegerBitLimitLengthParser(e.elementRuntimeData, packedSignCodes) - override lazy val unparser: Unparser = new PackedIntegerPrefixedLengthUnparser( - e.elementRuntimeData, - e.prefixedLengthBody.unparser, - e.prefixedLengthElementDecl.elementRuntimeData, - packedSignCodes, - e.lengthUnits, - e.prefixedLengthAdjustmentInUnits - ) + override lazy val unparser: Unparser = + new PackedIntegerMinimumLengthUnparser(e.elementRuntimeData, packedSignCodes) } class PackedDecimalRuntimeLength(val e: ElementBase, packedSignCodes: PackedSignCodes) @@ -139,23 +127,15 @@ class PackedDecimalKnownLength( class PackedDecimalPrefixedLength(val e: ElementBase, packedSignCodes: PackedSignCodes) extends Terminal(e, true) { - override lazy val parser = new PackedDecimalPrefixedLengthParser( + override lazy val parser = new PackedDecimalBitLimitLengthParser( e.elementRuntimeData, - e.prefixedLengthBody.parser, - e.prefixedLengthElementDecl.elementRuntimeData, e.binaryDecimalVirtualPoint, - packedSignCodes, - e.lengthUnits, - e.prefixedLengthAdjustmentInUnits + packedSignCodes ) - override lazy val unparser: Unparser = new PackedDecimalPrefixedLengthUnparser( + override lazy val unparser: Unparser = new PackedDecimalMinimumLengthUnparser( e.elementRuntimeData, - e.prefixedLengthBody.unparser, - e.prefixedLengthElementDecl.elementRuntimeData, e.binaryDecimalVirtualPoint, - packedSignCodes, - e.lengthUnits, - e.prefixedLengthAdjustmentInUnits + packedSignCodes ) } diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/core/runtime1/ElementBaseRuntime1Mixin.scala b/daffodil-core/src/main/scala/org/apache/daffodil/core/runtime1/ElementBaseRuntime1Mixin.scala index aa2e6a1dd8..2a4ef31fa3 100644 --- a/daffodil-core/src/main/scala/org/apache/daffodil/core/runtime1/ElementBaseRuntime1Mixin.scala +++ b/daffodil-core/src/main/scala/org/apache/daffodil/core/runtime1/ElementBaseRuntime1Mixin.scala @@ -24,7 +24,7 @@ import org.apache.daffodil.core.dsom.PrimitiveType import org.apache.daffodil.core.dsom.Root import org.apache.daffodil.core.dsom.SimpleTypeDefBase import org.apache.daffodil.lib.schema.annotation.props.gen.LengthKind -import org.apache.daffodil.lib.schema.annotation.props.gen.Representation +import org.apache.daffodil.lib.schema.annotation.props.gen.Representation.Text import org.apache.daffodil.lib.util.Delay import org.apache.daffodil.lib.util.Maybe import org.apache.daffodil.runtime1.dsom.DPathElementCompileInfo @@ -65,7 +65,12 @@ trait ElementBaseRuntime1Mixin { self: ElementBase => // no reason (unless it is referenced in a contentLength expression). val mightHaveSuspensions = (maybeFixedLengthInBits.isDefined && couldHaveSuspensions) - isReferenced || mightHaveSuspensions + // we want to capture contentlength when LK = prefixed because + // some prefixed length unparsers are unable to calculate the prefixed length + // of the field. Instead, they unparse the field to a buffer and the captured + // content length of the buffer is used. For this reason, prefixed length + // elements must capture content length for unparse. + lengthKind == LengthKind.Prefixed || isReferenced || mightHaveSuspensions } /** @@ -89,17 +94,18 @@ trait ElementBaseRuntime1Mixin { self: ElementBase => // // For complex elements with specified length, value length is captured in // the specified length parsers, since they handle skipping unused - // element regions. For complex elements, this means lengthKind is not + // element regions, and the length capturing has to be done before that. + // For complex elements, this means lengthKind is not // implicit or delimited. // // So for these cases we do not want to capture value length with the // Capture{Start,End}OfValueLengthParsers, since those lengths are captured // by the value parsers - val capturedByParsers = - (isSimpleType && (impliedRepresentation == Representation.Text || lengthKind == LengthKind.Delimited)) || + val capturedByValueParsers = + (isSimpleType && (impliedRepresentation == Text || lengthKind == LengthKind.Delimited)) || (isComplexType && (lengthKind != LengthKind.Implicit && lengthKind != LengthKind.Delimited)) - !capturedByParsers && isReferenced + !capturedByValueParsers && isReferenced } /** diff --git a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/BCDUnparsers.scala b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/BCDUnparsers.scala index 84dde6a128..86c80ba430 100644 --- a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/BCDUnparsers.scala +++ b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/BCDUnparsers.scala @@ -25,7 +25,6 @@ import org.apache.daffodil.lib.util.DecimalUtils import org.apache.daffodil.runtime1.processors.ElementRuntimeData import org.apache.daffodil.runtime1.processors.Evaluatable import org.apache.daffodil.runtime1.processors.ParseOrUnparseState -import org.apache.daffodil.runtime1.processors.Processor import org.apache.daffodil.runtime1.processors.parsers.HasKnownLengthInBits import org.apache.daffodil.runtime1.processors.parsers.HasRuntimeExplicitLength import org.apache.daffodil.runtime1.processors.unparsers._ @@ -57,16 +56,9 @@ final class BCDIntegerDelimitedUnparser(e: ElementRuntimeData) override def getBitLength(state: ParseOrUnparseState): Int = { 0 } } -final class BCDIntegerPrefixedLengthUnparser( - e: ElementRuntimeData, - override val prefixedLengthUnparser: Unparser, - override val prefixedLengthERD: ElementRuntimeData, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long -) extends BCDIntegerBaseUnparser(e) - with KnownPrefixedLengthUnparserMixin { +final class BCDIntegerMinimumLengthUnparser(e: ElementRuntimeData) + extends BCDIntegerBaseUnparser(e) { - override def childProcessors: Vector[Processor] = Vector(prefixedLengthUnparser) override lazy val runtimeDependencies = Vector() override def getBitLength(s: ParseOrUnparseState): Int = { @@ -75,11 +67,6 @@ final class BCDIntegerPrefixedLengthUnparser( val (byteLength, _) = DecimalUtils.bcdFromBigIntegerLength(absBigIntStr, 0) byteLength * 8 } - - override def unparse(state: UState): Unit = { - unparsePrefixedLength(state) - super.unparse(state) - } } abstract class BCDDecimalBaseUnparser(e: ElementRuntimeData, binaryDecimalVirtualPoint: Int) @@ -113,17 +100,11 @@ final class BCDDecimalDelimitedUnparser(e: ElementRuntimeData, binaryDecimalVirt override def getBitLength(state: ParseOrUnparseState): Int = { 0 } } -final class BCDDecimalPrefixedLengthUnparser( +final class BCDDecimalMinimumLengthUnparser( e: ElementRuntimeData, - override val prefixedLengthUnparser: Unparser, - override val prefixedLengthERD: ElementRuntimeData, - binaryDecimalVirtualPoint: Int, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long -) extends BCDDecimalBaseUnparser(e, binaryDecimalVirtualPoint) - with KnownPrefixedLengthUnparserMixin { + binaryDecimalVirtualPoint: Int +) extends BCDDecimalBaseUnparser(e, binaryDecimalVirtualPoint) { - override def childProcessors: Vector[Processor] = Vector(prefixedLengthUnparser) override lazy val runtimeDependencies = Vector() override def getBitLength(s: ParseOrUnparseState): Int = { @@ -132,9 +113,4 @@ final class BCDDecimalPrefixedLengthUnparser( val (byteLength, _) = DecimalUtils.bcdFromBigIntegerLength(absBigIntStr, 0) byteLength * 8 } - - override def unparse(state: UState): Unit = { - unparsePrefixedLength(state) - super.unparse(state) - } } diff --git a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/BinaryBooleanUnparsers.scala b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/BinaryBooleanUnparsers.scala index 8f57d2b59a..59bb85d04c 100644 --- a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/BinaryBooleanUnparsers.scala +++ b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/BinaryBooleanUnparsers.scala @@ -30,7 +30,6 @@ import org.apache.daffodil.lib.util.Numbers import org.apache.daffodil.runtime1.processors.ElementRuntimeData import org.apache.daffodil.runtime1.processors.Evaluatable import org.apache.daffodil.runtime1.processors.ParseOrUnparseState -import org.apache.daffodil.runtime1.processors.Processor import org.apache.daffodil.runtime1.processors.unparsers._ import passera.unsigned.ULong @@ -129,26 +128,20 @@ class BinaryBooleanUnparser( } } -class BinaryBooleanPrefixedLengthUnparser( +class BinaryBooleanMinimumLengthUnparser( e: ElementRuntimeData, - override val prefixedLengthUnparser: Unparser, - override val prefixedLengthERD: ElementRuntimeData, binaryBooleanTrueRep: MaybeULong, binaryBooleanFalseRep: ULong, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long -) extends BinaryBooleanUnparserBase(e, binaryBooleanTrueRep, binaryBooleanFalseRep, lengthUnits) - with KnownPrefixedLengthUnparserMixin { - - override def childProcessors: Vector[Processor] = Vector(prefixedLengthUnparser) + lengthUnits: LengthUnits +) extends BinaryBooleanUnparserBase( + e, + binaryBooleanTrueRep, + binaryBooleanFalseRep, + lengthUnits + ) { override lazy val runtimeDependencies = Vector() override def getBitLength(s: ParseOrUnparseState): Int = 32 - override def unparse(state: UState): Unit = { - unparsePrefixedLength(state) - super.unparse(state) - } - } diff --git a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/BinaryNumberUnparsers.scala b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/BinaryNumberUnparsers.scala index b4f99d9ab2..437587def9 100644 --- a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/BinaryNumberUnparsers.scala +++ b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/BinaryNumberUnparsers.scala @@ -32,7 +32,6 @@ import org.apache.daffodil.runtime1.dpath.NodeInfo import org.apache.daffodil.runtime1.processors.ElementRuntimeData import org.apache.daffodil.runtime1.processors.Evaluatable import org.apache.daffodil.runtime1.processors.ParseOrUnparseState -import org.apache.daffodil.runtime1.processors.Processor import org.apache.daffodil.runtime1.processors.parsers.BinaryNumberCheckWidth import org.apache.daffodil.runtime1.processors.parsers.HasKnownLengthInBits import org.apache.daffodil.runtime1.processors.parsers.HasRuntimeExplicitLength @@ -126,19 +125,13 @@ class BinaryIntegerRuntimeLengthUnparser( override val runtimeDependencies = Vector(lengthEv) } -class BinaryIntegerPrefixedLengthUnparser( +class BinaryIntegerMinimumLengthUnparser( e: ElementRuntimeData, - override val prefixedLengthUnparser: Unparser, - override val prefixedLengthERD: ElementRuntimeData, - maybeNBits: MaybeInt, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long -) extends BinaryIntegerBaseUnparser(e: ElementRuntimeData) - with KnownPrefixedLengthUnparserMixin { + maybeNBits: MaybeInt +) extends BinaryIntegerBaseUnparser(e: ElementRuntimeData) { private val primNumeric = e.optPrimType.get.asInstanceOf[NodeInfo.PrimType.PrimNumeric] - override def childProcessors: Vector[Processor] = Vector(prefixedLengthUnparser) override lazy val runtimeDependencies = Vector() override def getBitLength(s: ParseOrUnparseState): Int = { @@ -154,11 +147,6 @@ class BinaryIntegerPrefixedLengthUnparser( (signedLen + 7) & ~0x7 // round up to nearest multilpe of 8 } } - - override def unparse(state: UState): Unit = { - unparsePrefixedLength(state) - super.unparse(state) - } } class BinaryFloatUnparser(e: ElementRuntimeData) extends BinaryNumberBaseUnparser(e) { @@ -218,18 +206,12 @@ class BinaryDecimalRuntimeLengthUnparser( override val runtimeDependencies = Vector(lengthEv) } -class BinaryDecimalPrefixedLengthUnparser( +class BinaryDecimalMinimumLengthUnparser( e: ElementRuntimeData, - override val prefixedLengthUnparser: Unparser, - override val prefixedLengthERD: ElementRuntimeData, signed: YesNo, - binaryDecimalVirtualPoint: Int, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long -) extends BinaryDecimalUnparserBase(e, signed, binaryDecimalVirtualPoint) - with KnownPrefixedLengthUnparserMixin { + binaryDecimalVirtualPoint: Int +) extends BinaryDecimalUnparserBase(e, signed, binaryDecimalVirtualPoint) { - override def childProcessors: Vector[Processor] = Vector(prefixedLengthUnparser) override lazy val runtimeDependencies = Vector() override def getBitLength(s: ParseOrUnparseState): Int = { @@ -240,11 +222,6 @@ class BinaryDecimalPrefixedLengthUnparser( val signedLen = if (signed == YesNo.Yes) len + 1 else len (signedLen + 7) & ~0x7 // round up to nearest multilpe of 8 } - - override def unparse(state: UState): Unit = { - unparsePrefixedLength(state) - super.unparse(state) - } } abstract class BinaryDecimalUnparserBase( diff --git a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/HexBinaryLengthUnparser.scala b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/HexBinaryLengthUnparser.scala index 6fa3d845e7..2bd7d316ff 100644 --- a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/HexBinaryLengthUnparser.scala +++ b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/HexBinaryLengthUnparser.scala @@ -18,12 +18,9 @@ package org.apache.daffodil.unparsers.runtime1 import org.apache.daffodil.lib.exceptions.Assert -import org.apache.daffodil.lib.schema.annotation.props.gen.LengthUnits import org.apache.daffodil.lib.util.Maybe._ import org.apache.daffodil.runtime1.infoset.RetryableException import org.apache.daffodil.runtime1.processors.ElementRuntimeData -import org.apache.daffodil.runtime1.processors.ParseOrUnparseState -import org.apache.daffodil.runtime1.processors.Processor import org.apache.daffodil.runtime1.processors.UnparseTargetLengthInBitsEv import org.apache.daffodil.runtime1.processors.unparsers._ @@ -129,26 +126,3 @@ final class HexBinarySpecifiedLengthUnparser( l } } - -final class HexBinaryLengthPrefixedUnparser( - erd: ElementRuntimeData, - override val prefixedLengthUnparser: Unparser, - override val prefixedLengthERD: ElementRuntimeData, - minLengthInBytes: Long, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long -) extends HexBinaryMinLengthInBytesUnparser(minLengthInBytes, erd) - with KnownPrefixedLengthUnparserMixin { - - override def childProcessors: Vector[Processor] = Vector(prefixedLengthUnparser) - - override def getBitLength(state: ParseOrUnparseState): Int = { - val bits = getLengthInBits(state.asInstanceOf[UState]) - bits.toInt - } - - override def unparse(state: UState): Unit = { - unparsePrefixedLength(state) - super.unparse(state) - } -} diff --git a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/IBM4690PackedDecimalUnparsers.scala b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/IBM4690PackedDecimalUnparsers.scala index c401643e7e..1fb458cf9a 100644 --- a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/IBM4690PackedDecimalUnparsers.scala +++ b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/IBM4690PackedDecimalUnparsers.scala @@ -25,7 +25,6 @@ import org.apache.daffodil.lib.util.DecimalUtils import org.apache.daffodil.runtime1.processors.ElementRuntimeData import org.apache.daffodil.runtime1.processors.Evaluatable import org.apache.daffodil.runtime1.processors.ParseOrUnparseState -import org.apache.daffodil.runtime1.processors.Processor import org.apache.daffodil.runtime1.processors.parsers.HasKnownLengthInBits import org.apache.daffodil.runtime1.processors.parsers.HasRuntimeExplicitLength import org.apache.daffodil.runtime1.processors.unparsers._ @@ -59,16 +58,9 @@ final class IBM4690PackedIntegerDelimitedUnparser(e: ElementRuntimeData) override def getBitLength(state: ParseOrUnparseState): Int = { 0 } } -final class IBM4690PackedIntegerPrefixedLengthUnparser( - e: ElementRuntimeData, - override val prefixedLengthUnparser: Unparser, - override val prefixedLengthERD: ElementRuntimeData, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long -) extends IBM4690PackedIntegerBaseUnparser(e) - with KnownPrefixedLengthUnparserMixin { +final class IBM4690PackedIntegerMinimumLengthUnparser(e: ElementRuntimeData) + extends IBM4690PackedIntegerBaseUnparser(e) { - override def childProcessors: Vector[Processor] = Vector(prefixedLengthUnparser) override lazy val runtimeDependencies = Vector() override def getBitLength(s: ParseOrUnparseState): Int = { @@ -79,11 +71,6 @@ final class IBM4690PackedIntegerPrefixedLengthUnparser( val (byteLength, _) = DecimalUtils.ibm4690FromBigIntegerLength(absBigIntStr, 0, negative) byteLength * 8 } - - override def unparse(state: UState): Unit = { - unparsePrefixedLength(state) - super.unparse(state) - } } abstract class IBM4690PackedDecimalBaseUnparser( @@ -121,17 +108,11 @@ final class IBM4690PackedDecimalDelimitedUnparser( override def getBitLength(state: ParseOrUnparseState): Int = { 0 } } -final class IBM4690PackedDecimalPrefixedLengthUnparser( +final class IBM4690PackedDecimalMinimumLengthUnparser( e: ElementRuntimeData, - override val prefixedLengthUnparser: Unparser, - override val prefixedLengthERD: ElementRuntimeData, - binaryDecimalVirtualPoint: Int, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long -) extends IBM4690PackedDecimalBaseUnparser(e, binaryDecimalVirtualPoint) - with KnownPrefixedLengthUnparserMixin { + binaryDecimalVirtualPoint: Int +) extends IBM4690PackedDecimalBaseUnparser(e, binaryDecimalVirtualPoint) { - override def childProcessors: Vector[Processor] = Vector(prefixedLengthUnparser) override lazy val runtimeDependencies = Vector() override def getBitLength(s: ParseOrUnparseState): Int = { @@ -142,9 +123,4 @@ final class IBM4690PackedDecimalPrefixedLengthUnparser( val (byteLength, _) = DecimalUtils.ibm4690FromBigIntegerLength(absBigIntStr, 0, negative) byteLength * 8 } - - override def unparse(state: UState): Unit = { - unparsePrefixedLength(state) - super.unparse(state) - } } diff --git a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/PackedDecimalUnparsers.scala b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/PackedDecimalUnparsers.scala index ccad3a7a46..c378f80b3f 100644 --- a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/PackedDecimalUnparsers.scala +++ b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/PackedDecimalUnparsers.scala @@ -25,7 +25,6 @@ import org.apache.daffodil.lib.util.{ DecimalUtils, PackedSignCodes } import org.apache.daffodil.runtime1.processors.ElementRuntimeData import org.apache.daffodil.runtime1.processors.Evaluatable import org.apache.daffodil.runtime1.processors.ParseOrUnparseState -import org.apache.daffodil.runtime1.processors.Processor import org.apache.daffodil.runtime1.processors.parsers.HasKnownLengthInBits import org.apache.daffodil.runtime1.processors.parsers.HasRuntimeExplicitLength import org.apache.daffodil.runtime1.processors.unparsers._ @@ -65,17 +64,11 @@ final class PackedIntegerDelimitedUnparser( override def getBitLength(state: ParseOrUnparseState): Int = { 0 } } -final class PackedIntegerPrefixedLengthUnparser( +final class PackedIntegerMinimumLengthUnparser( e: ElementRuntimeData, - override val prefixedLengthUnparser: Unparser, - override val prefixedLengthERD: ElementRuntimeData, - packedSignCodes: PackedSignCodes, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long -) extends PackedIntegerBaseUnparser(e, packedSignCodes) - with KnownPrefixedLengthUnparserMixin { + packedSignCodes: PackedSignCodes +) extends PackedIntegerBaseUnparser(e, packedSignCodes) { - override def childProcessors: Vector[Processor] = Vector(prefixedLengthUnparser) override lazy val runtimeDependencies = Vector() override def getBitLength(s: ParseOrUnparseState): Int = { @@ -84,11 +77,6 @@ final class PackedIntegerPrefixedLengthUnparser( val (byteLength, _) = DecimalUtils.packedFromBigIntegerLength(absBigIntStr, 0) byteLength * 8 } - - override def unparse(state: UState): Unit = { - unparsePrefixedLength(state) - super.unparse(state) - } } abstract class PackedDecimalBaseUnparser( @@ -130,18 +118,12 @@ final class PackedDecimalDelimitedUnparser( override def getBitLength(state: ParseOrUnparseState): Int = { 0 } } -final class PackedDecimalPrefixedLengthUnparser( +final class PackedDecimalMinimumLengthUnparser( e: ElementRuntimeData, - override val prefixedLengthUnparser: Unparser, - override val prefixedLengthERD: ElementRuntimeData, binaryDecimalVirtualPoint: Int, - packedSignCodes: PackedSignCodes, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long -) extends PackedDecimalBaseUnparser(e, binaryDecimalVirtualPoint, packedSignCodes) - with KnownPrefixedLengthUnparserMixin { + packedSignCodes: PackedSignCodes +) extends PackedDecimalBaseUnparser(e, binaryDecimalVirtualPoint, packedSignCodes) { - override def childProcessors: Vector[Processor] = Vector(prefixedLengthUnparser) override lazy val runtimeDependencies = Vector() override def getBitLength(s: ParseOrUnparseState): Int = { @@ -151,9 +133,4 @@ final class PackedDecimalPrefixedLengthUnparser( byteLength * 8 } - override def unparse(state: UState): Unit = { - unparsePrefixedLength(state) - super.unparse(state) - } - } diff --git a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/SpecifiedLength2.scala b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/SpecifiedLength2.scala index 3dcebfa9d6..957110f4e4 100644 --- a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/SpecifiedLength2.scala +++ b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/SpecifiedLength2.scala @@ -931,11 +931,11 @@ class PrefixLengthSuspendableOperation( override protected def maybeKnownLengthInBits(ustate: UState): MaybeULong = MaybeULong(0L) override def test(ustate: UState): Boolean = { - elem.valueLength.maybeLengthInBits.isDefined + elem.contentLength.maybeLengthInBits.isDefined } override def continuation(state: UState): Unit = { - val len = elem.valueLength.maybeLengthInBits.isDefined + val len = elem.contentLength.maybeLengthInBits.isDefined assignPrefixLength(state, elem, plElem) } } diff --git a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/SpecifiedLengthUnparsers.scala b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/SpecifiedLengthUnparsers.scala index f2ec32e9b3..d8e9bc3c48 100644 --- a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/SpecifiedLengthUnparsers.scala +++ b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/SpecifiedLengthUnparsers.scala @@ -26,7 +26,6 @@ import org.apache.daffodil.runtime1.infoset.DISimple import org.apache.daffodil.runtime1.infoset.Infoset import org.apache.daffodil.runtime1.processors.CharsetEv import org.apache.daffodil.runtime1.processors.ElementRuntimeData -import org.apache.daffodil.runtime1.processors.ParseOrUnparseState import org.apache.daffodil.runtime1.processors.UnparseTargetLengthInBitsEv import org.apache.daffodil.runtime1.processors.unparsers._ @@ -73,85 +72,10 @@ final class SpecifiedLengthExplicitImplicitUnparser( } } -// TODO: implement the capture length unparsers as just using this trait? -trait CaptureUnparsingValueLength { - - def captureValueLengthStart(state: UState, elem: DIElement): Unit = { - val dos = state.dataOutputStream - if (dos.maybeAbsBitPos0b.isDefined) { - elem.valueLength.setAbsStartPos0bInBits(dos.maybeAbsBitPos0b.getULong) - } else { - elem.valueLength.setRelStartPos0bInBits(dos.relBitPos0b, dos) - } - } - - def captureValueLengthEnd(state: UState, elem: DIElement): Unit = { - val dos = state.dataOutputStream - if (dos.maybeAbsBitPos0b.isDefined) { - elem.valueLength.setAbsEndPos0bInBits(dos.maybeAbsBitPos0b.getULong) - } else { - elem.valueLength.setRelEndPos0bInBits(dos.relBitPos0b, dos) - } - } -} - -/** - * This trait is to be used with prefixed length unparsers where the length is - * known without needing to unparse the data. This means there is either a - * fixed length (like in the case of some binary numbers), or the length can be - * determined completly be inspecting the infoset data (like in the case of - * packed decimals). The length calculation performed in the getBitLength - * function, which returns the length of the data in bits. - */ -trait KnownPrefixedLengthUnparserMixin { - def prefixedLengthERD: ElementRuntimeData - def prefixedLengthUnparser: Unparser - def lengthUnits: LengthUnits - def getBitLength(s: ParseOrUnparseState): Int - def prefixedLengthAdjustmentInUnits: Long - - def unparsePrefixedLength(state: UState): Unit = { - val bits = getBitLength(state) - val lenInUnits = - if (lengthUnits == LengthUnits.Bytes) { - bits >> 3 - } else { - bits - } - val adjustedLenInUnits = lenInUnits + prefixedLengthAdjustmentInUnits - // Create a "detached" DIDocument with a single child element that the - // prefix length will be unparsed from. This creates a completely new - // infoset and unparses from that, so care is taken to ensure this infoset - // is only used for the prefix length unparsing and is removed afterwards - val plElement = Infoset.newDetachedElement(state, prefixedLengthERD).asInstanceOf[DISimple] - - plElement.setDataValue(java.lang.Integer.valueOf(adjustedLenInUnits.toInt)) - - // do checks on facets expressed on prefixLengthType - val optSTRD = plElement.erd.optSimpleTypeRuntimeData - if (optSTRD.isDefined) { - val strd = optSTRD.get - val check = strd.executeCheck(plElement) - if (check.isError) { - UnparseError( - One(state.schemaFileLocation), - One(state.currentLocation), - s"The calculated value of ${prefixedLengthERD.namedQName} ($adjustedLenInUnits) failed check due to ${check.errMsg}" - ) - } - } - - // unparse the prefixed length element - state.currentInfosetNodeStack.push(One(plElement)) - prefixedLengthUnparser.unparse1(state) - state.currentInfosetNodeStack.pop - } -} - /** * This trait is to be used with prefixed length unparsers where the length - * must be calculated based on the value length of the data. This means the - * data must be unparsed, the value length calculated, and that value will be + * must be calculated based on the content length of the data. This means the + * data must be unparsed, the content length calculated, and that value will be * assigned to the prefix length element. */ trait CalculatedPrefixedLengthUnparserMixin { @@ -168,16 +92,16 @@ trait CalculatedPrefixedLengthUnparserMixin { */ def assignPrefixLength(state: UState, elem: DIElement, plElem: DISimple): Unit = { val lenInUnits = lengthUnits match { - case LengthUnits.Bits => elem.valueLength.lengthInBits - case LengthUnits.Bytes => elem.valueLength.lengthInBytes + case LengthUnits.Bits => elem.contentLength.lengthInBits + case LengthUnits.Bytes => elem.contentLength.lengthInBytes case LengthUnits.Characters => { val maybeFixedWidth = elem.erd.encInfo.getEncoderInfo(state).coder.bitsCharset.maybeFixedWidth val lengthInChars = if (maybeFixedWidth.isDefined) { val fixedWidth = maybeFixedWidth.get - Assert.invariant((elem.valueLength.lengthInBits % fixedWidth) == 0) // divisible - elem.valueLength.lengthInBits / fixedWidth + Assert.invariant((elem.contentLength.lengthInBits % fixedWidth) == 0) // divisible + elem.contentLength.lengthInBits / fixedWidth } else { // This is checked for statically, so should not get here. // $COVERAGE-OFF$ @@ -200,7 +124,7 @@ trait CalculatedPrefixedLengthUnparserMixin { UnparseError( One(state.schemaFileLocation), One(state.currentLocation), - s"The calculated value of ${elem.namedQName} ($adjustedLenInUnits) failed check due to ${check.errMsg}" + s"The prefix length value of ${elem.namedQName} ($adjustedLenInUnits) failed check due to ${check.errMsg}" ) } } @@ -215,7 +139,6 @@ class SpecifiedLengthPrefixedUnparser( override val lengthUnits: LengthUnits, override val prefixedLengthAdjustmentInUnits: Long ) extends CombinatorUnparser(erd) - with CaptureUnparsingValueLength with CalculatedPrefixedLengthUnparserMixin { override lazy val runtimeDependencies = Vector() @@ -238,13 +161,10 @@ class SpecifiedLengthPrefixedUnparser( prefixedLengthUnparser.unparse1(state) state.currentInfosetNodeStack.pop - // We now need to capture the length of the actual element val elem = state.currentInfosetNode.asInstanceOf[DIElement] - captureValueLengthStart(state, elem) eUnparser.unparse1(state) - captureValueLengthEnd(state, elem) - if (elem.valueLength.maybeLengthInBits.isDefined) { + if (elem.contentLength.maybeLengthInBits.isDefined) { // If we were able to immediately calculate the length of the element, // then just set it as the value of the detached element created above so // that when the prefixedLengthUnparser suspension resumes it can unparse @@ -253,7 +173,7 @@ class SpecifiedLengthPrefixedUnparser( } else { // The length was not able to be calculated, likely because there was a // suspension when unparsing the eUnparser. So let's create a new - // suspension with the only goal to retry until the valueLength of this + // suspension with the only goal to retry until the contentLength of this // element is determined. Once determined, it will set the value of the // prefix length element, ultimately allowing the prefix length element // suspension to resume and unparse the value diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetImpl.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetImpl.scala index 1aed39f826..03c4c15e1b 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetImpl.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/infoset/InfosetImpl.scala @@ -733,6 +733,10 @@ sealed abstract class LengthState(ie: DIElement) { } def setAbsStartPos0bInBits(absPosInBits0b: ULong): Unit = { + Assert.invariant( + maybeStartPos0bInBits.isEmpty, + s"maybeStartPos0bInBits already has a value: $maybeStartPos0bInBits" + ) maybeStartPos0bInBits = MaybeULong(absPosInBits0b.longValue) maybeStartDataOutputStream = Nope } @@ -743,6 +747,10 @@ sealed abstract class LengthState(ie: DIElement) { } def setAbsEndPos0bInBits(absPosInBits0b: ULong): Unit = { + Assert.invariant( + maybeEndPos0bInBits.isEmpty, + s"maybeEndPos0bInBits already has a value: $maybeEndPos0bInBits" + ) maybeEndPos0bInBits = MaybeULong(absPosInBits0b.longValue) maybeEndDataOutputStream = Nope } diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/BCDParsers.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/BCDParsers.scala index e18eecd502..60dae90905 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/BCDParsers.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/BCDParsers.scala @@ -24,8 +24,6 @@ import org.apache.daffodil.lib.schema.annotation.props.gen.LengthUnits import org.apache.daffodil.lib.util.DecimalUtils import org.apache.daffodil.runtime1.processors.ElementRuntimeData import org.apache.daffodil.runtime1.processors.Evaluatable -import org.apache.daffodil.runtime1.processors.ParseOrUnparseState -import org.apache.daffodil.runtime1.processors.Processor class BCDDecimalKnownLengthParser( e: ElementRuntimeData, @@ -52,25 +50,14 @@ class BCDDecimalRuntimeLengthParser( } -class BCDDecimalPrefixedLengthParser( +class BCDDecimalBitLimitLengthParser( e: ElementRuntimeData, - override val prefixedLengthParser: Parser, - override val prefixedLengthERD: ElementRuntimeData, - binaryDecimalVirtualPoint: Int, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long + binaryDecimalVirtualPoint: Int ) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint) - with PrefixedLengthParserMixin { + with BitLengthFromBitLimitMixin { override def toNumber(num: Array[Byte]): JBigDecimal = DecimalUtils.bcdToBigDecimal(num, binaryDecimalVirtualPoint) - - override def childProcessors: Vector[Processor] = Vector(prefixedLengthParser) - - override def getBitLength(state: ParseOrUnparseState): Int = { - getPrefixedLengthInBits(state.asInstanceOf[PState]).toInt - } - } class BCDIntegerRuntimeLengthParser( @@ -92,20 +79,9 @@ class BCDIntegerKnownLengthParser(e: ElementRuntimeData, val lengthInBits: Int) } -class BCDIntegerPrefixedLengthParser( - e: ElementRuntimeData, - override val prefixedLengthParser: Parser, - override val prefixedLengthERD: ElementRuntimeData, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long -) extends PackedBinaryIntegerBaseParser(e) - with PrefixedLengthParserMixin { +class BCDIntegerBitLimitLengthParser(e: ElementRuntimeData) + extends PackedBinaryIntegerBaseParser(e) + with BitLengthFromBitLimitMixin { override def toNumber(num: Array[Byte]): JBigInteger = DecimalUtils.bcdToBigInteger(num) - - override def childProcessors: Vector[Processor] = Vector(prefixedLengthParser) - - override def getBitLength(state: ParseOrUnparseState): Int = { - getPrefixedLengthInBits(state.asInstanceOf[PState]).toInt - } } diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/IBM4690PackedDecimalParsers.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/IBM4690PackedDecimalParsers.scala index e0a3598188..077c766713 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/IBM4690PackedDecimalParsers.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/IBM4690PackedDecimalParsers.scala @@ -24,8 +24,6 @@ import org.apache.daffodil.lib.schema.annotation.props.gen.LengthUnits import org.apache.daffodil.lib.util.DecimalUtils import org.apache.daffodil.runtime1.processors.ElementRuntimeData import org.apache.daffodil.runtime1.processors.Evaluatable -import org.apache.daffodil.runtime1.processors.ParseOrUnparseState -import org.apache.daffodil.runtime1.processors.Processor class IBM4690PackedDecimalKnownLengthParser( e: ElementRuntimeData, @@ -52,25 +50,15 @@ class IBM4690PackedDecimalRuntimeLengthParser( } -class IBM4690PackedDecimalPrefixedLengthParser( +class IBM4690PackedDecimalBitLimitLengthParser( e: ElementRuntimeData, - override val prefixedLengthParser: Parser, - override val prefixedLengthERD: ElementRuntimeData, - binaryDecimalVirtualPoint: Int, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long + binaryDecimalVirtualPoint: Int ) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint) - with PrefixedLengthParserMixin { + with BitLengthFromBitLimitMixin { override def toNumber(num: Array[Byte]): JBigDecimal = DecimalUtils.ibm4690ToBigDecimal(num, binaryDecimalVirtualPoint) - override def childProcessors: Vector[Processor] = Vector(prefixedLengthParser) - - override def getBitLength(state: ParseOrUnparseState): Int = { - getPrefixedLengthInBits(state.asInstanceOf[PState]).toInt - } - } class IBM4690PackedIntegerRuntimeLengthParser( @@ -96,21 +84,11 @@ class IBM4690PackedIntegerKnownLengthParser( } -class IBM4690PackedIntegerPrefixedLengthParser( - e: ElementRuntimeData, - override val prefixedLengthParser: Parser, - override val prefixedLengthERD: ElementRuntimeData, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long -) extends PackedBinaryIntegerBaseParser(e) - with PrefixedLengthParserMixin { +class IBM4690PackedIntegerBitLimitLengthParser(e: ElementRuntimeData) + extends PackedBinaryIntegerBaseParser(e) + with BitLengthFromBitLimitMixin { override def toNumber(num: Array[Byte]): JBigInteger = DecimalUtils.ibm4690ToBigInteger(num) - override def childProcessors: Vector[Processor] = Vector(prefixedLengthParser) - - override def getBitLength(state: ParseOrUnparseState): Int = { - getPrefixedLengthInBits(state.asInstanceOf[PState]).toInt - } } diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/PackedDecimalParsers.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/PackedDecimalParsers.scala index 7e19f2d1ff..1ac74993d8 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/PackedDecimalParsers.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/PackedDecimalParsers.scala @@ -24,8 +24,6 @@ import org.apache.daffodil.lib.schema.annotation.props.gen.LengthUnits import org.apache.daffodil.lib.util.{ DecimalUtils, PackedSignCodes } import org.apache.daffodil.runtime1.processors.ElementRuntimeData import org.apache.daffodil.runtime1.processors.Evaluatable -import org.apache.daffodil.runtime1.processors.ParseOrUnparseState -import org.apache.daffodil.runtime1.processors.Processor class PackedDecimalKnownLengthParser( e: ElementRuntimeData, @@ -53,26 +51,15 @@ class PackedDecimalRuntimeLengthParser( DecimalUtils.packedToBigDecimal(num, binaryDecimalVirtualPoint, packedSignCodes) } -class PackedDecimalPrefixedLengthParser( +class PackedDecimalBitLimitLengthParser( e: ElementRuntimeData, - override val prefixedLengthParser: Parser, - override val prefixedLengthERD: ElementRuntimeData, binaryDecimalVirtualPoint: Int, - packedSignCodes: PackedSignCodes, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long + packedSignCodes: PackedSignCodes ) extends PackedBinaryDecimalBaseParser(e, binaryDecimalVirtualPoint) - with PrefixedLengthParserMixin { + with BitLengthFromBitLimitMixin { override def toNumber(num: Array[Byte]): JBigDecimal = DecimalUtils.packedToBigDecimal(num, binaryDecimalVirtualPoint, packedSignCodes) - - override def childProcessors: Vector[Processor] = Vector(prefixedLengthParser) - - override def getBitLength(state: ParseOrUnparseState): Int = { - getPrefixedLengthInBits(state.asInstanceOf[PState]).toInt - } - } class PackedIntegerRuntimeLengthParser( @@ -100,22 +87,13 @@ class PackedIntegerKnownLengthParser( } -class PackedIntegerPrefixedLengthParser( +class PackedIntegerBitLimitLengthParser( e: ElementRuntimeData, - override val prefixedLengthParser: Parser, - override val prefixedLengthERD: ElementRuntimeData, - packedSignCodes: PackedSignCodes, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long + packedSignCodes: PackedSignCodes ) extends PackedBinaryIntegerBaseParser(e) - with PrefixedLengthParserMixin { + with BitLengthFromBitLimitMixin { override def toNumber(num: Array[Byte]): JBigInteger = DecimalUtils.packedToBigInteger(num, packedSignCodes) - override def childProcessors: Vector[Processor] = Vector(prefixedLengthParser) - - override def getBitLength(state: ParseOrUnparseState): Int = { - getPrefixedLengthInBits(state.asInstanceOf[PState]).toInt - } } diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryBooleanParsers.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryBooleanParsers.scala index ee7e85ba3b..3ce64df07a 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryBooleanParsers.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryBooleanParsers.scala @@ -26,7 +26,6 @@ import org.apache.daffodil.lib.util.MaybeULong import org.apache.daffodil.lib.util.Numbers import org.apache.daffodil.runtime1.processors.ElementRuntimeData import org.apache.daffodil.runtime1.processors.Evaluatable -import org.apache.daffodil.runtime1.processors.Processor import passera.unsigned.ULong @@ -106,21 +105,17 @@ class BinaryBooleanParser( } } -class BinaryBooleanPrefixedLengthParser( +class BinaryBooleanBitLimitLengthParser( override val context: ElementRuntimeData, - override val prefixedLengthParser: Parser, - override val prefixedLengthERD: ElementRuntimeData, binaryBooleanTrueRep: MaybeULong, binaryBooleanFalseRep: ULong, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long + lengthUnits: LengthUnits ) extends BinaryBooleanParserBase(binaryBooleanTrueRep, binaryBooleanFalseRep, lengthUnits) - with PrefixedLengthParserMixin { + with BitLengthFromBitLimitMixin { - override def childProcessors: Vector[Processor] = Vector(prefixedLengthParser) override val runtimeDependencies = Vector() override def getBitLength(state: PState): Int = { - getPrefixedLengthInBits(state).toInt + getLengthInBits(state).toInt } } diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryNumberParsers.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryNumberParsers.scala index fac7a9078f..1b65a6e08c 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryNumberParsers.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryNumberParsers.scala @@ -28,7 +28,6 @@ import org.apache.daffodil.runtime1.dpath.NodeInfo import org.apache.daffodil.runtime1.processors.ElementRuntimeData import org.apache.daffodil.runtime1.processors.Evaluatable import org.apache.daffodil.runtime1.processors.ParseOrUnparseState -import org.apache.daffodil.runtime1.processors.Processor import org.apache.daffodil.runtime1.processors.unparsers.UState class BinaryFloatParser(override val context: ElementRuntimeData) extends PrimParser { @@ -80,23 +79,12 @@ class BinaryDecimalRuntimeLengthParser( ) extends BinaryDecimalParserBase(e, signed, binaryDecimalVirtualPoint) with HasRuntimeExplicitLength {} -class BinaryDecimalPrefixedLengthParser( +class BinaryDecimalBitLimitLengthParser( e: ElementRuntimeData, - override val prefixedLengthParser: Parser, - override val prefixedLengthERD: ElementRuntimeData, signed: YesNo, - binaryDecimalVirtualPoint: Int, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long + binaryDecimalVirtualPoint: Int ) extends BinaryDecimalParserBase(e, signed, binaryDecimalVirtualPoint) - with PrefixedLengthParserMixin { - - override def childProcessors: Vector[Processor] = Vector(prefixedLengthParser) - - override def getBitLength(state: ParseOrUnparseState): Int = { - getPrefixedLengthInBits(state.asInstanceOf[PState]).toInt - } -} + with BitLengthFromBitLimitMixin abstract class BinaryDecimalParserBase( override val context: ElementRuntimeData, @@ -142,21 +130,9 @@ class BinaryIntegerKnownLengthParser( ) extends BinaryIntegerBaseParser(e) with HasKnownLengthInBits {} -class BinaryIntegerPrefixedLengthParser( - e: ElementRuntimeData, - override val prefixedLengthParser: Parser, - override val prefixedLengthERD: ElementRuntimeData, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long -) extends BinaryIntegerBaseParser(e) - with PrefixedLengthParserMixin { - - override def childProcessors: Vector[Processor] = Vector(prefixedLengthParser) - - override def getBitLength(state: ParseOrUnparseState): Int = { - getPrefixedLengthInBits(state.asInstanceOf[PState]).toInt - } -} +class BinaryIntegerBitLimitLengthParser(e: ElementRuntimeData) + extends BinaryIntegerBaseParser(e) + with BitLengthFromBitLimitMixin abstract class BinaryIntegerBaseParser( override val context: ElementRuntimeData diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryNumberTraits.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryNumberTraits.scala index 29317a2952..9641aef5f1 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryNumberTraits.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/BinaryNumberTraits.scala @@ -110,7 +110,7 @@ trait PrefixedLengthParserMixin { val check = strd.executeCheck(plElement) if (check.isError) { val pe = state.toProcessingError( - s"The value of ${prefixedLengthERD.namedQName} ($parsedLen) failed check due to ${check.errMsg}" + s"The prefix length value of ${savedInfoset.namedQName} ($parsedLen) failed check due to ${check.errMsg}" ) state.setFailed(pe) } @@ -165,3 +165,23 @@ trait PrefixedLengthParserMixin { } } } + +/** + * Some parsers do not calculate their own length, but instead expect another parser + * to set the bit limit, and then they use that bit limit as the length. + * An example of this is prefix length parsers. This trait can be used by those + * parsers to do determine the length based on the bitLimit and position. + */ +trait BitLengthFromBitLimitMixin { + + def getBitLength(s: ParseOrUnparseState): Int = { + val pState = s.asInstanceOf[PState] + val len = getLengthInBits(pState) + len.toInt + } + + def getLengthInBits(pstate: PState): Long = { + val len = pstate.bitLimit0b.get - pstate.bitPos0b + len + } +} diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/HexBinaryLengthParsers.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/HexBinaryLengthParsers.scala index 5f00208a4b..b211ce2ee0 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/HexBinaryLengthParsers.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/HexBinaryLengthParsers.scala @@ -19,10 +19,8 @@ package org.apache.daffodil.runtime1.processors.parsers import java.nio.ByteBuffer -import org.apache.daffodil.lib.schema.annotation.props.gen.LengthUnits import org.apache.daffodil.runtime1.processors.ElementRuntimeData import org.apache.daffodil.runtime1.processors.LengthInBitsEv -import org.apache.daffodil.runtime1.processors.Processor sealed abstract class HexBinaryLengthParser(override val context: ElementRuntimeData) extends PrimParser @@ -94,20 +92,3 @@ final class HexBinaryEndOfBitLimitParser(erd: ElementRuntimeData) pstate.bitLimit0b.get - pstate.bitPos0b } } - -final class HexBinaryLengthPrefixedParser( - erd: ElementRuntimeData, - override val prefixedLengthParser: Parser, - override val prefixedLengthERD: ElementRuntimeData, - override val lengthUnits: LengthUnits, - override val prefixedLengthAdjustmentInUnits: Long -) extends HexBinaryLengthParser(erd) - with PrefixedLengthParserMixin { - - override def childProcessors: Vector[Processor] = Vector(prefixedLengthParser) - override val runtimeDependencies = Vector() - - override def getLengthInBits(pstate: PState): Long = { - getPrefixedLengthInBits(pstate) - } -} diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/SpecifiedLengthParsers.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/SpecifiedLengthParsers.scala index a969ba8b6b..42e42f10e5 100644 --- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/SpecifiedLengthParsers.scala +++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/SpecifiedLengthParsers.scala @@ -85,7 +85,11 @@ sealed abstract class SpecifiedLengthParserBase(eParser: Parser, erd: RuntimeDat if (pState.processorStatus ne Success) return val finalEndPos0b = startingBitPos0b + nBits - captureValueLength(pState, ULong(startingBitPos0b), ULong(dis.bitPos0b)) + // we want to capture the length before we do any skipping + // value length of simple types is captured by the eParser if needed + // the SpecifiedLengthParserBase is extended by SpecifiedLengthChoiceParser which should not have its valueLength captured here + if (pState.infoset.isComplex && !erd.isInstanceOf[ChoiceRuntimeData]) + captureValueLength(pState, ULong(startingBitPos0b), ULong(dis.bitPos0b)) Assert.invariant(dis eq pState.dataInputStream) val bitsToSkip = finalEndPos0b - dis.bitPos0b diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/section12/lengthKind/PrefixedTests.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/section12/lengthKind/PrefixedTests.tdml index 6882e2057b..4a331602b1 100644 --- a/daffodil-test/src/test/resources/org/apache/daffodil/section12/lengthKind/PrefixedTests.tdml +++ b/daffodil-test/src/test/resources/org/apache/daffodil/section12/lengthKind/PrefixedTests.tdml @@ -19,7 +19,7 @@ - + + + + + + + + + + + + + + + @@ -2326,6 +2347,28 @@ + + + + + + + + + + + + + + + + + + + ABC + + + + + ABC + 3 + + + + + + + + 00 00 00 0B + ABC + + + + + ABC + 3 + + + + + @@ -2580,7 +2654,7 @@ + ignoreUnexpectedWarnings="false"> 08 ff @@ -2913,7 +2987,7 @@ failed check - field2 (prefixLength) (5) + field2 (5) facet maxInclusive (4) @@ -2926,7 +3000,7 @@ failed check - field1 (prefixLength) (6) + field1 (6) facet maxInclusive (4) @@ -2956,7 +3030,7 @@ failed check - field3 (prefixLength) (1) + field3 (1) facet minInclusive (2) diff --git a/daffodil-test/src/test/scala/org/apache/daffodil/section12/lengthKind/TestLengthKindPrefixed.scala b/daffodil-test/src/test/scala/org/apache/daffodil/section12/lengthKind/TestLengthKindPrefixed.scala index 99a563fd90..3ec2eec760 100644 --- a/daffodil-test/src/test/scala/org/apache/daffodil/section12/lengthKind/TestLengthKindPrefixed.scala +++ b/daffodil-test/src/test/scala/org/apache/daffodil/section12/lengthKind/TestLengthKindPrefixed.scala @@ -172,7 +172,11 @@ class TestLengthKindPrefixed extends TdmlTests { @Test def pl_simpleContentLengthBytes_1 = test // DAFFODIL-2658 - @Ignore @Test def pl_simpleValueLengthBytes_1 = test + @Test def pl_simpleValueLengthBytes_1() = test + @Test def pl_simpleValueLengthBytes_2() = test + + // DAFFODIL-2948 + @Test def pl_simpleValueLengthBytes_3() = test @Test def pl_simpleContentLengthCharacters_1 = test @Test def pl_complexContentLengthCharacters_1 = test